Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(376)

Side by Side Diff: chrome/browser/resources/bluetooth_internals/bluetooth_internals.js

Issue 2576603002: bluetooth: Add device details page with basic properties to internals page. (Closed)
Patch Set: Fix formatting, fix comments, fix test, change service/rssi display Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * Javascript for bluetooth_internals.html, served from 6 * Javascript for bluetooth_internals.html, served from
7 * chrome://bluetooth-internals/. 7 * chrome://bluetooth-internals/.
8 */ 8 */
9 9
10 // Expose for testing. 10 // Expose for testing.
11 /** @type {adapter_broker.AdapterBroker} */
11 var adapterBroker = null; 12 var adapterBroker = null;
13 /** @type {device_collection.DeviceCollection} */
12 var devices = null; 14 var devices = null;
15 /** @type {sidebar.Sidebar} */
13 var sidebarObj = null; 16 var sidebarObj = null;
14 17
15 cr.define('bluetooth_internals', function() { 18 cr.define('bluetooth_internals', function() {
16 /** @const */ var AdapterPage = adapter_page.AdapterPage; 19 /** @const */ var AdapterPage = adapter_page.AdapterPage;
20 /** @const */ var DeviceDetailsPage = device_details_page.DeviceDetailsPage;
17 /** @const */ var DevicesPage = devices_page.DevicesPage; 21 /** @const */ var DevicesPage = devices_page.DevicesPage;
18 /** @const */ var PageManager = cr.ui.pageManager.PageManager; 22 /** @const */ var PageManager = cr.ui.pageManager.PageManager;
19 /** @const */ var Snackbar = snackbar.Snackbar; 23 /** @const */ var Snackbar = snackbar.Snackbar;
20 /** @const */ var SnackbarType = snackbar.SnackbarType; 24 /** @const */ var SnackbarType = snackbar.SnackbarType;
21 25
26 devices = new device_collection.DeviceCollection([]);
27
28 /** @type {adapter_page.AdapterPage} */
29 var adapterPage = null;
30 /** @type {devices_page.DevicesPage} */
31 var devicesPage = null;
32
33 /** @type {interfaces.BluetoothAdapter.DiscoverySession.ptrClass} */
34 var discoverySession = null;
35
36 /** @type {boolean} */
37 var userRequestedScanStop = false;
38
22 /** 39 /**
23 * Observer for page changes. Used to update page title header. 40 * Observer for page changes. Used to update page title header.
24 * @extends {cr.ui.pageManager.PageManager.Observer} 41 * @extends {cr.ui.pageManager.PageManager.Observer}
25 */ 42 */
26 var PageObserver = function() {}; 43 var PageObserver = function() {};
27 44
28 PageObserver.prototype = { 45 PageObserver.prototype = {
29 __proto__: PageManager.Observer.prototype, 46 __proto__: PageManager.Observer.prototype,
30 47
31 updateHistory: function(path) { 48 updateHistory: function(path) {
32 window.location.hash = '#' + path; 49 window.location.hash = '#' + path;
33 }, 50 },
34 51
35 /** 52 /**
36 * Sets the page title. Called by PageManager. 53 * Sets the page title. Called by PageManager.
37 * @override 54 * @override
38 * @param {string} title 55 * @param {string} title
39 */ 56 */
40 updateTitle: function(title) { 57 updateTitle: function(title) {
41 document.querySelector('.page-title').textContent = title; 58 document.querySelector('.page-title').textContent = title;
42 }, 59 },
43 }; 60 };
44 61
45 /** @type {!Map<string, !interfaces.BluetoothDevice.DevicePtr>} */ 62 /**
46 var deviceAddressToProxy = new Map(); 63 * Removes DeviceDetailsPage with matching device |address|. The associated
64 * sidebar item is also removed.
65 * @param {string} address
66 */
67 function removeDeviceDetailsPage(address) {
68 var id = 'devices/' + address.toLowerCase();
69 sidebarObj.removeItem(id);
47 70
48 /** @type {!device_collection.DeviceCollection} */ 71 var deviceDetailsPage = PageManager.registeredPages[id];
49 devices = new device_collection.DeviceCollection([]); 72 assert(deviceDetailsPage, 'Device Details page must exist');
50 73
51 /** @type {adapter_page.AdapterPage} */ 74 deviceDetailsPage.disconnect();
52 var adapterPage = null; 75 deviceDetailsPage.pageDiv.parentNode.removeChild(deviceDetailsPage.pageDiv);
53 /** @type {devices_page.DevicesPage} */
54 var devicesPage = null;
55 76
56 /** @type {interfaces.BluetoothAdapter.DiscoverySession.ptrClass} */ 77 // Inform the devices page that the user is inspecting this device.
57 var discoverySession = null; 78 // This will update the links in the device table.
79 devicesPage.setInspecting(
80 deviceDetailsPage.deviceInfo, false /* isInspecting */);
58 81
59 /** @type {boolean} */ 82 PageManager.unregister(deviceDetailsPage);
60 var userRequestedScanStop = false; 83 }
61 84
62 function handleInspect(event) { 85 /**
63 // TODO(crbug.com/663470): Move connection logic to DeviceDetailsView 86 * Creates a DeviceDetailsPage with the given |deviceInfo|, appends it to
64 // when it's added in chrome://bluetooth-internals. 87 * '#page-container', and adds a sidebar item to show the new page. If a
65 var address = event.detail.address; 88 * page exists that matches |deviceInfo.address|, nothing is created and the
66 var proxy = deviceAddressToProxy.get(address); 89 * existing page is returned.
90 * @param {!interfaces.BluetoothDevice.Device} deviceInfo
91 * @return {!device_details_page.DeviceDetailsPage}
92 */
93 function makeDeviceDetailsPage(deviceInfo) {
94 var deviceDetailsPageId = 'devices/' + deviceInfo.address.toLowerCase();
95 var deviceDetailsPage = PageManager.registeredPages[deviceDetailsPageId];
96 if (deviceDetailsPage) return deviceDetailsPage;
67 97
68 if (proxy) { 98 var pageSection = document.createElement('section');
69 // Device is already connected, so disconnect. 99 pageSection.hidden = true;
70 proxy.disconnect(); 100 pageSection.id = deviceDetailsPageId;
71 deviceAddressToProxy.delete(address); 101 $('page-container').appendChild(pageSection);
72 devices.updateConnectionStatus(
73 address, device_collection.ConnectionStatus.DISCONNECTED);
74 return;
75 }
76 102
77 devices.updateConnectionStatus( 103 deviceDetailsPage = new DeviceDetailsPage(deviceDetailsPageId, deviceInfo);
78 address, device_collection.ConnectionStatus.CONNECTING); 104 deviceDetailsPage.pageDiv.addEventListener('connectionchanged',
105 function(event) {
106 devices.updateConnectionStatus(
107 event.detail.address, event.detail.status);
108 });
79 109
80 adapterBroker.connectToDevice(address).then(function(deviceProxy) { 110 deviceDetailsPage.pageDiv.addEventListener('infochanged', function(event) {
81 var deviceInfo = devices.getByAddress(address); 111 devices.addOrUpdate(event.detail.info);
82 if (!deviceInfo) { 112 });
83 // Device no longer in list, so drop the connection.
84 deviceProxy.disconnect();
85 return;
86 }
87 113
88 deviceAddressToProxy.set(address, deviceProxy); 114 deviceDetailsPage.pageDiv.addEventListener('forgetpressed',
89 devices.updateConnectionStatus( 115 function(event) {
90 address, device_collection.ConnectionStatus.CONNECTED); 116 PageManager.showPageByName(devicesPage.name);
91 Snackbar.show(deviceInfo.name_for_display + ': Connected', 117 removeDeviceDetailsPage(event.detail.address);
92 SnackbarType.SUCCESS); 118 });
93 119
94 // Fetch services asynchronously. 120 // Inform the devices page that the user is inspecting this device.
95 return deviceProxy.getServices(); 121 // This will update the links in the device table.
96 }).then(function(response) { 122 devicesPage.setInspecting(deviceInfo, true /* isInspecting */);
97 if (!response) return; 123 PageManager.register(deviceDetailsPage);
98 124
99 var deviceInfo = devices.getByAddress(address); 125 sidebarObj.addItem({
100 deviceInfo.services = response.services; 126 pageName: deviceDetailsPageId,
101 devices.addOrUpdate(deviceInfo); 127 text: deviceInfo.name_for_display,
102 }).catch(function(error) { 128 });
103 // If a connection error occurs while fetching the services, the proxy
104 // reference must be removed.
105 var proxy = deviceAddressToProxy.get(address);
106 if (proxy) {
107 proxy.disconnect();
108 deviceAddressToProxy.delete(address);
109 }
110 129
111 devices.updateConnectionStatus( 130 deviceDetailsPage.connect();
112 address, device_collection.ConnectionStatus.DISCONNECTED); 131 return deviceDetailsPage;
132 }
113 133
114 var deviceInfo = devices.getByAddress(address); 134 /**
115 Snackbar.show(deviceInfo.name_for_display + ': ' + error.message, 135 * Updates the DeviceDetailsPage with the matching device |address| and
116 SnackbarType.ERROR, 'Retry', function() { handleInspect(event); }); 136 * redraws it.
117 }); 137 * @param {string} address
138 */
139 function updateDeviceDetailsPage(address) {
140 var detailPageId = 'devices/' + address.toLowerCase();
141 var page = PageManager.registeredPages[detailPageId];
142 if (page) page.redraw();
118 } 143 }
119 144
120 function updateStoppedDiscoverySession() { 145 function updateStoppedDiscoverySession() {
121 devicesPage.setScanStatus(devices_page.ScanStatus.OFF); 146 devicesPage.setScanStatus(devices_page.ScanStatus.OFF);
122 discoverySession.ptr.reset(); 147 discoverySession.ptr.reset();
123 discoverySession = null; 148 discoverySession = null;
124 } 149 }
125 150
126 function setupAdapterSystem(response) { 151 function setupAdapterSystem(response) {
127 adapterBroker.addEventListener('adapterchanged', function(event) { 152 adapterBroker.addEventListener('adapterchanged', function(event) {
(...skipping 15 matching lines...) Expand all
143 adapterBroker.getInfo().then(function(response) { 168 adapterBroker.getInfo().then(function(response) {
144 adapterPage.setAdapterInfo(response.info); 169 adapterPage.setAdapterInfo(response.info);
145 }); 170 });
146 }); 171 });
147 } 172 }
148 173
149 function setupDeviceSystem(response) { 174 function setupDeviceSystem(response) {
150 // Hook up device collection events. 175 // Hook up device collection events.
151 adapterBroker.addEventListener('deviceadded', function(event) { 176 adapterBroker.addEventListener('deviceadded', function(event) {
152 devices.addOrUpdate(event.detail.deviceInfo); 177 devices.addOrUpdate(event.detail.deviceInfo);
178 updateDeviceDetailsPage(event.detail.deviceInfo.address);
153 }); 179 });
154 adapterBroker.addEventListener('devicechanged', function(event) { 180 adapterBroker.addEventListener('devicechanged', function(event) {
155 devices.addOrUpdate(event.detail.deviceInfo); 181 devices.addOrUpdate(event.detail.deviceInfo);
182 updateDeviceDetailsPage(event.detail.deviceInfo.address);
156 }); 183 });
157 adapterBroker.addEventListener('deviceremoved', function(event) { 184 adapterBroker.addEventListener('deviceremoved', function(event) {
158 devices.remove(event.detail.deviceInfo); 185 devices.remove(event.detail.deviceInfo);
186 updateDeviceDetailsPage(event.detail.deviceInfo.address);
159 }); 187 });
160 188
161 response.devices.forEach(devices.addOrUpdate, devices /* this */); 189 response.devices.forEach(devices.addOrUpdate, devices /* this */);
162 190
163 devicesPage.setDevices(devices); 191 devicesPage.setDevices(devices);
164 devicesPage.pageDiv.addEventListener('inspectpressed', handleInspect); 192
193 devicesPage.pageDiv.addEventListener('inspectpressed', function(event) {
194 var detailsPage = makeDeviceDetailsPage(
195 devices.getByAddress(event.detail.address));
196 PageManager.showPageByName(detailsPage.name);
197 });
198
199 devicesPage.pageDiv.addEventListener('forgetpressed', function(event) {
200 PageManager.showPageByName(devicesPage.name);
201 removeDeviceDetailsPage(event.detail.address);
202 });
165 203
166 devicesPage.pageDiv.addEventListener('scanpressed', function(event) { 204 devicesPage.pageDiv.addEventListener('scanpressed', function(event) {
167 if (discoverySession && discoverySession.ptr.isBound()) { 205 if (discoverySession && discoverySession.ptr.isBound()) {
168 userRequestedScanStop = true; 206 userRequestedScanStop = true;
169 devicesPage.setScanStatus(devices_page.ScanStatus.STOPPING); 207 devicesPage.setScanStatus(devices_page.ScanStatus.STOPPING);
170 208
171 discoverySession.stop().then(function(response) { 209 discoverySession.stop().then(function(response) {
172 if (response.success) { 210 if (response.success) {
173 updateStoppedDiscoverySession(); 211 updateStoppedDiscoverySession();
174 userRequestedScanStop = false; 212 userRequestedScanStop = false;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 PageManager.addObserver(sidebarObj); 246 PageManager.addObserver(sidebarObj);
209 PageManager.addObserver(new PageObserver()); 247 PageManager.addObserver(new PageObserver());
210 248
211 devicesPage = new DevicesPage(); 249 devicesPage = new DevicesPage();
212 PageManager.register(devicesPage); 250 PageManager.register(devicesPage);
213 adapterPage = new AdapterPage(); 251 adapterPage = new AdapterPage();
214 PageManager.register(adapterPage); 252 PageManager.register(adapterPage);
215 253
216 // Set up hash-based navigation. 254 // Set up hash-based navigation.
217 window.addEventListener('hashchange', function() { 255 window.addEventListener('hashchange', function() {
218 PageManager.showPageByName(window.location.hash.substr(1)); 256 // If a user navigates and the page doesn't exist, do nothing.
257 var pageName = window.location.hash.substr(1);
258 if ($(pageName))
259 PageManager.showPageByName(pageName);
219 }); 260 });
220 261
221 if (!window.location.hash) { 262 if (!window.location.hash) {
222 PageManager.showPageByName(adapterPage.name); 263 PageManager.showPageByName(adapterPage.name);
223 return; 264 return;
224 } 265 }
225 266
226 PageManager.showPageByName(window.location.hash.substr(1)); 267 // Only the root pages are available on page load.
268 PageManager.showPageByName(window.location.hash.split('/')[0].substr(1));
227 } 269 }
228 270
229 function initializeViews() { 271 function initializeViews() {
230 setupPages(); 272 setupPages();
231 273
232 adapter_broker.getAdapterBroker() 274 adapter_broker.getAdapterBroker()
233 .then(function(broker) { adapterBroker = broker; }) 275 .then(function(broker) { adapterBroker = broker; })
234 .then(function() { return adapterBroker.getInfo(); }) 276 .then(function() { return adapterBroker.getInfo(); })
235 .then(setupAdapterSystem) 277 .then(setupAdapterSystem)
236 .then(function() { return adapterBroker.getDevices(); }) 278 .then(function() { return adapterBroker.getDevices(); })
237 .then(setupDeviceSystem) 279 .then(setupDeviceSystem)
238 .catch(function(error) { 280 .catch(function(error) {
239 Snackbar.show(error.message, SnackbarType.ERROR); 281 Snackbar.show(error.message, SnackbarType.ERROR);
240 console.error(error); 282 console.error(error);
241 }); 283 });
242 } 284 }
243 285
244 return { 286 return {
245 initializeViews: initializeViews 287 initializeViews: initializeViews,
246 }; 288 };
247 }); 289 });
248 290
249 document.addEventListener( 291 document.addEventListener(
250 'DOMContentLoaded', bluetooth_internals.initializeViews); 292 'DOMContentLoaded', bluetooth_internals.initializeViews);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698