Commit 695ff571 authored by Jon Mann's avatar Jon Mann Committed by Chromium LUCI CQ

Wi-Fi Sync: Show announcement notification on first unlock

Existing users of the multidevice suite will have Wi-Fi Sync set to
be disabled by default when it is first.  This adds a notification to
announce the feature to these users on the first unlock after the
feature is available.

Bug: 1117619
Change-Id: Ia580ed2b4f99561a7295e585bc3cfa592ee5f1b1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2630733
Commit-Queue: Jon Mann <jonmann@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#844301}
parent 95aaa5cd
......@@ -2668,6 +2668,12 @@ This file contains the strings for ash.
<message name="IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_NEW_CHROME_DEVICE_ADDED_MESSAGE" desc="Message shown as part of the notification shown to a user that has already completed the MultiDevice setup flow logging into a new Chrome device that all their Chrome devices are MultiDevice enabled.">
This <ph name="DEVICE_NAME">$1<ex>Chromebook</ex></ph> and your phone will connect automatically
</message>
<message name="IDS_ASH_MULTI_DEVICE_WIFI_SYNC_AVAILABLE_TITLE" desc="Title of the notification shown to a user that is newly eligible for Wi-Fi Sync.">
Turn on Wi-Fi Sync
</message>
<message name="IDS_ASH_MULTI_DEVICE_WIFI_SYNC_AVAILABLE_MESSAGE" desc="Message shown as part of the notification shown to a user that has become eligible to enable Wi-Fi Sync.">
Wi-Fi networks will be shared between your phone and <ph name="DEVICE_NAME">$1<ex>Chromebook</ex></ph>
</message>
<!-- Window teleportation warning dialog -->
<message name="IDS_ASH_TELEPORT_WARNING_TITLE" desc="The title of the dialog which warns user about oddities which can be seen when a window gets moved to another user desktop.">
......
77739c07b3a18f3b0a727267e02a489e466a048f
\ No newline at end of file
77739c07b3a18f3b0a727267e02a489e466a048f
\ No newline at end of file
......@@ -35,9 +35,13 @@ const char kNotifierMultiDevice[] = "ash.multi_device_setup";
} // namespace
// static
const char MultiDeviceNotificationPresenter::kNotificationId[] =
const char MultiDeviceNotificationPresenter::kSetupNotificationId[] =
"cros_multi_device_setup_notification_id";
// static
const char MultiDeviceNotificationPresenter::kWifiSyncNotificationId[] =
"cros_wifi_sync_announcement_notification_id";
// static
std::string
MultiDeviceNotificationPresenter::GetNotificationDescriptionForLogging(
......@@ -96,7 +100,7 @@ void MultiDeviceNotificationPresenter::OnPotentialHostExistsForNewUser() {
base::string16 message = l10n_util::GetStringFUTF16(
IDS_ASH_MULTI_DEVICE_SETUP_NEW_USER_POTENTIAL_HOST_EXISTS_MESSAGE,
ui::GetChromeOSDeviceName());
ShowNotification(Status::kNewUserNotificationVisible, title, message);
ShowSetupNotification(Status::kNewUserNotificationVisible, title, message);
}
void MultiDeviceNotificationPresenter::OnNoLongerNewUser() {
......@@ -113,8 +117,8 @@ void MultiDeviceNotificationPresenter::OnConnectedHostSwitchedForExistingUser(
base::string16 message = l10n_util::GetStringFUTF16(
IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_HOST_SWITCHED_MESSAGE,
ui::GetChromeOSDeviceName());
ShowNotification(Status::kExistingUserHostSwitchedNotificationVisible, title,
message);
ShowSetupNotification(Status::kExistingUserHostSwitchedNotificationVisible,
title, message);
}
void MultiDeviceNotificationPresenter::OnNewChromebookAddedForExistingUser(
......@@ -125,13 +129,22 @@ void MultiDeviceNotificationPresenter::OnNewChromebookAddedForExistingUser(
base::string16 message = l10n_util::GetStringFUTF16(
IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_NEW_CHROME_DEVICE_ADDED_MESSAGE,
ui::GetChromeOSDeviceName());
ShowNotification(Status::kExistingUserNewChromebookNotificationVisible, title,
message);
ShowSetupNotification(Status::kExistingUserNewChromebookNotificationVisible,
title, message);
}
void MultiDeviceNotificationPresenter::OnBecameEligibleForWifiSync() {
base::string16 title =
l10n_util::GetStringUTF16(IDS_ASH_MULTI_DEVICE_WIFI_SYNC_AVAILABLE_TITLE);
base::string16 message = l10n_util::GetStringFUTF16(
IDS_ASH_MULTI_DEVICE_WIFI_SYNC_AVAILABLE_MESSAGE,
ui::GetChromeOSDeviceName());
ShowNotification(kWifiSyncNotificationId, title, message);
}
void MultiDeviceNotificationPresenter::RemoveMultiDeviceSetupNotification() {
notification_status_ = Status::kNoNotificationVisible;
message_center_->RemoveNotification(kNotificationId,
message_center_->RemoveNotification(kSetupNotificationId,
/* by_user */ false);
}
......@@ -148,7 +161,7 @@ void MultiDeviceNotificationPresenter::OnSessionStateChanged(
void MultiDeviceNotificationPresenter::OnNotificationRemoved(
const std::string& notification_id,
bool by_user) {
if (by_user && notification_id == kNotificationId) {
if (by_user && notification_id == kSetupNotificationId) {
UMA_HISTOGRAM_ENUMERATION(
"MultiDeviceSetup_NotificationDismissed",
GetMetricValueForNotification(notification_status_),
......@@ -160,7 +173,14 @@ void MultiDeviceNotificationPresenter::OnNotificationClicked(
const std::string& notification_id,
const base::Optional<int>& button_index,
const base::Optional<base::string16>& reply) {
if (notification_id != kNotificationId)
if (notification_id == kWifiSyncNotificationId) {
Shell::Get()->system_tray_model()->client()->ShowConnectedDevicesSettings();
message_center_->RemoveNotification(kWifiSyncNotificationId,
/* by_user */ false);
return;
}
if (notification_id != kSetupNotificationId)
return;
DCHECK(notification_status_ != Status::kNoNotificationVisible);
......@@ -219,7 +239,7 @@ void MultiDeviceNotificationPresenter::ObserveMultiDeviceSetupIfPossible() {
message_center_->AddObserver(this);
}
void MultiDeviceNotificationPresenter::ShowNotification(
void MultiDeviceNotificationPresenter::ShowSetupNotification(
const Status notification_status,
const base::string16& title,
const base::string16& message) {
......@@ -229,28 +249,33 @@ void MultiDeviceNotificationPresenter::ShowNotification(
UMA_HISTOGRAM_ENUMERATION("MultiDeviceSetup_NotificationShown",
GetMetricValueForNotification(notification_status),
kNotificationTypeMax);
if (message_center_->FindVisibleNotificationById(kNotificationId)) {
message_center_->UpdateNotification(kNotificationId,
CreateNotification(title, message));
} else {
message_center_->AddNotification(CreateNotification(title, message));
}
ShowNotification(kSetupNotificationId, title, message);
notification_status_ = notification_status;
}
std::unique_ptr<message_center::Notification>
MultiDeviceNotificationPresenter::CreateNotification(
void MultiDeviceNotificationPresenter::ShowNotification(
const std::string& id,
const base::string16& title,
const base::string16& message) {
return CreateSystemNotification(
message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE,
kNotificationId, title, message, base::string16() /* display_source */,
GURL() /* origin_url */,
message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
kNotifierMultiDevice),
message_center::RichNotificationData(), nullptr /* delegate */,
kNotificationMultiDeviceSetupIcon,
message_center::SystemNotificationWarningLevel::NORMAL);
std::unique_ptr<message_center::Notification> notification =
CreateSystemNotification(
message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE, id, title,
message, base::string16() /* display_source */,
GURL() /* origin_url */,
message_center::NotifierId(
message_center::NotifierType::SYSTEM_COMPONENT,
kNotifierMultiDevice),
message_center::RichNotificationData(), nullptr /* delegate */,
kNotificationMultiDeviceSetupIcon,
message_center::SystemNotificationWarningLevel::NORMAL);
if (message_center_->FindVisibleNotificationById(kSetupNotificationId)) {
message_center_->UpdateNotification(id, std::move(notification));
return;
}
message_center_->AddNotification(std::move(notification));
}
void MultiDeviceNotificationPresenter::FlushForTesting() {
......
......@@ -61,6 +61,7 @@ class ASH_EXPORT MultiDeviceNotificationPresenter
const std::string& new_host_device_name) override;
void OnNewChromebookAddedForExistingUser(
const std::string& new_host_device_name) override;
void OnBecameEligibleForWifiSync() override;
// SessionObserver:
void OnUserSessionAdded(const AccountId& account_id) override;
......@@ -79,7 +80,8 @@ class ASH_EXPORT MultiDeviceNotificationPresenter
friend class MultiDeviceNotificationPresenterTest;
// MultiDevice setup notification ID.
static const char kNotificationId[];
static const char kSetupNotificationId[];
static const char kWifiSyncNotificationId[];
// Represents each possible MultiDevice setup notification that the setup flow
// can show with a "none" option for the general state with no notification
......@@ -107,12 +109,12 @@ class ASH_EXPORT MultiDeviceNotificationPresenter
Status notification_status);
void ObserveMultiDeviceSetupIfPossible();
void ShowNotification(const Status notification_status,
void ShowSetupNotification(const Status notification_status,
const base::string16& title,
const base::string16& message);
void ShowNotification(const std::string& id,
const base::string16& title,
const base::string16& message);
std::unique_ptr<message_center::Notification> CreateNotification(
const base::string16& title,
const base::string16& message);
void FlushForTesting();
......
......@@ -156,36 +156,65 @@ class MultiDeviceNotificationPresenterTest : public NoSessionAshTestBase {
InvokePendingMojoCalls();
}
void ShowWifiSyncNotification() {
EXPECT_TRUE(fake_multidevice_setup_->delegate().is_bound());
fake_multidevice_setup_->delegate()->OnBecameEligibleForWifiSync();
InvokePendingMojoCalls();
}
void ClickNotification() {
test_message_center_.ClickOnNotification(
MultiDeviceNotificationPresenter::kNotificationId);
MultiDeviceNotificationPresenter::kSetupNotificationId);
}
void ClickWifiSyncNotification() {
test_message_center_.ClickOnNotification(
MultiDeviceNotificationPresenter::kWifiSyncNotificationId);
}
void DismissNotification(bool by_user) {
test_message_center_.RemoveNotification(
MultiDeviceNotificationPresenter::kNotificationId, by_user);
MultiDeviceNotificationPresenter::kSetupNotificationId, by_user);
}
void VerifyNewUserPotentialHostExistsNotificationIsVisible() {
VerifyNotificationIsVisible(
VerifySetupNotificationIsVisible(
MultiDeviceNotificationPresenter::Status::kNewUserNotificationVisible);
}
void VerifyExistingUserHostSwitchedNotificationIsVisible() {
VerifyNotificationIsVisible(
VerifySetupNotificationIsVisible(
MultiDeviceNotificationPresenter::Status::
kExistingUserHostSwitchedNotificationVisible);
}
void VerifyExistingUserNewChromebookAddedNotificationIsVisible() {
VerifyNotificationIsVisible(
VerifySetupNotificationIsVisible(
MultiDeviceNotificationPresenter::Status::
kExistingUserNewChromebookNotificationVisible);
}
void VerifyWifiSyncNotificationIsVisible() {
const message_center::Notification* kVisibleNotification =
test_message_center_.FindVisibleNotificationById(
MultiDeviceNotificationPresenter::kWifiSyncNotificationId);
base::string16 title = l10n_util::GetStringUTF16(
IDS_ASH_MULTI_DEVICE_WIFI_SYNC_AVAILABLE_TITLE);
base::string16 message = l10n_util::GetStringFUTF16(
IDS_ASH_MULTI_DEVICE_WIFI_SYNC_AVAILABLE_MESSAGE,
base::ASCIIToUTF16(kTestDeviceType));
EXPECT_EQ(title, kVisibleNotification->title());
EXPECT_EQ(message, kVisibleNotification->message());
}
void VerifyNoNotificationIsVisible() {
EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
MultiDeviceNotificationPresenter::kNotificationId));
MultiDeviceNotificationPresenter::kSetupNotificationId));
}
void VerifyNoWifiSyncNotificationIsVisible() {
EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
MultiDeviceNotificationPresenter::kWifiSyncNotificationId));
}
void AssertPotentialHostBucketCount(std::string histogram, int count) {
......@@ -232,11 +261,11 @@ class MultiDeviceNotificationPresenterTest : public NoSessionAshTestBase {
std::unique_ptr<MultiDeviceNotificationPresenter> notification_presenter_;
private:
void VerifyNotificationIsVisible(
void VerifySetupNotificationIsVisible(
MultiDeviceNotificationPresenter::Status notification_status) {
const message_center::Notification* kVisibleNotification =
test_message_center_.FindVisibleNotificationById(
MultiDeviceNotificationPresenter::kNotificationId);
MultiDeviceNotificationPresenter::kSetupNotificationId);
base::string16 title;
base::string16 message;
switch (notification_status) {
......@@ -436,6 +465,21 @@ TEST_F(
AssertNewChromebookBucketCount("MultiDeviceSetup_NotificationShown", 1);
}
TEST_F(MultiDeviceNotificationPresenterTest,
TestWifiSyncNotification_TapNotification) {
SignIntoAccount();
ShowWifiSyncNotification();
VerifyWifiSyncNotificationIsVisible();
ClickWifiSyncNotification();
VerifyNoWifiSyncNotificationIsVisible();
EXPECT_EQ(test_system_tray_client_->show_connected_devices_settings_count(),
1);
}
TEST_F(MultiDeviceNotificationPresenterTest,
TestHostExistingUserNewChromebookAddedNotification_TapNotification) {
SignIntoAccount();
......
......@@ -75,6 +75,7 @@ static_library("multidevice_setup") {
"//chromeos/services/secure_channel/public/mojom",
"//components/pref_registry",
"//components/prefs:prefs",
"//components/session_manager/core",
"//url",
]
......@@ -162,6 +163,7 @@ source_set("unit_tests") {
"//chromeos/services/multidevice_setup/public/cpp:unit_tests",
"//chromeos/services/multidevice_setup/public/mojom",
"//chromeos/services/secure_channel/public/cpp/client:test_support",
"//components/session_manager/core",
"//components/sync_preferences:test_support",
"//testing/gmock",
"//testing/gtest",
......
......@@ -2,6 +2,7 @@ include_rules = [
"+chrome/common/url_constants.h",
"+components/proximity_auth/logging/logging.h",
'+components/keyed_service/core',
"+components/session_manager/core",
"+components/sync_preferences/testing_pref_service_syncable.h",
"+components/variations",
"+mojo/public/cpp/bindings",
......
......@@ -41,6 +41,8 @@ class AccountStatusChangeDelegateNotifier {
friend class MultiDeviceSetupImpl;
friend class MultiDeviceSetupAccountStatusChangeDelegateNotifierTest;
friend class MultiDeviceSetupImplTest;
friend class WifiSyncFeatureManagerImpl;
friend class MultiDeviceSetupWifiSyncFeatureManagerImplTest;
void FlushForTesting();
......
......@@ -37,6 +37,10 @@ void FakeAccountStatusChangeDelegate::OnNewChromebookAddedForExistingUser(
++num_existing_user_chromebook_added_events_handled_;
}
void FakeAccountStatusChangeDelegate::OnBecameEligibleForWifiSync() {
++num_eligible_for_wifi_sync_events_handled_;
}
} // namespace multidevice_setup
} // namespace chromeos
......@@ -23,22 +23,26 @@ class FakeAccountStatusChangeDelegate
mojo::PendingRemote<mojom::AccountStatusChangeDelegate> GenerateRemote();
size_t num_new_user_potential_host_events_handled() {
size_t num_new_user_potential_host_events_handled() const {
return num_new_user_potential_host_events_handled_;
}
size_t num_no_longer_new_user_events_handled() {
size_t num_no_longer_new_user_events_handled() const {
return num_no_longer_new_user_events_handled_;
}
size_t num_existing_user_host_switched_events_handled() {
size_t num_existing_user_host_switched_events_handled() const {
return num_existing_user_host_switched_events_handled_;
}
size_t num_existing_user_chromebook_added_events_handled() {
size_t num_existing_user_chromebook_added_events_handled() const {
return num_existing_user_chromebook_added_events_handled_;
}
size_t num_eligible_for_wifi_sync_events_handled() const {
return num_eligible_for_wifi_sync_events_handled_;
}
// mojom::AccountStatusChangeDelegate:
void OnPotentialHostExistsForNewUser() override;
void OnNoLongerNewUser() override;
......@@ -46,12 +50,14 @@ class FakeAccountStatusChangeDelegate
const std::string& new_host_device_name) override;
void OnNewChromebookAddedForExistingUser(
const std::string& new_host_device_name) override;
void OnBecameEligibleForWifiSync() override;
private:
size_t num_new_user_potential_host_events_handled_ = 0u;
size_t num_no_longer_new_user_events_handled_ = 0u;
size_t num_existing_user_host_switched_events_handled_ = 0u;
size_t num_existing_user_chromebook_added_events_handled_ = 0u;
size_t num_eligible_for_wifi_sync_events_handled_ = 0u;
mojo::ReceiverSet<mojom::AccountStatusChangeDelegate> receivers_;
......
......@@ -121,17 +121,6 @@ MultiDeviceSetupImpl::MultiDeviceSetupImpl(
host_backend_delegate_.get(),
device_sync_client,
pref_service)),
wifi_sync_feature_manager_(WifiSyncFeatureManagerImpl::Factory::Create(
host_status_provider_.get(),
pref_service,
device_sync_client)),
feature_state_manager_(FeatureStateManagerImpl::Factory::Create(
pref_service,
host_status_provider_.get(),
device_sync_client,
android_sms_pairing_state_tracker,
wifi_sync_feature_manager_.get(),
is_secondary_user)),
host_device_timestamp_manager_(
HostDeviceTimestampManagerImpl::Factory::Create(
host_status_provider_.get(),
......@@ -144,6 +133,18 @@ MultiDeviceSetupImpl::MultiDeviceSetupImpl(
host_device_timestamp_manager_.get(),
oobe_completion_tracker,
base::DefaultClock::GetInstance())),
wifi_sync_feature_manager_(WifiSyncFeatureManagerImpl::Factory::Create(
host_status_provider_.get(),
pref_service,
device_sync_client,
delegate_notifier_.get())),
feature_state_manager_(FeatureStateManagerImpl::Factory::Create(
pref_service,
host_status_provider_.get(),
device_sync_client,
android_sms_pairing_state_tracker,
wifi_sync_feature_manager_.get(),
is_secondary_user)),
device_reenroller_(
DeviceReenroller::Factory::Create(device_sync_client,
gcm_device_info_provider)),
......
......@@ -147,10 +147,10 @@ class MultiDeviceSetupImpl : public MultiDeviceSetupBase,
std::unique_ptr<HostStatusProvider> host_status_provider_;
std::unique_ptr<GrandfatheredEasyUnlockHostDisabler>
grandfathered_easy_unlock_host_disabler_;
std::unique_ptr<WifiSyncFeatureManager> wifi_sync_feature_manager_;
std::unique_ptr<FeatureStateManager> feature_state_manager_;
std::unique_ptr<HostDeviceTimestampManager> host_device_timestamp_manager_;
std::unique_ptr<AccountStatusChangeDelegateNotifier> delegate_notifier_;
std::unique_ptr<WifiSyncFeatureManager> wifi_sync_feature_manager_;
std::unique_ptr<FeatureStateManager> feature_state_manager_;
std::unique_ptr<DeviceReenroller> device_reenroller_;
std::unique_ptr<AndroidSmsAppInstallingStatusObserver>
android_sms_app_installing_host_observer_;
......
......@@ -263,6 +263,7 @@ class FakeWifiSyncFeatureManagerFactory
HostStatusProvider* host_status_provider,
PrefService* pref_service,
device_sync::DeviceSyncClient* device_sync_client,
AccountStatusChangeDelegateNotifier* delegate_notifier,
std::unique_ptr<base::OneShotTimer> timer) override {
EXPECT_FALSE(instance_);
EXPECT_EQ(fake_host_status_provider_factory_->instance(),
......
......@@ -110,6 +110,9 @@ struct HostDevice {
chromeos.device_sync.mojom.ConnectivityStatus connectivity_status;
};
// Delegate used to notify Chrome OS UI (//ash) of multidevice account changes
// from the multidevice setup service (//chromeos/services/multidevice_setup).
// Both sides currently live in the Chrome process.
interface AccountStatusChangeDelegate {
// Callback which indicates that one or more MultiDevice host phones are
// available for setup with the MultiDevice setup flow. This function is only
......@@ -134,6 +137,11 @@ interface AccountStatusChangeDelegate {
// the current user. This function is only called if the current user has
// already set up MultiDevice features.
OnNewChromebookAddedForExistingUser(string new_host_device_name);
// Indicates that the existing host has become eligible for Wi-Fi Sync, but
// the feature is not yet enabled. This is called when the announcement
// notification should be shown.
OnBecameEligibleForWifiSync();
};
interface HostStatusObserver {
......
......@@ -18,6 +18,7 @@
#include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/session_manager/core/session_manager.h"
namespace chromeos {
......@@ -28,6 +29,12 @@ namespace {
const char kPendingWifiSyncRequestEnabledPrefName[] =
"multidevice_setup.pending_set_wifi_sync_enabled_request";
// Pref to track whether the announcement notification can be shown the next
// time the device is unlocked with a verified host and wi-fi sync supported but
// disabled.
const char kCanShowAnnouncementPrefName[] =
"multidevice_setup.can_show_wifi_sync_announcement";
// The number of minutes to wait before retrying a failed attempt.
const int kNumMinutesBetweenRetries = 5;
......@@ -43,15 +50,17 @@ WifiSyncFeatureManagerImpl::Factory::Create(
HostStatusProvider* host_status_provider,
PrefService* pref_service,
device_sync::DeviceSyncClient* device_sync_client,
AccountStatusChangeDelegateNotifier* delegate_notifier,
std::unique_ptr<base::OneShotTimer> timer) {
if (test_factory_) {
return test_factory_->CreateInstance(host_status_provider, pref_service,
device_sync_client, std::move(timer));
device_sync_client, delegate_notifier,
std::move(timer));
}
return base::WrapUnique(
new WifiSyncFeatureManagerImpl(host_status_provider, pref_service,
device_sync_client, std::move(timer)));
return base::WrapUnique(new WifiSyncFeatureManagerImpl(
host_status_provider, pref_service, device_sync_client, delegate_notifier,
std::move(timer)));
}
// static
......@@ -65,22 +74,24 @@ WifiSyncFeatureManagerImpl::Factory::~Factory() = default;
void WifiSyncFeatureManagerImpl::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterIntegerPref(kPendingWifiSyncRequestEnabledPrefName,
static_cast<int>(PendingState::kPendingNone));
registry->RegisterBooleanPref(kCanShowAnnouncementPrefName, true);
}
WifiSyncFeatureManagerImpl::~WifiSyncFeatureManagerImpl() = default;
WifiSyncFeatureManagerImpl::WifiSyncFeatureManagerImpl(
HostStatusProvider* host_status_provider,
PrefService* pref_service,
device_sync::DeviceSyncClient* device_sync_client,
AccountStatusChangeDelegateNotifier* delegate_notifier,
std::unique_ptr<base::OneShotTimer> timer)
: WifiSyncFeatureManager(),
host_status_provider_(host_status_provider),
pref_service_(pref_service),
device_sync_client_(device_sync_client),
delegate_notifier_(delegate_notifier),
timer_(std::move(timer)) {
host_status_provider_->AddObserver(this);
device_sync_client_->AddObserver(this);
session_manager::SessionManager::Get()->AddObserver(this);
if (GetCurrentState() == CurrentState::kValidPendingRequest) {
AttemptSetWifiSyncHostStateNetworkRequest(false /* is_retry */);
......@@ -91,6 +102,12 @@ WifiSyncFeatureManagerImpl::WifiSyncFeatureManagerImpl(
}
}
WifiSyncFeatureManagerImpl::~WifiSyncFeatureManagerImpl() {
host_status_provider_->RemoveObserver(this);
device_sync_client_->RemoveObserver(this);
session_manager::SessionManager::Get()->RemoveObserver(this);
}
void WifiSyncFeatureManagerImpl::OnHostStatusChange(
const HostStatusProvider::HostStatusWithDevice& host_status_with_device) {
if (GetCurrentState() == CurrentState::kNoVerifiedHost &&
......@@ -116,6 +133,45 @@ void WifiSyncFeatureManagerImpl::OnNewDevicesSynced() {
}
}
void WifiSyncFeatureManagerImpl::OnSessionStateChanged() {
if (session_manager::SessionManager::Get()->IsUserSessionBlocked()) {
return;
}
// Show the announcement notification when the device is unlocked and
// eligible for wi-fi sync. This is done on unlock to avoid showing the
// notification on the first sign-in when it would distract from showoff
// and other announcements.
ShowAnnouncementNotificationIfEligible();
}
void WifiSyncFeatureManagerImpl::ShowAnnouncementNotificationIfEligible() {
if (!IsFeatureAllowed(mojom::Feature::kWifiSync, pref_service_)) {
return;
}
if (!pref_service_->GetBoolean(kCanShowAnnouncementPrefName)) {
return;
}
if (!IsWifiSyncSupported()) {
return;
}
if (GetCurrentState() == CurrentState::kNoVerifiedHost ||
IsWifiSyncEnabled()) {
pref_service_->SetBoolean(kCanShowAnnouncementPrefName, false);
return;
}
if (!delegate_notifier_->delegate()) {
return;
}
delegate_notifier_->delegate()->OnBecameEligibleForWifiSync();
pref_service_->SetBoolean(kCanShowAnnouncementPrefName, false);
}
void WifiSyncFeatureManagerImpl::SetIsWifiSyncEnabled(bool enabled) {
if (GetCurrentState() == CurrentState::kNoVerifiedHost) {
PA_LOG(ERROR)
......@@ -127,6 +183,7 @@ void WifiSyncFeatureManagerImpl::SetIsWifiSyncEnabled(bool enabled) {
SetPendingWifiSyncHostNetworkRequest(enabled ? PendingState::kPendingEnable
: PendingState::kPendingDisable);
pref_service_->SetBoolean(kCanShowAnnouncementPrefName, false);
// Stop timer since new attempt is started.
timer_->Stop();
......@@ -150,6 +207,19 @@ bool WifiSyncFeatureManagerImpl::IsWifiSyncEnabled() {
multidevice::SoftwareFeatureState::kEnabled;
}
bool WifiSyncFeatureManagerImpl::IsWifiSyncSupported() {
CurrentState current_state = GetCurrentState();
if (current_state == CurrentState::kNoVerifiedHost) {
return false;
}
return host_status_provider_->GetHostWithStatus()
.host_device()
->GetSoftwareFeatureState(
multidevice::SoftwareFeature::kWifiSyncHost) !=
multidevice::SoftwareFeatureState::kNotSupported;
}
void WifiSyncFeatureManagerImpl::ResetPendingWifiSyncHostNetworkRequest() {
SetPendingWifiSyncHostNetworkRequest(PendingState::kPendingNone);
timer_->Stop();
......
......@@ -12,7 +12,9 @@
#include "base/timer/timer.h"
#include "chromeos/components/multidevice/remote_device_ref.h"
#include "chromeos/services/device_sync/public/cpp/device_sync_client.h"
#include "chromeos/services/multidevice_setup/account_status_change_delegate_notifier.h"
#include "chromeos/services/multidevice_setup/wifi_sync_feature_manager.h"
#include "components/session_manager/core/session_manager_observer.h"
class PrefRegistrySimple;
class PrefService;
......@@ -32,7 +34,8 @@ namespace multidevice_setup {
class WifiSyncFeatureManagerImpl
: public WifiSyncFeatureManager,
public HostStatusProvider::Observer,
public device_sync::DeviceSyncClient::Observer {
public device_sync::DeviceSyncClient::Observer,
public session_manager::SessionManagerObserver {
public:
class Factory {
public:
......@@ -40,6 +43,7 @@ class WifiSyncFeatureManagerImpl
HostStatusProvider* host_status_provider,
PrefService* pref_service,
device_sync::DeviceSyncClient* device_sync_client,
AccountStatusChangeDelegateNotifier* delegate_notifier,
std::unique_ptr<base::OneShotTimer> timer =
std::make_unique<base::OneShotTimer>());
static void SetFactoryForTesting(Factory* test_factory);
......@@ -50,6 +54,7 @@ class WifiSyncFeatureManagerImpl
HostStatusProvider* host_status_provider,
PrefService* pref_service,
device_sync::DeviceSyncClient* device_sync_client,
AccountStatusChangeDelegateNotifier* delegate_notifier,
std::unique_ptr<base::OneShotTimer> timer) = 0;
private:
......@@ -64,10 +69,12 @@ class WifiSyncFeatureManagerImpl
delete;
private:
WifiSyncFeatureManagerImpl(HostStatusProvider* host_status_provider,
PrefService* pref_service,
device_sync::DeviceSyncClient* device_sync_client,
std::unique_ptr<base::OneShotTimer> timer);
WifiSyncFeatureManagerImpl(
HostStatusProvider* host_status_provider,
PrefService* pref_service,
device_sync::DeviceSyncClient* device_sync_client,
AccountStatusChangeDelegateNotifier* delegate_notifier,
std::unique_ptr<base::OneShotTimer> timer);
// HostStatusProvider::Observer,
void OnHostStatusChange(const HostStatusProvider::HostStatusWithDevice&
......@@ -76,6 +83,9 @@ class WifiSyncFeatureManagerImpl
// DeviceSyncClient::Observer:
void OnNewDevicesSynced() override;
// SessionManagerObserver:
void OnSessionStateChanged() override;
// WifiSyncFeatureManager:
// Attempts to enable/disable WIFI_SYNC_HOST on the backend for the host
......@@ -124,10 +134,13 @@ class WifiSyncFeatureManagerImpl
bool ShouldEnableOnVerify();
void ProcessEnableOnVerifyAttempt();
bool ShouldAttemptToEnableAfterHostVerified();
void ShowAnnouncementNotificationIfEligible();
bool IsWifiSyncSupported();
HostStatusProvider* host_status_provider_;
PrefService* pref_service_;
device_sync::DeviceSyncClient* device_sync_client_;
AccountStatusChangeDelegateNotifier* delegate_notifier_;
std::unique_ptr<base::OneShotTimer> timer_;
bool network_request_in_flight_ = false;
......
......@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/optional.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/timer/mock_timer.h"
#include "base/unguessable_token.h"
#include "chromeos/components/multidevice/remote_device_test_util.h"
......@@ -17,9 +18,12 @@
#include "chromeos/components/multidevice/software_feature_state.h"
#include "chromeos/constants/chromeos_features.h"
#include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h"
#include "chromeos/services/multidevice_setup/fake_account_status_change_delegate.h"
#include "chromeos/services/multidevice_setup/fake_account_status_change_delegate_notifier.h"
#include "chromeos/services/multidevice_setup/fake_host_status_provider.h"
#include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
#include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
#include "components/session_manager/core/session_manager.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -74,9 +78,18 @@ class MultiDeviceSetupWifiSyncFeatureManagerImplTest
// Allow Wifi Sync by policy
test_pref_service_->registry()->RegisterBooleanPref(
kWifiSyncAllowedPrefName, true);
session_manager_ = std::make_unique<session_manager::SessionManager>();
fake_device_sync_client_ =
std::make_unique<device_sync::FakeDeviceSyncClient>();
fake_device_sync_client_->set_synced_devices(test_devices_);
fake_account_status_change_delegate_ =
std::make_unique<FakeAccountStatusChangeDelegate>();
fake_account_status_change_delegate_notifier_ =
std::make_unique<FakeAccountStatusChangeDelegateNotifier>();
fake_account_status_change_delegate_notifier_
->SetAccountStatusChangeDelegateRemote(
fake_account_status_change_delegate_->GenerateRemote());
fake_account_status_change_delegate_notifier_->FlushForTesting();
}
void TearDown() override {}
......@@ -122,7 +135,9 @@ class MultiDeviceSetupWifiSyncFeatureManagerImplTest
delegate_ = WifiSyncFeatureManagerImpl::Factory::Create(
fake_host_status_provider_.get(), test_pref_service_.get(),
fake_device_sync_client_.get(), std::move(mock_timer));
fake_device_sync_client_.get(),
fake_account_status_change_delegate_notifier_.get(),
std::move(mock_timer));
}
void SetHostWithStatus(
......@@ -257,6 +272,14 @@ class MultiDeviceSetupWifiSyncFeatureManagerImplTest
return fake_device_sync_client_.get();
}
FakeAccountStatusChangeDelegate* fake_account_status_change_delegate() {
return fake_account_status_change_delegate_.get();
}
void FlushDelegateNotifier() {
fake_account_status_change_delegate_notifier_->FlushForTesting();
}
base::MockOneShotTimer* mock_timer() { return mock_timer_; }
WifiSyncFeatureManager* delegate() { return delegate_.get(); }
......@@ -268,13 +291,25 @@ class MultiDeviceSetupWifiSyncFeatureManagerImplTest
const multidevice::RemoteDeviceRefList& test_devices() const {
return test_devices_;
}
session_manager::SessionManager* session_manager() {
return session_manager_.get();
}
private:
base::test::TaskEnvironment task_environment_;
multidevice::RemoteDeviceRefList test_devices_;
std::unique_ptr<session_manager::SessionManager> session_manager_;
std::unique_ptr<FakeHostStatusProvider> fake_host_status_provider_;
std::unique_ptr<sync_preferences::TestingPrefServiceSyncable>
test_pref_service_;
std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_;
std::unique_ptr<FakeAccountStatusChangeDelegateNotifier>
fake_account_status_change_delegate_notifier_;
std::unique_ptr<FakeAccountStatusChangeDelegate>
fake_account_status_change_delegate_;
base::MockOneShotTimer* mock_timer_;
std::unique_ptr<WifiSyncFeatureManager> delegate_;
......@@ -899,6 +934,65 @@ TEST_P(MultiDeviceSetupWifiSyncFeatureManagerImplTest,
multidevice::SoftwareFeatureState::kEnabled);
}
TEST_P(MultiDeviceSetupWifiSyncFeatureManagerImplTest,
Notification_ShownOnFirstUnlockAfterPhoneEnabled) {
SetFeatureFlags(GetParam() /* use_v1_devicesync */,
true /* enable_wifi_sync */);
fake_host_status_provider()->SetHostWithStatus(
mojom::HostStatus::kHostVerified, test_devices()[0]);
CreateDelegate(test_devices()[0] /* initial_host */,
kPendingNone /* initial_pending_wifi_sync_request */);
EXPECT_FALSE(delegate()->IsWifiSyncEnabled());
EXPECT_EQ(test_devices()[0].GetSoftwareFeatureState(
multidevice::SoftwareFeature::kWifiSyncHost),
multidevice::SoftwareFeatureState::kSupported);
// Simulate lock/unlock
session_manager()->SetSessionState(session_manager::SessionState::LOCKED);
session_manager()->SetSessionState(session_manager::SessionState::ACTIVE);
FlushDelegateNotifier();
// Shown on first unlock.
EXPECT_EQ(1u, fake_account_status_change_delegate()
->num_eligible_for_wifi_sync_events_handled());
session_manager()->SetSessionState(session_manager::SessionState::LOCKED);
session_manager()->SetSessionState(session_manager::SessionState::ACTIVE);
FlushDelegateNotifier();
// Not shown on second unlock.
EXPECT_EQ(1u, fake_account_status_change_delegate()
->num_eligible_for_wifi_sync_events_handled());
}
TEST_P(MultiDeviceSetupWifiSyncFeatureManagerImplTest,
Notification_NotShownIfAlreadyEnabled) {
SetFeatureFlags(GetParam() /* use_v1_devicesync */,
true /* enable_wifi_sync */);
fake_host_status_provider()->SetHostWithStatus(
mojom::HostStatus::kHostVerified, test_devices()[0]);
CreateDelegate(test_devices()[0] /* initial_host */,
kPendingNone /* initial_pending_wifi_sync_request */);
SetIsWifiSyncEnabled(true);
EXPECT_TRUE(delegate()->IsWifiSyncEnabled());
EXPECT_EQ(test_devices()[0].GetSoftwareFeatureState(
multidevice::SoftwareFeature::kWifiSyncHost),
multidevice::SoftwareFeatureState::kSupported);
// Simulate lock/unlock
session_manager()->SetSessionState(session_manager::SessionState::LOCKED);
session_manager()->SetSessionState(session_manager::SessionState::ACTIVE);
FlushDelegateNotifier();
EXPECT_EQ(0u, fake_account_status_change_delegate()
->num_eligible_for_wifi_sync_events_handled());
}
// Runs tests twice; once with v1 DeviceSync enabled and once with it disabled.
// TODO(https://crbug.com/1019206): Remove when v1 DeviceSync is disabled,
// when all devices should have an Instance ID.
......
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