blob: 79c9f4131ecfc3c1ecdece9e37180ef967aa07b7 [file] [log] [blame]
// Copyright 2019 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 "content/browser/notifications/platform_notification_service_proxy.h"
#include <memory>
#include <utility>
#include "base/check_op.h"
#include "content/browser/notifications/devtools_event_logging.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/notification_database_data.h"
#include "content/public/browser/platform_notification_service.h"
#include "content/public/common/content_client.h"
namespace content {
PlatformNotificationServiceProxy::PlatformNotificationServiceProxy(
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
BrowserContext* browser_context)
: service_worker_context_(service_worker_context),
browser_context_(browser_context),
notification_service_(
GetContentClient()->browser()->GetPlatformNotificationService(
browser_context)) {}
PlatformNotificationServiceProxy::~PlatformNotificationServiceProxy() = default;
void PlatformNotificationServiceProxy::Shutdown() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
weak_ptr_factory_ui_.InvalidateWeakPtrs();
}
base::WeakPtr<PlatformNotificationServiceProxy>
PlatformNotificationServiceProxy::AsWeakPtr() {
return weak_ptr_factory_ui_.GetWeakPtr();
}
void PlatformNotificationServiceProxy::DoDisplayNotification(
const NotificationDatabaseData& data,
const GURL& service_worker_scope,
DisplayResultCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (notification_service_) {
notification_service_->DisplayPersistentNotification(
data.notification_id, service_worker_scope, data.origin,
data.notification_data,
data.notification_resources.value_or(blink::NotificationResources()));
notifications::LogNotificationDisplayedEventToDevTools(browser_context_,
data);
}
std::move(callback).Run(/* success= */ true, data.notification_id);
}
void PlatformNotificationServiceProxy::VerifyServiceWorkerScope(
const NotificationDatabaseData& data,
DisplayResultCallback callback,
blink::ServiceWorkerStatusCode status,
scoped_refptr<ServiceWorkerRegistration> registration) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
base::OnceClosure task;
if (status == blink::ServiceWorkerStatusCode::kOk &&
registration->scope().GetOrigin() == data.origin) {
DoDisplayNotification(data, registration->scope(), std::move(callback));
} else {
std::move(callback).Run(/* success= */ false, /* notification_id= */ "");
}
}
void PlatformNotificationServiceProxy::DisplayNotification(
const NotificationDatabaseData& data,
DisplayResultCallback callback) {
if (!service_worker_context_) {
GetUIThreadTaskRunner({base::TaskPriority::USER_VISIBLE})
->PostTask(FROM_HERE,
base::BindOnce(
&PlatformNotificationServiceProxy::DoDisplayNotification,
AsWeakPtr(), data, GURL(), std::move(callback)));
return;
}
scoped_refptr<base::SingleThreadTaskRunner> core_thread_task_runner;
constexpr BrowserTaskTraits traits = {base::TaskPriority::USER_VISIBLE};
switch (ServiceWorkerContext::GetCoreThreadId()) {
case BrowserThread::UI:
core_thread_task_runner = GetUIThreadTaskRunner(traits);
break;
case BrowserThread::IO:
core_thread_task_runner = GetIOThreadTaskRunner(traits);
break;
case BrowserThread::ID_COUNT:
NOTREACHED();
}
core_thread_task_runner->PostTask(
FROM_HERE,
base::BindOnce(
&ServiceWorkerContextWrapper::FindReadyRegistrationForId,
service_worker_context_, data.service_worker_registration_id,
url::Origin::Create(data.origin),
base::BindOnce(
&PlatformNotificationServiceProxy::VerifyServiceWorkerScope,
weak_ptr_factory_io_.GetWeakPtr(), data, std::move(callback))));
}
void PlatformNotificationServiceProxy::CloseNotifications(
const std::set<std::string>& notification_ids) {
if (!notification_service_)
return;
GetUIThreadTaskRunner({base::TaskPriority::USER_VISIBLE})
->PostTask(FROM_HERE,
base::BindOnce(
&PlatformNotificationServiceProxy::DoCloseNotifications,
AsWeakPtr(), notification_ids));
}
void PlatformNotificationServiceProxy::DoCloseNotifications(
const std::set<std::string>& notification_ids) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (const std::string& notification_id : notification_ids)
notification_service_->ClosePersistentNotification(notification_id);
}
void PlatformNotificationServiceProxy::ScheduleTrigger(base::Time timestamp) {
if (!notification_service_)
return;
GetUIThreadTaskRunner({base::TaskPriority::USER_VISIBLE})
->PostTask(
FROM_HERE,
base::BindOnce(&PlatformNotificationServiceProxy::DoScheduleTrigger,
AsWeakPtr(), timestamp));
}
void PlatformNotificationServiceProxy::DoScheduleTrigger(base::Time timestamp) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
notification_service_->ScheduleTrigger(timestamp);
}
void PlatformNotificationServiceProxy::ScheduleNotification(
const NotificationDatabaseData& data) {
DCHECK(data.notification_data.show_trigger_timestamp.has_value());
if (!notification_service_)
return;
GetUIThreadTaskRunner({base::TaskPriority::USER_VISIBLE})
->PostTask(FROM_HERE,
base::BindOnce(
&PlatformNotificationServiceProxy::DoScheduleNotification,
AsWeakPtr(), data));
}
void PlatformNotificationServiceProxy::DoScheduleNotification(
const NotificationDatabaseData& data) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::Time show_trigger_timestamp =
data.notification_data.show_trigger_timestamp.value();
notifications::LogNotificationScheduledEventToDevTools(
browser_context_, data, show_trigger_timestamp);
notification_service_->ScheduleTrigger(show_trigger_timestamp);
}
base::Time PlatformNotificationServiceProxy::GetNextTrigger() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!notification_service_)
return base::Time::Max();
return notification_service_->ReadNextTriggerTimestamp();
}
void PlatformNotificationServiceProxy::RecordNotificationUkmEvent(
const NotificationDatabaseData& data) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!notification_service_)
return;
notification_service_->RecordNotificationUkmEvent(data);
}
bool PlatformNotificationServiceProxy::ShouldLogClose(const GURL& origin) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return notifications::ShouldLogNotificationEventToDevTools(browser_context_,
origin);
}
void PlatformNotificationServiceProxy::LogClose(
const NotificationDatabaseData& data) {
GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
->PostTask(FROM_HERE,
base::BindOnce(&PlatformNotificationServiceProxy::DoLogClose,
AsWeakPtr(), data));
}
void PlatformNotificationServiceProxy::DoLogClose(
const NotificationDatabaseData& data) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
notifications::LogNotificationClosedEventToDevTools(browser_context_, data);
}
} // namespace content