Commit 9c7e3c2d authored by Steven Bennetts's avatar Steven Bennetts Committed by Commit Bot

Settings: Move bluetooth dialog to a shared location

This CL is in preparation for converting the bluetooth pairing dialog
(BluetoothPairingUI) to use the MD Settings UI.

This CL:
* Eliminate Settings dependencies from the bluetooth dialog element
  and moves some dialog related error parsing into the dialog element.
* Moves some 'options' strings to settings_strings.grd in anticipation
  of removal of all options strings.
* Adds a new shared location for higher level shared chromeos
  elements: ui/webui/resources/chromeos. These elements are allowed to
  use I18nBehavior to simplify localization.
* Moves the bluetooth dialog element to the new shared location.

Bug: 748193
Cq-Include-Trybots: master.tryserver.chromium.linux:closure_compilation
Change-Id: I861730aa9cbbe5cb37a8df3d26f62d9f20429672
Reviewed-on: https://chromium-review.googlesource.com/592461
Commit-Queue: Steven Bennetts <stevenjb@chromium.org>
Reviewed-by: default avatarDirk Pranke <dpranke@chromium.org>
Reviewed-by: default avatarDemetrios Papadopoulos <dpapad@chromium.org>
Reviewed-by: default avatarTommy Li <tommycli@chromium.org>
Reviewed-by: default avatarMichael Giuffrida <michaelpg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#491459}
parent 7f5284e3
...@@ -2041,8 +2041,9 @@ def _CheckForRiskyJsConstLet(input_api, line_number, line): ...@@ -2041,8 +2041,9 @@ def _CheckForRiskyJsConstLet(input_api, line_number, line):
def _CheckForRiskyJsFeatures(input_api, output_api): def _CheckForRiskyJsFeatures(input_api, output_api):
maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", ) maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js) chromeos_filter = (r".*chromeos.*", )
file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
black_list=chromeos_filter)
results = [] results = []
for f in input_api.AffectedFiles(file_filter=file_filter): for f in input_api.AffectedFiles(file_filter=file_filter):
arrow_error_lines = [] arrow_error_lines = []
......
...@@ -555,6 +555,21 @@ ...@@ -555,6 +555,21 @@
<message name="IDS_SETTINGS_BLUETOOTH_TOGGLE_ACCESSIBILITY_LABEL" desc="Accessibility only label for Bluetooth enable/disable toggle."> <message name="IDS_SETTINGS_BLUETOOTH_TOGGLE_ACCESSIBILITY_LABEL" desc="Accessibility only label for Bluetooth enable/disable toggle.">
Bluetooth enable Bluetooth enable
</message> </message>
<message name="IDS_SETTINGS_BLUETOOTH_ENTER_KEY" desc="Bluetooth pairing dialog: Text for enter key when pairing keyboard devices." >
enter
</message>
<message name="IDS_SETTINGS_BLUETOOTH_ACCEPT_PASSKEY" desc="Bluetooth pairing dialog: Text for button to accept pairing code.">
Accept
</message>
<message name="IDS_SETTINGS_BLUETOOTH_CONNECT" desc="Bluetooth pairing dialog: Text for dropdown meny item to connect to a device.">
Connect
</message>
<message name="IDS_SETTINGS_BLUETOOTH_DISCONNECT" desc="Bluetooth pairing dialog: dropdown meny item to disconnect from a device.">
Disconnect
</message>
<message name="IDS_SETTINGS_BLUETOOTH_REJECT_PASSKEY" desc="Bluetooth pairing dialog: Text for button to reject pairing a device.">
Reject
</message>
<message name="IDS_SETTINGS_BLUETOOTH_EXPAND_ACCESSIBILITY_LABEL" desc="Label for the button that toggles showing available Bluetooth devices. Only visible by screen reader software."> <message name="IDS_SETTINGS_BLUETOOTH_EXPAND_ACCESSIBILITY_LABEL" desc="Label for the button that toggles showing available Bluetooth devices. Only visible by screen reader software.">
Show available Bluetooth devices Show available Bluetooth devices
</message> </message>
......
<link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_scrollable_behavior.html"> <link rel="import" href="chrome://resources/cr_elements/cr_scrollable_behavior.html">
<link rel="import" href="chrome://resources/chromeos/bluetooth_dialog.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner.html">
...@@ -8,7 +9,6 @@ ...@@ -8,7 +9,6 @@
<link rel="import" href="../i18n_setup.html"> <link rel="import" href="../i18n_setup.html">
<link rel="import" href="../icons.html"> <link rel="import" href="../icons.html">
<link rel="import" href="../settings_shared_css.html"> <link rel="import" href="../settings_shared_css.html">
<link rel="import" href="bluetooth_device_dialog.html">
<link rel="import" href="bluetooth_device_list_item.html"> <link rel="import" href="bluetooth_device_list_item.html">
<dom-module id="settings-bluetooth-subpage"> <dom-module id="settings-bluetooth-subpage">
...@@ -99,14 +99,13 @@ ...@@ -99,14 +99,13 @@
</iron-list> </iron-list>
</div> </div>
<bluetooth-device-dialog id="deviceDialog" <bluetooth-dialog id="deviceDialog"
bluetooth="[[bluetooth]]"
bluetooth-private="[[bluetoothPrivate]]" bluetooth-private="[[bluetoothPrivate]]"
dialog-id="[[dialogId_]]" title="$i18n{bluetoothPairDevicePageTitle}"
error-message="[[errorMessage_]]"
on-close="onDialogClose_" on-close="onDialogClose_"
on-device-event="onDeviceEvent_"
pairing-device="[[pairingDevice_]]"> pairing-device="[[pairingDevice_]]">
</bluetooth-device-dialog> </bluetooth-dialog>
</template> </template>
<script src="bluetooth_subpage.js"></script> <script src="bluetooth_subpage.js"></script>
......
...@@ -8,9 +8,6 @@ ...@@ -8,9 +8,6 @@
* properties and devices. * properties and devices.
*/ */
// NOTE(dbeam): even though this behavior is only used privately, it must
// be globally accessible for Closure's --polymer_pass to compile happily.
Polymer({ Polymer({
is: 'settings-bluetooth-subpage', is: 'settings-bluetooth-subpage',
...@@ -40,7 +37,7 @@ Polymer({ ...@@ -40,7 +37,7 @@ Polymer({
showSpinner_: { showSpinner_: {
type: Boolean, type: Boolean,
notify: true, notify: true,
computed: 'computeShowSpinner_(adapterState.*, dialogId_)', computed: 'computeShowSpinner_(adapterState.*, dialogShown_)',
}, },
/** /**
...@@ -97,16 +94,12 @@ Polymer({ ...@@ -97,16 +94,12 @@ Polymer({
}, },
/** /**
* Set to the name of the dialog to show. This page uses a single * Whether or not the dialog is shown.
* dialog to host one of two dialog elements: 'pairDevice' or
* 'connectError'. This allows a seamless transition between dialogs.
* Note: This property should be set before opening the dialog and setting
* the property will not itself cause the dialog to open.
* @private * @private
*/ */
dialogId_: { dialogShown_: {
type: String, type: Boolean,
value: '', value: false,
}, },
/** /**
...@@ -116,12 +109,6 @@ Polymer({ ...@@ -116,12 +109,6 @@ Polymer({
*/ */
pairingDevice_: Object, pairingDevice_: Object,
/**
* The translated error message to show when a connect error occurs.
* @private
*/
errorMessage_: String,
/** /**
* Interface for bluetooth calls. Set in bluetooth-page. * Interface for bluetooth calls. Set in bluetooth-page.
* @type {Bluetooth} * @type {Bluetooth}
...@@ -200,7 +187,7 @@ Polymer({ ...@@ -200,7 +187,7 @@ Polymer({
/** @private */ /** @private */
computeShowSpinner_: function() { computeShowSpinner_: function() {
return !this.dialogId_ && this.get('adapterState.discovering'); return !this.dialogShown_ && this.get('adapterState.discovering');
}, },
/** @private */ /** @private */
...@@ -268,7 +255,7 @@ Polymer({ ...@@ -268,7 +255,7 @@ Polymer({
*/ */
onBluetoothDeviceUpdated_: function(device) { onBluetoothDeviceUpdated_: function(device) {
var address = device.address; var address = device.address;
if (this.dialogId_ && this.pairingDevice_ && if (this.dialogShown_ && this.pairingDevice_ &&
this.pairingDevice_.address == address) { this.pairingDevice_.address == address) {
this.pairingDevice_ = device; this.pairingDevice_ = device;
} }
...@@ -382,40 +369,22 @@ Polymer({ ...@@ -382,40 +369,22 @@ Polymer({
// If the device is not paired, show the pairing dialog before connecting. // If the device is not paired, show the pairing dialog before connecting.
if (!device.paired) { if (!device.paired) {
this.pairingDevice_ = device; this.pairingDevice_ = device;
this.openDialog_('pairDevice'); this.openDialog_();
} }
this.bluetoothPrivate.connect(device.address, result => { var address = device.address;
var error; this.bluetoothPrivate.connect(address, result => {
if (chrome.runtime.lastError) { // If |pairingDevice_| has changed, ignore the connect result.
error = chrome.runtime.lastError.message; if (this.pairingDevice_ && address != this.pairingDevice_.address)
} else {
switch (result) {
case chrome.bluetoothPrivate.ConnectResultType.IN_PROGRESS:
return; // Do not close the dialog
case chrome.bluetoothPrivate.ConnectResultType.ALREADY_CONNECTED:
case chrome.bluetoothPrivate.ConnectResultType.AUTH_CANCELED:
case chrome.bluetoothPrivate.ConnectResultType.SUCCESS:
break;
default:
error = result;
}
}
if (!error) {
this.$.deviceDialog.close();
return; return;
// Let the dialog handle any errors, otherwise close the dialog.
var dialog = this.$.deviceDialog;
if (dialog.handleError(device, chrome.runtime.lastError, result)) {
this.openDialog_();
} else if (
result != chrome.bluetoothPrivate.ConnectResultType.IN_PROGRESS) {
this.$.deviceDialog.close();
} }
var name = device.name || device.address;
var id = 'bluetooth_connect_' + error;
if (this.i18nExists(id)) {
this.errorMessage_ = this.i18n(id, name);
} else {
this.errorMessage_ = error;
console.error('Unexpected error connecting to: ' + name + ': ' + error);
}
this.openDialog_('connectError');
}); });
}, },
...@@ -448,25 +417,19 @@ Polymer({ ...@@ -448,25 +417,19 @@ Polymer({
}); });
}, },
/** /** @private */
* @param {string} dialogId openDialog_: function() {
* @private if (this.dialogShown_)
*/
openDialog_: function(dialogId) {
if (this.dialogId_) {
// Dialog already opened, just update the contents.
this.dialogId_ = dialogId;
return; return;
}
this.dialogId_ = dialogId;
// Call flush so that the dialog gets sized correctly before it is opened. // Call flush so that the dialog gets sized correctly before it is opened.
Polymer.dom.flush(); Polymer.dom.flush();
this.$.deviceDialog.open(); this.$.deviceDialog.open();
this.dialogShown_ = true;
}, },
/** @private */ /** @private */
onDialogClose_: function() { onDialogClose_: function() {
this.dialogId_ = ''; this.dialogShown_ = false;
this.pairingDevice_ = undefined; this.pairingDevice_ = undefined;
// The list is dynamic so focus the first item. // The list is dynamic so focus the first item.
var device = this.$$('#unpairedContainer bluetooth-device-list-item'); var device = this.$$('#unpairedContainer bluetooth-device-list-item');
......
...@@ -31,21 +31,6 @@ ...@@ -31,21 +31,6 @@
], ],
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
}, },
{
'target_name': 'bluetooth_device_dialog',
'dependencies': [
'<(DEPTH)/ui/webui/resources/cr_elements/cr_dialog/compiled_resources2.gyp:cr_dialog',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
'<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/compiled_resources2.gyp:iron-resizable-behavior-extracted',
'<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-input/compiled_resources2.gyp:paper-input-extracted',
'<(EXTERNS_GYP):bluetooth',
'<(EXTERNS_GYP):bluetooth_private',
'<(INTERFACES_GYP):bluetooth_private_interface',
],
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
{ {
'target_name': 'bluetooth_device_list_item', 'target_name': 'bluetooth_device_list_item',
'dependencies': [ 'dependencies': [
......
...@@ -1126,12 +1126,6 @@ ...@@ -1126,12 +1126,6 @@
<structure name="IDR_SETTINGS_ANDROID_SETTINGS_ELEMENT_JS" <structure name="IDR_SETTINGS_ANDROID_SETTINGS_ELEMENT_JS"
file="android_apps_page/android_settings_element.js" file="android_apps_page/android_settings_element.js"
type="chrome_html" /> type="chrome_html" />
<structure name="IDR_SETTINGS_BLUETOOTH_DEVICE_DIALOG_HTML"
file="bluetooth_page/bluetooth_device_dialog.html"
type="chrome_html" />
<structure name="IDR_SETTINGS_BLUETOOTH_DEVICE_DIALOG_JS"
file="bluetooth_page/bluetooth_device_dialog.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_BLUETOOTH_DEVICE_LIST_ITEM_HTML" <structure name="IDR_SETTINGS_BLUETOOTH_DEVICE_LIST_ITEM_HTML"
file="bluetooth_page/bluetooth_device_list_item.html" file="bluetooth_page/bluetooth_device_list_item.html"
type="chrome_html" /> type="chrome_html" />
......
...@@ -29,6 +29,9 @@ _RESOURCES_PATH = os.path.join(_SRC_PATH, 'ui', 'webui', 'resources') ...@@ -29,6 +29,9 @@ _RESOURCES_PATH = os.path.join(_SRC_PATH, 'ui', 'webui', 'resources')
_CR_ELEMENTS_PATH = os.path.join(_RESOURCES_PATH, 'cr_elements') _CR_ELEMENTS_PATH = os.path.join(_RESOURCES_PATH, 'cr_elements')
_CHROMEOS_PATH = os.path.join(_RESOURCES_PATH, 'chromeos')
_CSS_RESOURCES_PATH = os.path.join(_RESOURCES_PATH, 'css') _CSS_RESOURCES_PATH = os.path.join(_RESOURCES_PATH, 'css')
...@@ -64,6 +67,7 @@ _VULCANIZE_BASE_ARGS = [ ...@@ -64,6 +67,7 @@ _VULCANIZE_BASE_ARGS = [
_URL_MAPPINGS = [ _URL_MAPPINGS = [
('chrome://resources/chromeos/', _CHROMEOS_PATH),
('chrome://resources/cr_elements/', _CR_ELEMENTS_PATH), ('chrome://resources/cr_elements/', _CR_ELEMENTS_PATH),
('chrome://resources/css/', _CSS_RESOURCES_PATH), ('chrome://resources/css/', _CSS_RESOURCES_PATH),
('chrome://resources/html/', _HTML_RESOURCES_PATH), ('chrome://resources/html/', _HTML_RESOURCES_PATH),
......
...@@ -368,15 +368,14 @@ void AddAppearanceStrings(content::WebUIDataSource* html_source, ...@@ -368,15 +368,14 @@ void AddAppearanceStrings(content::WebUIDataSource* html_source,
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
void AddBluetoothStrings(content::WebUIDataSource* html_source) { void AddBluetoothStrings(content::WebUIDataSource* html_source) {
LocalizedString localized_strings[] = { LocalizedString localized_strings[] = {
{"bluetoothAccept", IDS_OPTIONS_SETTINGS_BLUETOOTH_ACCEPT_PASSKEY}, {"bluetoothAccept", IDS_SETTINGS_BLUETOOTH_ACCEPT_PASSKEY},
{"bluetoothConnected", IDS_SETTINGS_BLUETOOTH_CONNECTED}, {"bluetoothConnected", IDS_SETTINGS_BLUETOOTH_CONNECTED},
{"bluetoothConnecting", IDS_SETTINGS_BLUETOOTH_CONNECTING}, {"bluetoothConnecting", IDS_SETTINGS_BLUETOOTH_CONNECTING},
{"bluetoothDeviceListPaired", IDS_SETTINGS_BLUETOOTH_DEVICE_LIST_PAIRED}, {"bluetoothDeviceListPaired", IDS_SETTINGS_BLUETOOTH_DEVICE_LIST_PAIRED},
{"bluetoothDeviceListUnpaired", {"bluetoothDeviceListUnpaired",
IDS_SETTINGS_BLUETOOTH_DEVICE_LIST_UNPAIRED}, IDS_SETTINGS_BLUETOOTH_DEVICE_LIST_UNPAIRED},
{"bluetoothConnect", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT}, {"bluetoothConnect", IDS_SETTINGS_BLUETOOTH_CONNECT},
{"bluetoothDisconnect", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISCONNECT}, {"bluetoothDisconnect", IDS_SETTINGS_BLUETOOTH_DISCONNECT},
{"bluetoothDismiss", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISMISS_ERROR},
{"bluetoothToggleA11yLabel", {"bluetoothToggleA11yLabel",
IDS_SETTINGS_BLUETOOTH_TOGGLE_ACCESSIBILITY_LABEL}, IDS_SETTINGS_BLUETOOTH_TOGGLE_ACCESSIBILITY_LABEL},
{"bluetoothExpandA11yLabel", {"bluetoothExpandA11yLabel",
...@@ -388,11 +387,11 @@ void AddBluetoothStrings(content::WebUIDataSource* html_source) { ...@@ -388,11 +387,11 @@ void AddBluetoothStrings(content::WebUIDataSource* html_source) {
{"bluetoothPair", IDS_SETTINGS_BLUETOOTH_PAIR}, {"bluetoothPair", IDS_SETTINGS_BLUETOOTH_PAIR},
{"bluetoothPairDevicePageTitle", {"bluetoothPairDevicePageTitle",
IDS_SETTINGS_BLUETOOTH_PAIR_DEVICE_TITLE}, IDS_SETTINGS_BLUETOOTH_PAIR_DEVICE_TITLE},
{"bluetoothReject", IDS_OPTIONS_SETTINGS_BLUETOOTH_REJECT_PASSKEY}, {"bluetoothReject", IDS_SETTINGS_BLUETOOTH_REJECT_PASSKEY},
{"bluetoothRemove", IDS_SETTINGS_BLUETOOTH_REMOVE}, {"bluetoothRemove", IDS_SETTINGS_BLUETOOTH_REMOVE},
// Device connecting and pairing. // Device connecting and pairing.
{"bluetoothStartConnecting", IDS_SETTINGS_BLUETOOTH_START_CONNECTING}, {"bluetoothStartConnecting", IDS_SETTINGS_BLUETOOTH_START_CONNECTING},
{"bluetoothEnterKey", IDS_OPTIONS_SETTINGS_BLUETOOTH_ENTER_KEY}, {"bluetoothEnterKey", IDS_SETTINGS_BLUETOOTH_ENTER_KEY},
// These ids are generated in JS using 'bluetooth_' + a value from // These ids are generated in JS using 'bluetooth_' + a value from
// bluetoothPrivate.PairingEventType (see bluetooth_private.idl). // bluetoothPrivate.PairingEventType (see bluetooth_private.idl).
// 'keysEntered', and 'requestAuthorization' have no associated message. // 'keysEntered', and 'requestAuthorization' have no associated message.
......
...@@ -37,7 +37,11 @@ const char* const kPathAliases[][2] = { ...@@ -37,7 +37,11 @@ const char* const kPathAliases[][2] = {
"polymer/v1_0/web-animations-js/"}, "polymer/v1_0/web-animations-js/"},
{"../../views/resources/default_100_percent/common/", "images/apps/"}, {"../../views/resources/default_100_percent/common/", "images/apps/"},
{"../../views/resources/default_200_percent/common/", "images/2x/apps/"}, {"../../views/resources/default_200_percent/common/", "images/2x/apps/"},
{"../../webui/resources/cr_elements/", "cr_elements/"}}; #if defined(OS_CHROMEOS)
{"../../webui/resources/chromeos/", "chromeos/"},
#endif
{"../../webui/resources/cr_elements/", "cr_elements/"},
};
const struct { const struct {
const char* const path; const char* const path;
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
'<(DEPTH)/chrome/browser/resources/uber/compiled_resources2.gyp:*', '<(DEPTH)/chrome/browser/resources/uber/compiled_resources2.gyp:*',
'<(DEPTH)/chrome/browser/resources/webapks/compiled_resources2.gyp:*', '<(DEPTH)/chrome/browser/resources/webapks/compiled_resources2.gyp:*',
'<(DEPTH)/ui/file_manager/compiled_resources2.gyp:*', '<(DEPTH)/ui/file_manager/compiled_resources2.gyp:*',
'<(DEPTH)/ui/webui/resources/chromeos/compiled_resources2.gyp:*',
'<(DEPTH)/ui/webui/resources/cr_elements/compiled_resources2.gyp:*', '<(DEPTH)/ui/webui/resources/cr_elements/compiled_resources2.gyp:*',
'<(DEPTH)/ui/webui/resources/js/chromeos/compiled_resources2.gyp:*', '<(DEPTH)/ui/webui/resources/js/chromeos/compiled_resources2.gyp:*',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:*', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:*',
......
...@@ -28,9 +28,11 @@ def _CheckForTranslations(input_api, output_api): ...@@ -28,9 +28,11 @@ def _CheckForTranslations(input_api, output_api):
for f in input_api.AffectedFiles(): for f in input_api.AffectedFiles():
local_path = f.LocalPath() local_path = f.LocalPath()
# Allow translation in i18n_behavior.js and the chromeos/ directory.
if local_path.endswith('i18n_behavior.js'): if local_path.endswith('i18n_behavior.js'):
continue continue
if 'chromeos' in local_path:
continue
keywords = None keywords = None
if local_path.endswith('.js'): if local_path.endswith('.js'):
keywords = js_keywords keywords = js_keywords
......
This directory contains shared chromeos elements for Web UI
(e.g. between Settings and a stand alone dialog).
These components are allowed to use I18nBehavior. The Web UI hosting
these elements is expected to provide loadTimeData with the necessary
strings. TODO(stevenjb/dschuyler): Add support for i18n{} substitution.
<link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
<link rel="import" href="chrome://resources/html/cr.html"> <link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
<link rel="import" href="../bluetooth_page/bluetooth_device_list_item.html">
<link rel="import" href="../settings_shared_css.html">
<dom-module id="bluetooth-device-dialog"> <dom-module id="bluetooth-dialog">
<template> <template>
<style include="settings-shared iron-flex"> <style include="cr-hidden-style iron-flex">
#pairing { #pairing {
margin-bottom: 10px; margin-bottom: 10px;
} }
...@@ -68,73 +68,70 @@ ...@@ -68,73 +68,70 @@
margin: 0 20px; margin: 0 20px;
} }
</style> </style>
<!-- TODO(stevenjb/dschuyler): Find a solution to support i18n{} here -->
<dialog is="cr-dialog" id="dialog" on-cancel="onDialogCanceled_" <dialog is="cr-dialog" id="dialog" on-cancel="onDialogCanceled_"
close-text="$i18n{close}" on-closed="onDialogCanceled_"> close-text="[[i18n('close')]]" on-closed="onDialogCanceled_">
<div slot="title">$i18n{bluetoothPairDevicePageTitle}</div> <div slot="title">[[title]]</div>
<div slot="body"> <div slot="body">
<div class="contents layout vertical center center-justified"> <div class="contents layout vertical center center-justified">
<template is="dom-if" if="[[isDialogType_(dialogId, 'pairDevice')]]"> <template is="dom-if" if="[[!errorMessage_]]">
<div id="pairing" class="settings-box first layout vertical center <div id="pairing" class="layout vertical center center-justified">
center-justified">
<div class="dialog-message"> <div class="dialog-message">
[[getMessage_(pairingDevice, pairingEvent_)]] [[getMessage_(pairingDevice, pairingEvent_)]]
</div> </div>
<div hidden$="[[!showEnterPincode_(pairingEvent_)]]"> <div hidden$="[[!showEnterPincode_(pairingEvent_)]]">
<paper-input id="pincode" minlength="1" maxlength="16" <paper-input id="pincode" minlength="1" maxlength="16"
type="text" auto-validate value="{{pinOrPass}}"> type="text" auto-validate value="{{pinOrPass_}}">
</paper-input> </paper-input>
</div> </div>
<div hidden$="[[!showEnterPasskey_(pairingEvent_)]]"> <div hidden$="[[!showEnterPasskey_(pairingEvent_)]]">
<paper-input id="passkey" minlength="6" maxlength="6" <paper-input id="passkey" minlength="6" maxlength="6"
type="text" auto-validate value="{{pinOrPass}}"> type="text" auto-validate value="{{pinOrPass_}}">
</paper-input> </paper-input>
</div> </div>
<div id="pinDiv" class="layout horizontal center center-justified" <div id="pinDiv" class="layout horizontal center center-justified"
hidden="[[!showDisplayPassOrPin_(pairingEvent_)]]"> hidden="[[!showDisplayPassOrPin_(pairingEvent_)]]">
<template is="dom-repeat" items="[[digits]]"> <template is="dom-repeat" items="[[digits_]]">
<span class$="[[getPinClass_(index, pairingEvent_)]]"> <span class$="[[getPinClass_(index, pairingEvent_)]]">
[[getPinDigit_(index, pairingEvent_)]] [[getPinDigit_(index, pairingEvent_)]]
</span> </span>
</template> </template>
<span class$="[[getPinClass_(-1, pairingEvent_)]]" <span class$="[[getPinClass_(-1, pairingEvent_)]]"
hidden="[[showAcceptReject_(pairingEvent_)]]"> hidden="[[showAcceptReject_(pairingEvent_)]]">
$i18n{bluetoothEnterKey} [[i18n('bluetoothEnterKey')]]
</span> </span>
</div> </div>
</div> </div>
</template> </template>
<template is="dom-if" <template is="dom-if" if="[[errorMessage_]]">
if="[[isDialogType_('connectError', dialogId)]]"> <div class="layout vertical center center-justified">
<div class="settings-box first layout vertical center <div class="dialog-message">[[errorMessage_]]</div>
center-justified">
<div class="dialog-message">[[errorMessage]]</div>
</div> </div>
</template> </template>
</div> </div>
</div> </div>
<div slot="button-container"> <div slot="button-container">
<template is="dom-if" if="[[isDialogType_('pairDevice', dialogId)]]"> <template is="dom-if" if="[[!errorMessage_]]">
<paper-button hidden$="[[!showAcceptReject_(pairingEvent_)]]" <paper-button hidden$="[[!showAcceptReject_(pairingEvent_)]]"
on-tap="onAcceptTap_">$i18n{bluetoothAccept}</paper-button> on-tap="onAcceptTap_">[[i18n('bluetoothAccept')]]</paper-button>
<paper-button hidden$="[[!showAcceptReject_(pairingEvent_)]]" <paper-button hidden$="[[!showAcceptReject_(pairingEvent_)]]"
on-tap="onRejectTap_">$i18n{bluetoothReject}</paper-button> on-tap="onRejectTap_">[[i18n('bluetoothReject')]]</paper-button>
<paper-button hidden$="[[!showConnect_(pairingEvent_)]]" <paper-button hidden$="[[!showConnect_(pairingEvent_)]]"
disabled="[[!enableConnect_(pairingEvent_, pinOrPass)]]" disabled="[[!enableConnect_(pairingEvent_, pinOrPass_)]]"
on-tap="onConnectTap_">$i18n{bluetoothPair}</paper-button> on-tap="onConnectTap_">[[i18n('bluetoothPair')]]</paper-button>
<paper-button <paper-button
hidden$="[[!showDismiss_(pairingDevice, pairingEvent_)]]" hidden$="[[!showDismiss_(pairingDevice, pairingEvent_)]]"
on-tap="close">$i18n{bluetoothDismiss}</paper-button> on-tap="close">[[i18n('ok')]]</paper-button>
<paper-button hidden$="[[showDismiss_(pairingDevice, pairingEvent_)]]" <paper-button hidden$="[[showDismiss_(pairingDevice, pairingEvent_)]]"
on-tap="onCancelTap_"> on-tap="onCancelTap_">
$i18n{cancel} [[i18n('cancel')]]
</paper-button> </paper-button>
</template> </template>
<template is="dom-if" if="[[isDialogType_('connectError', dialogId)]]"> <template is="dom-if" if="[[errorMessage_]]">
<paper-button on-tap="close">$i18n{bluetoothDismiss} <paper-button on-tap="close">[[i18n('ok')]]</paper-button>
</paper-button>
</template> </template>
</div> </div>
</dialog> </dialog>
</template> </template>
<script src="bluetooth_device_dialog.js"></script> <script src="bluetooth_dialog.js"></script>
</dom-module> </dom-module>
...@@ -2,16 +2,43 @@ ...@@ -2,16 +2,43 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
cr.exportPath('settings'); /**
* @fileoverview
* Dialog used for pairing a provided |pairing-device|. Set |show-error| to
* show the error results from a pairing event instead of the pairing UI.
* NOTE: This module depends on I18nBehavior which depends on loadTimeData.
*/
var PairingEventType = chrome.bluetoothPrivate.PairingEventType; var PairingEventType = chrome.bluetoothPrivate.PairingEventType;
// NOTE(dbeam): even though this behavior is only used privately, it must Polymer({
// be globally accessible for Closure's --polymer_pass to compile happily. is: 'bluetooth-dialog',
behaviors: [I18nBehavior],
/** @polymerBehavior */
settings.BluetoothPairDeviceBehavior = {
properties: { properties: {
/**
* Interface for bluetooth calls. Set in bluetooth-page.
* @type {Bluetooth}
* @private
*/
bluetooth: {
type: Object,
value: chrome.bluetooth,
},
/**
* Interface for bluetoothPrivate calls.
* @type {BluetoothPrivate}
*/
bluetoothPrivate: {
type: Object,
value: chrome.bluetoothPrivate,
},
/** Dialog title */
title: String,
/** /**
* Current Pairing device. * Current Pairing device.
* @type {!chrome.bluetooth.Device|undefined} * @type {!chrome.bluetooth.Device|undefined}
...@@ -20,31 +47,31 @@ settings.BluetoothPairDeviceBehavior = { ...@@ -20,31 +47,31 @@ settings.BluetoothPairDeviceBehavior = {
/** /**
* Current Pairing event. * Current Pairing event.
* @type {?chrome.bluetoothPrivate.PairingEvent} * @private {?chrome.bluetoothPrivate.PairingEvent}
*/ */
pairingEvent_: { pairingEvent_: {
type: Object, type: Object,
value: null, value: null,
}, },
/** Pincode or passkey value, used to trigger connect enabled changes. */ /**
pinOrPass: String, * May be set by the host to show a pairing error result, or may be
* set by the dialog if a pairing or connect error occured.
* @private
*/
errorMessage_: String,
/** /**
* Interface for bluetoothPrivate calls. Set in bluetooth-page. * Pincode or passkey value, used to trigger connect enabled changes.
* @type {BluetoothPrivate}
* @private * @private
*/ */
bluetoothPrivate: { pinOrPass_: String,
type: Object,
value: chrome.bluetoothPrivate,
},
/** /**
* @const * @const {!Array<number>}
* @type {!Array<number>} * @private
*/ */
digits: { digits_: {
type: Array, type: Array,
readOnly: true, readOnly: true,
value: [0, 1, 2, 3, 4, 5], value: [0, 1, 2, 3, 4, 5],
...@@ -52,16 +79,100 @@ settings.BluetoothPairDeviceBehavior = { ...@@ -52,16 +79,100 @@ settings.BluetoothPairDeviceBehavior = {
}, },
observers: [ observers: [
'dialogUpdated_(errorMessage_, pairingEvent_)',
'pairingChanged_(pairingDevice, pairingEvent_)', 'pairingChanged_(pairingDevice, pairingEvent_)',
], ],
/** /**
* Listener for chrome.bluetoothPrivate.onPairing events. * Listener for chrome.bluetoothPrivate.onPairing events.
* @type {?function(!chrome.bluetoothPrivate.PairingEvent)} * @private {?function(!chrome.bluetoothPrivate.PairingEvent)}
* @private
*/ */
bluetoothPrivateOnPairingListener_: null, bluetoothPrivateOnPairingListener_: null,
/**
* Listener for chrome.bluetooth.onBluetoothDeviceChanged events.
* @private {?function(!chrome.bluetooth.Device)}
*/
bluetoothDeviceChangedListener_: null,
open: function() {
this.startPairing();
this.pinOrPass_ = '';
this.getDialog_().showModal();
this.itemWasFocused_ = false;
},
close: function() {
this.endPairing();
var dialog = this.getDialog_();
if (dialog.open)
dialog.close();
},
/**
* Updates the dialog after a connect attempt.
* @param {!chrome.bluetooth.Device} device The device connected to
* @param {!{message: string}} lastError chrome.runtime.lastError
* @param {chrome.bluetoothPrivate.ConnectResultType} result The connect
* result
* @return {boolean}
*/
handleError: function(device, lastError, result) {
var error;
if (lastError) {
error = lastError.message;
} else {
switch (result) {
case chrome.bluetoothPrivate.ConnectResultType.IN_PROGRESS:
case chrome.bluetoothPrivate.ConnectResultType.ALREADY_CONNECTED:
case chrome.bluetoothPrivate.ConnectResultType.AUTH_CANCELED:
case chrome.bluetoothPrivate.ConnectResultType.SUCCESS:
this.errorMessage_ = '';
return false;
default:
error = result;
}
}
var name = device.name || device.address;
var id = 'bluetooth_connect_' + error;
if (this.i18nExists(id)) {
this.errorMessage_ = this.i18n(id, name);
} else {
this.errorMessage_ = error;
console.error('Unexpected error connecting to: ' + name + ': ' + error);
}
return true;
},
/** @private */
dialogUpdated_: function() {
if (this.showEnterPincode_())
this.$$('#pincode').focus();
else if (this.showEnterPasskey_())
this.$$('#passkey').focus();
},
/**
* @return {!CrDialogElement}
* @private
*/
getDialog_: function() {
return /** @type {!CrDialogElement} */ (this.$.dialog);
},
/** @private */
onCancelTap_: function() {
this.getDialog_().cancel();
},
/** @private */
onDialogCanceled_: function() {
if (!this.errorMessage_)
this.sendResponse_(chrome.bluetoothPrivate.PairingResponse.CANCEL);
this.endPairing();
},
/** Called when the dialog is opened. Starts listening for pairing events. */ /** Called when the dialog is opened. Starts listening for pairing events. */
startPairing: function() { startPairing: function() {
if (!this.bluetoothPrivateOnPairingListener_) { if (!this.bluetoothPrivateOnPairingListener_) {
...@@ -70,6 +181,12 @@ settings.BluetoothPairDeviceBehavior = { ...@@ -70,6 +181,12 @@ settings.BluetoothPairDeviceBehavior = {
this.bluetoothPrivate.onPairing.addListener( this.bluetoothPrivate.onPairing.addListener(
this.bluetoothPrivateOnPairingListener_); this.bluetoothPrivateOnPairingListener_);
} }
if (!this.bluetoothDeviceChangedListener_) {
this.bluetoothDeviceChangedListener_ =
this.onBluetoothDeviceChanged_.bind(this);
this.bluetooth.onDeviceChanged.addListener(
this.bluetoothDeviceChangedListener_);
}
}, },
/** Called when the dialog is closed. */ /** Called when the dialog is closed. */
...@@ -79,6 +196,11 @@ settings.BluetoothPairDeviceBehavior = { ...@@ -79,6 +196,11 @@ settings.BluetoothPairDeviceBehavior = {
this.bluetoothPrivateOnPairingListener_); this.bluetoothPrivateOnPairingListener_);
this.bluetoothPrivateOnPairingListener_ = null; this.bluetoothPrivateOnPairingListener_ = null;
} }
if (this.bluetoothDeviceChangedListener_) {
this.bluetooth.onDeviceChanged.removeListener(
this.bluetoothDeviceChangedListener_);
this.bluetoothDeviceChangedListener_ = null;
}
this.pairingEvent_ = null; this.pairingEvent_ = null;
}, },
...@@ -101,6 +223,18 @@ settings.BluetoothPairDeviceBehavior = { ...@@ -101,6 +223,18 @@ settings.BluetoothPairDeviceBehavior = {
this.pairingEvent_ = event; this.pairingEvent_ = event;
}, },
/**
* Process bluetooth.onDeviceChanged events. This ensures that the dialog
* updates when the connection state changes.
* @param {!chrome.bluetooth.Device} device
* @private
*/
onBluetoothDeviceChanged_: function(device) {
if (!this.pairingDevice || device.address != this.pairingDevice.address)
return;
this.pairingDevice = device;
},
/** @private */ /** @private */
pairingChanged_: function() { pairingChanged_: function() {
// Auto-close the dialog when pairing completes. // Auto-close the dialog when pairing completes.
...@@ -109,7 +243,8 @@ settings.BluetoothPairDeviceBehavior = { ...@@ -109,7 +243,8 @@ settings.BluetoothPairDeviceBehavior = {
this.close(); this.close();
return; return;
} }
this.pinOrPass = ''; this.errorMessage_ = '';
this.pinOrPass_ = '';
}, },
/** /**
...@@ -313,7 +448,7 @@ settings.BluetoothPairDeviceBehavior = { ...@@ -313,7 +448,7 @@ settings.BluetoothPairDeviceBehavior = {
this.pairingEvent_.pairing == PairingEventType.KEYS_ENTERED && this.pairingEvent_.pairing == PairingEventType.KEYS_ENTERED &&
this.pairingEvent_.enteredKey) { this.pairingEvent_.enteredKey) {
var enteredKey = this.pairingEvent_.enteredKey; // 1-7 var enteredKey = this.pairingEvent_.enteredKey; // 1-7
var lastKey = this.digits.length; // 6 var lastKey = this.digits_.length; // 6
if ((index == -1 && enteredKey > lastKey) || (index + 1 == enteredKey)) if ((index == -1 && enteredKey > lastKey) || (index + 1 == enteredKey))
cssClass += ' next'; cssClass += ' next';
else if (index > enteredKey) else if (index > enteredKey)
...@@ -321,73 +456,4 @@ settings.BluetoothPairDeviceBehavior = { ...@@ -321,73 +456,4 @@ settings.BluetoothPairDeviceBehavior = {
} }
return cssClass; return cssClass;
}, },
};
Polymer({
is: 'bluetooth-device-dialog',
behaviors: [I18nBehavior, settings.BluetoothPairDeviceBehavior],
properties: {
/**
* The version of this dialog to show: 'pairDevice', or 'connectError'.
* Must be set before the dialog is opened.
*/
dialogId: String,
},
observers: [
'dialogUpdated_(dialogId, pairingEvent_)',
],
open: function() {
this.startPairing();
this.pinOrPass = '';
this.getDialog_().showModal();
this.itemWasFocused_ = false;
},
close: function() {
this.endPairing();
var dialog = this.getDialog_();
if (dialog.open)
dialog.close();
},
/** @private */
dialogUpdated_: function() {
if (this.showEnterPincode_())
this.$$('#pincode').focus();
else if (this.showEnterPasskey_())
this.$$('#passkey').focus();
},
/**
* @return {!CrDialogElement}
* @private
*/
getDialog_: function() {
return /** @type {!CrDialogElement} */ (this.$.dialog);
},
/**
* @param {string} desiredDialogType
* @return {boolean}
* @private
*/
isDialogType_: function(desiredDialogType, currentDialogType) {
return currentDialogType == desiredDialogType;
},
/** @private */
onCancelTap_: function() {
this.getDialog_().cancel();
},
/** @private */
onDialogCanceled_: function() {
if (this.dialogId == 'pairDevice')
this.sendResponse_(chrome.bluetoothPrivate.PairingResponse.CANCEL);
this.endPairing();
},
}); });
# Copyright 2017 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.
{
'targets': [
{
'target_name': 'bluetooth_dialog',
'dependencies': [
'<(DEPTH)/ui/webui/resources/cr_elements/cr_dialog/compiled_resources2.gyp:cr_dialog',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
'<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/compiled_resources2.gyp:iron-resizable-behavior-extracted',
'<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-input/compiled_resources2.gyp:paper-input-extracted',
'<(EXTERNS_GYP):bluetooth',
'<(EXTERNS_GYP):bluetooth_private',
'<(INTERFACES_GYP):bluetooth_interface',
'<(INTERFACES_GYP):bluetooth_private_interface',
],
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
},
],
}
<?xml version="1.0" encoding="utf-8"?>
<grit-part>
<!-- Chrome OS Custom Elements -->
<structure name="IDR_WEBUI_CHROMEOS_BLUETOOTH_DIALOG_HTML"
file="chromeos/bluetooth_dialog.html"
type="chrome_html" />
<structure name="IDR_WEBUI_CHROMEOS_BLUETOOTH_DIALOG_JS"
file="chromeos/bluetooth_dialog.js"
type="chrome_html" />
</grit-part>
...@@ -511,6 +511,9 @@ without changes to the corresponding grd file. --> ...@@ -511,6 +511,9 @@ without changes to the corresponding grd file. -->
<part file="cr_elements_resources.grdp" /> <part file="cr_elements_resources.grdp" />
<part file="polymer_resources.grdp" /> <part file="polymer_resources.grdp" />
</if> </if>
<if expr="chromeos">
<part file="chromeos_elements_resources.grdp" />
</if>
</structures> </structures>
</release> </release>
</grit> </grit>
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