diff options
author | Alex Blasche <alexander.blasche@theqtcompany.com> | 2014-11-07 15:51:02 +0100 |
---|---|---|
committer | Alex Blasche <alexander.blasche@theqtcompany.com> | 2014-11-11 09:14:55 +0100 |
commit | a57a9a6598eb8fa2578ea8511b351b49d5b55ff0 (patch) | |
tree | 2b357b3aad43cfeaf14713a4d0c2900582d23c81 /src/android | |
parent | 327b6b7f8ff9acda74f403f2ff286e67f4202dfd (diff) |
The service->characteristic->descriptor tree becomes available in Qt
At the same time this fixes bugs the following bugs:
1.) Non-readable characteristics were not visible
2.) Crashes when descriptor/characteristic values were empty
3.) QLEService::discoverServiceDetails always finished with an
UnknownError
Missing/incorrect are still service details such as included services and
the service type (which currently always defaults to primary service).
Change-Id: Id73013a3784cd3c3f632102f13f5459ab37e95a6
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.java | 182 |
1 files changed, 160 insertions, 22 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 93b4a50d..9295c2bb 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.Collection; import java.util.Hashtable; import java.util.List; import java.util.UUID; @@ -165,18 +164,66 @@ public class QtBluetoothLE { android.bluetooth.BluetoothGattCharacteristic characteristic, int status) { + if (status != BluetoothGatt.GATT_SUCCESS) { + Log.w(TAG, "onCharacteristicRead error: " + status); + return; + } + + //runningHandle is only used during serviceDetailsDiscovery + //If it is -1 we got an update outside of the details discovery process + if (runningHandle == -1) { + List<Integer> handles = uuidToEntry.get(characteristic.getService().getUuid()); + if (handles == null || handles.isEmpty()) { + Log.w(TAG, "Received Characteristic read update for unknown characteristic"); + return; + } + int serviceHandle = handles.get(0); + GattEntry entry; + int foundHandle = -1; + try { + for (int i = 1; serviceHandle + i < entries.size() && foundHandle == -1; i++) { + entry = entries.get(serviceHandle + i); + if (entry == null) + continue; + + if (entry.type == GattEntryType.Service) { + Log.w(TAG, "Out-of-detail-discovery: found unknown characteristic for known service"); + break; //reached next service -> unknown characteristic in service + } + + if (entry.type != GattEntryType.Characteristic) + continue; + + if (entry.characteristic == characteristic) + foundHandle = serviceHandle + i; + } + } catch (IndexOutOfBoundsException ex) { + Log.w(TAG, "Out-of-detail-discovery: cannot find handle for characteristic"); + return; + } + + if (foundHandle == -1) { + Log.w(TAG, "Out-of-detail-discovery: char update failed"); + return; + } + + leCharacteristicRead(qtObject, characteristic.getService().getUuid().toString(), + foundHandle+1, characteristic.getUuid().toString(), + characteristic.getProperties(), characteristic.getValue()); + + return; + } + GattEntry entry = entries.get(runningHandle); entry.valueKnown = true; entries.set(runningHandle, entry); - String data = new String(characteristic.getValue()); - // Qt manages handles starting at 1, in Java we use a system starting with 0 - characteristic.getService().getUuid().toString(); + // Qt manages handles starting at 1, in Java we use a system starting with 0 //TODO avoid sending service uuid -> service handle should be sufficient leCharacteristicRead(qtObject, characteristic.getService().getUuid().toString(), - runningHandle+1, characteristic.getUuid().toString(), + runningHandle + 1, characteristic.getUuid().toString(), characteristic.getProperties(), characteristic.getValue()); - performServiceDiscoveryForHandle(runningHandle+1, false); + performServiceDetailDiscoveryForHandle(runningHandle + 1, false); } public void onCharacteristicWrite(android.bluetooth.BluetoothGatt gatt, @@ -196,10 +243,63 @@ public class QtBluetoothLE { android.bluetooth.BluetoothGattDescriptor descriptor, int status) { + if (status != BluetoothGatt.GATT_SUCCESS) { + Log.w(TAG, "onDescriptorRead error: " + status); + return; + } + + //runningHandle is only used during serviceDetailsDiscovery + //If it is -1 we got an update outside of the details discovery process + if (runningHandle == -1) { + List<Integer> handles = uuidToEntry.get(descriptor.getCharacteristic().getService().getUuid()); + if (handles == null || handles.isEmpty()) { + Log.w(TAG, "Received Descriptor read update for unknown descriptor"); + return; + } + + int serviceHandle = handles.get(0); + GattEntry entry; + int foundHandle = -1; + try { + for (int i = 1; serviceHandle + i < entries.size() && foundHandle == -1; i++) { + entry = entries.get(serviceHandle + i); + if (entry == null) + continue; + + if (entry.type == GattEntryType.Service) { + Log.w(TAG, "Out-of-detail-discovery: found unknown descriptor for known service"); + break; //reached next service -> unknown descriptor in service + } + + if (entry.type != GattEntryType.Descriptor) + continue; + + if (entry.descriptor == descriptor) + foundHandle = serviceHandle + i; + } + } catch (IndexOutOfBoundsException ex) { + Log.w(TAG, "Out-of-detail-discovery: cannot find handle for descriptor"); + return; + } + + if (foundHandle == -1) + Log.w(TAG, "Out-of-detail-discovery: char update failed"); + + leDescriptorRead(qtObject, descriptor.getCharacteristic().getService().getUuid().toString(), + descriptor.getCharacteristic().getUuid().toString(), foundHandle+1, + descriptor.getUuid().toString(), descriptor.getValue()); + return; + } + + GattEntry entry = entries.get(runningHandle); entry.valueKnown = true; entries.set(runningHandle, entry); - performServiceDiscoveryForHandle(runningHandle+1, false); + //TODO avoid sending service and characteristic uuid -> handles should be sufficient + leDescriptorRead(qtObject, descriptor.getCharacteristic().getService().getUuid().toString(), + descriptor.getCharacteristic().getUuid().toString(), runningHandle+1, + descriptor.getUuid().toString(), descriptor.getValue()); + performServiceDetailDiscoveryForHandle(runningHandle + 1, false); } public void onDescriptorWrite(android.bluetooth.BluetoothGatt gatt, @@ -263,6 +363,7 @@ public class QtBluetoothLE { public BluetoothGattService service = null; public BluetoothGattCharacteristic characteristic = null; public BluetoothGattDescriptor descriptor = null; + public int endHandle; } Hashtable<UUID, List<Integer>> uuidToEntry = new Hashtable<UUID, List<Integer>>(100); ArrayList<GattEntry> entries = new ArrayList<GattEntry>(100); @@ -275,11 +376,14 @@ public class QtBluetoothLE { GattEntry entry = null; List<BluetoothGattService> services = mBluetoothGatt.getServices(); for (BluetoothGattService service: services) { - entry = new GattEntry(); - entry.type = GattEntryType.Service; - entry.service = service; + GattEntry serviceEntry = new GattEntry(); + serviceEntry.type = GattEntryType.Service; + serviceEntry.service = service; entries.add(entry); + // remember handle for the service for later update + int serviceHandle = entries.size() - 1; + //some devices may have more than one service with the same uuid List<Integer> old = uuidToEntry.get(service.getUuid()); if (old == null) @@ -287,29 +391,32 @@ public class QtBluetoothLE { old.add(entries.size()-1); uuidToEntry.put(service.getUuid(), old); + // add all characteristics List<BluetoothGattCharacteristic> charList = service.getCharacteristics(); for (BluetoothGattCharacteristic characteristic: charList) { entry = new GattEntry(); entry.type = GattEntryType.Characteristic; entry.characteristic = characteristic; entries.add(entry); - //uuidToEntry.put(characteristic.getUuid(), entries.size()-1); // this emulates GATT value attributes entry = new GattEntry(); entry.type = GattEntryType.CharacteristicValue; entries.add(entry); - //uuidToEntry.put(characteristic.getUuid(), entry); + // add all descriptors List<BluetoothGattDescriptor> descList = characteristic.getDescriptors(); for (BluetoothGattDescriptor desc: descList) { entry = new GattEntry(); entry.type = GattEntryType.Descriptor; entry.descriptor = desc; entries.add(entry); - //uuidToEntry.put(desc.getUuid(), entries.size()-1); } } + + // update endHandle of current service + serviceEntry.endHandle = entries.size() - 1; + entries.set(serviceHandle, serviceEntry); } entries.trimToSize(); @@ -364,7 +471,7 @@ public class QtBluetoothLE { } if (!entry.valueKnown) { - performServiceDiscoveryForHandle(serviceHandle, true); + performServiceDetailDiscoveryForHandle(serviceHandle, true); } else { Log.w(TAG, "Service already discovered"); } @@ -379,15 +486,19 @@ public class QtBluetoothLE { private void finishCurrentServiceDiscovery() { + int currentEntry = currentServiceInDiscovery; GattEntry discoveredService = entries.get(currentServiceInDiscovery); discoveredService.valueKnown = true; entries.set(currentServiceInDiscovery, discoveredService); + runningHandle = -1; currentServiceInDiscovery = -1; - leServiceDetailDiscoveryFinished(qtObject, discoveredService.service.getUuid().toString()); + + leServiceDetailDiscoveryFinished(qtObject, discoveredService.service.getUuid().toString(), + currentEntry + 1, discoveredService.endHandle + 1); } - private synchronized void performServiceDiscoveryForHandle(int nextHandle, boolean searchStarted) + private synchronized void performServiceDetailDiscoveryForHandle(int nextHandle, boolean searchStarted) { try { if (searchStarted) { @@ -411,17 +522,40 @@ public class QtBluetoothLE { switch (entry.type) { case Characteristic: result = mBluetoothGatt.readCharacteristic(entry.characteristic); - if (!result) - performServiceDiscoveryForHandle(runningHandle+1, false); + try { + if (!result) { + // add characteristic now since we won't get a read update later one + // this is possible when the characteristic is not readable + Log.d(TAG, "Non-readable characteristic " + entry.characteristic.getUuid() + + " for service " + entry.characteristic.getService().getUuid()); + leCharacteristicRead(qtObject, entry.characteristic.getService().getUuid().toString(), + nextHandle + 1, entry.characteristic.getUuid().toString(), + entry.characteristic.getProperties(), entry.characteristic.getValue()); + performServiceDetailDiscoveryForHandle(runningHandle + 1, false); + } + } catch (Exception ex) + { + ex.printStackTrace(); + } break; case CharacteristicValue: // ignore -> nothing to do for this artificial type - performServiceDiscoveryForHandle(runningHandle+1, false); + performServiceDetailDiscoveryForHandle(runningHandle + 1, false); break; case Descriptor: result = mBluetoothGatt.readDescriptor(entry.descriptor); - if (!result) - performServiceDiscoveryForHandle(runningHandle+1, false); + if (!result) { + // atm all descriptor types are readable + Log.d(TAG, "Non-readable descriptor " + entry.descriptor.getUuid() + + " for service/char" + entry.descriptor.getCharacteristic().getService().getUuid() + + "/" + entry.descriptor.getCharacteristic().getUuid()); + leDescriptorRead(qtObject, + entry.descriptor.getCharacteristic().getService().getUuid().toString(), + entry.descriptor.getCharacteristic().getUuid().toString(), + nextHandle+1, entry.descriptor.getUuid().toString(), + entry.descriptor.getValue()); + performServiceDetailDiscoveryForHandle(runningHandle + 1, false); + } break; case Service: finishCurrentServiceDiscovery(); @@ -438,9 +572,13 @@ public class QtBluetoothLE { public native void leConnectionStateChange(long qtObject, int wasErrorTransition, int newState); public native void leServicesDiscovered(long qtObject, int errorCode, String uuidList); - public native void leServiceDetailDiscoveryFinished(long qtObject, final String serviceUuid); + public native void leServiceDetailDiscoveryFinished(long qtObject, final String serviceUuid, + int startHandle, int endHandle); public native void leCharacteristicRead(long qtObject, String serviceUuid, int charHandle, String charUuid, int properties, byte[] data); + public native void leDescriptorRead(long qtObject, String serviceUuid, String charUuid, + int descHandle, String descUuid, byte[] data); + } |