Commit 43a9462c authored by reillyg's avatar reillyg Committed by Commit bot

Prompt for granting permission to access USB devices.

extensions::DevicePermissionsPrompt may be implemented by an embedder
of the extensions system to provide a way to prompt the user for
permission to access a set of USB devices. This is expandable to other
device types. Implementations for Chrome using the Views framework
(for Chrome OS, Linux and Windows) and Cocoa (for OS X) are provided
in this change.

Screenshots are attached to bug 420317.

BUG=352720,420317

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

Cr-Commit-Position: refs/heads/master@{#299983}
parent 3b177397
...@@ -14782,6 +14782,17 @@ Do you accept? ...@@ -14782,6 +14782,17 @@ Do you accept?
<message name="IDS_FLAGS_ENABLE_MESSAGE_CENTER_ALWAYS_SCROLL_UP_UPON_REMOVAL_DESCRIPTION" desc="Description of about:flags option for message center always scroll up experiment."> <message name="IDS_FLAGS_ENABLE_MESSAGE_CENTER_ALWAYS_SCROLL_UP_UPON_REMOVAL_DESCRIPTION" desc="Description of about:flags option for message center always scroll up experiment.">
Enables experiment that message center always scroll up when a notification is removed. Enables experiment that message center always scroll up when a notification is removed.
</message> </message>
<!-- Device permissions dialog strings. -->
<message name="IDS_DEVICE_PERMISSIONS_DIALOG_DEVICE_NAME_COLUMN" desc="Label for the table column displaying the name of a device.">
Device Name
</message>
<message name="IDS_DEVICE_PERMISSIONS_DIALOG_SERIAL_NUMBER_COLUMN" desc="Label for the table column displaying the serial number of a device.">
Serial Number
</message>
<message name="IDS_DEVICE_PERMISSIONS_DIALOG_SELECT" desc="Button confirming the devices selected for access by the app.">
Select
</message>
</messages> </messages>
</release> </release>
</grit> </grit>
This diff is collapsed.
// 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_UI_COCOA_EXTENSIONS_DEVICE_PERMISSIONS_DIALOG_CONTROLER_H_
#define CHROME_BROWSER_UI_COCOA_EXTENSIONS_DEVICE_PERMISSIONS_DIALOG_CONTROLER_H_
#import <Cocoa/Cocoa.h>
#include "base/mac/scoped_nsobject.h"
#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
#include "extensions/browser/api/device_permissions_prompt.h"
namespace content {
class WebContents;
}
@class DevicePermissionsViewController;
// Displays an device permissions selector prompt as a modal sheet constrained
// to the window/tab displaying the given web contents.
class DevicePermissionsDialogController
: public extensions::DevicePermissionsPrompt::Delegate,
public extensions::DevicePermissionsPrompt::Prompt::Observer,
public ConstrainedWindowMacDelegate {
public:
DevicePermissionsDialogController(
content::WebContents* web_contents,
extensions::DevicePermissionsPrompt::Delegate* delegate,
scoped_refptr<extensions::DevicePermissionsPrompt::Prompt> prompt);
virtual ~DevicePermissionsDialogController();
// extensions::DevicePermissionsPrompt::Delegate implementation.
virtual void OnUsbDevicesChosen(
const std::vector<scoped_refptr<device::UsbDevice>>& devices) override;
// extensions::DevicePermissionsPrompt::Prompt::Observer implementation.
virtual void OnDevicesChanged() override;
// ConstrainedWindowMacDelegate implementation.
virtual void OnConstrainedWindowClosed(ConstrainedWindowMac* window) override;
ConstrainedWindowMac* constrained_window() const {
return constrained_window_.get();
}
DevicePermissionsViewController* view_controller() const {
return view_controller_;
}
private:
extensions::DevicePermissionsPrompt::Delegate* delegate_;
scoped_refptr<extensions::DevicePermissionsPrompt::Prompt> prompt_;
base::scoped_nsobject<DevicePermissionsViewController> view_controller_;
scoped_ptr<ConstrainedWindowMac> constrained_window_;
};
#endif // CHROME_BROWSER_UI_COCOA_EXTENSIONS_DEVICE_PERMISSIONS_DIALOG_CONTROLER_H_
// 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.
#import "chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.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/extensions/device_permissions_view_controller.h"
#include "device/usb/usb_device.h"
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(
content::WebContents* web_contents,
DevicePermissionsPrompt::Delegate* delegate,
scoped_refptr<DevicePermissionsPrompt::Prompt> prompt)
: delegate_(delegate), prompt_(prompt) {
view_controller_.reset(
[[DevicePermissionsViewController alloc] initWithDelegate:this
prompt:prompt]);
prompt_->SetObserver(this);
base::scoped_nsobject<NSWindow> window([[ConstrainedWindowCustomWindow alloc]
initWithContentRect:[[view_controller_ view] bounds]]);
[[window contentView] addSubview:[view_controller_ view]];
base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
[[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window]);
constrained_window_.reset(
new ConstrainedWindowMac(this, web_contents, sheet));
}
DevicePermissionsDialogController::~DevicePermissionsDialogController() {
prompt_->SetObserver(nullptr);
}
void DevicePermissionsDialogController::OnUsbDevicesChosen(
const std::vector<scoped_refptr<device::UsbDevice>>& devices) {
delegate_->OnUsbDevicesChosen(devices);
delegate_ = nullptr;
constrained_window_->CloseWebContentsModalDialog();
}
void DevicePermissionsDialogController::OnDevicesChanged() {
[view_controller_ devicesChanged];
}
void DevicePermissionsDialogController::OnConstrainedWindowClosed(
ConstrainedWindowMac* window) {
if (delegate_) {
std::vector<scoped_refptr<device::UsbDevice>> empty;
delegate_->OnUsbDevicesChosen(empty);
}
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
}
// static
DevicePermissionsPrompt::ShowDialogCallback
DevicePermissionsPrompt::GetDefaultShowDialogCallback() {
return base::Bind(&ShowDevicePermissionsDialogImpl);
}
// 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_UI_COCOA_EXTENSIONS_DEVICE_PERMISSIONS_VIEW_CONTROLLER_H_
#define CHROME_BROWSER_UI_COCOA_EXTENSIONS_DEVICE_PERMISSIONS_VIEW_CONTROLLER_H_
#import <Cocoa/Cocoa.h>
#include "base/mac/scoped_nsobject.h"
#include "extensions/browser/api/device_permissions_prompt.h"
// Displays the device permissions prompt, and notifies the
// DevicePermissionsPrompt::Delegate of success or failure.
@interface DevicePermissionsViewController
: NSViewController<NSTableViewDataSource, NSTableViewDelegate> {
IBOutlet NSTextField* titleField_;
IBOutlet NSTextField* promptField_;
IBOutlet NSButton* cancelButton_;
IBOutlet NSButton* okButton_;
IBOutlet NSTableView* tableView_;
IBOutlet NSTableColumn* deviceNameColumn_;
IBOutlet NSTableColumn* serialNumberColumn_;
IBOutlet NSScrollView* scrollView_;
extensions::DevicePermissionsPrompt::Delegate* delegate_; // weak
scoped_refptr<extensions::DevicePermissionsPrompt::Prompt> prompt_;
}
- (id)initWithDelegate:(extensions::DevicePermissionsPrompt::Delegate*)delegate
prompt:
(scoped_refptr<extensions::DevicePermissionsPrompt::Prompt>)
prompt;
- (IBAction)cancel:(id)sender;
- (IBAction)ok:(id)sender;
- (void)devicesChanged;
@end
#endif // CHROME_BROWSER_UI_COCOA_EXTENSIONS_DEVICE_PERMISSIONS_VIEW_CONTROLLER_H_
// 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.
#import "base/mac/bundle_locations.h"
#include "base/strings/sys_string_conversions.h"
#import "chrome/browser/ui/cocoa/extensions/device_permissions_view_controller.h"
#include "chrome/grit/generated_resources.h"
#include "device/usb/usb_device.h"
#import "ui/base/l10n/l10n_util_mac.h"
using extensions::DevicePermissionsPrompt;
@implementation DevicePermissionsViewController
- (id)initWithDelegate:(DevicePermissionsPrompt::Delegate*)delegate
prompt:(scoped_refptr<DevicePermissionsPrompt::Prompt>)prompt {
if ((self = [super initWithNibName:@"DevicePermissionsPrompt"
bundle:base::mac::FrameworkBundle()])) {
delegate_ = delegate;
prompt_ = prompt;
}
return self;
}
- (IBAction)cancel:(id)sender {
std::vector<scoped_refptr<device::UsbDevice>> empty;
delegate_->OnUsbDevicesChosen(empty);
}
- (IBAction)ok:(id)sender {
__block std::vector<scoped_refptr<device::UsbDevice>> devices;
[[tableView_ selectedRowIndexes]
enumerateIndexesUsingBlock:^(NSUInteger index, BOOL* stop) {
prompt_->GrantDevicePermission(index);
devices.push_back(prompt_->GetDevice(index));
}];
delegate_->OnUsbDevicesChosen(devices);
}
- (void)devicesChanged {
[tableView_ reloadData];
}
- (void)awakeFromNib {
[titleField_ setStringValue:base::SysUTF16ToNSString(prompt_->GetHeading())];
[promptField_
setStringValue:base::SysUTF16ToNSString(prompt_->GetPromptMessage())];
[tableView_ setAllowsMultipleSelection:prompt_->multiple()];
[[deviceNameColumn_ headerCell]
setStringValue:l10n_util::GetNSString(
IDS_DEVICE_PERMISSIONS_DIALOG_DEVICE_NAME_COLUMN)];
[[serialNumberColumn_ headerCell]
setStringValue:l10n_util::GetNSString(
IDS_DEVICE_PERMISSIONS_DIALOG_SERIAL_NUMBER_COLUMN)];
[okButton_
setTitle:l10n_util::GetNSString(IDS_DEVICE_PERMISSIONS_DIALOG_SELECT)];
[cancelButton_ setTitle:l10n_util::GetNSString(IDS_CANCEL)];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView {
DCHECK_EQ(tableView_, tableView);
return prompt_->GetDeviceCount();
}
- (id)tableView:(NSTableView*)tableView
objectValueForTableColumn:(NSTableColumn*)tableColumn
row:(NSInteger)rowIndex {
if (tableColumn == deviceNameColumn_) {
return base::SysUTF16ToNSString(prompt_->GetDeviceName(rowIndex));
} else if (tableColumn == serialNumberColumn_) {
return base::SysUTF16ToNSString(prompt_->GetDeviceSerialNumber(rowIndex));
} else {
NOTREACHED();
return @"";
}
}
@end
// 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.
#include "chrome/browser/ui/views/extensions/device_permissions_dialog_view.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/views/constrained_window_views.h"
#include "chrome/grit/generated_resources.h"
#include "content/public/browser/browser_thread.h"
#include "device/usb/usb_device.h"
#include "extensions/common/extension.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/table_model.h"
#include "ui/base/models/table_model_observer.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/table/table_view.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/layout_constants.h"
using device::UsbDevice;
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
: public ui::TableModel,
public DevicePermissionsPrompt::Prompt::Observer {
public:
explicit DevicePermissionsTableModel(
scoped_refptr<DevicePermissionsPrompt::Prompt> prompt)
: prompt_(prompt) {
prompt_->SetObserver(this);
}
virtual ~DevicePermissionsTableModel() { prompt_->SetObserver(nullptr); }
// ui::TableModel
virtual int RowCount() override;
virtual base::string16 GetText(int row, int column) override;
virtual base::string16 GetTooltip(int row) override;
virtual void SetObserver(ui::TableModelObserver* observer) override;
// extensions::DevicePermissionsPrompt::Prompt::Observer
virtual void OnDevicesChanged() override;
private:
scoped_refptr<DevicePermissionsPrompt::Prompt> prompt_;
ui::TableModelObserver* observer_;
};
int DevicePermissionsTableModel::RowCount() {
return prompt_->GetDeviceCount();
}
base::string16 DevicePermissionsTableModel::GetText(int row, int col_id) {
switch (col_id) {
case IDS_DEVICE_PERMISSIONS_DIALOG_DEVICE_NAME_COLUMN:
return prompt_->GetDeviceName(row);
case IDS_DEVICE_PERMISSIONS_DIALOG_SERIAL_NUMBER_COLUMN:
return prompt_->GetDeviceSerialNumber(row);
default:
NOTREACHED();
return base::string16();
}
}
base::string16 DevicePermissionsTableModel::GetTooltip(int row) {
return prompt_->GetDeviceTooltip(row);
}
void DevicePermissionsTableModel::SetObserver(
ui::TableModelObserver* observer) {
observer_ = observer;
}
void DevicePermissionsTableModel::OnDevicesChanged() {
if (observer_) {
observer_->OnModelChanged();
}
}
DevicePermissionsDialogView::DevicePermissionsDialogView(
DevicePermissionsPrompt::Delegate* delegate,
scoped_refptr<DevicePermissionsPrompt::Prompt> prompt)
: delegate_(delegate), prompt_(prompt) {
views::BoxLayout* layout =
new views::BoxLayout(views::BoxLayout::kVertical,
views::kButtonHEdgeMarginNew,
0,
views::kRelatedControlVerticalSpacing);
SetLayoutManager(layout);
views::Label* label = new views::Label(prompt_->GetPromptMessage());
label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
AddChildView(label);
std::vector<ui::TableColumn> table_columns;
table_columns.push_back(
ui::TableColumn(IDS_DEVICE_PERMISSIONS_DIALOG_DEVICE_NAME_COLUMN,
ui::TableColumn::LEFT,
-1,
0.8f));
table_columns.back().title = l10n_util::GetStringUTF16(
IDS_DEVICE_PERMISSIONS_DIALOG_DEVICE_NAME_COLUMN);
table_columns.push_back(
ui::TableColumn(IDS_DEVICE_PERMISSIONS_DIALOG_SERIAL_NUMBER_COLUMN,
ui::TableColumn::LEFT,
-1,
0.2f));
table_columns.back().title = l10n_util::GetStringUTF16(
IDS_DEVICE_PERMISSIONS_DIALOG_SERIAL_NUMBER_COLUMN);
table_model_.reset(new DevicePermissionsTableModel(prompt_));
table_view_ = new views::TableView(table_model_.get(),
table_columns,
views::TEXT_ONLY,
!prompt_->multiple());
views::View* table_parent = table_view_->CreateParentIfNecessary();
AddChildView(table_parent);
layout->SetFlexForView(table_parent, 1);
}
DevicePermissionsDialogView::~DevicePermissionsDialogView() {
RemoveAllChildViews(true);
}
bool DevicePermissionsDialogView::Cancel() {
std::vector<scoped_refptr<UsbDevice>> empty;
delegate_->OnUsbDevicesChosen(empty);
return true;
}
bool DevicePermissionsDialogView::Accept() {
std::vector<scoped_refptr<UsbDevice>> devices;
for (int index : table_view_->selection_model().selected_indices()) {
prompt_->GrantDevicePermission(index);
devices.push_back(prompt_->GetDevice(index));
}
delegate_->OnUsbDevicesChosen(devices);
return true;
}
base::string16 DevicePermissionsDialogView::GetDialogButtonLabel(
ui::DialogButton button) const {
if (button == ui::DIALOG_BUTTON_OK) {
return l10n_util::GetStringUTF16(IDS_DEVICE_PERMISSIONS_DIALOG_SELECT);
}
return views::DialogDelegateView::GetDialogButtonLabel(button);
}
ui::ModalType DevicePermissionsDialogView::GetModalType() const {
return ui::MODAL_TYPE_CHILD;
}
base::string16 DevicePermissionsDialogView::GetWindowTitle() const {
return prompt_->GetHeading();
}
gfx::Size DevicePermissionsDialogView::GetPreferredSize() const {
return gfx::Size(500, 250);
}
// static
DevicePermissionsPrompt::ShowDialogCallback
DevicePermissionsPrompt::GetDefaultShowDialogCallback() {
return base::Bind(&ShowDevicePermissionsDialogImpl);
}
// 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_UI_VIEWS_EXTENSIONS_DEVICE_PERMISSIONS_DIALOG_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_DEVICE_PERMISSIONS_DIALOG_VIEW_H_
#include "extensions/browser/api/device_permissions_prompt.h"
#include "ui/views/window/dialog_delegate.h"
namespace views {
class TableView;
}
class DevicePermissionsTableModel;
// Displays a device permissions selector prompt as a modal dialog constrained
// to the window/tab displaying the given web contents.
class DevicePermissionsDialogView : public views::DialogDelegateView {
public:
DevicePermissionsDialogView(
extensions::DevicePermissionsPrompt::Delegate* delegate,
scoped_refptr<extensions::DevicePermissionsPrompt::Prompt> prompt);
virtual ~DevicePermissionsDialogView();
// Overriding views::DialogDelegate.
virtual bool Cancel() override;
virtual bool Accept() override;
// Overriding views::DialogModel.
virtual base::string16 GetDialogButtonLabel(
ui::DialogButton button) const override;
// Overriding views::WidgetDelegate.
virtual ui::ModalType GetModalType() const override;
virtual base::string16 GetWindowTitle() const override;
// Overriding views::View
virtual gfx::Size GetPreferredSize() const override;
private:
extensions::DevicePermissionsPrompt::Delegate* delegate_;
scoped_refptr<extensions::DevicePermissionsPrompt::Prompt> prompt_;
// Displays the list of devices.
views::TableView* table_view_;
scoped_ptr<DevicePermissionsTableModel> table_model_;
};
#endif // CHROME_BROWSER_UI_VIEWS_EXTENSIONS_DEVICE_PERMISSIONS_DIALOG_VIEW_H_
...@@ -422,6 +422,10 @@ ...@@ -422,6 +422,10 @@
'browser/ui/cocoa/extensions/browser_actions_container_view.mm', 'browser/ui/cocoa/extensions/browser_actions_container_view.mm',
'browser/ui/cocoa/extensions/browser_actions_controller.h', 'browser/ui/cocoa/extensions/browser_actions_controller.h',
'browser/ui/cocoa/extensions/browser_actions_controller.mm', 'browser/ui/cocoa/extensions/browser_actions_controller.mm',
'browser/ui/cocoa/extensions/device_permissions_dialog_controller.h',
'browser/ui/cocoa/extensions/device_permissions_dialog_controller.mm',
'browser/ui/cocoa/extensions/device_permissions_view_controller.h',
'browser/ui/cocoa/extensions/device_permissions_view_controller.mm',
'browser/ui/cocoa/extensions/extension_action_context_menu_controller.h', 'browser/ui/cocoa/extensions/extension_action_context_menu_controller.h',
'browser/ui/cocoa/extensions/extension_action_context_menu_controller.mm', 'browser/ui/cocoa/extensions/extension_action_context_menu_controller.mm',
'browser/ui/cocoa/extensions/extension_install_dialog_controller.h', 'browser/ui/cocoa/extensions/extension_install_dialog_controller.h',
...@@ -1997,6 +2001,8 @@ ...@@ -1997,6 +2001,8 @@
'browser/ui/views/extensions/media_galleries_dialog_views.h', 'browser/ui/views/extensions/media_galleries_dialog_views.h',
'browser/ui/views/extensions/media_gallery_checkbox_view.cc', 'browser/ui/views/extensions/media_gallery_checkbox_view.cc',
'browser/ui/views/extensions/media_gallery_checkbox_view.h', 'browser/ui/views/extensions/media_gallery_checkbox_view.h',
'browser/ui/views/extensions/device_permissions_dialog_view.cc',
'browser/ui/views/extensions/device_permissions_dialog_view.h',
'browser/ui/views/find_bar_host_aura.cc', 'browser/ui/views/find_bar_host_aura.cc',
'browser/ui/views/find_bar_host.cc', 'browser/ui/views/find_bar_host.cc',
'browser/ui/views/find_bar_host.h', 'browser/ui/views/find_bar_host.h',
......
...@@ -129,6 +129,8 @@ ...@@ -129,6 +129,8 @@
'browser/ui/cocoa/constrained_window/constrained_window_custom_window.mm', 'browser/ui/cocoa/constrained_window/constrained_window_custom_window.mm',
'browser/ui/cocoa/extensions/browser_actions_container_view.h', 'browser/ui/cocoa/extensions/browser_actions_container_view.h',
'browser/ui/cocoa/extensions/browser_actions_container_view.mm', 'browser/ui/cocoa/extensions/browser_actions_container_view.mm',
'browser/ui/cocoa/extensions/device_permissions_view_controller.h',
'browser/ui/cocoa/extensions/device_permissions_view_controller.mm',
'browser/ui/cocoa/extensions/extension_install_dialog_controller.h', 'browser/ui/cocoa/extensions/extension_install_dialog_controller.h',
'browser/ui/cocoa/extensions/extension_install_dialog_controller.mm', 'browser/ui/cocoa/extensions/extension_install_dialog_controller.mm',
'browser/ui/cocoa/extensions/extension_install_view_controller.h', 'browser/ui/cocoa/extensions/extension_install_view_controller.h',
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
'app/nibs/AboutIPC.xib', 'app/nibs/AboutIPC.xib',
'app/nibs/ActionBoxMenuItem.xib', 'app/nibs/ActionBoxMenuItem.xib',
'app/nibs/BookmarkBarFolderWindow.xib', 'app/nibs/BookmarkBarFolderWindow.xib',
'app/nibs/DevicePermissionsPrompt.xib',
'app/nibs/ExtensionInstalledBubbleBundle.xib', 'app/nibs/ExtensionInstalledBubbleBundle.xib',
'app/nibs/FindBar.xib', 'app/nibs/FindBar.xib',
'app/nibs/GlobalErrorBubble.xib', 'app/nibs/GlobalErrorBubble.xib',
......
// 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.
#include "extensions/browser/api/device_permissions_prompt.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "device/core/device_client.h"
#include "device/usb/usb_device.h"
#include "device/usb/usb_device_filter.h"
#include "device/usb/usb_ids.h"
#include "device/usb/usb_service.h"
#include "extensions/browser/api/device_permissions_manager.h"
#include "extensions/common/extension.h"
#include "extensions/strings/grit/extensions_strings.h"
#include "ui/base/l10n/l10n_util.h"
namespace extensions {
using device::UsbDevice;
using device::UsbDeviceFilter;
using device::UsbService;
DevicePermissionsPrompt::Prompt::DeviceInfo::DeviceInfo(
scoped_refptr<UsbDevice> device,
const base::string16& name,
const base::string16& serial_number,
const base::string16& tooltip)
: device(device),
name(name),
serial_number(serial_number),
tooltip(tooltip) {
}
DevicePermissionsPrompt::Prompt::DeviceInfo::~DeviceInfo() {
}
DevicePermissionsPrompt::Prompt::Prompt()
: extension_(nullptr),
browser_context_(nullptr),
multiple_(false),
observer_(nullptr) {
}
void DevicePermissionsPrompt::Prompt::SetObserver(Observer* observer) {
observer_ = observer;
content::BrowserThread::PostTask(
content::BrowserThread::FILE,
FROM_HERE,
base::Bind(&DevicePermissionsPrompt::Prompt::DoDeviceQuery, this));
}
base::string16 DevicePermissionsPrompt::Prompt::GetHeading() const {
return l10n_util::GetStringUTF16(IDS_DEVICE_PERMISSIONS_PROMPT_HEADING);
}
base::string16 DevicePermissionsPrompt::Prompt::GetPromptMessage() const {
return l10n_util::GetStringFUTF16(multiple_
? IDS_DEVICE_PERMISSIONS_PROMPT_MULTIPLE
: IDS_DEVICE_PERMISSIONS_PROMPT_SINGLE,
base::UTF8ToUTF16(extension_->name()));
}
scoped_refptr<UsbDevice> DevicePermissionsPrompt::Prompt::GetDevice(
size_t index) const {
DCHECK_LT(index, devices_.size());
return devices_[index].device;
}
void DevicePermissionsPrompt::Prompt::GrantDevicePermission(
size_t index) const {
DCHECK_LT(index, devices_.size());
DevicePermissionsManager* permissions_manager =
DevicePermissionsManager::Get(browser_context_);
if (permissions_manager) {
permissions_manager->AllowUsbDevice(extension_->id(),
devices_[index].device,
devices_[index].serial_number);
}
}
void DevicePermissionsPrompt::Prompt::set_filters(
const std::vector<UsbDeviceFilter>& filters) {
filters_ = filters;
}
DevicePermissionsPrompt::Prompt::~Prompt() {
}
void DevicePermissionsPrompt::Prompt::DoDeviceQuery() {
UsbService* service = device::DeviceClient::Get()->GetUsbService();
if (!service) {
return;
}
std::vector<scoped_refptr<UsbDevice>> devices;
service->GetDevices(&devices);
std::vector<DeviceInfo> device_info;
for (const auto& device : devices) {
if (!(filters_.empty() || UsbDeviceFilter::MatchesAny(device, filters_))) {
continue;
}
const char* vendor_name_raw =
device::UsbIds::GetVendorName(device->vendor_id());
base::string16 vendor_name;
if (vendor_name_raw) {
vendor_name = base::UTF8ToUTF16(vendor_name_raw);
} else {
vendor_name = l10n_util::GetStringUTF16(IDS_DEVICE_UNKNOWN_VENDOR);
}
const char* product_name_raw = device::UsbIds::GetProductName(
device->vendor_id(), device->product_id());
base::string16 product_name;
if (product_name_raw) {
product_name = base::UTF8ToUTF16(product_name_raw);
} else {
product_name = l10n_util::GetStringUTF16(IDS_DEVICE_UNKNOWN_PRODUCT);
}
base::string16 manufacturer_string;
if (!device->GetManufacturer(&manufacturer_string)) {
manufacturer_string = vendor_name;
}
base::string16 product_string;
if (!device->GetProduct(&product_string)) {
product_string = product_name;
}
base::string16 serial_number;
if (!device->GetSerialNumber(&serial_number)) {
serial_number.clear();
}
base::string16 vendor_id =
base::ASCIIToUTF16(base::StringPrintf("0x%04x", device->vendor_id()));
base::string16 product_id =
base::ASCIIToUTF16(base::StringPrintf("0x%04x", device->product_id()));
device_info.push_back(DeviceInfo(
device,
l10n_util::GetStringFUTF16(IDS_DEVICE_PERMISSIONS_PROMPT_DEVICE_NAME,
product_string,
manufacturer_string),
serial_number,
l10n_util::GetStringFUTF16(IDS_DEVICE_PERMISSIONS_PROMPT_DEVICE_TOOLTIP,
vendor_name,
vendor_id,
product_name,
product_id)));
}
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(
&DevicePermissionsPrompt::Prompt::SetDevices, this, device_info));
}
void DevicePermissionsPrompt::Prompt::SetDevices(
const std::vector<DeviceInfo>& devices) {
devices_ = devices;
if (observer_) {
observer_->OnDevicesChanged();
}
}
DevicePermissionsPrompt::DevicePermissionsPrompt(
content::WebContents* web_contents)
: web_contents_(web_contents),
delegate_(nullptr) {
}
DevicePermissionsPrompt::~DevicePermissionsPrompt() {
}
void DevicePermissionsPrompt::AskForUsbDevices(
Delegate* delegate,
const Extension* extension,
content::BrowserContext* context,
bool multiple,
const std::vector<UsbDeviceFilter>& filters) {
prompt_ = new Prompt();
prompt_->set_extension(extension);
prompt_->set_browser_context(context);
prompt_->set_multiple(multiple);
prompt_->set_filters(filters);
delegate_ = delegate;
GetDefaultShowDialogCallback().Run(web_contents_, delegate_, prompt_);
}
} // namespace extensions
// 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 EXTENSIONS_BROWSER_DEVICE_PERMISSIONS_PROMPT_H_
#define EXTENSIONS_BROWSER_DEVICE_PERMISSIONS_PROMPT_H_
#include <vector>
#include "base/callback.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
namespace content {
class BrowserContext;
class WebContents;
}
namespace device {
class UsbDevice;
class UsbDeviceFilter;
}
namespace extensions {
class Extension;
// Platform-independent interface for displaing a UI for choosing devices
// (similar to choosing files).
class DevicePermissionsPrompt {
public:
// Context information available to the UI implementation.
class Prompt : public base::RefCountedThreadSafe<Prompt> {
public:
// Displayed properties of a device.
struct DeviceInfo {
DeviceInfo(scoped_refptr<device::UsbDevice> device,
const base::string16& name,
const base::string16& serial_number,
const base::string16& tooltip);
~DeviceInfo();
scoped_refptr<device::UsbDevice> device;
base::string16 name;
base::string16 serial_number;
base::string16 tooltip;
};
// Since the set of devices can change while the UI is visible an
// implementation should register an observer.
class Observer {
public:
virtual void OnDevicesChanged() = 0;
};
Prompt();
// Only one observer may be registered at a time.
void SetObserver(Observer* observer);
base::string16 GetHeading() const;
base::string16 GetPromptMessage() const;
size_t GetDeviceCount() const { return devices_.size(); }
scoped_refptr<device::UsbDevice> GetDevice(size_t index) const;
base::string16 GetDeviceName(size_t index) const {
DCHECK_LT(index, devices_.size());
return devices_[index].name;
}
base::string16 GetDeviceSerialNumber(size_t index) const {
DCHECK_LT(index, devices_.size());
return devices_[index].serial_number;
}
base::string16 GetDeviceTooltip(size_t index) const {
DCHECK_LT(index, devices_.size());
return devices_[index].tooltip;
}
// Notifies the DevicePermissionsManager for the current extension that
// access to the device at the given index is now granted.
void GrantDevicePermission(size_t index) const;
const extensions::Extension* extension() const { return extension_; }
void set_extension(const extensions::Extension* extension) {
extension_ = extension;
}
void set_browser_context(content::BrowserContext* context) {
browser_context_ = context;
}
bool multiple() const { return multiple_; }
void set_multiple(bool multiple) { multiple_ = multiple; }
const std::vector<device::UsbDeviceFilter>& filters() const {
return filters_;
}
void set_filters(const std::vector<device::UsbDeviceFilter>& filters);
private:
friend class base::RefCountedThreadSafe<Prompt>;
virtual ~Prompt();
// Querying for devices must be done asynchronously on the FILE thread.
void DoDeviceQuery();
void SetDevices(const std::vector<DeviceInfo>& devices);
const extensions::Extension* extension_;
content::BrowserContext* browser_context_;
bool multiple_;
std::vector<device::UsbDeviceFilter> filters_;
std::vector<DeviceInfo> devices_;
Observer* observer_;
};
class Delegate {
public:
// Called with the list of selected USB devices.
virtual void OnUsbDevicesChosen(
const std::vector<scoped_refptr<device::UsbDevice>>& devices) = 0;
protected:
virtual ~Delegate() {}
};
typedef base::Callback<void(content::WebContents*,
DevicePermissionsPrompt::Delegate*,
scoped_refptr<DevicePermissionsPrompt::Prompt>)>
ShowDialogCallback;
static ShowDialogCallback GetDefaultShowDialogCallback();
DevicePermissionsPrompt(content::WebContents* web_contents);
virtual ~DevicePermissionsPrompt();
virtual void AskForUsbDevices(
Delegate* delegate,
const Extension* extension,
content::BrowserContext* context,
bool multiple,
const std::vector<device::UsbDeviceFilter>& filters);
private:
// Parent web contents of the device permissions UI dialog.
content::WebContents* web_contents_;
// The delegate called after the UI has been dismissed.
Delegate* delegate_;
// Parameters available to the UI implementation.
scoped_refptr<Prompt> prompt_;
};
} // namespace extensions
#endif // EXTENSIONS_BROWSER_API_DEVICE_PERMISSIONS_PROMPT_H_
...@@ -19,12 +19,14 @@ class ObserverListThreadSafe; ...@@ -19,12 +19,14 @@ class ObserverListThreadSafe;
namespace content { namespace content {
class BrowserContext; class BrowserContext;
class WebContents;
} }
namespace extensions { namespace extensions {
class AppViewGuestDelegate; class AppViewGuestDelegate;
class ContentRulesRegistry; class ContentRulesRegistry;
class DevicePermissionsPrompt;
class ExtensionOptionsGuest; class ExtensionOptionsGuest;
class ExtensionOptionsGuestDelegate; class ExtensionOptionsGuestDelegate;
class MimeHandlerViewGuest; class MimeHandlerViewGuest;
......
include_rules = [ include_rules = [
"+device/core",
"+device/hid", "+device/hid",
] ]
include_rules = [
"+device/core",
]
...@@ -415,6 +415,8 @@ ...@@ -415,6 +415,8 @@
'browser/api/declarative_webrequest/webrequest_rules_registry.h', 'browser/api/declarative_webrequest/webrequest_rules_registry.h',
'browser/api/device_permissions_manager.cc', 'browser/api/device_permissions_manager.cc',
'browser/api/device_permissions_manager.h', 'browser/api/device_permissions_manager.h',
'browser/api/device_permissions_prompt.cc',
'browser/api/device_permissions_prompt.h',
'browser/api/dns/dns_api.cc', 'browser/api/dns/dns_api.cc',
'browser/api/dns/dns_api.h', 'browser/api/dns/dns_api.h',
'browser/api/dns/host_resolver_wrapper.cc', 'browser/api/dns/host_resolver_wrapper.cc',
......
...@@ -305,6 +305,27 @@ ...@@ -305,6 +305,27 @@
</message> </message>
<!-- Device API strings. Please keep alphabetized. --> <!-- Device API strings. Please keep alphabetized. -->
<message name="IDS_DEVICE_PERMISSIONS_PROMPT_HEADING" desc="Title of the device selection dialog.">
USB Devices
</message>
<message name="IDS_DEVICE_PERMISSIONS_PROMPT_SINGLE" desc="Instructions asking the user to select one device for use with an app.">
Select a device to use with <ph name="APP_NAME">$1<ex>Chrome Dev Editor</ex></ph>.
</message>
<message name="IDS_DEVICE_PERMISSIONS_PROMPT_MULTIPLE" desc="Instructions asking the user to select one or more devices for use with an app.">
Select devices to use with <ph name="APP_NAME">$1<ex>Chrome Dev Editor</ex></ph>.
</message>
<message name="IDS_DEVICE_PERMISSIONS_PROMPT_DEVICE_NAME" desc="String describing a device in a list of devices.">
<ph name="PRODUCT_NAME">$1<ex>SoundKnob</ex></ph> from <ph name="VENDOR_NAME">$2<ex>Griffin Technology</ex></ph>
</message>
<message name="IDS_DEVICE_PERMISSIONS_PROMPT_DEVICE_TOOLTIP" desc="String providing device vendor and product ID details in a tooltip.">
<ph name="VENDOR_NAME">$1<ex>Griffin Technology</ex></ph> (<ph name="VENDOR_ID">$2<ex>0x1234</ex></ph>), <ph name="PRODUCT_NAME">$3<ex>SoundKnob</ex></ph> (<ph name="PRODUCT_ID">$4<ex>0x5678</ex></ph>)
</message>
<message name="IDS_DEVICE_UNKNOWN_PRODUCT" desc="String used when no human-readable product name is available for a device.">
Unknown Product
</message>
<message name="IDS_DEVICE_UNKNOWN_VENDOR" desc="String used when no human-readable vendor name is available for a device.">
Unknown Vendor
</message>
<message name="IDS_EXTENSION_PROMPT_WARNING_HID" desc="Permission string for access to HID devices."> <message name="IDS_EXTENSION_PROMPT_WARNING_HID" desc="Permission string for access to HID devices.">
Access your input devices Access your input devices
</message> </message>
......
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