blob: cdd7956133ccec6225c6b93882cbb7863c75a999 [file] [log] [blame]
// 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 "chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h"
#include <utility>
#include "ash/constants/ash_features.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/metrics/histogram_macros.h"
#include "chrome/browser/ash/login/oobe_screen.h"
#include "chrome/browser/ash/login/screens/assistant_optin_flow_screen.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.h"
#include "chrome/grit/generated_resources.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
#include "chromeos/services/assistant/public/cpp/assistant_service.h"
#include "chromeos/services/assistant/public/cpp/features.h"
#include "chromeos/services/assistant/public/proto/get_settings_ui.pb.h"
#include "chromeos/services/assistant/public/proto/settings_ui.pb.h"
#include "components/login/localized_values_builder.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/user_manager.h"
#include "ui/chromeos/devicetype_utils.h"
namespace chromeos {
namespace {
constexpr char kSkipPressed[] = "skip-pressed";
constexpr char kNextPressed[] = "next-pressed";
constexpr char kRecordPressed[] = "record-pressed";
constexpr char kFlowFinished[] = "flow-finished";
constexpr char kReloadRequested[] = "reload-requested";
constexpr char kVoiceMatchDone[] = "voice-match-done";
bool IsKnownEnumValue(ash::FlowType flow_type) {
return flow_type == ash::FlowType::kConsentFlow ||
flow_type == ash::FlowType::kSpeakerIdEnrollment ||
flow_type == ash::FlowType::kSpeakerIdRetrain;
}
} // namespace
constexpr StaticOobeScreenId AssistantOptInFlowScreenView::kScreenId;
AssistantOptInFlowScreenHandler::AssistantOptInFlowScreenHandler(
JSCallsContainer* js_calls_container)
: BaseScreenHandler(kScreenId, js_calls_container) {
set_user_acted_method_path("login.AssistantOptInFlowScreen.userActed");
}
AssistantOptInFlowScreenHandler::~AssistantOptInFlowScreenHandler() {
if (assistant::AssistantSettings::Get() && voice_match_enrollment_started_)
StopSpeakerIdEnrollment();
if (ash::AssistantState::Get())
ash::AssistantState::Get()->RemoveObserver(this);
if (screen_)
screen_->OnViewDestroyed(this);
}
void AssistantOptInFlowScreenHandler::DeclareLocalizedValues(
::login::LocalizedValuesBuilder* builder) {
builder->Add("assistantLogo", IDS_ASSISTANT_LOGO);
builder->Add("assistantOptinLoading", IDS_ASSISTANT_OPT_IN_LOADING);
builder->Add("assistantOptinLoadErrorTitle",
IDS_ASSISTANT_OPT_IN_LOAD_ERROR_TITLE);
builder->Add("assistantOptinLoadErrorMessage",
IDS_ASSISTANT_OPT_IN_LOAD_ERROR_MESSAGE);
builder->Add("assistantOptinSkipButton", IDS_ASSISTANT_OPT_IN_SKIP_BUTTON);
builder->Add("assistantOptinRetryButton", IDS_ASSISTANT_OPT_IN_RETRY_BUTTON);
builder->Add("assistantUserImage", IDS_ASSISTANT_OOBE_USER_IMAGE);
builder->Add("assistantRelatedInfoTitle",
IDS_ASSISTANT_RELATED_INFO_SCREEN_TITLE);
builder->Add("assistantRelatedInfoMessage",
IDS_ASSISTANT_RELATED_INFO_SCREEN_MESSAGE);
builder->Add("assistantRelatedInfoReturnedUserTitle",
IDS_ASSISTANT_RELATED_INFO_SCREEN_RETURNED_USER_TITLE);
builder->Add("assistantRelatedInfoReturnedUserMessage",
IDS_ASSISTANT_RELATED_INFO_SCREEN_RETURNED_USER_MESSAGE);
builder->Add("assistantScreenContextTitle",
IDS_ASSISTANT_SCREEN_CONTEXT_TITLE);
builder->Add("assistantScreenContextDesc", IDS_ASSISTANT_SCREEN_CONTEXT_DESC);
builder->Add("assistantVoiceMatchTitle", IDS_ASSISTANT_VOICE_MATCH_TITLE);
builder->Add("assistantVoiceMatchMessage",
chromeos::IsHotwordDspAvailable() || !DeviceHasBattery()
? IDS_ASSISTANT_VOICE_MATCH_MESSAGE
: IDS_ASSISTANT_VOICE_MATCH_NO_DSP_MESSAGE);
builder->Add("assistantVoiceMatchRecording",
IDS_ASSISTANT_VOICE_MATCH_RECORDING);
builder->Add("assistantVoiceMatchCompleted",
IDS_ASSISTANT_VOICE_MATCH_COMPLETED);
builder->Add("assistantVoiceMatchFooter", IDS_ASSISTANT_VOICE_MATCH_FOOTER);
builder->Add("assistantVoiceMatchInstruction0",
IDS_ASSISTANT_VOICE_MATCH_INSTRUCTION0);
builder->Add("assistantVoiceMatchInstruction1",
IDS_ASSISTANT_VOICE_MATCH_INSTRUCTION1);
builder->Add("assistantVoiceMatchInstruction2",
IDS_ASSISTANT_VOICE_MATCH_INSTRUCTION2);
builder->Add("assistantVoiceMatchInstruction3",
IDS_ASSISTANT_VOICE_MATCH_INSTRUCTION3);
builder->Add("assistantVoiceMatchComplete",
IDS_ASSISTANT_VOICE_MATCH_COMPLETE);
builder->Add("assistantVoiceMatchUploading",
IDS_ASSISTANT_VOICE_MATCH_UPLOADING);
builder->Add("assistantVoiceMatchA11yMessage",
IDS_ASSISTANT_VOICE_MATCH_ACCESSIBILITY_MESSAGE);
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->AddF("assistantReadyMessage", IDS_ASSISTANT_READY_SCREEN_MESSAGE,
ui::GetChromeOSDeviceName());
builder->Add("assistantReadyButton", IDS_ASSISTANT_DONE_BUTTON);
builder->Add("back", IDS_EULA_BACK_BUTTON);
builder->Add("next", IDS_EULA_NEXT_BUTTON);
builder->Add("assistantOobePopupOverlayLoading",
IDS_ASSISTANT_OOBE_POPUP_OVERLAY_LOADING);
}
void AssistantOptInFlowScreenHandler::RegisterMessages() {
AddCallback(
"login.AssistantOptInFlowScreen.ValuePropScreen.userActed",
&AssistantOptInFlowScreenHandler::HandleValuePropScreenUserAction);
AddCallback(
"login.AssistantOptInFlowScreen.RelatedInfoScreen.userActed",
&AssistantOptInFlowScreenHandler::HandleRelatedInfoScreenUserAction);
AddCallback(
"login.AssistantOptInFlowScreen.ThirdPartyScreen.userActed",
&AssistantOptInFlowScreenHandler::HandleThirdPartyScreenUserAction);
AddCallback(
"login.AssistantOptInFlowScreen.VoiceMatchScreen.userActed",
&AssistantOptInFlowScreenHandler::HandleVoiceMatchScreenUserAction);
AddCallback("login.AssistantOptInFlowScreen.GetMoreScreen.userActed",
&AssistantOptInFlowScreenHandler::HandleGetMoreScreenUserAction);
AddCallback("login.AssistantOptInFlowScreen.ValuePropScreen.screenShown",
&AssistantOptInFlowScreenHandler::HandleValuePropScreenShown);
AddCallback("login.AssistantOptInFlowScreen.RelatedInfoScreen.screenShown",
&AssistantOptInFlowScreenHandler::HandleRelatedInfoScreenShown);
AddCallback("login.AssistantOptInFlowScreen.ThirdPartyScreen.screenShown",
&AssistantOptInFlowScreenHandler::HandleThirdPartyScreenShown);
AddCallback("login.AssistantOptInFlowScreen.VoiceMatchScreen.screenShown",
&AssistantOptInFlowScreenHandler::HandleVoiceMatchScreenShown);
AddCallback("login.AssistantOptInFlowScreen.GetMoreScreen.screenShown",
&AssistantOptInFlowScreenHandler::HandleGetMoreScreenShown);
AddCallback("login.AssistantOptInFlowScreen.timeout",
&AssistantOptInFlowScreenHandler::HandleLoadingTimeout);
AddCallback("login.AssistantOptInFlowScreen.flowFinished",
&AssistantOptInFlowScreenHandler::HandleFlowFinished);
AddCallback("login.AssistantOptInFlowScreen.initialized",
&AssistantOptInFlowScreenHandler::HandleFlowInitialized);
}
void AssistantOptInFlowScreenHandler::GetAdditionalParameters(
base::DictionaryValue* dict) {
dict->SetBoolean("voiceMatchDisabled",
chromeos::assistant::features::IsVoiceMatchDisabled());
dict->SetBoolean("betterAssistantEnabled",
chromeos::assistant::features::IsBetterAssistantEnabled());
BaseScreenHandler::GetAdditionalParameters(dict);
}
void AssistantOptInFlowScreenHandler::Bind(AssistantOptInFlowScreen* screen) {
BaseScreenHandler::SetBaseScreen(screen);
screen_ = screen;
if (page_is_ready())
Initialize();
}
void AssistantOptInFlowScreenHandler::Unbind() {
screen_ = nullptr;
BaseScreenHandler::SetBaseScreen(nullptr);
}
void AssistantOptInFlowScreenHandler::Show() {
if (!page_is_ready() || !screen_) {
show_on_init_ = true;
return;
}
SetupAssistantConnection();
ShowScreen(kScreenId);
}
void AssistantOptInFlowScreenHandler::Hide() {}
void AssistantOptInFlowScreenHandler::Initialize() {
if (!screen_ || !show_on_init_)
return;
Show();
show_on_init_ = false;
}
void AssistantOptInFlowScreenHandler::OnListeningHotword() {
CallJS("login.AssistantOptInFlowScreen.onVoiceMatchUpdate",
base::Value("listen"));
}
void AssistantOptInFlowScreenHandler::OnProcessingHotword() {
CallJS("login.AssistantOptInFlowScreen.onVoiceMatchUpdate",
base::Value("process"));
}
void AssistantOptInFlowScreenHandler::OnSpeakerIdEnrollmentDone() {
StopSpeakerIdEnrollment();
CallJS("login.AssistantOptInFlowScreen.onVoiceMatchUpdate",
base::Value("done"));
}
void AssistantOptInFlowScreenHandler::OnSpeakerIdEnrollmentFailure() {
StopSpeakerIdEnrollment();
RecordAssistantOptInStatus(VOICE_MATCH_ENROLLMENT_ERROR);
CallJS("login.AssistantOptInFlowScreen.onVoiceMatchUpdate",
base::Value("failure"));
LOG(ERROR) << "Speaker ID enrollment failure.";
}
void AssistantOptInFlowScreenHandler::SetupAssistantConnection() {
PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
// If Assistant is disabled by domain admin, end the flow.
if (prefs->GetBoolean(assistant::prefs::kAssistantDisabledByPolicy)) {
HandleFlowFinished();
return;
}
// Make sure enable Assistant service since we need it during the flow.
prefs->SetBoolean(chromeos::assistant::prefs::kAssistantEnabled, true);
if (ash::AssistantState::Get()->assistant_status() ==
chromeos::assistant::AssistantStatus::NOT_READY) {
ash::AssistantState::Get()->AddObserver(this);
} else {
SendGetSettingsRequest();
}
}
void AssistantOptInFlowScreenHandler::ShowNextScreen() {
CallJS("login.AssistantOptInFlowScreen.showNextScreen");
}
void AssistantOptInFlowScreenHandler::OnActivityControlOptInResult(
bool opted_in) {
Profile* profile = ProfileManager::GetActiveUserProfile();
auto data = pending_consent_data_.front();
pending_consent_data_.pop_front();
// TODO(https://crbug.com/1223797): record activity control setting type.
RecordActivityControlConsent(profile, data.ui_audit_key, opted_in);
if (opted_in) {
has_opted_in_any_consent_ = true;
// TODO(https://crbug.com/1224850): differentiate which activity control is
// accepted.
RecordAssistantOptInStatus(ACTIVITY_CONTROL_ACCEPTED);
assistant::AssistantSettings::Get()->UpdateSettings(
GetSettingsUiUpdate(data.consent_token).SerializeAsString(),
base::BindOnce(
&AssistantOptInFlowScreenHandler::OnUpdateSettingsResponse,
weak_factory_.GetWeakPtr()));
} else {
has_opted_out_any_consent_ = true;
// TODO(https://crbug.com/1224850): differentiate which activity control is
// skipped.
RecordAssistantOptInStatus(ACTIVITY_CONTROL_SKIPPED);
profile->GetPrefs()->SetInteger(assistant::prefs::kAssistantConsentStatus,
assistant::prefs::ConsentStatus::kUnknown);
if (pending_consent_data_.empty()) {
if (has_opted_in_any_consent_) {
ShowNextScreen();
} else {
HandleFlowFinished();
}
} else {
UpdateValuePropScreen();
}
}
}
void AssistantOptInFlowScreenHandler::OnScreenContextOptInResult(
bool opted_in) {
RecordAssistantOptInStatus(opted_in ? RELATED_INFO_ACCEPTED
: RELATED_INFO_SKIPPED);
PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
prefs->SetBoolean(assistant::prefs::kAssistantContextEnabled, opted_in);
}
void AssistantOptInFlowScreenHandler::OnEmailOptInResult(bool opted_in) {
if (!email_optin_needed_) {
DCHECK(!opted_in);
HandleFlowFinished();
return;
}
// TODO(b/159363597): Handle network disconnect when sending email opt-in
// result.
RecordAssistantOptInStatus(opted_in ? EMAIL_OPTED_IN : EMAIL_OPTED_OUT);
assistant::AssistantSettings::Get()->UpdateSettings(
GetEmailOptInUpdate(opted_in).SerializeAsString(),
base::BindOnce(&AssistantOptInFlowScreenHandler::OnUpdateSettingsResponse,
weak_factory_.GetWeakPtr()));
HandleFlowFinished();
}
void AssistantOptInFlowScreenHandler::OnDialogClosed() {
// Disable hotword for user if voice match enrollment has not completed.
if (!voice_match_enrollment_done_ &&
flow_type_ == ash::FlowType::kSpeakerIdEnrollment) {
ProfileManager::GetActiveUserProfile()->GetPrefs()->SetBoolean(
assistant::prefs::kAssistantHotwordEnabled, false);
}
}
void AssistantOptInFlowScreenHandler::OnAssistantSettingsEnabled(bool enabled) {
// Close the opt-in screen is the Assistant is disabled.
if (!enabled)
HandleFlowFinished();
}
void AssistantOptInFlowScreenHandler::OnAssistantStatusChanged(
chromeos::assistant::AssistantStatus status) {
if (status != chromeos::assistant::AssistantStatus::NOT_READY) {
SendGetSettingsRequest();
ash::AssistantState::Get()->RemoveObserver(this);
}
}
void AssistantOptInFlowScreenHandler::SendGetSettingsRequest() {
if (!initialized_)
return;
if (ash::AssistantState::Get()->assistant_status() ==
chromeos::assistant::AssistantStatus::NOT_READY) {
return;
}
assistant::SettingsUiSelector selector = GetSettingsUiSelector();
assistant::AssistantSettings::Get()->GetSettingsWithHeader(
selector.SerializeAsString(),
base::BindOnce(&AssistantOptInFlowScreenHandler::OnGetSettingsResponse,
weak_factory_.GetWeakPtr()));
send_request_time_ = base::TimeTicks::Now();
}
void AssistantOptInFlowScreenHandler::StopSpeakerIdEnrollment() {
DCHECK(voice_match_enrollment_started_);
voice_match_enrollment_started_ = false;
assistant::AssistantSettings::Get()->StopSpeakerIdEnrollment();
}
void AssistantOptInFlowScreenHandler::ReloadContent(const base::Value& dict) {
CallJS("login.AssistantOptInFlowScreen.reloadContent", dict);
}
void AssistantOptInFlowScreenHandler::AddSettingZippy(const std::string& type,
const base::Value& data) {
CallJS("login.AssistantOptInFlowScreen.addSettingZippy", type, data);
}
void AssistantOptInFlowScreenHandler::UpdateValuePropScreen() {
CallJS("login.AssistantOptInFlowScreen.onValuePropUpdate");
}
void AssistantOptInFlowScreenHandler::OnGetSettingsResponse(
const std::string& response) {
const base::TimeDelta time_since_request_sent =
base::TimeTicks::Now() - send_request_time_;
UMA_HISTOGRAM_TIMES("Assistant.OptInFlow.GetSettingsRequestTime",
time_since_request_sent);
if (ProfileManager::GetActiveUserProfile()->GetPrefs()->GetBoolean(
assistant::prefs::kAssistantDisabledByPolicy)) {
DVLOG(1) << "Assistant is disabled by domain policy. Skip Assistant "
"opt-in flow.";
HandleFlowFinished();
return;
}
assistant::GetSettingsUiResponse settings_ui_response;
if (!settings_ui_response.ParseFromString(response)) {
LOG(ERROR) << "Failed to parse get settings response.";
HandleFlowFinished();
return;
}
auto settings_ui = settings_ui_response.settings();
auto header = settings_ui_response.header();
bool equal_weight_buttons =
features::IsMinorModeRestrictionEnabled() &&
header.footer_button_layout() ==
assistant::SettingsResponseHeader_AcceptRejectLayout_EQUAL_WEIGHT;
if (settings_ui.has_gaia_user_context_ui()) {
auto gaia_user_context_ui = settings_ui.gaia_user_context_ui();
if (gaia_user_context_ui.assistant_disabled_by_dasher_domain()) {
DVLOG(1) << "Assistant is disabled by domain policy. Skip Assistant "
"opt-in flow.";
PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
prefs->SetBoolean(assistant::prefs::kAssistantDisabledByPolicy, true);
prefs->SetBoolean(chromeos::assistant::prefs::kAssistantEnabled, false);
HandleFlowFinished();
return;
}
if (gaia_user_context_ui.waa_disabled_by_dasher_domain()) {
DVLOG(1) << "Web & app activity is disabled by domain policy. Skip "
"Assistant opt-in flow.";
HandleFlowFinished();
return;
}
}
DCHECK(settings_ui.has_consent_flow_ui());
RecordAssistantOptInStatus(FLOW_STARTED);
auto consent_ui = settings_ui.consent_flow_ui().consent_ui();
auto third_party_disclosure_ui = consent_ui.third_party_disclosure_ui();
base::Value zippy_data(base::Value::Type::LIST);
bool skip_activity_control = true;
pending_consent_data_.clear();
// We read from `multi_consent_ui` field if it is populated and we assume user
// is a minor user; otherwise, we read from `consent_ui` field.
if (features::IsMinorModeRestrictionEnabled() &&
settings_ui.consent_flow_ui().multi_consent_ui().size()) {
auto multi_consent_ui = settings_ui.consent_flow_ui().multi_consent_ui();
for (auto consent_ui : multi_consent_ui) {
auto activity_control_ui = consent_ui.activity_control_ui();
if (activity_control_ui.setting_zippy().size()) {
skip_activity_control = false;
auto data = ConsentData();
data.consent_token = activity_control_ui.consent_token();
data.ui_audit_key = activity_control_ui.ui_audit_key();
pending_consent_data_.push_back(data);
zippy_data.Append(CreateZippyData(activity_control_ui.setting_zippy(),
/*is_minor_mode=*/true));
}
}
} else {
auto activity_control_ui = consent_ui.activity_control_ui();
if (activity_control_ui.setting_zippy().size()) {
skip_activity_control = false;
auto data = ConsentData();
data.consent_token = activity_control_ui.consent_token();
data.ui_audit_key = activity_control_ui.ui_audit_key();
pending_consent_data_.push_back(data);
zippy_data.Append(CreateZippyData(activity_control_ui.setting_zippy(),
/*is_minor_mode=*/false));
}
}
// Process activity control data.
if (skip_activity_control) {
// No need to consent. Move to the next screen.
activity_control_needed_ = false;
PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
bool consented =
settings_ui.consent_flow_ui().consent_status() ==
assistant::ConsentFlowUi_ConsentStatus_ALREADY_CONSENTED ||
settings_ui.consent_flow_ui().consent_status() ==
assistant::ConsentFlowUi_ConsentStatus_ASK_FOR_CONSENT;
prefs->SetInteger(
assistant::prefs::kAssistantConsentStatus,
consented ? assistant::prefs::ConsentStatus::kActivityControlAccepted
: assistant::prefs::ConsentStatus::kUnknown);
} else {
AddSettingZippy("settings", zippy_data);
}
// Process third party disclosure data.
bool skip_third_party_disclosure =
skip_activity_control && !third_party_disclosure_ui.disclosures().size();
if (third_party_disclosure_ui.disclosures().size()) {
AddSettingZippy("disclosure", CreateDisclosureData(
third_party_disclosure_ui.disclosures()));
} else if (!skip_third_party_disclosure) {
// TODO(llin): Show an error message and log it properly.
LOG(ERROR) << "Missing third Party disclosure data.";
return;
}
// Process get more data.
email_optin_needed_ = settings_ui.has_email_opt_in_ui() &&
settings_ui.email_opt_in_ui().has_title();
auto* profile_helper = ProfileHelper::Get();
const auto* user = user_manager::UserManager::Get()->GetActiveUser();
auto get_more_data =
CreateGetMoreData(email_optin_needed_, settings_ui.email_opt_in_ui(),
profile_helper->GetProfileByUser(user)->GetPrefs());
bool skip_get_more =
skip_third_party_disclosure && !get_more_data.GetList().size();
if (get_more_data.GetList().size()) {
AddSettingZippy("get-more", get_more_data);
} else if (!skip_get_more) {
// TODO(llin): Show an error message and log it properly.
LOG(ERROR) << "Missing get more data.";
return;
}
// Pass string constants dictionary.
auto dictionary = GetSettingsUiStrings(settings_ui, activity_control_needed_,
equal_weight_buttons);
PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
dictionary.SetKey("voiceMatchEnforcedOff",
base::Value(IsVoiceMatchEnforcedOff(prefs)));
ReloadContent(dictionary);
// Now that screen's content has been reloaded, skip screens that can be
// skipped - if this is done before content reload, internal screen
// transitions might be based on incorrect data. For example, if both activity
// control and third party disclosure are skipped, opt in flow might skip
// voice match enrollment, thinking that voice match is not enabled.
// Skip activity control and users will be in opted out mode.
if (skip_activity_control)
ShowNextScreen();
if (skip_third_party_disclosure)
ShowNextScreen();
// If voice match is enabled, the screen that follows third party disclosure
// is the "voice match" screen, not "get more" screen.
if (skip_get_more && IsVoiceMatchEnforcedOff(prefs))
ShowNextScreen();
}
void AssistantOptInFlowScreenHandler::OnUpdateSettingsResponse(
const std::string& result) {
assistant::SettingsUiUpdateResult ui_result;
ui_result.ParseFromString(result);
if (ui_result.has_consent_flow_update_result()) {
if (ui_result.consent_flow_update_result().update_status() !=
assistant::ConsentFlowUiUpdateResult::SUCCESS) {
// TODO(updowndta): Handle consent update failure.
LOG(ERROR) << "Consent update error.";
} else if (activity_control_needed_ && pending_consent_data_.empty() &&
!has_opted_out_any_consent_) {
activity_control_needed_ = false;
PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
prefs->SetInteger(
assistant::prefs::kAssistantConsentStatus,
assistant::prefs::ConsentStatus::kActivityControlAccepted);
}
}
if (ui_result.has_email_opt_in_update_result()) {
if (ui_result.email_opt_in_update_result().update_status() !=
assistant::EmailOptInUpdateResult::SUCCESS) {
// TODO(updowndta): Handle email optin update failure.
LOG(ERROR) << "Email OptIn update error.";
}
return;
}
if (pending_consent_data_.empty()) {
ShowNextScreen();
} else {
UpdateValuePropScreen();
}
}
void AssistantOptInFlowScreenHandler::HandleValuePropScreenUserAction(
const std::string& action) {
if (action == kSkipPressed) {
OnActivityControlOptInResult(false);
} else if (action == kNextPressed) {
OnActivityControlOptInResult(true);
} else if (action == kReloadRequested) {
SendGetSettingsRequest();
}
}
void AssistantOptInFlowScreenHandler::HandleRelatedInfoScreenUserAction(
const std::string& action) {
if (action == kSkipPressed) {
OnScreenContextOptInResult(false);
ShowNextScreen();
} else if (action == kNextPressed) {
OnScreenContextOptInResult(true);
ShowNextScreen();
}
}
void AssistantOptInFlowScreenHandler::HandleThirdPartyScreenUserAction(
const std::string& action) {
if (action == kNextPressed) {
RecordAssistantOptInStatus(THIRD_PARTY_CONTINUED);
ShowNextScreen();
}
}
void AssistantOptInFlowScreenHandler::HandleVoiceMatchScreenUserAction(
const std::string& action) {
PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
if (action == kVoiceMatchDone) {
RecordAssistantOptInStatus(VOICE_MATCH_ENROLLMENT_DONE);
voice_match_enrollment_done_ = true;
ShowNextScreen();
} else if (action == kSkipPressed) {
RecordAssistantOptInStatus(VOICE_MATCH_ENROLLMENT_SKIPPED);
if (flow_type_ != ash::FlowType::kSpeakerIdRetrain) {
// No need to disable hotword for retrain flow since user has a model.
prefs->SetBoolean(assistant::prefs::kAssistantHotwordEnabled, false);
}
if (voice_match_enrollment_started_)
StopSpeakerIdEnrollment();
ShowNextScreen();
} else if (action == kRecordPressed) {
if (!prefs->GetBoolean(assistant::prefs::kAssistantHotwordEnabled)) {
prefs->SetBoolean(assistant::prefs::kAssistantHotwordEnabled, true);
}
DCHECK(!voice_match_enrollment_started_);
voice_match_enrollment_started_ = true;
assistant::AssistantSettings::Get()->StartSpeakerIdEnrollment(
flow_type_ == ash::FlowType::kSpeakerIdRetrain,
weak_factory_.GetWeakPtr());
} else if (action == kReloadRequested) {
if (voice_match_enrollment_started_)
StopSpeakerIdEnrollment();
}
}
void AssistantOptInFlowScreenHandler::HandleGetMoreScreenUserAction(
const bool screen_context,
const bool email_opted_in) {
RecordAssistantOptInStatus(GET_MORE_CONTINUED);
PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
prefs->SetBoolean(assistant::prefs::kAssistantContextEnabled, screen_context);
OnEmailOptInResult(email_opted_in);
}
void AssistantOptInFlowScreenHandler::HandleValuePropScreenShown() {
RecordAssistantOptInStatus(ACTIVITY_CONTROL_SHOWN);
}
void AssistantOptInFlowScreenHandler::HandleRelatedInfoScreenShown() {
RecordAssistantOptInStatus(RELATED_INFO_SHOWN);
}
void AssistantOptInFlowScreenHandler::HandleThirdPartyScreenShown() {
RecordAssistantOptInStatus(THIRD_PARTY_SHOWN);
}
void AssistantOptInFlowScreenHandler::HandleVoiceMatchScreenShown() {
RecordAssistantOptInStatus(VOICE_MATCH_SHOWN);
}
void AssistantOptInFlowScreenHandler::HandleGetMoreScreenShown() {
RecordAssistantOptInStatus(GET_MORE_SHOWN);
}
void AssistantOptInFlowScreenHandler::HandleLoadingTimeout() {
++loading_timeout_counter_;
}
void AssistantOptInFlowScreenHandler::HandleFlowFinished() {
auto* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
if (!prefs->GetUserPrefValue(assistant::prefs::kAssistantConsentStatus)) {
// Set consent status to unknown if user consent is needed but not provided.
prefs->SetInteger(
assistant::prefs::kAssistantConsentStatus,
activity_control_needed_
? assistant::prefs::ConsentStatus::kUnknown
: assistant::prefs::ConsentStatus::kActivityControlAccepted);
}
UMA_HISTOGRAM_EXACT_LINEAR("Assistant.OptInFlow.LoadingTimeoutCount",
loading_timeout_counter_, 10);
if (screen_)
screen_->HandleUserAction(kFlowFinished);
else
CallJS("login.AssistantOptInFlowScreen.closeDialog");
}
void AssistantOptInFlowScreenHandler::HandleFlowInitialized(
const int flow_type) {
auto* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
if (!prefs->GetBoolean(chromeos::assistant::prefs::kAssistantEnabled)) {
HandleFlowFinished();
return;
}
initialized_ = true;
if (on_initialized_)
std::move(on_initialized_).Run();
DCHECK(IsKnownEnumValue(static_cast<ash::FlowType>(flow_type)));
flow_type_ = static_cast<ash::FlowType>(flow_type);
if (flow_type_ == ash::FlowType::kConsentFlow)
SendGetSettingsRequest();
}
bool AssistantOptInFlowScreenHandler::DeviceHasBattery() {
// Assume that the device has a battery if we can't determine otherwise.
if (!chromeos::PowerManagerClient::Get())
return true;
auto status = PowerManagerClient::Get()->GetLastStatus();
if (!status.has_value() || !status->has_battery_state())
return true;
return status->battery_state() !=
power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT;
}
} // namespace chromeos