1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-25 10:05:49 +01:00

Merge remote-tracking branch 'origin/master'

This commit is contained in:
Daniel Dakhno 2020-10-29 02:43:01 +01:00
commit 0845d15ba2
8 changed files with 83 additions and 66 deletions

View File

@ -2313,15 +2313,24 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
return this; return this;
} }
protected HuamiSupport setDisplayItemsNew(TransactionBuilder builder, int defaultSettings, Map<String, Integer> keyIdMap) { protected HuamiSupport setDisplayItemsNew(TransactionBuilder builder, boolean isShortcuts, int defaultSettings, Map<String, Integer> keyIdMap) {
if (gbDevice.getFirmwareVersion() == null) { if (gbDevice.getFirmwareVersion() == null) {
LOG.warn("Device not initialized yet, won't set menu items"); LOG.warn("Device not initialized yet, won't set menu items");
return this; return this;
} }
SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()); SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress());
Set<String> pages = prefs.getStringSet(HuamiConst.PREF_DISPLAY_ITEMS, new HashSet<>(Arrays.asList(getContext().getResources().getStringArray(defaultSettings)))); Set<String> pages;
LOG.info("Setting display items to " + (pages == null ? "none" : 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) { if (pages != null) {
byte[] command = new byte[keyIdMap.size() * 4 + 1]; byte[] command = new byte[keyIdMap.size() * 4 + 1];
@ -2336,7 +2345,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
if (pages.contains(key)) { if (pages.contains(key)) {
command[pos++] = (byte) index++; command[pos++] = (byte) index++;
command[pos++] = 0x00; command[pos++] = 0x00;
command[pos++] = (byte) 0xff; command[pos++] = menuType;
command[pos++] = (byte) id; command[pos++] = (byte) id;
} }
} }
@ -2348,7 +2357,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
if (!pages.contains(key)) { if (!pages.contains(key)) {
command[pos++] = (byte) index++; command[pos++] = (byte) index++;
command[pos++] = 0x01; command[pos++] = 0x01;
command[pos++] = (byte) 0xff; command[pos++] = (byte) menuType;
command[pos++] = (byte) id; command[pos++] = (byte) id;
} }
} }

View File

@ -51,7 +51,7 @@ public class AmazfitBand5Support extends MiBand5Support {
keyIdMap.put("stress", 0x1c); keyIdMap.put("stress", 0x1c);
keyIdMap.put("cycles", 0x1d); 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; return this;
} }

View File

@ -132,59 +132,22 @@ public class AmazfitBipSSupport extends AmazfitBipSupport {
keyIdMap.put("music", 0x0b); keyIdMap.put("music", 0x0b);
keyIdMap.put("settings", 0x13); 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; return this;
} }
@Override @Override
protected AmazfitBipSSupport setShortcuts(TransactionBuilder builder) { protected AmazfitBipSSupport setShortcuts(TransactionBuilder builder) {
if (gbDevice.getFirmwareVersion() == null) { Map<String, Integer> keyIdMap = new LinkedHashMap<>();
LOG.warn("Device not initialized yet, won't set shortcuts"); keyIdMap.put("status", 0x01);
return this; keyIdMap.put("alipay", 0x11);
} keyIdMap.put("nfc", 0x10);
keyIdMap.put("pai", 0x19);
SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()); keyIdMap.put("hr", 0x02);
Set<String> pages = prefs.getStringSet(HuamiConst.PREF_SHORTCUTS, new HashSet<>(Arrays.asList(getContext().getResources().getStringArray(R.array.pref_bips_shortcuts_default)))); keyIdMap.put("music", 0x0b);
LOG.info("Setting shortcuts to " + (pages == null ? "none" : pages)); keyIdMap.put("weather", 0x04);
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);
}
setDisplayItemsNew(builder, true, R.array.pref_bips_display_items_default, keyIdMap);
return this; return this;
} }

View File

@ -80,7 +80,7 @@ public class AmazfitGTSSupport extends AmazfitBipSupport {
keyIdMap.put("more", 0x07); keyIdMap.put("more", 0x07);
keyIdMap.put("settings", 0x13); 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; return this;
} }

View File

@ -50,7 +50,7 @@ public class MiBand5Support extends MiBand4Support {
keyIdMap.put("stress", 0x1c); keyIdMap.put("stress", 0x1c);
keyIdMap.put("cycles", 0x1d); 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; return this;
} }

View File

@ -12,6 +12,8 @@ import android.graphics.Paint;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast; import android.widget.Toast;
import androidx.localbroadcastmanager.content.LocalBroadcastManager; 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.Weather;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; 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.QHybridSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.file.FileHandle; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.file.FileHandle;
@ -134,6 +137,16 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
@Override @Override
public void initialize() { public void initialize() {
try {
getSecretKey();
} catch (IllegalAccessException e) {
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());
return;
}
saveRawActivityFiles = getDeviceSpecificPreferences().getBoolean("save_raw_activity_files", false); saveRawActivityFiles = getDeviceSpecificPreferences().getBoolean("save_raw_activity_files", false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
@ -573,10 +586,26 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
} }
private void negotiateSymmetricKey() { private void negotiateSymmetricKey() {
queueWrite(new VerifyPrivateKeyRequest( try {
this.getSecretKey(), queueWrite(new VerifyPrivateKeyRequest(
this this.getSecretKey(),
)); this
));
} catch (IllegalAccessException e) {
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();
}
}
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 @Override
@ -628,7 +657,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
public void onFetchActivityData() { public void onFetchActivityData() {
syncSettings(); syncSettings();
queueWrite(new VerifyPrivateKeyRequest(this.getSecretKey(), this)); negotiateSymmetricKey();
queueWrite(new FileLookupRequest(FileHandle.ACTIVITY_FILE, this) { queueWrite(new FileLookupRequest(FileHandle.ACTIVITY_FILE, this) {
@Override @Override
public void handleFileLookup(final short fileHandle) { public void handleFileLookup(final short fileHandle) {
@ -948,17 +977,20 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
} }
public byte[] getSecretKey() { public byte[] getSecretKey() throws IllegalAccessException {
byte[] authKeyBytes = new byte[16]; byte[] authKeyBytes = new byte[16];
SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(getDeviceSupport().getDevice().getAddress()); SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(getDeviceSupport().getDevice().getAddress());
String authKey = sharedPrefs.getString("authkey", null); String authKey = sharedPrefs.getString("authkey", null);
if (authKey != null && !authKey.isEmpty()) { if (authKey != null && !authKey.isEmpty()) {
byte[] srcBytes = authKey.trim().getBytes(); authKey = authKey.replace(" ", "");
if (authKey.length() == 34 && authKey.startsWith("0x")) { authKey = authKey.replace("0x", "");
srcBytes = GB.hexStringToByteArray(authKey.substring(2)); 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)); System.arraycopy(srcBytes, 0, authKeyBytes, 0, Math.min(srcBytes.length, 16));
} }

View File

@ -17,6 +17,7 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file; package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file;
import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattCharacteristic;
import android.widget.Toast;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; 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.file.FileHandle;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.FossilRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.FossilRequest;
import nodomain.freeyourgadget.gadgetbridge.util.CRC32C; import nodomain.freeyourgadget.gadgetbridge.util.CRC32C;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
public abstract class FileEncryptedGetRequest extends FossilRequest { public abstract class FileEncryptedGetRequest extends FossilRequest {
private short handle; private short handle;
@ -72,7 +74,12 @@ public abstract class FileEncryptedGetRequest extends FossilRequest {
private void initDecryption() { private void initDecryption() {
try { try {
cipher = Cipher.getInstance("AES/CTR/NoPadding"); cipher = Cipher.getInstance("AES/CTR/NoPadding");
keySpec = new SecretKeySpec(this.adapter.getSecretKey(), "AES"); try {
keySpec = new SecretKeySpec(this.adapter.getSecretKey(), "AES");
} catch (IllegalAccessException e) {
GB.toast("error getting key: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e);
return;
}
iv = new byte[16]; iv = new byte[16];

View File

@ -91,7 +91,13 @@ public class FileEncryptedPutRequest extends FossilRequest {
this.prepareFilePackets(this.file); 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) {
GB.toast("error getting key: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e);
return;
}
try { try {
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");