|  | // Copyright 2017 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "chrome/browser/extensions/api/notifications/extension_notification_handler.h" | 
|  |  | 
|  | #include "base/check_op.h" | 
|  | #include "base/functional/callback.h" | 
|  | #include "base/metrics/histogram_macros.h" | 
|  | #include "chrome/browser/extensions/api/notifications/extension_notification_display_helper.h" | 
|  | #include "chrome/browser/extensions/api/notifications/extension_notification_display_helper_factory.h" | 
|  | #include "chrome/browser/notifications/notification_common.h" | 
|  | #include "chrome/browser/notifications/notifier_state_tracker.h" | 
|  | #include "chrome/browser/notifications/notifier_state_tracker_factory.h" | 
|  | #include "chrome/browser/profiles/profile.h" | 
|  | #include "chrome/common/extensions/api/notifications.h" | 
|  | #include "extensions/browser/app_window/app_window.h" | 
|  | #include "extensions/browser/app_window/app_window_registry.h" | 
|  | #include "extensions/browser/app_window/native_app_window.h" | 
|  | #include "extensions/common/constants.h" | 
|  | #include "extensions/common/extension_id.h" | 
|  | #include "ui/message_center/public/cpp/notifier_id.h" | 
|  | #include "url/gurl.h" | 
|  |  | 
|  | namespace extensions { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | base::Value::List CreateBaseEventArgs( | 
|  | const ExtensionId& extension_id, | 
|  | const std::string& scoped_notification_id) { | 
|  | // Unscope the notification id before returning it. | 
|  | size_t index_of_separator = extension_id.length() + 1; | 
|  | DCHECK_LT(index_of_separator, scoped_notification_id.length()); | 
|  | std::string unscoped_notification_id = | 
|  | scoped_notification_id.substr(index_of_separator); | 
|  |  | 
|  | base::Value::List args; | 
|  | args.Append(unscoped_notification_id); | 
|  | return args; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | ExtensionNotificationHandler::ExtensionNotificationHandler() = default; | 
|  |  | 
|  | ExtensionNotificationHandler::~ExtensionNotificationHandler() = default; | 
|  |  | 
|  | // static | 
|  | ExtensionId ExtensionNotificationHandler::GetExtensionId(const GURL& url) { | 
|  | if (!url.is_valid() || !url.SchemeIs(kExtensionScheme)) { | 
|  | return ""; | 
|  | } | 
|  | return ExtensionId(url.DeprecatedGetOriginAsURL().host_piece()); | 
|  | } | 
|  |  | 
|  | void ExtensionNotificationHandler::OnClose( | 
|  | Profile* profile, | 
|  | const GURL& origin, | 
|  | const std::string& notification_id, | 
|  | bool by_user, | 
|  | base::OnceClosure completed_closure) { | 
|  | EventRouter::UserGestureState gesture = | 
|  | by_user ? EventRouter::UserGestureState::kEnabled | 
|  | : EventRouter::UserGestureState::kNotEnabled; | 
|  | ExtensionId extension_id(GetExtensionId(GURL(origin))); | 
|  | DCHECK(!extension_id.empty()); | 
|  |  | 
|  | base::Value::List args = CreateBaseEventArgs(extension_id, notification_id); | 
|  | args.Append(by_user); | 
|  | SendEvent(profile, extension_id, events::NOTIFICATIONS_ON_CLOSED, | 
|  | api::notifications::OnClosed::kEventName, gesture, std::move(args)); | 
|  |  | 
|  | ExtensionNotificationDisplayHelper* display_helper = | 
|  | ExtensionNotificationDisplayHelperFactory::GetForProfile(profile); | 
|  | if (display_helper) | 
|  | display_helper->EraseDataForNotificationId(notification_id); | 
|  |  | 
|  | std::move(completed_closure).Run(); | 
|  | } | 
|  |  | 
|  | void ExtensionNotificationHandler::OnClick( | 
|  | Profile* profile, | 
|  | const GURL& origin, | 
|  | const std::string& notification_id, | 
|  | const std::optional<int>& action_index, | 
|  | const std::optional<std::u16string>& reply, | 
|  | base::OnceClosure completed_closure) { | 
|  | DCHECK(!reply.has_value()); | 
|  |  | 
|  | ExtensionId extension_id(GetExtensionId(GURL(origin))); | 
|  | base::Value::List args = CreateBaseEventArgs(extension_id, notification_id); | 
|  | if (action_index.has_value()) | 
|  | args.Append(action_index.value()); | 
|  | events::HistogramValue histogram_value = | 
|  | action_index.has_value() ? events::NOTIFICATIONS_ON_BUTTON_CLICKED | 
|  | : events::NOTIFICATIONS_ON_CLICKED; | 
|  | const std::string& event_name = | 
|  | action_index.has_value() ? api::notifications::OnButtonClicked::kEventName | 
|  | : api::notifications::OnClicked::kEventName; | 
|  |  | 
|  | SendEvent(profile, extension_id, histogram_value, event_name, | 
|  | EventRouter::UserGestureState::kEnabled, std::move(args)); | 
|  |  | 
|  | std::move(completed_closure).Run(); | 
|  | } | 
|  |  | 
|  | void ExtensionNotificationHandler::DisableNotifications( | 
|  | Profile* profile, | 
|  | const GURL& origin, | 
|  | const std::optional<std::string>& notification_id) { | 
|  | message_center::NotifierId notifier_id( | 
|  | message_center::NotifierType::APPLICATION, origin.host()); | 
|  | NotifierStateTrackerFactory::GetForProfile(profile)->SetNotifierEnabled( | 
|  | notifier_id, false /* enabled */); | 
|  | } | 
|  |  | 
|  | // There are not settings to open, but on the chance the notification shows with | 
|  | // the "Open Settings" prompt, this will no-op. | 
|  | void ExtensionNotificationHandler::OpenSettings(Profile* profile, | 
|  | const GURL& origin) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | void ExtensionNotificationHandler::SendEvent( | 
|  | Profile* profile, | 
|  | const ExtensionId& extension_id, | 
|  | events::HistogramValue histogram_value, | 
|  | const std::string& event_name, | 
|  | EventRouter::UserGestureState user_gesture, | 
|  | base::Value::List args) { | 
|  | if (extension_id.empty()) | 
|  | return; | 
|  |  | 
|  | EventRouter* event_router = EventRouter::Get(profile); | 
|  | if (!event_router) | 
|  | return; | 
|  |  | 
|  | auto event = | 
|  | std::make_unique<Event>(histogram_value, event_name, std::move(args)); | 
|  | event->user_gesture = user_gesture; | 
|  | event_router->DispatchEventToExtension(extension_id, std::move(event)); | 
|  | } | 
|  |  | 
|  | }  // namespace extensions |