diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ControlCenter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ControlCenter.java index cfa192d2..d7bde89f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ControlCenter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ControlCenter.java @@ -20,6 +20,9 @@ import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -30,6 +33,7 @@ import nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst; public class ControlCenter extends Activity { + private static final Logger LOG = LoggerFactory.getLogger(ControlCenter.class); public static final String ACTION_QUIT = "nodomain.freeyourgadget.gadgetbride.controlcenter.action.quit"; @@ -57,7 +61,7 @@ public class ControlCenter extends Activity { refreshPairedDevices(); break; case GBDevice.ACTION_DEVICE_CHANGED: - GBDevice dev = intent.getParcelableExtra("device"); + GBDevice dev = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE); if (dev.getAddress() != null) { int index = deviceList.indexOf(dev); // search by address if (index >= 0) { @@ -68,7 +72,8 @@ public class ControlCenter extends Activity { } refreshPairedDevices(); - if (dev.isConnected() && dev.getFirmwareVersion() == null) { + if (dev.isConnected() && dev.getFirmwareVersion() == null && !dev.isInitializing()) { + LOG.info("device connected, requesting more info"); requestDeviceInfo(); } break; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDevice.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDevice.java index 42cafaa8..9ddbdb28 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDevice.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDevice.java @@ -104,6 +104,10 @@ public class GBDevice implements Parcelable { return mState.ordinal() >= State.CONNECTED.ordinal(); } + public boolean isInitializing() { + return mState == State.INITIALIZING; + } + public boolean isInitialized() { return mState.ordinal() >= State.INITIALIZED.ordinal(); } @@ -118,7 +122,9 @@ public class GBDevice implements Parcelable { public void setState(State state) { mState = state; - unsetDynamicState(); + if (state.ordinal() <= State.CONNECTED.ordinal()) { + unsetDynamicState(); + } } private void unsetDynamicState() { @@ -136,6 +142,8 @@ public class GBDevice implements Parcelable { return GBApplication.getContext().getString(R.string.connecting); case CONNECTED: return GBApplication.getContext().getString(R.string.connected); + case INITIALIZING: + return GBApplication.getContext().getString(R.string.initializing); case INITIALIZED: return GBApplication.getContext().getString(R.string.initialized); } @@ -238,6 +246,7 @@ public class GBDevice implements Parcelable { NOT_CONNECTED, CONNECTING, CONNECTED, + INITIALIZING, INITIALIZED } 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 9764dfe7..5ad8b139 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/btle/AbstractBTLEDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/btle/AbstractBTLEDeviceSupport.java @@ -77,6 +77,7 @@ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport im if (!isInitialized()) { // first, add a transaction that performs device initialization TransactionBuilder builder = createTransactionBuilder("Initialize device"); + builder.add(new CheckInitializedAction(gbDevice)); initializeDevice(builder).queue(getQueue()); } return createTransactionBuilder(taskName); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/btle/BtLEQueue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/btle/BtLEQueue.java index 5de3cffd..c5126024 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/btle/BtLEQueue.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/btle/BtLEQueue.java @@ -87,15 +87,14 @@ public final class BtLEQueue { } } } catch (InterruptedException ignored) { - mWaitForActionResultLatch = null; mConnectionLatch = null; LOG.debug("Thread interrupted"); } catch (Throwable ex) { LOG.error("Queue Dispatch Thread died: " + ex.getMessage()); mCrashed = true; - mWaitForActionResultLatch = null; mConnectionLatch = null; } finally { + mWaitForActionResultLatch = null; mWaitCharacteristic = null; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/btle/CheckInitializedAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/btle/CheckInitializedAction.java new file mode 100644 index 00000000..eafdf750 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/btle/CheckInitializedAction.java @@ -0,0 +1,37 @@ +package nodomain.freeyourgadget.gadgetbridge.btle; + +import android.bluetooth.BluetoothGatt; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import nodomain.freeyourgadget.gadgetbridge.GBDevice; + +/** + * A special action that is executed at the very front of the initialization + * sequence (transaction). It will abort the entire initialization sequence + * by returning false, when the device is already initialized. + */ +public class CheckInitializedAction extends BtLEAction { + private static final Logger LOG = LoggerFactory.getLogger(CheckInitializedAction.class); + + private final GBDevice device; + + public CheckInitializedAction(GBDevice gbDevice) { + device = gbDevice; + } + + @Override + public boolean run(BluetoothGatt gatt) { + boolean continueWithOtherInitActions = !device.isInitialized(); + if (!continueWithOtherInitActions) { + LOG.info("Aborting device initialization, because already initialized: " + device); + } + return continueWithOtherInitActions; + } + + @Override + public boolean expectsResult() { + return false; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandSupport.java index cb2f3bea..8847225e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandSupport.java @@ -55,15 +55,27 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { @Override protected TransactionBuilder initializeDevice(TransactionBuilder builder) { + builder.add(new SetDeviceStateAction(getDevice(), State.INITIALIZING, getContext())); pair(builder) .sendUserInfo(builder) .enableNotifications(builder, true) .setCurrentTime(builder) - .requestBatteryInfo(builder); + .requestBatteryInfo(builder) + .setInitialized(builder); return builder; } + /** + * Last action of initialization sequence. Sets the device to initialized. + * It is only invoked if all other actions were successfully run, so the device + * must be initialized, then. + * @param builder + */ + private void setInitialized(TransactionBuilder builder) { + builder.add(new SetDeviceStateAction(getDevice(), State.INITIALIZED, getContext())); + } + // TODO: tear down the notifications on quit private MiBandSupport enableNotifications(TransactionBuilder builder, boolean enable) { builder.notify(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_NOTIFICATION), enable) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/SetDeviceStateAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/SetDeviceStateAction.java new file mode 100644 index 00000000..673e2a46 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/SetDeviceStateAction.java @@ -0,0 +1,35 @@ +package nodomain.freeyourgadget.gadgetbridge.miband; + +import android.bluetooth.BluetoothGatt; +import android.content.Context; + +import nodomain.freeyourgadget.gadgetbridge.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.btle.BtLEAction; + +public class SetDeviceStateAction extends BtLEAction { + private final GBDevice device; + private final GBDevice.State deviceState; + private final Context context; + + public SetDeviceStateAction(GBDevice device, GBDevice.State deviceState, Context context) { + this.device = device; + this.deviceState = deviceState; + this.context = context; + } + + @Override + public boolean run(BluetoothGatt gatt) { + device.setState(deviceState); + device.sendDeviceUpdateIntent(getContext()); + return true; + } + + @Override + public boolean expectsResult() { + return false; + } + + public Context getContext() { + return context; + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d297f632..52d30e88 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -104,5 +104,6 @@ Sleep Monitor LogToFile Write Log Files (needs restart) + initializing