2015-04-19 02:37:29 +02:00
|
|
|
package nodomain.freeyourgadget.gadgetbridge.btle;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Set;
|
|
|
|
import java.util.UUID;
|
|
|
|
|
|
|
|
import nodomain.freeyourgadget.gadgetbridge.AbstractDeviceSupport;
|
2015-04-22 22:50:35 +02:00
|
|
|
import android.bluetooth.BluetoothGatt;
|
|
|
|
import android.bluetooth.BluetoothGattCharacteristic;
|
|
|
|
import android.bluetooth.BluetoothGattService;
|
|
|
|
import android.bluetooth.BluetoothProfile;
|
|
|
|
import android.util.Log;
|
2015-04-19 02:37:29 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @see TransactionBuilder
|
|
|
|
* @see BtLEQueue
|
|
|
|
*/
|
|
|
|
public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport implements GattCallback {
|
|
|
|
private static final String TAG = "AbstractBTLEDeviceSupport";
|
2015-04-19 11:28:03 +02:00
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
private BtLEQueue mQueue;
|
|
|
|
private HashMap<UUID, BluetoothGattCharacteristic> mAvailableCharacteristics;
|
|
|
|
private Set<UUID> mSupportedServices = new HashSet<>(4);
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean connect() {
|
|
|
|
if (mQueue == null) {
|
|
|
|
mQueue = new BtLEQueue(getBluetoothAdapter(), getDevice(), this, getContext());
|
|
|
|
}
|
|
|
|
return mQueue.connect();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Subclasses should populate the given builder to initialize the device (if necessary).
|
2015-04-19 11:28:03 +02:00
|
|
|
*
|
2015-04-19 02:37:29 +02:00
|
|
|
* @param builder
|
|
|
|
* @return the same builder as passed as the argument
|
|
|
|
*/
|
|
|
|
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
|
|
|
|
return builder;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void dispose() {
|
|
|
|
if (mQueue != null) {
|
|
|
|
mQueue.dispose();
|
|
|
|
}
|
|
|
|
}
|
2015-04-19 11:28:03 +02:00
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
/**
|
|
|
|
* Send commands like this to the device:
|
|
|
|
* <p>
|
|
|
|
* <code>perform("sms notification").write(someCharacteristic, someByteArray).queue(getQueue());</code>
|
|
|
|
* </p>
|
|
|
|
* TODO: support orchestration of multiple reads and writes depending on returned values
|
2015-04-19 11:28:03 +02:00
|
|
|
*
|
2015-04-19 02:37:29 +02:00
|
|
|
* @see #performConnected(Transaction)
|
|
|
|
* @see #initializeDevice(TransactionBuilder)
|
|
|
|
*/
|
|
|
|
protected TransactionBuilder performInitialized(String taskName) throws IOException {
|
|
|
|
if (!isConnected()) {
|
|
|
|
if (!connect()) {
|
|
|
|
throw new IOException("1: Unable to connect to device: " + getDevice());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!isInitialized()) {
|
|
|
|
// first, add a transaction that performs device initialization
|
|
|
|
TransactionBuilder builder = new TransactionBuilder("Initialize device");
|
|
|
|
initializeDevice(builder).queue(getQueue());
|
|
|
|
}
|
|
|
|
return new TransactionBuilder(taskName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param transaction
|
|
|
|
* @throws IOException
|
|
|
|
* @see {@link #performInitialized(String)}
|
|
|
|
*/
|
|
|
|
protected void performConnected(Transaction transaction) throws IOException {
|
|
|
|
if (!isConnected()) {
|
|
|
|
if (!connect()) {
|
|
|
|
throw new IOException("2: Unable to connect to device: " + getDevice());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
getQueue().add(transaction);
|
|
|
|
}
|
|
|
|
|
|
|
|
public BtLEQueue getQueue() {
|
|
|
|
return mQueue;
|
|
|
|
}
|
2015-04-19 11:28:03 +02:00
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
/**
|
|
|
|
* Subclasses should call this method to add services they support.
|
|
|
|
* Only supported services will be queried for characteristics.
|
2015-04-19 11:28:03 +02:00
|
|
|
*
|
2015-04-19 02:37:29 +02:00
|
|
|
* @param aSupportedService
|
|
|
|
* @see #getCharacteristic(UUID)
|
|
|
|
*/
|
|
|
|
protected void addSupportedService(UUID aSupportedService) {
|
|
|
|
mSupportedServices.add(aSupportedService);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the characteristic matching the given UUID. Only characteristics
|
|
|
|
* are returned whose service is marked as supported.
|
2015-04-19 11:28:03 +02:00
|
|
|
*
|
2015-04-19 02:37:29 +02:00
|
|
|
* @param uuid
|
|
|
|
* @return the characteristic for the given UUID or <code>null</code>
|
|
|
|
* @see #addSupportedService(UUID)
|
|
|
|
*/
|
|
|
|
protected BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
|
|
|
|
if (mAvailableCharacteristics == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return mAvailableCharacteristics.get(uuid);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void gattServicesDiscovered(List<BluetoothGattService> discoveredGattServices) {
|
|
|
|
mAvailableCharacteristics = null;
|
|
|
|
|
|
|
|
if (discoveredGattServices == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Set<UUID> supportedServices = getSupportedServices();
|
2015-04-19 11:28:03 +02:00
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
for (BluetoothGattService service : discoveredGattServices) {
|
|
|
|
if (supportedServices.contains(service.getUuid())) {
|
|
|
|
List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
|
|
|
|
if (characteristics == null || characteristics.isEmpty()) {
|
|
|
|
Log.w(TAG, "Supported LE service " + service.getUuid() + "did not return any characteristics");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
mAvailableCharacteristics = new HashMap<>(characteristics.size());
|
|
|
|
for (BluetoothGattCharacteristic characteristic : characteristics) {
|
|
|
|
mAvailableCharacteristics.put(characteristic.getUuid(), characteristic);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected Set<UUID> getSupportedServices() {
|
|
|
|
return mSupportedServices;
|
|
|
|
}
|
|
|
|
|
|
|
|
// default implementations of event handler methods (gatt callbacks)
|
|
|
|
@Override
|
|
|
|
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
|
|
|
|
}
|
2015-04-19 11:28:03 +02:00
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
@Override
|
|
|
|
public void onServicesDiscovered(BluetoothGatt gatt) {
|
|
|
|
gattServicesDiscovered(getQueue().getSupportedGattServices());
|
2015-04-22 22:50:35 +02:00
|
|
|
initializeDevice(new TransactionBuilder("Initializing device")).queue(getQueue());
|
2015-04-19 02:37:29 +02:00
|
|
|
}
|
2015-04-19 11:28:03 +02:00
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
@Override
|
|
|
|
public void onCharacteristicRead(BluetoothGatt gatt,
|
2015-04-19 11:28:03 +02:00
|
|
|
BluetoothGattCharacteristic characteristic, int status) {
|
2015-04-19 02:37:29 +02:00
|
|
|
}
|
2015-04-19 11:28:03 +02:00
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
@Override
|
|
|
|
public void onCharacteristicWrite(BluetoothGatt gatt,
|
2015-04-19 11:28:03 +02:00
|
|
|
BluetoothGattCharacteristic characteristic, int status) {
|
2015-04-19 02:37:29 +02:00
|
|
|
}
|
2015-04-19 11:28:03 +02:00
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
@Override
|
|
|
|
public void onCharacteristicChanged(BluetoothGatt gatt,
|
2015-04-19 11:28:03 +02:00
|
|
|
BluetoothGattCharacteristic characteristic) {
|
2015-04-19 02:37:29 +02:00
|
|
|
}
|
2015-04-19 11:28:03 +02:00
|
|
|
|
2015-04-22 22:50:35 +02:00
|
|
|
@Override
|
2015-04-19 02:37:29 +02:00
|
|
|
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
|
|
|
|
}
|
|
|
|
}
|