blob: b85766c00cbbaf529c17d6fc397766603049ed7b [file] [log] [blame]
Jack Hsiehaba560282022-12-12 17:36:531// Copyright 2022 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/hid/hid_connection_tracker.h"
6
7#include <string>
8
9#include "base/notreached.h"
10#include "base/strings/strcat.h"
11#include "base/strings/utf_string_conversions.h"
12#include "build/build_config.h"
13#include "chrome/browser/browser_process.h"
Jack Hsiehea76b94b52022-12-13 16:37:0514#include "chrome/browser/hid/hid_system_tray_icon.h"
Jack Hsiehaba560282022-12-12 17:36:5315#include "chrome/browser/notifications/notification_display_service.h"
16#include "chrome/browser/profiles/profile.h"
17#include "chrome/browser/ui/chrome_pages.h"
18#include "chrome/grit/chromium_strings.h"
19#include "chrome/grit/generated_resources.h"
20#include "components/vector_icons/vector_icons.h"
21#include "extensions/buildflags/buildflags.h"
22#include "ui/base/l10n/l10n_util.h"
23#include "ui/message_center/public/cpp/notification.h"
24#include "ui/message_center/public/cpp/notification_delegate.h"
25#include "url/origin.h"
26
27#if BUILDFLAG(ENABLE_EXTENSIONS)
28#include "extensions/browser/extension_registry.h"
29#include "extensions/common/constants.h"
30#endif // BUILDFLAG(ENABLE_EXTENSIONS)
31
32namespace {
33
34std::u16string GetDeviceConnectedNotificationMessage(
35 Profile* profile,
36 const url::Origin& origin) {
37#if BUILDFLAG(ENABLE_EXTENSIONS)
38 if (origin.scheme() == extensions::kExtensionScheme) {
39 const auto* extension_registry =
40 extensions::ExtensionRegistry::Get(profile);
41 DCHECK(extension_registry);
42 const extensions::Extension* extension =
43 extension_registry->GetExtensionById(
44 origin.host(), extensions::ExtensionRegistry::EVERYTHING);
45 return l10n_util::GetStringFUTF16(
46 IDS_WEBHID_DEVICE_CONNECTED_BY_EXTENSION_NOTIFICATION_MESSAGE,
47 base::UTF8ToUTF16(extension->name()));
48 }
49#endif // BUILDFLAG(ENABLE_EXTENSIONS)
50 NOTREACHED();
51 return u"";
52}
53
54std::string GetDeviceOpenedNotificationId(Profile* profile,
55 const url::Origin& origin) {
56 return base::StrCat(
57 {"webhid.opened.", profile->UniqueId(), ".", origin.host()});
58}
59
60} // namespace
61
62HidConnectionTracker::HidConnectionTracker(Profile* profile)
63 : profile_(profile) {}
64
65HidConnectionTracker::~HidConnectionTracker() {
66 CleanUp();
67}
68
Jack Hsiehe777b292023-04-15 07:26:4569void HidConnectionTracker::IncrementConnectionCount(const url::Origin& origin) {
Jack Hsiehaba560282022-12-12 17:36:5370 ++connection_count_;
Jack Hsiehea76b94b52022-12-13 16:37:0571 auto* hid_system_tray_icon = g_browser_process->hid_system_tray_icon();
72 if (!hid_system_tray_icon) {
73 return;
74 }
75
76 if (connection_count_ == 1) {
Jack Hsieh2ba757f2023-03-25 03:50:4377 hid_system_tray_icon->StageProfile(profile_);
Jack Hsiehea76b94b52022-12-13 16:37:0578 } else {
79 hid_system_tray_icon->NotifyConnectionCountUpdated(profile_);
80 }
Jack Hsiehaba560282022-12-12 17:36:5381}
82
Jack Hsiehe777b292023-04-15 07:26:4583void HidConnectionTracker::DecrementConnectionCount(const url::Origin& origin) {
Jack Hsiehaba560282022-12-12 17:36:5384 --connection_count_;
Jack Hsiehea76b94b52022-12-13 16:37:0585 auto* hid_system_tray_icon = g_browser_process->hid_system_tray_icon();
86 if (!hid_system_tray_icon) {
87 return;
88 }
89
90 if (connection_count_ == 0) {
Jack Hsieh2ba757f2023-03-25 03:50:4391 hid_system_tray_icon->UnstageProfile(profile_, /*immediate=*/false);
Jack Hsiehea76b94b52022-12-13 16:37:0592 } else {
93 hid_system_tray_icon->NotifyConnectionCountUpdated(profile_);
94 }
Jack Hsiehaba560282022-12-12 17:36:5395}
96
97void HidConnectionTracker::NotifyDeviceConnected(const url::Origin& origin) {
98 auto delegate =
99 base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
100 base::BindRepeating(
101 [](HidConnectionTracker* hid_connection_tracker,
102 const url::Origin& origin, absl::optional<int> button_index) {
103 // |hid_connection_tracker| will always be valid here because an
104 // active notification prevents the Profile (which owns the
105 // HidConnectionTracker as a KeyedService) from being destroyed.
106 hid_connection_tracker->ShowSiteSettings(origin);
107 },
108 this, origin));
109
110 auto notification_id = GetDeviceOpenedNotificationId(profile_, origin);
111 message_center::Notification notification(
112 message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
113 l10n_util::GetStringUTF16(
114 IDS_WEBHID_DEVICE_CONNECTED_BY_EXTENSION_NOTIFICATION_TITLE),
115 GetDeviceConnectedNotificationMessage(profile_, origin),
116 ui::ImageModel::FromVectorIcon(vector_icons::kVideogameAssetIcon,
117 ui::kColorIcon, 64),
118 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), /*origin_url=*/{},
119#if BUILDFLAG(IS_CHROMEOS_ASH)
120 message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
121 notification_id,
122 ash::NotificationCatalogName::kWebHid),
123#else
124 message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
125 notification_id),
126#endif // BUILDFLAG(IS_CHROMEOS_ASH)
127 message_center::RichNotificationData(), std::move(delegate));
128 NotificationDisplayService::GetForProfile(profile_)->Display(
129 NotificationHandler::Type::TRANSIENT, notification,
130 /*metadata=*/nullptr);
131}
132
133void HidConnectionTracker::ShowHidContentSettingsExceptions() {
134 chrome::ShowContentSettingsExceptionsForProfile(
135 profile_, ContentSettingsType::HID_CHOOSER_DATA);
136}
137
138void HidConnectionTracker::ShowSiteSettings(const url::Origin& origin) {
139 chrome::ShowSiteSettings(profile_, origin.GetURL());
140}
141
142void HidConnectionTracker::CleanUp() {
143 if (connection_count_ > 0) {
144 connection_count_ = 0;
Jack Hsiehea76b94b52022-12-13 16:37:05145 auto* hid_system_tray_icon = g_browser_process->hid_system_tray_icon();
146 if (hid_system_tray_icon)
Jack Hsieh2ba757f2023-03-25 03:50:43147 hid_system_tray_icon->UnstageProfile(profile_, /*immediate=*/true);
Jack Hsiehaba560282022-12-12 17:36:53148 }
149}