| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/quick_answers/quick_answers_state_ash.h" |
| |
| #include "ash/constants/ash_pref_names.h" |
| #include "ash/session/session_controller_impl.h" |
| #include "ash/shell.h" |
| #include "chromeos/components/quick_answers/utils/quick_answers_metrics.h" |
| #include "components/language/core/browser/pref_names.h" |
| #include "components/prefs/pref_change_registrar.h" |
| #include "components/prefs/pref_service.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| namespace { |
| |
| using quick_answers::prefs::ConsentStatus; |
| using quick_answers::prefs::kQuickAnswersConsentStatus; |
| using quick_answers::prefs::kQuickAnswersDefinitionEnabled; |
| using quick_answers::prefs::kQuickAnswersEnabled; |
| using quick_answers::prefs::kQuickAnswersNoticeImpressionCount; |
| using quick_answers::prefs::kQuickAnswersTranslationEnabled; |
| using quick_answers::prefs::kQuickAnswersUnitConversionEnabled; |
| |
| void IncrementPrefCounter(PrefService* prefs, |
| const std::string& path, |
| int count) { |
| prefs->SetInteger(path, prefs->GetInteger(path) + count); |
| } |
| |
| } // namespace |
| |
| QuickAnswersStateAsh::QuickAnswersStateAsh() : session_observer_(this) { |
| // Register pref changes if use session already started. |
| if (ash::Shell::Get()->session_controller() && |
| ash::Shell::Get()->session_controller()->IsActiveUserSessionStarted()) { |
| PrefService* prefs = |
| ash::Shell::Get()->session_controller()->GetPrimaryUserPrefService(); |
| DCHECK(prefs); |
| RegisterPrefChanges(prefs); |
| } |
| } |
| |
| QuickAnswersStateAsh::~QuickAnswersStateAsh() = default; |
| |
| void QuickAnswersStateAsh::OnFirstSessionStarted() { |
| PrefService* prefs = |
| ash::Shell::Get()->session_controller()->GetPrimaryUserPrefService(); |
| RegisterPrefChanges(prefs); |
| } |
| |
| void QuickAnswersStateAsh::RegisterPrefChanges(PrefService* pref_service) { |
| pref_change_registrar_.reset(); |
| |
| if (!pref_service) |
| return; |
| |
| // Register preference changes. |
| pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>(); |
| pref_change_registrar_->Init(pref_service); |
| pref_change_registrar_->Add( |
| kQuickAnswersEnabled, |
| base::BindRepeating(&QuickAnswersStateAsh::UpdateSettingsEnabled, |
| base::Unretained(this))); |
| pref_change_registrar_->Add( |
| kQuickAnswersConsentStatus, |
| base::BindRepeating(&QuickAnswersStateAsh::UpdateConsentStatus, |
| base::Unretained(this))); |
| pref_change_registrar_->Add( |
| kQuickAnswersDefinitionEnabled, |
| base::BindRepeating(&QuickAnswersStateAsh::UpdateDefinitionEnabled, |
| base::Unretained(this))); |
| pref_change_registrar_->Add( |
| kQuickAnswersTranslationEnabled, |
| base::BindRepeating(&QuickAnswersStateAsh::UpdateTranslationEnabled, |
| base::Unretained(this))); |
| pref_change_registrar_->Add( |
| kQuickAnswersUnitConversionEnabled, |
| base::BindRepeating(&QuickAnswersStateAsh::UpdateUnitConversionEnabled, |
| base::Unretained(this))); |
| pref_change_registrar_->Add( |
| language::prefs::kApplicationLocale, |
| base::BindRepeating(&QuickAnswersStateAsh::OnApplicationLocaleReady, |
| base::Unretained(this))); |
| pref_change_registrar_->Add( |
| language::prefs::kPreferredLanguages, |
| base::BindRepeating(&QuickAnswersStateAsh::UpdatePreferredLanguages, |
| base::Unretained(this))); |
| pref_change_registrar_->Add( |
| ash::prefs::kAccessibilitySpokenFeedbackEnabled, |
| base::BindRepeating(&QuickAnswersStateAsh::UpdateSpokenFeedbackEnabled, |
| base::Unretained(this))); |
| |
| UpdateSettingsEnabled(); |
| UpdateConsentStatus(); |
| UpdateDefinitionEnabled(); |
| UpdateTranslationEnabled(); |
| UpdateUnitConversionEnabled(); |
| OnApplicationLocaleReady(); |
| UpdatePreferredLanguages(); |
| UpdateSpokenFeedbackEnabled(); |
| |
| prefs_initialized_ = true; |
| for (auto& observer : observers_) { |
| observer.OnPrefsInitialized(); |
| } |
| |
| quick_answers::RecordFeatureEnabled( |
| pref_service->GetBoolean(kQuickAnswersEnabled)); |
| |
| UpdateEligibility(); |
| } |
| |
| void QuickAnswersStateAsh::StartConsent() { |
| consent_start_time_ = base::TimeTicks::Now(); |
| } |
| |
| void QuickAnswersStateAsh::OnConsentResult(ConsentResultType result) { |
| auto* prefs = pref_change_registrar_->prefs(); |
| |
| DCHECK(!consent_start_time_.is_null()); |
| auto duration = base::TimeTicks::Now() - consent_start_time_; |
| |
| // Only increase the counter and record the impression if the minimum duration |
| // has been reached. |
| if (duration.InSeconds() >= kConsentImpressionMinimumDuration) { |
| // Increments impression count. |
| IncrementPrefCounter(pref_change_registrar_->prefs(), |
| kQuickAnswersNoticeImpressionCount, 1); |
| RecordConsentResult(result, |
| prefs->GetInteger(kQuickAnswersNoticeImpressionCount), |
| duration); |
| } |
| |
| switch (result) { |
| case ConsentResultType::kAllow: |
| // Enable Quick Answers if the user accepted the consent. |
| prefs->SetBoolean(kQuickAnswersEnabled, true); |
| prefs->SetInteger(kQuickAnswersConsentStatus, ConsentStatus::kAccepted); |
| break; |
| case ConsentResultType::kNoThanks: |
| prefs->SetInteger(kQuickAnswersConsentStatus, ConsentStatus::kRejected); |
| prefs->SetBoolean(kQuickAnswersEnabled, false); |
| break; |
| case ConsentResultType::kDismiss: |
| // If the impression count cap is reached, set the consented status to |
| // false; |
| bool impression_cap_reached = |
| prefs->GetInteger(kQuickAnswersNoticeImpressionCount) >= |
| kConsentImpressionCap; |
| if (impression_cap_reached) { |
| prefs->SetInteger(kQuickAnswersConsentStatus, ConsentStatus::kRejected); |
| prefs->SetBoolean(kQuickAnswersEnabled, false); |
| } |
| } |
| |
| consent_start_time_ = base::TimeTicks(); |
| } |
| |
| void QuickAnswersStateAsh::UpdateSettingsEnabled() { |
| auto* prefs = pref_change_registrar_->prefs(); |
| |
| auto settings_enabled = prefs->GetBoolean(kQuickAnswersEnabled); |
| if (settings_enabled_ == settings_enabled) { |
| return; |
| } |
| settings_enabled_ = settings_enabled; |
| |
| // If the user turn on the Quick Answers in settings, set the consented status |
| // to true. |
| if (settings_enabled_) { |
| prefs->SetInteger(kQuickAnswersConsentStatus, ConsentStatus::kAccepted); |
| } |
| |
| // If the feature is enforced off by the administrator policy, set the |
| // consented status to rejected. |
| if (!settings_enabled_ && |
| prefs->IsManagedPreference(quick_answers::prefs::kQuickAnswersEnabled)) { |
| prefs->SetInteger(kQuickAnswersConsentStatus, ConsentStatus::kRejected); |
| } |
| |
| for (auto& observer : observers_) |
| observer.OnSettingsEnabled(settings_enabled_); |
| } |
| |
| void QuickAnswersStateAsh::UpdateConsentStatus() { |
| auto consent_status = static_cast<ConsentStatus>( |
| pref_change_registrar_->prefs()->GetInteger(kQuickAnswersConsentStatus)); |
| |
| consent_status_ = consent_status; |
| |
| for (auto& observer : observers_) |
| observer.OnConsentStatusUpdated(consent_status_); |
| } |
| |
| void QuickAnswersStateAsh::UpdateDefinitionEnabled() { |
| auto definition_enabled = pref_change_registrar_->prefs()->GetBoolean( |
| kQuickAnswersDefinitionEnabled); |
| |
| definition_enabled_ = definition_enabled; |
| } |
| |
| void QuickAnswersStateAsh::UpdateTranslationEnabled() { |
| auto translation_enabled = pref_change_registrar_->prefs()->GetBoolean( |
| kQuickAnswersTranslationEnabled); |
| |
| translation_enabled_ = translation_enabled; |
| } |
| |
| void QuickAnswersStateAsh::UpdateUnitConversionEnabled() { |
| auto unit_conversion_enabled = pref_change_registrar_->prefs()->GetBoolean( |
| kQuickAnswersUnitConversionEnabled); |
| |
| unit_conversion_enabled_ = unit_conversion_enabled; |
| } |
| |
| void QuickAnswersStateAsh::OnApplicationLocaleReady() { |
| auto locale = pref_change_registrar_->prefs()->GetString( |
| language::prefs::kApplicationLocale); |
| |
| if (locale.empty()) |
| return; |
| |
| // We should not directly use the pref locale, resolve the generic locale name |
| // to one of the locally defined ones first. |
| std::string resolved_locale; |
| bool resolve_success = |
| l10n_util::CheckAndResolveLocale(locale, &resolved_locale, |
| /*perform_io=*/false); |
| DCHECK(resolve_success); |
| |
| if (resolved_application_locale_ == resolved_locale) { |
| return; |
| } |
| resolved_application_locale_ = resolved_locale; |
| |
| for (auto& observer : observers_) { |
| observer.OnApplicationLocaleReady(resolved_locale); |
| } |
| |
| UpdateEligibility(); |
| } |
| |
| void QuickAnswersStateAsh::UpdatePreferredLanguages() { |
| auto preferred_languages = pref_change_registrar_->prefs()->GetString( |
| language::prefs::kPreferredLanguages); |
| |
| preferred_languages_ = preferred_languages; |
| |
| for (auto& observer : observers_) |
| observer.OnPreferredLanguagesChanged(preferred_languages); |
| } |
| |
| void QuickAnswersStateAsh::UpdateSpokenFeedbackEnabled() { |
| auto spoken_feedback_enabled = pref_change_registrar_->prefs()->GetBoolean( |
| ash::prefs::kAccessibilitySpokenFeedbackEnabled); |
| |
| spoken_feedback_enabled_ = spoken_feedback_enabled; |
| } |