Upload upstream chromium 108.0.5359.1
[platform/framework/web/chromium-efl.git] / ash / multi_device_setup / multi_device_notification_presenter.cc
1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ash/multi_device_setup/multi_device_notification_presenter.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "ash/constants/notifier_catalogs.h"
11 #include "ash/public/cpp/notification_utils.h"
12 #include "ash/public/cpp/system_tray_client.h"
13 #include "ash/resources/vector_icons/vector_icons.h"
14 #include "ash/session/session_controller_impl.h"
15 #include "ash/shell.h"
16 #include "ash/shell_delegate.h"
17 #include "ash/strings/grit/ash_strings.h"
18 #include "ash/system/model/system_tray_model.h"
19 #include "base/callback_helpers.h"
20 #include "base/memory/ptr_util.h"
21 #include "base/metrics/histogram_functions.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "chromeos/ash/components/multidevice/logging/logging.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/chromeos/devicetype_utils.h"
26 #include "ui/message_center/message_center.h"
27 #include "ui/message_center/public/cpp/notifier_id.h"
28
29 namespace ash {
30
31 namespace {
32
33 bool g_disable_notifications_for_test_ = false;
34
35 const char kNotifierMultiDevice[] = "ash.multi_device_setup";
36
37 }  // namespace
38
39 // static
40 const char MultiDeviceNotificationPresenter::kSetupNotificationId[] =
41     "cros_multi_device_setup_notification_id";
42
43 // static
44 const char MultiDeviceNotificationPresenter::kWifiSyncNotificationId[] =
45     "cros_wifi_sync_announcement_notification_id";
46
47 // static
48 std::string
49 MultiDeviceNotificationPresenter::GetNotificationDescriptionForLogging(
50     Status notification_status) {
51   switch (notification_status) {
52     case Status::kNewUserNotificationVisible:
53       return "notification to prompt setup";
54     case Status::kExistingUserHostSwitchedNotificationVisible:
55       return "notification of switch to new host";
56     case Status::kExistingUserNewChromebookNotificationVisible:
57       return "notification of new Chromebook added";
58     case Status::kNoNotificationVisible:
59       return "no notification";
60   }
61   NOTREACHED();
62 }
63
64 // static
65 MultiDeviceNotificationPresenter::NotificationType
66 MultiDeviceNotificationPresenter::GetMetricValueForNotification(
67     Status notification_status) {
68   switch (notification_status) {
69     case Status::kNewUserNotificationVisible:
70       return NotificationType::kNewUserPotentialHostExists;
71     case Status::kExistingUserHostSwitchedNotificationVisible:
72       return NotificationType::kExistingUserHostSwitched;
73     case Status::kExistingUserNewChromebookNotificationVisible:
74       return NotificationType::kExistingUserNewChromebookAdded;
75     case Status::kNoNotificationVisible:
76       NOTREACHED();
77       return NotificationType::kErrorUnknown;
78   }
79 }
80
81 MultiDeviceNotificationPresenter::MultiDeviceNotificationPresenter(
82     message_center::MessageCenter* message_center)
83     : message_center_(message_center) {
84   DCHECK(message_center_);
85
86   Shell::Get()->session_controller()->AddObserver(this);
87
88   // If the constructor is called after the session state has already been set
89   // (e.g., if recovering from a crash), handle that now. If the user has not
90   // yet logged in, this will be a no-op.
91   ObserveMultiDeviceSetupIfPossible();
92 }
93
94 MultiDeviceNotificationPresenter::~MultiDeviceNotificationPresenter() {
95   message_center_->RemoveObserver(this);
96   Shell::Get()->session_controller()->RemoveObserver(this);
97 }
98
99 void MultiDeviceNotificationPresenter::OnPotentialHostExistsForNewUser() {
100   std::u16string title = l10n_util::GetStringUTF16(
101       IDS_ASH_MULTI_DEVICE_SETUP_NEW_USER_POTENTIAL_HOST_EXISTS_TITLE);
102   std::u16string message = l10n_util::GetStringFUTF16(
103       IDS_ASH_MULTI_DEVICE_SETUP_NEW_USER_POTENTIAL_HOST_EXISTS_MESSAGE,
104       ui::GetChromeOSDeviceName());
105   ShowSetupNotification(Status::kNewUserNotificationVisible, title, message);
106 }
107
108 void MultiDeviceNotificationPresenter::OnNoLongerNewUser() {
109   if (notification_status_ != Status::kNewUserNotificationVisible)
110     return;
111   RemoveMultiDeviceSetupNotification();
112 }
113
114 void MultiDeviceNotificationPresenter::OnConnectedHostSwitchedForExistingUser(
115     const std::string& new_host_device_name) {
116   std::u16string title = l10n_util::GetStringFUTF16(
117       IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_HOST_SWITCHED_TITLE,
118       base::ASCIIToUTF16(new_host_device_name));
119   std::u16string message = l10n_util::GetStringFUTF16(
120       IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_HOST_SWITCHED_MESSAGE,
121       ui::GetChromeOSDeviceName());
122   ShowSetupNotification(Status::kExistingUserHostSwitchedNotificationVisible,
123                         title, message);
124 }
125
126 void MultiDeviceNotificationPresenter::OnNewChromebookAddedForExistingUser(
127     const std::string& new_host_device_name) {
128   std::u16string title = l10n_util::GetStringFUTF16(
129       IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_NEW_CHROME_DEVICE_ADDED_TITLE,
130       base::ASCIIToUTF16(new_host_device_name));
131   std::u16string message = l10n_util::GetStringFUTF16(
132       IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_NEW_CHROME_DEVICE_ADDED_MESSAGE,
133       ui::GetChromeOSDeviceName());
134   ShowSetupNotification(Status::kExistingUserNewChromebookNotificationVisible,
135                         title, message);
136 }
137
138 void MultiDeviceNotificationPresenter::OnBecameEligibleForWifiSync() {
139   std::u16string title =
140       l10n_util::GetStringUTF16(IDS_ASH_MULTI_DEVICE_WIFI_SYNC_AVAILABLE_TITLE);
141   std::u16string message = l10n_util::GetStringFUTF16(
142       IDS_ASH_MULTI_DEVICE_WIFI_SYNC_AVAILABLE_MESSAGE,
143       ui::GetChromeOSDeviceName());
144   message_center::RichNotificationData optional_fields;
145   optional_fields.buttons.push_back(
146       message_center::ButtonInfo(l10n_util::GetStringUTF16(
147           IDS_ASH_MULTI_DEVICE_WIFI_SYNC_AVAILABLE_TURN_ON_BUTTON)));
148   optional_fields.buttons.push_back(
149       message_center::ButtonInfo(l10n_util::GetStringUTF16(
150           IDS_ASH_MULTI_DEVICE_WIFI_SYNC_AVAILABLE_CANCEL_BUTTON)));
151
152   ShowNotification(kWifiSyncNotificationId, title, message, optional_fields);
153   base::UmaHistogramEnumeration("MultiDeviceSetup_NotificationShown",
154                                 NotificationType::kWifiSyncAnnouncement);
155 }
156
157 // static
158 std::unique_ptr<base::AutoReset<bool>>
159 MultiDeviceNotificationPresenter::DisableNotificationsForTesting() {
160   return std::make_unique<base::AutoReset<bool>>(
161       &g_disable_notifications_for_test_, true);
162 }
163
164 void MultiDeviceNotificationPresenter::RemoveMultiDeviceSetupNotification() {
165   notification_status_ = Status::kNoNotificationVisible;
166   message_center_->RemoveNotification(kSetupNotificationId,
167                                       /* by_user */ false);
168 }
169
170 void MultiDeviceNotificationPresenter::OnUserSessionAdded(
171     const AccountId& account_id) {
172   ObserveMultiDeviceSetupIfPossible();
173 }
174
175 void MultiDeviceNotificationPresenter::OnSessionStateChanged(
176     session_manager::SessionState state) {
177   ObserveMultiDeviceSetupIfPossible();
178 }
179
180 void MultiDeviceNotificationPresenter::OnNotificationRemoved(
181     const std::string& notification_id,
182     bool by_user) {
183   if (!by_user) {
184     return;
185   }
186   if (notification_id == kSetupNotificationId) {
187     base::UmaHistogramEnumeration(
188         "MultiDeviceSetup_NotificationDismissed",
189         GetMetricValueForNotification(notification_status_));
190     return;
191   }
192   if (notification_id == kWifiSyncNotificationId) {
193     base::UmaHistogramEnumeration("MultiDeviceSetup_NotificationDismissed",
194                                   NotificationType::kWifiSyncAnnouncement);
195     return;
196   }
197 }
198
199 void MultiDeviceNotificationPresenter::OnNotificationClicked(
200     const std::string& notification_id,
201     const absl::optional<int>& button_index,
202     const absl::optional<std::u16string>& reply) {
203   if (notification_id == kWifiSyncNotificationId) {
204     message_center_->RemoveNotification(kWifiSyncNotificationId,
205                                         /* by_user */ false);
206
207     if (button_index) {
208       switch (*button_index) {
209         case 0:  // "Turn on" button
210           PA_LOG(INFO) << "Enabling Wi-Fi Sync.";
211           multidevice_setup_remote_->SetFeatureEnabledState(
212               multidevice_setup::mojom::Feature::kWifiSync,
213               /*enabled=*/true, /*auth_token=*/absl::nullopt,
214               /*callback=*/base::DoNothing());
215           break;
216         case 1:  // "Cancel" button
217           base::UmaHistogramEnumeration(
218               "MultiDeviceSetup_NotificationDismissed",
219               NotificationType::kWifiSyncAnnouncement);
220           return;
221       }
222     }
223
224     Shell::Get()->system_tray_model()->client()->ShowWifiSyncSettings();
225     base::UmaHistogramEnumeration("MultiDeviceSetup_NotificationClicked",
226                                   NotificationType::kWifiSyncAnnouncement);
227     return;
228   }
229
230   if (notification_id != kSetupNotificationId)
231     return;
232
233   DCHECK(notification_status_ != Status::kNoNotificationVisible);
234   PA_LOG(VERBOSE) << "User clicked "
235                   << GetNotificationDescriptionForLogging(notification_status_)
236                   << ".";
237   base::UmaHistogramEnumeration(
238       "MultiDeviceSetup_NotificationClicked",
239       GetMetricValueForNotification(notification_status_));
240   switch (notification_status_) {
241     case Status::kNewUserNotificationVisible:
242       Shell::Get()->system_tray_model()->client()->ShowMultiDeviceSetup();
243       break;
244     case Status::kExistingUserHostSwitchedNotificationVisible:
245       // Clicks on the 'host switched' and 'Chromebook added' notifications have
246       // the same effect, i.e. opening the Settings subpage.
247       [[fallthrough]];
248     case Status::kExistingUserNewChromebookNotificationVisible:
249       Shell::Get()
250           ->system_tray_model()
251           ->client()
252           ->ShowConnectedDevicesSettings();
253       break;
254     case Status::kNoNotificationVisible:
255       NOTREACHED();
256   }
257   RemoveMultiDeviceSetupNotification();
258 }
259
260 void MultiDeviceNotificationPresenter::ObserveMultiDeviceSetupIfPossible() {
261   // If already the delegate, there is nothing else to do.
262   if (multidevice_setup_remote_)
263     return;
264
265   const SessionControllerImpl* session_controller =
266       Shell::Get()->session_controller();
267
268   if (session_controller->GetSessionState() !=
269       session_manager::SessionState::ACTIVE) {
270     return;
271   }
272
273   const UserSession* user_session = session_controller->GetPrimaryUserSession();
274
275   // The primary user session may be unavailable (e.g., for test/guest users).
276   if (!user_session)
277     return;
278
279   Shell::Get()->shell_delegate()->BindMultiDeviceSetup(
280       multidevice_setup_remote_.BindNewPipeAndPassReceiver());
281
282   // Add this object as the delegate of the MultiDeviceSetup Service.
283   multidevice_setup_remote_->SetAccountStatusChangeDelegate(
284       receiver_.BindNewPipeAndPassRemote());
285
286   message_center_->AddObserver(this);
287 }
288
289 void MultiDeviceNotificationPresenter::ShowSetupNotification(
290     const Status notification_status,
291     const std::u16string& title,
292     const std::u16string& message) {
293   PA_LOG(VERBOSE) << "Showing "
294                   << GetNotificationDescriptionForLogging(notification_status)
295                   << ".";
296   base::UmaHistogramEnumeration(
297       "MultiDeviceSetup_NotificationShown",
298       GetMetricValueForNotification(notification_status));
299
300   ShowNotification(kSetupNotificationId, title, message,
301                    message_center::RichNotificationData());
302   notification_status_ = notification_status;
303 }
304
305 void MultiDeviceNotificationPresenter::ShowNotification(
306     const std::string& id,
307     const std::u16string& title,
308     const std::u16string& message,
309     message_center::RichNotificationData optional_fields) {
310   if (g_disable_notifications_for_test_)
311     return;
312
313   std::unique_ptr<message_center::Notification> notification =
314       CreateSystemNotification(
315           message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE, id, title,
316           message, std::u16string() /* display_source */,
317           GURL() /* origin_url */,
318           message_center::NotifierId(
319               message_center::NotifierType::SYSTEM_COMPONENT,
320               kNotifierMultiDevice, NotificationCatalogName::kMultiDevice),
321           optional_fields, nullptr /* delegate */,
322           kNotificationMultiDeviceSetupIcon,
323           message_center::SystemNotificationWarningLevel::NORMAL);
324
325   if (message_center_->FindVisibleNotificationById(kSetupNotificationId)) {
326     message_center_->UpdateNotification(id, std::move(notification));
327     return;
328   }
329
330   message_center_->AddNotification(std::move(notification));
331 }
332
333 void MultiDeviceNotificationPresenter::FlushForTesting() {
334   if (multidevice_setup_remote_)
335     multidevice_setup_remote_.FlushForTesting();
336 }
337
338 }  // namespace ash