| // 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/devtools_event_logging.h" |
| |
| #include "base/callback.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/devtools_background_services_context.h" |
| #include "content/public/browser/notification_database_data.h" |
| #include "content/public/browser/storage_partition.h" |
| #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h" |
| #include "url/gurl.h" |
| |
| namespace content { |
| namespace notifications { |
| |
| namespace { |
| |
| using EventMetadata = std::map<std::string, std::string>; |
| using DevToolsBaseCallback = |
| base::OnceCallback<void(const std::string& event_name, |
| const std::string& instance_id, |
| const EventMetadata& event_metadata)>; |
| using DevToolsCallback = |
| base::OnceCallback<void(const std::string& event_name, |
| const EventMetadata& event_metadata)>; |
| |
| DevToolsBackgroundServicesContext* GetDevToolsContext( |
| BrowserContext* browser_context, |
| const GURL& origin) { |
| auto* storage_partition = |
| BrowserContext::GetStoragePartitionForSite(browser_context, origin); |
| if (!storage_partition) |
| return nullptr; |
| |
| auto* devtools_context = |
| storage_partition->GetDevToolsBackgroundServicesContext(); |
| if (!devtools_context || !devtools_context->IsRecording( |
| DevToolsBackgroundService::kNotifications)) { |
| return nullptr; |
| } |
| |
| return devtools_context; |
| } |
| |
| DevToolsCallback GetDevToolsCallback(BrowserContext* browser_context, |
| const NotificationDatabaseData& data) { |
| if (data.service_worker_registration_id == |
| blink::mojom::kInvalidServiceWorkerRegistrationId) { |
| return DevToolsCallback(); |
| } |
| |
| auto* devtools_context = GetDevToolsContext(browser_context, data.origin); |
| if (!devtools_context) |
| return DevToolsCallback(); |
| |
| // Passing the |devtools_context| as base::Unretained is safe as the callback |
| // is executed synchronously. |
| auto base_callback = base::BindOnce( |
| &DevToolsBackgroundServicesContext::LogBackgroundServiceEvent, |
| base::Unretained(devtools_context), data.service_worker_registration_id, |
| url::Origin::Create(data.origin), |
| DevToolsBackgroundService::kNotifications); |
| |
| // TODO(knollr): Reorder parameters of LogBackgroundServiceEvent instead. |
| return base::BindOnce( |
| [](DevToolsBaseCallback callback, const std::string& notification_id, |
| const std::string& event_name, const EventMetadata& metadata) { |
| std::move(callback).Run(event_name, notification_id, metadata); |
| }, |
| std::move(base_callback), data.notification_data.tag); |
| } |
| |
| } // namespace |
| |
| bool ShouldLogNotificationEventToDevTools(BrowserContext* browser_context, |
| const GURL& origin) { |
| return GetDevToolsContext(browser_context, origin) != nullptr; |
| } |
| |
| void LogNotificationDisplayedEventToDevTools( |
| BrowserContext* browser_context, |
| const NotificationDatabaseData& data) { |
| DevToolsCallback callback = GetDevToolsCallback(browser_context, data); |
| if (!callback) |
| return; |
| |
| std::move(callback).Run(/* event_name= */ "Notification displayed", |
| /* event_metadata= */ {}); |
| } |
| |
| void LogNotificationClosedEventToDevTools( |
| BrowserContext* browser_context, |
| const NotificationDatabaseData& data) { |
| DevToolsCallback callback = GetDevToolsCallback(browser_context, data); |
| if (!callback) |
| return; |
| |
| std::move(callback).Run(/* event_name= */ "Notification closed", |
| /* event_metadata= */ {}); |
| } |
| |
| void LogNotificationScheduledEventToDevTools( |
| BrowserContext* browser_context, |
| const NotificationDatabaseData& data, |
| base::Time show_trigger_timestamp) { |
| DevToolsCallback callback = GetDevToolsCallback(browser_context, data); |
| if (!callback) |
| return; |
| |
| std::move(callback).Run( |
| /* event_name= */ "Notification scheduled", |
| /* event_metadata= */ { |
| {"Show Trigger Timestamp", |
| base::NumberToString(show_trigger_timestamp.ToJsTime())}}); |
| } |
| |
| void LogNotificationClickedEventToDevTools( |
| BrowserContext* browser_context, |
| const NotificationDatabaseData& data, |
| const base::Optional<int>& action_index, |
| const base::Optional<base::string16>& reply) { |
| DevToolsCallback callback = GetDevToolsCallback(browser_context, data); |
| if (!callback) |
| return; |
| |
| EventMetadata event_metadata; |
| if (action_index) |
| event_metadata["Action Index"] = base::NumberToString(*action_index); |
| if (reply) |
| event_metadata["Reply"] = base::UTF16ToUTF8(*reply); |
| |
| std::move(callback).Run(/* event_name= */ "Notification clicked", |
| event_metadata); |
| } |
| |
| } // namespace notifications |
| } // namespace content |