1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.h"
6 
7 #include <utility>
8 
9 #include "base/metrics/histogram_macros.h"
10 #include "chrome/browser/consent_auditor/consent_auditor_factory.h"
11 #include "chrome/browser/signin/identity_manager_factory.h"
12 #include "chrome/browser/ui/webui/chromeos/user_image_source.h"
13 #include "chrome/grit/browser_resources.h"
14 #include "chrome/grit/generated_resources.h"
15 #include "chromeos/audio/cras_audio_handler.h"
16 #include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
17 #include "chromeos/services/assistant/public/features.h"
18 #include "components/arc/arc_prefs.h"
19 #include "components/consent_auditor/consent_auditor.h"
20 #include "components/prefs/pref_service.h"
21 #include "components/signin/public/identity_manager/consent_level.h"
22 #include "components/signin/public/identity_manager/identity_manager.h"
23 #include "components/user_manager/user_manager.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/base/webui/web_ui_util.h"
26 
27 namespace {
28 
IsPreferenceDefaultEnabled(const PrefService * prefs,const std::string & path)29 bool IsPreferenceDefaultEnabled(const PrefService* prefs,
30                                 const std::string& path) {
31   const PrefService::Preference* pref = prefs->FindPreference(path);
32 
33   if (pref->IsManaged())
34     return pref->GetValue()->GetBool();
35 
36   if (pref->GetRecommendedValue())
37     return pref->GetRecommendedValue()->GetBool();
38 
39   return true;
40 }
41 
IsScreenContextDefaultEnabled(PrefService * prefs)42 bool IsScreenContextDefaultEnabled(PrefService* prefs) {
43   return IsPreferenceDefaultEnabled(
44       prefs, chromeos::assistant::prefs::kAssistantContextEnabled);
45 }
46 
IsScreenContextToggleDisabled(PrefService * prefs)47 bool IsScreenContextToggleDisabled(PrefService* prefs) {
48   return prefs->IsManagedPreference(
49       chromeos::assistant::prefs::kAssistantContextEnabled);
50 }
51 
52 }  // namespace
53 
54 namespace chromeos {
55 
RecordAssistantOptInStatus(AssistantOptInFlowStatus status)56 void RecordAssistantOptInStatus(AssistantOptInFlowStatus status) {
57   UMA_HISTOGRAM_ENUMERATION("Assistant.OptInFlowStatus", status, kMaxValue + 1);
58 }
59 
60 // Construct SettingsUiSelector for the ConsentFlow UI.
GetSettingsUiSelector()61 assistant::SettingsUiSelector GetSettingsUiSelector() {
62   assistant::SettingsUiSelector selector;
63   assistant::ConsentFlowUiSelector* consent_flow_ui =
64       selector.mutable_consent_flow_ui_selector();
65   consent_flow_ui->set_flow_id(assistant::ActivityControlSettingsUiSelector::
66                                    ASSISTANT_SUW_ONBOARDING_ON_CHROME_OS);
67   selector.set_email_opt_in(true);
68   selector.set_gaia_user_context_ui(true);
69   return selector;
70 }
71 
72 // Construct SettingsUiUpdate for user opt-in.
GetSettingsUiUpdate(const std::string & consent_token)73 assistant::SettingsUiUpdate GetSettingsUiUpdate(
74     const std::string& consent_token) {
75   assistant::SettingsUiUpdate update;
76   assistant::ConsentFlowUiUpdate* consent_flow_update =
77       update.mutable_consent_flow_ui_update();
78   consent_flow_update->set_flow_id(
79       assistant::ActivityControlSettingsUiSelector::
80           ASSISTANT_SUW_ONBOARDING_ON_CHROME_OS);
81   consent_flow_update->set_consent_token(consent_token);
82 
83   return update;
84 }
85 
86 // Construct SettingsUiUpdate for email opt-in.
GetEmailOptInUpdate(bool opted_in)87 assistant::SettingsUiUpdate GetEmailOptInUpdate(bool opted_in) {
88   assistant::SettingsUiUpdate update;
89   assistant::EmailOptInUpdate* email_optin_update =
90       update.mutable_email_opt_in_update();
91   email_optin_update->set_email_opt_in_update_state(
92       opted_in ? assistant::EmailOptInUpdate::OPT_IN
93                : assistant::EmailOptInUpdate::OPT_OUT);
94 
95   return update;
96 }
97 
98 // Helper method to create zippy data.
CreateZippyData(const SettingZippyList & zippy_list)99 base::Value CreateZippyData(const SettingZippyList& zippy_list) {
100   base::Value zippy_data(base::Value::Type::LIST);
101   for (auto& setting_zippy : zippy_list) {
102     base::Value data(base::Value::Type::DICTIONARY);
103     data.SetKey("title", base::Value(setting_zippy.title()));
104     if (setting_zippy.description_paragraph_size()) {
105       data.SetKey("description",
106                   base::Value(setting_zippy.description_paragraph(0)));
107     }
108     if (setting_zippy.additional_info_paragraph_size()) {
109       data.SetKey("additionalInfo",
110                   base::Value(setting_zippy.additional_info_paragraph(0)));
111     }
112     data.SetKey("iconUri", base::Value(setting_zippy.icon_uri()));
113     data.SetKey("popupLink", base::Value(l10n_util::GetStringUTF16(
114                                  IDS_ASSISTANT_ACTIVITY_CONTROL_POPUP_LINK)));
115     zippy_data.Append(std::move(data));
116   }
117   return zippy_data;
118 }
119 
120 // Helper method to create disclosure data.
CreateDisclosureData(const SettingZippyList & disclosure_list)121 base::Value CreateDisclosureData(const SettingZippyList& disclosure_list) {
122   base::Value disclosure_data(base::Value::Type::LIST);
123   for (auto& disclosure : disclosure_list) {
124     base::Value data(base::Value::Type::DICTIONARY);
125     data.SetKey("title", base::Value(disclosure.title()));
126     if (disclosure.description_paragraph_size()) {
127       data.SetKey("description",
128                   base::Value(disclosure.description_paragraph(0)));
129     }
130     if (disclosure.additional_info_paragraph_size()) {
131       data.SetKey("additionalInfo",
132                   base::Value(disclosure.additional_info_paragraph(0)));
133     }
134     data.SetKey("iconUri", base::Value(disclosure.icon_uri()));
135     disclosure_data.Append(std::move(data));
136   }
137   return disclosure_data;
138 }
139 
140 // Helper method to create get more screen data.
CreateGetMoreData(bool email_optin_needed,const assistant::EmailOptInUi & email_optin_ui,PrefService * prefs)141 base::Value CreateGetMoreData(bool email_optin_needed,
142                               const assistant::EmailOptInUi& email_optin_ui,
143                               PrefService* prefs) {
144   base::Value get_more_data(base::Value::Type::LIST);
145 
146   // Process screen context data.
147   base::Value context_data(base::Value::Type::DICTIONARY);
148   context_data.SetKey("id", base::Value("context"));
149   context_data.SetKey("title", base::Value(l10n_util::GetStringUTF16(
150                                    IDS_ASSISTANT_SCREEN_CONTEXT_TITLE)));
151   context_data.SetKey("description", base::Value(l10n_util::GetStringUTF16(
152                                          IDS_ASSISTANT_SCREEN_CONTEXT_DESC)));
153   context_data.SetKey("defaultEnabled",
154                       base::Value(IsScreenContextDefaultEnabled(prefs)));
155   context_data.SetKey("toggleDisabled",
156                       base::Value(IsScreenContextToggleDisabled(prefs)));
157   context_data.SetKey(
158       "iconUri",
159       base::Value("https://www.gstatic.com/images/icons/material/system/"
160                   "2x/screen_search_desktop_grey600_24dp.png"));
161   get_more_data.Append(std::move(context_data));
162 
163   // Process email optin data.
164   if (email_optin_needed) {
165     base::Value data(base::Value::Type::DICTIONARY);
166     data.SetKey("id", base::Value("email"));
167     data.SetKey("title", base::Value(email_optin_ui.title()));
168     data.SetKey("description", base::Value(email_optin_ui.description()));
169     data.SetKey("defaultEnabled",
170                 base::Value(email_optin_ui.default_enabled()));
171     data.SetKey("iconUri", base::Value(email_optin_ui.icon_uri()));
172     data.SetKey("legalText", base::Value(email_optin_ui.legal_text()));
173     get_more_data.Append(std::move(data));
174   }
175 
176   return get_more_data;
177 }
178 
179 // Get string constants for settings ui.
GetSettingsUiStrings(const assistant::SettingsUi & settings_ui,bool activity_control_needed)180 base::Value GetSettingsUiStrings(const assistant::SettingsUi& settings_ui,
181                                  bool activity_control_needed) {
182   auto consent_ui = settings_ui.consent_flow_ui().consent_ui();
183   auto activity_control_ui = consent_ui.activity_control_ui();
184   auto third_party_disclosure_ui = consent_ui.third_party_disclosure_ui();
185   base::Value dictionary(base::Value::Type::DICTIONARY);
186 
187   // Add activity control string constants.
188   if (activity_control_needed) {
189     scoped_refptr<base::RefCountedMemory> image =
190         chromeos::UserImageSource::GetUserImage(
191             user_manager::UserManager::Get()->GetActiveUser()->GetAccountId());
192     std::string icon_url = webui::GetPngDataUrl(image->front(), image->size());
193     dictionary.SetKey("valuePropUserImage", base::Value(icon_url));
194 
195     dictionary.SetKey("valuePropIdentity",
196                       base::Value(activity_control_ui.identity()));
197     dictionary.SetKey("valuePropTitle",
198                       base::Value(activity_control_ui.title()));
199     if (activity_control_ui.intro_text_paragraph_size()) {
200       dictionary.SetKey(
201           "valuePropIntro",
202           base::Value(activity_control_ui.intro_text_paragraph(0)));
203     }
204     if (activity_control_ui.footer_paragraph_size()) {
205       dictionary.SetKey("valuePropFooter",
206                         base::Value(activity_control_ui.footer_paragraph(0)));
207     }
208     dictionary.SetKey("valuePropNextButton",
209                       base::Value(consent_ui.accept_button_text()));
210     dictionary.SetKey("valuePropSkipButton",
211                       base::Value(consent_ui.reject_button_text()));
212   }
213 
214   // Add third party string constants.
215   dictionary.SetKey("thirdPartyTitle",
216                     base::Value(third_party_disclosure_ui.title()));
217   dictionary.SetKey("thirdPartyContinueButton",
218                     base::Value(third_party_disclosure_ui.button_continue()));
219   dictionary.SetKey("thirdPartyFooter", base::Value(consent_ui.tos_pp_links()));
220 
221   return dictionary;
222 }
223 
RecordActivityControlConsent(Profile * profile,std::string ui_audit_key,bool opted_in)224 void RecordActivityControlConsent(Profile* profile,
225                                   std::string ui_audit_key,
226                                   bool opted_in) {
227   auto* identity_manager = IdentityManagerFactory::GetForProfile(profile);
228   // This function doesn't care about browser sync consent.
229   DCHECK(
230       identity_manager->HasPrimaryAccount(signin::ConsentLevel::kNotRequired));
231   const CoreAccountId account_id =
232       identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kNotRequired);
233 
234   using sync_pb::UserConsentTypes;
235   UserConsentTypes::AssistantActivityControlConsent consent;
236   consent.set_ui_audit_key(ui_audit_key);
237   consent.set_status(opted_in ? UserConsentTypes::GIVEN
238                               : UserConsentTypes::NOT_GIVEN);
239 
240   ConsentAuditorFactory::GetForProfile(profile)
241       ->RecordAssistantActivityControlConsent(account_id, consent);
242 }
243 
IsHotwordDspAvailable()244 bool IsHotwordDspAvailable() {
245   return chromeos::CrasAudioHandler::Get()->HasHotwordDevice();
246 }
247 
IsVoiceMatchEnforcedOff(const PrefService * prefs)248 bool IsVoiceMatchEnforcedOff(const PrefService* prefs) {
249   // If the hotword preference is managed to always disabled, then we should not
250   // show Voice Match flow.
251   return prefs->IsManagedPreference(
252              assistant::prefs::kAssistantHotwordEnabled) &&
253          !prefs->GetBoolean(assistant::prefs::kAssistantHotwordEnabled);
254 }
255 
256 }  // namespace chromeos
257