Chromium Code Reviews| Index: chrome/browser/resources/bluetooth_internals/device_details_page.js |
| diff --git a/chrome/browser/resources/bluetooth_internals/device_details_page.js b/chrome/browser/resources/bluetooth_internals/device_details_page.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f54db036f2ca427bbacf03666b68f79dab5a50ad |
| --- /dev/null |
| +++ b/chrome/browser/resources/bluetooth_internals/device_details_page.js |
| @@ -0,0 +1,210 @@ |
| +// 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. |
| + |
| +/** |
| + * Javascript for DeviceDetailsPage which displays all of the details of a |
| + * device. The page is generated and managed dynamically in bluetooth_internals. |
| + * served from chrome://bluetooth-internals/. |
| + */ |
| + |
| +cr.define('device_details_page', function() { |
| + /** @const */ var Page = cr.ui.pageManager.Page; |
| + /** @const */ var Snackbar = snackbar.Snackbar; |
| + /** @const */ var SnackbarType = snackbar.SnackbarType; |
| + |
| + /** |
| + * Property names that will be displayed in the ObjectFieldSet which contains |
| + * the DeviceInfo object. |
| + */ |
| + var PROPERTY_NAMES = { |
| + name: 'Name', |
| + address: 'Address', |
| + is_gatt_connected: 'GATT Connected', |
| + 'rssi.value': 'Latest RSSI', |
| + 'services.length': 'Services', |
| + }; |
| + |
| + /** |
| + * Page that displays all of the details of a device. This page is generated |
| + * and managed dynamically in bluetooth_internals. This page is the owner of |
| + * the DevicePtr when a connection is created. Therefore, it manages the |
| + * connection to the Bluetooth device and performs all Device interface |
| + * related actions. |
| + * @constructor |
| + * @param {string} id |
| + * @param {!interfaces.BluetoothDevice.DeviceInfo} deviceInfo |
| + * @extends {cr.ui.pageManager.Page} |
| + */ |
| + function DeviceDetailsPage(id, deviceInfo) { |
| + Page.call(this, id, deviceInfo.name_for_display, id); |
| + |
| + this.deviceInfo = deviceInfo; |
| + |
| + /** @type {interfaces.BluetoothDevice.Device.ptrClass} */ |
| + this.devicePtr = null; |
| + /** @private {!device_collection.ConnectionStatus} */ |
| + this.status_ = device_collection.ConnectionStatus.DISCONNECTED; |
| + |
| + this.pageDiv.appendChild( |
| + document.importNode($('device-details-template').content, |
| + true /* deep */)); |
| + |
| + this.pageDiv.querySelector('.forget-btn').addEventListener('click', |
| + function() { |
| + this.disconnect(); |
| + this.pageDiv.dispatchEvent(new CustomEvent('forgetpressed', { |
| + detail: { |
| + address: this.deviceInfo.address, |
| + }, |
| + })); |
| + }.bind(this)); |
| + |
| + this.disconnectBtn_ = this.pageDiv.querySelector('.disconnect-btn'); |
| + this.disconnectBtn_.addEventListener('click', function() { |
| + if (this.devicePtr) { |
| + this.disconnect(); |
| + return; |
| + } |
| + this.connect(); |
| + }.bind(this)); |
| + |
| + this.deviceFieldSet = new object_fieldset.ObjectFieldSet(); |
| + this.deviceFieldSet.setPropertyDisplayNames(PROPERTY_NAMES); |
| + this.pageDiv.querySelector('.device-details').appendChild( |
| + this.deviceFieldSet); |
| + |
| + this.redraw(); |
| + } |
| + |
| + DeviceDetailsPage.prototype = { |
| + __proto__: Page.prototype, |
| + |
| + /** Creates a connection to the Bluetooth device. */ |
| + connect: function() { |
| + if (this.status_ !== device_collection.ConnectionStatus.DISCONNECTED) |
| + return; |
| + |
| + this.updateConnectionStatus_( |
| + device_collection.ConnectionStatus.CONNECTING); |
| + this.connecting_ = true; |
| + |
| + adapter_broker.getAdapterBroker().then(function(adapterBroker) { |
| + adapterBroker.connectToDevice(this.deviceInfo.address).then( |
| + function(devicePtr) { |
| + this.devicePtr = devicePtr; |
| + |
| + this.updateConnectionStatus_( |
| + device_collection.ConnectionStatus.CONNECTED); |
| + |
| + // Fetch services asynchronously. |
| + return this.devicePtr.getServices(); |
| + }.bind(this)).then(function(response) { |
| + this.deviceInfo.services = response.services; |
| + this.redraw(); |
| + this.fireDeviceInfoChanged_(); |
| + }.bind(this)).catch(function(error) { |
| + // If a connection error occurs while fetching the services, the |
| + // devicePtr reference must be removed. |
| + if (this.devicePtr) { |
| + this.devicePtr.disconnect(); |
| + this.devicePtr = null; |
| + } |
| + |
| + Snackbar.show( |
| + this.deviceInfo.name_for_display + ': ' + error.message, |
| + SnackbarType.DANGER, 'Retry', function() { |
| + this.connect(); |
| + }.bind(this)); |
| + |
| + this.updateConnectionStatus_( |
| + device_collection.ConnectionStatus.DISCONNECTED); |
| + }.bind(this)); |
| + }.bind(this)); |
| + }, |
| + |
| + /** Disconnects the page from the Bluetooth device. */ |
| + disconnect: function() { |
| + if (!this.devicePtr) return; |
| + |
| + this.devicePtr.disconnect(); |
| + this.devicePtr = null; |
| + this.updateConnectionStatus_( |
| + device_collection.ConnectionStatus.DISCONNECTED); |
| + }, |
| + |
| + /** Redraws the contents of the page with the current |deviceInfo|. */ |
| + redraw: function() { |
| + var isConnected = this.deviceInfo.is_gatt_connected; |
| + |
| + // Update status if connection was dropped. |
| + if (!isConnected) this.disconnect(); |
|
scheib
2017/01/11 02:16:14
This condition seems odd here, it's not really par
mbrunson
2017/01/11 21:22:59
It's general maintenance. Redraw is called when th
|
| + var connectedText = isConnected ? 'Connected' : 'Not Connected'; |
| + |
| + var rssi = this.deviceInfo.rssi; |
| + var services = this.deviceInfo.services; |
| + |
| + var deviceViewObj = { |
| + name: this.deviceInfo.name_for_display, |
| + address: this.deviceInfo.address, |
| + is_gatt_connected: connectedText, |
| + 'rssi.value': (rssi && rssi.value) || 'Unknown', |
| + 'services.length': (services && services.length) || 'Unknown', |
| + }; |
| + |
| + this.deviceFieldSet.setObject(deviceViewObj); |
| + }, |
| + |
| + /** |
| + * Sets the page's device info and forces a redraw. |
| + * @param {!interfaces.BluetoothDevice.DeviceInfo} |
| + */ |
| + setDeviceInfo: function(info) { |
| + this.deviceInfo = info; |
| + this.redraw(); |
| + }, |
| + |
| + /** Fires an 'infochanged' event with the current |deviceInfo| */ |
| + fireDeviceInfoChanged_: function() { |
| + this.pageDiv.dispatchEvent(new CustomEvent('infochanged', { |
| + bubbles: true, |
| + detail: { |
| + info: this.deviceInfo, |
| + }, |
| + })); |
| + }, |
| + |
| + /** |
| + * Updates the current connection status. Caches the latest status, updates |
| + * the connection button message, and fires a 'connectionchanged' event when |
| + * finished. |
| + * @param {!device_collection.ConnectionStatus} status |
| + * @param {Error=} opt_error |
| + */ |
| + updateConnectionStatus_: function(status) { |
| + this.status_ = status; |
| + if (status === device_collection.ConnectionStatus.DISCONNECTED) { |
| + this.disconnectBtn_.textContent = 'Connect'; |
| + this.disconnectBtn_.disabled = false; |
| + } else if (status === device_collection.ConnectionStatus.CONNECTING) { |
| + this.disconnectBtn_.textContent = 'Connecting'; |
| + this.disconnectBtn_.disabled = true; |
| + } else { |
| + this.disconnectBtn_.textContent = 'Disconnect'; |
| + this.disconnectBtn_.disabled = false; |
| + } |
| + |
| + this.pageDiv.dispatchEvent(new CustomEvent('connectionchanged', { |
| + bubbles: true, |
| + detail: { |
| + address: this.deviceInfo.address, |
| + status: status, |
| + } |
| + })); |
| + }, |
| + }; |
| + |
| + return { |
| + DeviceDetailsPage: DeviceDetailsPage, |
| + }; |
| +}); |