diff options
author | Sven Gothel <[email protected]> | 2020-07-24 10:00:15 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-07-24 10:00:15 +0200 |
commit | 3437e34c97c1dad0c4c0d27680371f693aadac4f (patch) | |
tree | 5e2e5ad9dd3351ad5e332ed2159a0e6f3428a92e /java/direct_bt | |
parent | a1e74bf1e23f4833261556e55612f34afc8dbcf1 (diff) |
Reworking GATTCharacteristicListener (C++ and Java)
- Aligned all related C++ and Java API doc entries and made sure it matches implementation.
- Renaming SpecificGATTCharacteristicListener to AssociatedGATTCharacteristicListener,
as we refer to the associate GATTCharacteristic of a GATTCharacteristicListener
AssociatedGATTCharacteristicListener is a specialization knowing its
associated GATTCharacteristic to be used for match().
- Renamed 'configIndicationNotification(..)' to 'configNotificationIndication(..)',
matching order of arguments and the returned enabledState array.
- Exposed 'configNotificationIndication(..)' incl enabledState array to Java
- Clarified the 'add listener' and 'configNotificationIndication(..)' semantic in API doc
and implementation. Added new API entries to distinguish them.
- DBTGattCharacteristic.java skips adding its 'TinyB API compatibility' GATTCharacteristicListener
in case neither notify nor indicate property exist.
Also skip the native configNotificationIndication(..) in such case.
This reduces the overall listener load to GattHandler by factor 5!
- General: Add new method 'removeAllAssociatedCharacteristicListener(GATTCharacteristic)',
allowing removal of all GATTCharacteristic associated listener.
This is usefull to complete the GATTCharacteristic C++ dtor or Java close() operation.
- DBTDevice: Add GATTCharacteristicListener methods to align with Java API
and allow user not to deal with GATTHandler directly.
Convenience and validates the C++/Java API alignement.
- C++ JNICriticalArray: Added 2nd template typename for the java-array-type,
enabling it for other than jbyteArray. Here used for a jbooleanArray.
- The GATTCharacteristicListener Java to C++ native holding specialization JNICharacteristicListener
keeps a new global reference to the Java GATTCharacteristicListener
and the optional associated GATTCharacteristic.
This ensures the instances won't get garbage collected and hence ensures proper
object lifecycle even when passing 'throw away' listener object created just
for the add*Listener call.
- Removal and hence destruction of the listeners is always guaranteed at:
-- Device / GATTHandler disconnect
-- GattCharacteristic dtor or close
Diffstat (limited to 'java/direct_bt')
-rw-r--r-- | java/direct_bt/tinyb/DBTDevice.java | 11 | ||||
-rw-r--r-- | java/direct_bt/tinyb/DBTGattCharacteristic.java | 181 |
2 files changed, 99 insertions, 93 deletions
diff --git a/java/direct_bt/tinyb/DBTDevice.java b/java/direct_bt/tinyb/DBTDevice.java index 1f9ec3be..fa47a6ff 100644 --- a/java/direct_bt/tinyb/DBTDevice.java +++ b/java/direct_bt/tinyb/DBTDevice.java @@ -241,7 +241,8 @@ public class DBTDevice extends DBTObject implements BluetoothDevice return; } if( !isShutdown ) { // avoid all interaction @ JVM shutdown, native dtor (deleteImpl) cleans up. - disconnect(); + // implicit via disconnect, gatt.disconnect(): GATTHandler::removeAllCharacteristicListener(); + disconnectImpl(); // make sure, regardless of isConnected state disableConnectedNotifications(); disableRSSINotifications(); @@ -651,12 +652,18 @@ public class DBTDevice extends DBTObject implements BluetoothDevice protected native void deleteImpl(long nativeInstance); @Override - public native boolean addCharacteristicListener(final GATTCharacteristicListener listener, final BluetoothGattCharacteristic characteristicMatch); + public boolean addCharacteristicListener(final GATTCharacteristicListener listener) { + return addCharacteristicListener(listener, (DBTGattCharacteristic)listener.getAssociatedCharacteristic()); + } + private native boolean addCharacteristicListener(final GATTCharacteristicListener listener, final DBTGattCharacteristic associatedCharacteristic); @Override public native boolean removeCharacteristicListener(final GATTCharacteristicListener l); @Override + public native int removeAllAssociatedCharacteristicListener(final BluetoothGattCharacteristic associatedCharacteristic); + + @Override public native int removeAllCharacteristicListener(); /* local functionality */ diff --git a/java/direct_bt/tinyb/DBTGattCharacteristic.java b/java/direct_bt/tinyb/DBTGattCharacteristic.java index 7a0973f1..a5b07f2a 100644 --- a/java/direct_bt/tinyb/DBTGattCharacteristic.java +++ b/java/direct_bt/tinyb/DBTGattCharacteristic.java @@ -33,7 +33,6 @@ import org.tinyb.BluetoothException; import org.tinyb.BluetoothGattCharacteristic; import org.tinyb.BluetoothGattDescriptor; import org.tinyb.BluetoothGattService; -import org.tinyb.BluetoothManager; import org.tinyb.BluetoothNotification; import org.tinyb.BluetoothObject; import org.tinyb.BluetoothType; @@ -57,8 +56,8 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha /* Characteristics Property */ private final String[] properties; - // private final boolean hasNotify; - // private final boolean hasIndicate; + private final boolean hasNotify; + private final boolean hasIndicate; /* Characteristics Value Type UUID */ private final String value_type_uuid; @@ -96,41 +95,9 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha return valueChanged; } - private final GATTCharacteristicListener characteristicListener = new GATTCharacteristicListener() { - - @Override - public void notificationReceived(final BluetoothGattCharacteristic charDecl, final byte[] value, final long timestamp) { - final DBTGattCharacteristic cd = (DBTGattCharacteristic)charDecl; - if( !cd.equals(DBTGattCharacteristic.this) ) { - throw new InternalError("Filtered GATTCharacteristicListener.notificationReceived: Wrong Characteristic: Got "+charDecl+ - ", expected "+DBTGattCharacteristic.this.toString()); - } - final boolean valueChanged = updateCachedValue(value, true); - if( DEBUG ) { - System.err.println("GATTCharacteristicListener.notificationReceived: "+charDecl+ - ", value[changed "+valueChanged+", data "+BluetoothUtils.bytesHexString(value, true, true)+"]"); - } - } - - @Override - public void indicationReceived(final BluetoothGattCharacteristic charDecl, final byte[] value, final long timestamp, - final boolean confirmationSent) { - final DBTGattCharacteristic cd = (DBTGattCharacteristic)charDecl; - if( !cd.equals(DBTGattCharacteristic.this) ) { - throw new InternalError("Filtered GATTCharacteristicListener.indicationReceived: Wrong Characteristic: Got "+charDecl+ - ", expected "+DBTGattCharacteristic.this.toString()); - } - final boolean valueChanged = updateCachedValue(value, true); - if( DEBUG ) { - System.err.println("GATTCharacteristicListener.indicationReceived: "+charDecl+ - ", value[changed "+valueChanged+", data "+BluetoothUtils.bytesHexString(value, true, true)+"]"); - } - } - - }; - /* pp */ DBTGattCharacteristic(final long nativeInstance, final DBTGattService service, final short handle, final String[] properties, + final boolean hasNotify, final boolean hasIndicate, final String value_type_uuid, final short value_handle, final int clientCharacteristicsConfigIndex) { @@ -139,26 +106,47 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha this.handle = handle; this.properties = properties; - /** { - boolean hasNotify = false; - boolean hasIndicate = false; - for(int i=0; !hasNotify && !hasIndicate && i<properties.length; i++) { - if( "notify".equals(properties[i]) ) { - hasNotify = true; - } - if( "indicate".equals(properties[i]) ) { - hasIndicate = true; - } - } - this.hasNotify = hasNotify; - this.hasIndicate = hasIndicate; - } */ - + this.hasNotify = hasNotify; + this.hasIndicate = hasIndicate; this.value_type_uuid = value_type_uuid; this.value_handle = value_handle; this.clientCharacteristicsConfigIndex = clientCharacteristicsConfigIndex; this.descriptorList = getDescriptorsImpl(); - this.addCharacteristicListener(characteristicListener, false); // silent, don't enable native GATT ourselves + + if( hasNotify || hasIndicate ) { + // This characteristicListener serves TinyB 'enableValueNotification(..)' and 'getValue()' (cached value) + // backwards compatibility only! + final GATTCharacteristicListener characteristicListener = new GATTCharacteristicListener(this) { + @Override + public void notificationReceived(final BluetoothGattCharacteristic charDecl, final byte[] value, final long timestamp) { + final DBTGattCharacteristic cd = (DBTGattCharacteristic)charDecl; + if( !cd.equals(DBTGattCharacteristic.this) ) { + throw new InternalError("Filtered GATTCharacteristicListener.notificationReceived: Wrong Characteristic: Got "+charDecl+ + ", expected "+DBTGattCharacteristic.this.toString()); + } + final boolean valueChanged = updateCachedValue(value, true); + if( DEBUG ) { + System.err.println("GATTCharacteristicListener.notificationReceived: "+charDecl+ + ", value[changed "+valueChanged+", data "+BluetoothUtils.bytesHexString(value, true, true)+"]"); + } + } + @Override + public void indicationReceived(final BluetoothGattCharacteristic charDecl, final byte[] value, final long timestamp, + final boolean confirmationSent) { + final DBTGattCharacteristic cd = (DBTGattCharacteristic)charDecl; + if( !cd.equals(DBTGattCharacteristic.this) ) { + throw new InternalError("Filtered GATTCharacteristicListener.indicationReceived: Wrong Characteristic: Got "+charDecl+ + ", expected "+DBTGattCharacteristic.this.toString()); + } + final boolean valueChanged = updateCachedValue(value, true); + if( DEBUG ) { + System.err.println("GATTCharacteristicListener.indicationReceived: "+charDecl+ + ", value[changed "+valueChanged+", data "+BluetoothUtils.bytesHexString(value, true, true)+"]"); + } + } + }; + this.addCharacteristicListener(characteristicListener); // silent, don't enable native GATT ourselves + } } @Override @@ -166,8 +154,7 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha if( !isValid() ) { return; } - removeAllCharacteristicListener(); - disableValueNotifications(); + removeAllAssociatedCharacteristicListener(true); super.close(); } @@ -235,57 +222,74 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha public final List<BluetoothGattDescriptor> getDescriptors() { return descriptorList; } @Override - public final synchronized void enableValueNotifications(final BluetoothNotification<byte[]> callback) { - final boolean res = enableValueNotificationsImpl(true); - if( DEBUG ) { - System.err.println("GATTCharacteristicListener.enableValueNotifications: GATT Native: "+res); - } - valueNotificationCB = callback; - } - - @Override - public final synchronized void disableValueNotifications() { - try { - final boolean res = enableValueNotificationsImpl(false); + public final synchronized boolean configNotificationIndication(final boolean enableNotification, final boolean enableIndication, final boolean enabledState[/*2*/]) + throws IllegalStateException + { + if( hasNotify || hasIndicate ) { + final boolean res = configNotificationIndicationImpl(enableNotification, enableIndication, enabledState); if( DEBUG ) { - System.err.println("GATTCharacteristicListener.disableValueNotifications: GATT Native: "+res); + System.err.println("GATTCharacteristicListener.configNotificationIndication: "+res+", enableResult "+Arrays.toString(enabledState)); } - } catch (final Throwable t) { + return res; + } else { + enabledState[0] = false; + enabledState[1] = false; if( DEBUG ) { - System.err.println("Caught "+t.getMessage()); - t.printStackTrace(); + System.err.println("GATTCharacteristicListener.configNotificationIndication: FALSE*"); } + return false; } - valueNotificationCB = null; } + private native boolean configNotificationIndicationImpl(boolean enableNotification, boolean enableIndication, final boolean enabledState[/*2*/]) + throws IllegalStateException; @Override - public final boolean getNotifying() { - return null != valueNotificationCB; + public final boolean addCharacteristicListener(final GATTCharacteristicListener listener) { + return getService().getDevice().addCharacteristicListener(listener); } @Override - public final boolean addCharacteristicListener(final GATTCharacteristicListener listener) { - return addCharacteristicListener(listener, true); - } - private final boolean addCharacteristicListener(final GATTCharacteristicListener listener, final boolean nativeEnable) { - if( nativeEnable ) { - final boolean res = enableValueNotificationsImpl(true); - if( DEBUG ) { - System.err.println("GATTCharacteristicListener.addCharacteristicListener: GATT Native: "+res); - } + public final boolean addCharacteristicListener(final GATTCharacteristicListener listener, final boolean enabledState[/*2*/]) { + if( !configNotificationIndication(true /* enableNotification */, true /* enableIndication */, enabledState) ) { + return false; } - return getService().getDevice().addCharacteristicListener(listener, this); + return getService().getDevice().addCharacteristicListener(listener); } @Override - public final boolean removeCharacteristicListener(final GATTCharacteristicListener l) { + public final boolean removeCharacteristicListener(final GATTCharacteristicListener l, final boolean disableIndicationNotification) { + if( disableIndicationNotification ) { + configNotificationIndication(false /* enableNotification */, false /* enableIndication */, new boolean[2]); + } return getService().getDevice().removeCharacteristicListener(l); } @Override - public final int removeAllCharacteristicListener() { - return getService().getDevice().removeAllCharacteristicListener(); + public final int removeAllAssociatedCharacteristicListener(final boolean disableIndicationNotification) { + if( disableIndicationNotification ) { + configNotificationIndication(false /* enableNotification */, false /* enableIndication */, new boolean[2]); + } + return getService().getDevice().removeAllAssociatedCharacteristicListener(this); + } + + @Override + public final synchronized void enableValueNotifications(final BluetoothNotification<byte[]> callback) { + if( !configNotificationIndication(true /* enableNotification */, true /* enableIndication */, null) ) { + valueNotificationCB = null; + } else { + valueNotificationCB = callback; + } + } + + @Override + public final synchronized void disableValueNotifications() { + configNotificationIndication(false /* enableNotification */, false /* enableIndication */, null); + valueNotificationCB = null; + } + + @Override + public final boolean getNotifying() { + return null != valueNotificationCB; } /** @@ -325,11 +329,6 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha private native List<BluetoothGattDescriptor> getDescriptorsImpl(); - /** - * Enables disables GATT notification and/or indication. - */ - private native boolean enableValueNotificationsImpl(boolean v); - @Override protected native void deleteImpl(long nativeInstance); |