| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/assistant/assistant_notification_controller.h" |
| |
| #include "ash/assistant/assistant_controller.h" |
| #include "ash/new_window_controller.h" |
| #include "ash/public/cpp/vector_icons/vector_icons.h" |
| #include "ash/public/interfaces/voice_interaction_controller.mojom.h" |
| #include "ash/shell.h" |
| #include "ash/strings/grit/ash_strings.h" |
| #include "ash/voice_interaction/voice_interaction_controller.h" |
| #include "base/bind.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/message_center/message_center.h" |
| #include "ui/message_center/public/cpp/notification.h" |
| #include "ui/message_center/public/cpp/notification_delegate.h" |
| #include "url/gurl.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| constexpr char kNotificationId[] = "assistant"; |
| constexpr char kNotifierAssistant[] = "assistant"; |
| |
| // Delegate for an assistant notification. |
| class AssistantNotificationDelegate |
| : public message_center::NotificationDelegate { |
| public: |
| AssistantNotificationDelegate( |
| base::WeakPtr<AssistantNotificationController> notification_controller, |
| base::WeakPtr<AssistantController> assistant_controller, |
| chromeos::assistant::mojom::AssistantNotificationPtr notification) |
| : notification_controller_(std::move(notification_controller)), |
| assistant_controller_(std::move(assistant_controller)), |
| notification_(std::move(notification)) { |
| DCHECK(notification_); |
| } |
| |
| // message_center::NotificationDelegate: |
| void Close(bool by_user) override { |
| // If |by_user| is true, means that this close action is initiated by user, |
| // need to dismiss this notification at server to notify other devices. |
| // If |by_user| is false, means that this close action is initiated from the |
| // server, so do not need to dismiss this notification again. |
| if (by_user && notification_controller_) |
| notification_controller_->DismissNotification(notification_.Clone()); |
| } |
| |
| void Click(const base::Optional<int>& button_index, |
| const base::Optional<base::string16>& reply) override { |
| // Open the action url if it is valid. |
| if (notification_->action_url.is_valid() && assistant_controller_) { |
| assistant_controller_->OpenUrl(notification_->action_url); |
| return; |
| } |
| |
| if (notification_controller_) { |
| // TODO(wutao): support buttons with different |action_index|. |
| notification_controller_->RetrieveNotification(notification_.Clone(), |
| /*action_index=*/0); |
| } |
| } |
| |
| private: |
| // Refcounted. |
| ~AssistantNotificationDelegate() override = default; |
| |
| base::WeakPtr<AssistantNotificationController> notification_controller_; |
| |
| base::WeakPtr<AssistantController> assistant_controller_; |
| |
| chromeos::assistant::mojom::AssistantNotificationPtr notification_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AssistantNotificationDelegate); |
| }; |
| |
| std::string GetNotificationId(const std::string& grouping_key) { |
| return kNotificationId + grouping_key; |
| } |
| |
| message_center::NotifierId GetNotifierId() { |
| return message_center::NotifierId( |
| message_center::NotifierId::SYSTEM_COMPONENT, kNotifierAssistant); |
| } |
| |
| } // namespace |
| |
| AssistantNotificationController::AssistantNotificationController( |
| AssistantController* assistant_controller) |
| : assistant_controller_(assistant_controller), |
| assistant_notification_subscriber_binding_(this), |
| notifier_id_(GetNotifierId()), |
| weak_factory_(this) {} |
| |
| AssistantNotificationController::~AssistantNotificationController() = default; |
| |
| void AssistantNotificationController::SetAssistant( |
| chromeos::assistant::mojom::Assistant* assistant) { |
| assistant_ = assistant; |
| |
| // Subscribe to Assistant notification events. |
| chromeos::assistant::mojom::AssistantNotificationSubscriberPtr ptr; |
| assistant_notification_subscriber_binding_.Bind(mojo::MakeRequest(&ptr)); |
| assistant_->AddAssistantNotificationSubscriber(std::move(ptr)); |
| } |
| |
| void AssistantNotificationController::RetrieveNotification( |
| AssistantNotificationPtr notification, |
| int action_index) { |
| assistant_->RetrieveNotification(std::move(notification), action_index); |
| } |
| |
| void AssistantNotificationController::DismissNotification( |
| AssistantNotificationPtr notification) { |
| assistant_->DismissNotification(std::move(notification)); |
| } |
| |
| void AssistantNotificationController::OnShowNotification( |
| AssistantNotificationPtr notification) { |
| DCHECK(assistant_); |
| |
| // Do not show notification if the setting is false. |
| if (!Shell::Get()->voice_interaction_controller()->notification_enabled()) |
| return; |
| |
| // Create the specified |notification| that should be rendered in the |
| // |message_center| for the interaction. |
| const base::string16 title = base::UTF8ToUTF16(notification->title); |
| const base::string16 message = base::UTF8ToUTF16(notification->message); |
| const base::string16 display_source = |
| l10n_util::GetStringUTF16(IDS_ASH_ASSISTANT_NOTIFICATION_DISPLAY_SOURCE); |
| |
| message_center::MessageCenter* message_center = |
| message_center::MessageCenter::Get(); |
| message_center::RichNotificationData optional_field; |
| |
| std::unique_ptr<message_center::Notification> system_notification = |
| message_center::Notification::CreateSystemNotification( |
| message_center::NOTIFICATION_TYPE_SIMPLE, |
| GetNotificationId(notification->grouping_key), title, message, |
| display_source, GURL(), notifier_id_, optional_field, |
| new AssistantNotificationDelegate(weak_factory_.GetWeakPtr(), |
| assistant_controller_->GetWeakPtr(), |
| notification.Clone()), |
| kNotificationAssistantIcon, |
| message_center::SystemNotificationWarningLevel::NORMAL); |
| system_notification->set_priority(message_center::DEFAULT_PRIORITY); |
| message_center->AddNotification(std::move(system_notification)); |
| } |
| |
| void AssistantNotificationController::OnRemoveNotification( |
| const std::string& grouping_key) { |
| message_center::MessageCenter* message_center = |
| message_center::MessageCenter::Get(); |
| if (grouping_key.empty()) { |
| // Remove all assistant notifications by NotifierId. |
| message_center->RemoveNotificationsForNotifierId(notifier_id_); |
| } else { |
| // Remove the notification with |grouping_key|. It is no-op if no |
| // corresponding notification is found in |message_center|. |
| message_center->RemoveNotification(GetNotificationId(grouping_key), |
| /*by_user=*/false); |
| } |
| } |
| |
| } // namespace ash |