package no.topi.fiken.display; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.util.Log; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; import java.util.Queue; class BtActionExecutor { private final static String TAG = BtActionExecutor.class.getSimpleName(); Queue actions = new ArrayDeque(); Queue fallbackActions = new ArrayDeque(); private final Runnable disconnect; List remoteRssi = new ArrayList(); BtActionExecutor(Runnable disconnect) { this.disconnect = disconnect; } public static final BtCallback waitForIt = new BtCallback("Wait for it") { @Override public boolean onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { Log.w(TAG, "wait for it...!"); return true; } }; public synchronized BtActionExecutor onSuccess(BtCallback btCallback) { actions.add(btCallback); return this; } public synchronized BtActionExecutor addFallback(BtCallback btCallback) { fallbackActions.add(btCallback); return this; } public synchronized BtActionExecutor onRemoteRssi(BluetoothGattCallback callback) { remoteRssi.add(callback); return this; } public void onEvent(String key, String values, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, BluetoothGattDescriptor descriptor, int status, int newState) { if (status != BluetoothGatt.GATT_SUCCESS) { Log.w(TAG, "Operation failed: " + key + ", " + values); return; } Log.i(TAG, "Bt action completed successfully: callback=" + key); BtCallback btCallback; synchronized (this) { if (actions.isEmpty()) { Log.d(TAG, "All Bluetooth actions are done"); for (BtCallback callback = fallbackActions.poll(); callback != null; callback = fallbackActions.poll()) { try { callCallback(key, gatt, characteristic, descriptor, newState, callback); } catch (NotOverriddenException e) { return; } } return; } try { Thread.sleep(1000); } catch (InterruptedException e) { // ignore } btCallback = actions.remove(); Log.i(TAG, "Executing bt action: " + btCallback.name); } boolean ok; try { ok = callCallback(key, gatt, characteristic, descriptor, newState, btCallback); } catch (NotOverriddenException e) { Log.w(TAG, "Unexpected callback by listener: " + key); disconnect.run(); return; } if (!ok) { Log.w(TAG, "Error performing Bluetooth action."); disconnect.run(); } } private Boolean callCallback(String key, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, BluetoothGattDescriptor descriptor, int newState, BtCallback btCallback) { if (key.equals("onConnectionStateChange")) { return btCallback.onConnectionStateChange(gatt, newState); } else if (key.equals("onServicesDiscovered")) { return btCallback.onServicesDiscovered(gatt); } else if (key.equals("onCharacteristicRead")) { return btCallback.onCharacteristicRead(gatt, characteristic); } else if (key.equals("onCharacteristicWrite")) { return btCallback.onCharacteristicWrite(gatt, characteristic); } else if (key.equals("onCharacteristicChanged")) { return btCallback.onCharacteristicChanged(gatt, characteristic); } else if (key.equals("onDescriptorRead")) { return btCallback.onDescriptorRead(gatt, descriptor); } else if (key.equals("onDescriptorWrite")) { return btCallback.onDescriptorWrite(gatt, descriptor); } else if (key.equals("onReliableWriteCompleted")) { return btCallback.onReliableWriteCompleted(gatt); } Log.w(TAG, "Unknown callback: " + key); return null; } public BluetoothGattCallback asCallback() { return new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { onEvent("onConnectionStateChange", "status=" + status + ", newState=" + newState, gatt, null, null, status, newState); } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { onEvent("onServicesDiscovered", "status=" + status, gatt, null, null, status, 9); } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { onEvent("onCharacteristicRead", "status=" + status + ", characteristic=" + characteristic.getUuid(), gatt, characteristic, null, status, 0); } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { onEvent("onCharacteristicWrite", "status=" + status + ", characteristic=" + characteristic.getUuid(), gatt, characteristic, null, status, 0); } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { onEvent("onCharacteristicChanged", "characteristic=" + characteristic.getUuid(), gatt, characteristic, null, BluetoothGatt.GATT_SUCCESS, 0); } @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { onEvent("onDescriptorRead", "status=" + status + ", descriptor=" + descriptor.getUuid(), gatt, null, descriptor, status, 0); } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { onEvent("onDescriptorWrite", "status=" + status + ", descriptor=" + descriptor.getUuid(), gatt, null, descriptor, status, 0); } @Override public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { onEvent("onReliableWriteCompleted", "status=" + status, gatt, null, null, status, 0); } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { for (BluetoothGattCallback callback : remoteRssi) { callback.onReadRemoteRssi(gatt, rssi, status); } } }; } }