diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js index ab39fe7ab17ea..4644d19acaeae 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js @@ -46,6 +46,13 @@ Polymer({ */ screenShown_: false, + /** + * Whether the voice match feature has been enabled. + * @type {boolean} + * @private + */ + voiceMatchFeatureEnabled_: false, + /** * On-tap event handler for next button. * @@ -56,13 +63,17 @@ Polymer({ return; } this.buttonsDisabled = true; - var hotword = this.$$('#toggle0').hasAttribute('checked'); - var screenContext = this.$$('#toggle1').hasAttribute('checked'); - var toggle2 = this.$$('#toggle2'); - var emailOptedIn = toggle2 != null && toggle2.hasAttribute('checked'); + + if (!this.voiceMatchFeatureEnabled_) { + var hotword = this.$$('#toggle-hotword').hasAttribute('checked'); + chrome.send('login.AssistantOptInFlowScreen.hotwordResult', [hotword]); + } + var screenContext = this.$$('#toggle-context').hasAttribute('checked'); + var toggleEmail = this.$$('#toggle-email'); + var emailOptedIn = + toggleEmail != null && toggleEmail.hasAttribute('checked'); // TODO(updowndota): Wrap chrome.send() calls with a proxy object. - chrome.send('login.AssistantOptInFlowScreen.hotwordResult', [hotword]); chrome.send( 'login.AssistantOptInFlowScreen.GetMoreScreen.userActed', [screenContext, emailOptedIn]); @@ -83,6 +94,7 @@ Polymer({ this.$['title-text'].textContent = data['getMoreTitle']; this.$['intro-text'].textContent = data['getMoreIntro']; this.$['next-button-text'].textContent = data['getMoreContinueButton']; + this.voiceMatchFeatureEnabled_ = data['voiceMatchFeatureEnabled']; this.consentStringLoaded_ = true; if (this.settingZippyLoaded_) { @@ -103,7 +115,7 @@ Polymer({ 'data:text/html;charset=utf-8,' + encodeURIComponent(zippy.getWrappedIcon(data['iconUri']))); zippy.setAttribute('toggle-style', true); - zippy.id = 'zippy' + i; + zippy.id = 'zippy-' + data['id']; var title = document.createElement('div'); title.className = 'zippy-title'; title.textContent = data['title']; @@ -111,7 +123,7 @@ Polymer({ var toggle = document.createElement('cr-toggle'); toggle.className = 'zippy-toggle'; - toggle.id = 'toggle' + i; + toggle.id = 'toggle-' + data['id']; if (data['defaultEnabled']) { toggle.setAttribute('checked', ''); } diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.js index cebd7a0545b0a..e323662f77e14 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.js +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.js @@ -42,9 +42,7 @@ Polymer({ * @param {!Object} data New dictionary with i18n values. */ reloadContent: function(data) { - // Reload global local strings, process DOM tree again. - loadTimeData.overrideValues(data); - i18nTemplate.process(document, loadTimeData); + this.voiceMatchFeatureEnabled = data['voiceMatchFeatureEnabled']; this.$['value-prop'].reloadContent(data); this.$['third-party'].reloadContent(data); this.$['get-more'].reloadContent(data); @@ -80,7 +78,11 @@ Polymer({ this.showScreen(this.$['third-party']); break; case this.$['third-party']: - this.showScreen(this.$['voice-match']); + if (this.voiceMatchFeatureEnabled) { + this.showScreen(this.$['voice-match']); + } else { + this.showScreen(this.$['get-more']); + } break; case this.$['voice-match']: this.showScreen(this.$['get-more']); diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.css b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.css index dd3466c826c0b..72bdc4fb48f00 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.css +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.css @@ -24,11 +24,17 @@ padding: 0 8px 0 8px; } -.intro #recording-container, -.recording #intro-container, -.completed #intro-container { - position: absolute; - visibility: hidden; +#intro-container, +#recording-container, +#already-setup-container { + display: none; +} + +.intro #intro-container, +.recording #recording-container, +.completed #recording-container, +.already-setup #already-setup-container { + display: block; } .recording #title-completed, @@ -37,9 +43,10 @@ } .intro #skip-button, -.intro #next-button, +.intro #agree-button, .recording #later-button, -.completed #done-button { +.completed #done-button, +.already-setup #next-button { display: block; } diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html index a360727601662..f00939ff471ca 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html @@ -48,25 +48,35 @@ +
+
+
+
-
No thanks
+
-
Do it later
+
- -
I agree
+
-
Save
+
+
+ +
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js index 8919d13849c32..c5644ff92898d 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js @@ -31,11 +31,11 @@ Polymer({ }, /** - * On-tap event handler for next button. + * On-tap event handler for agree button. * * @private */ - onNextTap_: function() { + onAgreeTap_: function() { this.removeClass_('intro'); this.addClass_('recording'); chrome.send( @@ -44,7 +44,7 @@ Polymer({ }, /** - * On-tap event handler for next button. + * On-tap event handler for done button. * * @private */ @@ -107,6 +107,6 @@ Polymer({ * Signal from host to show the screen. */ onShow: function() { - this.$['next-button'].focus(); + this.$['agree-button'].focus(); }, }); diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc index 0647fc5837c0e..43c582bef06d2 100644 --- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc +++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc @@ -10,6 +10,7 @@ #include "chrome/browser/ui/webui/chromeos/user_image_source.h" #include "chrome/grit/browser_resources.h" #include "chrome/grit/generated_resources.h" +#include "chromeos/services/assistant/public/features.h" #include "components/arc/arc_prefs.h" #include "components/consent_auditor/consent_auditor.h" #include "components/signin/core/browser/signin_manager_base.h" @@ -108,23 +109,28 @@ base::Value CreateGetMoreData(bool email_optin_needed, const assistant::EmailOptInUi& email_optin_ui) { base::Value get_more_data(base::Value::Type::LIST); - // Process hotword data. - base::Value hotword_data(base::Value::Type::DICTIONARY); - hotword_data.SetKey( - "title", - base::Value(l10n_util::GetStringUTF16(IDS_ASSISTANT_HOTWORD_TITLE))); - hotword_data.SetKey( - "description", - base::Value(l10n_util::GetStringUTF16(IDS_ASSISTANT_HOTWORD_DESC))); - hotword_data.SetKey("defaultEnabled", base::Value(true)); - hotword_data.SetKey( - "iconUri", - base::Value("https://www.gstatic.com/images/icons/material/system/" - "2x/mic_none_grey600_48dp.png")); - get_more_data.GetList().push_back(std::move(hotword_data)); + if (!base::FeatureList::IsEnabled( + assistant::features::kAssistantVoiceMatch)) { + // Process hotword data. + base::Value hotword_data(base::Value::Type::DICTIONARY); + hotword_data.SetKey("id", base::Value("hotword")); + hotword_data.SetKey( + "title", + base::Value(l10n_util::GetStringUTF16(IDS_ASSISTANT_HOTWORD_TITLE))); + hotword_data.SetKey( + "description", + base::Value(l10n_util::GetStringUTF16(IDS_ASSISTANT_HOTWORD_DESC))); + hotword_data.SetKey("defaultEnabled", base::Value(true)); + hotword_data.SetKey( + "iconUri", + base::Value("https://www.gstatic.com/images/icons/material/system/" + "2x/mic_none_grey600_48dp.png")); + get_more_data.GetList().push_back(std::move(hotword_data)); + } // Process screen context data. base::Value context_data(base::Value::Type::DICTIONARY); + context_data.SetKey("id", base::Value("context")); context_data.SetKey("title", base::Value(l10n_util::GetStringUTF16( IDS_ASSISTANT_SCREEN_CONTEXT_TITLE))); context_data.SetKey("description", base::Value(l10n_util::GetStringUTF16( @@ -139,6 +145,7 @@ base::Value CreateGetMoreData(bool email_optin_needed, // Process email optin data. if (email_optin_needed) { base::Value data(base::Value::Type::DICTIONARY); + data.SetKey("id", base::Value("email")); data.SetKey("title", base::Value(email_optin_ui.title())); data.SetKey("description", base::Value(email_optin_ui.description())); data.SetKey("defaultEnabled", diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc index 6d6ea7e6f614b..e20f1527a0c76 100644 --- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc @@ -79,7 +79,16 @@ void AssistantOptInFlowScreenHandler::DeclareLocalizedValues( IDS_ASSISTANT_VOICE_MATCH_COMPLETE); builder->Add("assistantVoiceMatchUploading", IDS_ASSISTANT_VOICE_MATCH_UPLOADING); + builder->Add("assistantVoiceMatchAlreadySetupTitle", + IDS_ASSISTANT_VOICE_MATCH_ALREADY_SETUP_TITLE); + builder->Add("assistantVoiceMatchAlreadySetupMessage", + IDS_ASSISTANT_VOICE_MATCH_ALREADY_SETUP_MESSAGE); builder->Add("assistantOptinOKButton", IDS_OOBE_OK_BUTTON_TEXT); + builder->Add("assistantOptinNoThanksButton", IDS_ASSISTANT_NO_THANKS_BUTTON); + builder->Add("assistantOptinLaterButton", IDS_ASSISTANT_LATER_BUTTON); + builder->Add("assistantOptinAgreeButton", IDS_ASSISTANT_AGREE_BUTTON); + builder->Add("assistantOptinSaveButton", IDS_ASSISTANT_SAVE_BUTTON); + builder->Add("assistantOptinWaitMessage", IDS_ASSISTANT_WAIT_MESSAGE); builder->Add("assistantReadyTitle", IDS_ASSISTANT_READY_SCREEN_TITLE); builder->Add("assistantReadyMessage", IDS_ASSISTANT_READY_SCREEN_MESSAGE); builder->Add("assistantReadyButton", IDS_ASSISTANT_DONE_BUTTON); @@ -166,6 +175,7 @@ void AssistantOptInFlowScreenHandler::OnProcessingHotword() { } void AssistantOptInFlowScreenHandler::OnSpeakerIdEnrollmentDone() { + settings_manager_->StopSpeakerIdEnrollment(base::DoNothing()); CallJSWithPrefix("onVoiceMatchUpdate", base::Value("done")); } @@ -227,7 +237,15 @@ void AssistantOptInFlowScreenHandler::OnEmailOptInResult(bool opted_in) { void AssistantOptInFlowScreenHandler::OnStateChanged( ash::mojom::VoiceInteractionState state) { if (state != ash::mojom::VoiceInteractionState::NOT_READY) { - BindAssistantSettingsManager(); + if (voice_enrollment_pending) { + voice_enrollment_pending = false; + DCHECK(settings_manager_.is_bound() && + base::FeatureList::IsEnabled( + assistant::features::kAssistantVoiceMatch)); + settings_manager_->StartSpeakerIdEnrollment(true, std::move(client_ptr_)); + } else { + BindAssistantSettingsManager(); + } arc::VoiceInteractionControllerClient::Get()->RemoveObserver(this); } } @@ -244,7 +262,9 @@ void AssistantOptInFlowScreenHandler::BindAssistantSettingsManager() { mojo::MakeRequest(&settings_manager_)); client_binding_.Bind(mojo::MakeRequest(&client_ptr_)); - SendGetSettingsRequest(); + if (initialized_) { + SendGetSettingsRequest(); + } } void AssistantOptInFlowScreenHandler::SendGetSettingsRequest() { @@ -337,7 +357,11 @@ void AssistantOptInFlowScreenHandler::OnGetSettingsResponse( } // Pass string constants dictionary. - ReloadContent(GetSettingsUiStrings(settings_ui, activity_control_needed_)); + auto dictionary = GetSettingsUiStrings(settings_ui, activity_control_needed_); + dictionary.SetKey("voiceMatchFeatureEnabled", + base::Value(base::FeatureList::IsEnabled( + assistant::features::kAssistantVoiceMatch))); + ReloadContent(dictionary); } void AssistantOptInFlowScreenHandler::OnUpdateSettingsResponse( @@ -395,11 +419,6 @@ void AssistantOptInFlowScreenHandler::HandleThirdPartyScreenUserAction( if (action == kNextPressed) { RecordAssistantOptInStatus(THIRD_PARTY_CONTINUED); ShowNextScreen(); - if (!base::FeatureList::IsEnabled( - assistant::features::kAssistantVoiceMatch)) { - // Skip the voice match enrollment if feature is disabled. - ShowNextScreen(); - } } } @@ -409,10 +428,24 @@ void AssistantOptInFlowScreenHandler::HandleVoiceMatchScreenUserAction( assistant::features::kAssistantVoiceMatch)) { return; } - if (action == kNextPressed || action == kSkipPressed) { + PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs(); + + if (action == kNextPressed) { + ShowNextScreen(); + } else if (action == kSkipPressed) { + prefs->SetBoolean(arc::prefs::kVoiceInteractionHotwordEnabled, false); + settings_manager_->StopSpeakerIdEnrollment(base::DoNothing()); ShowNextScreen(); } else if (action == kRecordPressed) { - settings_manager_->StartSpeakerIdEnrollment(true, std::move(client_ptr_)); + if (!prefs->GetBoolean(arc::prefs::kVoiceInteractionHotwordEnabled)) { + // Turn on hotword will restart the Assistant service. Thus the enrollment + // request should be sent after the service restart complete. + voice_enrollment_pending = true; + prefs->SetBoolean(arc::prefs::kVoiceInteractionHotwordEnabled, true); + arc::VoiceInteractionControllerClient::Get()->AddObserver(this); + } else { + settings_manager_->StartSpeakerIdEnrollment(true, std::move(client_ptr_)); + } } } @@ -475,6 +508,12 @@ void AssistantOptInFlowScreenHandler::HandleFlowFinished() { CallJSWithPrefix("closeDialog"); } -void AssistantOptInFlowScreenHandler::HandleFlowInitialized() {} +void AssistantOptInFlowScreenHandler::HandleFlowInitialized() { + initialized_ = true; + + if (settings_manager_.is_bound()) { + SendGetSettingsRequest(); + } +} } // namespace chromeos diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h index fbdc367dc661a..2491cab2adb8b 100644 --- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h @@ -118,6 +118,12 @@ class AssistantOptInFlowScreenHandler // Counter for the number of loading timeout happens. int loading_timeout_counter_ = 0; + // Whether the screen has been initialized. + bool initialized_ = false; + + // Whether there is a pending voice match enrollment request. + bool voice_enrollment_pending = false; + mojo::Binding client_binding_; assistant::mojom::SpeakerIdEnrollmentClientPtr client_ptr_; assistant::mojom::AssistantSettingsManagerPtr settings_manager_; diff --git a/chromeos/services/assistant/assistant_manager_service_impl.cc b/chromeos/services/assistant/assistant_manager_service_impl.cc index f6a2861a13955..e3545379240af 100644 --- a/chromeos/services/assistant/assistant_manager_service_impl.cc +++ b/chromeos/services/assistant/assistant_manager_service_impl.cc @@ -23,6 +23,7 @@ #include "chromeos/assistant/internal/internal_util.h" #include "chromeos/assistant/internal/proto/google3/assistant/api/client_op/device_args.pb.h" #include "chromeos/dbus/util/version_loader.h" +#include "chromeos/services/assistant/public/features.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" @@ -74,7 +75,8 @@ void UpdateInternalOptions( assistant_client::AssistantManagerInternal* assistant_manager_internal, const std::string& arc_version, const std::string& locale, - bool spoken_feedback_enabled) { + bool spoken_feedback_enabled, + bool speaker_enrollment_done) { // Build user agent string. std::string user_agent; base::StringAppendF(&user_agent, @@ -93,6 +95,12 @@ void UpdateInternalOptions( assistant_manager_internal->CreateDefaultInternalOptions(); SetAssistantOptions(internal_options, user_agent, locale, spoken_feedback_enabled); + + if (base::FeatureList::IsEnabled(assistant::features::kAssistantVoiceMatch) && + speaker_enrollment_done) { + internal_options->EnableRequireVoiceMatchVerification(); + } + assistant_manager_internal->SetOptions(*internal_options, [](bool success) { DVLOG(2) << "set options: " << success; }); @@ -780,7 +788,7 @@ AssistantManagerServiceImpl::StartAssistantInternal( UnwrapAssistantManagerInternal(assistant_manager.get()); UpdateInternalOptions(assistant_manager_internal, arc_version, locale, - spoken_feedback_enabled); + spoken_feedback_enabled, speaker_id_enrollment_done_); assistant_manager_internal->SetDisplayConnection(display_connection_.get()); assistant_manager_internal->RegisterActionModule(action_module_.get()); @@ -819,8 +827,32 @@ void AssistantManagerServiceImpl::PostInitAssistant( std::move(post_init_callback).Run(); UpdateDeviceSettings(); + SyncSpeakerIdEnrollmentStatus(); } +void AssistantManagerServiceImpl::SyncSpeakerIdEnrollmentStatus() { + DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); + 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_internal_->StartSpeakerIdEnrollment( + client_config, + [weak_ptr = weak_factory_.GetWeakPtr(), + task_runner = main_thread_task_runner_]( + const assistant_client::SpeakerIdEnrollmentUpdate& update) { + task_runner->PostTask( + FROM_HERE, base::BindOnce(&AssistantManagerServiceImpl:: + HandleSpeakerIdEnrollmentStatusSync, + weak_ptr, update)); + }); +} void AssistantManagerServiceImpl::UpdateDeviceSettings() { DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); @@ -875,6 +907,14 @@ void AssistantManagerServiceImpl::HandleSpeakerIdEnrollmentUpdate( break; case SpeakerIdEnrollmentState::DONE: speaker_id_enrollment_client_->OnSpeakerIdEnrollmentDone(); + if (!speaker_id_enrollment_done_) { + speaker_id_enrollment_done_ = true; + UpdateInternalOptions(assistant_manager_internal_, + chromeos::version_loader::GetARCVersion(), + service_->assistant_state()->locale().value(), + spoken_feedback_enabled_, + speaker_id_enrollment_done_); + } break; case SpeakerIdEnrollmentState::FAILURE: speaker_id_enrollment_client_->OnSpeakerIdEnrollmentFailure(); @@ -887,6 +927,33 @@ void AssistantManagerServiceImpl::HandleSpeakerIdEnrollmentUpdate( } } +void AssistantManagerServiceImpl::HandleSpeakerIdEnrollmentStatusSync( + const assistant_client::SpeakerIdEnrollmentUpdate& update) { + 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()); + break; + case SpeakerIdEnrollmentState::DONE: + speaker_id_enrollment_done_ = true; + UpdateInternalOptions(assistant_manager_internal_, + chromeos::version_loader::GetARCVersion(), + service_->assistant_state()->locale().value(), + spoken_feedback_enabled_, + speaker_id_enrollment_done_); + break; + case SpeakerIdEnrollmentState::PROCESS: + case SpeakerIdEnrollmentState::FAILURE: + case SpeakerIdEnrollmentState::INIT: + case SpeakerIdEnrollmentState::CHECK: + case SpeakerIdEnrollmentState::UPLOAD: + case SpeakerIdEnrollmentState::FETCH: + break; + } +} + void AssistantManagerServiceImpl::HandleStopSpeakerIdEnrollment( base::RepeatingCallback callback) { speaker_id_enrollment_client_.reset(); @@ -1129,10 +1196,10 @@ void AssistantManagerServiceImpl::OnAccessibilityStatusChanged( // When |spoken_feedback_enabled_| changes we need to update our internal // options to turn on/off A11Y features in LibAssistant. if (assistant_manager_internal_) - UpdateInternalOptions(assistant_manager_internal_, - chromeos::version_loader::GetARCVersion(), - service_->assistant_state()->locale().value(), - spoken_feedback_enabled_); + UpdateInternalOptions( + assistant_manager_internal_, chromeos::version_loader::GetARCVersion(), + service_->assistant_state()->locale().value(), spoken_feedback_enabled_, + speaker_id_enrollment_done_); } void AssistantManagerServiceImpl::CacheAssistantStructure( diff --git a/chromeos/services/assistant/assistant_manager_service_impl.h b/chromeos/services/assistant/assistant_manager_service_impl.h index f06afa4afd210..1bccd499a297c 100644 --- a/chromeos/services/assistant/assistant_manager_service_impl.h +++ b/chromeos/services/assistant/assistant_manager_service_impl.h @@ -160,6 +160,9 @@ class AssistantManagerServiceImpl // Update device id, type and locale void UpdateDeviceSettings(); + // Sync speaker id enrollment status. + void SyncSpeakerIdEnrollmentStatus(); + void HandleGetSettingsResponse( base::RepeatingCallback callback, const std::string& settings); @@ -169,6 +172,8 @@ class AssistantManagerServiceImpl void HandleSpeakerIdEnrollmentUpdate( const assistant_client::SpeakerIdEnrollmentUpdate& update); void HandleStopSpeakerIdEnrollment(base::RepeatingCallback callback); + void HandleSpeakerIdEnrollmentStatusSync( + const assistant_client::SpeakerIdEnrollmentUpdate& update); void OnConversationTurnStartedOnMainThread(bool is_mic_open); void OnConversationTurnFinishedOnMainThread( @@ -231,6 +236,9 @@ class AssistantManagerServiceImpl bool spoken_feedback_enabled_ = false; + // Whether the speaker id enrollment has complete for the user. + bool speaker_id_enrollment_done_ = false; + ax::mojom::AssistantExtraPtr assistant_extra_; std::unique_ptr assistant_tree_; std::vector assistant_screenshot_;