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.
5 #include "ash/multi_device_setup/multi_device_notification_presenter.h"
10 #include "ash/public/cpp/notification_utils.h"
11 #include "ash/public/cpp/system_tray_client.h"
12 #include "ash/resources/vector_icons/vector_icons.h"
13 #include "ash/session/session_controller_impl.h"
14 #include "ash/shell.h"
15 #include "ash/shell_delegate.h"
16 #include "ash/strings/grit/ash_strings.h"
17 #include "ash/system/model/system_tray_model.h"
18 #include "base/callback_helpers.h"
19 #include "base/memory/ptr_util.h"
20 #include "base/metrics/histogram_functions.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "chromeos/components/multidevice/logging/logging.h"
23 #include "ui/base/l10n/l10n_util.h"
24 #include "ui/chromeos/devicetype_utils.h"
25 #include "ui/message_center/message_center.h"
26 #include "ui/message_center/public/cpp/notifier_id.h"
32 const char kNotifierMultiDevice[] = "ash.multi_device_setup";
37 const char MultiDeviceNotificationPresenter::kSetupNotificationId[] =
38 "cros_multi_device_setup_notification_id";
41 const char MultiDeviceNotificationPresenter::kWifiSyncNotificationId[] =
42 "cros_wifi_sync_announcement_notification_id";
46 MultiDeviceNotificationPresenter::GetNotificationDescriptionForLogging(
47 Status notification_status) {
48 switch (notification_status) {
49 case Status::kNewUserNotificationVisible:
50 return "notification to prompt setup";
51 case Status::kExistingUserHostSwitchedNotificationVisible:
52 return "notification of switch to new host";
53 case Status::kExistingUserNewChromebookNotificationVisible:
54 return "notification of new Chromebook added";
55 case Status::kNoNotificationVisible:
56 return "no notification";
62 MultiDeviceNotificationPresenter::NotificationType
63 MultiDeviceNotificationPresenter::GetMetricValueForNotification(
64 Status notification_status) {
65 switch (notification_status) {
66 case Status::kNewUserNotificationVisible:
67 return NotificationType::kNewUserPotentialHostExists;
68 case Status::kExistingUserHostSwitchedNotificationVisible:
69 return NotificationType::kExistingUserHostSwitched;
70 case Status::kExistingUserNewChromebookNotificationVisible:
71 return NotificationType::kExistingUserNewChromebookAdded;
72 case Status::kNoNotificationVisible:
74 return NotificationType::kErrorUnknown;
78 MultiDeviceNotificationPresenter::MultiDeviceNotificationPresenter(
79 message_center::MessageCenter* message_center)
80 : message_center_(message_center) {
81 DCHECK(message_center_);
83 Shell::Get()->session_controller()->AddObserver(this);
85 // If the constructor is called after the session state has already been set
86 // (e.g., if recovering from a crash), handle that now. If the user has not
87 // yet logged in, this will be a no-op.
88 ObserveMultiDeviceSetupIfPossible();
91 MultiDeviceNotificationPresenter::~MultiDeviceNotificationPresenter() {
92 message_center_->RemoveObserver(this);
93 Shell::Get()->session_controller()->RemoveObserver(this);
96 void MultiDeviceNotificationPresenter::OnPotentialHostExistsForNewUser() {
97 std::u16string title = l10n_util::GetStringUTF16(
98 IDS_ASH_MULTI_DEVICE_SETUP_NEW_USER_POTENTIAL_HOST_EXISTS_TITLE);
99 std::u16string message = l10n_util::GetStringFUTF16(
100 IDS_ASH_MULTI_DEVICE_SETUP_NEW_USER_POTENTIAL_HOST_EXISTS_MESSAGE,
101 ui::GetChromeOSDeviceName());
102 ShowSetupNotification(Status::kNewUserNotificationVisible, title, message);
105 void MultiDeviceNotificationPresenter::OnNoLongerNewUser() {
106 if (notification_status_ != Status::kNewUserNotificationVisible)
108 RemoveMultiDeviceSetupNotification();
111 void MultiDeviceNotificationPresenter::OnConnectedHostSwitchedForExistingUser(
112 const std::string& new_host_device_name) {
113 std::u16string title = l10n_util::GetStringFUTF16(
114 IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_HOST_SWITCHED_TITLE,
115 base::ASCIIToUTF16(new_host_device_name));
116 std::u16string message = l10n_util::GetStringFUTF16(
117 IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_HOST_SWITCHED_MESSAGE,
118 ui::GetChromeOSDeviceName());
119 ShowSetupNotification(Status::kExistingUserHostSwitchedNotificationVisible,
123 void MultiDeviceNotificationPresenter::OnNewChromebookAddedForExistingUser(
124 const std::string& new_host_device_name) {
125 std::u16string title = l10n_util::GetStringFUTF16(
126 IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_NEW_CHROME_DEVICE_ADDED_TITLE,
127 base::ASCIIToUTF16(new_host_device_name));
128 std::u16string message = l10n_util::GetStringFUTF16(
129 IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_NEW_CHROME_DEVICE_ADDED_MESSAGE,
130 ui::GetChromeOSDeviceName());
131 ShowSetupNotification(Status::kExistingUserNewChromebookNotificationVisible,
135 void MultiDeviceNotificationPresenter::OnBecameEligibleForWifiSync() {
136 std::u16string title =
137 l10n_util::GetStringUTF16(IDS_ASH_MULTI_DEVICE_WIFI_SYNC_AVAILABLE_TITLE);
138 std::u16string message = l10n_util::GetStringFUTF16(
139 IDS_ASH_MULTI_DEVICE_WIFI_SYNC_AVAILABLE_MESSAGE,
140 ui::GetChromeOSDeviceName());
141 message_center::RichNotificationData optional_fields;
142 optional_fields.buttons.push_back(
143 message_center::ButtonInfo(l10n_util::GetStringUTF16(
144 IDS_ASH_MULTI_DEVICE_WIFI_SYNC_AVAILABLE_TURN_ON_BUTTON)));
145 optional_fields.buttons.push_back(
146 message_center::ButtonInfo(l10n_util::GetStringUTF16(
147 IDS_ASH_MULTI_DEVICE_WIFI_SYNC_AVAILABLE_CANCEL_BUTTON)));
149 ShowNotification(kWifiSyncNotificationId, title, message, optional_fields);
150 base::UmaHistogramEnumeration("MultiDeviceSetup_NotificationShown",
151 NotificationType::kWifiSyncAnnouncement);
154 void MultiDeviceNotificationPresenter::RemoveMultiDeviceSetupNotification() {
155 notification_status_ = Status::kNoNotificationVisible;
156 message_center_->RemoveNotification(kSetupNotificationId,
157 /* by_user */ false);
160 void MultiDeviceNotificationPresenter::OnUserSessionAdded(
161 const AccountId& account_id) {
162 ObserveMultiDeviceSetupIfPossible();
165 void MultiDeviceNotificationPresenter::OnSessionStateChanged(
166 session_manager::SessionState state) {
167 ObserveMultiDeviceSetupIfPossible();
170 void MultiDeviceNotificationPresenter::OnNotificationRemoved(
171 const std::string& notification_id,
176 if (notification_id == kSetupNotificationId) {
177 base::UmaHistogramEnumeration(
178 "MultiDeviceSetup_NotificationDismissed",
179 GetMetricValueForNotification(notification_status_));
182 if (notification_id == kWifiSyncNotificationId) {
183 base::UmaHistogramEnumeration("MultiDeviceSetup_NotificationDismissed",
184 NotificationType::kWifiSyncAnnouncement);
189 void MultiDeviceNotificationPresenter::OnNotificationClicked(
190 const std::string& notification_id,
191 const absl::optional<int>& button_index,
192 const absl::optional<std::u16string>& reply) {
193 if (notification_id == kWifiSyncNotificationId) {
194 message_center_->RemoveNotification(kWifiSyncNotificationId,
195 /* by_user */ false);
198 switch (*button_index) {
199 case 0: // "Turn on" button
200 PA_LOG(INFO) << "Enabling Wi-Fi Sync.";
201 multidevice_setup_remote_->SetFeatureEnabledState(
202 chromeos::multidevice_setup::mojom::Feature::kWifiSync,
203 /*enabled=*/true, /*auth_token=*/absl::nullopt,
204 /*callback=*/base::DoNothing());
206 case 1: // "Cancel" button
207 base::UmaHistogramEnumeration(
208 "MultiDeviceSetup_NotificationDismissed",
209 NotificationType::kWifiSyncAnnouncement);
214 Shell::Get()->system_tray_model()->client()->ShowWifiSyncSettings();
215 base::UmaHistogramEnumeration("MultiDeviceSetup_NotificationClicked",
216 NotificationType::kWifiSyncAnnouncement);
220 if (notification_id != kSetupNotificationId)
223 DCHECK(notification_status_ != Status::kNoNotificationVisible);
224 PA_LOG(VERBOSE) << "User clicked "
225 << GetNotificationDescriptionForLogging(notification_status_)
227 base::UmaHistogramEnumeration(
228 "MultiDeviceSetup_NotificationClicked",
229 GetMetricValueForNotification(notification_status_));
230 switch (notification_status_) {
231 case Status::kNewUserNotificationVisible:
232 Shell::Get()->system_tray_model()->client()->ShowMultiDeviceSetup();
234 case Status::kExistingUserHostSwitchedNotificationVisible:
235 // Clicks on the 'host switched' and 'Chromebook added' notifications have
236 // the same effect, i.e. opening the Settings subpage.
238 case Status::kExistingUserNewChromebookNotificationVisible:
240 ->system_tray_model()
242 ->ShowConnectedDevicesSettings();
244 case Status::kNoNotificationVisible:
247 RemoveMultiDeviceSetupNotification();
250 void MultiDeviceNotificationPresenter::ObserveMultiDeviceSetupIfPossible() {
251 // If already the delegate, there is nothing else to do.
252 if (multidevice_setup_remote_)
255 const SessionControllerImpl* session_controller =
256 Shell::Get()->session_controller();
258 if (session_controller->GetSessionState() !=
259 session_manager::SessionState::ACTIVE) {
263 const UserSession* user_session = session_controller->GetPrimaryUserSession();
265 // The primary user session may be unavailable (e.g., for test/guest users).
269 Shell::Get()->shell_delegate()->BindMultiDeviceSetup(
270 multidevice_setup_remote_.BindNewPipeAndPassReceiver());
272 // Add this object as the delegate of the MultiDeviceSetup Service.
273 multidevice_setup_remote_->SetAccountStatusChangeDelegate(
274 receiver_.BindNewPipeAndPassRemote());
276 message_center_->AddObserver(this);
279 void MultiDeviceNotificationPresenter::ShowSetupNotification(
280 const Status notification_status,
281 const std::u16string& title,
282 const std::u16string& message) {
283 PA_LOG(VERBOSE) << "Showing "
284 << GetNotificationDescriptionForLogging(notification_status)
286 base::UmaHistogramEnumeration(
287 "MultiDeviceSetup_NotificationShown",
288 GetMetricValueForNotification(notification_status));
290 ShowNotification(kSetupNotificationId, title, message,
291 message_center::RichNotificationData());
292 notification_status_ = notification_status;
295 void MultiDeviceNotificationPresenter::ShowNotification(
296 const std::string& id,
297 const std::u16string& title,
298 const std::u16string& message,
299 message_center::RichNotificationData optional_fields) {
300 std::unique_ptr<message_center::Notification> notification =
301 CreateSystemNotification(
302 message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE, id, title,
303 message, std::u16string() /* display_source */,
304 GURL() /* origin_url */,
305 message_center::NotifierId(
306 message_center::NotifierType::SYSTEM_COMPONENT,
307 kNotifierMultiDevice),
308 optional_fields, nullptr /* delegate */,
309 kNotificationMultiDeviceSetupIcon,
310 message_center::SystemNotificationWarningLevel::NORMAL);
312 if (message_center_->FindVisibleNotificationById(kSetupNotificationId)) {
313 message_center_->UpdateNotification(id, std::move(notification));
317 message_center_->AddNotification(std::move(notification));
320 void MultiDeviceNotificationPresenter::FlushForTesting() {
321 if (multidevice_setup_remote_)
322 multidevice_setup_remote_.FlushForTesting();