| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * Javascript for DeviceCollection, served from |
| * chrome://bluetooth-internals/. |
| */ |
| |
| import {assert} from 'chrome://resources/js/assert.js'; |
| |
| /** |
| * Enum of connection status for a device. |
| * @enum {number} |
| */ |
| export const ConnectionStatus = { |
| DISCONNECTED: 0, |
| CONNECTING: 1, |
| CONNECTED: 2, |
| }; |
| |
| /** |
| * Collection of devices. Extends EventTarget to notify observers when the |
| * collection changes. |
| */ |
| export class DeviceCollection extends EventTarget { |
| /** |
| * @param {!Array<!DeviceInfo>} array The starting |
| * collection of devices. |
| */ |
| constructor(array) { |
| super(); |
| |
| /** @private {!Array<!DeviceInfo>} */ |
| this.array_ = array; |
| |
| // Keep track of MAC addresses which were previously found via scan, but |
| // are no longer being advertised or nearby. Used to inform isRemoved(). |
| /** @private {!Object<string, boolean>} */ |
| this.removedDevices_ = {}; |
| } |
| |
| /** @return {number} */ |
| get length() { |
| return this.array_.length; |
| } |
| |
| /** |
| * @param {number} |
| * @return {DeviceInfo} |
| */ |
| item(index) { |
| return (index < 0 || index > this.length) ? undefined : this.array_[index]; |
| } |
| |
| /** |
| * Finds the Device in the collection with the matching address. |
| * @param {string} address |
| * @return {number} The index where the device was found. |
| */ |
| getByAddress(address) { |
| for (let i = 0; i < this.length; i++) { |
| const device = this.array_[i]; |
| if (address === device.address) { |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * Adds or updates a Device with new DeviceInfo. |
| * @param {!DeviceInfo} deviceInfo |
| */ |
| addOrUpdate(deviceInfo) { |
| this.removedDevices_[deviceInfo.address] = false; |
| const oldDeviceIndex = this.getByAddress(deviceInfo.address); |
| |
| if (oldDeviceIndex !== -1) { |
| // Update rssi if it's valid |
| const oldDeviceInfo = this.array_[oldDeviceIndex]; |
| const rssi = (deviceInfo.rssi && deviceInfo.rssi.value) || |
| (oldDeviceInfo.rssi && oldDeviceInfo.rssi.value); |
| |
| // The rssi property may be null, so it must be re-assigned. |
| Object.assign(oldDeviceInfo, deviceInfo); |
| oldDeviceInfo.rssi = {value: rssi}; |
| this.dispatchEvent(new CustomEvent( |
| 'device-update', |
| {bubbles: true, composed: true, detail: oldDeviceIndex})); |
| } else { |
| this.array_.push(deviceInfo); |
| this.dispatchEvent(new CustomEvent('device-added', { |
| bubbles: true, |
| composed: true, |
| detail: {index: this.length - 1, device: deviceInfo}, |
| })); |
| } |
| } |
| |
| /** |
| * Marks the Device as removed. |
| * @param {!DeviceInfo} deviceInfo |
| */ |
| remove(deviceInfo) { |
| const deviceIndex = this.getByAddress(deviceInfo.address); |
| assert(deviceIndex !== -1, 'Device does not exist.'); |
| this.removedDevices_[deviceInfo.address] = true; |
| this.dispatchEvent(new CustomEvent( |
| 'device-update', {bubbles: true, composed: true, detail: deviceIndex})); |
| } |
| |
| /** |
| * Return true if device was "removed" -- previously found via scan but |
| * either no longer advertising or no longer nearby. |
| * @param {!DeviceInfo} deviceInfo |
| * @return {boolean} |
| */ |
| isRemoved(deviceInfo) { |
| return !!this.removedDevices_[deviceInfo.address]; |
| } |
| |
| resetForTest() { |
| this.array_ = []; |
| this.removedDevices_ = []; |
| |
| this.dispatchEvent(new CustomEvent( |
| 'devices-reset-for-test', {bubbles: true, composed: true})); |
| } |
| } |