blob: 383ca4fea56c02be9795f62ac8970a23986670d8 [file] [log] [blame]
// 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