Commit 042073be authored by reillyg's avatar reillyg Committed by Commit bot

Add getUserSelectedDevices to the USB extensions API.

chrome.usb.getUserSelectedDevices allows an app to prompt the user for
one or more USB devices for it to access. This is an alternative to
statically declaring the list of devices an app can access in the
application manifest. This is useful for device classes such as
ADB-enabled Android devices which may have a great number of vendor and
product ID pairs but all match a well-known interface protocol.

If a selected device has a serial number then the app can retain access
to it until explicitly revoked (as is the case for most Android phones)
while access to a device without a serial number is revoked when the app
is unloaded or the device is disconnected.

BUG=346953

Review URL: https://codereview.chromium.org/599303004

Cr-Commit-Position: refs/heads/master@{#300141}
parent a703ee15
// Copyright 2014 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.
#ifndef CHROME_BROWSER_EXTENSIONS_API_CHROME_DEVICE_PERMISSIONS_PROMPT_H_
#define CHROME_BROWSER_EXTENSIONS_API_CHROME_DEVICE_PERMISSIONS_PROMPT_H_
#include "extensions/browser/api/device_permissions_prompt.h"
class ChromeDevicePermissionsPrompt
: public extensions::DevicePermissionsPrompt {
public:
explicit ChromeDevicePermissionsPrompt(content::WebContents* web_contents)
: extensions::DevicePermissionsPrompt(web_contents) {}
virtual ~ChromeDevicePermissionsPrompt() {}
private:
virtual void ShowDialog() override;
};
#endif // CHROME_BROWSER_EXTENSIONS_API_CHROME_DEVICE_PERMISSIONS_PROMPT_H_
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "chrome/browser/extensions/api/chrome_extensions_api_client.h" #include "chrome/browser/extensions/api/chrome_extensions_api_client.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "chrome/browser/extensions/api/chrome_device_permissions_prompt.h"
#include "chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.h" #include "chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.h"
#include "chrome/browser/extensions/api/storage/sync_value_store_cache.h" #include "chrome/browser/extensions/api/storage/sync_value_store_cache.h"
#include "chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.h" #include "chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.h"
...@@ -85,4 +86,10 @@ ChromeExtensionsAPIClient::CreateContentRulesRegistry( ...@@ -85,4 +86,10 @@ ChromeExtensionsAPIClient::CreateContentRulesRegistry(
new ChromeContentRulesRegistry(browser_context, cache_delegate)); new ChromeContentRulesRegistry(browser_context, cache_delegate));
} }
scoped_ptr<DevicePermissionsPrompt>
ChromeExtensionsAPIClient::CreateDevicePermissionsPrompt(
content::WebContents* web_contents) const {
return make_scoped_ptr(new ChromeDevicePermissionsPrompt(web_contents));
}
} // namespace extensions } // namespace extensions
...@@ -39,6 +39,8 @@ class ChromeExtensionsAPIClient : public ExtensionsAPIClient { ...@@ -39,6 +39,8 @@ class ChromeExtensionsAPIClient : public ExtensionsAPIClient {
virtual scoped_refptr<ContentRulesRegistry> CreateContentRulesRegistry( virtual scoped_refptr<ContentRulesRegistry> CreateContentRulesRegistry(
content::BrowserContext* browser_context, content::BrowserContext* browser_context,
RulesCacheDelegate* cache_delegate) const override; RulesCacheDelegate* cache_delegate) const override;
virtual scoped_ptr<DevicePermissionsPrompt> CreateDevicePermissionsPrompt(
content::WebContents* web_contents) const override;
private: private:
DISALLOW_COPY_AND_ASSIGN(ChromeExtensionsAPIClient); DISALLOW_COPY_AND_ASSIGN(ChromeExtensionsAPIClient);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/location.h" #include "base/location.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h" #include "base/thread_task_runner_handle.h"
#include "chrome/browser/extensions/api/chrome_device_permissions_prompt.h"
#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h" #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h" #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h"
#import "chrome/browser/ui/cocoa/extensions/device_permissions_view_controller.h" #import "chrome/browser/ui/cocoa/extensions/device_permissions_view_controller.h"
...@@ -15,18 +16,6 @@ ...@@ -15,18 +16,6 @@
using extensions::DevicePermissionsPrompt; using extensions::DevicePermissionsPrompt;
namespace {
void ShowDevicePermissionsDialogImpl(
content::WebContents* web_contents,
DevicePermissionsPrompt::Delegate* delegate,
scoped_refptr<DevicePermissionsPrompt::Prompt> prompt) {
// These objects will delete themselves when the dialog closes.
new DevicePermissionsDialogController(web_contents, delegate, prompt);
}
} // namespace
DevicePermissionsDialogController::DevicePermissionsDialogController( DevicePermissionsDialogController::DevicePermissionsDialogController(
content::WebContents* web_contents, content::WebContents* web_contents,
DevicePermissionsPrompt::Delegate* delegate, DevicePermissionsPrompt::Delegate* delegate,
...@@ -72,8 +61,7 @@ void DevicePermissionsDialogController::OnConstrainedWindowClosed( ...@@ -72,8 +61,7 @@ void DevicePermissionsDialogController::OnConstrainedWindowClosed(
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
} }
// static void ChromeDevicePermissionsPrompt::ShowDialog() {
DevicePermissionsPrompt::ShowDialogCallback // These objects will delete themselves when the dialog closes.
DevicePermissionsPrompt::GetDefaultShowDialogCallback() { new DevicePermissionsDialogController(web_contents(), delegate(), prompt());
return base::Bind(&ShowDevicePermissionsDialogImpl);
} }
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "chrome/browser/ui/views/extensions/device_permissions_dialog_view.h" #include "chrome/browser/ui/views/extensions/device_permissions_dialog_view.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/api/chrome_device_permissions_prompt.h"
#include "chrome/browser/ui/views/constrained_window_views.h" #include "chrome/browser/ui/views/constrained_window_views.h"
#include "chrome/grit/generated_resources.h" #include "chrome/grit/generated_resources.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
...@@ -21,19 +22,6 @@ ...@@ -21,19 +22,6 @@
using device::UsbDevice; using device::UsbDevice;
using extensions::DevicePermissionsPrompt; using extensions::DevicePermissionsPrompt;
namespace {
void ShowDevicePermissionsDialogImpl(
content::WebContents* web_contents,
DevicePermissionsPrompt::Delegate* delegate,
scoped_refptr<DevicePermissionsPrompt::Prompt> prompt) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
ShowWebModalDialogViews(new DevicePermissionsDialogView(delegate, prompt),
web_contents);
}
} // namespace
class DevicePermissionsTableModel class DevicePermissionsTableModel
: public ui::TableModel, : public ui::TableModel,
public DevicePermissionsPrompt::Prompt::Observer { public DevicePermissionsPrompt::Prompt::Observer {
...@@ -173,8 +161,8 @@ gfx::Size DevicePermissionsDialogView::GetPreferredSize() const { ...@@ -173,8 +161,8 @@ gfx::Size DevicePermissionsDialogView::GetPreferredSize() const {
return gfx::Size(500, 250); return gfx::Size(500, 250);
} }
// static void ChromeDevicePermissionsPrompt::ShowDialog() {
DevicePermissionsPrompt::ShowDialogCallback DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DevicePermissionsPrompt::GetDefaultShowDialogCallback() { ShowWebModalDialogViews(new DevicePermissionsDialogView(delegate(), prompt()),
return base::Bind(&ShowDevicePermissionsDialogImpl); web_contents());
} }
...@@ -141,6 +141,7 @@ ...@@ -141,6 +141,7 @@
'browser/extensions/api/browser/browser_api.h', 'browser/extensions/api/browser/browser_api.h',
'browser/extensions/api/browsing_data/browsing_data_api.cc', 'browser/extensions/api/browsing_data/browsing_data_api.cc',
'browser/extensions/api/browsing_data/browsing_data_api.h', 'browser/extensions/api/browsing_data/browsing_data_api.h',
'browser/extensions/api/chrome_device_permissions_prompt.h',
'browser/extensions/api/chrome_extensions_api_client.cc', 'browser/extensions/api/chrome_extensions_api_client.cc',
'browser/extensions/api/chrome_extensions_api_client.h', 'browser/extensions/api/chrome_extensions_api_client.h',
'browser/extensions/api/cloud_print_private/cloud_print_private_api.cc', 'browser/extensions/api/cloud_print_private/cloud_print_private_api.cc',
......
...@@ -128,6 +128,8 @@ source_set("browser") { ...@@ -128,6 +128,8 @@ source_set("browser") {
"api/declarative_webrequest/webrequest_rules_registry.h", "api/declarative_webrequest/webrequest_rules_registry.h",
"api/device_permissions_manager.cc", "api/device_permissions_manager.cc",
"api/device_permissions_manager.h", "api/device_permissions_manager.h",
"api/device_permissions_prompt.cc",
"api/device_permissions_prompt.h",
"api/dns/dns_api.cc", "api/dns/dns_api.cc",
"api/dns/dns_api.h", "api/dns/dns_api.h",
"api/dns/host_resolver_wrapper.cc", "api/dns/host_resolver_wrapper.cc",
......
...@@ -173,8 +173,7 @@ void DevicePermissionsPrompt::Prompt::SetDevices( ...@@ -173,8 +173,7 @@ void DevicePermissionsPrompt::Prompt::SetDevices(
DevicePermissionsPrompt::DevicePermissionsPrompt( DevicePermissionsPrompt::DevicePermissionsPrompt(
content::WebContents* web_contents) content::WebContents* web_contents)
: web_contents_(web_contents), : web_contents_(web_contents), delegate_(nullptr) {
delegate_(nullptr) {
} }
DevicePermissionsPrompt::~DevicePermissionsPrompt() { DevicePermissionsPrompt::~DevicePermissionsPrompt() {
...@@ -193,7 +192,7 @@ void DevicePermissionsPrompt::AskForUsbDevices( ...@@ -193,7 +192,7 @@ void DevicePermissionsPrompt::AskForUsbDevices(
prompt_->set_filters(filters); prompt_->set_filters(filters);
delegate_ = delegate; delegate_ = delegate;
GetDefaultShowDialogCallback().Run(web_contents_, delegate_, prompt_); ShowDialog();
} }
} // namespace extensions } // namespace extensions
...@@ -124,22 +124,21 @@ class DevicePermissionsPrompt { ...@@ -124,22 +124,21 @@ class DevicePermissionsPrompt {
virtual ~Delegate() {} virtual ~Delegate() {}
}; };
typedef base::Callback<void(content::WebContents*,
DevicePermissionsPrompt::Delegate*,
scoped_refptr<DevicePermissionsPrompt::Prompt>)>
ShowDialogCallback;
static ShowDialogCallback GetDefaultShowDialogCallback();
DevicePermissionsPrompt(content::WebContents* web_contents); DevicePermissionsPrompt(content::WebContents* web_contents);
virtual ~DevicePermissionsPrompt(); virtual ~DevicePermissionsPrompt();
virtual void AskForUsbDevices( void AskForUsbDevices(Delegate* delegate,
Delegate* delegate, const Extension* extension,
const Extension* extension, content::BrowserContext* context,
content::BrowserContext* context, bool multiple,
bool multiple, const std::vector<device::UsbDeviceFilter>& filters);
const std::vector<device::UsbDeviceFilter>& filters);
protected:
virtual void ShowDialog() = 0;
content::WebContents* web_contents() { return web_contents_; }
Delegate* delegate() { return delegate_; }
scoped_refptr<Prompt> prompt() { return prompt_; }
private: private:
// Parent web contents of the device permissions UI dialog. // Parent web contents of the device permissions UI dialog.
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "extensions/browser/api/extensions_api_client.h" #include "extensions/browser/api/extensions_api_client.h"
#include "base/logging.h" #include "base/logging.h"
#include "extensions/browser/api/device_permissions_prompt.h"
#include "extensions/browser/api/web_request/web_request_event_router_delegate.h" #include "extensions/browser/api/web_request/web_request_event_router_delegate.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h" #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h"
#include "extensions/browser/guest_view/web_view/web_view_permission_helper_delegate.h" #include "extensions/browser/guest_view/web_view/web_view_permission_helper_delegate.h"
...@@ -68,4 +69,10 @@ ExtensionsAPIClient::CreateContentRulesRegistry( ...@@ -68,4 +69,10 @@ ExtensionsAPIClient::CreateContentRulesRegistry(
return scoped_refptr<ContentRulesRegistry>(); return scoped_refptr<ContentRulesRegistry>();
} }
scoped_ptr<DevicePermissionsPrompt>
ExtensionsAPIClient::CreateDevicePermissionsPrompt(
content::WebContents* web_contents) const {
return nullptr;
}
} // namespace extensions } // namespace extensions
...@@ -98,6 +98,10 @@ class ExtensionsAPIClient { ...@@ -98,6 +98,10 @@ class ExtensionsAPIClient {
content::BrowserContext* browser_context, content::BrowserContext* browser_context,
RulesCacheDelegate* cache_delegate) const; RulesCacheDelegate* cache_delegate) const;
// Creates a DevicePermissionsPrompt appropriate for the embedder.
virtual scoped_ptr<DevicePermissionsPrompt> CreateDevicePermissionsPrompt(
content::WebContents* web_contents) const;
// NOTE: If this interface gains too many methods (perhaps more than 20) it // NOTE: If this interface gains too many methods (perhaps more than 20) it
// should be split into one interface per API. // should be split into one interface per API.
}; };
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
#include "device/core/device_client.h" #include "device/core/device_client.h"
#include "device/usb/usb_device_handle.h" #include "device/usb/usb_device_handle.h"
#include "device/usb/usb_service.h" #include "device/usb/usb_service.h"
#include "extensions/browser/api/device_permissions_manager.h"
#include "extensions/browser/api/device_permissions_prompt.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/api/usb/usb_device_resource.h" #include "extensions/browser/api/usb/usb_device_resource.h"
#include "extensions/browser/extension_system.h" #include "extensions/browser/extension_system.h"
#include "extensions/common/api/usb.h" #include "extensions/common/api/usb.h"
...@@ -25,6 +28,7 @@ namespace CloseDevice = usb::CloseDevice; ...@@ -25,6 +28,7 @@ namespace CloseDevice = usb::CloseDevice;
namespace ControlTransfer = usb::ControlTransfer; namespace ControlTransfer = usb::ControlTransfer;
namespace FindDevices = usb::FindDevices; namespace FindDevices = usb::FindDevices;
namespace GetDevices = usb::GetDevices; namespace GetDevices = usb::GetDevices;
namespace GetUserSelectedDevices = usb::GetUserSelectedDevices;
namespace InterruptTransfer = usb::InterruptTransfer; namespace InterruptTransfer = usb::InterruptTransfer;
namespace IsochronousTransfer = usb::IsochronousTransfer; namespace IsochronousTransfer = usb::IsochronousTransfer;
namespace GetConfiguration = usb::GetConfiguration; namespace GetConfiguration = usb::GetConfiguration;
...@@ -36,6 +40,20 @@ namespace ResetDevice = usb::ResetDevice; ...@@ -36,6 +40,20 @@ namespace ResetDevice = usb::ResetDevice;
namespace SetInterfaceAlternateSetting = usb::SetInterfaceAlternateSetting; namespace SetInterfaceAlternateSetting = usb::SetInterfaceAlternateSetting;
using content::BrowserThread; using content::BrowserThread;
using device::UsbConfigDescriptor;
using device::UsbDevice;
using device::UsbDeviceFilter;
using device::UsbDeviceHandle;
using device::UsbEndpointDescriptor;
using device::UsbEndpointDirection;
using device::UsbInterfaceDescriptor;
using device::UsbService;
using device::UsbSynchronizationType;
using device::UsbTransferStatus;
using device::UsbTransferType;
using device::UsbUsageType;
using std::string;
using std::vector;
using usb::ConfigDescriptor; using usb::ConfigDescriptor;
using usb::ControlTransferInfo; using usb::ControlTransferInfo;
using usb::ConnectionHandle; using usb::ConnectionHandle;
...@@ -50,18 +68,6 @@ using usb::RequestType; ...@@ -50,18 +68,6 @@ using usb::RequestType;
using usb::SynchronizationType; using usb::SynchronizationType;
using usb::TransferType; using usb::TransferType;
using usb::UsageType; using usb::UsageType;
using device::UsbConfigDescriptor;
using device::UsbDevice;
using device::UsbDeviceFilter;
using device::UsbDeviceHandle;
using device::UsbEndpointDescriptor;
using device::UsbEndpointDirection;
using device::UsbInterfaceDescriptor;
using device::UsbService;
using device::UsbSynchronizationType;
using device::UsbTransferStatus;
using device::UsbTransferType;
using device::UsbUsageType;
typedef std::vector<scoped_refptr<UsbDevice> > DeviceVector; typedef std::vector<scoped_refptr<UsbDevice> > DeviceVector;
typedef scoped_ptr<DeviceVector> ScopedDeviceVector; typedef scoped_ptr<DeviceVector> ScopedDeviceVector;
...@@ -77,9 +83,7 @@ const char kErrorOpen[] = "Failed to open device."; ...@@ -77,9 +83,7 @@ const char kErrorOpen[] = "Failed to open device.";
const char kErrorCancelled[] = "Transfer was cancelled."; const char kErrorCancelled[] = "Transfer was cancelled.";
const char kErrorDisconnect[] = "Device disconnected."; const char kErrorDisconnect[] = "Device disconnected.";
const char kErrorGeneric[] = "Transfer failed."; const char kErrorGeneric[] = "Transfer failed.";
#if !defined(OS_CHROMEOS)
const char kErrorNotSupported[] = "Not supported on this platform."; const char kErrorNotSupported[] = "Not supported on this platform.";
#endif
const char kErrorOverflow[] = "Inbound transfer overflow."; const char kErrorOverflow[] = "Inbound transfer overflow.";
const char kErrorStalled[] = "Transfer stalled."; const char kErrorStalled[] = "Transfer stalled.";
const char kErrorTimeout[] = "Transfer timed out."; const char kErrorTimeout[] = "Transfer timed out.";
...@@ -294,7 +298,7 @@ base::Value* PopulateConnectionHandle(int handle, ...@@ -294,7 +298,7 @@ base::Value* PopulateConnectionHandle(int handle,
return result.ToValue().release(); return result.ToValue().release();
} }
base::Value* PopulateDevice(UsbDevice* device) { base::Value* PopulateDevice(const UsbDevice* device) {
Device result; Device result;
result.device = device->unique_id(); result.device = device->unique_id();
result.vendor_id = device->vendor_id(); result.vendor_id = device->vendor_id();
...@@ -419,6 +423,25 @@ void ConvertConfigDescriptor(const UsbConfigDescriptor& input, ...@@ -419,6 +423,25 @@ void ConvertConfigDescriptor(const UsbConfigDescriptor& input,
} }
} }
void ConvertDeviceFilter(const usb::DeviceFilter& input,
UsbDeviceFilter* output) {
if (input.vendor_id) {
output->SetVendorId(*input.vendor_id);
}
if (input.product_id) {
output->SetProductId(*input.product_id);
}
if (input.interface_class) {
output->SetInterfaceClass(*input.interface_class);
}
if (input.interface_subclass) {
output->SetInterfaceSubclass(*input.interface_subclass);
}
if (input.interface_protocol) {
output->SetInterfaceProtocol(*input.interface_protocol);
}
}
} // namespace } // namespace
namespace extensions { namespace extensions {
...@@ -439,33 +462,21 @@ bool UsbAsyncApiFunction::Respond() { ...@@ -439,33 +462,21 @@ bool UsbAsyncApiFunction::Respond() {
return error_.empty(); return error_.empty();
} }
// static
void UsbAsyncApiFunction::CreateDeviceFilter(const usb::DeviceFilter& input,
UsbDeviceFilter* output) {
if (input.vendor_id) {
output->SetVendorId(*input.vendor_id);
}
if (input.product_id) {
output->SetProductId(*input.product_id);
}
if (input.interface_class) {
output->SetInterfaceClass(*input.interface_class);
}
if (input.interface_subclass) {
output->SetInterfaceSubclass(*input.interface_subclass);
}
if (input.interface_protocol) {
output->SetInterfaceProtocol(*input.interface_protocol);
}
}
bool UsbAsyncApiFunction::HasDevicePermission(scoped_refptr<UsbDevice> device) { bool UsbAsyncApiFunction::HasDevicePermission(scoped_refptr<UsbDevice> device) {
UsbDevicePermission::CheckParam param( UsbDevicePermission::CheckParam param(
device->vendor_id(), device->vendor_id(),
device->product_id(), device->product_id(),
UsbDevicePermissionData::UNSPECIFIED_INTERFACE); UsbDevicePermissionData::UNSPECIFIED_INTERFACE);
return extension()->permissions_data()->CheckAPIPermissionWithParam( if (extension()->permissions_data()->CheckAPIPermissionWithParam(
APIPermission::kUsbDevice, &param); APIPermission::kUsbDevice, &param)) {
return true;
}
if (device_permissions_.get()) {
return device_permissions_->CheckUsbDevice(device);
}
return false;
} }
scoped_refptr<UsbDevice> UsbAsyncApiFunction::GetDeviceOrCompleteWithError( scoped_refptr<UsbDevice> UsbAsyncApiFunction::GetDeviceOrCompleteWithError(
...@@ -657,6 +668,8 @@ UsbGetDevicesFunction::~UsbGetDevicesFunction() { ...@@ -657,6 +668,8 @@ UsbGetDevicesFunction::~UsbGetDevicesFunction() {
bool UsbGetDevicesFunction::Prepare() { bool UsbGetDevicesFunction::Prepare() {
parameters_ = GetDevices::Params::Create(*args_); parameters_ = GetDevices::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(parameters_.get()); EXTENSION_FUNCTION_VALIDATE(parameters_.get());
device_permissions_ = DevicePermissionsManager::Get(browser_context())
->GetForExtension(extension()->id());
return true; return true;
} }
...@@ -665,8 +678,8 @@ void UsbGetDevicesFunction::AsyncWorkStart() { ...@@ -665,8 +678,8 @@ void UsbGetDevicesFunction::AsyncWorkStart() {
if (parameters_->options.filters) { if (parameters_->options.filters) {
filters.resize(parameters_->options.filters->size()); filters.resize(parameters_->options.filters->size());
for (size_t i = 0; i < parameters_->options.filters->size(); ++i) { for (size_t i = 0; i < parameters_->options.filters->size(); ++i) {
CreateDeviceFilter(*parameters_->options.filters->at(i).get(), ConvertDeviceFilter(*parameters_->options.filters->at(i).get(),
&filters[i]); &filters[i]);
} }
} }
if (parameters_->options.vendor_id) { if (parameters_->options.vendor_id) {
...@@ -699,6 +712,59 @@ void UsbGetDevicesFunction::AsyncWorkStart() { ...@@ -699,6 +712,59 @@ void UsbGetDevicesFunction::AsyncWorkStart() {
AsyncWorkCompleted(); AsyncWorkCompleted();
} }
UsbGetUserSelectedDevicesFunction::UsbGetUserSelectedDevicesFunction() {
}
UsbGetUserSelectedDevicesFunction::~UsbGetUserSelectedDevicesFunction() {
}
AsyncApiFunction::ResponseAction UsbGetUserSelectedDevicesFunction::Run() {
scoped_ptr<extensions::core_api::usb::GetUserSelectedDevices::Params>
parameters = GetUserSelectedDevices::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(parameters.get());
if (!user_gesture()) {
return RespondNow(OneArgument(new base::ListValue()));
}
bool multiple = false;
if (parameters->options.multiple) {
multiple = *parameters->options.multiple;
}
std::vector<UsbDeviceFilter> filters;
if (parameters->options.filters) {
filters.resize(parameters->options.filters->size());
for (size_t i = 0; i < parameters->options.filters->size(); ++i) {
ConvertDeviceFilter(*parameters->options.filters->at(i).get(),
&filters[i]);
}
}
prompt_ = ExtensionsAPIClient::Get()->CreateDevicePermissionsPrompt(
GetAssociatedWebContents());
if (!prompt_) {
return RespondNow(Error(kErrorNotSupported));
}
AddRef();
prompt_->AskForUsbDevices(
this, extension(), browser_context(), multiple, filters);
return RespondLater();
}
void UsbGetUserSelectedDevicesFunction::OnUsbDevicesChosen(
const std::vector<scoped_refptr<UsbDevice>>& devices) {
scoped_ptr<base::ListValue> result(new base::ListValue());
for (const auto& device : devices) {
result->Append(PopulateDevice(device.get()));
}
SetResult(result.release());
SendResponse(true);
Release();
}
UsbRequestAccessFunction::UsbRequestAccessFunction() { UsbRequestAccessFunction::UsbRequestAccessFunction() {
} }
...@@ -708,6 +774,8 @@ UsbRequestAccessFunction::~UsbRequestAccessFunction() { ...@@ -708,6 +774,8 @@ UsbRequestAccessFunction::~UsbRequestAccessFunction() {
bool UsbRequestAccessFunction::Prepare() { bool UsbRequestAccessFunction::Prepare() {
parameters_ = RequestAccess::Params::Create(*args_); parameters_ = RequestAccess::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(parameters_.get()); EXTENSION_FUNCTION_VALIDATE(parameters_.get());
device_permissions_ = DevicePermissionsManager::Get(browser_context())
->GetForExtension(extension()->id());
return true; return true;
} }
...@@ -741,6 +809,8 @@ UsbOpenDeviceFunction::~UsbOpenDeviceFunction() { ...@@ -741,6 +809,8 @@ UsbOpenDeviceFunction::~UsbOpenDeviceFunction() {
bool UsbOpenDeviceFunction::Prepare() { bool UsbOpenDeviceFunction::Prepare() {
parameters_ = OpenDevice::Params::Create(*args_); parameters_ = OpenDevice::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(parameters_.get()); EXTENSION_FUNCTION_VALIDATE(parameters_.get());
device_permissions_ = DevicePermissionsManager::Get(browser_context())
->GetForExtension(extension()->id());
return true; return true;
} }
......
...@@ -15,11 +15,13 @@ ...@@ -15,11 +15,13 @@
#include "device/usb/usb_device_handle.h" #include "device/usb/usb_device_handle.h"
#include "extensions/browser/api/api_resource_manager.h" #include "extensions/browser/api/api_resource_manager.h"
#include "extensions/browser/api/async_api_function.h" #include "extensions/browser/api/async_api_function.h"
#include "extensions/browser/api/device_permissions_prompt.h"
#include "extensions/common/api/usb.h" #include "extensions/common/api/usb.h"
#include "net/base/io_buffer.h" #include "net/base/io_buffer.h"
namespace extensions { namespace extensions {
class DevicePermissions;
class UsbDeviceResource; class UsbDeviceResource;
class UsbAsyncApiFunction : public AsyncApiFunction { class UsbAsyncApiFunction : public AsyncApiFunction {
...@@ -32,15 +34,9 @@ class UsbAsyncApiFunction : public AsyncApiFunction { ...@@ -32,15 +34,9 @@ class UsbAsyncApiFunction : public AsyncApiFunction {
virtual bool PrePrepare() override; virtual bool PrePrepare() override;
virtual bool Respond() override; virtual bool Respond() override;
static void CreateDeviceFilter(
const extensions::core_api::usb::DeviceFilter& input,
device::UsbDeviceFilter* output);
bool HasDevicePermission(scoped_refptr<device::UsbDevice> device); bool HasDevicePermission(scoped_refptr<device::UsbDevice> device);
scoped_refptr<device::UsbDevice> GetDeviceOrCompleteWithError( scoped_refptr<device::UsbDevice> GetDeviceOrCompleteWithError(
const extensions::core_api::usb::Device& input_device); const extensions::core_api::usb::Device& input_device);
scoped_refptr<device::UsbDeviceHandle> GetDeviceHandleOrCompleteWithError( scoped_refptr<device::UsbDeviceHandle> GetDeviceHandleOrCompleteWithError(
const extensions::core_api::usb::ConnectionHandle& input_device_handle); const extensions::core_api::usb::ConnectionHandle& input_device_handle);
...@@ -49,6 +45,7 @@ class UsbAsyncApiFunction : public AsyncApiFunction { ...@@ -49,6 +45,7 @@ class UsbAsyncApiFunction : public AsyncApiFunction {
void CompleteWithError(const std::string& error); void CompleteWithError(const std::string& error);
ApiResourceManager<UsbDeviceResource>* manager_; ApiResourceManager<UsbDeviceResource>* manager_;
scoped_ptr<DevicePermissions> device_permissions_;
}; };
class UsbAsyncApiTransferFunction : public UsbAsyncApiFunction { class UsbAsyncApiTransferFunction : public UsbAsyncApiFunction {
...@@ -103,12 +100,32 @@ class UsbGetDevicesFunction : public UsbAsyncApiFunction { ...@@ -103,12 +100,32 @@ class UsbGetDevicesFunction : public UsbAsyncApiFunction {
virtual ~UsbGetDevicesFunction(); virtual ~UsbGetDevicesFunction();
private: private:
void EnumerationCompletedFileThread(
scoped_ptr<std::vector<scoped_refptr<device::UsbDevice> > > devices);
scoped_ptr<extensions::core_api::usb::GetDevices::Params> parameters_; scoped_ptr<extensions::core_api::usb::GetDevices::Params> parameters_;
}; };
class UsbGetUserSelectedDevicesFunction
: public UIThreadExtensionFunction,
public DevicePermissionsPrompt::Delegate {
public:
DECLARE_EXTENSION_FUNCTION("usb.getUserSelectedDevices",
USB_GETUSERSELECTEDDEVICES)
UsbGetUserSelectedDevicesFunction();
protected:
virtual ~UsbGetUserSelectedDevicesFunction();
virtual ResponseAction Run() override;
private:
virtual void OnUsbDevicesChosen(
const std::vector<scoped_refptr<device::UsbDevice>>& devices) override;
scoped_ptr<DevicePermissionsPrompt> prompt_;
std::vector<uint32> device_ids_;
std::vector<scoped_refptr<device::UsbDevice>> devices_;
std::vector<base::string16> serial_numbers_;
};
class UsbRequestAccessFunction : public UsbAsyncApiFunction { class UsbRequestAccessFunction : public UsbAsyncApiFunction {
public: public:
DECLARE_EXTENSION_FUNCTION("usb.requestAccess", USB_REQUESTACCESS) DECLARE_EXTENSION_FUNCTION("usb.requestAccess", USB_REQUESTACCESS)
......
...@@ -965,6 +965,7 @@ enum HistogramValue { ...@@ -965,6 +965,7 @@ enum HistogramValue {
COPRESENCESOCKET_DISCONNECT, COPRESENCESOCKET_DISCONNECT,
BOOKMARKMANAGERPRIVATE_SETVERSION, BOOKMARKMANAGERPRIVATE_SETVERSION,
FILESYSTEMPROVIDER_NOTIFY, FILESYSTEMPROVIDER_NOTIFY,
USB_GETUSERSELECTEDDEVICES,
// Last entry: Add new entries above and ensure to update // Last entry: Add new entries above and ensure to update
// tools/metrics/histograms/histograms.xml. // tools/metrics/histograms/histograms.xml.
ENUM_BOUNDARY ENUM_BOUNDARY
......
...@@ -289,6 +289,11 @@ ...@@ -289,6 +289,11 @@
"dependencies": ["permission:usb"], "dependencies": ["permission:usb"],
"contexts": ["blessed_extension"] "contexts": ["blessed_extension"]
}, },
"usb.getUserSelectedDevices": {
"channel": "dev",
"dependencies": ["permission:usb"],
"contexts": ["blessed_extension"]
},
"webRequest": { "webRequest": {
"dependencies": ["permission:webRequest"], "dependencies": ["permission:webRequest"],
"contexts": ["blessed_extension"] "contexts": ["blessed_extension"]
......
...@@ -186,7 +186,7 @@ namespace usb { ...@@ -186,7 +186,7 @@ namespace usb {
// will return all devices the app has permission for. // will return all devices the app has permission for.
DeviceFilter[]? filters; DeviceFilter[]? filters;
}; };
dictionary EnumerateDevicesAndRequestAccessOptions { dictionary EnumerateDevicesAndRequestAccessOptions {
// The device vendor ID. // The device vendor ID.
long vendorId; long vendorId;
...@@ -197,6 +197,14 @@ namespace usb { ...@@ -197,6 +197,14 @@ namespace usb {
long? interfaceId; long? interfaceId;
}; };
dictionary DevicePromptOptions {
// Allow the user to select multiple devices.
boolean? multiple;
// Filter the list of devices presented to the user. If multiple filters are
// provided devices matching any filter will be displayed.
DeviceFilter[]? filters;
};
callback VoidCallback = void (); callback VoidCallback = void ();
callback GetDevicesCallback = void (Device[] devices); callback GetDevicesCallback = void (Device[] devices);
callback RequestAccessCallback = void (boolean success); callback RequestAccessCallback = void (boolean success);
...@@ -214,6 +222,16 @@ namespace usb { ...@@ -214,6 +222,16 @@ namespace usb {
static void getDevices(EnumerateDevicesOptions options, static void getDevices(EnumerateDevicesOptions options,
GetDevicesCallback callback); GetDevicesCallback callback);
// Presents a device picker to the user and returns the $(ref:Device)s
// selected.
// If the user cancels the picker devices will be empty. A user gesture
// is required for the dialog to display. Without a user gesture, the
// callback will run as though the user cancelled.
// |options|: Configuration of the device picker dialog box.
// |callback|: Invoked with a list of chosen $(ref:Device)s.
static void getUserSelectedDevices(DevicePromptOptions options,
GetDevicesCallback callback);
// Requests access from the permission broker to a device claimed by // Requests access from the permission broker to a device claimed by
// ChromeOS if the given interface on the device is not claimed. // ChromeOS if the given interface on the device is not claimed.
// //
......
...@@ -42998,6 +42998,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. ...@@ -42998,6 +42998,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="904" label="COPRESENCESOCKET_DISCONNECT"/> <int value="904" label="COPRESENCESOCKET_DISCONNECT"/>
<int value="905" label="BOOKMARKMANAGERPRIVATE_SETVERSION"/> <int value="905" label="BOOKMARKMANAGERPRIVATE_SETVERSION"/>
<int value="906" label="FILESYSTEMPROVIDER_NOTIFY"/> <int value="906" label="FILESYSTEMPROVIDER_NOTIFY"/>
<int value="907" label="USB_GETUSERSELECTEDDEVICES"/>
</enum> </enum>
<enum name="ExtensionInstallCause" type="int"> <enum name="ExtensionInstallCause" type="int">
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment