mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-28 21:06:50 +01:00
Initial work on synchronizing activity data with feedback.
A device now has a busy flag (set during synchronization). While busy, no other communication with the device shall occur (TODO) Refactors the non-bluetooth actions a bit #45 Next step: make use of the busy state in ControlCenter (show a busy cursor) and in BluetoothCommunicationService (to not call other operations while busy)
This commit is contained in:
parent
2f0d00d645
commit
9e4e50be47
@ -150,6 +150,12 @@ public abstract class AbstractBTDeviceSupport extends AbstractDeviceSupport {
|
||||
sendToDevice(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSynchronizeActivityData() {
|
||||
byte[] bytes = gbDeviceProtocol.encodeSynchronizeActivityData();
|
||||
sendToDevice(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReboot() {
|
||||
byte[] bytes = gbDeviceProtocol.encodeReboot();
|
||||
|
@ -27,6 +27,8 @@ public interface EventHandler {
|
||||
|
||||
void onPhoneVersion(byte os);
|
||||
|
||||
void onSynchronizeActivityData();
|
||||
|
||||
void onReboot();
|
||||
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ public class GBDevice implements Parcelable {
|
||||
private short mBatteryLevel = BATTERY_UNKNOWN;
|
||||
private String mBatteryState;
|
||||
private short mRssi = RSSI_UNKNOWN;
|
||||
private String mBusyTask;
|
||||
|
||||
public GBDevice(String address, String name, DeviceType deviceType) {
|
||||
mAddress = address;
|
||||
@ -54,6 +55,8 @@ public class GBDevice implements Parcelable {
|
||||
mBatteryLevel = (short) in.readInt();
|
||||
mBatteryState = in.readString();
|
||||
mRssi = (short) in.readInt();
|
||||
mBusyTask = in.readString();
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
@ -68,6 +71,7 @@ public class GBDevice implements Parcelable {
|
||||
dest.writeInt(mBatteryLevel);
|
||||
dest.writeString(mBatteryState);
|
||||
dest.writeInt(mRssi);
|
||||
dest.writeString(mBusyTask);
|
||||
}
|
||||
|
||||
private void validate() {
|
||||
@ -116,6 +120,42 @@ public class GBDevice implements Parcelable {
|
||||
return mState == State.CONNECTING;
|
||||
}
|
||||
|
||||
public boolean isBusy() {
|
||||
return mBusyTask != null;
|
||||
}
|
||||
|
||||
public String getBusyTask() {
|
||||
return mBusyTask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the device as busy, performing a certain task. While busy, no other operations will
|
||||
* be performed on the device.
|
||||
*
|
||||
* Note that nested busy tasks are not supported, every single call to #setBusyTask()
|
||||
* or unsetBusy() has an effect.
|
||||
* @param task a textual name of the task to be performed, possibly displayed to the user
|
||||
*/
|
||||
public void setBusyTask(String task) {
|
||||
if (task == null) {
|
||||
throw new IllegalArgumentException("busy task must not be null");
|
||||
}
|
||||
if (mBusyTask != null) {
|
||||
LOG.warn("Attempt to mark device as busy with: " + task + ", but is already busy with: " + mBusyTask);
|
||||
}
|
||||
mBusyTask = task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the device as not busy anymore.
|
||||
*/
|
||||
public void unsetBusyTask() {
|
||||
if (mBusyTask == null) {
|
||||
LOG.error("Attempt to mark device as not busy anymore, but was not busy before.");
|
||||
}
|
||||
mBusyTask = null;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return mState;
|
||||
}
|
||||
@ -132,6 +172,7 @@ public class GBDevice implements Parcelable {
|
||||
setBatteryState(null);
|
||||
setFirmwareVersion(null);
|
||||
setRssi(RSSI_UNKNOWN);
|
||||
unsetBusyTask();
|
||||
}
|
||||
|
||||
public String getStateString() {
|
||||
@ -249,5 +290,4 @@ public class GBDevice implements Parcelable {
|
||||
INITIALIZING,
|
||||
INITIALIZED
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,10 +14,6 @@ import android.bluetooth.BluetoothGattCharacteristic;
|
||||
public abstract class BtLEAction {
|
||||
private final BluetoothGattCharacteristic characteristic;
|
||||
|
||||
public BtLEAction() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public BtLEAction(BluetoothGattCharacteristic characteristic) {
|
||||
this.characteristic = characteristic;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBDevice;
|
||||
* sequence (transaction). It will abort the entire initialization sequence
|
||||
* by returning false, when the device is already initialized.
|
||||
*/
|
||||
public class CheckInitializedAction extends BtLEAction {
|
||||
public class CheckInitializedAction extends PlainAction {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CheckInitializedAction.class);
|
||||
|
||||
private final GBDevice device;
|
||||
@ -29,9 +29,4 @@ public class CheckInitializedAction extends BtLEAction {
|
||||
}
|
||||
return continueWithOtherInitActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expectsResult() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.btle;
|
||||
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
|
||||
/**
|
||||
* An abstract non-BTLE action. It performs no bluetooth operation,
|
||||
* does not have a BluetoothGattCharacteristic instance and expects no result.
|
||||
*/
|
||||
public abstract class PlainAction extends BtLEAction {
|
||||
|
||||
public PlainAction() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expectsResult() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.btle;
|
||||
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.content.Context;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBDevice;
|
||||
|
||||
public class SetDeviceBusyAction extends PlainAction {
|
||||
private final GBDevice device;
|
||||
private final Context context;
|
||||
private final String busyTask;
|
||||
|
||||
/**
|
||||
* When run, will mark the device as busy (or not busy).
|
||||
* @param device the device to mark
|
||||
* @param busyTask the task name to set as busy task, or null to mark as not busy
|
||||
* @param context
|
||||
*/
|
||||
public SetDeviceBusyAction(GBDevice device, String busyTask, Context context) {
|
||||
this.device = device;
|
||||
this.busyTask = busyTask;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean run(BluetoothGatt gatt) {
|
||||
device.setBusyTask(busyTask);
|
||||
device.sendDeviceUpdateIntent(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + ": " + busyTask;
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ package nodomain.freeyourgadget.gadgetbridge.btle;
|
||||
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
|
||||
public class WaitAction extends BtLEAction {
|
||||
public class WaitAction extends PlainAction {
|
||||
|
||||
private int mMillis;
|
||||
|
||||
@ -19,10 +19,4 @@ public class WaitAction extends BtLEAction {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expectsResult() {
|
||||
// no BT communication at all, no result
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -132,12 +132,13 @@ public class MiBandService {
|
||||
public static final byte COMMAND_STOP_MOTOR_VIBRATE = 0x13;
|
||||
|
||||
public static final byte COMMAND_CONFIRM_ACTIVITY_DATA_TRANSFER_COMPLETE = 0xa;
|
||||
|
||||
public static final byte COMMAND_FETCH_DATA = 0x6;
|
||||
/*
|
||||
|
||||
|
||||
public static final byte COMMAND_FACTORY_RESET = 0x9t;
|
||||
|
||||
public static final byte COMMAND_FETCH_DATA = 0x6t;
|
||||
|
||||
public static final byte COMMAND_GET_SENSOR_DATA = 0x12t
|
||||
|
||||
|
@ -20,7 +20,9 @@ import nodomain.freeyourgadget.gadgetbridge.GBActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBCommand;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBDevice.State;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.btle.SetDeviceBusyAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.btle.TransactionBuilder;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.DEFAULT_VALUE_FLASH_COLOUR;
|
||||
@ -147,10 +149,10 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
builder.queue(getQueue());
|
||||
}
|
||||
|
||||
private static final byte[] startVibrate = new byte[]{MiBandService.COMMAND_SEND_NOTIFICATION, 1};
|
||||
private static final byte[] stopVibrate = new byte[]{MiBandService.COMMAND_STOP_MOTOR_VIBRATE};
|
||||
private static final byte[] reboot = new byte[]{MiBandService.COMMAND_REBOOT};
|
||||
private static final byte[] fetch = new byte[]{6};
|
||||
private static final byte[] startVibrate = new byte[] { MiBandService.COMMAND_SEND_NOTIFICATION, 1 };
|
||||
private static final byte[] stopVibrate = new byte[] { MiBandService.COMMAND_STOP_MOTOR_VIBRATE };
|
||||
private static final byte[] reboot = new byte[]{ MiBandService.COMMAND_REBOOT };
|
||||
private static final byte[] fetch = new byte[]{ MiBandService.COMMAND_FETCH_DATA };
|
||||
|
||||
private byte[] getNotification(long vibrateDuration, int vibrateTimes, int flashTimes, int flashColour, int originalColour, long flashDuration) {
|
||||
byte[] vibrate = new byte[]{MiBandService.COMMAND_SEND_NOTIFICATION, (byte) 1};
|
||||
@ -357,8 +359,20 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
|
||||
@Override
|
||||
public void onReboot() {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("Reboot");
|
||||
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), reboot);
|
||||
builder.queue(getQueue());
|
||||
} catch (IOException ex) {
|
||||
LOG.error("Unable to reboot MI", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSynchronizeActivityData() {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("fetch activity data");
|
||||
builder.add(new SetDeviceBusyAction(getDevice(), getContext().getString(R.string.busy_task_fetch_activity_data), getContext()));
|
||||
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), fetch);
|
||||
builder.queue(getQueue());
|
||||
} catch (IOException ex) {
|
||||
@ -487,7 +501,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
flushActivityDataHolder();
|
||||
}
|
||||
} else {
|
||||
// the lenght of the chunk is not what we expect. We need to make sense of this data
|
||||
// the length of the chunk is not what we expect. We need to make sense of this data
|
||||
LOG.warn("GOT UNEXPECTED ACTIVITY DATA WITH LENGTH: " + value.length + ", EXPECTED LENGTH: " + this.activityDataRemainingBytes);
|
||||
for (byte b: value){
|
||||
LOG.warn("DATA: " + String.format("0x%8x", b));
|
||||
@ -530,11 +544,31 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
LOG.warn("Could not write to the control point.");
|
||||
}
|
||||
LOG.info("handleControlPoint got status:" + status);
|
||||
|
||||
if (getDevice().isBusy()) {
|
||||
if (isActivityDataSyncFinished(value)) {
|
||||
unsetBusy();
|
||||
}
|
||||
}
|
||||
for (byte b: value){
|
||||
LOG.info("handleControlPoint GOT DATA:" + String.format("0x%8x", b));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean isActivityDataSyncFinished(byte[] value) {
|
||||
if (value.length == 9) {
|
||||
if (value[0] == 0xa && value[1] == 0xf && value[2] == 5 && value[7] == 0 && value[8] == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void unsetBusy() {
|
||||
getDevice().unsetBusyTask();
|
||||
getDevice().sendDeviceUpdateIntent(getContext());
|
||||
}
|
||||
|
||||
private void sendAckDataTransfer(Calendar time, int bytesTransferred) {
|
||||
byte[] ack = new byte[]{
|
||||
MiBandService.COMMAND_CONFIRM_ACTIVITY_DATA_TRANSFER_COMPLETE,
|
||||
|
@ -5,8 +5,9 @@ import android.content.Context;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.btle.BtLEAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.btle.PlainAction;
|
||||
|
||||
public class SetDeviceStateAction extends BtLEAction {
|
||||
public class SetDeviceStateAction extends PlainAction {
|
||||
private final GBDevice device;
|
||||
private final GBDevice.State deviceState;
|
||||
private final Context context;
|
||||
@ -24,11 +25,6 @@ public class SetDeviceStateAction extends BtLEAction {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expectsResult() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
@ -54,6 +54,10 @@ public abstract class GBDeviceProtocol {
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] encodeSynchronizeActivityData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] encodeReboot() {
|
||||
return null;
|
||||
}
|
||||
|
@ -105,5 +105,6 @@
|
||||
<string name="pref_log_to_file">LogToFile</string>
|
||||
<string name="pref_write_logfiles">Write Log Files (needs restart)</string>
|
||||
<string name="initializing">initializing</string>
|
||||
<string name="busy_task_fetch_activity_data">Fetching Activity Data</string>
|
||||
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user