| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chromeos/services/assistant/assistant_settings_manager_impl.h" |
| |
| #include <utility> |
| |
| #include "chromeos/dbus/util/version_loader.h" |
| #include "chromeos/services/assistant/assistant_manager_service_impl.h" |
| #include "chromeos/services/assistant/constants.h" |
| #include "chromeos/services/assistant/public/proto/assistant_device_settings_ui.pb.h" |
| #include "chromeos/services/assistant/public/proto/settings_ui.pb.h" |
| #include "chromeos/services/assistant/service.h" |
| #include "libassistant/shared/internal_api/assistant_manager_internal.h" |
| |
| using SpeakerIdEnrollmentState = |
| assistant_client::SpeakerIdEnrollmentUpdate::State; |
| |
| namespace chromeos { |
| namespace assistant { |
| |
| AssistantSettingsManagerImpl::AssistantSettingsManagerImpl( |
| Service* service, |
| AssistantManagerServiceImpl* assistant_manager_service) |
| : service_(service), |
| assistant_manager_service_(assistant_manager_service), |
| weak_factory_(this) {} |
| |
| AssistantSettingsManagerImpl::~AssistantSettingsManagerImpl() = default; |
| |
| void AssistantSettingsManagerImpl::BindRequest( |
| mojom::AssistantSettingsManagerRequest request) { |
| bindings_.AddBinding(this, std::move(request)); |
| } |
| |
| void AssistantSettingsManagerImpl::GetSettings(const std::string& selector, |
| GetSettingsCallback callback) { |
| DCHECK(assistant_manager_service_->GetState() == |
| AssistantManagerService::State::RUNNING); |
| DCHECK(service_->main_task_runner()->RunsTasksInCurrentSequence()); |
| |
| // Wraps the callback into a repeating callback since the server side |
| // interface requires the callback to be copyable. |
| std::string serialized_proto = SerializeGetSettingsUiRequest(selector); |
| assistant_manager_service_->assistant_manager_internal() |
| ->SendGetSettingsUiRequest( |
| serialized_proto, std::string(), |
| [repeating_callback = |
| base::AdaptCallbackForRepeating(std::move(callback)), |
| task_runner = service_->main_task_runner()]( |
| const assistant_client::VoicelessResponse& response) { |
| // This callback may be called from server multiple times. We should |
| // only process non-empty response. |
| std::string settings = UnwrapGetSettingsUiResponse(response); |
| if (!settings.empty()) { |
| task_runner->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| [](base::RepeatingCallback<void(const std::string&)> |
| callback, |
| const std::string& result) { callback.Run(result); }, |
| repeating_callback, settings)); |
| } |
| }); |
| } |
| |
| void AssistantSettingsManagerImpl::UpdateSettings( |
| const std::string& update, |
| GetSettingsCallback callback) { |
| DCHECK(assistant_manager_service_->GetState() == |
| AssistantManagerService::State::RUNNING); |
| DCHECK(service_->main_task_runner()->RunsTasksInCurrentSequence()); |
| // Wraps the callback into a repeating callback since the server side |
| // interface requires the callback to be copyable. |
| std::string serialized_proto = SerializeUpdateSettingsUiRequest(update); |
| assistant_manager_service_->assistant_manager_internal() |
| ->SendUpdateSettingsUiRequest( |
| serialized_proto, std::string(), |
| [repeating_callback = |
| base::AdaptCallbackForRepeating(std::move(callback)), |
| task_runner = service_->main_task_runner()]( |
| const assistant_client::VoicelessResponse& response) { |
| // This callback may be called from server multiple times. We should |
| // only process non-empty response. |
| std::string update = UnwrapUpdateSettingsUiResponse(response); |
| if (!update.empty()) { |
| task_runner->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| [](base::RepeatingCallback<void(const std::string&)> |
| callback, |
| const std::string& result) { callback.Run(result); }, |
| repeating_callback, update)); |
| } |
| }); |
| } |
| |
| void AssistantSettingsManagerImpl::StartSpeakerIdEnrollment( |
| bool skip_cloud_enrollment, |
| mojom::SpeakerIdEnrollmentClientPtr client) { |
| DCHECK(assistant_manager_service_->GetState() == |
| AssistantManagerService::State::RUNNING); |
| DCHECK(service_->main_task_runner()->RunsTasksInCurrentSequence()); |
| |
| speaker_id_enrollment_client_ = std::move(client); |
| |
| assistant_client::SpeakerIdEnrollmentConfig client_config; |
| client_config.user_id = kUserID; |
| client_config.skip_cloud_enrollment = skip_cloud_enrollment; |
| |
| assistant_manager_service_->assistant_manager_internal() |
| ->StartSpeakerIdEnrollment( |
| client_config, |
| [weak_ptr = weak_factory_.GetWeakPtr(), |
| task_runner = service_->main_task_runner()]( |
| const assistant_client::SpeakerIdEnrollmentUpdate& update) { |
| task_runner->PostTask( |
| FROM_HERE, base::BindOnce(&AssistantSettingsManagerImpl:: |
| HandleSpeakerIdEnrollmentUpdate, |
| weak_ptr, update)); |
| }); |
| } |
| |
| void AssistantSettingsManagerImpl::StopSpeakerIdEnrollment( |
| StopSpeakerIdEnrollmentCallback callback) { |
| DCHECK(assistant_manager_service_->GetState() == |
| AssistantManagerService::State::RUNNING); |
| DCHECK(service_->main_task_runner()->RunsTasksInCurrentSequence()); |
| assistant_manager_service_->assistant_manager_internal() |
| ->StopSpeakerIdEnrollment([repeating_callback = |
| base::AdaptCallbackForRepeating( |
| std::move(callback)), |
| task_runner = service_->main_task_runner(), |
| weak_ptr = weak_factory_.GetWeakPtr()]() { |
| task_runner->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &AssistantSettingsManagerImpl::HandleStopSpeakerIdEnrollment, |
| std::move(weak_ptr), repeating_callback)); |
| }); |
| } |
| |
| void AssistantSettingsManagerImpl::HandleSpeakerIdEnrollmentUpdate( |
| const assistant_client::SpeakerIdEnrollmentUpdate& update) { |
| DCHECK(service_->main_task_runner()->RunsTasksInCurrentSequence()); |
| switch (update.state) { |
| case SpeakerIdEnrollmentState::LISTEN: |
| speaker_id_enrollment_client_->OnListeningHotword(); |
| break; |
| case SpeakerIdEnrollmentState::PROCESS: |
| speaker_id_enrollment_client_->OnProcessingHotword(); |
| break; |
| case SpeakerIdEnrollmentState::DONE: |
| speaker_id_enrollment_client_->OnSpeakerIdEnrollmentDone(); |
| if (!speaker_id_enrollment_done_) { |
| speaker_id_enrollment_done_ = true; |
| assistant_manager_service_->UpdateInternalOptions( |
| assistant_manager_service_->assistant_manager_internal()); |
| } |
| break; |
| case SpeakerIdEnrollmentState::FAILURE: |
| speaker_id_enrollment_client_->OnSpeakerIdEnrollmentFailure(); |
| break; |
| case SpeakerIdEnrollmentState::INIT: |
| case SpeakerIdEnrollmentState::CHECK: |
| case SpeakerIdEnrollmentState::UPLOAD: |
| case SpeakerIdEnrollmentState::FETCH: |
| break; |
| } |
| } |
| |
| void AssistantSettingsManagerImpl::HandleSpeakerIdEnrollmentStatusSync( |
| const assistant_client::SpeakerIdEnrollmentUpdate& update) { |
| DCHECK(service_->main_task_runner()->RunsTasksInCurrentSequence()); |
| switch (update.state) { |
| case SpeakerIdEnrollmentState::LISTEN: |
| speaker_id_enrollment_done_ = false; |
| // Stop the enrollment since we already get the status. |
| if (!speaker_id_enrollment_client_) { |
| StopSpeakerIdEnrollment(base::DoNothing()); |
| // If hotword is enabled but there is no voice model found, launch the |
| // enrollment flow. |
| if (service_->assistant_state()->hotword_enabled().value()) |
| service_->assistant_controller()->StartSpeakerIdEnrollmentFlow(); |
| } |
| break; |
| case SpeakerIdEnrollmentState::DONE: |
| speaker_id_enrollment_done_ = true; |
| assistant_manager_service_->UpdateInternalOptions( |
| assistant_manager_service_->assistant_manager_internal()); |
| break; |
| case SpeakerIdEnrollmentState::PROCESS: |
| case SpeakerIdEnrollmentState::FAILURE: |
| case SpeakerIdEnrollmentState::INIT: |
| case SpeakerIdEnrollmentState::CHECK: |
| case SpeakerIdEnrollmentState::UPLOAD: |
| case SpeakerIdEnrollmentState::FETCH: |
| break; |
| } |
| } |
| |
| void AssistantSettingsManagerImpl::HandleStopSpeakerIdEnrollment( |
| base::RepeatingCallback<void()> callback) { |
| DCHECK(service_->main_task_runner()->RunsTasksInCurrentSequence()); |
| speaker_id_enrollment_client_.reset(); |
| callback.Run(); |
| } |
| |
| void AssistantSettingsManagerImpl::SyncSpeakerIdEnrollmentStatus() { |
| DCHECK(service_->main_task_runner()->RunsTasksInCurrentSequence()); |
| if (speaker_id_enrollment_client_) { |
| // Speaker id enrollment is in progress. |
| return; |
| } |
| |
| // TODO(updowndota): Add a dedicate API for fetching enrollment status. |
| assistant_client::SpeakerIdEnrollmentConfig client_config; |
| client_config.user_id = kUserID; |
| client_config.skip_cloud_enrollment = false; |
| |
| assistant_manager_service_->assistant_manager_internal() |
| ->StartSpeakerIdEnrollment( |
| client_config, |
| [weak_ptr = weak_factory_.GetWeakPtr(), |
| task_runner = service_->main_task_runner()]( |
| const assistant_client::SpeakerIdEnrollmentUpdate& update) { |
| task_runner->PostTask( |
| FROM_HERE, |
| base::BindOnce(&AssistantSettingsManagerImpl:: |
| HandleSpeakerIdEnrollmentStatusSync, |
| weak_ptr, update)); |
| }); |
| } |
| |
| void AssistantSettingsManagerImpl::UpdateServerDeviceSettings() { |
| DCHECK(service_->main_task_runner()->RunsTasksInCurrentSequence()); |
| |
| const std::string device_id = |
| assistant_manager_service_->assistant_manager()->GetDeviceId(); |
| if (device_id.empty()) |
| return; |
| |
| // Update device id and device type. |
| assistant::SettingsUiUpdate update; |
| assistant::AssistantDeviceSettingsUpdate* device_settings_update = |
| update.mutable_assistant_device_settings_update() |
| ->add_assistant_device_settings_update(); |
| device_settings_update->set_device_id(device_id); |
| device_settings_update->set_assistant_device_type( |
| assistant::AssistantDevice::CROS); |
| |
| VLOG(1) << "Update assistant device locale: " |
| << service_->assistant_state()->locale().value(); |
| device_settings_update->mutable_device_settings()->set_locale( |
| service_->assistant_state()->locale().value()); |
| |
| // Enable personal readout to grant permission for personal features. |
| device_settings_update->mutable_device_settings()->set_personal_readout( |
| assistant::AssistantDeviceSettings::PERSONAL_READOUT_ENABLED); |
| |
| // Device settings update result is not handled because it is not included in |
| // the SettingsUiUpdateResult. |
| UpdateSettings(update.SerializeAsString(), base::DoNothing()); |
| } |
| |
| } // namespace assistant |
| } // namespace chromeos |