summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorreillyg <reillyg@chromium.org>2014-10-16 14:59:11 -0700
committerCommit bot <commit-bot@chromium.org>2014-10-16 21:59:58 +0000
commit43a9462cd259b1a3c6cc961b28518ba6aac261e9 (patch)
tree1fe9fa13c92324b64be54f509bab00283629d910
parent3b1773974278b7c66508ef24929f6c702ffbde38 (diff)
downloadchromium_src-43a9462cd259b1a3c6cc961b28518ba6aac261e9.zip
chromium_src-43a9462cd259b1a3c6cc961b28518ba6aac261e9.tar.gz
chromium_src-43a9462cd259b1a3c6cc961b28518ba6aac261e9.tar.bz2
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}
-rw-r--r--chrome/app/generated_resources.grd11
-rw-r--r--chrome/app/nibs/DevicePermissionsPrompt.xib791
-rw-r--r--chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.h57
-rw-r--r--chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.mm79
-rw-r--r--chrome/browser/ui/cocoa/extensions/device_permissions_view_controller.h40
-rw-r--r--chrome/browser/ui/cocoa/extensions/device_permissions_view_controller.mm79
-rw-r--r--chrome/browser/ui/views/extensions/device_permissions_dialog_view.cc180
-rw-r--r--chrome/browser/ui/views/extensions/device_permissions_dialog_view.h50
-rw-r--r--chrome/chrome_browser_ui.gypi6
-rw-r--r--chrome/chrome_nibs.gyp2
-rw-r--r--chrome/chrome_nibs.gypi1
-rw-r--r--extensions/browser/api/DEPS (renamed from extensions/browser/api/usb/DEPS)0
-rw-r--r--extensions/browser/api/device_permissions_prompt.cc199
-rw-r--r--extensions/browser/api/device_permissions_prompt.h157
-rw-r--r--extensions/browser/api/extensions_api_client.h2
-rw-r--r--extensions/browser/api/hid/DEPS1
-rw-r--r--extensions/browser/api/usb_private/DEPS3
-rw-r--r--extensions/extensions.gyp2
-rw-r--r--extensions/extensions_strings.grd21
19 files changed, 1677 insertions, 4 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 52442f6..7c45527 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -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.">
Enables experiment that message center always scroll up when a notification is removed.
</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>
</release>
</grit>
diff --git a/chrome/app/nibs/DevicePermissionsPrompt.xib b/chrome/app/nibs/DevicePermissionsPrompt.xib
new file mode 100644
index 0000000..52537669
--- /dev/null
+++ b/chrome/app/nibs/DevicePermissionsPrompt.xib
@@ -0,0 +1,791 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00">
+ <data>
+ <int key="IBDocument.SystemTarget">0</int>
+ <string key="IBDocument.SystemVersion">12F45</string>
+ <string key="IBDocument.InterfaceBuilderVersion">3084</string>
+ <string key="IBDocument.AppKitVersion">1187.40</string>
+ <string key="IBDocument.HIToolboxVersion">626.00</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="NS.object.0">3084</string>
+ </object>
+ <array key="IBDocument.IntegratedClassDependencies">
+ <string>NSButton</string>
+ <string>NSButtonCell</string>
+ <string>NSCustomObject</string>
+ <string>NSCustomView</string>
+ <string>NSScrollView</string>
+ <string>NSScroller</string>
+ <string>NSTableColumn</string>
+ <string>NSTableHeaderView</string>
+ <string>NSTableView</string>
+ <string>NSTextField</string>
+ <string>NSTextFieldCell</string>
+ </array>
+ <array key="IBDocument.PluginDependencies">
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </array>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
+ <integer value="1" key="NS.object.0"/>
+ </object>
+ <array class="NSMutableArray" key="IBDocument.RootObjects" id="205393295">
+ <object class="NSCustomObject" id="458336797">
+ <string key="NSClassName">DevicePermissionsViewController</string>
+ </object>
+ <object class="NSCustomObject" id="87661179">
+ <string key="NSClassName">FirstResponder</string>
+ </object>
+ <object class="NSCustomObject" id="402154537">
+ <string key="NSClassName">NSObject</string>
+ </object>
+ <object class="NSCustomView" id="647242925">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">268</int>
+ <array class="NSMutableArray" key="NSSubviews">
+ <object class="NSScrollView" id="406062022">
+ <reference key="NSNextResponder" ref="647242925"/>
+ <int key="NSvFlags">268</int>
+ <array class="NSMutableArray" key="NSSubviews">
+ <object class="NSClipView" id="681374603">
+ <reference key="NSNextResponder" ref="406062022"/>
+ <int key="NSvFlags">2322</int>
+ <array class="NSMutableArray" key="NSSubviews">
+ <object class="NSTableView" id="813004360">
+ <reference key="NSNextResponder" ref="681374603"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{438, 128}</string>
+ <reference key="NSSuperview" ref="681374603"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="387191171"/>
+ <bool key="NSEnabled">YES</bool>
+ <bool key="NSAllowsLogicalLayoutDirection">NO</bool>
+ <bool key="NSControlAllowsExpansionToolTips">YES</bool>
+ <object class="NSTableHeaderView" key="NSHeaderView" id="771521013">
+ <reference key="NSNextResponder" ref="845860729"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{438, 17}</string>
+ <reference key="NSSuperview" ref="845860729"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="681374603"/>
+ <reference key="NSTableView" ref="813004360"/>
+ </object>
+ <object class="_NSCornerView" key="NSCornerView">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{15, 20}</string>
+ </object>
+ <array class="NSMutableArray" key="NSTableColumns">
+ <object class="NSTableColumn" id="956401423">
+ <double key="NSWidth">300</double>
+ <double key="NSMinWidth">300</double>
+ <double key="NSMaxWidth">1000</double>
+ <object class="NSTableHeaderCell" key="NSHeaderCell">
+ <int key="NSCellFlags">75497536</int>
+ <int key="NSCellFlags2">2048</int>
+ <string key="NSContents">Device Name</string>
+ <object class="NSFont" key="NSSupport" id="26">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">11</double>
+ <int key="NSfFlags">3100</int>
+ </object>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC4zMzMzMzI5ODU2AA</bytes>
+ </object>
+ <object class="NSColor" key="NSTextColor" id="266395793">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">headerTextColor</string>
+ <object class="NSColor" key="NSColor" id="704594360">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MAA</bytes>
+ </object>
+ </object>
+ </object>
+ <object class="NSTextFieldCell" key="NSDataCell" id="678763659">
+ <int key="NSCellFlags">337641537</int>
+ <int key="NSCellFlags2">2048</int>
+ <string key="NSContents">Text Cell</string>
+ <object class="NSFont" key="NSSupport" id="755343331">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">13</double>
+ <int key="NSfFlags">1044</int>
+ </object>
+ <reference key="NSControlView" ref="813004360"/>
+ <object class="NSColor" key="NSBackgroundColor" id="432601266">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlBackgroundColor</string>
+ <object class="NSColor" key="NSColor" id="746101907">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSTextColor" id="846635943">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlTextColor</string>
+ <reference key="NSColor" ref="704594360"/>
+ </object>
+ </object>
+ <int key="NSResizingMask">3</int>
+ <bool key="NSIsResizeable">YES</bool>
+ <bool key="NSIsEditable">YES</bool>
+ <reference key="NSTableView" ref="813004360"/>
+ </object>
+ <object class="NSTableColumn" id="90551597">
+ <double key="NSWidth">132</double>
+ <double key="NSMinWidth">100</double>
+ <double key="NSMaxWidth">1000</double>
+ <object class="NSTableHeaderCell" key="NSHeaderCell">
+ <int key="NSCellFlags">75497536</int>
+ <int key="NSCellFlags2">2048</int>
+ <string key="NSContents">Serial Number</string>
+ <reference key="NSSupport" ref="26"/>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC4zMzMzMzI5ODU2AA</bytes>
+ </object>
+ <reference key="NSTextColor" ref="266395793"/>
+ </object>
+ <object class="NSTextFieldCell" key="NSDataCell" id="214845024">
+ <int key="NSCellFlags">337641537</int>
+ <int key="NSCellFlags2">2048</int>
+ <string key="NSContents">Text Cell</string>
+ <reference key="NSSupport" ref="755343331"/>
+ <reference key="NSControlView" ref="813004360"/>
+ <reference key="NSBackgroundColor" ref="432601266"/>
+ <reference key="NSTextColor" ref="846635943"/>
+ </object>
+ <int key="NSResizingMask">3</int>
+ <bool key="NSIsResizeable">YES</bool>
+ <bool key="NSIsEditable">YES</bool>
+ <reference key="NSTableView" ref="813004360"/>
+ </object>
+ </array>
+ <double key="NSIntercellSpacingWidth">3</double>
+ <double key="NSIntercellSpacingHeight">2</double>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ </object>
+ <object class="NSColor" key="NSGridColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">gridColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC41AA</bytes>
+ </object>
+ </object>
+ <double key="NSRowHeight">17</double>
+ <int key="NSTvFlags">-700448768</int>
+ <reference key="NSDelegate"/>
+ <reference key="NSDataSource"/>
+ <int key="NSColumnAutoresizingStyle">4</int>
+ <int key="NSDraggingSourceMaskForLocal">-1</int>
+ <int key="NSDraggingSourceMaskForNonLocal">0</int>
+ <bool key="NSAllowsTypeSelect">YES</bool>
+ <int key="NSTableViewDraggingDestinationStyle">0</int>
+ <int key="NSTableViewGroupRowStyle">1</int>
+ </object>
+ </array>
+ <string key="NSFrame">{{1, 17}, {438, 128}}</string>
+ <reference key="NSSuperview" ref="406062022"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="813004360"/>
+ <reference key="NSDocView" ref="813004360"/>
+ <reference key="NSBGColor" ref="432601266"/>
+ <int key="NScvFlags">4</int>
+ </object>
+ <object class="NSClipView" id="845860729">
+ <reference key="NSNextResponder" ref="406062022"/>
+ <int key="NSvFlags">2338</int>
+ <array class="NSMutableArray" key="NSSubviews">
+ <reference ref="771521013"/>
+ </array>
+ <string key="NSFrame">{{1, 0}, {438, 17}}</string>
+ <reference key="NSSuperview" ref="406062022"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="771521013"/>
+ <reference key="NSDocView" ref="771521013"/>
+ <reference key="NSBGColor" ref="432601266"/>
+ <int key="NScvFlags">4</int>
+ </object>
+ <object class="NSScroller" id="559248773">
+ <reference key="NSNextResponder" ref="406062022"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{1, 130}, {438, 15}}</string>
+ <reference key="NSSuperview" ref="406062022"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="185086302"/>
+ <bool key="NSAllowsLogicalLayoutDirection">NO</bool>
+ <int key="NSsFlags">1</int>
+ <reference key="NSTarget" ref="406062022"/>
+ <string key="NSAction">_doScroller:</string>
+ </object>
+ <object class="NSScroller" id="387191171">
+ <reference key="NSNextResponder" ref="406062022"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{224, 17}, {15, 102}}</string>
+ <reference key="NSSuperview" ref="406062022"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="559248773"/>
+ <bool key="NSAllowsLogicalLayoutDirection">NO</bool>
+ <reference key="NSTarget" ref="406062022"/>
+ <string key="NSAction">_doScroller:</string>
+ </object>
+ </array>
+ <string key="NSFrame">{{20, 56}, {440, 146}}</string>
+ <reference key="NSSuperview" ref="647242925"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="845860729"/>
+ <int key="NSsFlags">133682</int>
+ <reference key="NSVScroller" ref="387191171"/>
+ <reference key="NSHScroller" ref="559248773"/>
+ <reference key="NSContentView" ref="681374603"/>
+ <reference key="NSHeaderClipView" ref="845860729"/>
+ <bytes key="NSScrollAmts">QSAAAEEgAABBmAAAQZgAAA</bytes>
+ <double key="NSMinMagnification">0.25</double>
+ <double key="NSMaxMagnification">4</double>
+ <double key="NSMagnification">1</double>
+ </object>
+ <object class="NSTextField" id="939129060">
+ <reference key="NSNextResponder" ref="647242925"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{18, 210}, {444, 17}}</string>
+ <reference key="NSSuperview" ref="647242925"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="406062022"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="568677004">
+ <int key="NSCellFlags">68157504</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents">User action prompt.</string>
+ <reference key="NSSupport" ref="755343331"/>
+ <reference key="NSControlView" ref="939129060"/>
+ <object class="NSColor" key="NSBackgroundColor" id="905020283">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlColor</string>
+ <reference key="NSColor" ref="746101907"/>
+ </object>
+ <reference key="NSTextColor" ref="846635943"/>
+ </object>
+ <bool key="NSAllowsLogicalLayoutDirection">NO</bool>
+ </object>
+ <object class="NSButton" id="185086302">
+ <reference key="NSNextResponder" ref="647242925"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{258, 20}, {96, 28}}</string>
+ <reference key="NSSuperview" ref="647242925"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="215375254"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="272704635">
+ <int key="NSCellFlags">-2080374784</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Cancel</string>
+ <reference key="NSSupport" ref="755343331"/>
+ <reference key="NSControlView" ref="185086302"/>
+ <int key="NSButtonFlags">-2038284288</int>
+ <int key="NSButtonFlags2">134</int>
+ <object class="NSFont" key="NSAlternateImage">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">13</double>
+ <int key="NSfFlags">16</int>
+ </object>
+ <string key="NSAlternateContents"/>
+ <string type="base64-UTF8" key="NSKeyEquivalent">DQ</string>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ <bool key="NSAllowsLogicalLayoutDirection">NO</bool>
+ </object>
+ <object class="NSButton" id="215375254">
+ <reference key="NSNextResponder" ref="647242925"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{364, 20}, {96, 28}}</string>
+ <reference key="NSSuperview" ref="647242925"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="641345922">
+ <int key="NSCellFlags">67108864</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Select</string>
+ <reference key="NSSupport" ref="755343331"/>
+ <reference key="NSControlView" ref="215375254"/>
+ <int key="NSButtonFlags">-2038415360</int>
+ <int key="NSButtonFlags2">134</int>
+ <object class="NSImage" key="NSNormalImage">
+ <int key="NSImageFlags">549650432</int>
+ <string key="NSSize">{1, 1}</string>
+ <array class="NSMutableArray" key="NSReps">
+ <array>
+ <integer value="0"/>
+ <object class="NSBitmapImageRep">
+ <object class="NSData" key="NSTIFFRepresentation">
+ <bytes key="NS.bytes">TU0AKgAAAAoAAAANAQAAAwAAAAEAAQAAAQEAAwAAAAEAAQAAAQIAAwAAAAIACAAIAQMAAwAAAAEAAQAA
+AQYAAwAAAAEAAQAAAREABAAAAAEAAAAIARIAAwAAAAEAAQAAARUAAwAAAAEAAgAAARYAAwAAAAEAAQAA
+ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA</bytes>
+ </object>
+ </object>
+ </array>
+ </array>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MCAwAA</bytes>
+ </object>
+ </object>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ <bool key="NSAllowsLogicalLayoutDirection">NO</bool>
+ </object>
+ <object class="NSTextField" id="490288410">
+ <reference key="NSNextResponder" ref="647242925"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{18, 233}, {444, 19}}</string>
+ <reference key="NSSuperview" ref="647242925"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="939129060"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="93025338">
+ <int key="NSCellFlags">68157504</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents">Title</string>
+ <object class="NSFont" key="NSSupport">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">15</double>
+ <int key="NSfFlags">16</int>
+ </object>
+ <reference key="NSControlView" ref="490288410"/>
+ <reference key="NSBackgroundColor" ref="905020283"/>
+ <reference key="NSTextColor" ref="846635943"/>
+ </object>
+ <bool key="NSAllowsLogicalLayoutDirection">NO</bool>
+ </object>
+ </array>
+ <string key="NSFrameSize">{480, 272}</string>
+ <reference key="NSSuperview"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="490288410"/>
+ <string key="NSClassName">NSView</string>
+ </object>
+ </array>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <bool key="usesAutoincrementingIDs">NO</bool>
+ <array class="NSMutableArray" key="connectionRecords">
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">cancelButton_</string>
+ <reference key="source" ref="458336797"/>
+ <reference key="destination" ref="185086302"/>
+ </object>
+ <string key="id">coa-ad-ZQs</string>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">okButton_</string>
+ <reference key="source" ref="458336797"/>
+ <reference key="destination" ref="215375254"/>
+ </object>
+ <string key="id">nfH-Ii-7L2</string>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">promptField_</string>
+ <reference key="source" ref="458336797"/>
+ <reference key="destination" ref="939129060"/>
+ </object>
+ <string key="id">M6B-U7-6qF</string>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">scrollView_</string>
+ <reference key="source" ref="458336797"/>
+ <reference key="destination" ref="406062022"/>
+ </object>
+ <string key="id">5M4-1o-N04</string>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">titleField_</string>
+ <reference key="source" ref="458336797"/>
+ <reference key="destination" ref="490288410"/>
+ </object>
+ <string key="id">dbx-yV-40H</string>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">view</string>
+ <reference key="source" ref="458336797"/>
+ <reference key="destination" ref="647242925"/>
+ </object>
+ <string key="id">Cr1-cc-ymz</string>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">ok:</string>
+ <reference key="source" ref="458336797"/>
+ <reference key="destination" ref="215375254"/>
+ </object>
+ <string key="id">PB8-dN-YhU</string>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">cancel:</string>
+ <reference key="source" ref="458336797"/>
+ <reference key="destination" ref="185086302"/>
+ </object>
+ <string key="id">AJw-0Q-hix</string>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">tableView_</string>
+ <reference key="source" ref="458336797"/>
+ <reference key="destination" ref="813004360"/>
+ </object>
+ <string key="id">kVr-kl-EXb</string>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">deviceNameColumn_</string>
+ <reference key="source" ref="458336797"/>
+ <reference key="destination" ref="956401423"/>
+ </object>
+ <string key="id">6n4-hW-mJ8</string>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">serialNumberColumn_</string>
+ <reference key="source" ref="458336797"/>
+ <reference key="destination" ref="90551597"/>
+ </object>
+ <string key="id">O1u-Zs-JLa</string>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">dataSource</string>
+ <reference key="source" ref="813004360"/>
+ <reference key="destination" ref="458336797"/>
+ </object>
+ <string key="id">HB6-2N-mpD</string>
+ </object>
+ </array>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <array key="orderedObjects">
+ <object class="IBObjectRecord">
+ <string key="id">0</string>
+ <array key="object" id="0"/>
+ <reference key="children" ref="205393295"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">-2</string>
+ <reference key="object" ref="458336797"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">File's Owner</string>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">-1</string>
+ <reference key="object" ref="87661179"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">First Responder</string>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">-3</string>
+ <reference key="object" ref="402154537"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">1</string>
+ <reference key="object" ref="647242925"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="490288410"/>
+ <reference ref="215375254"/>
+ <reference ref="185086302"/>
+ <reference ref="939129060"/>
+ <reference ref="406062022"/>
+ </array>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">10</string>
+ <reference key="object" ref="490288410"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="93025338"/>
+ </array>
+ <reference key="parent" ref="647242925"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">11</string>
+ <reference key="object" ref="93025338"/>
+ <reference key="parent" ref="490288410"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">14</string>
+ <reference key="object" ref="215375254"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="641345922"/>
+ </array>
+ <reference key="parent" ref="647242925"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">17</string>
+ <reference key="object" ref="641345922"/>
+ <reference key="parent" ref="215375254"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">15</string>
+ <reference key="object" ref="185086302"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="272704635"/>
+ </array>
+ <reference key="parent" ref="647242925"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">16</string>
+ <reference key="object" ref="272704635"/>
+ <reference key="parent" ref="185086302"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">34</string>
+ <reference key="object" ref="939129060"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="568677004"/>
+ </array>
+ <reference key="parent" ref="647242925"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">35</string>
+ <reference key="object" ref="568677004"/>
+ <reference key="parent" ref="939129060"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">38</string>
+ <reference key="object" ref="406062022"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="559248773"/>
+ <reference ref="387191171"/>
+ <reference ref="771521013"/>
+ <reference ref="813004360"/>
+ </array>
+ <reference key="parent" ref="647242925"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">40</string>
+ <reference key="object" ref="559248773"/>
+ <reference key="parent" ref="406062022"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">42</string>
+ <reference key="object" ref="387191171"/>
+ <reference key="parent" ref="406062022"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">41</string>
+ <reference key="object" ref="771521013"/>
+ <reference key="parent" ref="406062022"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">39</string>
+ <reference key="object" ref="813004360"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="90551597"/>
+ <reference ref="956401423"/>
+ </array>
+ <reference key="parent" ref="406062022"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">44</string>
+ <reference key="object" ref="90551597"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="214845024"/>
+ </array>
+ <reference key="parent" ref="813004360"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">43</string>
+ <reference key="object" ref="956401423"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="678763659"/>
+ </array>
+ <reference key="parent" ref="813004360"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">46</string>
+ <reference key="object" ref="678763659"/>
+ <reference key="parent" ref="956401423"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">45</string>
+ <reference key="object" ref="214845024"/>
+ <reference key="parent" ref="90551597"/>
+ </object>
+ </array>
+ </object>
+ <dictionary class="NSMutableDictionary" key="flattenedProperties">
+ <string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="NO" key="-1.showNotes"/>
+ <string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="NO" key="-2.showNotes"/>
+ <string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="NO" key="-3.showNotes"/>
+ <string key="1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference key="1.IBUserGuides" ref="0"/>
+ <boolean value="NO" key="1.showNotes"/>
+ <boolean value="NO" key="10.IBNSControlSetsMaxLayoutWidthAtFirstLayoutMetadataKey"/>
+ <string key="10.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference key="10.IBUserGuides" ref="0"/>
+ <boolean value="NO" key="10.showNotes"/>
+ <string key="11.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="NO" key="11.showNotes"/>
+ <string key="14.CustomClassName">ConstrainedWindowButton</string>
+ <boolean value="NO" key="14.IBNSControlSetsMaxLayoutWidthAtFirstLayoutMetadataKey"/>
+ <string key="14.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference key="14.IBUserGuides" ref="0"/>
+ <boolean value="NO" key="14.showNotes"/>
+ <string key="15.CustomClassName">ConstrainedWindowButton</string>
+ <boolean value="NO" key="15.IBNSControlSetsMaxLayoutWidthAtFirstLayoutMetadataKey"/>
+ <string key="15.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference key="15.IBUserGuides" ref="0"/>
+ <boolean value="NO" key="15.showNotes"/>
+ <string key="16.CustomClassName">ConstrainedWindowButtonCell</string>
+ <string key="16.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="NO" key="16.showNotes"/>
+ <string key="17.CustomClassName">ConstrainedWindowButtonCell</string>
+ <string key="17.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="NO" key="17.showNotes"/>
+ <boolean value="NO" key="34.IBNSControlSetsMaxLayoutWidthAtFirstLayoutMetadataKey"/>
+ <string key="34.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference key="34.IBUserGuides" ref="0"/>
+ <boolean value="NO" key="34.showNotes"/>
+ <string key="35.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="NO" key="35.showNotes"/>
+ <string key="38.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference key="38.IBUserGuides" ref="0"/>
+ <boolean value="NO" key="38.showNotes"/>
+ <boolean value="NO" key="39.IBNSControlSetsMaxLayoutWidthAtFirstLayoutMetadataKey"/>
+ <string key="39.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference key="39.IBUserGuides" ref="0"/>
+ <boolean value="NO" key="39.showNotes"/>
+ <boolean value="NO" key="40.IBNSControlSetsMaxLayoutWidthAtFirstLayoutMetadataKey"/>
+ <string key="40.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference key="40.IBUserGuides" ref="0"/>
+ <boolean value="NO" key="40.showNotes"/>
+ <string key="41.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference key="41.IBUserGuides" ref="0"/>
+ <boolean value="NO" key="41.showNotes"/>
+ <boolean value="NO" key="42.IBNSControlSetsMaxLayoutWidthAtFirstLayoutMetadataKey"/>
+ <string key="42.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference key="42.IBUserGuides" ref="0"/>
+ <boolean value="NO" key="42.showNotes"/>
+ <string key="43.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="NO" key="43.showNotes"/>
+ <string key="44.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="NO" key="44.showNotes"/>
+ <string key="45.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="NO" key="45.showNotes"/>
+ <string key="46.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="NO" key="46.showNotes"/>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
+ <nil key="activeLocalization"/>
+ <dictionary class="NSMutableDictionary" key="localizations"/>
+ <nil key="sourceID"/>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <array class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <object class="IBPartialClassDescription">
+ <string key="className">DevicePermissionsViewController</string>
+ <string key="superclassName">NSViewController</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="cancel:">id</string>
+ <string key="ok:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="cancel:">
+ <string key="name">cancel:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="ok:">
+ <string key="name">ok:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="cancelButton_">NSButton</string>
+ <string key="deviceNameColumn_">NSTableColumn</string>
+ <string key="okButton_">NSButton</string>
+ <string key="promptField_">NSTextField</string>
+ <string key="scrollView_">NSScrollView</string>
+ <string key="serialNumberColumn_">NSTableColumn</string>
+ <string key="tableView_">NSTableView</string>
+ <string key="titleField_">NSTextField</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="cancelButton_">
+ <string key="name">cancelButton_</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="deviceNameColumn_">
+ <string key="name">deviceNameColumn_</string>
+ <string key="candidateClassName">NSTableColumn</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="okButton_">
+ <string key="name">okButton_</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="promptField_">
+ <string key="name">promptField_</string>
+ <string key="candidateClassName">NSTextField</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="scrollView_">
+ <string key="name">scrollView_</string>
+ <string key="candidateClassName">NSScrollView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="serialNumberColumn_">
+ <string key="name">serialNumberColumn_</string>
+ <string key="candidateClassName">NSTableColumn</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="tableView_">
+ <string key="name">tableView_</string>
+ <string key="candidateClassName">NSTableView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="titleField_">
+ <string key="name">titleField_</string>
+ <string key="candidateClassName">NSTextField</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/DevicePermissionsViewController.h</string>
+ </object>
+ </object>
+ </array>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
+ <real value="0.0" key="NS.object.0"/>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
+ <real value="1060" key="NS.object.0"/>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
+ <integer value="4600" key="NS.object.0"/>
+ </object>
+ <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ </data>
+</archive>
diff --git a/chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.h b/chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.h
new file mode 100644
index 0000000..ac0138f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.h
@@ -0,0 +1,57 @@
+// 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_
diff --git a/chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.mm b/chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.mm
new file mode 100644
index 0000000..5bf1d3f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.mm
@@ -0,0 +1,79 @@
+// 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);
+}
diff --git a/chrome/browser/ui/cocoa/extensions/device_permissions_view_controller.h b/chrome/browser/ui/cocoa/extensions/device_permissions_view_controller.h
new file mode 100644
index 0000000..9b32179
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/device_permissions_view_controller.h
@@ -0,0 +1,40 @@
+// 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_
diff --git a/chrome/browser/ui/cocoa/extensions/device_permissions_view_controller.mm b/chrome/browser/ui/cocoa/extensions/device_permissions_view_controller.mm
new file mode 100644
index 0000000..c058708
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/device_permissions_view_controller.mm
@@ -0,0 +1,79 @@
+// 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
diff --git a/chrome/browser/ui/views/extensions/device_permissions_dialog_view.cc b/chrome/browser/ui/views/extensions/device_permissions_dialog_view.cc
new file mode 100644
index 0000000..4633ac2
--- /dev/null
+++ b/chrome/browser/ui/views/extensions/device_permissions_dialog_view.cc
@@ -0,0 +1,180 @@
+// 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);
+}
diff --git a/chrome/browser/ui/views/extensions/device_permissions_dialog_view.h b/chrome/browser/ui/views/extensions/device_permissions_dialog_view.h
new file mode 100644
index 0000000..024f8c2
--- /dev/null
+++ b/chrome/browser/ui/views/extensions/device_permissions_dialog_view.h
@@ -0,0 +1,50 @@
+// 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_
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 41f9e42..1c1f2a5 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -422,6 +422,10 @@
'browser/ui/cocoa/extensions/browser_actions_container_view.mm',
'browser/ui/cocoa/extensions/browser_actions_controller.h',
'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.mm',
'browser/ui/cocoa/extensions/extension_install_dialog_controller.h',
@@ -1997,6 +2001,8 @@
'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.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.cc',
'browser/ui/views/find_bar_host.h',
diff --git a/chrome/chrome_nibs.gyp b/chrome/chrome_nibs.gyp
index f0ea18f..f919952 100644
--- a/chrome/chrome_nibs.gyp
+++ b/chrome/chrome_nibs.gyp
@@ -129,6 +129,8 @@
'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.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.mm',
'browser/ui/cocoa/extensions/extension_install_view_controller.h',
diff --git a/chrome/chrome_nibs.gypi b/chrome/chrome_nibs.gypi
index 3ad7f21..354b620 100644
--- a/chrome/chrome_nibs.gypi
+++ b/chrome/chrome_nibs.gypi
@@ -53,6 +53,7 @@
'app/nibs/AboutIPC.xib',
'app/nibs/ActionBoxMenuItem.xib',
'app/nibs/BookmarkBarFolderWindow.xib',
+ 'app/nibs/DevicePermissionsPrompt.xib',
'app/nibs/ExtensionInstalledBubbleBundle.xib',
'app/nibs/FindBar.xib',
'app/nibs/GlobalErrorBubble.xib',
diff --git a/extensions/browser/api/usb/DEPS b/extensions/browser/api/DEPS
index 76a2fb6..76a2fb6 100644
--- a/extensions/browser/api/usb/DEPS
+++ b/extensions/browser/api/DEPS
diff --git a/extensions/browser/api/device_permissions_prompt.cc b/extensions/browser/api/device_permissions_prompt.cc
new file mode 100644
index 0000000..40bb4cd
--- /dev/null
+++ b/extensions/browser/api/device_permissions_prompt.cc
@@ -0,0 +1,199 @@
+// 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
diff --git a/extensions/browser/api/device_permissions_prompt.h b/extensions/browser/api/device_permissions_prompt.h
new file mode 100644
index 0000000..d96e767
--- /dev/null
+++ b/extensions/browser/api/device_permissions_prompt.h
@@ -0,0 +1,157 @@
+// 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_
diff --git a/extensions/browser/api/extensions_api_client.h b/extensions/browser/api/extensions_api_client.h
index 878555b..9cf4d97 100644
--- a/extensions/browser/api/extensions_api_client.h
+++ b/extensions/browser/api/extensions_api_client.h
@@ -19,12 +19,14 @@ class ObserverListThreadSafe;
namespace content {
class BrowserContext;
+class WebContents;
}
namespace extensions {
class AppViewGuestDelegate;
class ContentRulesRegistry;
+class DevicePermissionsPrompt;
class ExtensionOptionsGuest;
class ExtensionOptionsGuestDelegate;
class MimeHandlerViewGuest;
diff --git a/extensions/browser/api/hid/DEPS b/extensions/browser/api/hid/DEPS
index 7dc8543..76a0f69 100644
--- a/extensions/browser/api/hid/DEPS
+++ b/extensions/browser/api/hid/DEPS
@@ -1,4 +1,3 @@
include_rules = [
- "+device/core",
"+device/hid",
]
diff --git a/extensions/browser/api/usb_private/DEPS b/extensions/browser/api/usb_private/DEPS
deleted file mode 100644
index 76a2fb6..0000000
--- a/extensions/browser/api/usb_private/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+device/core",
-]
diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp
index e1e7b87..12dcd7e 100644
--- a/extensions/extensions.gyp
+++ b/extensions/extensions.gyp
@@ -415,6 +415,8 @@
'browser/api/declarative_webrequest/webrequest_rules_registry.h',
'browser/api/device_permissions_manager.cc',
'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.h',
'browser/api/dns/host_resolver_wrapper.cc',
diff --git a/extensions/extensions_strings.grd b/extensions/extensions_strings.grd
index 424410ef..1abb4e2 100644
--- a/extensions/extensions_strings.grd
+++ b/extensions/extensions_strings.grd
@@ -305,6 +305,27 @@
</message>
<!-- 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.">
Access your input devices
</message>