1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-25 19:36:50 +01:00

Huami: support old version of new chunked protocol used on Amazfit Bip U at least

This is used for setting world clock and setting canned messages for call rejection.
This PR implements setting the canned messages, but unfortunately the feature is somehow not "unlocked"
This commit is contained in:
Andreas Shimokawa 2021-12-23 18:06:58 +01:00
parent 8baf97fd93
commit e1b04f6a5c
3 changed files with 57 additions and 17 deletions

View File

@ -97,6 +97,7 @@ public class AmazfitBipUCoordinator extends HuamiCoordinator {
public int[] getSupportedDeviceSpecificSettings(GBDevice device) { public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
return new int[]{ return new int[]{
R.xml.devicesettings_amazfitbipu, R.xml.devicesettings_amazfitbipu,
//R.xml.devicesettings_canned_dismisscall_16,
R.xml.devicesettings_timeformat, R.xml.devicesettings_timeformat,
R.xml.devicesettings_wearlocation, R.xml.devicesettings_wearlocation,
R.xml.devicesettings_custom_emoji_font, R.xml.devicesettings_custom_emoji_font,

View File

@ -1004,6 +1004,27 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
@Override @Override
public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) { public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) {
if (cannedMessagesSpec.type == CannedMessagesSpec.TYPE_REJECTEDCALLS) {
try {
TransactionBuilder builder = performInitialized("Set canned messages");
int handle = 0x12345678;
for (String cannedMessage : cannedMessagesSpec.cannedMessages) {
int length = cannedMessage.getBytes().length + 5;
ByteBuffer buf = ByteBuffer.allocate(length);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.put((byte) 0x05); // create
buf.putInt(handle++);
buf.put(cannedMessage.getBytes());
writeToChunked2021(builder, (short) 0x0013, getNextHandle(), buf.array(), false, false);
}
builder.queue(getQueue());
} catch (IOException ex) {
LOG.error("Unable to set time on Huami device", ex);
}
}
} }
private boolean isAlarmClockRinging() { private boolean isAlarmClockRinging() {
@ -2976,7 +2997,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
} }
byte[] command = ArrayUtils.addAll(new byte[]{0x00, 0x00, (byte) (0xc0 | type), 0x00}, data); byte[] command = ArrayUtils.addAll(new byte[]{0x00, 0x00, (byte) (0xc0 | type), 0x00}, data);
writeToChunked2021(builder, HuamiService.CHUNKED2021_ENDPOINT_COMPAT, getNextHandle(), command, encrypt); writeToChunked2021(builder, HuamiService.CHUNKED2021_ENDPOINT_COMPAT, getNextHandle(), command, true, encrypt);
} else { } else {
writeToChunkedOld(builder, type, data); writeToChunkedOld(builder, type, data);
} }
@ -3010,13 +3031,17 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
} }
} }
public void writeToChunked2021(TransactionBuilder builder, short type, byte handle, byte[] data, boolean encrypt) { public void writeToChunked2021(TransactionBuilder builder, short type, byte handle, byte[] data, boolean extended_flags, boolean encrypt) {
int remaining = data.length; int remaining = data.length;
int length = data.length; int length = data.length;
byte count = 0; byte count = 0;
int header_size = 11; int header_size = 10;
if (encrypt) { if (extended_flags) {
header_size++;
}
if (extended_flags && encrypt) {
byte[] messagekey = new byte[16]; byte[] messagekey = new byte[16];
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
messagekey[i] = (byte) (sharedSessionKey[i] ^ handle); messagekey[i] = (byte) (sharedSessionKey[i] ^ handle);
@ -3060,26 +3085,40 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
} }
if (count == 0) { if (count == 0) {
flags |= 0x01; flags |= 0x01;
chunk[5] = (byte) (length & 0xff); int i = 4;
chunk[6] = (byte) ((length >> 8) & 0xff); if (extended_flags) {
chunk[7] = (byte) ((length >> 16) & 0xff); i++;
chunk[8] = (byte) ((length >> 24) & 0xff); }
chunk[9] = (byte) (type & 0xff); chunk[i++] = (byte) (length & 0xff);
chunk[10] = (byte) ((type >> 8) & 0xff); chunk[i++] = (byte) ((length >> 8) & 0xff);
chunk[i++] = (byte) ((length >> 16) & 0xff);
chunk[i++] = (byte) ((length >> 24) & 0xff);
chunk[i++] = (byte) (type & 0xff);
chunk[i] = (byte) ((type >> 8) & 0xff);
} }
if (remaining <= MAX_CHUNKLENGTH) { if (remaining <= MAX_CHUNKLENGTH) {
flags |= 0x06; // last chunk? flags |= 0x06; // last chunk?
} }
chunk[0] = 0x03; chunk[0] = 0x03;
chunk[1] = flags; chunk[1] = flags;
chunk[2] = 0; if (extended_flags) {
chunk[3] = handle; chunk[2] = 0;
chunk[4] = count; chunk[3] = handle;
chunk[4] = count;
} else {
chunk[2] = handle;
chunk[3] = count;
}
System.arraycopy(data, data.length - remaining, chunk, header_size, copybytes); System.arraycopy(data, data.length - remaining, chunk, header_size, copybytes);
builder.write(characteristicChunked2021Write, chunk); builder.write(characteristicChunked2021Write, chunk);
remaining -= copybytes; remaining -= copybytes;
header_size = 5; header_size = 4;
if (extended_flags) {
header_size++;
}
count++; count++;
} }
} }
@ -3087,7 +3126,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
public void writeToConfiguration(TransactionBuilder builder, byte[] data) { public void writeToConfiguration(TransactionBuilder builder, byte[] data) {
if (force2021Protocol) { if (force2021Protocol) {
data = ArrayUtils.insert(0, data, (byte) 1); data = ArrayUtils.insert(0, data, (byte) 1);
writeToChunked2021(builder, HuamiService.CHUNKED2021_ENDPOINT_COMPAT, getNextHandle(), data, true); writeToChunked2021(builder, HuamiService.CHUNKED2021_ENDPOINT_COMPAT, getNextHandle(), data, true, true);
} else { } else {
builder.write(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION), data); builder.write(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION), data);
} }

View File

@ -87,7 +87,7 @@ public class InitOperation2021 extends InitOperation {
sendPubkeyCommand[3] = 0x02; sendPubkeyCommand[3] = 0x02;
System.arraycopy(publicEC, 0, sendPubkeyCommand, 4, 48); System.arraycopy(publicEC, 0, sendPubkeyCommand, 4, 48);
//testAuth(); //testAuth();
huamiSupport.writeToChunked2021(builder, HuamiService.CHUNKED2021_ENDPOINT_AUTH, huamiSupport.getNextHandle(), sendPubkeyCommand, false); huamiSupport.writeToChunked2021(builder, HuamiService.CHUNKED2021_ENDPOINT_AUTH, huamiSupport.getNextHandle(), sendPubkeyCommand, true, false);
} }
private native byte[] ecdh_generate_public(byte[] privateEC); private native byte[] ecdh_generate_public(byte[] privateEC);
@ -170,7 +170,7 @@ public class InitOperation2021 extends InitOperation {
System.arraycopy(encryptedRandom1, 0, command, 1, 16); System.arraycopy(encryptedRandom1, 0, command, 1, 16);
System.arraycopy(encryptedRandom2, 0, command, 17, 16); System.arraycopy(encryptedRandom2, 0, command, 17, 16);
TransactionBuilder builder = createTransactionBuilder("Sending double encryted random to device"); TransactionBuilder builder = createTransactionBuilder("Sending double encryted random to device");
huamiSupport.writeToChunked2021(builder, HuamiService.CHUNKED2021_ENDPOINT_AUTH, huamiSupport.getNextHandle(), command, false); huamiSupport.writeToChunked2021(builder, HuamiService.CHUNKED2021_ENDPOINT_AUTH, huamiSupport.getNextHandle(), command, true, false);
huamiSupport.performImmediately(builder); huamiSupport.performImmediately(builder);
} }
} catch (Exception e) { } catch (Exception e) {