diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractBTDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractBTDeviceSupport.java index 29d4ffeb8..4f5ba5397 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractBTDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractBTDeviceSupport.java @@ -9,6 +9,20 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceProtocol; +/** + * An abstract base class for all devices connected via Bluetooth + * (not Bluetooth LE). + * + * Such devices are typically connected with an (rfcomm) socket connection. + * This class uses two helper classes to deal with that: + * - GBDeviceIoThread, which creates and maintains the actual socket connection and implements the transport layer + * - GBDeviceProtocol, which implements the encoding and decoding of messages, i.e. the actual device specific protocol + * + * Note that these two classes need to be implemented in a device specific way. + * + * This implementation implements all methods of {@link EventHandler}, calls the {@link GBDeviceProtocol device protocol} + * to create the device specific message for the respective events and sends them to the device via {@link #sendToDevice(byte[])}. + */ public abstract class AbstractBTDeviceSupport extends AbstractDeviceSupport { private static final Logger LOG = LoggerFactory.getLogger(AbstractDeviceSupport.class); @@ -16,8 +30,14 @@ public abstract class AbstractBTDeviceSupport extends AbstractDeviceSupport { private GBDeviceProtocol gbDeviceProtocol; private GBDeviceIoThread gbDeviceIOThread; + /** + * Factory method to create the device specific GBDeviceProtocol instance to be used. + */ protected abstract GBDeviceProtocol createDeviceProtocol(); + /** + * Factory method to create the device specific GBDeviceIoThread instance to be used. + */ protected abstract GBDeviceIoThread createDeviceIOThread(); @Override @@ -40,6 +60,9 @@ public abstract class AbstractBTDeviceSupport extends AbstractDeviceSupport { // pairing dialog instead. } + /** + * Lazily creates and returns the GBDeviceProtocol instance to be used. + */ public synchronized GBDeviceProtocol getDeviceProtocol() { if (gbDeviceProtocol == null) { gbDeviceProtocol = createDeviceProtocol(); @@ -47,6 +70,9 @@ public abstract class AbstractBTDeviceSupport extends AbstractDeviceSupport { return gbDeviceProtocol; } + /** + * Lazily creates and returns the GBDeviceIoThread instance to be used. + */ public synchronized GBDeviceIoThread getDeviceIOThread() { if (gbDeviceIOThread == null) { gbDeviceIOThread = createDeviceIOThread(); @@ -54,6 +80,11 @@ public abstract class AbstractBTDeviceSupport extends AbstractDeviceSupport { return gbDeviceIOThread; } + /** + * Sends the given message to the device. This implementation delegates the + * writing to the {@link #getDeviceIOThread device io thread} + * @param bytes the message to send to the device + */ protected void sendToDevice(byte[] bytes) { if (bytes != null && gbDeviceIOThread != null) { gbDeviceIOThread.write(bytes); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractDeviceSupport.java index 1212c8288..1ef882658 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractDeviceSupport.java @@ -32,6 +32,11 @@ import nodomain.freeyourgadget.gadgetbridge.externalevents.NotificationListener; // TODO: support option for a single reminder notification when notifications could not be delivered? // conditions: app was running and received notifications, but device was not connected. // maybe need to check for "unread notifications" on device for that. + +/** + * Abstract implementation of DeviceSupport with some implementations for + * common functionality. Still transport independent. + */ public abstract class AbstractDeviceSupport implements DeviceSupport { private static final Logger LOG = LoggerFactory.getLogger(AbstractDeviceSupport.class); private static final int NOTIFICATION_ID_SCREENSHOT = 8000; @@ -40,7 +45,7 @@ public abstract class AbstractDeviceSupport implements DeviceSupport { private BluetoothAdapter btAdapter; private Context context; - public void initialize(GBDevice gbDevice, BluetoothAdapter btAdapter, Context context) { + public void setContext(GBDevice gbDevice, BluetoothAdapter btAdapter, Context context) { this.gbDevice = gbDevice; this.btAdapter = btAdapter; this.context = context; @@ -51,6 +56,11 @@ public abstract class AbstractDeviceSupport implements DeviceSupport { return gbDevice.isConnected(); } + /** + * Returns true if the device is not only connected, but also + * initialized. + * @see GBDevice#isInitialized() + */ protected boolean isInitialized() { return gbDevice.isInitialized(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java index c14bbee65..46db7d1af 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java @@ -166,7 +166,7 @@ public class BluetoothCommunicationService extends Service { mDeviceSupport = new ServiceDeviceSupport(new PebbleSupport()); } if (mDeviceSupport != null) { - mDeviceSupport.initialize(mGBDevice, mBtAdapter, this); + mDeviceSupport.setContext(mGBDevice, mBtAdapter, this); if (pair) { mDeviceSupport.pair(); } else { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/DeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/DeviceSupport.java index 1c9cb38c9..ea3808f6b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/DeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/DeviceSupport.java @@ -4,32 +4,79 @@ import android.bluetooth.BluetoothAdapter; import android.content.Context; /** - * Provides support for a specific device. Has hooks to manage the life cycle + * Provides the communication support for a specific device. Instances will only + * be used inside the BluetoothCommunicationService. Has hooks to manage the life cycle * of a device: instances of this interface will be created, initialized, and disposed * as needed. *
* Implementations need to act accordingly, in order to establish, reestablish or close * the connection to the device. * - * This interface is agnostic to the kind transport, i.e. whether the device is connected - * via Bluetooth, Bluetooth LE, Wifi or something else. + * In principle, this interface is agnostic to the kind of transport, i.e. whether the + * device is connected via Bluetooth, Bluetooth LE, Wifi or something else, however at the + * moment, only the BluetoothAdapter is passed to implementations. */ public interface DeviceSupport extends EventHandler { - void initialize(GBDevice gbDevice, BluetoothAdapter btAdapter, Context context); + /** + * Sets all context information needed for the instance to operate. + * @param gbDevice the device to operate with + * @param btAdapter the bluetooth adapter to use + * @param context the android context, e.g. to look up resources + */ + void setContext(GBDevice gbDevice, BluetoothAdapter btAdapter, Context context); + /** + * Returns whether a transport-level connection is established with the device + * @return whether the device is connected with the system running this software + */ boolean isConnected(); + /** + * Attempts to establish a connection to the device. Implementations may perform + * the connection in a synchronous or asynchronous way. + * Returns true if a connection attempt was made. If the implementation is synchronous + * it may also return true if the connection was successfully established, however + * callers shall not rely on that. + * + * The actual connection state change (successful or not) will be reported via the + * #getDevice device as a device change Intent. + * @see GBDevice#ACTION_DEVICE_CHANGED + */ boolean connect(); + /** + * Disposes of this instance, closing all connections and freeing all resources. + * Instances will not be reused after having been disposed. + */ void dispose(); - GBDevice getDevice(); - - BluetoothAdapter getBluetoothAdapter(); - - Context getContext(); - + /** + * Returns true if a connection attempt shall be made automatically whenever + * needed (e.g. when a notification shall be sent to the device while not connected. + */ boolean useAutoConnect(); + /** + * Attempts to pair and connect this device with the gadget device. Success + * will be reported via a device change Intent. + * @see GBDevice#ACTION_DEVICE_CHANGED + */ void pair(); + + /** + * Returns the associated device this instance communicates with. + */ + GBDevice getDevice(); + + /** + * Returns the bluetooth adapter. When we support different transports + * than Bluetooth, we should use a generic type T and rename this method + * to getTransportAdapter() + */ + BluetoothAdapter getBluetoothAdapter(); + + /** + * Returns the Android context to use, e.g. to look up resources. + */ + Context getContext(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/EventHandler.java index 78995fd37..25d576483 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/EventHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/EventHandler.java @@ -5,6 +5,11 @@ import android.net.Uri; import java.util.ArrayList; import java.util.UUID; +/** + * Specifies all events that GadgetBridge intends to send to the gadget device. + * Implementations can decide to ignore events that they do not support. + * Implementations need to send/encode event to the connected device. + */ public interface EventHandler { void onSMS(String from, String body); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ServiceDeviceSupport.java index 8ea3df39d..f0f7ad136 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ServiceDeviceSupport.java @@ -26,8 +26,8 @@ public class ServiceDeviceSupport implements DeviceSupport { } @Override - public void initialize(GBDevice gbDevice, BluetoothAdapter btAdapter, Context context) { - delegate.initialize(gbDevice, btAdapter, context); + public void setContext(GBDevice gbDevice, BluetoothAdapter btAdapter, Context context) { + delegate.setContext(gbDevice, btAdapter, context); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/btle/AbstractBTLEDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/btle/AbstractBTLEDeviceSupport.java index 5ad8b1397..378b3c351 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/btle/AbstractBTLEDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/btle/AbstractBTLEDeviceSupport.java @@ -18,6 +18,13 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.AbstractDeviceSupport; /** + * Abstract base class for all devices connected through Bluetooth Low Energy (LE) aka + * Bluetooth Smart. + * + * The connection to the device and all communication is made with a generic {@link BtLEQueue}. + * Messages to the device are encoded as {@link BtLEAction actions} that are grouped with a + * {@link Transaction} and sent via {@link BtLEQueue}. + * * @see TransactionBuilder * @see BtLEQueue */