Commit 290d696c authored by Andy Paicu's avatar Andy Paicu Committed by Commit Bot

Add a method of determining whether the quiet UI was enabled manually...

...or adaptively

This will be needed for the CPSS implementation in the decision
algorithm: go/permissions-suggestions-client-doc#heading=h.qqrjggkdxk7

Bug: 1138595
Change-Id: I8cd55b6d460ae29aef545c03655674ec3df73eb8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2472004
Commit-Queue: Andy Paicu <andypaicu@chromium.org>
Reviewed-by: default avatarBalazs Engedy <engedy@chromium.org>
Reviewed-by: default avatarKamila Hasanbega <hkamila@chromium.org>
Cr-Commit-Position: refs/heads/master@{#825923}
parent 229973fe
......@@ -21,6 +21,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/permissions/quiet_notification_permission_ui_config.h"
#include "chrome/browser/permissions/quiet_notification_permission_ui_state.h"
#include "chrome/browser/profiles/incognito_helpers.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
......@@ -34,6 +35,8 @@
namespace {
using EnablingMethod = QuietNotificationPermissionUiState::EnablingMethod;
// Enable the quiet UX after 3 consecutive denies in adapative activation mode.
constexpr int kConsecutiveDeniesThresholdForActivation = 3u;
......@@ -195,6 +198,9 @@ void AdaptiveQuietNotificationPermissionUiEnabler::
base::AutoReset<bool> enabling_adaptively(&is_enabling_adaptively_, true);
profile_->GetPrefs()->SetBoolean(
prefs::kEnableQuietNotificationPermissionUi, true /* value */);
// TODO(crbug.com/1147467): If `kQuietNotificationPermissionShouldShowPromo`
// stops being a good indicator as to how the quiet UI pref was enabled,
// remove the |BackfillEnablingMethodIfMissing| logic.
profile_->GetPrefs()->SetBoolean(
prefs::kQuietNotificationPermissionShouldShowPromo, true /* value */);
}
......@@ -245,6 +251,8 @@ AdaptiveQuietNotificationPermissionUiEnabler::
base::UmaHistogramBoolean(kIsQuietUiEnabledInPrefs,
is_quiet_ui_enabled_in_prefs);
}
BackfillEnablingMethodIfMissing();
}
AdaptiveQuietNotificationPermissionUiEnabler::
......@@ -259,13 +267,19 @@ void AdaptiveQuietNotificationPermissionUiEnabler::OnQuietUiStateChanged() {
if (is_quiet_ui_enabled_in_prefs) {
base::UmaHistogramBoolean(kDidAdaptivelyEnableQuietUiInPrefs,
is_enabling_adaptively_);
profile_->GetPrefs()->SetInteger(
prefs::kQuietNotificationPermissionUiEnablingMethod,
static_cast<int>(is_enabling_adaptively_ ? EnablingMethod::kAdaptive
: EnablingMethod::kManual));
} else {
// Reset the promo state so that if the quiet UI is enabled adaptively
// again, the promo will be shown again.
profile_->GetPrefs()->SetBoolean(
prefs::kQuietNotificationPermissionShouldShowPromo, false /* value */);
profile_->GetPrefs()->SetBoolean(
prefs::kQuietNotificationPermissionPromoWasShown, false /* value */);
profile_->GetPrefs()->ClearPref(
prefs::kQuietNotificationPermissionShouldShowPromo);
profile_->GetPrefs()->ClearPref(
prefs::kQuietNotificationPermissionPromoWasShown);
profile_->GetPrefs()->ClearPref(
prefs::kQuietNotificationPermissionUiEnablingMethod);
// If the users has just turned off the quiet UI, clear interaction history
// so that if we are in adaptive mode, and the triggering conditions are
......@@ -273,3 +287,23 @@ void AdaptiveQuietNotificationPermissionUiEnabler::OnQuietUiStateChanged() {
ClearInteractionHistory(base::Time(), base::Time::Max());
}
}
void AdaptiveQuietNotificationPermissionUiEnabler::
BackfillEnablingMethodIfMissing() {
if (QuietNotificationPermissionUiState::GetQuietUiEnablingMethod(profile_) !=
EnablingMethod::kUnspecified) {
return;
}
// `kQuietNotificationPermissionUiEnablingMethod` was not populated prior to
// M88, but `kQuietNotificationPermissionShouldShowPromo` is a solid indicator
// as to how the setting was enabled in the first place because it's only set
// to true when the quiet UI has been enabled adaptively.
const bool has_enabled_adaptively = profile_->GetPrefs()->GetBoolean(
prefs::kQuietNotificationPermissionShouldShowPromo);
profile_->GetPrefs()->SetInteger(
prefs::kQuietNotificationPermissionUiEnablingMethod,
static_cast<int>(has_enabled_adaptively ? EnablingMethod::kAdaptive
: EnablingMethod::kManual));
}
......@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_PERMISSIONS_ADAPTIVE_QUIET_NOTIFICATION_PERMISSION_UI_ENABLER_H_
#define CHROME_BROWSER_PERMISSIONS_ADAPTIVE_QUIET_NOTIFICATION_PERMISSION_UI_ENABLER_H_
#include <memory>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
......@@ -61,6 +62,11 @@ class AdaptiveQuietNotificationPermissionUiEnabler : public KeyedService {
// The |clock| must outlive this instance.
void set_clock_for_testing(base::Clock* clock) { clock_ = clock; }
// Only used for testing.
void BackfillEnablingMethodIfMissingForTesting() {
BackfillEnablingMethodIfMissing();
}
private:
explicit AdaptiveQuietNotificationPermissionUiEnabler(Profile* profile);
~AdaptiveQuietNotificationPermissionUiEnabler() override;
......@@ -68,6 +74,10 @@ class AdaptiveQuietNotificationPermissionUiEnabler : public KeyedService {
// Called when the quiet UI state is updated in preferences.
void OnQuietUiStateChanged();
// Retroactively backfills the enabling method, which was not populated
// before M88.
void BackfillEnablingMethodIfMissing();
Profile* profile_;
std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
bool is_enabling_adaptively_ = false;
......
// Copyright 2019 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/permissions/adaptive_quiet_notification_permission_ui_enabler.h"
#include <memory>
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/permissions/quiet_notification_permission_ui_state.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/prefs/testing_pref_service.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
using QuietUiEnablingMethod =
QuietNotificationPermissionUiState::EnablingMethod;
} // namespace
class AdaptiveQuietNotificationPermissionUiEnablerTest : public testing::Test {
public:
AdaptiveQuietNotificationPermissionUiEnablerTest()
: testing_profile_(std::make_unique<TestingProfile>()) {}
~AdaptiveQuietNotificationPermissionUiEnablerTest() override = default;
AdaptiveQuietNotificationPermissionUiEnablerTest(
const AdaptiveQuietNotificationPermissionUiEnablerTest&) = delete;
AdaptiveQuietNotificationPermissionUiEnablerTest& operator=(
const AdaptiveQuietNotificationPermissionUiEnablerTest&) = delete;
TestingProfile* profile() { return testing_profile_.get(); }
private:
content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<TestingProfile> testing_profile_;
};
// Check the |BackfillEnablingMethodIfMissing| method.
TEST_F(AdaptiveQuietNotificationPermissionUiEnablerTest,
BackfillEnablingMethodIfMissing) {
struct {
bool enable_quiet_ui_pref;
base::Optional<QuietUiEnablingMethod> quiet_ui_method_pref;
bool should_show_promo_pref;
QuietUiEnablingMethod expected_quiet_ui_method_pref;
} kTests[] = {
// If the quiet ui is not enabled, the method is always unspecified.
{false, QuietUiEnablingMethod::kUnspecified, false,
QuietUiEnablingMethod::kUnspecified},
{false, QuietUiEnablingMethod::kAdaptive, false,
QuietUiEnablingMethod::kUnspecified},
{false, QuietUiEnablingMethod::kManual, true,
QuietUiEnablingMethod::kUnspecified},
// If the method is set already it will stay the same.
{true, QuietUiEnablingMethod::kAdaptive, false,
QuietUiEnablingMethod::kAdaptive},
{true, QuietUiEnablingMethod::kManual, true,
QuietUiEnablingMethod::kManual},
// If the method is unspecified, use the promo perf to decide the method.
{true, QuietUiEnablingMethod::kUnspecified, true,
QuietUiEnablingMethod::kAdaptive},
{true, QuietUiEnablingMethod::kUnspecified, false,
QuietUiEnablingMethod::kManual},
// If the method is unset, it should be treated as kUnspecified.
{false, base::nullopt, false, QuietUiEnablingMethod::kUnspecified},
{true, base::nullopt, true, QuietUiEnablingMethod::kAdaptive},
{true, base::nullopt, false, QuietUiEnablingMethod::kManual},
};
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kQuietNotificationPrompts);
auto* permission_ui_enabler =
AdaptiveQuietNotificationPermissionUiEnabler::GetForProfile(profile());
int test_case = 0;
for (const auto& kTest : kTests) {
SCOPED_TRACE(test_case++);
profile()->GetPrefs()->SetBoolean(
prefs::kEnableQuietNotificationPermissionUi,
kTest.enable_quiet_ui_pref);
if (kTest.quiet_ui_method_pref.has_value()) {
profile()->GetPrefs()->SetInteger(
prefs::kQuietNotificationPermissionUiEnablingMethod,
static_cast<int>(kTest.quiet_ui_method_pref.value()));
} else {
profile()->GetPrefs()->ClearPref(
prefs::kQuietNotificationPermissionUiEnablingMethod);
}
profile()->GetPrefs()->SetBoolean(
prefs::kQuietNotificationPermissionShouldShowPromo,
kTest.should_show_promo_pref);
permission_ui_enabler->BackfillEnablingMethodIfMissingForTesting();
EXPECT_EQ(kTest.expected_quiet_ui_method_pref,
QuietNotificationPermissionUiState::GetQuietUiEnablingMethod(
profile()));
}
}
......@@ -5,6 +5,7 @@
#include "chrome/browser/permissions/quiet_notification_permission_ui_state.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
......@@ -27,6 +28,9 @@ void QuietNotificationPermissionUiState::RegisterProfilePrefs(
registry->RegisterBooleanPref(
prefs::kHadThreeConsecutiveNotificationPermissionDenies,
false /* default_value */);
registry->RegisterIntegerPref(
prefs::kQuietNotificationPermissionUiEnablingMethod,
static_cast<int>(EnablingMethod::kUnspecified));
}
// static
......@@ -44,3 +48,19 @@ void QuietNotificationPermissionUiState::PromoWasShown(Profile* profile) {
profile->GetPrefs()->SetBoolean(
prefs::kQuietNotificationPermissionPromoWasShown, true /* value */);
}
// static
QuietNotificationPermissionUiState::EnablingMethod
QuietNotificationPermissionUiState::GetQuietUiEnablingMethod(Profile* profile) {
// Since the `kEnableQuietNotificationPermissionUi` pref is not reset if the
// `kQuietNotificationPrompts` is disabled, we have to check both values to
// ensure that the quiet UI is enabled.
if (!base::FeatureList::IsEnabled(features::kQuietNotificationPrompts) ||
!profile->GetPrefs()->GetBoolean(
prefs::kEnableQuietNotificationPermissionUi)) {
return EnablingMethod::kUnspecified;
}
return static_cast<EnablingMethod>(profile->GetPrefs()->GetInteger(
prefs::kQuietNotificationPermissionUiEnablingMethod));
}
......@@ -13,6 +13,23 @@ class Profile;
class QuietNotificationPermissionUiState {
public:
// Defines the method by which the quiet UI was enabled.
enum class EnablingMethod {
// The quiet UI is either not enabled, or was enabled in M87 or earlier,
// which did not keep track of the enabling method. The latter situation
// should be self-correcting as the
// AdaptiveQuietNotificationPermissionUiEnabler will backfill these values
// shortly after start-up.
kUnspecified = 0,
// The user manually selected the quiet UI in settings.
kManual,
// The adaptive activation mechanism in
// AdaptiveQuietNotificationPermissionUiEnabler has enabled the quiet UI.
kAdaptive,
};
// Register Profile-keyed preferences used for permission UI selection.
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
......@@ -21,6 +38,9 @@ class QuietNotificationPermissionUiState {
// Records that the promo was shown.
static void PromoWasShown(Profile* profile);
// Returns the method that was used to enable the quiet UI.
static EnablingMethod GetQuietUiEnablingMethod(Profile* profile);
};
#endif // CHROME_BROWSER_PERMISSIONS_QUIET_NOTIFICATION_PERMISSION_UI_STATE_H_:b
......@@ -3559,6 +3559,7 @@ test("unit_tests") {
"../browser/performance_manager/test_support/page_aggregator.h",
"../browser/performance_monitor/system_monitor_unittest.cc",
"../browser/permissions/abusive_origin_permission_revocation_request_unittests.cc",
"../browser/permissions/adaptive_quiet_notification_permission_ui_enabler_unittest.cc",
"../browser/permissions/chrome_permission_manager_unittest.cc",
"../browser/permissions/chrome_permission_request_manager_unittest.cc",
"../browser/permissions/contextual_notification_permission_ui_selector_unittest.cc",
......
......@@ -111,11 +111,18 @@ const char kManagedSerialBlockedForUrls[] =
const char kManagedInsecurePrivateNetworkAllowedForUrls[] =
"profile.managed_insecure_private_network_allowed_for_urls";
// Boolean indicating whether the quiet UX is enabled for notification
// Boolean indicating whether the quiet UI is enabled for notification
// permission requests.
const char kEnableQuietNotificationPermissionUi[] =
"profile.content_settings.enable_quiet_permission_ui.notifications";
// Enum indicating by which method the quiet UI has been enabled for
// notification permission requests. This is stored as of M88 and will be
// backfilled if the quiet UI is enabled but this preference has no value.
const char kQuietNotificationPermissionUiEnablingMethod[] =
"profile.content_settings.enable_quiet_permission_ui_enabling_method."
"notifications";
#if defined(OS_ANDROID)
// Enable vibration for web notifications.
const char kNotificationsVibrateEnabled[] = "notifications.vibrate_enabled";
......
......@@ -65,6 +65,7 @@ extern const char kManagedSerialBlockedForUrls[];
extern const char kManagedInsecurePrivateNetworkAllowedForUrls[];
extern const char kEnableQuietNotificationPermissionUi[];
extern const char kQuietNotificationPermissionUiEnablingMethod[];
#if defined(OS_ANDROID)
extern const char kNotificationsVibrateEnabled[];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment