diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miwatch/MiWatchLiteCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/miwatch/MiWatchLiteCoordinator.java
similarity index 90%
rename from app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miwatch/MiWatchLiteCoordinator.java
rename to app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/miwatch/MiWatchLiteCoordinator.java
index 8327d9b90..51a9b17e6 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miwatch/MiWatchLiteCoordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/miwatch/MiWatchLiteCoordinator.java
@@ -14,7 +14,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see . */
-package nodomain.freeyourgadget.gadgetbridge.devices.miwatch;
+package nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.miwatch;
import android.content.Context;
import android.net.Uri;
@@ -28,8 +28,7 @@ import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiCoordinator;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
-import nodomain.freeyourgadget.gadgetbridge.service.devices.miwatch.MiWatchLiteSupport;
-import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiSupport;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiPlaintextSupport;
public class MiWatchLiteCoordinator extends XiaomiCoordinator {
@Override
@@ -62,6 +61,6 @@ public class MiWatchLiteCoordinator extends XiaomiCoordinator {
@NonNull
@Override
public Class extends DeviceSupport> getDeviceSupportClass() {
- return MiWatchLiteSupport.class;
+ return XiaomiPlaintextSupport.class;
}
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java
index 3d89a8c8d..53f026eaa 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java
@@ -143,7 +143,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.withingssteelhr.WithingsStee
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.miband8.MiBand8Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.xwatch.XWatchCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.zetime.ZeTimeCoordinator;
-import nodomain.freeyourgadget.gadgetbridge.devices.miwatch.MiWatchLiteCoordinator;
+import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.miwatch.MiWatchLiteCoordinator;
/**
* For every supported device, a device type constant must exist.
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miwatch/MiWatchLiteSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miwatch/MiWatchLiteSupport.java
deleted file mode 100644
index f4356c5af..000000000
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miwatch/MiWatchLiteSupport.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/* Copyright (C) 2023 Andreas Shimokawa
-
- This file is part of Gadgetbridge.
-
- Gadgetbridge is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Gadgetbridge is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see . */
-package nodomain.freeyourgadget.gadgetbridge.service.devices.miwatch;
-
-import android.bluetooth.BluetoothGatt;
-import android.bluetooth.BluetoothGattCharacteristic;
-import android.content.SharedPreferences;
-
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-import java.util.UUID;
-
-import nodomain.freeyourgadget.gadgetbridge.GBApplication;
-import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
-import nodomain.freeyourgadget.gadgetbridge.proto.xiaomi.XiaomiProto;
-import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
-import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
-import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiAuthService;
-import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiSupport;
-import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils;
-import nodomain.freeyourgadget.gadgetbridge.util.GB;
-
-public class MiWatchLiteSupport extends XiaomiSupport {
-
- private static final Logger LOG = LoggerFactory.getLogger(MiWatchLiteSupport.class);
-
- private static final UUID UUID_CHARACTERISTIC_MAIN = UUID.fromString("16186f02-0000-1000-8000-00807f9b34fb");
- private static final UUID UUID_CHARACTERISTIC_UNK1 = UUID.fromString("16186f01-0000-1000-8000-00807f9b34fb");
- private static final UUID UUID_CHARACTERISTIC_UNK2 = UUID.fromString("16186f03-0000-1000-8000-00807f9b34fb");
- private static final UUID UUID_CHARACTERISTIC_UNK3 = UUID.fromString("16186f04-0000-1000-8000-00807f9b34fb");
- private static final UUID UUID_CHARACTERISTIC_UNK4 = UUID.fromString("16186f05-0000-1000-8000-00807f9b34fb");
-
- public MiWatchLiteSupport() {
- super(); // FIXME: no we do not want to do this!! This adds supported characteristics which we do not have - but we have to.
- addSupportedService(UUID.fromString("16186f00-0000-1000-8000-00807f9b34fb"));
- }
-
- @Override
- protected TransactionBuilder initializeDevice(final TransactionBuilder builder) {
-
- // FIXME why is this needed?
- getDevice().setFirmwareVersion("...");
- //getDevice().setFirmwareVersion2("...");
- enableNotifications(builder, true);
- builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
- builder.requestMtu(247);
- String userId = getUserId(gbDevice);
-
- final XiaomiProto.Auth auth = XiaomiProto.Auth.newBuilder()
- .setUserId(userId)
- .build();
-
- final XiaomiProto.Command command = XiaomiProto.Command.newBuilder()
- .setType(XiaomiAuthService.COMMAND_TYPE)
- .setSubtype(XiaomiAuthService.CMD_SEND_USERID)
- .setAuth(auth)
- .build();
- sendCommand(builder, command);
-
- builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
-
-
- return builder;
- }
-
- private void enableNotifications(TransactionBuilder builder, boolean enable) {
- builder.notify(getCharacteristic(UUID_CHARACTERISTIC_MAIN), enable);
- builder.notify(getCharacteristic(UUID_CHARACTERISTIC_UNK1), enable);
- builder.notify(getCharacteristic(UUID_CHARACTERISTIC_UNK2), enable);
- builder.notify(getCharacteristic(UUID_CHARACTERISTIC_UNK3), enable);
- builder.notify(getCharacteristic(UUID_CHARACTERISTIC_UNK4), enable);
- }
-
- protected static String getUserId(final GBDevice device) {
- final SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(device.getAddress());
-
- final String authKey = sharedPrefs.getString("authkey", null);
- if (StringUtils.isNotBlank(authKey)) {
- return authKey;
- }
-
- return "0000000000";
- }
-
- @Override
- public void sendCommand(final TransactionBuilder builder, final nodomain.freeyourgadget.gadgetbridge.proto.xiaomi.XiaomiProto.Command command) {
- final byte[] commandBytes = command.toByteArray();
- final int commandLength = 2 + commandBytes.length;
- if (commandLength > getMTU()) {
- LOG.warn("Command with {} bytes is too large for MTU of {}", commandLength, getMTU());
- }
- builder.write(getCharacteristic(UUID_CHARACTERISTIC_MAIN), new byte[]{0x00, 0x00, 0x00, 0x00, 0x01, 0x00});
- builder.wait(500);
-
- final ByteBuffer buf = ByteBuffer.allocate(commandLength).order(ByteOrder.LITTLE_ENDIAN);
- buf.put((byte) 1);
- buf.put((byte) 0);
- buf.put(commandBytes);
- LOG.debug("Sending command {} as {}", GB.hexdump(commandBytes), GB.hexdump(buf.array()));
- builder.write(getCharacteristic(UUID_CHARACTERISTIC_MAIN), buf.array());
- }
-
- @Override
- public boolean onCharacteristicChanged(BluetoothGatt gatt,
- BluetoothGattCharacteristic characteristic) {
- if (super.onCharacteristicChanged(gatt, characteristic)) {
- return true;
- }
-
- UUID characteristicUUID = characteristic.getUuid();
-
- final byte[] success_bytes = new byte[]{0x00, 0x00, 0x01, 0x01, 0x00, 0x00};
- final byte[] ping_request = new byte[]{0x00, 0x00, 0x00, 0x00, 0x01, 0x00};
- if (characteristicUUID.equals(UUID_CHARACTERISTIC_UNK1)) {
- if (Arrays.equals(ping_request, characteristic.getValue())) {
- TransactionBuilder builder = new TransactionBuilder("reply ping");
- builder.write(getCharacteristic(UUID_CHARACTERISTIC_UNK1), new byte[]{0x00, 0x00, 0x01, 0x01});
- builder.queue(getQueue());
- return true;
- }
- if (ArrayUtils.startsWith(characteristic.getValue(), new byte[]{1, 0, 8})) {
- TransactionBuilder builder = new TransactionBuilder("ack whatever");
- builder.write(getCharacteristic(UUID_CHARACTERISTIC_UNK1), new byte[]{0x00, 0x00, 0x01, 0x00});
- builder.queue(getQueue());
- return true;
- }
-
- }
- LOG.info("Unhandled characteristic changed: " + characteristicUUID);
- return false;
- }
-}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiCharacteristic.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiCharacteristic.java
index d2e4d3b95..6c7f664db 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiCharacteristic.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiCharacteristic.java
@@ -38,8 +38,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
public class XiaomiCharacteristic {
public static final byte[] PAYLOAD_ACK = new byte[]{0, 0, 3, 0};
- public static final byte[] PAYLOAD_CHUNKED_START_ACK = new byte[]{0, 0, 1, 1};
- public static final byte[] PAYLOAD_CHUNKED_END_ACK = new byte[]{0, 0, 1, 0};
private final Logger LOG;
@@ -301,13 +299,13 @@ public class XiaomiCharacteristic {
private void sendChunkStartAck() {
final TransactionBuilder builder = mSupport.createTransactionBuilder("send chunked start ack");
- builder.write(bluetoothGattCharacteristic, PAYLOAD_CHUNKED_START_ACK);
+ builder.write(bluetoothGattCharacteristic, new byte[]{0x00, 0x00, 0x01, 0x01});
builder.queue(mSupport.getQueue());
}
private void sendChunkEndAck() {
final TransactionBuilder builder = mSupport.createTransactionBuilder("send chunked end ack");
- builder.write(bluetoothGattCharacteristic, PAYLOAD_CHUNKED_END_ACK);
+ builder.write(bluetoothGattCharacteristic, new byte[]{0x00, 0x00, 0x01, 0x00});
builder.queue(mSupport.getQueue());
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiEncryptedSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiEncryptedSupport.java
index 87c17cd91..8e51887e1 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiEncryptedSupport.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiEncryptedSupport.java
@@ -68,12 +68,13 @@ public class XiaomiEncryptedSupport extends XiaomiSupport {
final BluetoothGattCharacteristic btCharacteristicActivityData = getCharacteristic(UUID_CHARACTERISTIC_XIAOMI_ACTIVITY_DATA);
final BluetoothGattCharacteristic btCharacteristicDataUpload = getCharacteristic(UUID_CHARACTERISTIC_XIAOMI_DATA_UPLOAD);
- if (btCharacteristicCommandRead == null || btCharacteristicCommandWrite == null || btCharacteristicActivityData == null || btCharacteristicDataUpload == null) {
+ if (btCharacteristicCommandRead == null || btCharacteristicCommandWrite == null) {
LOG.warn("Characteristics are null, will attempt to reconnect");
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.WAITING_FOR_RECONNECT, getContext()));
return builder;
}
+ // TODO move this initialization to upstream class
this.characteristicCommandRead = new XiaomiCharacteristic(this, btCharacteristicCommandRead, authService);
this.characteristicCommandRead.setEncrypted(true);
this.characteristicCommandRead.setHandler(this::handleCommandBytes);
@@ -96,6 +97,7 @@ public class XiaomiEncryptedSupport extends XiaomiSupport {
builder.notify(getCharacteristic(UUID_CHARACTERISTIC_XIAOMI_COMMAND_WRITE), true);
builder.notify(getCharacteristic(UUID_CHARACTERISTIC_XIAOMI_ACTIVITY_DATA), true);
builder.notify(getCharacteristic(UUID_CHARACTERISTIC_XIAOMI_DATA_UPLOAD), true);
+
authService.startEncryptedHandshake(builder);
return builder;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiPlaintextSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiPlaintextSupport.java
new file mode 100644
index 000000000..ff668849a
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiPlaintextSupport.java
@@ -0,0 +1,122 @@
+/* Copyright (C) 2023 Andreas Shimokawa
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi;
+
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.content.SharedPreferences;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.UUID;
+
+import nodomain.freeyourgadget.gadgetbridge.GBApplication;
+import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
+import nodomain.freeyourgadget.gadgetbridge.proto.xiaomi.XiaomiProto;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
+import nodomain.freeyourgadget.gadgetbridge.util.GB;
+
+public class XiaomiPlaintextSupport extends XiaomiSupport {
+
+ private static final Logger LOG = LoggerFactory.getLogger(XiaomiPlaintextSupport.class);
+
+ private static final UUID UUID_CHARACTERISTIC_MAIN_READ = UUID.fromString("16186f01-0000-1000-8000-00807f9b34fb");
+ private static final UUID UUID_CHARACTERISTIC_MAIN_WRITE = UUID.fromString("16186f02-0000-1000-8000-00807f9b34fb");
+ private static final UUID UUID_CHARACTERISTIC_ACTIVITY_DATA = UUID.fromString("16186f03-0000-1000-8000-00807f9b34fb");
+ private static final UUID UUID_CHARACTERISTIC_DATA_UPLOAD = UUID.fromString("16186f04-0000-1000-8000-00807f9b34fb");
+ private static final UUID UUID_CHARACTERISTIC_UNK5 = UUID.fromString("16186f05-0000-1000-8000-00807f9b34fb");
+
+ public XiaomiPlaintextSupport() {
+ super();
+ addSupportedService(UUID.fromString("16186f00-0000-1000-8000-00807f9b34fb"));
+ }
+
+ @Override
+ protected TransactionBuilder initializeDevice(final TransactionBuilder builder) {
+ final BluetoothGattCharacteristic btCharacteristicCommandRead = getCharacteristic(UUID_CHARACTERISTIC_MAIN_READ);
+ final BluetoothGattCharacteristic btCharacteristicCommandWrite = getCharacteristic(UUID_CHARACTERISTIC_MAIN_WRITE);
+ final BluetoothGattCharacteristic btCharacteristicActivityData = getCharacteristic(UUID_CHARACTERISTIC_ACTIVITY_DATA);
+ final BluetoothGattCharacteristic btCharacteristicDataUpload = getCharacteristic(UUID_CHARACTERISTIC_DATA_UPLOAD);
+
+ if (btCharacteristicCommandRead == null || btCharacteristicCommandWrite == null) {
+ LOG.warn("Characteristics are null, will attempt to reconnect");
+ builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.WAITING_FOR_RECONNECT, getContext()));
+ return builder;
+ }
+
+ // TODO move this initialization to upstream class
+ this.characteristicCommandRead = new XiaomiCharacteristic(this, btCharacteristicCommandRead, authService);
+ this.characteristicCommandRead.setEncrypted(false);
+ this.characteristicCommandRead.setHandler(this::handleCommandBytes);
+ this.characteristicCommandWrite = new XiaomiCharacteristic(this, btCharacteristicCommandWrite, authService);
+ this.characteristicCommandRead.setEncrypted(false);
+ this.characteristicActivityData = new XiaomiCharacteristic(this, btCharacteristicActivityData, authService);
+ this.characteristicActivityData.setHandler(healthService.getActivityFetcher()::addChunk);
+ this.characteristicCommandRead.setEncrypted(false);
+ this.characteristicDataUpload = new XiaomiCharacteristic(this, btCharacteristicDataUpload, authService);
+ this.characteristicCommandRead.setEncrypted(false);
+
+ // FIXME why is this needed?
+ getDevice().setFirmwareVersion("...");
+ //getDevice().setFirmwareVersion2("...");
+
+ enableNotifications(builder, true);
+ builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
+ builder.requestMtu(247);
+ String userId = getUserId(gbDevice);
+
+ final XiaomiProto.Auth auth = XiaomiProto.Auth.newBuilder()
+ .setUserId(userId)
+ .build();
+
+ final XiaomiProto.Command command = XiaomiProto.Command.newBuilder()
+ .setType(XiaomiAuthService.COMMAND_TYPE)
+ .setSubtype(XiaomiAuthService.CMD_SEND_USERID)
+ .setAuth(auth)
+ .build();
+
+ sendCommand(builder, command);
+
+ builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
+
+
+ return builder;
+ }
+
+ private void enableNotifications(TransactionBuilder builder, boolean enable) {
+ builder.notify(getCharacteristic(UUID_CHARACTERISTIC_MAIN_WRITE), enable);
+ builder.notify(getCharacteristic(UUID_CHARACTERISTIC_MAIN_READ), enable);
+ builder.notify(getCharacteristic(UUID_CHARACTERISTIC_ACTIVITY_DATA), enable);
+ builder.notify(getCharacteristic(UUID_CHARACTERISTIC_DATA_UPLOAD), enable);
+ builder.notify(getCharacteristic(UUID_CHARACTERISTIC_UNK5), enable);
+ }
+
+ protected static String getUserId(final GBDevice device) {
+ final SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(device.getAddress());
+
+ final String authKey = sharedPrefs.getString("authkey", null);
+ if (StringUtils.isNotBlank(authKey)) {
+ return authKey;
+ }
+
+ return "0000000000";
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiSupport.java
index e3f8ae022..1441ea584 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiSupport.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiSupport.java
@@ -394,12 +394,14 @@ public abstract class XiaomiSupport extends AbstractBTLEDeviceSupport {
}
public void sendCommand(final TransactionBuilder builder, final XiaomiProto.Command command) {
+ // FIXME builder is ignored
final byte[] commandBytes = command.toByteArray();
LOG.debug("Sending command {}", GB.hexdump(commandBytes));
this.characteristicCommandWrite.write(commandBytes);
}
public void sendCommand(final TransactionBuilder builder, final byte[] commandBytes) {
+ // FIXME builder is ignored
this.characteristicCommandWrite.write(commandBytes);
}