1 // Copyright 2016 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/public/cpp/external_arc/message_center/arc_notification_manager.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "ash/public/cpp/arc_app_id_provider.h"
11 #include "ash/public/cpp/ash_features.h"
12 #include "ash/public/cpp/external_arc/message_center/arc_notification_delegate.h"
13 #include "ash/public/cpp/external_arc/message_center/arc_notification_item_impl.h"
14 #include "ash/public/cpp/external_arc/message_center/arc_notification_view.h"
15 #include "ash/public/cpp/message_center/arc_notification_constants.h"
16 #include "ash/public/cpp/message_center/arc_notification_manager_delegate.h"
17 #include "base/bind.h"
18 #include "base/command_line.h"
19 #include "base/stl_util.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "components/arc/session/mojo_channel.h"
22 #include "ui/message_center/lock_screen/lock_screen_controller.h"
23 #include "ui/message_center/message_center_impl.h"
24 #include "ui/message_center/message_center_observer.h"
25 #include "ui/message_center/views/message_view_factory.h"
26 
27 using arc::ConnectionHolder;
28 using arc::MojoChannel;
29 using arc::mojom::ArcDoNotDisturbStatus;
30 using arc::mojom::ArcDoNotDisturbStatusPtr;
31 using arc::mojom::ArcNotificationData;
32 using arc::mojom::ArcNotificationDataPtr;
33 using arc::mojom::ArcNotificationEvent;
34 using arc::mojom::ArcNotificationPriority;
35 using arc::mojom::MessageCenterVisibility;
36 using arc::mojom::NotificationConfiguration;
37 using arc::mojom::NotificationConfigurationPtr;
38 using arc::mojom::NotificationsHost;
39 using arc::mojom::NotificationsInstance;
40 
41 namespace ash {
42 namespace {
43 
44 constexpr char kPlayStorePackageName[] = "com.android.vending";
45 
CreateCustomMessageView(const message_center::Notification & notification)46 std::unique_ptr<message_center::MessageView> CreateCustomMessageView(
47     const message_center::Notification& notification) {
48   DCHECK_EQ(notification.notifier_id().type,
49             message_center::NotifierType::ARC_APPLICATION);
50   DCHECK_EQ(kArcNotificationCustomViewType, notification.custom_view_type());
51   auto* arc_delegate =
52       static_cast<ArcNotificationDelegate*>(notification.delegate());
53   return arc_delegate->CreateCustomMessageView(notification);
54 }
55 
56 class DoNotDisturbManager : public message_center::MessageCenterObserver {
57  public:
DoNotDisturbManager(ArcNotificationManager * manager)58   explicit DoNotDisturbManager(ArcNotificationManager* manager)
59       : manager_(manager) {}
OnQuietModeChanged(bool in_quiet_mode)60   void OnQuietModeChanged(bool in_quiet_mode) override {
61     manager_->SetDoNotDisturbStatusOnAndroid(in_quiet_mode);
62   }
63 
64  private:
65   ArcNotificationManager* const manager_;
66 
67   DISALLOW_COPY_AND_ASSIGN(DoNotDisturbManager);
68 };
69 
70 class VisibilityManager : public message_center::MessageCenterObserver {
71  public:
VisibilityManager(ArcNotificationManager * manager)72   explicit VisibilityManager(ArcNotificationManager* manager)
73       : manager_(manager) {}
OnCenterVisibilityChanged(message_center::Visibility visibility)74   void OnCenterVisibilityChanged(
75       message_center::Visibility visibility) override {
76     manager_->OnMessageCenterVisibilityChanged(toMojom(visibility));
77   }
78 
79  private:
toMojom(message_center::Visibility visibility)80   static MessageCenterVisibility toMojom(
81       message_center::Visibility visibility) {
82     if (visibility == message_center::Visibility::VISIBILITY_TRANSIENT)
83       return MessageCenterVisibility::VISIBILITY_TRANSIENT;
84     if (visibility == message_center::Visibility::VISIBILITY_MESSAGE_CENTER)
85       return MessageCenterVisibility::VISIBILITY_MESSAGE_CENTER;
86     VLOG(2) << "Unknown message_center::Visibility: " << visibility;
87     return MessageCenterVisibility::VISIBILITY_TRANSIENT;
88   }
89 
90   ArcNotificationManager* const manager_;
91 
92   DISALLOW_COPY_AND_ASSIGN(VisibilityManager);
93 };
94 
95 }  // namespace
96 
97 class ArcNotificationManager::InstanceOwner {
98  public:
99   InstanceOwner() = default;
100   ~InstanceOwner() = default;
101 
SetInstanceRemote(mojo::PendingRemote<arc::mojom::NotificationsInstance> instance_remote)102   void SetInstanceRemote(
103       mojo::PendingRemote<arc::mojom::NotificationsInstance> instance_remote) {
104     DCHECK(!channel_);
105 
106     channel_ =
107         std::make_unique<MojoChannel<NotificationsInstance, NotificationsHost>>(
108             &holder_, std::move(instance_remote));
109 
110     // Using base::Unretained because |this| owns |channel_|.
111     channel_->set_disconnect_handler(
112         base::BindOnce(&InstanceOwner::OnDisconnected, base::Unretained(this)));
113     channel_->QueryVersion();
114   }
115 
holder()116   ConnectionHolder<NotificationsInstance, NotificationsHost>* holder() {
117     return &holder_;
118   }
119 
120  private:
OnDisconnected()121   void OnDisconnected() { channel_.reset(); }
122 
123   ConnectionHolder<NotificationsInstance, NotificationsHost> holder_;
124   std::unique_ptr<MojoChannel<NotificationsInstance, NotificationsHost>>
125       channel_;
126 
127   DISALLOW_COPY_AND_ASSIGN(InstanceOwner);
128 };
129 
130 // static
SetCustomNotificationViewFactory()131 void ArcNotificationManager::SetCustomNotificationViewFactory() {
132   message_center::MessageViewFactory::SetCustomNotificationViewFactory(
133       kArcNotificationCustomViewType,
134       base::BindRepeating(&CreateCustomMessageView));
135 }
136 
ArcNotificationManager()137 ArcNotificationManager::ArcNotificationManager()
138     : instance_owner_(std::make_unique<InstanceOwner>()) {}
139 
~ArcNotificationManager()140 ArcNotificationManager::~ArcNotificationManager() {
141   for (auto& obs : observers_)
142     obs.OnArcNotificationManagerDestroyed(this);
143 
144   message_center_->RemoveObserver(do_not_disturb_manager_.get());
145   message_center_->RemoveObserver(visibility_manager_.get());
146 
147   instance_owner_->holder()->RemoveObserver(this);
148   instance_owner_->holder()->SetHost(nullptr);
149 
150   // Ensures that any callback tied to |instance_owner_| is not invoked.
151   instance_owner_.reset();
152 }
153 
SetInstance(mojo::PendingRemote<arc::mojom::NotificationsInstance> instance_remote)154 void ArcNotificationManager::SetInstance(
155     mojo::PendingRemote<arc::mojom::NotificationsInstance> instance_remote) {
156   instance_owner_->SetInstanceRemote(std::move(instance_remote));
157 }
158 
159 ConnectionHolder<NotificationsInstance, NotificationsHost>*
GetConnectionHolderForTest()160 ArcNotificationManager::GetConnectionHolderForTest() {
161   return instance_owner_->holder();
162 }
163 
OnConnectionReady()164 void ArcNotificationManager::OnConnectionReady() {
165   DCHECK(!ready_);
166 
167   // TODO(hidehiko): Replace this by ConnectionHolder::IsConnected().
168   ready_ = true;
169 
170   // Sync the initial quiet mode state with Android.
171   SetDoNotDisturbStatusOnAndroid(message_center_->IsQuietMode());
172 
173   // Sync the initial visibility of message center with Android.
174   auto visibility = message_center_->IsMessageCenterVisible()
175                         ? MessageCenterVisibility::VISIBILITY_MESSAGE_CENTER
176                         : MessageCenterVisibility::VISIBILITY_TRANSIENT;
177   OnMessageCenterVisibilityChanged(visibility);
178 
179   // Set configuration variables for notifications on arc.
180   SetNotificationConfiguration();
181 }
182 
OnConnectionClosed()183 void ArcNotificationManager::OnConnectionClosed() {
184   DCHECK(ready_);
185   while (!items_.empty()) {
186     auto it = items_.begin();
187     std::unique_ptr<ArcNotificationItem> item = std::move(it->second);
188     items_.erase(it);
189     item->OnClosedFromAndroid();
190   }
191   ready_ = false;
192 }
193 
OnNotificationPosted(ArcNotificationDataPtr data)194 void ArcNotificationManager::OnNotificationPosted(ArcNotificationDataPtr data) {
195   if (ShouldIgnoreNotification(data.get())) {
196     VLOG(3) << "Posted notification was ignored.";
197     return;
198   }
199 
200   const std::string& key = data->key;
201   auto it = items_.find(key);
202   if (it == items_.end()) {
203     // Show a notification on the primary logged-in user's desktop and badge the
204     // app icon in the shelf if the icon exists.
205     // TODO(yoshiki): Reconsider when ARC supports multi-user.
206     auto item = std::make_unique<ArcNotificationItemImpl>(
207         this, message_center_, key, main_profile_id_);
208     auto result = items_.insert(std::make_pair(key, std::move(item)));
209     DCHECK(result.second);
210     it = result.first;
211   }
212 
213   std::string app_id =
214       data->package_name
215           ? ArcAppIdProvider::Get()->GetAppIdByPackageName(*data->package_name)
216           : std::string();
217   it->second->OnUpdatedFromAndroid(std::move(data), app_id);
218 
219   for (auto& observer : observers_)
220     observer.OnNotificationUpdated(it->second->GetNotificationId(), app_id);
221 }
222 
OnNotificationUpdated(ArcNotificationDataPtr data)223 void ArcNotificationManager::OnNotificationUpdated(
224     ArcNotificationDataPtr data) {
225   if (ShouldIgnoreNotification(data.get())) {
226     VLOG(3) << "Updated notification was ignored.";
227     return;
228   }
229 
230   const std::string& key = data->key;
231   auto it = items_.find(key);
232   if (it == items_.end())
233     return;
234 
235   bool is_remote_view_focused =
236       (data->remote_input_state ==
237        arc::mojom::ArcNotificationRemoteInputState::OPENED);
238   if (is_remote_view_focused && (previously_focused_notification_key_ != key)) {
239     if (!previously_focused_notification_key_.empty()) {
240       auto prev_it = items_.find(previously_focused_notification_key_);
241       // The case that another remote input is focused. Notify the previously-
242       // focused notification (if any).
243       if (prev_it != items_.end())
244         prev_it->second->OnRemoteInputActivationChanged(false);
245     }
246 
247     // Notify the newly-focused notification.
248     previously_focused_notification_key_ = key;
249     it->second->OnRemoteInputActivationChanged(true);
250   } else if (!is_remote_view_focused &&
251              (previously_focused_notification_key_ == key)) {
252     // The case that the previously-focused notification gets unfocused. Notify
253     // the previously-focused notification if the notification still exists.
254     auto it = items_.find(previously_focused_notification_key_);
255     if (it != items_.end())
256       it->second->OnRemoteInputActivationChanged(false);
257 
258     previously_focused_notification_key_.clear();
259   }
260 
261   std::string app_id =
262       data->package_name
263           ? ArcAppIdProvider::Get()->GetAppIdByPackageName(*data->package_name)
264           : std::string();
265   it->second->OnUpdatedFromAndroid(std::move(data), app_id);
266 
267   for (auto& observer : observers_)
268     observer.OnNotificationUpdated(it->second->GetNotificationId(), app_id);
269 }
270 
OpenMessageCenter()271 void ArcNotificationManager::OpenMessageCenter() {
272   delegate_->ShowMessageCenter();
273 }
274 
CloseMessageCenter()275 void ArcNotificationManager::CloseMessageCenter() {
276   delegate_->HideMessageCenter();
277 }
278 
OnLockScreenSettingUpdated(arc::mojom::ArcLockScreenNotificationSettingPtr setting)279 void ArcNotificationManager::OnLockScreenSettingUpdated(
280     arc::mojom::ArcLockScreenNotificationSettingPtr setting) {
281   // TODO(yoshiki): sync the setting.
282 }
283 
ProcessUserAction(arc::mojom::ArcNotificationUserActionDataPtr data)284 void ArcNotificationManager::ProcessUserAction(
285     arc::mojom::ArcNotificationUserActionDataPtr data) {
286   if (!data->defer_until_unlock) {
287     PerformUserAction(data->action_id, data->to_be_focused_after_unlock);
288     return;
289   }
290 
291   // TODO(yoshiki): remove the static cast after refactionring.
292   static_cast<message_center::MessageCenterImpl*>(message_center_)
293       ->lock_screen_controller()
294       ->DismissLockScreenThenExecute(
295           base::BindOnce(&ArcNotificationManager::PerformUserAction,
296                          weak_ptr_factory_.GetWeakPtr(), data->action_id,
297                          data->to_be_focused_after_unlock),
298           base::BindOnce(&ArcNotificationManager::CancelUserAction,
299                          weak_ptr_factory_.GetWeakPtr(), data->action_id));
300 }
301 
PerformUserAction(uint32_t id,bool open_message_center)302 void ArcNotificationManager::PerformUserAction(uint32_t id,
303                                                bool open_message_center) {
304   // TODO(yoshiki): Pass the event to the message center and handle the action
305   // in the NotificationDelegate::Click() for consistency with non-arc
306   // notifications.
307   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
308       instance_owner_->holder(), PerformDeferredUserAction);
309 
310   // On shutdown, the ARC channel may quit earlier than notifications.
311   if (!notifications_instance) {
312     VLOG(2) << "Trying to perform the defered operation, "
313                "but the ARC channel has already gone.";
314     return;
315   }
316 
317   notifications_instance->PerformDeferredUserAction(id);
318 
319   if (open_message_center) {
320     OpenMessageCenter();
321     // TODO(yoshiki): focus the target notification after opening the message
322     // center.
323   }
324 }
325 
CancelUserAction(uint32_t id)326 void ArcNotificationManager::CancelUserAction(uint32_t id) {
327   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
328       instance_owner_->holder(), CancelDeferredUserAction);
329 
330   // On shutdown, the ARC channel may quit earlier than notifications.
331   if (!notifications_instance) {
332     VLOG(2) << "Trying to cancel the defered operation, "
333                "but the ARC channel has already gone.";
334     return;
335   }
336 
337   notifications_instance->CancelDeferredUserAction(id);
338 }
339 
OnNotificationRemoved(const std::string & key)340 void ArcNotificationManager::OnNotificationRemoved(const std::string& key) {
341   auto it = items_.find(key);
342   if (it == items_.end()) {
343     VLOG(3) << "Android requests to remove a notification (key: " << key
344             << "), but it is already gone.";
345     return;
346   }
347 
348   std::unique_ptr<ArcNotificationItem> item = std::move(it->second);
349   items_.erase(it);
350   item->OnClosedFromAndroid();
351 
352   for (auto& observer : observers_)
353     observer.OnNotificationRemoved(item->GetNotificationId());
354 }
355 
SendNotificationRemovedFromChrome(const std::string & key)356 void ArcNotificationManager::SendNotificationRemovedFromChrome(
357     const std::string& key) {
358   auto it = items_.find(key);
359   if (it == items_.end()) {
360     VLOG(3) << "Chrome requests to remove a notification (key: " << key
361             << "), but it is already gone.";
362     return;
363   }
364 
365   // The removed ArcNotificationItem needs to live in this scope, since the
366   // given argument |key| may be a part of the removed item.
367   std::unique_ptr<ArcNotificationItem> item = std::move(it->second);
368   items_.erase(it);
369 
370   for (auto& observer : observers_)
371     observer.OnNotificationRemoved(item->GetNotificationId());
372 
373   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
374       instance_owner_->holder(), SendNotificationEventToAndroid);
375 
376   // On shutdown, the ARC channel may quit earlier than notifications.
377   if (!notifications_instance) {
378     VLOG(2) << "ARC Notification (key: " << key
379             << ") is closed, but the ARC channel has already gone.";
380     return;
381   }
382 
383   notifications_instance->SendNotificationEventToAndroid(
384       key, ArcNotificationEvent::CLOSED);
385 }
386 
SendNotificationClickedOnChrome(const std::string & key)387 void ArcNotificationManager::SendNotificationClickedOnChrome(
388     const std::string& key) {
389   if (items_.find(key) == items_.end()) {
390     VLOG(3) << "Chrome requests to fire a click event on notification (key: "
391             << key << "), but it is gone.";
392     return;
393   }
394 
395   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
396       instance_owner_->holder(), SendNotificationEventToAndroid);
397 
398   // On shutdown, the ARC channel may quit earlier than notifications.
399   if (!notifications_instance) {
400     VLOG(2) << "ARC Notification (key: " << key
401             << ") is clicked, but the ARC channel has already gone.";
402     return;
403   }
404 
405   notifications_instance->SendNotificationEventToAndroid(
406       key, ArcNotificationEvent::BODY_CLICKED);
407 }
408 
SendNotificationActivatedInChrome(const std::string & key,bool activated)409 void ArcNotificationManager::SendNotificationActivatedInChrome(
410     const std::string& key,
411     bool activated) {
412   if (items_.find(key) == items_.end()) {
413     VLOG(3)
414         << "Chrome requests to fire an activation event on notification (key: "
415         << key << "), but it is gone.";
416     return;
417   }
418 
419   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
420       instance_owner_->holder(), SendNotificationEventToAndroid);
421 
422   // On shutdown, the ARC channel may quit earlier than notifications.
423   if (!notifications_instance) {
424     VLOG(2) << "ARC Notification (key: " << key
425             << ") is (de)activated, but the ARC channel has already gone.";
426     return;
427   }
428 
429   notifications_instance->SendNotificationEventToAndroid(
430       key, activated ? ArcNotificationEvent::ACTIVATED
431                      : ArcNotificationEvent::DEACTIVATED);
432 }
433 
CreateNotificationWindow(const std::string & key)434 void ArcNotificationManager::CreateNotificationWindow(const std::string& key) {
435   if (items_.find(key) == items_.end()) {
436     VLOG(3) << "Chrome requests to create window on notification (key: " << key
437             << "), but it is gone.";
438     return;
439   }
440 
441   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
442       instance_owner_->holder(), CreateNotificationWindow);
443   if (!notifications_instance)
444     return;
445 
446   notifications_instance->CreateNotificationWindow(key);
447 }
448 
CloseNotificationWindow(const std::string & key)449 void ArcNotificationManager::CloseNotificationWindow(const std::string& key) {
450   if (items_.find(key) == items_.end()) {
451     VLOG(3) << "Chrome requests to close window on notification (key: " << key
452             << "), but it is gone.";
453     return;
454   }
455 
456   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
457       instance_owner_->holder(), CloseNotificationWindow);
458   if (!notifications_instance)
459     return;
460 
461   notifications_instance->CloseNotificationWindow(key);
462 }
463 
OpenNotificationSettings(const std::string & key)464 void ArcNotificationManager::OpenNotificationSettings(const std::string& key) {
465   if (items_.find(key) == items_.end()) {
466     DVLOG(3) << "Chrome requests to fire a click event on the notification "
467              << "settings button (key: " << key << "), but it is gone.";
468     return;
469   }
470 
471   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
472       instance_owner_->holder(), OpenNotificationSettings);
473 
474   // On shutdown, the ARC channel may quit earlier than notifications.
475   if (!notifications_instance)
476     return;
477 
478   notifications_instance->OpenNotificationSettings(key);
479 }
480 
OpenNotificationSnoozeSettings(const std::string & key)481 void ArcNotificationManager::OpenNotificationSnoozeSettings(
482     const std::string& key) {
483   if (!base::Contains(items_, key)) {
484     DVLOG(3) << "Chrome requests to show a snooze setting gut on the"
485              << "notification (key: " << key << "), but it is gone.";
486     return;
487   }
488 
489   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
490       instance_owner_->holder(), OpenNotificationSnoozeSettings);
491 
492   // On shutdown, the ARC channel may quit earlier than notifications.
493   if (!notifications_instance)
494     return;
495 
496   notifications_instance->OpenNotificationSnoozeSettings(key);
497 }
498 
IsOpeningSettingsSupported() const499 bool ArcNotificationManager::IsOpeningSettingsSupported() const {
500   const auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
501       instance_owner_->holder(), OpenNotificationSettings);
502   return notifications_instance != nullptr;
503 }
504 
SendNotificationToggleExpansionOnChrome(const std::string & key)505 void ArcNotificationManager::SendNotificationToggleExpansionOnChrome(
506     const std::string& key) {
507   if (items_.find(key) == items_.end()) {
508     VLOG(3) << "Chrome requests to fire a click event on notification (key: "
509             << key << "), but it is gone.";
510     return;
511   }
512 
513   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
514       instance_owner_->holder(), SendNotificationEventToAndroid);
515 
516   // On shutdown, the ARC channel may quit earlier than notifications.
517   if (!notifications_instance) {
518     VLOG(2) << "ARC Notification (key: " << key
519             << ") is clicked, but the ARC channel has already gone.";
520     return;
521   }
522 
523   notifications_instance->SendNotificationEventToAndroid(
524       key, ArcNotificationEvent::TOGGLE_EXPANSION);
525 }
526 
ShouldIgnoreNotification(ArcNotificationData * data)527 bool ArcNotificationManager::ShouldIgnoreNotification(
528     ArcNotificationData* data) {
529   if (data->priority == ArcNotificationPriority::NONE)
530     return true;
531 
532   // Notifications from Play Store are ignored in Public Session and Kiosk mode.
533   // TODO: Use centralized const for Play Store package.
534   if (data->package_name.has_value() &&
535       *data->package_name == kPlayStorePackageName &&
536       delegate_->IsPublicSessionOrKiosk()) {
537     return true;
538   }
539 
540   // Media Notifications may be ignored if we have the native views based media
541   // session notifications enabled.
542   if (data->is_media_notification &&
543       features::IsHideArcMediaNotificationsEnabled()) {
544     return true;
545   }
546 
547   return false;
548 }
549 
OnDoNotDisturbStatusUpdated(ArcDoNotDisturbStatusPtr status)550 void ArcNotificationManager::OnDoNotDisturbStatusUpdated(
551     ArcDoNotDisturbStatusPtr status) {
552   // Remove the observer to prevent from sending the command to Android since
553   // this request came from Android.
554   message_center_->RemoveObserver(do_not_disturb_manager_.get());
555 
556   if (message_center_->IsQuietMode() != status->enabled)
557     message_center_->SetQuietMode(status->enabled);
558 
559   // Add back the observer.
560   message_center_->AddObserver(do_not_disturb_manager_.get());
561 }
562 
SetDoNotDisturbStatusOnAndroid(bool enabled)563 void ArcNotificationManager::SetDoNotDisturbStatusOnAndroid(bool enabled) {
564   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
565       instance_owner_->holder(), SetDoNotDisturbStatusOnAndroid);
566 
567   // On shutdown, the ARC channel may quit earlier than notifications.
568   if (!notifications_instance) {
569     VLOG(2) << "Trying to send the Do Not Disturb status (" << enabled
570             << "), but the ARC channel has already gone.";
571     return;
572   }
573 
574   ArcDoNotDisturbStatusPtr status = ArcDoNotDisturbStatus::New();
575   status->enabled = enabled;
576 
577   notifications_instance->SetDoNotDisturbStatusOnAndroid(std::move(status));
578 }
579 
CancelPress(const std::string & key)580 void ArcNotificationManager::CancelPress(const std::string& key) {
581   auto* notifications_instance =
582       ARC_GET_INSTANCE_FOR_METHOD(instance_owner_->holder(), CancelPress);
583 
584   // On shutdown, the ARC channel may quit earlier than notifications.
585   if (!notifications_instance) {
586     VLOG(2) << "Trying to cancel the long press operation, "
587                "but the ARC channel has already gone.";
588     return;
589   }
590 
591   notifications_instance->CancelPress(key);
592 }
593 
SetNotificationConfiguration()594 void ArcNotificationManager::SetNotificationConfiguration() {
595   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
596       instance_owner_->holder(), SetNotificationConfiguration);
597 
598   if (!notifications_instance) {
599     VLOG(2) << "Trying to set notification expansion animations"
600             << ", but the ARC channel has already gone.";
601     return;
602   }
603 
604   NotificationConfigurationPtr configuration = NotificationConfiguration::New();
605   configuration->expansion_animation =
606       features::IsNotificationExpansionAnimationEnabled();
607 
608   notifications_instance->SetNotificationConfiguration(
609       std::move(configuration));
610 }
611 
OnMessageCenterVisibilityChanged(MessageCenterVisibility visibility)612 void ArcNotificationManager::OnMessageCenterVisibilityChanged(
613     MessageCenterVisibility visibility) {
614   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
615       instance_owner_->holder(), OnMessageCenterVisibilityChanged);
616 
617   if (!notifications_instance) {
618     VLOG(2) << "Trying to report message center visibility (" << visibility
619             << "), but the ARC channel has already gone.";
620     return;
621   }
622 
623   notifications_instance->OnMessageCenterVisibilityChanged(visibility);
624 }
625 
AddObserver(Observer * observer)626 void ArcNotificationManager::AddObserver(Observer* observer) {
627   observers_.AddObserver(observer);
628 }
629 
RemoveObserver(Observer * observer)630 void ArcNotificationManager::RemoveObserver(Observer* observer) {
631   observers_.RemoveObserver(observer);
632 }
633 
Init(std::unique_ptr<ArcNotificationManagerDelegate> delegate,const AccountId & main_profile_id,message_center::MessageCenter * message_center)634 void ArcNotificationManager::Init(
635     std::unique_ptr<ArcNotificationManagerDelegate> delegate,
636     const AccountId& main_profile_id,
637     message_center::MessageCenter* message_center) {
638   DCHECK(message_center);
639   delegate_ = std::move(delegate);
640   main_profile_id_ = main_profile_id;
641   message_center_ = message_center;
642   do_not_disturb_manager_ = std::make_unique<DoNotDisturbManager>(this);
643   visibility_manager_ = std::make_unique<VisibilityManager>(this);
644 
645   instance_owner_->holder()->SetHost(this);
646   instance_owner_->holder()->AddObserver(this);
647   if (!message_center::MessageViewFactory::HasCustomNotificationViewFactory(
648           kArcNotificationCustomViewType)) {
649     SetCustomNotificationViewFactory();
650   }
651   message_center_->AddObserver(do_not_disturb_manager_.get());
652   message_center_->AddObserver(visibility_manager_.get());
653 }
654 
655 }  // namespace ash
656