From 43536fcb2970bcf3fa67b36777a9cf16ff46363d Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Tue, 2 Dec 2014 15:33:10 +0100 Subject: Android: Fix automatic notification sending when device demands it Some BTLE devices enable notifications be default. However since Android's BTLE API requires a call to BluetoothGatt.setCharacteristicNotification(..) to forward them, we have to peek at the ClientCharacteristicConfigurations during the service detail discovery and tell Android to forward the notification when required. Change-Id: Ief419404694d70a1373218c1b8275ef868a49ddb Reviewed-by: Timur Pocheptsov Reviewed-by: Alex Blasche --- .../qtproject/qt5/android/bluetooth/QtBluetoothLE.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/android') diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java index ea5d6ce6..edeacb82 100644 --- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java +++ b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java @@ -347,6 +347,24 @@ public class QtBluetoothLE { leDescriptorRead(qtObject, descriptor.getCharacteristic().getService().getUuid().toString(), descriptor.getCharacteristic().getUuid().toString(), runningHandle+1, descriptor.getUuid().toString(), descriptor.getValue()); + + /* Some devices preset ClientCharacteristicConfiguration descriptors + * to enable notifications out of the box. However the additional + * BluetoothGatt.setCharacteristicNotification call prevents + * automatic notifications from coming through. Hence we manually set them + * up here. + */ + + if (descriptor.getUuid().compareTo(clientCharacteristicUuid) == 0) { + final int value = descriptor.getValue()[0]; + // notification or indication bit set? + if ((value & 0x03) > 0) { + Log.d(TAG, "Found descriptor with automatic notifications."); + mBluetoothGatt.setCharacteristicNotification( + descriptor.getCharacteristic(), true); + } + } + performServiceDetailDiscoveryForHandle(runningHandle + 1, false); } -- cgit v1.2.3 From 01ea948742b649ad482c2e3e6d914fc1ac5f4917 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Tue, 2 Dec 2014 14:41:38 +0100 Subject: Android: enable writing of characteristics without response mode Change-Id: I9c26aaa11857db8dc33a99d42347a9b7f6281ad7 Reviewed-by: Timur Pocheptsov Reviewed-by: Alex Blasche --- .../qt5/android/bluetooth/QtBluetoothLE.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'src/android') diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java index edeacb82..748d709e 100644 --- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java +++ b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java @@ -450,6 +450,7 @@ public class QtBluetoothLE { { public GattEntry entry; public byte[] newValue; + public int requestedWriteType; } private final Hashtable> uuidToEntry = new Hashtable>(100); @@ -805,7 +806,8 @@ public class QtBluetoothLE { /* Write Characteristics */ /*************************************************************/ - public boolean writeCharacteristic(int charHandle, byte[] newValue) + public boolean writeCharacteristic(int charHandle, byte[] newValue, + int writeMode) { if (mBluetoothGatt == null) return false; @@ -822,6 +824,17 @@ public class QtBluetoothLE { newJob.newValue = newValue; newJob.entry = entry; + // writeMode must be in sync with QLowEnergyService::WriteMode + // For now we ignore SignedWriteType as Qt doesn't support it yet. + switch (writeMode) { + case 1: //WriteWithoutResponse + newJob.requestedWriteType = BluetoothGattCharacteristic. WRITE_TYPE_NO_RESPONSE; + break; + default: + newJob.requestedWriteType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT; + break; + } + boolean result; synchronized (writeQueue) { result = writeQueue.add(newJob); @@ -856,6 +869,7 @@ public class QtBluetoothLE { WriteJob newJob = new WriteJob(); newJob.newValue = newValue; newJob.entry = entry; + newJob.requestedWriteType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT; boolean result; synchronized (writeQueue) { @@ -891,6 +905,9 @@ public class QtBluetoothLE { boolean result; switch (nextJob.entry.type) { case Characteristic: + if (nextJob.entry.characteristic.getWriteType() != nextJob.requestedWriteType) { + nextJob.entry.characteristic.setWriteType(nextJob.requestedWriteType); + } result = nextJob.entry.characteristic.setValue(nextJob.newValue); if (!result || !mBluetoothGatt.writeCharacteristic(nextJob.entry.characteristic)) skip = true; -- cgit v1.2.3 From 90491cb94b5aaad8c9aded106fea0aba09ac4be9 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Wed, 3 Dec 2014 14:19:48 +0100 Subject: Don't update cached char value when property is not readable In addition we update the documentation to reflect the slightly changed API behavior. Change-Id: Ieddee750aa35a32d3c01213dfbf678ee2a1d88d7 Reviewed-by: Timur Pocheptsov Reviewed-by: Alex Blasche --- .../src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/android') diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java index 748d709e..b9f7e184 100644 --- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java +++ b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java @@ -919,7 +919,7 @@ public class QtBluetoothLE { into two operations. BluetoothGatt.enableCharacteristicNotification ensures the local Blueooth stack forwards the notifications. In addition, BluetoothGattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) - must be written to the peripheral + must be written to the peripheral. */ -- cgit v1.2.3 From 9856b182bb43ff36266e63027f18f67a0ce244ea Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Fri, 5 Dec 2014 13:11:55 +0100 Subject: Cleanup Bluetooth Java code These points were raised by Android-studio's Code analyzer Change-Id: I5481b7ca74ec902b289a71096879e32301ee6494 Reviewed-by: Timur Pocheptsov Reviewed-by: Alex Blasche --- .../qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java | 12 +++++++----- .../qt5/android/bluetooth/QtBluetoothInputStreamThread.java | 5 ++++- .../org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java | 6 +++--- .../qt5/android/bluetooth/QtBluetoothSocketServer.java | 11 +++++++---- 4 files changed, 21 insertions(+), 13 deletions(-) (limited to 'src/android') diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java index f12e68fa..c8453a0b 100644 --- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java +++ b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java @@ -40,7 +40,7 @@ import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; + import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashSet; @@ -49,7 +49,9 @@ import java.util.List; public class QtBluetoothBroadcastReceiver extends BroadcastReceiver { /* Pointer to the Qt object that "owns" the Java object */ + @SuppressWarnings("WeakerAccess") long qtObject = 0; + @SuppressWarnings("WeakerAccess") static Activity qtactivity = null; private static final int TURN_BT_ON = 3330; @@ -158,11 +160,11 @@ public class QtBluetoothBroadcastReceiver extends BroadcastReceiver //process found remote connections but avoid duplications HashSet set = new HashSet(); - for (int i = 0; i < gattConnections.size(); i++) - set.add(gattConnections.get(i).toString()); + for (Object gattConnection : gattConnections) + set.add(gattConnection.toString()); - for (int i = 0; i < gattServerConnections.size(); i++) - set.add(gattServerConnections.get(i).toString()); + for (Object gattServerConnection : gattServerConnections) + set.add(gattServerConnection.toString()); return set.toArray(new String[set.size()]); } catch (Exception ex) { diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothInputStreamThread.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothInputStreamThread.java index 30ada8c9..455054a8 100644 --- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothInputStreamThread.java +++ b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothInputStreamThread.java @@ -37,10 +37,13 @@ import java.io.InputStream; import java.io.IOException; import android.util.Log; +@SuppressWarnings("WeakerAccess") public class QtBluetoothInputStreamThread extends Thread { /* Pointer to the Qt object that "owns" the Java object */ + @SuppressWarnings("CanBeFinal") long qtObject = 0; + @SuppressWarnings("CanBeFinal") public boolean logEnabled = false; private static final String TAG = "QtBluetooth"; private InputStream m_inputStream = null; @@ -68,7 +71,7 @@ public class QtBluetoothInputStreamThread extends Thread } byte[] buffer = new byte[1000]; - int bytesRead = 0; + int bytesRead; try { while (!isInterrupted()) { diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java index b9f7e184..10aaf9ca 100644 --- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java +++ b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java @@ -45,7 +45,6 @@ import android.bluetooth.BluetoothProfile; import android.util.Log; import java.util.ArrayList; -import java.util.Arrays; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; @@ -58,7 +57,7 @@ public class QtBluetoothLE { private BluetoothGatt mBluetoothGatt = null; private String mRemoteGattAddress; - final UUID clientCharacteristicUuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); + private final UUID clientCharacteristicUuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); /* Pointer to the Qt object that "owns" the Java object */ @@ -67,6 +66,7 @@ public class QtBluetoothLE { @SuppressWarnings("WeakerAccess") Activity qtactivity = null; + @SuppressWarnings("WeakerAccess") public QtBluetoothLE() { mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); } @@ -917,7 +917,7 @@ public class QtBluetoothLE { /* For some reason, Android splits characteristic notifications into two operations. BluetoothGatt.enableCharacteristicNotification - ensures the local Blueooth stack forwards the notifications. In addition, + ensures the local Bluetooth stack forwards the notifications. In addition, BluetoothGattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) must be written to the peripheral. */ diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer.java index ae0a03a5..1b1aaac9 100644 --- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer.java +++ b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer.java @@ -40,11 +40,14 @@ import android.util.Log; import java.io.IOException; import java.util.UUID; +@SuppressWarnings("WeakerAccess") public class QtBluetoothSocketServer extends Thread { /* Pointer to the Qt object that "owns" the Java object */ + @SuppressWarnings({"WeakerAccess", "CanBeFinal"}) long qtObject = 0; + @SuppressWarnings({"WeakerAccess", "CanBeFinal"}) public boolean logEnabled = false; private static final String TAG = "QtBluetooth"; @@ -54,9 +57,9 @@ public class QtBluetoothSocketServer extends Thread private BluetoothServerSocket m_serverSocket = null; //error codes - public static final int QT_NO_BLUETOOTH_SUPPORTED = 0; - public static final int QT_LISTEN_FAILED = 1; - public static final int QT_ACCEPT_FAILED = 2; + private static final int QT_NO_BLUETOOTH_SUPPORTED = 0; + private static final int QT_LISTEN_FAILED = 1; + private static final int QT_ACCEPT_FAILED = 2; public QtBluetoothSocketServer() { @@ -97,7 +100,7 @@ public class QtBluetoothSocketServer extends Thread return; } - BluetoothSocket s = null; + BluetoothSocket s; if (m_serverSocket != null) { try { while (!isInterrupted()) { -- cgit v1.2.3