mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-25 18:15:49 +01:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
0845d15ba2
@ -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;
|
||||||
|
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));
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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() {
|
||||||
|
try {
|
||||||
queueWrite(new VerifyPrivateKeyRequest(
|
queueWrite(new VerifyPrivateKeyRequest(
|
||||||
this.getSecretKey(),
|
this.getSecretKey(),
|
||||||
this
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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");
|
||||||
|
try {
|
||||||
keySpec = new SecretKeySpec(this.adapter.getSecretKey(), "AES");
|
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];
|
||||||
|
@ -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");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user