Commit eb033605 authored by mbrunson's avatar mbrunson Committed by Commit bot

bluetooth: Add device list UI for chrome://bluetooth-internals.

Adds mobile responsive device list to bluetooth internals page.
Lists device name, address, and latest RSSI.
Refreshes when devices are discovered, removed, or advertising packets are received.

Screenshots
Desktop: https://goo.gl/photos/bot7JsdTuf8P2A328
Mobile: https://goo.gl/photos/G9bb9s4ih5KT3PJw8

BUG=651282
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:closure_compilation

Review-Url: https://codereview.chromium.org/2418343002
Cr-Commit-Position: refs/heads/master@{#427261}
parent 97df95a8
...@@ -13,11 +13,83 @@ body { ...@@ -13,11 +13,83 @@ body {
padding: 0; padding: 0;
} }
/* Header bar */
header { header {
background-color: blue; align-items: center;
padding: 2px; background-color: rgb(33, 150, 243);
display: flex;
flex-direction: row;
font-size: 20pt;
height: 56px;
justify-content: flex-start;
padding: 0 16px;
} }
header * { .title {
color: white; color: white;
display: inline-block;
margin-left: 8px;
}
/* Device table */
table {
border: 1px solid #ccc;
border-collapse: collapse;
margin: 0;
padding: 0;
width: 100%;
}
table tr {
border: 1px solid #ddd;
padding: 5px;
}
table th,
table td {
padding: 10px;
text-align: center;
}
table th {
font-size: 14px;
letter-spacing: 1px;
text-transform: uppercase;
}
@media screen and (max-width: 600px) {
table {
border: 0;
}
table thead {
display: none;
}
table tr {
border-bottom: 2px solid #ddd;
display: block;
}
table td {
border-bottom: 1px dotted #ccc;
display: block;
font-size: 13px;
text-align: right;
}
table td:last-child {
border-bottom: 0;
}
table td::before {
content: attr(data-label);
float: left;
font-weight: bold;
text-transform: uppercase;
}
}
/* Device Row */
table .removed {
background-color: #BDBDBD;
} }
\ No newline at end of file
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html>
<!-- TODO(crbug.com/658814): Localize strings. -->
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bluetooth Internals</title> <title>Bluetooth Internals</title>
<link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
<link rel="stylesheet" href="bluetooth_internals.css"> <link rel="stylesheet" href="bluetooth_internals.css">
<script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="bluetooth_internals.js"></script> <script src="bluetooth_internals.js"></script>
</head> </head>
<body> <body>
<header> <header>
<h1>Bluetooth Internals</h1> <div class="title">
Bluetooth Internals
</div>
</header> </header>
<table id="device-table">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>Latest RSSI</th>
</tr>
</thead>
<tbody id="device-list">
</tbody>
</table>
</body> </body>
<template id="device-row-template">
<tr class="device-row">
<td class="device-name" data-label="Name"></td>
<td class="device-address" data-label="Address"></td>
<td class="device-rssi" data-label="Latest RSSI">Unknown</td>
</tr>
</template>
</html> </html>
\ No newline at end of file
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
(function() { (function() {
var adapter, adapterClient, bluetoothAdapter, bluetoothDevice, connection; var adapter, adapterClient, bluetoothAdapter, bluetoothDevice, connection;
var REMOVED_CSS = 'removed';
/* /*
* Data model for a cached device. * Data model for a cached device.
* @constructor * @constructor
...@@ -26,32 +28,56 @@ ...@@ -26,32 +28,56 @@
var AdapterClient = function() { this.devices_ = new Map(); }; var AdapterClient = function() { this.devices_ = new Map(); };
AdapterClient.prototype = { AdapterClient.prototype = {
/** /**
* Logs added device to console and caches the device info. * Caches the device info and updates the device list.
* @param {!bluetoothDevice.DeviceInfo} device * @param {!bluetoothDevice.DeviceInfo} deviceInfo
*/ */
deviceAdded: function(deviceInfo) { deviceAdded: function(deviceInfo) {
console.log('Device added', deviceInfo); if (this.devices_.has(deviceInfo.address)) {
this.devices_.set(deviceInfo.address, new Device(deviceInfo)); var deviceElement = $(deviceInfo.address);
deviceElement.classList.remove(REMOVED_CSS);
} else {
this.devices_.set(deviceInfo.address, new Device(deviceInfo));
var deviceRowTemplate = $('device-row-template');
var deviceRow = document.importNode(
deviceRowTemplate.content.children[0], true /* deep */);
deviceRow.id = deviceInfo.address;
var deviceList = $('device-list');
deviceList.appendChild(deviceRow);
}
this.deviceChanged(deviceInfo);
}, },
/** /**
* Logs removed device to console and removes the cached device. * Marks device as removed.
* @param {!bluetoothDevice.DeviceInfo} device * @param {!bluetoothDevice.DeviceInfo} deviceInfo
*/ */
deviceRemoved: function(deviceInfo) { deviceRemoved: function(deviceInfo) {
console.log('Device removed', deviceInfo); $(deviceInfo.address).classList.add(REMOVED_CSS);
this.devices_.delete(deviceInfo.address);
}, },
/** /**
* Logs changed device info to console and updates the cached device. * Updates cached device and updates the device list.
* @param {!bluetoothDevice.DeviceInfo} deviceInfo * @param {!bluetoothDevice.DeviceInfo} deviceInfo
*/ */
deviceChanged: function(deviceInfo) { deviceChanged: function(deviceInfo) {
console.log(new Date(), deviceInfo); console.log(new Date(), deviceInfo);
if (this.devices_.has(deviceInfo.address)) {
this.devices_.get(deviceInfo.address).info = deviceInfo; assert(this.devices_.has(deviceInfo.address), 'Device does not exist.');
}
this.devices_.get(deviceInfo.address).info = deviceInfo;
var deviceRow = $(deviceInfo.address);
deviceRow.querySelector('.device-name').textContent =
deviceInfo.name_for_display;
deviceRow.querySelector('.device-address').textContent =
deviceInfo.address;
var rssi = (deviceInfo.rssi && deviceInfo.rssi.value) ||
deviceRow.querySelector('.device-rssi').textContent;
deviceRow.querySelector('.device-rssi').textContent = rssi;
} }
}; };
...@@ -81,8 +107,6 @@ ...@@ -81,8 +107,6 @@
'device/bluetooth/public/interfaces/device.mojom', 'device/bluetooth/public/interfaces/device.mojom',
'mojo/public/js/connection', 'mojo/public/js/connection',
]).then(function([frameInterfaces, ...modules]) { ]).then(function([frameInterfaces, ...modules]) {
console.log('Loaded modules');
// Destructure here to assign global variables. // Destructure here to assign global variables.
[bluetoothAdapter, bluetoothDevice, connection] = modules; [bluetoothAdapter, bluetoothDevice, connection] = modules;
...@@ -117,11 +141,7 @@ ...@@ -117,11 +141,7 @@
.then(function(response) { console.log('adapter', response.info); }) .then(function(response) { console.log('adapter', response.info); })
.then(function() { return adapter.getDevices(); }) .then(function() { return adapter.getDevices(); })
.then(function(response) { .then(function(response) {
console.log('devices', response.devices.length); response.devices.forEach(adapterClient.deviceAdded, adapterClient);
response.devices.forEach(function(deviceInfo) {
adapterClient.deviceAdded(deviceInfo);
});
}) })
.catch(function(error) { console.error(error); }); .catch(function(error) { console.error(error); });
}); });
......
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