From 1224cfeffc6a11aef8654439496b5f161dfc59ba Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Wed, 21 Oct 2020 21:43:48 +0200 Subject: [PATCH 1/3] Amazfit Bip S: unify shortcuts code with display items code --- .../service/devices/huami/HuamiSupport.java | 19 +++++-- .../amazfitband5/AmazfitBand5Support.java | 2 +- .../huami/amazfitbips/AmazfitBipSSupport.java | 57 ++++--------------- .../huami/amazfitgts/AmazfitGTSSupport.java | 2 +- .../devices/huami/miband5/MiBand5Support.java | 2 +- 5 files changed, 27 insertions(+), 55 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java index 3245ac2cd..ec06fc75c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java @@ -2313,15 +2313,24 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport { return this; } - protected HuamiSupport setDisplayItemsNew(TransactionBuilder builder, int defaultSettings, Map keyIdMap) { + protected HuamiSupport setDisplayItemsNew(TransactionBuilder builder, boolean isShortcuts, int defaultSettings, Map keyIdMap) { if (gbDevice.getFirmwareVersion() == null) { LOG.warn("Device not initialized yet, won't set menu items"); return this; } SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()); - Set pages = prefs.getStringSet(HuamiConst.PREF_DISPLAY_ITEMS, new HashSet<>(Arrays.asList(getContext().getResources().getStringArray(defaultSettings)))); - LOG.info("Setting display items to " + (pages == null ? "none" : pages)); + Set pages; + byte menuType; + if (isShortcuts) { + menuType = (byte) 0xfd; + pages = prefs.getStringSet(HuamiConst.PREF_SHORTCUTS, new HashSet<>(Arrays.asList(getContext().getResources().getStringArray(R.array.pref_bips_shortcuts_default)))); + LOG.info("Setting shortcuts to " + (pages == null ? "none" : pages)); + } else { + menuType = (byte) 0xff; + pages = prefs.getStringSet(HuamiConst.PREF_DISPLAY_ITEMS, new HashSet<>(Arrays.asList(getContext().getResources().getStringArray(defaultSettings)))); + LOG.info("Setting display items to " + (pages == null ? "none" : pages)); + } if (pages != null) { byte[] command = new byte[keyIdMap.size() * 4 + 1]; @@ -2336,7 +2345,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport { if (pages.contains(key)) { command[pos++] = (byte) index++; command[pos++] = 0x00; - command[pos++] = (byte) 0xff; + command[pos++] = menuType; command[pos++] = (byte) id; } } @@ -2348,7 +2357,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport { if (!pages.contains(key)) { command[pos++] = (byte) index++; command[pos++] = 0x01; - command[pos++] = (byte) 0xff; + command[pos++] = (byte) menuType; command[pos++] = (byte) id; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitband5/AmazfitBand5Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitband5/AmazfitBand5Support.java index 9f350c107..5badad8cf 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitband5/AmazfitBand5Support.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitband5/AmazfitBand5Support.java @@ -51,7 +51,7 @@ public class AmazfitBand5Support extends MiBand5Support { keyIdMap.put("stress", 0x1c); keyIdMap.put("cycles", 0x1d); - setDisplayItemsNew(builder, R.array.pref_amazfitband5_display_items_default, keyIdMap); + setDisplayItemsNew(builder, false, R.array.pref_amazfitband5_display_items_default, keyIdMap); return this; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbips/AmazfitBipSSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbips/AmazfitBipSSupport.java index 686a9291f..0b1a49e39 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbips/AmazfitBipSSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbips/AmazfitBipSSupport.java @@ -132,59 +132,22 @@ public class AmazfitBipSSupport extends AmazfitBipSupport { keyIdMap.put("music", 0x0b); keyIdMap.put("settings", 0x13); - setDisplayItemsNew(builder, R.array.pref_bips_display_items_default, keyIdMap); + setDisplayItemsNew(builder, false, R.array.pref_bips_display_items_default, keyIdMap); return this; } @Override protected AmazfitBipSSupport setShortcuts(TransactionBuilder builder) { - if (gbDevice.getFirmwareVersion() == null) { - LOG.warn("Device not initialized yet, won't set shortcuts"); - return this; - } - - SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()); - Set pages = prefs.getStringSet(HuamiConst.PREF_SHORTCUTS, new HashSet<>(Arrays.asList(getContext().getResources().getStringArray(R.array.pref_bips_shortcuts_default)))); - LOG.info("Setting shortcuts to " + (pages == null ? "none" : pages)); - byte[] command = new byte[]{ - 0x1E, - 0x00, 0x00, (byte) 0xFD, 0x01, // Status - 0x01, 0x00, (byte) 0xFD, 0x11, // Alipay - 0x02, 0x00, (byte) 0xFD, 0x10, // NFC - 0x03, 0x00, (byte) 0xFD, 0x19, // PAI - 0x04, 0x00, (byte) 0xFD, 0x02, // HR - 0x05, 0x00, (byte) 0xFD, 0x0B, // Music - 0x06, 0x00, (byte) 0xFD, 0x04, // Weather - }; - - String[] keys = {"status", "alipay", "nfc", "pai", "hr", "music", "weather"}; - byte[] ids = {1, 17, 16, 25, 2, 11, 4}; - - if (pages != null) { - // it seem that we first have to put all ENABLED items into the array - int pos = 1; - for (int i = 0; i < keys.length; i++) { - String key = keys[i]; - byte id = ids[i]; - if (pages.contains(key)) { - command[pos + 1] = 0x00; - command[pos + 3] = id; - pos += 4; - } - } - // And then all DISABLED ones - for (int i = 0; i < keys.length; i++) { - String key = keys[i]; - byte id = ids[i]; - if (!pages.contains(key)) { - command[pos + 1] = 0x01; - command[pos + 3] = id; - pos += 4; - } - } - writeToChunked(builder, 2, command); - } + Map keyIdMap = new LinkedHashMap<>(); + keyIdMap.put("status", 0x01); + keyIdMap.put("alipay", 0x11); + keyIdMap.put("nfc", 0x10); + keyIdMap.put("pai", 0x19); + keyIdMap.put("hr", 0x02); + keyIdMap.put("music", 0x0b); + keyIdMap.put("weather", 0x04); + setDisplayItemsNew(builder, true, R.array.pref_bips_display_items_default, keyIdMap); return this; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitgts/AmazfitGTSSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitgts/AmazfitGTSSupport.java index 1a7ab2a9b..46bcff777 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitgts/AmazfitGTSSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitgts/AmazfitGTSSupport.java @@ -80,7 +80,7 @@ public class AmazfitGTSSupport extends AmazfitBipSupport { keyIdMap.put("more", 0x07); keyIdMap.put("settings", 0x13); - setDisplayItemsNew(builder, R.array.pref_gts_display_items_default, keyIdMap); + setDisplayItemsNew(builder, false, R.array.pref_gts_display_items_default, keyIdMap); return this; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband5/MiBand5Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband5/MiBand5Support.java index 8eb2ee7c8..a1bc831f9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband5/MiBand5Support.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband5/MiBand5Support.java @@ -50,7 +50,7 @@ public class MiBand5Support extends MiBand4Support { keyIdMap.put("stress", 0x1c); keyIdMap.put("cycles", 0x1d); - setDisplayItemsNew(builder, R.array.pref_miband5_display_items_default, keyIdMap); + setDisplayItemsNew(builder, false, R.array.pref_miband5_display_items_default, keyIdMap); return this; } From d14687388b19a54a3ef2b217e4095d87d5818a0e Mon Sep 17 00:00:00 2001 From: Daniel Dakhno Date: Mon, 26 Oct 2020 04:13:52 +0100 Subject: [PATCH 2/3] Fossil Hybrid: show warning on wrong key format --- .../fossil_hr/FossilHRWatchAdapter.java | 52 +++++++++++++++---- .../file/FileEncryptedGetRequest.java | 7 ++- .../file/FileEncryptedPutRequest.java | 8 ++- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java index c2bec0974..ec3f6cf4c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java @@ -12,6 +12,8 @@ import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; +import android.os.Handler; +import android.os.Looper; import android.widget.Toast; import androidx.localbroadcastmanager.content.LocalBroadcastManager; @@ -57,6 +59,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.Weather; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; +import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.file.FileHandle; @@ -134,6 +137,17 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { @Override public void initialize() { + try { + getSecretKey(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + toast(e.getMessage()); + new TransactionBuilder("init fail") + .add(new SetDeviceStateAction(getDeviceSupport().getDevice(), GBDevice.State.AUTHENTICATION_REQUIRED, getContext())) + .queue(getDeviceSupport().getQueue()); + return; + } + saveRawActivityFiles = getDeviceSpecificPreferences().getBoolean("save_raw_activity_files", false); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { @@ -573,10 +587,27 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { } private void negotiateSymmetricKey() { - queueWrite(new VerifyPrivateKeyRequest( - this.getSecretKey(), - this - )); + try { + queueWrite(new VerifyPrivateKeyRequest( + this.getSecretKey(), + this + )); + } catch (IllegalAccessException e) { + e.printStackTrace(); + toast(e.getMessage()); + getDeviceSupport().getDevice().setState(GBDevice.State.AUTHENTICATION_REQUIRED); + getDeviceSupport().getDevice().sendDeviceUpdateIntent(getContext()); + getDeviceSupport().getQueue().clear(); + } + } + + private void toast(final String data){ + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + Toast.makeText(getContext(), data, Toast.LENGTH_LONG).show(); + } + }); } @Override @@ -628,7 +659,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { public void onFetchActivityData() { syncSettings(); - queueWrite(new VerifyPrivateKeyRequest(this.getSecretKey(), this)); + negotiateSymmetricKey(); queueWrite(new FileLookupRequest(FileHandle.ACTIVITY_FILE, this) { @Override public void handleFileLookup(final short fileHandle) { @@ -948,17 +979,20 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { } - public byte[] getSecretKey() { + public byte[] getSecretKey() throws IllegalAccessException { byte[] authKeyBytes = new byte[16]; SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(getDeviceSupport().getDevice().getAddress()); String authKey = sharedPrefs.getString("authkey", null); if (authKey != null && !authKey.isEmpty()) { - byte[] srcBytes = authKey.trim().getBytes(); - if (authKey.length() == 34 && authKey.startsWith("0x")) { - srcBytes = GB.hexStringToByteArray(authKey.substring(2)); + authKey = authKey.replace(" ", ""); + authKey = authKey.replace("0x", ""); + if(authKey.length() != 32){ + throw new IllegalAccessException("Key should be 16 bytes long as hex string"); } + byte[] srcBytes = GB.hexStringToByteArray(authKey); + System.arraycopy(srcBytes, 0, authKeyBytes, 0, Math.min(srcBytes.length, 16)); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedGetRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedGetRequest.java index d493dc530..d06bd168f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedGetRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedGetRequest.java @@ -72,7 +72,12 @@ public abstract class FileEncryptedGetRequest extends FossilRequest { private void initDecryption() { try { cipher = Cipher.getInstance("AES/CTR/NoPadding"); - keySpec = new SecretKeySpec(this.adapter.getSecretKey(), "AES"); + try { + keySpec = new SecretKeySpec(this.adapter.getSecretKey(), "AES"); + } catch (IllegalAccessException e) { + e.printStackTrace(); + return; + } iv = new byte[16]; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedPutRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedPutRequest.java index d10ece07f..f19dd36e8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedPutRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedPutRequest.java @@ -91,7 +91,13 @@ public class FileEncryptedPutRequest extends FossilRequest { this.prepareFilePackets(this.file); - SecretKeySpec keySpec = new SecretKeySpec(this.adapter.getSecretKey(), "AES"); + SecretKeySpec keySpec = null; + try { + keySpec = new SecretKeySpec(this.adapter.getSecretKey(), "AES"); + } catch (IllegalAccessException e) { + e.printStackTrace(); + return; + } try { Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); From f11977597b90c5f16b87deec4fbb01ec70fb548c Mon Sep 17 00:00:00 2001 From: Daniel Dakhno Date: Tue, 27 Oct 2020 23:51:35 +0100 Subject: [PATCH 3/3] Fossil Hybrid: use GB.toast() --- .../qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java | 6 ++---- .../requests/fossil_hr/file/FileEncryptedGetRequest.java | 4 +++- .../requests/fossil_hr/file/FileEncryptedPutRequest.java | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java index ec3f6cf4c..990b965ee 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java @@ -140,8 +140,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { try { getSecretKey(); } catch (IllegalAccessException e) { - e.printStackTrace(); - toast(e.getMessage()); + GB.toast("erro getting key: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e); new TransactionBuilder("init fail") .add(new SetDeviceStateAction(getDeviceSupport().getDevice(), GBDevice.State.AUTHENTICATION_REQUIRED, getContext())) .queue(getDeviceSupport().getQueue()); @@ -593,8 +592,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { this )); } catch (IllegalAccessException e) { - e.printStackTrace(); - toast(e.getMessage()); + GB.toast("error getting key: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e); getDeviceSupport().getDevice().setState(GBDevice.State.AUTHENTICATION_REQUIRED); getDeviceSupport().getDevice().sendDeviceUpdateIntent(getContext()); getDeviceSupport().getQueue().clear(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedGetRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedGetRequest.java index d06bd168f..d94d45a46 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedGetRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedGetRequest.java @@ -17,6 +17,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file; import android.bluetooth.BluetoothGattCharacteristic; +import android.widget.Toast; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -38,6 +39,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.foss import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.file.FileHandle; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.FossilRequest; import nodomain.freeyourgadget.gadgetbridge.util.CRC32C; +import nodomain.freeyourgadget.gadgetbridge.util.GB; public abstract class FileEncryptedGetRequest extends FossilRequest { private short handle; @@ -75,7 +77,7 @@ public abstract class FileEncryptedGetRequest extends FossilRequest { try { keySpec = new SecretKeySpec(this.adapter.getSecretKey(), "AES"); } catch (IllegalAccessException e) { - e.printStackTrace(); + GB.toast("error getting key: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e); return; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedPutRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedPutRequest.java index f19dd36e8..8f0af0e8f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedPutRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/FileEncryptedPutRequest.java @@ -95,7 +95,7 @@ public class FileEncryptedPutRequest extends FossilRequest { try { keySpec = new SecretKeySpec(this.adapter.getSecretKey(), "AES"); } catch (IllegalAccessException e) { - e.printStackTrace(); + GB.toast("error getting key: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e); return; } try {