OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * Javascript for DeviceDetailsPage which displays all of the details of a |
| 7 * device. The page is generated and managed dynamically in bluetooth_internals. |
| 8 * served from chrome://bluetooth-internals/. |
| 9 */ |
| 10 |
| 11 cr.define('device_details_page', function() { |
| 12 /** @const */ var Page = cr.ui.pageManager.Page; |
| 13 /** @const */ var Snackbar = snackbar.Snackbar; |
| 14 /** @const */ var SnackbarType = snackbar.SnackbarType; |
| 15 |
| 16 /** |
| 17 * Property names that will be displayed in the ObjectFieldSet which contains |
| 18 * the DeviceInfo object. |
| 19 */ |
| 20 var PROPERTY_NAMES = { |
| 21 name: 'Name', |
| 22 address: 'Address', |
| 23 is_gatt_connected: 'GATT Connected', |
| 24 'rssi.value': 'Latest RSSI', |
| 25 'services.length': 'Services', |
| 26 }; |
| 27 |
| 28 /** |
| 29 * Page that displays all of the details of a device. This page is generated |
| 30 * and managed dynamically in bluetooth_internals. This page is the owner of |
| 31 * the DevicePtr when a connection is created. Therefore, it manages the |
| 32 * connection to the Bluetooth device and performs all Device interface |
| 33 * related actions. |
| 34 * @constructor |
| 35 * @param {string} id |
| 36 * @param {!interfaces.BluetoothDevice.DeviceInfo} deviceInfo |
| 37 * @extends {cr.ui.pageManager.Page} |
| 38 */ |
| 39 function DeviceDetailsPage(id, deviceInfo) { |
| 40 Page.call(this, id, deviceInfo.name_for_display, id); |
| 41 |
| 42 /** @type {interfaces.BluetoothDevice.DeviceInfo} */ |
| 43 this.deviceInfo = deviceInfo; |
| 44 |
| 45 /** @type {interfaces.BluetoothDevice.Device.ptrClass} */ |
| 46 this.devicePtr = null; |
| 47 |
| 48 /** @type {!object_fieldset.ObjectFieldSet} */ |
| 49 this.deviceFieldSet = new object_fieldset.ObjectFieldSet(); |
| 50 this.deviceFieldSet.setPropertyDisplayNames(PROPERTY_NAMES); |
| 51 |
| 52 /** @private {!device_collection.ConnectionStatus} */ |
| 53 this.status_ = device_collection.ConnectionStatus.DISCONNECTED; |
| 54 |
| 55 /** @private {?HTMLElement} */ |
| 56 this.connectBtn_ = null; |
| 57 |
| 58 this.pageDiv.appendChild( |
| 59 document.importNode($('device-details-template').content, |
| 60 true /* deep */)); |
| 61 |
| 62 this.pageDiv.querySelector('.device-details').appendChild( |
| 63 this.deviceFieldSet); |
| 64 |
| 65 this.pageDiv.querySelector('.forget').addEventListener( |
| 66 'click', function() { |
| 67 this.disconnect(); |
| 68 this.pageDiv.dispatchEvent(new CustomEvent('forgetpressed', { |
| 69 detail: { |
| 70 address: this.deviceInfo.address, |
| 71 }, |
| 72 })); |
| 73 }.bind(this)); |
| 74 |
| 75 this.connectBtn_ = this.pageDiv.querySelector('.disconnect'); |
| 76 this.connectBtn_.addEventListener('click', function() { |
| 77 this.devicePtr !== null ? this.disconnect() : this.connect(); |
| 78 }.bind(this)); |
| 79 |
| 80 this.redraw(); |
| 81 } |
| 82 |
| 83 DeviceDetailsPage.prototype = { |
| 84 __proto__: Page.prototype, |
| 85 |
| 86 /** Creates a connection to the Bluetooth device. */ |
| 87 connect: function() { |
| 88 if (this.status_ !== device_collection.ConnectionStatus.DISCONNECTED) |
| 89 return; |
| 90 |
| 91 this.updateConnectionStatus_( |
| 92 device_collection.ConnectionStatus.CONNECTING); |
| 93 |
| 94 adapter_broker.getAdapterBroker().then(function(adapterBroker) { |
| 95 return adapterBroker.connectToDevice(this.deviceInfo.address); |
| 96 }.bind(this)).then(function(devicePtr) { |
| 97 this.devicePtr = devicePtr; |
| 98 |
| 99 this.updateConnectionStatus_( |
| 100 device_collection.ConnectionStatus.CONNECTED); |
| 101 |
| 102 // Fetch services asynchronously. |
| 103 return this.devicePtr.getServices(); |
| 104 }.bind(this)).then(function(response) { |
| 105 this.deviceInfo.services = response.services; |
| 106 this.redraw(); |
| 107 this.fireDeviceInfoChanged_(); |
| 108 }.bind(this)).catch(function(error) { |
| 109 // If a connection error occurs while fetching the services, the |
| 110 // devicePtr reference must be removed. |
| 111 if (this.devicePtr) { |
| 112 this.devicePtr.disconnect(); |
| 113 this.devicePtr = null; |
| 114 } |
| 115 |
| 116 Snackbar.show( |
| 117 this.deviceInfo.name_for_display + ': ' + error.message, |
| 118 SnackbarType.DANGER, 'Retry', this.connect.bind(this)); |
| 119 |
| 120 this.updateConnectionStatus_( |
| 121 device_collection.ConnectionStatus.DISCONNECTED); |
| 122 }.bind(this)); |
| 123 }, |
| 124 |
| 125 /** Disconnects the page from the Bluetooth device. */ |
| 126 disconnect: function() { |
| 127 if (!this.devicePtr) return; |
| 128 |
| 129 this.devicePtr.disconnect(); |
| 130 this.devicePtr = null; |
| 131 this.updateConnectionStatus_( |
| 132 device_collection.ConnectionStatus.DISCONNECTED); |
| 133 }, |
| 134 |
| 135 /** Redraws the contents of the page with the current |deviceInfo|. */ |
| 136 redraw: function() { |
| 137 var isConnected = this.deviceInfo.is_gatt_connected; |
| 138 |
| 139 // Update status if connection was dropped. |
| 140 if (!isConnected) this.disconnect(); |
| 141 var connectedText = isConnected ? 'Connected' : 'Not Connected'; |
| 142 |
| 143 var rssi = this.deviceInfo.rssi || {}; |
| 144 var services = this.deviceInfo.services; |
| 145 |
| 146 var rssiValue = 'Unknown'; |
| 147 if (rssi.value != null && rssi.value <= 0) |
| 148 rssiValue = rssi.value; |
| 149 |
| 150 var serviceCount = 'Unknown'; |
| 151 if (services != null && services.length >= 0) |
| 152 serviceCount = services.length; |
| 153 |
| 154 var deviceViewObj = { |
| 155 name: this.deviceInfo.name_for_display, |
| 156 address: this.deviceInfo.address, |
| 157 is_gatt_connected: connectedText, |
| 158 'rssi.value': rssiValue, |
| 159 'services.length': serviceCount, |
| 160 }; |
| 161 |
| 162 this.deviceFieldSet.setObject(deviceViewObj); |
| 163 }, |
| 164 |
| 165 /** |
| 166 * Sets the page's device info and forces a redraw. |
| 167 * @param {!interfaces.BluetoothDevice.DeviceInfo} |
| 168 */ |
| 169 setDeviceInfo: function(info) { |
| 170 this.deviceInfo = info; |
| 171 this.redraw(); |
| 172 }, |
| 173 |
| 174 /** |
| 175 * Fires an 'infochanged' event with the current |deviceInfo| |
| 176 * @private |
| 177 */ |
| 178 fireDeviceInfoChanged_: function() { |
| 179 this.pageDiv.dispatchEvent(new CustomEvent('infochanged', { |
| 180 bubbles: true, |
| 181 detail: { |
| 182 info: this.deviceInfo, |
| 183 }, |
| 184 })); |
| 185 }, |
| 186 |
| 187 /** |
| 188 * Updates the current connection status. Caches the latest status, updates |
| 189 * the connection button message, and fires a 'connectionchanged' event when |
| 190 * finished. |
| 191 * @param {!device_collection.ConnectionStatus} status |
| 192 * @private |
| 193 */ |
| 194 updateConnectionStatus_: function(status) { |
| 195 if (this.status === status) |
| 196 return; |
| 197 |
| 198 this.status_ = status; |
| 199 if (status === device_collection.ConnectionStatus.DISCONNECTED) { |
| 200 this.connectBtn_.textContent = 'Connect'; |
| 201 this.connectBtn_.disabled = false; |
| 202 } else if (status === device_collection.ConnectionStatus.CONNECTING) { |
| 203 this.connectBtn_.textContent = 'Connecting'; |
| 204 this.connectBtn_.disabled = true; |
| 205 } else { |
| 206 this.connectBtn_.textContent = 'Disconnect'; |
| 207 this.connectBtn_.disabled = false; |
| 208 } |
| 209 |
| 210 this.pageDiv.dispatchEvent(new CustomEvent('connectionchanged', { |
| 211 bubbles: true, |
| 212 detail: { |
| 213 address: this.deviceInfo.address, |
| 214 status: status, |
| 215 } |
| 216 })); |
| 217 }, |
| 218 }; |
| 219 |
| 220 return { |
| 221 DeviceDetailsPage: DeviceDetailsPage, |
| 222 }; |
| 223 }); |
OLD | NEW |