| Index: chrome/browser/resources/bluetooth_internals/device_table.js | 
| diff --git a/chrome/browser/resources/bluetooth_internals/device_table.js b/chrome/browser/resources/bluetooth_internals/device_table.js | 
| index 443c590ff8ff906b96fbfe172b8e7fad4bf9565c..3e2ebb38fb00bd9ac1da112532baaf6822bfbf50 100644 | 
| --- a/chrome/browser/resources/bluetooth_internals/device_table.js | 
| +++ b/chrome/browser/resources/bluetooth_internals/device_table.js | 
| @@ -7,9 +7,20 @@ | 
| */ | 
|  | 
| cr.define('device_table', function() { | 
| +  var COLUMNS = { | 
| +    NAME: 0, | 
| +    ADDRESS: 1, | 
| +    RSSI: 2, | 
| +    SERVICES: 3, | 
| +    CONNECTION_STATE: 4, | 
| +    INSPECT_BUTTON: 5, | 
| +    CONNECTION_ERROR: 6, | 
| +  }; | 
| + | 
| /** | 
| * A table that lists the devices and responds to changes in the given | 
| -   *     DeviceCollection. | 
| +   * DeviceCollection. Fires events for inspection requests from listed | 
| +   * devices. | 
| * @constructor | 
| * @extends {HTMLTableElement} | 
| */ | 
| @@ -53,16 +64,30 @@ cr.define('device_table', function() { | 
| /** | 
| * Updates table row on change event of the device collection. | 
| * @private | 
| -     * @param {!CustomEvent} event | 
| +     * @param {!Event} event | 
| */ | 
| handleChange_: function(event) { | 
| this.updateRow_(this.devices_.item(event.index), event.index); | 
| }, | 
|  | 
| /** | 
| +     * Fires a inspect pressed event for the row |index|. | 
| +     * @private | 
| +     * @param {number} index | 
| +     */ | 
| +    handleInspectBtn_: function(index) { | 
| +      var event = new CustomEvent('inspectpressed', { | 
| +        detail: { | 
| +          address: this.devices_.item(index).address, | 
| +        } | 
| +      }); | 
| +      this.dispatchEvent(event); | 
| +    }, | 
| + | 
| +    /** | 
| * Updates table row on splice event of the device collection. | 
| * @private | 
| -     * @param {!CustomEvent} event | 
| +     * @param {!Event} event | 
| */ | 
| handleSplice_: function(event) { | 
| event.removed.forEach(function() { | 
| @@ -77,17 +102,30 @@ cr.define('device_table', function() { | 
| /** | 
| * Inserts a new row at |index| and updates it with info from |device|. | 
| * @private | 
| -     * @param {!device_collection.Device} device | 
| +     * @param {!interfaces.BluetoothDevice.DeviceInfo} device | 
| * @param {?number} index | 
| */ | 
| insertRow_: function(device, index) { | 
| var row = this.body_.insertRow(index); | 
| -      row.id = device.info.address; | 
| +      row.id = device.address; | 
|  | 
| for (var i = 0; i < this.headers_.length; i++) { | 
| row.insertCell(); | 
| } | 
|  | 
| +      // Make two extra cells for the inspect button and connect errors. | 
| +      var inspectCell = row.insertCell(); | 
| + | 
| +      // TODO(crbug.com/663830): Replace connection error column with better | 
| +      // notification system. | 
| +      var connectErrorCell = row.insertCell(); | 
| + | 
| +      var inspectButton = document.createElement('button'); | 
| +      inspectCell.appendChild(inspectButton); | 
| +      inspectButton.addEventListener('click', function() { | 
| +        this.handleInspectBtn_(row.sectionRowIndex); | 
| +      }.bind(this)); | 
| + | 
| this.updateRow_(device, row.sectionRowIndex); | 
| }, | 
|  | 
| @@ -109,29 +147,53 @@ cr.define('device_table', function() { | 
| /** | 
| * Updates the row at |index| with the info from |device|. | 
| * @private | 
| -     * @param {!device_collection.Device} device | 
| +     * @param {!interfaces.BluetoothDevice.DeviceInfo} device | 
| * @param {number} index | 
| */ | 
| updateRow_: function(device, index) { | 
| -      assert(this.body_.rows[index], 'Row ' + index + ' is not in the table.'); | 
| var row = this.body_.rows[index]; | 
| +      assert(row, 'Row ' + index + ' is not in the table.'); | 
|  | 
| row.classList.toggle('removed', device.removed); | 
|  | 
| +      var inspectButton = row.cells[COLUMNS.INSPECT_BUTTON].children[0]; | 
| +      inspectButton.disabled = false; | 
| +      switch (device.connectionStatus) { | 
| +        case device_collection.ConnectionStatus.DISCONNECTED: | 
| +          inspectButton.textContent = 'Inspect'; | 
| +          break; | 
| +        case device_collection.ConnectionStatus.CONNECTED: | 
| +          inspectButton.textContent = 'Forget'; | 
| +          break; | 
| +        case device_collection.ConnectionStatus.CONNECTING: | 
| +          inspectButton.disabled = true; | 
| +          break; | 
| +        default: assert('case not handled'); | 
| +      } | 
| + | 
| +      // TODO(crbug.com/663830): Replace connection error column with better | 
| +      // notification system. | 
| +      var connectErrorCell = row.cells[COLUMNS.CONNECTION_ERROR]; | 
| +      connectErrorCell.textContent = device.connectionMessage; | 
| + | 
| // Update the properties based on the header field path. | 
| for (var i = 0; i < this.headers_.length; i++) { | 
| var header = this.headers_[i]; | 
| var propName = header.dataset.field; | 
|  | 
| var parts = propName.split('.'); | 
| -        var obj = device.info; | 
| +        var obj = device; | 
| while (obj != null && parts.length > 0) { | 
| var part = parts.shift(); | 
| obj = obj[part]; | 
| } | 
|  | 
| +        if (propName == 'is_gatt_connected') { | 
| +          obj = obj ? 'Connected' : 'Not Connected'; | 
| +        } | 
| + | 
| var cell = row.cells[i]; | 
| -        cell.textContent = obj || 'Unknown'; | 
| +        cell.textContent = obj == null ? 'Unknown' : obj; | 
| cell.dataset.label = header.textContent; | 
| } | 
| }, | 
|  |