blob: 36fcdd1f6205579f0b6fba5b4407f4d18c57dc26 [file] [log] [blame]
// Copyright 2020 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 "chrome/browser/notifications/notification_platform_bridge_lacros.h"
#include <utility>
#include "base/check.h"
#include "base/notreached.h"
#include "base/numerics/ranges.h"
#include "base/numerics/safe_conversions.h"
#include "base/optional.h"
#include "chrome/browser/notifications/notification_platform_bridge_delegate.h"
#include "chromeos/crosapi/mojom/message_center.mojom.h"
#include "chromeos/crosapi/mojom/notification.mojom.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notification_types.h"
namespace {
crosapi::mojom::NotificationType ToMojo(message_center::NotificationType type) {
switch (type) {
case message_center::NOTIFICATION_TYPE_SIMPLE:
case message_center::NOTIFICATION_TYPE_BASE_FORMAT:
// TYPE_BASE_FORMAT is displayed the same as TYPE_SIMPLE.
return crosapi::mojom::NotificationType::kSimple;
case message_center::NOTIFICATION_TYPE_IMAGE:
return crosapi::mojom::NotificationType::kImage;
case message_center::NOTIFICATION_TYPE_MULTIPLE:
return crosapi::mojom::NotificationType::kList;
case message_center::NOTIFICATION_TYPE_PROGRESS:
return crosapi::mojom::NotificationType::kProgress;
case message_center::NOTIFICATION_TYPE_CUSTOM:
// TYPE_CUSTOM exists only within ash.
NOTREACHED();
return crosapi::mojom::NotificationType::kSimple;
}
}
crosapi::mojom::FullscreenVisibility ToMojo(
message_center::FullscreenVisibility visibility) {
switch (visibility) {
case message_center::FullscreenVisibility::NONE:
return crosapi::mojom::FullscreenVisibility::kNone;
case message_center::FullscreenVisibility::OVER_USER:
return crosapi::mojom::FullscreenVisibility::kOverUser;
}
}
crosapi::mojom::NotificationPtr ToMojo(
const message_center::Notification& notification) {
auto mojo_note = crosapi::mojom::Notification::New();
mojo_note->type = ToMojo(notification.type());
mojo_note->id = notification.id();
mojo_note->title = notification.title();
mojo_note->message = notification.message();
mojo_note->display_source = notification.display_source();
mojo_note->origin_url = notification.origin_url();
if (!notification.icon().IsEmpty())
mojo_note->icon = notification.icon().AsImageSkia();
mojo_note->priority = base::ClampToRange(notification.priority(), -2, 2);
mojo_note->require_interaction = notification.never_timeout();
mojo_note->timestamp = notification.timestamp();
if (!notification.image().IsEmpty())
mojo_note->image = notification.image().AsImageSkia();
if (!notification.small_image().IsEmpty())
mojo_note->badge = notification.small_image().AsImageSkia();
for (const auto& item : notification.items()) {
auto mojo_item = crosapi::mojom::NotificationItem::New();
mojo_item->title = item.title;
mojo_item->message = item.message;
mojo_note->items.push_back(std::move(mojo_item));
}
mojo_note->progress = base::ClampToRange(notification.progress(), -1, 100);
mojo_note->progress_status = notification.progress_status();
for (const auto& button : notification.buttons()) {
auto mojo_button = crosapi::mojom::ButtonInfo::New();
mojo_button->title = button.title;
mojo_note->buttons.push_back(std::move(mojo_button));
}
mojo_note->pinned = notification.pinned();
mojo_note->renotify = notification.renotify();
mojo_note->silent = notification.silent();
mojo_note->accessible_name = notification.accessible_name();
mojo_note->fullscreen_visibility =
ToMojo(notification.fullscreen_visibility());
return mojo_note;
}
} // namespace
// Keeps track of notifications being displayed in the remote message center.
class NotificationPlatformBridgeLacros::RemoteNotificationDelegate
: public crosapi::mojom::NotificationDelegate {
public:
RemoteNotificationDelegate(
const std::string& notification_id,
NotificationPlatformBridgeDelegate* bridge_delegate,
base::WeakPtr<NotificationPlatformBridgeLacros> owner)
: notification_id_(notification_id),
bridge_delegate_(bridge_delegate),
owner_(owner) {
DCHECK(!notification_id_.empty());
DCHECK(bridge_delegate_);
DCHECK(owner_);
}
RemoteNotificationDelegate(const RemoteNotificationDelegate&) = delete;
RemoteNotificationDelegate& operator=(const RemoteNotificationDelegate&) =
delete;
~RemoteNotificationDelegate() override = default;
mojo::PendingRemote<crosapi::mojom::NotificationDelegate>
BindNotificationDelegate() {
return receiver_.BindNewPipeAndPassRemote();
}
// crosapi::mojom::NotificationDelegate:
void OnNotificationClosed(bool by_user) override {
bridge_delegate_->HandleNotificationClosed(notification_id_, by_user);
if (owner_)
owner_->OnRemoteNotificationClosed(notification_id_);
// NOTE: |this| is deleted.
}
void OnNotificationClicked() override {
bridge_delegate_->HandleNotificationClicked(notification_id_);
}
void OnNotificationButtonClicked(uint32_t button_index) override {
// Chrome OS does not support inline reply.
bridge_delegate_->HandleNotificationButtonClicked(
notification_id_, base::checked_cast<int>(button_index),
/*reply=*/base::nullopt);
}
void OnNotificationSettingsButtonClicked() override {
bridge_delegate_->HandleNotificationSettingsButtonClicked(notification_id_);
}
void OnNotificationDisabled() override {
bridge_delegate_->DisableNotification(notification_id_);
}
private:
const std::string notification_id_;
NotificationPlatformBridgeDelegate* const bridge_delegate_;
base::WeakPtr<NotificationPlatformBridgeLacros> owner_;
mojo::Receiver<crosapi::mojom::NotificationDelegate> receiver_{this};
};
NotificationPlatformBridgeLacros::NotificationPlatformBridgeLacros(
NotificationPlatformBridgeDelegate* delegate,
mojo::Remote<crosapi::mojom::MessageCenter>* message_center_remote)
: bridge_delegate_(delegate),
message_center_remote_(message_center_remote) {
DCHECK(bridge_delegate_);
}
NotificationPlatformBridgeLacros::~NotificationPlatformBridgeLacros() = default;
void NotificationPlatformBridgeLacros::Display(
NotificationHandler::Type notification_type,
Profile* profile,
const message_center::Notification& notification,
std::unique_ptr<NotificationCommon::Metadata> metadata) {
if (!message_center_remote_)
return;
// |profile| is ignored because Profile management is handled in
// NotificationPlatformBridgeChromeOs, which includes a profile ID as part of
// the notification ID. Lacros does not support Chrome OS multi-signin, so we
// don't need to handle inactive user notification blockers in ash.
// Clean up any old notification with the same ID before creating the new one.
remote_notifications_.erase(notification.id());
auto pending_notification = std::make_unique<RemoteNotificationDelegate>(
notification.id(), bridge_delegate_, weak_factory_.GetWeakPtr());
(*message_center_remote_)
->DisplayNotification(ToMojo(notification),
pending_notification->BindNotificationDelegate());
remote_notifications_[notification.id()] = std::move(pending_notification);
}
void NotificationPlatformBridgeLacros::Close(
Profile* profile,
const std::string& notification_id) {
if (!message_center_remote_)
return;
(*message_center_remote_)->CloseNotification(notification_id);
// |remote_notifications_| is cleaned up after the remote notification closes
// and notifies us via the delegate.
}
void NotificationPlatformBridgeLacros::GetDisplayed(
Profile* profile,
GetDisplayedNotificationsCallback callback) const {
NOTIMPLEMENTED();
std::move(callback).Run(/*notification_ids=*/{}, /*supports_sync=*/false);
}
void NotificationPlatformBridgeLacros::SetReadyCallback(
NotificationBridgeReadyCallback callback) {
std::move(callback).Run(!!message_center_remote_);
}
void NotificationPlatformBridgeLacros::DisplayServiceShutDown(
Profile* profile) {
remote_notifications_.clear();
}
void NotificationPlatformBridgeLacros::OnRemoteNotificationClosed(
const std::string& id) {
remote_notifications_.erase(id);
}