Initial support for transaction-local GattCallbacks (not used yet)

So that we won't have to mix everything in MiBandSupport
master
cpfeiffer 2015-08-05 23:24:58 +02:00
parent 495a8cc650
commit b7223c7e86
4 changed files with 119 additions and 22 deletions

View File

@ -0,0 +1,42 @@
package nodomain.freeyourgadget.gadgetbridge.service.btle;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
/**
* Base class for GattCallbacks wishing to just implement a few of the methods.
*/
public abstract class AbstractGattCallback implements GattCallback {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt) {
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
}
@Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
}
}

View File

@ -9,6 +9,7 @@ import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.support.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -19,9 +20,9 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
/**
* One queue/thread per connectable device.
@ -49,7 +50,7 @@ public final class BtLEQueue {
private CountDownLatch mWaitForActionResultLatch;
private CountDownLatch mConnectionLatch;
private BluetoothGattCharacteristic mWaitCharacteristic;
private GattCallback mExternalGattCallback;
private final InternalGattCallback internalGattCallback;
private Thread dispatchThread = new Thread("GadgetBridge GATT Dispatcher") {
@ -60,6 +61,8 @@ public final class BtLEQueue {
while (!mDisposed && !mCrashed) {
try {
Transaction transaction = mTransactions.take();
internalGattCallback.setTransactionGattCallback(null);
if (!isConnected()) {
// TODO: request connection and initialization from the outside and wait until finished
@ -73,6 +76,7 @@ public final class BtLEQueue {
mConnectionLatch = null;
}
internalGattCallback.setTransactionGattCallback(transaction.getGattCallback());
mAbortTransaction = false;
// Run all actions of the transaction until one doesn't succeed
for (BtLEAction action : transaction.getActions()) {
@ -106,6 +110,7 @@ public final class BtLEQueue {
} finally {
mWaitForActionResultLatch = null;
mWaitCharacteristic = null;
internalGattCallback.reset();
}
}
LOG.info("Queue Dispatch Thread terminated.");
@ -115,7 +120,7 @@ public final class BtLEQueue {
public BtLEQueue(BluetoothAdapter bluetoothAdapter, GBDevice gbDevice, GattCallback externalGattCallback, Context context) {
mBluetoothAdapter = bluetoothAdapter;
mGbDevice = gbDevice;
mExternalGattCallback = externalGattCallback;
internalGattCallback = new InternalGattCallback(externalGattCallback);
mContext = context;
dispatchThread.start();
@ -254,7 +259,25 @@ public final class BtLEQueue {
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback internalGattCallback = new BluetoothGattCallback() {
private final class InternalGattCallback extends BluetoothGattCallback {
private @Nullable GattCallback mTransactionGattCallback;
private GattCallback mExternalGattCallback;
public InternalGattCallback(GattCallback externalGattCallback) {
mExternalGattCallback = externalGattCallback;
}
public void setTransactionGattCallback(@Nullable GattCallback callback) {
mTransactionGattCallback = callback;
}
private GattCallback getCallbackToUse() {
if (mTransactionGattCallback != null) {
return mTransactionGattCallback;
}
return mExternalGattCallback;
}
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
LOG.debug("connection state change, newState: " + newState + getStatusString(status));
@ -293,9 +316,9 @@ public final class BtLEQueue {
}
if (status == BluetoothGatt.GATT_SUCCESS) {
if (mExternalGattCallback != null) {
if (getCallbackToUse() != null) {
// only propagate the successful event
mExternalGattCallback.onServicesDiscovered(gatt);
getCallbackToUse().onServicesDiscovered(gatt);
}
} else {
LOG.warn("onServicesDiscovered received: " + status);
@ -308,8 +331,8 @@ public final class BtLEQueue {
if (!checkCorrectGattInstance(gatt, "characteristic write")) {
return;
}
if (mExternalGattCallback != null) {
mExternalGattCallback.onCharacteristicWrite(gatt, characteristic, status);
if (getCallbackToUse() != null) {
getCallbackToUse().onCharacteristicWrite(gatt, characteristic, status);
}
checkWaitingCharacteristic(characteristic, status);
}
@ -322,8 +345,8 @@ public final class BtLEQueue {
if (!checkCorrectGattInstance(gatt, "characteristic read")) {
return;
}
if (mExternalGattCallback != null) {
mExternalGattCallback.onCharacteristicRead(gatt, characteristic, status);
if (getCallbackToUse() != null) {
getCallbackToUse().onCharacteristicRead(gatt, characteristic, status);
}
checkWaitingCharacteristic(characteristic, status);
}
@ -334,8 +357,8 @@ public final class BtLEQueue {
if (!checkCorrectGattInstance(gatt, "descriptor read")) {
return;
}
if (mExternalGattCallback != null) {
mExternalGattCallback.onDescriptorRead(gatt, descriptor, status);
if (getCallbackToUse() != null) {
getCallbackToUse().onDescriptorRead(gatt, descriptor, status);
}
checkWaitingCharacteristic(descriptor.getCharacteristic(), status);
}
@ -346,8 +369,8 @@ public final class BtLEQueue {
if (!checkCorrectGattInstance(gatt, "descriptor write")) {
return;
}
if (mExternalGattCallback != null) {
mExternalGattCallback.onDescriptorWrite(gatt, descriptor, status);
if (getCallbackToUse() != null) {
getCallbackToUse().onDescriptorWrite(gatt, descriptor, status);
}
checkWaitingCharacteristic(descriptor.getCharacteristic(), status);
}
@ -363,8 +386,8 @@ public final class BtLEQueue {
LOG.info("Ignoring characteristic change event from wrong BluetoothGatt instance");
return;
}
if (mExternalGattCallback != null) {
mExternalGattCallback.onCharacteristicChanged(gatt, characteristic);
if (getCallbackToUse() != null) {
getCallbackToUse().onCharacteristicChanged(gatt, characteristic);
}
}
@ -378,8 +401,8 @@ public final class BtLEQueue {
LOG.info("Ignoring remote rssi event from wrong BluetoothGatt instance");
return;
}
if (mExternalGattCallback != null) {
mExternalGattCallback.onReadRemoteRssi(gatt, rssi, status);
if (getCallbackToUse() != null) {
getCallbackToUse().onReadRemoteRssi(gatt, rssi, status);
}
}
@ -398,9 +421,13 @@ public final class BtLEQueue {
}
}
}
};
private String getStatusString(int status) {
return status == BluetoothGatt.GATT_SUCCESS ? " (success)" : " (failed: " + status + ")";
}
private String getStatusString(int status) {
return status == BluetoothGatt.GATT_SUCCESS ? " (success)" : " (failed: " + status + ")";
}
public void reset() {
mTransactionGattCallback = null;
}
};
}

View File

@ -1,5 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge.service.btle;
import android.support.annotation.Nullable;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
@ -17,6 +19,7 @@ public class Transaction {
private String mName;
private List<BtLEAction> mActions = new ArrayList<>(4);
private long creationTimestamp = System.currentTimeMillis();
private @Nullable GattCallback gattCallback;
public Transaction(String taskName) {
this.mName = taskName;
@ -46,4 +49,15 @@ public class Transaction {
public String toString() {
return String.format(Locale.US, "%s: Transaction task: %s with %d actions", getCreationTime(), getTaskName(), mActions.size());
}
public void setGattCallback(@Nullable GattCallback callback) {
gattCallback = callback;
}
/**
* Returns the GattCallback for this transaction, or null if none.
*/
public @Nullable GattCallback getGattCallback() {
return gattCallback;
}
}

View File

@ -1,6 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge.service.btle;
import android.bluetooth.BluetoothGattCharacteristic;
import android.support.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -60,6 +61,19 @@ public class TransactionBuilder {
return this;
}
/**
* Sets a GattCallback instance that will be called when the transaction is executed,
* resulting in GattCallback events.
* @param callback the callback to set, may be null
*/
public void setGattCallback(@Nullable GattCallback callback) {
mTransaction.setGattCallback(callback);
}
public @Nullable GattCallback getGattCallback() {
return mTransaction.getGattCallback();
}
/**
* To be used as the final step to execute the transaction by the given queue.
*