nativescript-akylas-bluetooth
Version:
Connect to and interact with Bluetooth LE peripherals
925 lines • 44 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var utils = require("tns-core-modules/utils/utils");
var application = require("tns-core-modules/application/application");
var common_1 = require("../common");
var TNS_BluetoothGattCallback_1 = require("./TNS_BluetoothGattCallback");
var Queue = require("p-queue");
var ACCESS_COARSE_LOCATION_PERMISSION_REQUEST_CODE = 222;
var ACTION_REQUEST_ENABLE_BLUETOOTH_REQUEST_CODE = 223;
var ACTION_REQUEST_BLUETOOTH_DISCOVERABLE_REQUEST_CODE = 224;
var ANDROID_SDK = -1;
function getAndroidSDK() {
if (ANDROID_SDK === -1) {
ANDROID_SDK = android.os.Build.VERSION.SDK_INT;
}
return ANDROID_SDK;
}
var LOLLIPOP = 21;
var MARSHMALLOW = 23;
var ScanMode;
(function (ScanMode) {
ScanMode[ScanMode["LOW_LATENCY"] = 0] = "LOW_LATENCY";
ScanMode[ScanMode["BALANCED"] = 1] = "BALANCED";
ScanMode[ScanMode["LOW_POWER"] = 2] = "LOW_POWER";
ScanMode[ScanMode["OPPORTUNISTIC"] = 3] = "OPPORTUNISTIC";
})(ScanMode = exports.ScanMode || (exports.ScanMode = {}));
function androidScanMode(mode) {
switch (mode) {
case ScanMode.BALANCED:
return android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
case ScanMode.LOW_POWER:
return android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_POWER;
case ScanMode.OPPORTUNISTIC:
return android.bluetooth.le.ScanSettings.SCAN_MODE_OPPORTUNISTIC;
case ScanMode.LOW_LATENCY:
default:
return android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_LATENCY;
}
}
var MatchMode;
(function (MatchMode) {
MatchMode[MatchMode["AGGRESSIVE"] = 0] = "AGGRESSIVE";
MatchMode[MatchMode["STICKY"] = 1] = "STICKY";
})(MatchMode = exports.MatchMode || (exports.MatchMode = {}));
function androidMatchMode(mode) {
switch (mode) {
case MatchMode.STICKY:
return android.bluetooth.le.ScanSettings.MATCH_MODE_STICKY;
default:
return android.bluetooth.le.ScanSettings.MATCH_MODE_AGGRESSIVE;
}
}
var MatchNum;
(function (MatchNum) {
MatchNum[MatchNum["MAX_ADVERTISEMENT"] = 0] = "MAX_ADVERTISEMENT";
MatchNum[MatchNum["FEW_ADVERTISEMENT"] = 1] = "FEW_ADVERTISEMENT";
MatchNum[MatchNum["ONE_ADVERTISEMENT"] = 2] = "ONE_ADVERTISEMENT";
})(MatchNum = exports.MatchNum || (exports.MatchNum = {}));
function androidMatchNum(mode) {
switch (mode) {
case MatchNum.ONE_ADVERTISEMENT:
return android.bluetooth.le.ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT;
case MatchNum.FEW_ADVERTISEMENT:
return android.bluetooth.le.ScanSettings.MATCH_NUM_FEW_ADVERTISEMENT;
default:
return android.bluetooth.le.ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT;
}
}
var CallbackType;
(function (CallbackType) {
CallbackType[CallbackType["ALL_MATCHES"] = 0] = "ALL_MATCHES";
CallbackType[CallbackType["FIRST_MATCH"] = 1] = "FIRST_MATCH";
CallbackType[CallbackType["MATCH_LOST"] = 2] = "MATCH_LOST";
})(CallbackType = exports.CallbackType || (exports.CallbackType = {}));
function androidCallbackType(mode) {
switch (mode) {
case CallbackType.MATCH_LOST:
return android.bluetooth.le.ScanSettings.CALLBACK_TYPE_MATCH_LOST;
case CallbackType.FIRST_MATCH:
return android.bluetooth.le.ScanSettings.CALLBACK_TYPE_FIRST_MATCH;
default:
return android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
}
}
var Phy;
(function (Phy) {
Phy[Phy["LE_1M"] = 0] = "LE_1M";
Phy[Phy["LE_CODED"] = 1] = "LE_CODED";
Phy[Phy["LE_ALL_SUPPORTED"] = 2] = "LE_ALL_SUPPORTED";
})(Phy = exports.Phy || (exports.Phy = {}));
function androidPhy(mode) {
switch (mode) {
case Phy.LE_1M:
return android.bluetooth.BluetoothDevice.PHY_LE_1M;
case Phy.LE_CODED:
return android.bluetooth.BluetoothDevice.PHY_LE_CODED;
default:
return android.bluetooth.le.ScanSettings.PHY_LE_ALL_SUPPORTED;
}
}
function uuidToString(uuid) {
var uuidStr = uuid.toString();
var pattern = java.util.regex.Pattern.compile('0000(.{4})-0000-1000-8000-00805f9b34fb', 2);
var matcher = pattern.matcher(uuidStr);
return matcher.matches() ? matcher.group(1) : uuidStr;
}
exports.uuidToString = uuidToString;
function encodeValue(val) {
var parts = val;
if (typeof val === 'string') {
parts = val.split(',');
if (parts[0].indexOf('x') === -1) {
return null;
}
}
var result = Array.create('byte', parts.length);
for (var i = 0; i < parts.length; i++) {
result[i] = parts[i];
}
return result;
}
exports.encodeValue = encodeValue;
function nativeEncoding(encoding) {
var result = java.nio.charset.Charset.forName(encoding);
return result;
}
function valueToByteArray(value, encoding) {
if (encoding === void 0) { encoding = 'iso-8859-1'; }
if (typeof value === 'string') {
return new java.lang.String(value).getBytes(nativeEncoding(encoding));
}
else if (Array.isArray(value)) {
return value;
}
return null;
}
exports.valueToByteArray = valueToByteArray;
function byteArrayToBuffer(value) {
if (!value) {
return null;
}
var ret = new Uint8Array(value.length);
var isString = typeof value === 'string';
for (var i = 0; i < value.length; i++) {
ret[i] = isString ? value.charCodeAt(i) : value[i];
}
return ret.buffer;
}
exports.byteArrayToBuffer = byteArrayToBuffer;
function printValueToString(value) {
if (value instanceof java.lang.Object) {
var array = [];
var bytes = value;
for (var i = 0; i < bytes.length; i++) {
array.push(new Number(bytes[i]).valueOf());
}
return array;
}
return value;
}
exports.printValueToString = printValueToString;
function stringToUuid(uuidStr) {
if (uuidStr.length === 4) {
uuidStr = '0000' + uuidStr + '-0000-1000-8000-00805f9b34fb';
}
return java.util.UUID.fromString(uuidStr);
}
exports.stringToUuid = stringToUuid;
var Bluetooth = (function (_super) {
__extends(Bluetooth, _super);
function Bluetooth() {
var _this = _super.call(this) || this;
_this.bluetoothGattCallback = new TNS_BluetoothGattCallback_1.TNS_BluetoothGattCallback();
_this.gattQueue = new Queue({ concurrency: 1 });
_this.connections = {};
common_1.CLog(common_1.CLogTypes.info, '*** Android Bluetooth Constructor ***');
if (android.os.Build.VERSION.SDK_INT >= LOLLIPOP) {
_this.scanCallback = new (require('./TNS_ScanCallback')).TNS_ScanCallback();
_this.scanCallback.onInit(new WeakRef(_this));
}
else {
_this.LeScanCallback = new (require('./TNS_LeScanCallback')).TNS_LeScanCallback();
_this.LeScanCallback.onInit(new WeakRef(_this));
}
_this.bluetoothGattCallback.onInit(new WeakRef(_this));
_this.broadcastReceiver = application.android.registerBroadcastReceiver(android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED, function (context, intent) {
var state = intent.getIntExtra(android.bluetooth.BluetoothAdapter.EXTRA_STATE, android.bluetooth.BluetoothAdapter.ERROR);
if (state === android.bluetooth.BluetoothAdapter.STATE_ON || state === android.bluetooth.BluetoothAdapter.STATE_OFF) {
_this.sendEvent(Bluetooth.bluetooth_status_event, {
state: state === android.bluetooth.BluetoothAdapter.STATE_ON ? 'on' : 'off'
});
}
});
return _this;
}
Object.defineProperty(Bluetooth.prototype, "adapter", {
get: function () {
if (!this._adapter) {
this._adapter = this.bluetoothManager.getAdapter();
}
return this._adapter;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Bluetooth.prototype, "bluetoothManager", {
get: function () {
if (!this._bluetoothManager) {
this._bluetoothManager = utils.ad.getApplicationContext().getSystemService(android.content.Context.BLUETOOTH_SERVICE);
}
return this._bluetoothManager;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Bluetooth.prototype, "enabled", {
get: function () {
return this._isEnabled();
},
enumerable: true,
configurable: true
});
Bluetooth.prototype.coarseLocationPermissionGranted = function () {
var hasPermission = getAndroidSDK() < MARSHMALLOW;
if (!hasPermission) {
var ctx = this._getContext();
common_1.CLog(common_1.CLogTypes.info, 'app context', ctx);
hasPermission =
android.content.pm.PackageManager.PERMISSION_GRANTED === android.support.v4.content.ContextCompat.checkSelfPermission(ctx, android.Manifest.permission.ACCESS_COARSE_LOCATION);
}
common_1.CLog(common_1.CLogTypes.info, 'coarseLocationPermissionGranted ---- ACCESS_COARSE_LOCATION permission granted?', hasPermission);
return hasPermission;
};
Bluetooth.prototype.hasCoarseLocationPermission = function () {
var _this = this;
return new Promise(function (resolve) {
resolve(_this.coarseLocationPermissionGranted());
});
};
Bluetooth.prototype.requestCoarseLocationPermission = function (callback) {
var _this = this;
return new Promise(function (resolve, reject) {
var permissionCb = function (args) {
if (args.requestCode === ACCESS_COARSE_LOCATION_PERMISSION_REQUEST_CODE) {
application.android.off(application.AndroidApplication.activityRequestPermissionsEvent, permissionCb);
permissionCb = null;
for (var i = 0; i < args.permissions.length; i++) {
if (args.grantResults[i] === android.content.pm.PackageManager.PERMISSION_DENIED) {
reject('Permission denied');
return;
}
}
if (callback) {
callback();
}
resolve();
}
};
application.android.on(application.AndroidApplication.activityRequestPermissionsEvent, permissionCb);
android.support.v4.app.ActivityCompat.requestPermissions(_this._getActivity(), [android.Manifest.permission.ACCESS_COARSE_LOCATION], ACCESS_COARSE_LOCATION_PERMISSION_REQUEST_CODE);
});
};
Bluetooth.prototype.getAndroidLocationManager = function () {
return application.android.context.getSystemService(android.content.Context.LOCATION_SERVICE);
};
Bluetooth.prototype.isGPSEnabled = function () {
var _this = this;
if (!this.hasCoarseLocationPermission()) {
return this.requestCoarseLocationPermission().then(function () { return _this.isGPSEnabled(); });
}
var result = this.getAndroidLocationManager().isProviderEnabled(android.location.LocationManager.GPS_PROVIDER);
if (common_1.BluetoothUtil.debug) {
var providers = this.getAndroidLocationManager().getProviders(false);
common_1.CLog(common_1.CLogTypes.info, 'isGPSEnabled providers', providers);
common_1.CLog(common_1.CLogTypes.info, 'isGPSEnabled: ', result);
}
return Promise.resolve(result);
};
Bluetooth.prototype.enableGPS = function () {
var _this = this;
common_1.CLog(common_1.CLogTypes.info, 'Bluetooth.enableGPS');
return new Promise(function (resolve, reject) {
var currentContext = application.android.currentContext;
if (!_this.isGPSEnabled()) {
var onActivityResultHandler_1 = function (data) {
application.android.off(application.AndroidApplication.activityResultEvent, onActivityResultHandler_1);
if (data.requestCode === 0) {
if (_this.isGPSEnabled()) {
resolve();
}
else {
reject('GPS not enabled');
}
}
};
application.android.on(application.AndroidApplication.activityResultEvent, onActivityResultHandler_1);
currentContext.startActivityForResult(new android.content.Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS), 0);
}
else {
resolve();
}
});
};
Bluetooth.prototype.enable = function () {
var _this = this;
common_1.CLog(common_1.CLogTypes.info, 'enable:', this._isEnabled());
return new Promise(function (resolve, reject) {
if (_this._isEnabled()) {
return resolve(true);
}
try {
common_1.CLog(common_1.CLogTypes.info, 'enable: asking to enable bluetooth');
var onBluetoothEnableResult_1 = function (args) {
common_1.CLog(common_1.CLogTypes.info, 'Bluetooth.onBluetoothEnableResult ---', "requestCode: " + args.requestCode + ", result: " + args.resultCode);
if (args.requestCode === ACTION_REQUEST_ENABLE_BLUETOOTH_REQUEST_CODE) {
try {
application.android.off(application.AndroidApplication.activityResultEvent, onBluetoothEnableResult_1);
if (args.resultCode === android.app.Activity.RESULT_OK) {
_this.sendEvent(Bluetooth.bluetooth_enabled_event);
resolve(true);
}
else {
resolve(false);
}
}
catch (ex) {
common_1.CLog(common_1.CLogTypes.error, ex);
application.android.off(application.AndroidApplication.activityResultEvent, onBluetoothEnableResult_1);
_this.sendEvent(Bluetooth.error_event, { error: ex }, "enable ---- error: " + ex);
reject(ex);
return;
}
}
else {
application.android.off(application.AndroidApplication.activityResultEvent, onBluetoothEnableResult_1);
resolve(false);
return;
}
};
application.android.on(application.AndroidApplication.activityResultEvent, onBluetoothEnableResult_1);
var intent = new android.content.Intent(android.bluetooth.BluetoothAdapter.ACTION_REQUEST_ENABLE);
var activity = application.android.foregroundActivity || application.android.startActivity;
common_1.CLog(common_1.CLogTypes.info, 'enable: startActivityForResult');
activity.startActivityForResult(intent, ACTION_REQUEST_ENABLE_BLUETOOTH_REQUEST_CODE);
}
catch (ex) {
common_1.CLog(common_1.CLogTypes.error, 'enable:', ex);
reject(ex);
_this.sendEvent(Bluetooth.error_event, { error: ex }, 'Error enabling bluetooth.');
}
});
};
Bluetooth.prototype.isBluetoothEnabled = function () {
var _this = this;
return new Promise(function (resolve, reject) {
try {
resolve(_this._isEnabled());
}
catch (ex) {
common_1.CLog(common_1.CLogTypes.error, 'isBluetoothEnabled ---- error:', ex);
reject(ex);
}
});
};
Bluetooth.prototype.openBluetoothSettings = function () {
var _this = this;
return new Promise(function (resolve, reject) {
var currentContext = application.android.currentContext;
if (!_this._isEnabled()) {
var that_1 = _this;
var onActivityResultHandler_2 = function (data) {
application.android.off(application.AndroidApplication.activityResultEvent, onActivityResultHandler_2);
if (data.requestCode === 0) {
if (that_1._isEnabled()) {
resolve();
}
else {
reject('bluetooth_not_enabled');
}
}
};
application.android.on(application.AndroidApplication.activityResultEvent, onActivityResultHandler_2);
currentContext.startActivityForResult(new android.content.Intent(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS), 0);
}
else {
resolve();
}
});
};
Bluetooth.prototype.stopCurrentScan = function () {
common_1.CLog(common_1.CLogTypes.info, 'stopCurrentScan:', !!this.scanningReferTimer);
if (!this.adapter) {
common_1.CLog(common_1.CLogTypes.error, 'stopCurrentScan: no adapter');
return;
}
if (this.scanCallback) {
var scanner = this.adapter.getBluetoothLeScanner();
if (scanner) {
scanner.stopScan(this.scanCallback);
}
this.scanCallback.onPeripheralDiscovered = null;
}
if (this.LeScanCallback) {
this.adapter.stopLeScan(this.LeScanCallback);
this.LeScanCallback.onPeripheralDiscovered = null;
}
if (this.scanningReferTimer) {
clearTimeout(this.scanningReferTimer.timer);
this.scanningReferTimer.resolve();
this.scanningReferTimer = null;
}
};
Bluetooth.prototype.startScanning = function (arg) {
var _this = this;
if (!this.adapter) {
common_1.CLog(common_1.CLogTypes.error, 'stopCurrentScan: no adapter');
return Promise.reject('no_bluetooth');
}
return new Promise(function (resolve, reject) {
try {
if (!_this._isEnabled()) {
reject('bluetooth_not_enabled');
return;
}
var onPermissionGranted = function () {
for (var key in _this.connections) {
if (_this.connections[key] && _this.connections[key].state === 'disconnected') {
delete _this.connections[key];
}
}
var filters = arg.filters || [];
if (_this.scanningReferTimer) {
_this.stopCurrentScan();
}
if (_this.LeScanCallback) {
var uuids_1 = [];
filters.forEach(function (f) {
if (f.serviceUUID) {
uuids_1.push(stringToUuid(f.serviceUUID));
}
});
_this.LeScanCallback.onPeripheralDiscovered = arg.onDiscovered;
var didStart = uuids_1.length === 0 ? _this.adapter.startLeScan(_this.LeScanCallback) : _this.adapter.startLeScan(uuids_1, _this.LeScanCallback);
common_1.CLog(common_1.CLogTypes.info, 'startScanning ---- PreLollipop ---- didStart scanning:', didStart, JSON.stringify(uuids_1));
if (!didStart) {
reject('couldnt_start_scanning');
return;
}
}
else {
var scanner = _this.adapter.getBluetoothLeScanner();
if (!scanner) {
reject('bluetooth_not_enabled');
return;
}
var scanFilters_1 = null;
if (filters.length > 0) {
scanFilters_1 = new java.util.ArrayList();
filters.forEach(function (f) {
var scanFilterBuilder = new android.bluetooth.le.ScanFilter.Builder();
if (f.serviceUUID) {
scanFilterBuilder.setServiceUuid(new android.os.ParcelUuid(stringToUuid(f.serviceUUID)));
}
if (f.deviceName) {
scanFilterBuilder.setDeviceName(f.deviceName);
}
if (f.deviceAddress) {
scanFilterBuilder.setDeviceAddress(f.deviceAddress);
}
if (f.manufacturerData) {
var manufacturerId = new DataView(f.manufacturerData, 0).getUint16(0, true);
scanFilterBuilder.setManufacturerData(manufacturerId, encodeValue(f.manufacturerData));
}
scanFilters_1.add(scanFilterBuilder.build());
});
}
var scanSettings = new android.bluetooth.le.ScanSettings.Builder();
scanSettings.setReportDelay(0);
var scanMode = (arg.android && arg.android.scanMode) || ScanMode.LOW_LATENCY;
scanSettings.setScanMode(androidScanMode(scanMode));
if (android.os.Build.VERSION.SDK_INT >= 23) {
var matchMode = (arg.android && arg.android.matchMode) || MatchMode.AGGRESSIVE;
scanSettings.setMatchMode(androidMatchMode(matchMode));
var matchNum = (arg.android && arg.android.matchNum) || MatchNum.MAX_ADVERTISEMENT;
scanSettings.setNumOfMatches(androidMatchNum(matchNum));
var callbackType = (arg.android && arg.android.callbackType) || CallbackType.ALL_MATCHES;
scanSettings.setCallbackType(androidCallbackType(callbackType));
}
_this.scanCallback.onPeripheralDiscovered = arg.onDiscovered;
_this.adapter.getBluetoothLeScanner().startScan(scanFilters_1, scanSettings.build(), _this.scanCallback);
common_1.CLog(common_1.CLogTypes.info, 'startScanning ---- PostLollipop ---- didStart scanning:', JSON.stringify(filters));
}
_this.scanningReferTimer = { resolve: resolve };
if (arg.seconds) {
_this.scanningReferTimer.timer = setTimeout(function () { return _this.stopCurrentScan(); }, arg.seconds * 1000);
}
else {
resolve();
}
};
if (arg.skipPermissionCheck !== true && !_this.coarseLocationPermissionGranted()) {
common_1.CLog(common_1.CLogTypes.info, 'startScanning ---- Coarse Location Permission not granted on Android device, will request permission.');
_this.requestCoarseLocationPermission(onPermissionGranted);
}
else {
onPermissionGranted();
}
}
catch (ex) {
common_1.CLog(common_1.CLogTypes.error, 'startScanning ---- error:', ex);
reject(ex);
}
});
};
Bluetooth.prototype.stopScanning = function () {
var _this = this;
if (!this.adapter) {
common_1.CLog(common_1.CLogTypes.error, 'stopCurrentScan: no adapter');
return Promise.reject('no_bluetooth');
}
return new Promise(function (resolve, reject) {
try {
if (!_this._isEnabled()) {
reject('Bluetooth is not enabled');
return;
}
_this.stopCurrentScan();
resolve();
}
catch (ex) {
common_1.CLog(common_1.CLogTypes.info, 'stopScanning:', ex);
reject(ex);
}
});
};
Bluetooth.prototype.connect = function (arg) {
var _this = this;
if (!this.adapter) {
common_1.CLog(common_1.CLogTypes.error, 'stopCurrentScan: no adapter');
return Promise.reject('no_bluetooth');
}
return new Promise(function (resolve, reject) {
try {
if (!arg.UUID) {
reject('No UUID was passed');
return;
}
var bluetoothDevice = _this.adapter.getRemoteDevice(arg.UUID);
if (bluetoothDevice === null) {
reject('Could not find peripheral with UUID ' + arg.UUID);
}
else {
common_1.CLog(common_1.CLogTypes.info, 'connect ---- Connecting to peripheral with UUID:', arg.UUID);
var gatt = void 0;
if (getAndroidSDK() < MARSHMALLOW) {
gatt = bluetoothDevice.connectGatt(utils.ad.getApplicationContext(), false, _this.bluetoothGattCallback);
}
else {
gatt = bluetoothDevice.connectGatt(utils.ad.getApplicationContext(), false, _this.bluetoothGattCallback, android.bluetooth.BluetoothDevice.TRANSPORT_LE);
}
_this.connections[arg.UUID] = {
state: 'connecting',
onConnected: arg.onConnected,
onDisconnected: arg.onDisconnected,
device: gatt
};
resolve();
}
}
catch (ex) {
common_1.CLog(common_1.CLogTypes.error, 'connect ---- error:', ex);
reject(ex);
}
});
};
Bluetooth.prototype.disconnect = function (arg) {
var _this = this;
return new Promise(function (resolve, reject) {
try {
if (!arg.UUID) {
reject('No UUID was passed');
return;
}
var connection = _this.connections[arg.UUID];
common_1.CLog(common_1.CLogTypes.info, 'disconnect ---- connection:', arg.UUID);
if (!connection) {
reject("Peripheral wasn't connected");
return;
}
_this.gattDisconnect(connection.device);
resolve();
}
catch (ex) {
common_1.CLog(common_1.CLogTypes.error, 'disconnect ---- error:', ex);
reject(ex);
}
});
};
Bluetooth.prototype.read = function (arg) {
var _this = this;
return this.gattQueue.add(function () {
return new Promise(function (resolve, reject) {
try {
var wrapper = _this._getWrapper(arg, reject);
if (!wrapper) {
return;
}
var gatt = wrapper.gatt;
var bluetoothGattService = wrapper.bluetoothGattService;
var characteristicUUID = stringToUuid(arg.characteristicUUID);
common_1.CLog(common_1.CLogTypes.info, "read ---- peripheralUUID:" + arg.peripheralUUID + " serviceUUID:" + arg.serviceUUID + " characteristicUUID:" + arg.characteristicUUID);
var bluetoothGattCharacteristic = _this._findCharacteristicOfType(bluetoothGattService, characteristicUUID, android.bluetooth.BluetoothGattCharacteristic.PROPERTY_READ);
if (!bluetoothGattCharacteristic) {
reject("Could not find characteristic with UUID " + arg.characteristicUUID + " on service with UUID " + arg.serviceUUID + " on peripheral with UUID " + arg.peripheralUUID);
return;
}
var stateObject = _this.connections[arg.peripheralUUID];
stateObject.onReadPromise = resolve;
if (!gatt.readCharacteristic(bluetoothGattCharacteristic)) {
reject('Failed to read client characteristic read for ' + characteristicUUID);
}
}
catch (ex) {
common_1.CLog(common_1.CLogTypes.error, 'read ---- error:', ex);
reject(ex);
}
});
});
};
Bluetooth.prototype.write = function (arg) {
var _this = this;
return this.gattQueue.add(function () {
return new Promise(function (resolve, reject) {
try {
if (!arg.value) {
reject("You need to provide some data to write in the 'value' property");
return;
}
var wrapper = _this._getWrapper(arg, reject);
if (wrapper === null) {
return;
}
var characteristic = _this._findCharacteristicOfType(wrapper.bluetoothGattService, stringToUuid(arg.characteristicUUID), android.bluetooth.BluetoothGattCharacteristic.PROPERTY_WRITE);
if (!characteristic) {
reject("Could not find characteristic with UUID " + arg.characteristicUUID + " on service with UUID " + arg.serviceUUID + " on peripheral with UUID " + arg.peripheralUUID);
return;
}
var val = valueToByteArray(arg.value, arg.encoding);
if (val === null) {
reject('Invalid value: ' + arg.value);
return;
}
characteristic.setValue(val);
characteristic.setWriteType(android.bluetooth.BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
_this.connections[arg.peripheralUUID].onWritePromise = resolve;
if (wrapper.gatt.writeCharacteristic(characteristic)) {
if (common_1.BluetoothUtil.debug) {
common_1.CLog(common_1.CLogTypes.info, 'write ---- characteristic:', arg.value, printValueToString(val));
}
}
else {
reject("Failed to write to characteristic " + arg.characteristicUUID + ", " + val);
}
}
catch (ex) {
common_1.CLog(common_1.CLogTypes.error, 'write ---- error:', ex);
reject(ex);
}
});
});
};
Bluetooth.prototype.writeWithoutResponse = function (arg) {
var _this = this;
return this.gattQueue.add(function () {
return new Promise(function (resolve, reject) {
try {
if (!arg.value) {
reject("You need to provide some data to write in the 'value' property");
return;
}
var wrapper = _this._getWrapper(arg, reject);
if (!wrapper) {
return;
}
var characteristic = _this._findCharacteristicOfType(wrapper.bluetoothGattService, stringToUuid(arg.characteristicUUID), android.bluetooth.BluetoothGattCharacteristic.PROPERTY_WRITE);
if (!characteristic) {
reject("Could not find characteristic with UUID " + arg.characteristicUUID + " on service with UUID " + arg.serviceUUID + " on peripheral with UUID " + arg.peripheralUUID);
return;
}
var val = valueToByteArray(arg.value, arg.encoding);
if (!val) {
reject("Invalid value: " + arg.value);
return;
}
characteristic.setValue(val);
characteristic.setWriteType(android.bluetooth.BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
_this.connections[arg.peripheralUUID].onWritePromise = resolve;
if (wrapper.gatt.writeCharacteristic(characteristic)) {
if (common_1.BluetoothUtil.debug) {
common_1.CLog(common_1.CLogTypes.info, 'writeWithoutResponse:', arg.value, JSON.stringify(printValueToString(val)));
}
}
else {
reject("Failed to write to characteristic " + arg.characteristicUUID + ", " + val);
}
}
catch (ex) {
common_1.CLog(common_1.CLogTypes.error, 'writeWithoutResponse ---- error:', ex);
reject(ex);
}
});
});
};
Bluetooth.prototype.startNotifying = function (arg) {
var _this = this;
return this.gattQueue.add(function () {
return new Promise(function (resolve, reject) {
try {
var wrapper = _this._getWrapper(arg, reject);
if (!wrapper) {
return;
}
var gatt = wrapper.gatt;
var bluetoothGattService = wrapper.bluetoothGattService;
var characteristicUUID = stringToUuid(arg.characteristicUUID);
var characteristic = _this._findNotifyCharacteristic(bluetoothGattService, characteristicUUID);
common_1.CLog(common_1.CLogTypes.info, 'startNotifying ---- characteristic:', characteristic);
if (!characteristic) {
reject("Could not find characteristic with UUID " + arg.characteristicUUID + " on service with UUID " + arg.serviceUUID + " on peripheral with UUID " + arg.peripheralUUID);
return;
}
if (!gatt.setCharacteristicNotification(characteristic, true)) {
reject("Failed to register notification for characteristic " + arg.characteristicUUID);
return;
}
var clientCharacteristicConfigId = stringToUuid('2902');
var bluetoothGattDescriptor = characteristic.getDescriptor(clientCharacteristicConfigId);
if (!bluetoothGattDescriptor) {
bluetoothGattDescriptor = new android.bluetooth.BluetoothGattDescriptor(clientCharacteristicConfigId, android.bluetooth.BluetoothGattDescriptor.PERMISSION_WRITE);
characteristic.addDescriptor(bluetoothGattDescriptor);
common_1.CLog(common_1.CLogTypes.info, 'startNotifying ---- descriptor:', bluetoothGattDescriptor);
}
if ((characteristic.getProperties() & android.bluetooth.BluetoothGattCharacteristic.PROPERTY_NOTIFY) !== 0) {
bluetoothGattDescriptor.setValue(android.bluetooth.BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
}
else if ((characteristic.getProperties() & android.bluetooth.BluetoothGattCharacteristic.PROPERTY_INDICATE) !== 0) {
bluetoothGattDescriptor.setValue(android.bluetooth.BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
}
else {
reject("Characteristic " + characteristicUUID + " does not have NOTIFY or INDICATE property set.");
return;
}
if (gatt.writeDescriptor(bluetoothGattDescriptor)) {
var cb = arg.onNotify ||
function (result) {
common_1.CLog(common_1.CLogTypes.warning, "No 'onNotify' callback function specified for 'startNotifying'");
};
var stateObject = _this.connections[arg.peripheralUUID];
stateObject.onNotifyCallback = cb;
common_1.CLog(common_1.CLogTypes.info, '--- notifying');
resolve();
}
else {
reject("Failed to set client characteristic notification for " + characteristicUUID);
}
}
catch (ex) {
common_1.CLog(common_1.CLogTypes.error, 'startNotifying ---- error:', ex);
reject(ex);
}
});
});
};
Bluetooth.prototype.stopNotifying = function (arg) {
var _this = this;
return this.gattQueue.add(function () {
return new Promise(function (resolve, reject) {
try {
var wrapper = _this._getWrapper(arg, reject);
if (!wrapper) {
return;
}
var gatt = wrapper.gatt;
var gattService = wrapper.bluetoothGattService;
var characteristicUUID = stringToUuid(arg.characteristicUUID);
var characteristic = _this._findNotifyCharacteristic(gattService, characteristicUUID);
common_1.CLog(common_1.CLogTypes.info, 'stopNotifying ---- service characteristic:', characteristic);
if (!characteristic) {
reject("Could not find characteristic with UUID " + arg.characteristicUUID + " on service with UUID " + arg.serviceUUID + " on peripheral with UUID " + arg.peripheralUUID);
return;
}
var stateObject = _this.connections[arg.peripheralUUID];
stateObject.onNotifyCallback = null;
if (gatt.setCharacteristicNotification(characteristic, false)) {
resolve();
}
else {
reject('Failed to remove client characteristic notification for ' + characteristicUUID);
}
}
catch (ex) {
common_1.CLog(common_1.CLogTypes.error, 'stopNotifying:', ex);
reject(ex);
}
});
});
};
Bluetooth.prototype.gattDisconnect = function (gatt) {
if (gatt !== null) {
var device = gatt.getDevice();
var address = device.getAddress();
common_1.CLog(common_1.CLogTypes.info, 'gattDisconnect ---- device:', address);
var stateObject = this.connections[address];
if (stateObject && stateObject.onDisconnected) {
stateObject.onDisconnected({
UUID: address,
name: device.getName()
});
}
else {
common_1.CLog(common_1.CLogTypes.info, 'gattDisconnect ---- no disconnect callback found');
}
this.connections[address] = null;
common_1.CLog(common_1.CLogTypes.info, 'gattDisconnect ---- Closing GATT client');
gatt.close();
}
};
Bluetooth.prototype._findNotifyCharacteristic = function (bluetoothGattService, characteristicUUID) {
var characteristics = bluetoothGattService.getCharacteristics();
for (var i = 0; i < characteristics.size(); i++) {
var c = characteristics.get(i);
if ((c.getProperties() & android.bluetooth.BluetoothGattCharacteristic.PROPERTY_NOTIFY) !== 0 && characteristicUUID.equals(c.getUuid())) {
return c;
}
}
for (var j = 0; j < characteristics.size(); j++) {
var ch = characteristics.get(j);
if ((ch.getProperties() & android.bluetooth.BluetoothGattCharacteristic.PROPERTY_INDICATE) !== 0 && characteristicUUID.equals(ch.getUuid())) {
return ch;
}
}
return bluetoothGattService.getCharacteristic(characteristicUUID);
};
Bluetooth.prototype._findCharacteristicOfType = function (bluetoothGattService, characteristicUUID, charType) {
var characteristics = bluetoothGattService.getCharacteristics();
for (var i = 0; i < characteristics.size(); i++) {
var c = characteristics.get(i);
if ((c.getProperties() & charType) !== 0 && characteristicUUID.equals(c.getUuid())) {
return c;
}
}
return bluetoothGattService.getCharacteristic(characteristicUUID);
};
Bluetooth.prototype._getWrapper = function (arg, reject) {
if (!this._isEnabled()) {
reject('Bluetooth is not enabled');
return null;
}
if (!arg.peripheralUUID) {
reject('No peripheralUUID was passed');
return null;
}
if (!arg.serviceUUID) {
reject('No serviceUUID was passed');
return null;
}
if (!arg.characteristicUUID) {
reject('No characteristicUUID was passed');
return null;
}
var serviceUUID = stringToUuid(arg.serviceUUID);
var stateObject = this.connections[arg.peripheralUUID];
if (!stateObject) {
reject('The peripheral is disconnected');
return null;
}
var gatt = stateObject.device;
var bluetoothGattService = gatt.getService(serviceUUID);
if (!bluetoothGattService) {
reject("Could not find service with UUID " + arg.serviceUUID + " on peripheral with UUID " + arg.peripheralUUID);
return null;
}
return {
gatt: gatt,
bluetoothGattService: bluetoothGattService
};
};
Bluetooth.prototype._isEnabled = function () {
var adapter = this.adapter;
return adapter && adapter.isEnabled();
};
Bluetooth.prototype._getContext = function () {
var ctx = java.lang.Class.forName('android.app.AppGlobals')
.getMethod('getInitialApplication', null)
.invoke(null, null);
if (ctx) {
return ctx;
}
return java.lang.Class.forName('android.app.ActivityThread')
.getMethod('currentApplication', null)
.invoke(null, null);
};
Bluetooth.prototype._getActivity = function () {
var _this = this;
var activity = application.android.foregroundActivity || application.android.startActivity;
if (activity === null) {
setTimeout(function () {
_this._getActivity();
}, 250);
return;
}
else {
return activity;
}
};
Bluetooth.android = {
ScanMode: ScanMode,
MatchMode: MatchMode,
MatchNum: MatchNum,
CallbackType: CallbackType
};
return Bluetooth;
}(common_1.BluetoothCommon));
exports.Bluetooth = Bluetooth;
//# sourceMappingURL=android_main.js.map