Upload upstream chromium 71.0.3578.0
[platform/framework/web/chromium-efl.git] / ash / multi_device_setup / multi_device_notification_presenter.cc
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.
4
5 #include "ash/multi_device_setup/multi_device_notification_presenter.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "ash/public/cpp/vector_icons/vector_icons.h"
11 #include "ash/public/interfaces/session_controller.mojom.h"
12 #include "ash/session/session_controller.h"
13 #include "ash/shell.h"
14 #include "ash/strings/grit/ash_strings.h"
15 #include "ash/system/model/system_tray_model.h"
16 #include "base/bind_helpers.h"
17 #include "base/memory/ptr_util.h"
18 #include "base/metrics/histogram_macros.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "chromeos/components/proximity_auth/logging/logging.h"
21 #include "chromeos/services/multidevice_setup/public/mojom/constants.mojom.h"
22 #include "services/service_manager/public/cpp/connector.h"
23 #include "ui/base/l10n/l10n_util.h"
24 #include "ui/message_center/message_center.h"
25 #include "ui/message_center/public/cpp/notification_types.h"
26 #include "ui/message_center/public/cpp/notifier_id.h"
27
28 namespace ash {
29
30 namespace {
31
32 const char kNotifierMultiDevice[] = "ash.multi_device_setup";
33
34 }  // namespace
35
36 // static
37 const char MultiDeviceNotificationPresenter::kNotificationId[] =
38     "cros_multi_device_setup_notification_id";
39
40 // static
41 std::string
42 MultiDeviceNotificationPresenter::GetNotificationDescriptionForLogging(
43     Status notification_status) {
44   switch (notification_status) {
45     case Status::kNewUserNotificationVisible:
46       return "notification to prompt setup";
47     case Status::kExistingUserHostSwitchedNotificationVisible:
48       return "notification of switch to new host";
49     case Status::kExistingUserNewChromebookNotificationVisible:
50       return "notification of new Chromebook added";
51     case Status::kNoNotificationVisible:
52       return "no notification";
53   }
54   NOTREACHED();
55 }
56
57 MultiDeviceNotificationPresenter::OpenUiDelegate::~OpenUiDelegate() = default;
58
59 void MultiDeviceNotificationPresenter::OpenUiDelegate::
60     OpenMultiDeviceSetupUi() {
61   Shell::Get()->system_tray_model()->client_ptr()->ShowMultiDeviceSetup();
62 }
63
64 void MultiDeviceNotificationPresenter::OpenUiDelegate::
65     OpenConnectedDevicesSettings() {
66   Shell::Get()
67       ->system_tray_model()
68       ->client_ptr()
69       ->ShowConnectedDevicesSettings();
70 }
71
72 // static
73 MultiDeviceNotificationPresenter::NotificationType
74 MultiDeviceNotificationPresenter::GetMetricValueForNotification(
75     Status notification_status) {
76   switch (notification_status) {
77     case Status::kNewUserNotificationVisible:
78       return kNotificationTypeNewUserPotentialHostExists;
79     case Status::kExistingUserHostSwitchedNotificationVisible:
80       return kNotificationTypeExistingUserHostSwitched;
81     case Status::kExistingUserNewChromebookNotificationVisible:
82       return kNotificationTypeExistingUserNewChromebookAdded;
83     case Status::kNoNotificationVisible:
84       NOTREACHED();
85       return kNotificationTypeMax;
86   }
87 }
88
89 MultiDeviceNotificationPresenter::MultiDeviceNotificationPresenter(
90     message_center::MessageCenter* message_center,
91     service_manager::Connector* connector)
92     : message_center_(message_center),
93       connector_(connector),
94       binding_(this),
95       open_ui_delegate_(std::make_unique<OpenUiDelegate>()),
96       weak_ptr_factory_(this) {
97   DCHECK(message_center_);
98   DCHECK(connector_);
99
100   Shell::Get()->session_controller()->AddObserver(this);
101
102   // If the constructor is called after the session state has already been set
103   // (e.g., if recovering from a crash), handle that now. If the user has not
104   // yet logged in, this will be a no-op.
105   ObserveMultiDeviceSetupIfPossible();
106 }
107
108 MultiDeviceNotificationPresenter::~MultiDeviceNotificationPresenter() {
109   Shell::Get()->session_controller()->RemoveObserver(this);
110 }
111
112 void MultiDeviceNotificationPresenter::OnPotentialHostExistsForNewUser() {
113   base::string16 title = l10n_util::GetStringUTF16(
114       IDS_ASH_MULTI_DEVICE_SETUP_NEW_USER_POTENTIAL_HOST_EXISTS_TITLE);
115   base::string16 message = l10n_util::GetStringUTF16(
116       IDS_ASH_MULTI_DEVICE_SETUP_NEW_USER_POTENTIAL_HOST_EXISTS_MESSAGE);
117   ShowNotification(Status::kNewUserNotificationVisible, title, message);
118 }
119
120 void MultiDeviceNotificationPresenter::OnNoLongerNewUser() {
121   if (notification_status_ != Status::kNewUserNotificationVisible)
122     return;
123   RemoveMultiDeviceSetupNotification();
124 }
125
126 void MultiDeviceNotificationPresenter::OnConnectedHostSwitchedForExistingUser(
127     const std::string& new_host_device_name) {
128   base::string16 title = l10n_util::GetStringFUTF16(
129       IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_HOST_SWITCHED_TITLE,
130       base::ASCIIToUTF16(new_host_device_name));
131   base::string16 message = l10n_util::GetStringUTF16(
132       IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_HOST_SWITCHED_MESSAGE);
133   ShowNotification(Status::kExistingUserHostSwitchedNotificationVisible, title,
134                    message);
135 }
136
137 void MultiDeviceNotificationPresenter::OnNewChromebookAddedForExistingUser(
138     const std::string& new_host_device_name) {
139   base::string16 title = l10n_util::GetStringFUTF16(
140       IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_NEW_CHROMEBOOK_ADDED_TITLE,
141       base::ASCIIToUTF16(new_host_device_name));
142   base::string16 message = l10n_util::GetStringUTF16(
143       IDS_ASH_MULTI_DEVICE_SETUP_EXISTING_USER_NEW_CHROMEBOOK_ADDED_MESSAGE);
144   ShowNotification(Status::kExistingUserNewChromebookNotificationVisible, title,
145                    message);
146 }
147
148 void MultiDeviceNotificationPresenter::RemoveMultiDeviceSetupNotification() {
149   notification_status_ = Status::kNoNotificationVisible;
150   message_center_->RemoveNotification(kNotificationId,
151                                       /* by_user */ false);
152 }
153
154 void MultiDeviceNotificationPresenter::OnUserSessionAdded(
155     const AccountId& account_id) {
156   ObserveMultiDeviceSetupIfPossible();
157 }
158
159 void MultiDeviceNotificationPresenter::OnSessionStateChanged(
160     session_manager::SessionState state) {
161   ObserveMultiDeviceSetupIfPossible();
162 }
163
164 void MultiDeviceNotificationPresenter::ObserveMultiDeviceSetupIfPossible() {
165   // If already the delegate, there is nothing else to do.
166   if (multidevice_setup_ptr_)
167     return;
168
169   const SessionController* session_controller =
170       Shell::Get()->session_controller();
171
172   // If no active user is logged in, there is nothing to do.
173   if (session_controller->GetSessionState() !=
174       session_manager::SessionState::ACTIVE) {
175     return;
176   }
177
178   const mojom::UserSession* user_session =
179       session_controller->GetPrimaryUserSession();
180
181   // The primary user session may be unavailable (e.g., for test/guest users).
182   if (!user_session)
183     return;
184
185   std::string service_user_id = user_session->user_info->service_user_id;
186   DCHECK(!service_user_id.empty());
187
188   connector_->BindInterface(
189       service_manager::Identity(
190           chromeos::multidevice_setup::mojom::kServiceName, service_user_id),
191       &multidevice_setup_ptr_);
192
193   // Add this object as the delegate of the MultiDeviceSetup Service.
194   chromeos::multidevice_setup::mojom::AccountStatusChangeDelegatePtr
195       delegate_ptr;
196   binding_.Bind(mojo::MakeRequest(&delegate_ptr));
197   multidevice_setup_ptr_->SetAccountStatusChangeDelegate(
198       std::move(delegate_ptr));
199 }
200
201 void MultiDeviceNotificationPresenter::OnNotificationClicked() {
202   DCHECK(notification_status_ != Status::kNoNotificationVisible);
203   PA_LOG(INFO) << "User clicked "
204                << GetNotificationDescriptionForLogging(notification_status_)
205                << ".";
206   UMA_HISTOGRAM_ENUMERATION("MultiDeviceSetup_NotificationClicked",
207                             GetMetricValueForNotification(notification_status_),
208                             kNotificationTypeMax);
209   switch (notification_status_) {
210     case Status::kNewUserNotificationVisible:
211       open_ui_delegate_->OpenMultiDeviceSetupUi();
212       break;
213     case Status::kExistingUserHostSwitchedNotificationVisible:
214       // Clicks on the 'host switched' and 'Chromebook added' notifications have
215       // the same effect, i.e. opening the Settings subpage.
216       FALLTHROUGH;
217     case Status::kExistingUserNewChromebookNotificationVisible:
218       open_ui_delegate_->OpenConnectedDevicesSettings();
219       break;
220     case Status::kNoNotificationVisible:
221       NOTREACHED();
222   }
223   RemoveMultiDeviceSetupNotification();
224 }
225
226 void MultiDeviceNotificationPresenter::ShowNotification(
227     const Status notification_status,
228     const base::string16& title,
229     const base::string16& message) {
230   PA_LOG(INFO) << "Showing "
231                << GetNotificationDescriptionForLogging(notification_status)
232                << ".";
233   UMA_HISTOGRAM_ENUMERATION("MultiDeviceSetup_NotificationShown",
234                             GetMetricValueForNotification(notification_status),
235                             kNotificationTypeMax);
236   if (message_center_->FindVisibleNotificationById(kNotificationId)) {
237     message_center_->UpdateNotification(kNotificationId,
238                                         CreateNotification(title, message));
239   } else {
240     message_center_->AddNotification(CreateNotification(title, message));
241   }
242   notification_status_ = notification_status;
243 }
244
245 std::unique_ptr<message_center::Notification>
246 MultiDeviceNotificationPresenter::CreateNotification(
247     const base::string16& title,
248     const base::string16& message) {
249   return message_center::Notification::CreateSystemNotification(
250       message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE,
251       kNotificationId, title, message, base::string16() /* display_source */,
252       GURL() /* origin_url */,
253       message_center::NotifierId(
254           message_center::NotifierId::NotifierType::SYSTEM_COMPONENT,
255           kNotifierMultiDevice),
256       message_center::RichNotificationData(),
257       new message_center::HandleNotificationClickDelegate(base::BindRepeating(
258           &MultiDeviceNotificationPresenter::OnNotificationClicked,
259           weak_ptr_factory_.GetWeakPtr())),
260       ash::kNotificationMultiDeviceSetupIcon,
261       message_center::SystemNotificationWarningLevel::NORMAL);
262 }
263
264 void MultiDeviceNotificationPresenter::FlushForTesting() {
265   if (multidevice_setup_ptr_)
266     multidevice_setup_ptr_.FlushForTesting();
267 }
268
269 }  // namespace ash