Commit 1d647b1b authored by Li Lin's avatar Li Lin Committed by Commit Bot

Handle quick answers consent with prefs.

The consent will be shown to user:
- Cumulative 8 seconds (based on reading speed from notification study)
OR
- Up to a total of 3 times.

Bug: 1054575
Test: unit tests
Change-Id: Id05fe4edda8cf04005684d84ed7d36df32c06cd9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2039890Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Commit-Queue: Li Lin <llin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#743317}
parent 730f5630
......@@ -105,6 +105,7 @@ source_set("chromeos") {
"//chromeos/components/multidevice/logging",
"//chromeos/components/power",
"//chromeos/components/proximity_auth",
"//chromeos/components/quick_answers/public/cpp:prefs",
"//chromeos/components/smbfs",
"//chromeos/components/smbfs/mojom",
"//chromeos/components/tether",
......
......@@ -326,6 +326,7 @@
#include "chrome/browser/upgrade_detector/upgrade_detector_chromeos.h"
#include "chromeos/audio/audio_devices_pref_handler_impl.h"
#include "chromeos/components/account_manager/account_manager.h"
#include "chromeos/components/quick_answers/public/cpp/quick_answers_prefs.h"
#include "chromeos/constants/chromeos_switches.h"
#include "chromeos/network/fast_transition_observer.h"
#include "chromeos/network/proxy/proxy_config_handler.h"
......@@ -1014,6 +1015,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
chromeos::PrintJobHistoryService::RegisterProfilePrefs(registry);
chromeos::SyncedPrintersManager::RegisterProfilePrefs(registry);
chromeos::parent_access::ParentAccessService::RegisterProfilePrefs(registry);
chromeos::quick_answers::prefs::RegisterProfilePrefs(registry);
chromeos::quick_unlock::RegisterProfilePrefs(registry);
chromeos::RegisterSamlProfilePrefs(registry);
chromeos::ScreenTimeController::RegisterProfilePrefs(registry);
......
......@@ -6,6 +6,8 @@ source_set("quick_answers") {
sources = [
"quick_answers_client.cc",
"quick_answers_client.h",
"quick_answers_consents.cc",
"quick_answers_consents.h",
"quick_answers_model.cc",
"quick_answers_model.h",
"search_result_loader.cc",
......@@ -29,7 +31,9 @@ source_set("quick_answers") {
"//ash/public/cpp",
"//ash/public/mojom",
"//base",
"//chromeos/components/quick_answers/public/cpp:prefs",
"//chromeos/constants:constants",
"//components/prefs:prefs",
"//net:net",
"//services/data_decoder/public/cpp",
"//services/network/public/cpp:cpp",
......@@ -43,6 +47,7 @@ source_set("unit_tests") {
sources = [
"quick_answers_client_unittest.cc",
"quick_answers_consents_unittest.cc",
"search_result_loader_unittest.cc",
"search_result_parsers/definition_result_parser_unittest.cc",
"search_result_parsers/kp_entity_result_parser_unittest.cc",
......@@ -60,7 +65,10 @@ source_set("unit_tests") {
"//ash/public/mojom",
"//base",
"//base/test:test_support",
"//chromeos/components/quick_answers/public/cpp:prefs",
"//chromeos/constants:constants",
"//components/prefs:prefs",
"//components/prefs:test_support",
"//services/data_decoder/public/cpp:test_support",
"//services/network:test_support",
"//testing/gmock",
......
# Copyright 2020 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.
source_set("prefs") {
sources = [
"quick_answers_prefs.cc",
"quick_answers_prefs.h",
]
deps = [ "//components/prefs" ]
}
// Copyright 2020 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 "chromeos/components/quick_answers/public/cpp/quick_answers_prefs.h"
#include "components/prefs/pref_registry_simple.h"
namespace chromeos {
namespace quick_answers {
namespace prefs {
// A preference that indicates the user has allowed the Quick Answers to access
// the "selected content".
const char kQuickAnswersConsented[] = "settings.quick_answers.consented";
// A preference to keep track of the number of Quick Answers consent impression.
const char kQuickAnswersConsentImpressionCount[] =
"settings.quick_answers.consent.count";
// A preference to keep track of how long (in seconds) the Quick Answers consent
// has shown to the user.
const char kQuickAnswersConsentImpressionDuration[] =
"settings.quick_answers.consent.duration";
void RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(kQuickAnswersConsented, false);
registry->RegisterIntegerPref(kQuickAnswersConsentImpressionCount, 0);
registry->RegisterIntegerPref(kQuickAnswersConsentImpressionDuration, 0);
}
} // namespace prefs
} // namespace quick_answers
} // namespace chromeos
// Copyright 2020 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.
#ifndef CHROMEOS_COMPONENTS_QUICK_ANSWERS_PUBLIC_CPP_QUICK_ANSWERS_PREFS_H_
#define CHROMEOS_COMPONENTS_QUICK_ANSWERS_PUBLIC_CPP_QUICK_ANSWERS_PREFS_H_
class PrefRegistrySimple;
namespace chromeos {
namespace quick_answers {
namespace prefs {
extern const char kQuickAnswersConsented[];
extern const char kQuickAnswersConsentImpressionCount[];
extern const char kQuickAnswersConsentImpressionDuration[];
// Registers Quick Answers specific profile preferences for browser prefs.
void RegisterProfilePrefs(PrefRegistrySimple* registry);
} // namespace prefs
} // namespace quick_answers
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_QUICK_ANSWERS_PUBLIC_CPP_QUICK_ANSWERS_PREFS_H_
// Copyright 2020 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 "chromeos/components/quick_answers/quick_answers_consents.h"
#include <string>
#include "base/metrics/histogram_functions.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "chromeos/components/quick_answers/public/cpp/quick_answers_prefs.h"
#include "components/prefs/pref_service.h"
namespace chromeos {
namespace quick_answers {
namespace {
constexpr int kImpressionCap = 3;
constexpr int kDurationCap = 8;
} // namespace
QuickAnswersConsent::QuickAnswersConsent(PrefService* prefs) : prefs_(prefs) {}
QuickAnswersConsent::~QuickAnswersConsent() = default;
void QuickAnswersConsent::StartConsent() {
// Increments impression count.
IncrementPerfCounter(prefs::kQuickAnswersConsentImpressionCount, 1);
start_time_ = base::TimeTicks::Now();
}
void QuickAnswersConsent::DismissConsent() {
RecordImpressionDuration();
}
void QuickAnswersConsent::AcceptConsent() {
RecordImpressionDuration();
// Marks the consent as accepted.
prefs_->SetBoolean(prefs::kQuickAnswersConsented, true);
}
bool QuickAnswersConsent::ShouldShowConsent() const {
return !HasConsented() && !HasReachedImpressionCap() &&
!HasReachedDurationCap();
}
bool QuickAnswersConsent::HasConsented() const {
return prefs_->GetBoolean(prefs::kQuickAnswersConsented);
}
bool QuickAnswersConsent::HasReachedImpressionCap() const {
int impression_count =
prefs_->GetInteger(prefs::kQuickAnswersConsentImpressionCount);
return impression_count + 1 > kImpressionCap;
}
bool QuickAnswersConsent::HasReachedDurationCap() const {
int duration_secs =
prefs_->GetInteger(prefs::kQuickAnswersConsentImpressionDuration);
return duration_secs >= kDurationCap;
}
void QuickAnswersConsent::IncrementPerfCounter(const std::string& path,
int count) {
prefs_->SetInteger(path, prefs_->GetInteger(path) + count);
}
void QuickAnswersConsent::RecordImpressionDuration() {
DCHECK(!start_time_.is_null());
// Records duration in pref.
base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
IncrementPerfCounter(prefs::kQuickAnswersConsentImpressionDuration,
duration.InSeconds());
}
} // namespace quick_answers
} // namespace chromeos
// Copyright 2020 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.
#ifndef CHROMEOS_COMPONENTS_QUICK_ANSWERS_QUICK_ANSWERS_CONSENTS_H_
#define CHROMEOS_COMPONENTS_QUICK_ANSWERS_QUICK_ANSWERS_CONSENTS_H_
#include <memory>
#include "base/timer/timer.h"
class PrefService;
namespace chromeos {
namespace quick_answers {
// Tracks whether quick answers consent should be shown and records impression
// count and duration when there is a interaction with the consent (shown,
// accepted and dismissed).
class QuickAnswersConsent {
public:
explicit QuickAnswersConsent(PrefService* prefs);
QuickAnswersConsent(const QuickAnswersConsent&) = delete;
QuickAnswersConsent& operator=(const QuickAnswersConsent&) = delete;
virtual ~QuickAnswersConsent();
// Starts showing consent. Virtual for testing.
virtual void StartConsent();
// Marks the consent as accepted and records the impression duration. Virtual
// for testing.
virtual void AcceptConsent();
// The consent is dismissed by users. Records the impression duration. Virtual
// for testing.
virtual void DismissConsent();
// Whether the consent should be shown (based on consent state, impression
// count and impression duration). Virtual for testing.
virtual bool ShouldShowConsent() const;
private:
// Whether users have grained the consent.
bool HasConsented() const;
// Whether the consent has been seen by users for |kImpressionCap| times.
bool HasReachedImpressionCap() const;
// Whether the consent has been seen by users for |kDurationCap| seconds.
bool HasReachedDurationCap() const;
// Increments the perf counter by |count|.
void IncrementPerfCounter(const std::string& path, int count);
// Records how long the consent has been seen by the users.
void RecordImpressionDuration();
PrefService* const prefs_;
// Time when the consent is shown.
base::TimeTicks start_time_;
};
} // namespace quick_answers
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_QUICK_ANSWERS_QUICK_ANSWERS_CONSENTS_H_
// Copyright 2020 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 "chromeos/components/quick_answers/quick_answers_consents.h"
#include <memory>
#include <string>
#include "base/test/task_environment.h"
#include "base/test/test_mock_time_task_runner.h"
#include "chromeos/components/quick_answers/public/cpp/quick_answers_prefs.h"
#include "components/prefs/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace quick_answers {
class QuickAnswersConsentTest : public testing::Test {
public:
QuickAnswersConsentTest() = default;
~QuickAnswersConsentTest() override = default;
void SetUp() override {
prefs::RegisterProfilePrefs(pref_service_.registry());
consent_ = std::make_unique<QuickAnswersConsent>(&pref_service_);
}
void TearDown() override { consent_.reset(); }
PrefService* pref_service() { return &pref_service_; }
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
TestingPrefServiceSimple pref_service_;
std::unique_ptr<QuickAnswersConsent> consent_;
};
TEST_F(QuickAnswersConsentTest, ShouldShowConsentHasConsented) {
EXPECT_TRUE(consent_->ShouldShowConsent());
pref_service()->SetBoolean(prefs::kQuickAnswersConsented, true);
// Verify that it is consented.
EXPECT_FALSE(consent_->ShouldShowConsent());
}
TEST_F(QuickAnswersConsentTest, ShouldShowConsentHasReachedImpressionCap) {
EXPECT_TRUE(consent_->ShouldShowConsent());
pref_service()->SetInteger(prefs::kQuickAnswersConsentImpressionCount, 3);
// Verify that impression cap is reached.
EXPECT_FALSE(consent_->ShouldShowConsent());
}
TEST_F(QuickAnswersConsentTest, ShouldShowConsentHasReachedDurationCap) {
EXPECT_TRUE(consent_->ShouldShowConsent());
pref_service()->SetInteger(prefs::kQuickAnswersConsentImpressionDuration, 7);
// Not reach impression duration cap yet.
EXPECT_TRUE(consent_->ShouldShowConsent());
pref_service()->SetInteger(prefs::kQuickAnswersConsentImpressionDuration, 8);
// Reach impression duration cap.
EXPECT_FALSE(consent_->ShouldShowConsent());
}
TEST_F(QuickAnswersConsentTest, AcceptConsent) {
EXPECT_TRUE(consent_->ShouldShowConsent());
consent_->StartConsent();
// Consent is accepted after 6 seconds.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(6));
consent_->AcceptConsent();
// Verify that it is consented.
ASSERT_TRUE(pref_service()->GetBoolean(prefs::kQuickAnswersConsented));
// Verify that the duration is recorded.
ASSERT_EQ(6, pref_service()->GetInteger(
prefs::kQuickAnswersConsentImpressionDuration));
// Verify that it is consented.
EXPECT_FALSE(consent_->ShouldShowConsent());
}
TEST_F(QuickAnswersConsentTest, DismissConsent) {
// Start consent.
consent_->StartConsent();
// Dismiss consent after reaching the impression cap.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(8));
consent_->DismissConsent();
// Verify that the impression count is recorded.
ASSERT_EQ(8, pref_service()->GetInteger(
prefs::kQuickAnswersConsentImpressionDuration));
}
} // namespace quick_answers
} // namespace chromeos
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