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