blob: a125877a76d4e23bc26dda5c7869fc92c917aa71 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Custom binding for the Bluetooth API.
var binding = require('binding').Binding.create('bluetooth');
var chrome = requireNative('chrome').GetChrome();
var Event = require('event_bindings').Event;
var lastError = require('lastError');
var sendRequest = require('sendRequest').sendRequest;
// Use custom binding to create an undocumented event listener that will
// receive events about device discovery and call the event listener that was
// provided with the request to begin discovery.
binding.registerCustomHook(function(api) {
var apiFunctions = api.apiFunctions;
var bluetooth = {};
function callCallbackIfPresent(name, args, error) {
var callback = args[args.length - 1];
if (typeof(callback) == 'function')
lastError.run(name, error, callback);
}
bluetooth.deviceDiscoveredHandler = null;
bluetooth.onDeviceDiscovered = new Event('bluetooth.onDeviceDiscovered');
function clearDeviceDiscoveredHandler() {
bluetooth.onDeviceDiscovered.removeListener(
bluetooth.deviceDiscoveredHandler);
bluetooth.deviceDiscoveredHandler = null;
}
apiFunctions.setHandleRequest('startDiscovery',
function() {
var args = arguments;
if (args.length > 0 && args[0] && args[0].deviceCallback) {
if (bluetooth.deviceDiscoveredHandler != null) {
callCallbackIfPresent('bluetooth.startDiscovery',
args,
'Concurrent discovery is not allowed.');
return;
}
bluetooth.deviceDiscoveredHandler = args[0].deviceCallback;
bluetooth.onDeviceDiscovered.addListener(
bluetooth.deviceDiscoveredHandler);
sendRequest(this.name,
args,
this.definition.parameters,
{customCallback:this.customCallback});
} else {
callCallbackIfPresent(
'bluetooth.startDiscovery',
args,
'deviceCallback is required in the options object');
return;
}
});
apiFunctions.setCustomCallback('startDiscovery',
function(name, request, response) {
if (chrome.runtime.lastError) {
clearDeviceDiscoveredHandler();
return;
}
});
apiFunctions.setHandleRequest('stopDiscovery',
function() {
clearDeviceDiscoveredHandler();
sendRequest(this.name, arguments, this.definition.parameters);
});
// An object to hold state during one call to getDevices.
bluetooth.getDevicesState = null;
// Hidden events used to deliver getDevices data to the client callbacks
bluetooth.onDeviceSearchResult = new Event('bluetooth.onDeviceSearchResult');
bluetooth.onDeviceSearchFinished =
new Event('bluetooth.onDeviceSearchFinished');
function deviceSearchResultHandler(device) {
bluetooth.getDevicesState.actualEvents++;
bluetooth.getDevicesState.deviceCallback(device);
maybeFinishDeviceSearch();
}
function deviceSearchFinishedHandler(info) {
bluetooth.getDevicesState.expectedEventCount = info.expectedEventCount;
maybeFinishDeviceSearch();
}
function addDeviceSearchListeners() {
bluetooth.onDeviceSearchResult.addListener(deviceSearchResultHandler);
bluetooth.onDeviceSearchFinished.addListener(deviceSearchFinishedHandler);
}
function removeDeviceSearchListeners() {
bluetooth.onDeviceSearchResult.removeListener(deviceSearchResultHandler);
bluetooth.onDeviceSearchFinished.removeListener(
deviceSearchFinishedHandler);
}
function maybeFinishDeviceSearch() {
var state = bluetooth.getDevicesState;
if (typeof(state.expectedEventCount) != 'undefined' &&
state.actualEvents >= state.expectedEventCount) {
finishDeviceSearch();
}
}
function finishDeviceSearch() {
var finalCallback = bluetooth.getDevicesState.finalCallback;
removeDeviceSearchListeners();
bluetooth.getDevicesState = null;
if (finalCallback) {
finalCallback();
}
}
apiFunctions.setUpdateArgumentsPostValidate('getDevices',
function() {
var args = $Array.slice(arguments);
if (bluetooth.getDevicesState != null) {
throw new Error('Concurrent calls to getDevices are not allowed.');
}
var state = { actualEvents: 0 };
if (typeof(args[args.length - 1]) == 'function') {
state.finalCallback = args.pop();
$Array.push(args,
function() {
if (chrome.runtime.lastError) {
finishDeviceSearch();
}
});
} else {
throw new Error('getDevices must have a final callback parameter.');
}
if (typeof(args[0].deviceCallback) == 'function') {
state.deviceCallback = args[0].deviceCallback;
} else {
throw new Error('getDevices must be passed options with a ' +
'deviceCallback.');
}
bluetooth.getDevicesState = state;
addDeviceSearchListeners();
return args;
});
});
exports.binding = binding.generate();