// 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.
import {AdapterObserverReceiver, AdapterRemote, ConnectResult, DiscoverySessionRemote} from './adapter.mojom-webui.js';
import {BluetoothInternalsHandler, BluetoothInternalsHandlerRemote} from './bluetooth_internals.mojom-webui.js';
import {Device, DeviceRemote} from './device.mojom-webui.js';
const SCAN_CLIENT_NAME = 'Bluetooth Internals Page';
/**
* Javascript for AdapterBroker, served from
* chrome://bluetooth-internals/.
*/
/**
* Enum of adapter property names. Used for adapterchanged events.
* @enum {string}
*/
export const AdapterProperty = {
DISCOVERABLE: 'discoverable',
DISCOVERING: 'discovering',
POWERED: 'powered',
PRESENT: 'present',
};
/**
* The proxy class of an adapter and router of adapter events.
* Exposes an EventTarget interface that allows other object to subscribe to
* to specific AdapterObserver events.
* Provides remote access to Adapter functions. Converts parameters to Mojo
* handles and back when necessary.
*
* @implements {AdapterObserverInterface}
*/
export class AdapterBroker extends EventTarget {
/** @param {!AdapterRemote} adapter */
constructor(adapter) {
super();
this.adapterObserverReceiver_ = new AdapterObserverReceiver(this);
this.adapter_ = adapter;
this.adapter_.addObserver(
this.adapterObserverReceiver_.$.bindNewPipeAndPassRemote());
}
presentChanged(present) {
this.dispatchEvent(new CustomEvent('adapterchanged', {
detail: {
property: AdapterProperty.PRESENT,
value: present,
},
}));
}
poweredChanged(powered) {
this.dispatchEvent(new CustomEvent('adapterchanged', {
detail: {
property: AdapterProperty.POWERED,
value: powered,
},
}));
}
discoverableChanged(discoverable) {
this.dispatchEvent(new CustomEvent('adapterchanged', {
detail: {
property: AdapterProperty.DISCOVERABLE,
value: discoverable,
},
}));
}
discoveringChanged(discovering) {
this.dispatchEvent(new CustomEvent('adapterchanged', {
detail: {
property: AdapterProperty.DISCOVERING,
value: discovering,
},
}));
}
deviceAdded(device) {
this.dispatchEvent(
new CustomEvent('deviceadded', {detail: {deviceInfo: device}}));
}
deviceChanged(device) {
this.dispatchEvent(
new CustomEvent('devicechanged', {detail: {deviceInfo: device}}));
}
deviceRemoved(device) {
this.dispatchEvent(
new CustomEvent('deviceremoved', {detail: {deviceInfo: device}}));
}
/**
* Creates a GATT connection to the device with |address|.
* @param {string} address
* @return {!Promise<!Device>}
*/
connectToDevice(address) {
return this.adapter_.connectToDevice(address).then(function(response) {
if (response.result !== ConnectResult.SUCCESS) {
// TODO(crbug.com/40492643): Replace with more descriptive error
// messages.
const errorString = Object.keys(ConnectResult).find(function(key) {
return ConnectResult[key] === response.result;
});
throw new Error(errorString);
}
return response.device;
});
}
/**
* Gets an array of currently detectable devices from the Adapter service.
* @return {Promise<{devices: Array<!DeviceInfo>}>}
*/
getDevices() {
return this.adapter_.getDevices();
}
/**
* Gets the current state of the Adapter.
* @return {Promise<{info: AdapterInfo}>}
*/
getInfo() {
return this.adapter_.getInfo();
}
/**
* Requests the adapter to start a new discovery session.
* @return {!Promise<!DiscoverySessionRemote>}
*/
startDiscoverySession() {
return this.adapter_.startDiscoverySession(SCAN_CLIENT_NAME)
.then(function(response) {
if (!response.session) {
throw new Error('Discovery session failed to start');
}
return response.session;
});
}
}
let adapterBroker = null;
/**
* Initializes an AdapterBroker if one doesn't exist.
* @param {!BluetoothInternalsHandlerRemote=}
* opt_bluetoothInternalsHandler
* @return {!Promise<!AdapterBroker>} resolves with
* AdapterBroker, rejects if Bluetooth is not supported.
*/
export function getAdapterBroker(opt_bluetoothInternalsHandler) {
if (adapterBroker) {
return Promise.resolve(adapterBroker);
}
const bluetoothInternalsHandler = opt_bluetoothInternalsHandler ?
opt_bluetoothInternalsHandler :
BluetoothInternalsHandler.getRemote();
// Get an Adapter service.
return bluetoothInternalsHandler.getAdapter().then(function(response) {
if (!response.adapter) {
throw new Error('Bluetooth Not Supported on this platform.');
}
adapterBroker = new AdapterBroker(response.adapter);
return adapterBroker;
});
}