#include "ash/assistant/assistant_notification_controller_impl.h"
#include <memory>
#include <utility>
#include "ash/assistant/assistant_controller_impl.h"
#include "ash/assistant/assistant_notification_expiry_monitor.h"
#include "ash/assistant/util/deep_link_util.h"
#include "ash/constants/notifier_catalogs.h"
#include "ash/public/cpp/assistant/assistant_state.h"
#include "ash/public/cpp/assistant/controller/assistant_controller.h"
#include "ash/public/cpp/notification_utils.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "base/strings/utf_string_conversions.h"
#include "chromeos/ash/services/libassistant/public/cpp/assistant_notification.h"
#include "chromeos/ui/vector_icons/vector_icons.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/notification.h"
#include "url/gurl.h"
namespace ash {
namespace {
constexpr char kNotifierId[] = "assistant";
std::unique_ptr<message_center::Notification> CreateSystemNotification(
const message_center::NotifierId& notifier_id,
const assistant::AssistantNotification& notification) {
const std::u16string title = base::UTF8ToUTF16(notification.title);
const std::u16string message = base::UTF8ToUTF16(notification.message);
const std::u16string display_source =
l10n_util::GetStringUTF16(IDS_ASH_ASSISTANT_NOTIFICATION_DISPLAY_SOURCE);
message_center::RichNotificationData data;
for (const auto& button : notification.buttons)
data.buttons.emplace_back(base::UTF8ToUTF16(button.label));
std::unique_ptr<message_center::Notification> system_notification =
ash::CreateSystemNotificationPtr(
message_center::NOTIFICATION_TYPE_SIMPLE, notification.client_id,
title, message, display_source, GURL(), notifier_id, data,
nullptr, chromeos::kNotificationAssistantIcon,
message_center::SystemNotificationWarningLevel::NORMAL);
system_notification->set_renotify(notification.renotify);
system_notification->set_pinned(notification.is_pinned);
switch (notification.priority) {
case assistant::AssistantNotificationPriority::kLow:
system_notification->set_priority(message_center::LOW_PRIORITY);
break;
case assistant::AssistantNotificationPriority::kDefault:
system_notification->set_priority(message_center::DEFAULT_PRIORITY);
break;
case assistant::AssistantNotificationPriority::kHigh:
system_notification->set_priority(message_center::HIGH_PRIORITY);
break;
}
return system_notification;
}
message_center::NotifierId GetNotifierId() {
return message_center::NotifierId(
message_center::NotifierType::SYSTEM_COMPONENT, kNotifierId,
NotificationCatalogName::kAssistantNotification);
}
bool IsValidActionUrl(const GURL& action_url) {
return action_url.is_valid() && (action_url.SchemeIsHTTPOrHTTPS() ||
assistant::util::IsDeepLinkUrl(action_url));
}
}
AssistantNotificationControllerImpl::AssistantNotificationControllerImpl()
: expiry_monitor_(this), notifier_id_(GetNotifierId()) {
model_.AddObserver(this);
message_center::MessageCenter::Get()->AddObserver(this);
}
AssistantNotificationControllerImpl::~AssistantNotificationControllerImpl() {
message_center::MessageCenter::Get()->RemoveObserver(this);
model_.RemoveObserver(this);
}
void AssistantNotificationControllerImpl::SetAssistant(
assistant::Assistant* assistant) {
receiver_.reset();
assistant_ = assistant;
if (assistant)
receiver_.Bind(assistant_->GetPendingNotificationDelegate());
}
void AssistantNotificationControllerImpl::RemoveNotificationById(
const std::string& id,
bool from_server) {
model_.RemoveNotificationById(id, from_server);
}
void AssistantNotificationControllerImpl::SetQuietMode(bool enabled) {
message_center::MessageCenter::Get()->SetQuietMode(enabled);
}
void AssistantNotificationControllerImpl::AddOrUpdateNotification(
AssistantNotification notification) {
model_.AddOrUpdateNotification(std::move(notification));
}
void AssistantNotificationControllerImpl::RemoveNotificationByGroupingKey(
const std::string& grouping_key,
bool from_server) {
model_.RemoveNotificationsByGroupingKey(grouping_key, from_server);
}
void AssistantNotificationControllerImpl::RemoveAllNotifications(
bool from_server) {
model_.RemoveAllNotifications(from_server);
}
void AssistantNotificationControllerImpl::OnNotificationAdded(
const AssistantNotification& notification) {
if (!AssistantState::Get()->notification_enabled().value_or(true))
return;
message_center::MessageCenter::Get()->AddNotification(
CreateSystemNotification(notifier_id_, notification));
}
void AssistantNotificationControllerImpl::OnNotificationUpdated(
const AssistantNotification& notification) {
if (!AssistantState::Get()->notification_enabled().value_or(true))
return;
message_center::MessageCenter::Get()->UpdateNotification(
notification.client_id,
CreateSystemNotification(notifier_id_, notification));
}
void AssistantNotificationControllerImpl::OnNotificationRemoved(
const AssistantNotification& notification,
bool from_server) {
message_center::MessageCenter::Get()->RemoveNotification(
notification.client_id, false);
if (!from_server && AssistantState::Get()->assistant_status() ==
assistant::AssistantStatus::READY) {
assistant_->DismissNotification(notification);
}
}
void AssistantNotificationControllerImpl::OnAllNotificationsRemoved(
bool from_server) {
message_center::MessageCenter::Get()->RemoveNotificationsForNotifierId(
notifier_id_);
}
void AssistantNotificationControllerImpl::OnNotificationClicked(
const std::string& id,
const absl::optional<int>& button_index,
const absl::optional<std::u16string>& reply) {
const AssistantNotification* notification = model_.GetNotificationById(id);
if (!notification)
return;
const auto& action_url =
button_index.has_value()
? notification->buttons[button_index.value()].action_url
: notification->action_url;
if (IsValidActionUrl(action_url)) {
AssistantController::Get()->OpenUrl(GURL(action_url));
const bool remove_notification =
button_index.has_value() ? notification->buttons[button_index.value()]
.remove_notification_on_click
: notification->remove_on_click;
if (remove_notification)
model_.RemoveNotificationById(id, false);
return;
}
if (!notification->from_server)
return;
const int action_index = button_index.value_or(-1) + 1;
if (AssistantState::Get()->assistant_status() ==
assistant::AssistantStatus::READY) {
assistant_->RetrieveNotification(*notification, action_index);
}
}
void AssistantNotificationControllerImpl::OnNotificationRemoved(
const std::string& notification_id,
bool by_user) {
if (model_.GetNotificationById(notification_id))
model_.RemoveNotificationById(notification_id, false);
}
}