assistant_notification_controller_impl.cc 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. #include "ash/assistant/assistant_notification_controller_impl.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "ash/assistant/assistant_controller_impl.h"
  8. #include "ash/assistant/assistant_notification_expiry_monitor.h"
  9. #include "ash/assistant/util/deep_link_util.h"
  10. #include "ash/constants/notifier_catalogs.h"
  11. #include "ash/public/cpp/assistant/controller/assistant_controller.h"
  12. #include "ash/public/cpp/notification_utils.h"
  13. #include "ash/shell.h"
  14. #include "ash/strings/grit/ash_strings.h"
  15. #include "base/strings/utf_string_conversions.h"
  16. #include "chromeos/services/libassistant/public/cpp/assistant_notification.h"
  17. #include "chromeos/ui/vector_icons/vector_icons.h"
  18. #include "mojo/public/cpp/bindings/pending_receiver.h"
  19. #include "mojo/public/cpp/bindings/receiver.h"
  20. #include "ui/base/l10n/l10n_util.h"
  21. #include "ui/message_center/message_center.h"
  22. #include "ui/message_center/public/cpp/notification.h"
  23. #include "url/gurl.h"
  24. namespace ash {
  25. namespace {
  26. constexpr char kNotifierId[] = "assistant";
  27. // Helpers ---------------------------------------------------------------------
  28. std::unique_ptr<message_center::Notification> CreateSystemNotification(
  29. const message_center::NotifierId& notifier_id,
  30. const chromeos::assistant::AssistantNotification& notification) {
  31. const std::u16string title = base::UTF8ToUTF16(notification.title);
  32. const std::u16string message = base::UTF8ToUTF16(notification.message);
  33. const std::u16string display_source =
  34. l10n_util::GetStringUTF16(IDS_ASH_ASSISTANT_NOTIFICATION_DISPLAY_SOURCE);
  35. message_center::RichNotificationData data;
  36. for (const auto& button : notification.buttons)
  37. data.buttons.emplace_back(base::UTF8ToUTF16(button.label));
  38. std::unique_ptr<message_center::Notification> system_notification =
  39. ash::CreateSystemNotification(
  40. message_center::NOTIFICATION_TYPE_SIMPLE, notification.client_id,
  41. title, message, display_source, GURL(), notifier_id, data,
  42. /*delegate=*/nullptr, chromeos::kNotificationAssistantIcon,
  43. message_center::SystemNotificationWarningLevel::NORMAL);
  44. system_notification->set_renotify(notification.renotify);
  45. system_notification->set_pinned(notification.is_pinned);
  46. switch (notification.priority) {
  47. case chromeos::assistant::AssistantNotificationPriority::kLow:
  48. system_notification->set_priority(message_center::LOW_PRIORITY);
  49. break;
  50. case chromeos::assistant::AssistantNotificationPriority::kDefault:
  51. system_notification->set_priority(message_center::DEFAULT_PRIORITY);
  52. break;
  53. case chromeos::assistant::AssistantNotificationPriority::kHigh:
  54. system_notification->set_priority(message_center::HIGH_PRIORITY);
  55. break;
  56. }
  57. return system_notification;
  58. }
  59. message_center::NotifierId GetNotifierId() {
  60. return message_center::NotifierId(
  61. message_center::NotifierType::SYSTEM_COMPONENT, kNotifierId,
  62. NotificationCatalogName::kAssistantNotification);
  63. }
  64. bool IsValidActionUrl(const GURL& action_url) {
  65. return action_url.is_valid() && (action_url.SchemeIsHTTPOrHTTPS() ||
  66. assistant::util::IsDeepLinkUrl(action_url));
  67. }
  68. } // namespace
  69. // AssistantNotificationControllerImpl
  70. // ---------------------------------------------
  71. AssistantNotificationControllerImpl::AssistantNotificationControllerImpl()
  72. : expiry_monitor_(this), notifier_id_(GetNotifierId()) {
  73. model_.AddObserver(this);
  74. message_center::MessageCenter::Get()->AddObserver(this);
  75. }
  76. AssistantNotificationControllerImpl::~AssistantNotificationControllerImpl() {
  77. message_center::MessageCenter::Get()->RemoveObserver(this);
  78. model_.RemoveObserver(this);
  79. }
  80. void AssistantNotificationControllerImpl::SetAssistant(
  81. assistant::Assistant* assistant) {
  82. receiver_.reset();
  83. assistant_ = assistant;
  84. if (assistant)
  85. receiver_.Bind(assistant_->GetPendingNotificationDelegate());
  86. }
  87. // AssistantNotificationController --------------------------------------
  88. void AssistantNotificationControllerImpl::RemoveNotificationById(
  89. const std::string& id,
  90. bool from_server) {
  91. model_.RemoveNotificationById(id, from_server);
  92. }
  93. void AssistantNotificationControllerImpl::SetQuietMode(bool enabled) {
  94. message_center::MessageCenter::Get()->SetQuietMode(enabled);
  95. }
  96. // NotificationDelegate ------------------------------------------------------
  97. void AssistantNotificationControllerImpl::AddOrUpdateNotification(
  98. AssistantNotification notification) {
  99. model_.AddOrUpdateNotification(std::move(notification));
  100. }
  101. void AssistantNotificationControllerImpl::RemoveNotificationByGroupingKey(
  102. const std::string& grouping_key,
  103. bool from_server) {
  104. model_.RemoveNotificationsByGroupingKey(grouping_key, from_server);
  105. }
  106. void AssistantNotificationControllerImpl::RemoveAllNotifications(
  107. bool from_server) {
  108. model_.RemoveAllNotifications(from_server);
  109. }
  110. // AssistantNotificationModelObserver ------------------------------------------
  111. void AssistantNotificationControllerImpl::OnNotificationAdded(
  112. const AssistantNotification& notification) {
  113. // Do not show system notifications if the setting is disabled.
  114. if (!AssistantState::Get()->notification_enabled().value_or(true))
  115. return;
  116. message_center::MessageCenter::Get()->AddNotification(
  117. CreateSystemNotification(notifier_id_, notification));
  118. }
  119. void AssistantNotificationControllerImpl::OnNotificationUpdated(
  120. const AssistantNotification& notification) {
  121. // Do not show system notifications if the setting is disabled.
  122. if (!AssistantState::Get()->notification_enabled().value_or(true))
  123. return;
  124. message_center::MessageCenter::Get()->UpdateNotification(
  125. notification.client_id,
  126. CreateSystemNotification(notifier_id_, notification));
  127. }
  128. void AssistantNotificationControllerImpl::OnNotificationRemoved(
  129. const AssistantNotification& notification,
  130. bool from_server) {
  131. // Remove the notification from the message center.
  132. message_center::MessageCenter::Get()->RemoveNotification(
  133. notification.client_id, /*by_user=*/false);
  134. // Dismiss the notification on the server to sync across devices.
  135. if (!from_server)
  136. assistant_->DismissNotification(notification);
  137. }
  138. void AssistantNotificationControllerImpl::OnAllNotificationsRemoved(
  139. bool from_server) {
  140. message_center::MessageCenter::Get()->RemoveNotificationsForNotifierId(
  141. notifier_id_);
  142. }
  143. // message_center::MessageCenterObserver ---------------------------------------
  144. void AssistantNotificationControllerImpl::OnNotificationClicked(
  145. const std::string& id,
  146. const absl::optional<int>& button_index,
  147. const absl::optional<std::u16string>& reply) {
  148. const AssistantNotification* notification = model_.GetNotificationById(id);
  149. if (!notification)
  150. return;
  151. const auto& action_url =
  152. button_index.has_value()
  153. ? notification->buttons[button_index.value()].action_url
  154. : notification->action_url;
  155. // Open the action url if it is valid.
  156. if (IsValidActionUrl(action_url)) {
  157. // NOTE: We copy construct a new GURL as our |notification| may be destroyed
  158. // during the OpenUrl() sequence leaving |action_url| in a bad state.
  159. AssistantController::Get()->OpenUrl(GURL(action_url));
  160. const bool remove_notification =
  161. button_index.has_value() ? notification->buttons[button_index.value()]
  162. .remove_notification_on_click
  163. : notification->remove_on_click;
  164. if (remove_notification)
  165. model_.RemoveNotificationById(id, /*from_server=*/false);
  166. return;
  167. }
  168. if (!notification->from_server)
  169. return;
  170. // If the notification is from the server, we retrieve the notification
  171. // payload using the following indexing scheme:
  172. //
  173. // Index: | [0] | [1] | [2] | ...
  174. // -------------------------------------------------
  175. // Action: | Top Level | Button 1 | Button 2 | ...
  176. const int action_index = button_index.value_or(-1) + 1;
  177. assistant_->RetrieveNotification(*notification, action_index);
  178. }
  179. void AssistantNotificationControllerImpl::OnNotificationRemoved(
  180. const std::string& notification_id,
  181. bool by_user) {
  182. // Update our notification model to remain in sync w/ Message Center.
  183. if (model_.GetNotificationById(notification_id))
  184. model_.RemoveNotificationById(notification_id, /*from_server=*/false);
  185. }
  186. } // namespace ash