summaryrefslogtreecommitdiffstats
path: root/src/android
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@theqtcompany.com>2014-11-10 15:07:20 +0100
committerAlex Blasche <alexander.blasche@theqtcompany.com>2014-11-12 09:19:29 +0100
commitd2c2e502dcee44d06eb0b0ad392571d7bc3021bf (patch)
tree7e05f7d978664b363e856ccfdc88619266a882fe /src/android
parentb299a75a1d90dfd44c0f11ad75665c087c9ea120 (diff)
Improve reliability of QLEController connect()/disconnect()/connect()
Quick disconnecting and reconnecting caused some bugs and revealed some unreliabe API behavior on Android. The internal data structures were never cleaned up when disconnecting from the remote device. If multiple QLEService objects of the same QLEController instance requested a service discovery, every request but the first failed. This was fixed by queueing up the service discovery requests. Last but not least, reusing the same BluetoothGatt instance for the reconnect is very error prone. It may well be caused by Android API bugs. The reconnect would sometimes fail or toggle the connect/disconnect flag a couple of times which is not a problem for the Qt API itself but the stability of the related unit test (see tst_QLowEnergyController::tst_concurrentDiscovery()). Therefore we won't reuse the same BluetoothGatt instance but rather request a new one. Change-Id: I314f2a30960284b9bcd4926f4944c415a6d75788 Reviewed-by: Timur Pocheptsov <Timur.Pocheptsov@digia.com> Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
Diffstat (limited to 'src/android')
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java55
1 files changed, 49 insertions, 6 deletions
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 0ed4962b..84744a4d 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
@@ -46,6 +46,7 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.Hashtable;
+import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
@@ -124,7 +125,13 @@ public class QtBluetoothLE {
//This must be in sync with QLowEnergyController::ControllerState
switch (newState) {
case BluetoothProfile.STATE_DISCONNECTED:
- qLowEnergyController_State = 0; break;
+ qLowEnergyController_State = 0;
+ // we disconnected -> get rid of data from previous run
+ resetServiceDetailData();
+ // reset mBluetoothGatt, reusing same object is not very reliable
+ // sometimes it reconnects and sometimes it does not.
+ mBluetoothGatt = null;
+ break;
case BluetoothProfile.STATE_CONNECTED:
qLowEnergyController_State = 2;
}
@@ -169,6 +176,11 @@ public class QtBluetoothLE {
return;
}
+ synchronized (this) {
+ if (uuidToEntry.isEmpty()) // ignore data if internal setup is not ready;
+ return;
+ }
+
//runningHandle is only used during serviceDetailsDiscovery
//If it is -1 we got an update outside of the details discovery process
if (runningHandle == -1) {
@@ -248,6 +260,11 @@ public class QtBluetoothLE {
return;
}
+ synchronized (this) {
+ if (uuidToEntry.isEmpty()) // ignore data if internal setup is not ready;
+ return;
+ }
+
//runningHandle is only used during serviceDetailsDiscovery
//If it is -1 we got an update outside of the details discovery process
if (runningHandle == -1) {
@@ -323,9 +340,6 @@ public class QtBluetoothLE {
public boolean connect() {
- if (mBluetoothGatt != null)
- return mBluetoothGatt.connect();
-
mRemoteGattDevice = mBluetoothAdapter.getRemoteDevice(mRemoteGattAddress);
if (mRemoteGattDevice == null)
return false;
@@ -367,6 +381,7 @@ public class QtBluetoothLE {
}
Hashtable<UUID, List<Integer>> uuidToEntry = new Hashtable<UUID, List<Integer>>(100);
ArrayList<GattEntry> entries = new ArrayList<GattEntry>(100);
+ private LinkedList<Integer> servicesToBeDiscovered = new LinkedList<Integer>();
private void populateHandles()
{
@@ -424,6 +439,16 @@ public class QtBluetoothLE {
private int currentServiceInDiscovery = -1;
private int runningHandle = -1;
+
+ private synchronized void resetServiceDetailData()
+ {
+ runningHandle = -1;
+ currentServiceInDiscovery = -1;
+ uuidToEntry.clear();
+ entries.clear();
+ servicesToBeDiscovered.clear();
+ }
+
public synchronized boolean discoverServiceDetails(String serviceUuid)
{
try {
@@ -466,8 +491,16 @@ public class QtBluetoothLE {
return true;
if (currentServiceInDiscovery != -1) {
- Log.w(TAG, "Service discovery already running on another service");
- return false;
+ // we are currently discovering another service
+ // we queue the new one up until we finish the previous one
+ if (!entry.valueKnown) {
+ servicesToBeDiscovered.add(serviceHandle);
+ Log.w(TAG, "Service discovery already running on another service, " +
+ "queueing request for " + serviceUuid);
+ } else {
+ Log.w(TAG, "Service already known");
+ }
+ return true;
}
if (!entry.valueKnown) {
@@ -496,6 +529,16 @@ public class QtBluetoothLE {
leServiceDetailDiscoveryFinished(qtObject, discoveredService.service.getUuid().toString(),
currentEntry + 1, discoveredService.endHandle + 1);
+
+ if (!servicesToBeDiscovered.isEmpty()) {
+ try {
+ int nextService = servicesToBeDiscovered.remove();
+ performServiceDetailDiscoveryForHandle(nextService, true);
+ } catch (IndexOutOfBoundsException ex) {
+ Log.w(TAG, "Expected queued service but didn't find any");
+ return;
+ }
+ }
}
private synchronized void performServiceDetailDiscoveryForHandle(int nextHandle, boolean searchStarted)