Revert "Fix broken channel icon in chrome://help on CrOS" and try again
[chromium-blink-merge.git] / extensions / browser / api / device_permissions_prompt.cc
blob80697482333f3bf15be911cf4d54bd64356a8aea
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/api/device_permissions_prompt.h"
7 #include "base/bind.h"
8 #include "base/i18n/message_formatter.h"
9 #include "base/scoped_observer.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "device/core/device_client.h"
13 #include "device/hid/hid_device_filter.h"
14 #include "device/hid/hid_device_info.h"
15 #include "device/hid/hid_service.h"
16 #include "device/usb/usb_device.h"
17 #include "device/usb/usb_device_filter.h"
18 #include "device/usb/usb_ids.h"
19 #include "device/usb/usb_service.h"
20 #include "extensions/browser/api/device_permissions_manager.h"
21 #include "extensions/common/extension.h"
22 #include "extensions/strings/grit/extensions_strings.h"
23 #include "ui/base/l10n/l10n_util.h"
25 #if defined(OS_CHROMEOS)
26 #include "chromeos/dbus/dbus_thread_manager.h"
27 #include "chromeos/dbus/permission_broker_client.h"
28 #include "device/hid/hid_device_info_linux.h"
29 #endif // defined(OS_CHROMEOS)
31 using device::HidDeviceFilter;
32 using device::HidService;
33 using device::UsbDevice;
34 using device::UsbDeviceFilter;
35 using device::UsbService;
37 namespace extensions {
39 namespace {
41 class UsbDeviceInfo : public DevicePermissionsPrompt::Prompt::DeviceInfo {
42 public:
43 UsbDeviceInfo(scoped_refptr<UsbDevice> device) : device_(device) {
44 name_ = DevicePermissionsManager::GetPermissionMessage(
45 device->vendor_id(), device->product_id(),
46 device->manufacturer_string(), device->product_string(),
47 base::string16(), // Serial number is displayed separately.
48 true);
49 serial_number_ = device->serial_number();
52 ~UsbDeviceInfo() override {}
54 const scoped_refptr<UsbDevice>& device() const { return device_; }
56 private:
57 // TODO(reillyg): Convert this to a weak reference when UsbDevice has a
58 // connected flag.
59 scoped_refptr<UsbDevice> device_;
62 class UsbDevicePermissionsPrompt : public DevicePermissionsPrompt::Prompt,
63 public device::UsbService::Observer {
64 public:
65 UsbDevicePermissionsPrompt(
66 const Extension* extension,
67 content::BrowserContext* context,
68 bool multiple,
69 const std::vector<UsbDeviceFilter>& filters,
70 const DevicePermissionsPrompt::UsbDevicesCallback& callback)
71 : Prompt(extension, context, multiple),
72 filters_(filters),
73 callback_(callback),
74 service_observer_(this) {}
76 private:
77 ~UsbDevicePermissionsPrompt() override {}
79 // DevicePermissionsPrompt::Prompt implementation:
80 void SetObserver(
81 DevicePermissionsPrompt::Prompt::Observer* observer) override {
82 DevicePermissionsPrompt::Prompt::SetObserver(observer);
84 if (observer) {
85 UsbService* service = device::DeviceClient::Get()->GetUsbService();
86 if (service && !service_observer_.IsObserving(service)) {
87 service->GetDevices(
88 base::Bind(&UsbDevicePermissionsPrompt::OnDevicesEnumerated, this));
89 service_observer_.Add(service);
94 base::string16 GetHeading() const override {
95 return l10n_util::GetSingleOrMultipleStringUTF16(
96 IDS_USB_DEVICE_PERMISSIONS_PROMPT_TITLE, multiple());
99 void Dismissed() override {
100 DevicePermissionsManager* permissions_manager =
101 DevicePermissionsManager::Get(browser_context());
102 std::vector<scoped_refptr<UsbDevice>> devices;
103 for (const DeviceInfo* device : devices_) {
104 if (device->granted()) {
105 const UsbDeviceInfo* usb_device =
106 static_cast<const UsbDeviceInfo*>(device);
107 devices.push_back(usb_device->device());
108 if (permissions_manager) {
109 permissions_manager->AllowUsbDevice(extension()->id(),
110 usb_device->device());
114 DCHECK(multiple() || devices.size() <= 1);
115 callback_.Run(devices);
116 callback_.Reset();
119 // device::UsbService::Observer implementation:
120 void OnDeviceAdded(scoped_refptr<UsbDevice> device) override {
121 if (!(filters_.empty() || UsbDeviceFilter::MatchesAny(device, filters_))) {
122 return;
125 scoped_ptr<DeviceInfo> device_info(new UsbDeviceInfo(device));
126 device->CheckUsbAccess(
127 base::Bind(&UsbDevicePermissionsPrompt::AddCheckedDevice, this,
128 base::Passed(&device_info)));
131 void OnDeviceRemoved(scoped_refptr<UsbDevice> device) override {
132 for (auto it = devices_.begin(); it != devices_.end(); ++it) {
133 const UsbDeviceInfo* entry = static_cast<const UsbDeviceInfo*>(*it);
134 if (entry->device() == device) {
135 devices_.erase(it);
136 if (observer()) {
137 observer()->OnDevicesChanged();
139 return;
144 void OnDevicesEnumerated(
145 const std::vector<scoped_refptr<UsbDevice>>& devices) {
146 for (const auto& device : devices) {
147 OnDeviceAdded(device);
151 std::vector<UsbDeviceFilter> filters_;
152 DevicePermissionsPrompt::UsbDevicesCallback callback_;
153 ScopedObserver<UsbService, UsbService::Observer> service_observer_;
156 class HidDeviceInfo : public DevicePermissionsPrompt::Prompt::DeviceInfo {
157 public:
158 HidDeviceInfo(scoped_refptr<device::HidDeviceInfo> device) : device_(device) {
159 name_ = DevicePermissionsManager::GetPermissionMessage(
160 device->vendor_id(), device->product_id(),
161 base::string16(), // HID devices include manufacturer in product name.
162 base::UTF8ToUTF16(device->product_name()),
163 base::string16(), // Serial number is displayed separately.
164 false);
165 serial_number_ = base::UTF8ToUTF16(device->serial_number());
168 ~HidDeviceInfo() override {}
170 const scoped_refptr<device::HidDeviceInfo>& device() const { return device_; }
172 private:
173 scoped_refptr<device::HidDeviceInfo> device_;
176 class HidDevicePermissionsPrompt : public DevicePermissionsPrompt::Prompt,
177 public device::HidService::Observer {
178 public:
179 HidDevicePermissionsPrompt(
180 const Extension* extension,
181 content::BrowserContext* context,
182 bool multiple,
183 const std::vector<HidDeviceFilter>& filters,
184 const DevicePermissionsPrompt::HidDevicesCallback& callback)
185 : Prompt(extension, context, multiple),
186 filters_(filters),
187 callback_(callback),
188 service_observer_(this) {}
190 private:
191 ~HidDevicePermissionsPrompt() override {}
193 // DevicePermissionsPrompt::Prompt implementation:
194 void SetObserver(
195 DevicePermissionsPrompt::Prompt::Observer* observer) override {
196 DevicePermissionsPrompt::Prompt::SetObserver(observer);
198 if (observer) {
199 HidService* service = device::DeviceClient::Get()->GetHidService();
200 if (service && !service_observer_.IsObserving(service)) {
201 service->GetDevices(
202 base::Bind(&HidDevicePermissionsPrompt::OnDevicesEnumerated, this));
203 service_observer_.Add(service);
208 base::string16 GetHeading() const override {
209 return l10n_util::GetSingleOrMultipleStringUTF16(
210 IDS_HID_DEVICE_PERMISSIONS_PROMPT_TITLE, multiple());
213 void Dismissed() override {
214 DevicePermissionsManager* permissions_manager =
215 DevicePermissionsManager::Get(browser_context());
216 std::vector<scoped_refptr<device::HidDeviceInfo>> devices;
217 for (const DeviceInfo* device : devices_) {
218 if (device->granted()) {
219 const HidDeviceInfo* hid_device =
220 static_cast<const HidDeviceInfo*>(device);
221 devices.push_back(hid_device->device());
222 if (permissions_manager) {
223 permissions_manager->AllowHidDevice(extension()->id(),
224 hid_device->device());
228 DCHECK(multiple() || devices.size() <= 1);
229 callback_.Run(devices);
230 callback_.Reset();
233 // device::HidService::Observer implementation:
234 void OnDeviceAdded(scoped_refptr<device::HidDeviceInfo> device) override {
235 if (HasUnprotectedCollections(device) &&
236 (filters_.empty() || HidDeviceFilter::MatchesAny(device, filters_))) {
237 scoped_ptr<DeviceInfo> device_info(new HidDeviceInfo(device));
238 #if defined(OS_CHROMEOS)
239 chromeos::PermissionBrokerClient* client =
240 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
241 DCHECK(client) << "Could not get permission broker client.";
242 device::HidDeviceInfoLinux* linux_device_info =
243 static_cast<device::HidDeviceInfoLinux*>(device.get());
244 client->CheckPathAccess(
245 linux_device_info->device_node(),
246 base::Bind(&HidDevicePermissionsPrompt::AddCheckedDevice, this,
247 base::Passed(&device_info)));
248 #else
249 AddCheckedDevice(device_info.Pass(), true);
250 #endif // defined(OS_CHROMEOS)
254 void OnDeviceRemoved(scoped_refptr<device::HidDeviceInfo> device) override {
255 for (auto it = devices_.begin(); it != devices_.end(); ++it) {
256 const HidDeviceInfo* entry = static_cast<const HidDeviceInfo*>(*it);
257 if (entry->device() == device) {
258 devices_.erase(it);
259 if (observer()) {
260 observer()->OnDevicesChanged();
262 return;
267 void OnDevicesEnumerated(
268 const std::vector<scoped_refptr<device::HidDeviceInfo>>& devices) {
269 for (const auto& device : devices) {
270 OnDeviceAdded(device);
274 bool HasUnprotectedCollections(scoped_refptr<device::HidDeviceInfo> device) {
275 for (const auto& collection : device->collections()) {
276 if (!collection.usage.IsProtected()) {
277 return true;
280 return false;
283 std::vector<HidDeviceFilter> filters_;
284 DevicePermissionsPrompt::HidDevicesCallback callback_;
285 ScopedObserver<HidService, HidService::Observer> service_observer_;
288 } // namespace
290 DevicePermissionsPrompt::Prompt::DeviceInfo::DeviceInfo() {
293 DevicePermissionsPrompt::Prompt::DeviceInfo::~DeviceInfo() {
296 DevicePermissionsPrompt::Prompt::Observer::~Observer() {
299 DevicePermissionsPrompt::Prompt::Prompt(const Extension* extension,
300 content::BrowserContext* context,
301 bool multiple)
302 : extension_(extension), browser_context_(context), multiple_(multiple) {
305 void DevicePermissionsPrompt::Prompt::SetObserver(Observer* observer) {
306 observer_ = observer;
309 base::string16 DevicePermissionsPrompt::Prompt::GetPromptMessage() const {
310 return base::i18n::MessageFormatter::FormatWithNumberedArgs(
311 l10n_util::GetStringUTF16(IDS_DEVICE_PERMISSIONS_PROMPT),
312 multiple_ ? "multiple" : "single", extension_->name());
315 base::string16 DevicePermissionsPrompt::Prompt::GetDeviceName(
316 size_t index) const {
317 DCHECK_LT(index, devices_.size());
318 return devices_[index]->name();
321 base::string16 DevicePermissionsPrompt::Prompt::GetDeviceSerialNumber(
322 size_t index) const {
323 DCHECK_LT(index, devices_.size());
324 return devices_[index]->serial_number();
327 void DevicePermissionsPrompt::Prompt::GrantDevicePermission(size_t index) {
328 DCHECK_LT(index, devices_.size());
329 devices_[index]->set_granted();
332 DevicePermissionsPrompt::Prompt::~Prompt() {
335 void DevicePermissionsPrompt::Prompt::AddCheckedDevice(
336 scoped_ptr<DeviceInfo> device,
337 bool allowed) {
338 if (allowed) {
339 devices_.push_back(device.Pass());
340 if (observer_) {
341 observer_->OnDevicesChanged();
346 DevicePermissionsPrompt::DevicePermissionsPrompt(
347 content::WebContents* web_contents)
348 : web_contents_(web_contents) {
351 DevicePermissionsPrompt::~DevicePermissionsPrompt() {
354 void DevicePermissionsPrompt::AskForUsbDevices(
355 const Extension* extension,
356 content::BrowserContext* context,
357 bool multiple,
358 const std::vector<UsbDeviceFilter>& filters,
359 const UsbDevicesCallback& callback) {
360 prompt_ = new UsbDevicePermissionsPrompt(extension, context, multiple,
361 filters, callback);
362 ShowDialog();
365 void DevicePermissionsPrompt::AskForHidDevices(
366 const Extension* extension,
367 content::BrowserContext* context,
368 bool multiple,
369 const std::vector<HidDeviceFilter>& filters,
370 const HidDevicesCallback& callback) {
371 prompt_ = new HidDevicePermissionsPrompt(extension, context, multiple,
372 filters, callback);
373 ShowDialog();
376 } // namespace extensions