Skip to content

Commit 6fb87d9

Browse files
authored
Merge pull request #236 from facetious/facetious/fix-android-notification-disable
fix(android): Notification streams are now properly disabled when stop requested.
2 parents b418954 + b4afb5a commit 6fb87d9

File tree

1 file changed

+111
-83
lines changed

1 file changed

+111
-83
lines changed

src/bluetooth.android.ts

Lines changed: 111 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -2278,19 +2278,8 @@ export class Bluetooth extends BluetoothCommon {
22782278
const cUUID = uuidToString(characteristic.getUuid());
22792279
const sUUID = uuidToString(characteristic.getService().getUuid());
22802280

2281-
const stateObject = this.connections[pUUID];
2282-
stateObject.onNotifyCallbacks = stateObject.onNotifyCallbacks || {};
22832281
const key = sUUID + '/' + cUUID;
22842282
const onNotify = args.onNotify;
2285-
stateObject.onNotifyCallbacks[key] = function (result) {
2286-
// CLog(
2287-
// CLogTypes.warning,
2288-
// `onNotifyCallback ---- UUID: ${UUID}, pUUID: ${pUUID}, cUUID: ${cUUID}, args.characteristicUUID: ${
2289-
// args.characteristicUUID
2290-
// }, sUUID: ${sUUID}, args.serviceUUID: ${args.serviceUUID}, result: ${result}`
2291-
// );
2292-
onNotify(result);
2293-
};
22942283

22952284
this.attachSubDelegate(
22962285
{methodName, args, resolve, reject},
@@ -2305,11 +2294,16 @@ export class Bluetooth extends BluetoothCommon {
23052294
}
23062295

23072296
if (UUID === pUUID && cUUID === args.characteristicUUID && sUUID === args.serviceUUID) {
2308-
if (status === GATT_SUCCESS) {
2297+
if (status === GATT_SUCCESS && descriptor.getValue() !== android.bluetooth.BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE) {
2298+
// only assign notify callback when receiving a successful response
2299+
const stateObject = this.connections[pUUID];
2300+
stateObject.onNotifyCallbacks = stateObject.onNotifyCallbacks || {};
2301+
stateObject.onNotifyCallbacks[key] = function (result) {
2302+
onNotify(result);
2303+
};
23092304
resolve();
23102305
clearListeners();
23112306
} else {
2312-
delete stateObject.onNotifyCallbacks[key];
23132307
onError(
23142308
new BluetoothError(BluetoothCommon.msg_error_function_call, {
23152309
arguments: args,
@@ -2318,8 +2312,6 @@ export class Bluetooth extends BluetoothCommon {
23182312
})
23192313
);
23202314
}
2321-
} else {
2322-
delete stateObject.onNotifyCallbacks[key];
23232315
}
23242316
},
23252317
}),
@@ -2347,74 +2339,110 @@ export class Bluetooth extends BluetoothCommon {
23472339
return this.addToQueue(
23482340
args,
23492341
(wrapper) =>
2350-
new Promise<void>((resolve, reject) => {
2351-
const gatt = wrapper.gatt;
2352-
const gattService = wrapper.bluetoothGattService;
2353-
const characteristicUUID = stringToUuid(args.characteristicUUID);
2354-
2355-
const characteristic = this._findNotifyCharacteristic(gattService, characteristicUUID);
2356-
if (Trace.isEnabled()) {
2357-
CLog(CLogTypes.info, `${methodName} ---- peripheralUUID:${args.peripheralUUID} serviceUUID:${args.serviceUUID} characteristicUUID:${args.characteristicUUID}`);
2358-
}
2359-
2360-
if (!characteristic) {
2361-
return reject(
2362-
new BluetoothError(BluetoothCommon.msg_no_characteristic, {
2363-
method: methodName,
2364-
arguments: args,
2365-
})
2366-
);
2367-
}
2368-
2369-
const stateObject = this.connections[args.peripheralUUID];
2370-
if (stateObject && stateObject.onNotifyCallbacks) {
2371-
const key = args.serviceUUID + '/' + args.characteristicUUID;
2372-
delete stateObject.onNotifyCallbacks[key];
2373-
}
2374-
const clearListeners = () => {
2375-
this.removeDisconnectListener(onDisconnect);
2376-
};
2377-
const onError = (err) => {
2378-
reject(err);
2379-
clearListeners();
2380-
};
2381-
const onDisconnect = (address) => {
2382-
if (address === args.peripheralUUID) {
2383-
onError(
2384-
new BluetoothError(BluetoothCommon.msg_peripheral_disconnected, {
2385-
method: methodName,
2386-
arguments: args,
2387-
})
2388-
);
2389-
}
2390-
};
2391-
this.addDisconnectListener(onDisconnect);
2392-
try {
2393-
if (gatt.setCharacteristicNotification(characteristic, false)) {
2394-
resolve();
2395-
clearListeners();
2396-
} else {
2397-
onError(
2398-
new BluetoothError(BluetoothCommon.msg_error_function_call, {
2399-
method: 'setCharacteristicNotification',
2400-
arguments: args,
2401-
})
2402-
);
2403-
}
2404-
} catch (ex) {
2405-
if (Trace.isEnabled()) {
2406-
CLog(CLogTypes.error, methodName, ex);
2407-
}
2408-
onError(
2409-
new BluetoothError(ex.message, {
2410-
stack: ex.stackTrace || ex.stack,
2411-
nativeException: ex.nativeException,
2412-
arguments: args,
2413-
method: methodName,
2414-
})
2415-
);
2416-
}
2417-
})
2342+
new Promise<void>((resolve, reject) => {
2343+
const gatt = wrapper.gatt;
2344+
const bluetoothGattService = wrapper.bluetoothGattService;
2345+
const characteristicUUID = stringToUuid(args.characteristicUUID);
2346+
2347+
const characteristic = this._findNotifyCharacteristic(bluetoothGattService, characteristicUUID);
2348+
if (Trace.isEnabled()) {
2349+
CLog(CLogTypes.info, `${methodName} ---- peripheralUUID:${args.peripheralUUID} serviceUUID:${args.serviceUUID} characteristicUUID:${args.characteristicUUID}`);
2350+
}
2351+
if (!characteristic) {
2352+
return reject(
2353+
new BluetoothError(BluetoothCommon.msg_no_characteristic, {
2354+
method: methodName,
2355+
arguments: args,
2356+
})
2357+
);
2358+
}
2359+
2360+
if (!gatt.setCharacteristicNotification(characteristic, false)) {
2361+
return reject(
2362+
new BluetoothError(BluetoothCommon.msg_error_function_call, {
2363+
method: 'setCharacteristicNotification',
2364+
arguments: args,
2365+
})
2366+
);
2367+
}
2368+
2369+
const clientCharacteristicConfigId = stringToUuid('2902');
2370+
let bluetoothGattDescriptor = characteristic.getDescriptor(clientCharacteristicConfigId) as android.bluetooth.BluetoothGattDescriptor;
2371+
if (!bluetoothGattDescriptor) {
2372+
bluetoothGattDescriptor = new android.bluetooth.BluetoothGattDescriptor(clientCharacteristicConfigId, android.bluetooth.BluetoothGattDescriptor.PERMISSION_WRITE);
2373+
bluetoothGattDescriptor.setValue(android.bluetooth.BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
2374+
characteristic.addDescriptor(bluetoothGattDescriptor);
2375+
if (Trace.isEnabled()) {
2376+
CLog(CLogTypes.info, methodName, '---- descriptor:', bluetoothGattDescriptor);
2377+
}
2378+
// Any creation error will trigger the global catch. Ok.
2379+
}
2380+
2381+
// prefer notify over indicate
2382+
if ((characteristic.getProperties() & android.bluetooth.BluetoothGattCharacteristic.PROPERTY_NOTIFY) !== 0) {
2383+
bluetoothGattDescriptor.setValue(android.bluetooth.BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
2384+
} else if ((characteristic.getProperties() & android.bluetooth.BluetoothGattCharacteristic.PROPERTY_INDICATE) !== 0) {
2385+
bluetoothGattDescriptor.setValue(android.bluetooth.BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
2386+
} else {
2387+
return reject(
2388+
new BluetoothError(BluetoothCommon.msg_characteristic_cant_notify, {
2389+
method: methodName,
2390+
arguments: args,
2391+
})
2392+
);
2393+
}
2394+
2395+
const pUUID = args.peripheralUUID;
2396+
const cUUID = uuidToString(characteristic.getUuid());
2397+
const sUUID = uuidToString(characteristic.getService().getUuid());
2398+
2399+
const key = sUUID + '/' + cUUID;
2400+
this.attachSubDelegate(
2401+
{methodName, args, resolve, reject},
2402+
(clearListeners, onError) => ({
2403+
onDescriptorWrite: (gatt: android.bluetooth.BluetoothGatt, descriptor: android.bluetooth.BluetoothGattDescriptor, status: number) => {
2404+
const device = gatt.getDevice();
2405+
let UUID: string = null;
2406+
if (device == null) {
2407+
// happens some time, why ... ?
2408+
} else {
2409+
UUID = device.getAddress();
2410+
}
2411+
2412+
if (UUID === pUUID && cUUID === args.characteristicUUID && sUUID === args.serviceUUID) {
2413+
if (status === GATT_SUCCESS && descriptor.getValue() === android.bluetooth.BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE) {
2414+
// Only delete callback on successful disable
2415+
const stateObject = this.connections[args.peripheralUUID];
2416+
if (stateObject && stateObject.onNotifyCallbacks) {
2417+
const key = args.serviceUUID + '/' + args.characteristicUUID;
2418+
delete stateObject.onNotifyCallbacks[key];
2419+
}
2420+
resolve();
2421+
clearListeners();
2422+
} else {
2423+
onError(
2424+
new BluetoothError(BluetoothCommon.msg_error_function_call, {
2425+
arguments: args,
2426+
method: 'writeDescriptor',
2427+
status,
2428+
})
2429+
);
2430+
}
2431+
}
2432+
},
2433+
}),
2434+
(onError) => {
2435+
if (!gatt.writeDescriptor(bluetoothGattDescriptor)) {
2436+
onError(
2437+
new BluetoothError(BluetoothCommon.msg_error_function_call, {
2438+
method: 'writeDescriptor',
2439+
arguments: args,
2440+
})
2441+
);
2442+
}
2443+
},
2444+
);
2445+
})
24182446
);
24192447
}
24202448

0 commit comments

Comments
 (0)