mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-26 16:41:43 +01:00
Huawei: Initial ephemeris update support
This commit is contained in:
parent
5272d017ac
commit
cf7fa3adde
@ -35,6 +35,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.App;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Calls;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Calls;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.CameraRemote;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.CameraRemote;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Contacts;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Contacts;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.EphemerisFileUpload;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileDownloadService0A;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileDownloadService0A;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileDownloadService2C;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileDownloadService2C;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.GpsAndTime;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.GpsAndTime;
|
||||||
@ -48,6 +49,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FitnessData;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.MusicControl;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.MusicControl;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Notifications;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Notifications;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileUpload;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileUpload;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Ephemeris;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
||||||
|
|
||||||
public class HuaweiPacket {
|
public class HuaweiPacket {
|
||||||
@ -664,6 +666,36 @@ public class HuaweiPacket {
|
|||||||
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
|
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
case Ephemeris.id:
|
||||||
|
switch (this.commandId) {
|
||||||
|
case Ephemeris.OperatorData.id:
|
||||||
|
return new Ephemeris.OperatorData.OperatorIncomingRequest(paramsProvider).fromPacket(this);
|
||||||
|
case Ephemeris.ParameterConsult.id:
|
||||||
|
return new Ephemeris.ParameterConsult.Response(paramsProvider).fromPacket(this);
|
||||||
|
case Ephemeris.FileStatus.id:
|
||||||
|
return new Ephemeris.FileStatus.Response(paramsProvider).fromPacket(this);
|
||||||
|
default:
|
||||||
|
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
case EphemerisFileUpload.id:
|
||||||
|
switch (this.commandId) {
|
||||||
|
case EphemerisFileUpload.FileList.id:
|
||||||
|
return new EphemerisFileUpload.FileList.FileListIncomingRequest(paramsProvider).fromPacket(this);
|
||||||
|
case EphemerisFileUpload.FileConsult.id:
|
||||||
|
return new EphemerisFileUpload.FileConsult.FileConsultIncomingRequest(paramsProvider).fromPacket(this);
|
||||||
|
case EphemerisFileUpload.QuerySingleFileInfo.id:
|
||||||
|
return new EphemerisFileUpload.QuerySingleFileInfo.QuerySingleFileInfoIncomingRequest(paramsProvider).fromPacket(this);
|
||||||
|
case EphemerisFileUpload.DataRequest.id:
|
||||||
|
return new EphemerisFileUpload.DataRequest.DataRequestIncomingRequest(paramsProvider).fromPacket(this);
|
||||||
|
case EphemerisFileUpload.UploadData.id:
|
||||||
|
return new EphemerisFileUpload.UploadData.UploadDataResponse(paramsProvider).fromPacket(this);
|
||||||
|
case EphemerisFileUpload.UploadDone.id:
|
||||||
|
return new EphemerisFileUpload.UploadDone.UploadDoneIncomingRequest(paramsProvider).fromPacket(this);
|
||||||
|
default:
|
||||||
|
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
|
||||||
|
return this;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
|
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
|
||||||
return this;
|
return this;
|
||||||
@ -864,6 +896,63 @@ public class HuaweiPacket {
|
|||||||
return retv;
|
return retv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<byte[]> serializeFileChunk1c(byte[] fileChunk, short transferSize, int packetCount) throws SerializeException {
|
||||||
|
List<byte[]> retv = new ArrayList<>();
|
||||||
|
int headerLength = 4; // Magic + (short)(bodyLength + 1) + 0x00
|
||||||
|
int bodyHeaderLength = 2; // sID + cID
|
||||||
|
int footerLength = 2; //CRC16
|
||||||
|
int subHeaderLength = 1;
|
||||||
|
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(fileChunk);
|
||||||
|
|
||||||
|
for (int i = 0; i < packetCount; i++) {
|
||||||
|
|
||||||
|
short contentSize = (short) Math.min(transferSize, buffer.remaining());
|
||||||
|
|
||||||
|
ByteBuffer payload = ByteBuffer.allocate(contentSize + subHeaderLength);
|
||||||
|
payload.put((byte)i);
|
||||||
|
|
||||||
|
byte[] packetContent = new byte[contentSize];
|
||||||
|
buffer.get(packetContent);
|
||||||
|
payload.put(packetContent);
|
||||||
|
|
||||||
|
byte[] new_payload = payload.array();
|
||||||
|
|
||||||
|
int bodyLength = bodyHeaderLength + new_payload.length;
|
||||||
|
|
||||||
|
short packetSize = (short)(headerLength + bodyLength + footerLength);
|
||||||
|
ByteBuffer packet = ByteBuffer.allocate(packetSize);
|
||||||
|
|
||||||
|
int start = packet.position();
|
||||||
|
packet.put((byte) 0x5a); // Magic byte
|
||||||
|
packet.putShort((short) (bodyLength + 1)); // Length
|
||||||
|
|
||||||
|
packet.put((byte) 0x00);
|
||||||
|
packet.put(this.serviceId);
|
||||||
|
packet.put(this.commandId);
|
||||||
|
|
||||||
|
packet.put(new_payload);
|
||||||
|
|
||||||
|
int length = packet.position() - start;
|
||||||
|
if (length != packetSize - footerLength) {
|
||||||
|
throw new HuaweiPacket.SerializeException(String.format(GBApplication.getLanguage(), "Packet lengths don't match! %d != %d", length, packetSize + headerLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] complete = new byte[length];
|
||||||
|
packet.position(start);
|
||||||
|
packet.get(complete, 0, length);
|
||||||
|
int crc16 = CheckSums.getCRC16(complete, 0x0000);
|
||||||
|
|
||||||
|
packet.putShort((short) crc16); // CRC16
|
||||||
|
|
||||||
|
retv.add(packet.array());
|
||||||
|
}
|
||||||
|
return retv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public List<byte[]> serialize() throws CryptoException {
|
public List<byte[]> serialize() throws CryptoException {
|
||||||
// TODO: necessary for this to work:
|
// TODO: necessary for this to work:
|
||||||
// - serviceId
|
// - serviceId
|
||||||
|
@ -0,0 +1,114 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV;
|
||||||
|
|
||||||
|
public class Ephemeris {
|
||||||
|
public static final int id = 0x1f;
|
||||||
|
|
||||||
|
public static class OperatorData {
|
||||||
|
public static final int id = 0x01;
|
||||||
|
|
||||||
|
public static class OperatorIncomingRequest extends HuaweiPacket {
|
||||||
|
public byte operationInfo;
|
||||||
|
public int operationTime;
|
||||||
|
|
||||||
|
public OperatorIncomingRequest(ParamsProvider paramsProvider) {
|
||||||
|
super(paramsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parseTlv() throws ParseException {
|
||||||
|
|
||||||
|
//TODO: can contain many elements.
|
||||||
|
//List<HuaweiTLV> subContainers = container.getObjects(0x81);
|
||||||
|
HuaweiTLV subTlv = this.tlv.getObject(0x81);
|
||||||
|
|
||||||
|
this.operationInfo = subTlv.getByte(0x02);
|
||||||
|
this.operationTime = subTlv.getInteger(0x03);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class OperatorResponse extends HuaweiPacket {
|
||||||
|
|
||||||
|
public OperatorResponse(ParamsProvider paramsProvider, int responseCode) {
|
||||||
|
super(paramsProvider);
|
||||||
|
|
||||||
|
this.serviceId = Ephemeris.id;
|
||||||
|
this.commandId = id;
|
||||||
|
|
||||||
|
this.tlv = new HuaweiTLV().put(0x7f, responseCode);
|
||||||
|
|
||||||
|
this.complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ParameterConsult {
|
||||||
|
public static final byte id = 0x02;
|
||||||
|
|
||||||
|
public static class Request extends HuaweiPacket {
|
||||||
|
|
||||||
|
|
||||||
|
public Request(ParamsProvider paramsProvider) {
|
||||||
|
super(paramsProvider);
|
||||||
|
this.serviceId = Ephemeris.id;
|
||||||
|
this.commandId = id;
|
||||||
|
this.tlv = new HuaweiTLV().put(0x81);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends HuaweiPacket {
|
||||||
|
public int consultDeviceTime;
|
||||||
|
public byte downloadVersion;
|
||||||
|
public String downloadTag;
|
||||||
|
|
||||||
|
public Response (ParamsProvider paramsProvider) {
|
||||||
|
super(paramsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parseTlv() throws HuaweiPacket.ParseException {
|
||||||
|
|
||||||
|
//TODO: can contain many elements.
|
||||||
|
//List<HuaweiTLV> subContainers = container.getObjects(0x81);
|
||||||
|
HuaweiTLV subTlv = this.tlv.getObject(0x81);
|
||||||
|
|
||||||
|
this.consultDeviceTime = subTlv.getByte(0x04) * 1000;
|
||||||
|
this.downloadVersion = subTlv.getByte(0x05);
|
||||||
|
this.downloadTag = subTlv.getString(0x06);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FileStatus {
|
||||||
|
public static final byte id = 0x03;
|
||||||
|
|
||||||
|
public static class Request extends HuaweiPacket {
|
||||||
|
|
||||||
|
|
||||||
|
public Request(ParamsProvider paramsProvider, byte status) {
|
||||||
|
super(paramsProvider);
|
||||||
|
this.serviceId = Ephemeris.id;
|
||||||
|
this.commandId = id;
|
||||||
|
this.tlv = new HuaweiTLV().put(0x1, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends HuaweiPacket {
|
||||||
|
public int responseCode;
|
||||||
|
|
||||||
|
public Response (ParamsProvider paramsProvider) {
|
||||||
|
super(paramsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parseTlv() throws HuaweiPacket.ParseException {
|
||||||
|
this.responseCode = this.tlv.getInteger(0x7f);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,269 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV;
|
||||||
|
|
||||||
|
public class EphemerisFileUpload {
|
||||||
|
public static final int id = 0x1c;
|
||||||
|
|
||||||
|
public static class FileList {
|
||||||
|
public static final int id = 0x01;
|
||||||
|
|
||||||
|
public static class FileListIncomingRequest extends HuaweiPacket {
|
||||||
|
public byte fileType;
|
||||||
|
public String productId = "";
|
||||||
|
|
||||||
|
public FileListIncomingRequest(ParamsProvider paramsProvider) {
|
||||||
|
super(paramsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parseTlv() throws ParseException {
|
||||||
|
|
||||||
|
// 0x1 - filenames
|
||||||
|
// 0x2 - fileType
|
||||||
|
// 0x3 - productId
|
||||||
|
// 0x4 - issuerId
|
||||||
|
// 0x5 - cardType
|
||||||
|
this.fileType = this.tlv.getByte(0x02);
|
||||||
|
if (this.tlv.contains(0x3))
|
||||||
|
productId = this.tlv.getString(0x3);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FileListResponse extends HuaweiPacket {
|
||||||
|
|
||||||
|
public FileListResponse(ParamsProvider paramsProvider, int responseCode, String files) {
|
||||||
|
super(paramsProvider);
|
||||||
|
|
||||||
|
this.serviceId = EphemerisFileUpload.id;
|
||||||
|
this.commandId = id;
|
||||||
|
|
||||||
|
if (responseCode != 0) {
|
||||||
|
this.tlv = new HuaweiTLV().put(0x7f, responseCode);
|
||||||
|
} else {
|
||||||
|
this.tlv = new HuaweiTLV().put(0x1, files);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FileConsult {
|
||||||
|
public static final int id = 0x02;
|
||||||
|
|
||||||
|
public static class FileConsultIncomingRequest extends HuaweiPacket {
|
||||||
|
public int responseCode = 0;
|
||||||
|
public String protocolVersion = null;
|
||||||
|
public byte bitmapEnable = 0;
|
||||||
|
public short transferSize = 0;
|
||||||
|
public int maxDataSize = 0;
|
||||||
|
public short timeOut = 0;
|
||||||
|
public byte fileType = 0;
|
||||||
|
|
||||||
|
public FileConsultIncomingRequest(ParamsProvider paramsProvider) {
|
||||||
|
super(paramsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parseTlv() throws ParseException {
|
||||||
|
|
||||||
|
if (this.tlv.contains(0x7f))
|
||||||
|
responseCode = this.tlv.getInteger(0x7f);
|
||||||
|
|
||||||
|
// 0x1 - version
|
||||||
|
// 0x2 - bitmapEnable
|
||||||
|
// 0x3 - transferSize
|
||||||
|
// 0x4 - maxDataSize
|
||||||
|
// 0x5 - timeOut
|
||||||
|
// 0x6 - fileType
|
||||||
|
|
||||||
|
if (this.tlv.contains(0x1))
|
||||||
|
this.protocolVersion = this.tlv.getString(0x1);
|
||||||
|
if (this.tlv.contains(0x2))
|
||||||
|
this.bitmapEnable = this.tlv.getByte(0x2);
|
||||||
|
if (this.tlv.contains(0x3))
|
||||||
|
this.transferSize = this.tlv.getShort(0x3);
|
||||||
|
if (this.tlv.contains(0x4))
|
||||||
|
this.maxDataSize = this.tlv.getInteger(0x4);
|
||||||
|
if (this.tlv.contains(0x5))
|
||||||
|
this.timeOut = this.tlv.getShort(0x5);
|
||||||
|
if (this.tlv.contains(0x6))
|
||||||
|
this.fileType = this.tlv.getByte(0x6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FileConsultResponse extends HuaweiPacket {
|
||||||
|
|
||||||
|
public FileConsultResponse(ParamsProvider paramsProvider, int responseCode) {
|
||||||
|
super(paramsProvider);
|
||||||
|
|
||||||
|
this.serviceId = EphemerisFileUpload.id;
|
||||||
|
this.commandId = id;
|
||||||
|
|
||||||
|
this.tlv = new HuaweiTLV().put(0x7f, responseCode);
|
||||||
|
|
||||||
|
this.complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class QuerySingleFileInfo {
|
||||||
|
public static final int id = 0x03;
|
||||||
|
|
||||||
|
public static class QuerySingleFileInfoIncomingRequest extends HuaweiPacket {
|
||||||
|
public int responseCode = 0;
|
||||||
|
public String fileName = null;
|
||||||
|
|
||||||
|
public QuerySingleFileInfoIncomingRequest(ParamsProvider paramsProvider) {
|
||||||
|
super(paramsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parseTlv() throws ParseException {
|
||||||
|
|
||||||
|
if (this.tlv.contains(0x7f))
|
||||||
|
responseCode = this.tlv.getInteger(0x7f);
|
||||||
|
|
||||||
|
if (this.tlv.contains(0x1))
|
||||||
|
this.fileName = this.tlv.getString(0x1);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class QuerySingleFileInfoResponse extends HuaweiPacket {
|
||||||
|
|
||||||
|
public QuerySingleFileInfoResponse(ParamsProvider paramsProvider, int responseCode, int fileSize, short crc) {
|
||||||
|
super(paramsProvider);
|
||||||
|
|
||||||
|
this.serviceId = EphemerisFileUpload.id;
|
||||||
|
this.commandId = id;
|
||||||
|
|
||||||
|
if(responseCode != 0) {
|
||||||
|
this.tlv = new HuaweiTLV().put(0x7f, responseCode);
|
||||||
|
} else {
|
||||||
|
this.tlv = new HuaweiTLV().put(0x2, fileSize).put(0x3, crc);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DataRequest {
|
||||||
|
public static final int id = 0x04;
|
||||||
|
|
||||||
|
public static class DataRequestIncomingRequest extends HuaweiPacket {
|
||||||
|
public int responseCode = 0;
|
||||||
|
public String fileName = null;
|
||||||
|
public int offset = -1;
|
||||||
|
public int len = -1;
|
||||||
|
public byte bitmap = (byte) 0xff;
|
||||||
|
|
||||||
|
|
||||||
|
public DataRequestIncomingRequest(ParamsProvider paramsProvider) {
|
||||||
|
super(paramsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parseTlv() throws ParseException {
|
||||||
|
// 1 - fileName
|
||||||
|
// 2 - offset
|
||||||
|
// 3 - length
|
||||||
|
// 4 - fileBitmap
|
||||||
|
// 7f - error
|
||||||
|
|
||||||
|
if (this.tlv.contains(0x7f))
|
||||||
|
responseCode = this.tlv.getInteger(0x7f);
|
||||||
|
|
||||||
|
if (this.tlv.contains(0x1))
|
||||||
|
this.fileName = this.tlv.getString(0x1);
|
||||||
|
if (this.tlv.contains(0x2))
|
||||||
|
this.offset = this.tlv.getInteger(0x2);
|
||||||
|
if (this.tlv.contains(0x3))
|
||||||
|
this.len = this.tlv.getInteger(0x3);
|
||||||
|
if (this.tlv.contains(0x4))
|
||||||
|
this.bitmap = this.tlv.getByte(0x4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DataRequestResponse extends HuaweiPacket {
|
||||||
|
public DataRequestResponse(ParamsProvider paramsProvider, int responseCode, String filename, int offset) {
|
||||||
|
super(paramsProvider);
|
||||||
|
|
||||||
|
this.serviceId = EphemerisFileUpload.id;
|
||||||
|
this.commandId = id;
|
||||||
|
|
||||||
|
this.tlv = new HuaweiTLV().put(0x7f, responseCode);
|
||||||
|
if(responseCode == 100000) {
|
||||||
|
this.tlv.put(0x2, filename).put(0x3, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UploadData {
|
||||||
|
public static final int id = 0x05;
|
||||||
|
|
||||||
|
public static class FileNextChunkSend extends HuaweiPacket {
|
||||||
|
public FileNextChunkSend(ParamsProvider paramsProvider) {
|
||||||
|
super(paramsProvider);
|
||||||
|
this.serviceId = EphemerisFileUpload.id;
|
||||||
|
this.commandId = id;
|
||||||
|
this.complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UploadDataResponse extends HuaweiPacket {
|
||||||
|
public int responseCode = 0;
|
||||||
|
|
||||||
|
public UploadDataResponse(ParamsProvider paramsProvider) {
|
||||||
|
super(paramsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parseTlv() throws ParseException {
|
||||||
|
this.tlv = new HuaweiTLV();
|
||||||
|
this.tlv.parse(payload, 2, payload.length - 2);
|
||||||
|
this.responseCode = this.tlv.getInteger(0x7f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class UploadDone {
|
||||||
|
public static final int id = 0x06;
|
||||||
|
|
||||||
|
public static class UploadDoneIncomingRequest extends HuaweiPacket {
|
||||||
|
public byte uploadResult = 0;
|
||||||
|
|
||||||
|
public UploadDoneIncomingRequest(ParamsProvider paramsProvider) {
|
||||||
|
super(paramsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parseTlv() throws ParseException {
|
||||||
|
this.uploadResult = this.tlv.getByte(0x1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UploadDoneResponse extends HuaweiPacket {
|
||||||
|
|
||||||
|
public UploadDoneResponse(ParamsProvider paramsProvider, int responseCode) {
|
||||||
|
super(paramsProvider);
|
||||||
|
|
||||||
|
this.serviceId = EphemerisFileUpload.id;
|
||||||
|
this.commandId = id;
|
||||||
|
|
||||||
|
this.tlv = new HuaweiTLV().put(0x7f, responseCode);
|
||||||
|
|
||||||
|
this.complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -32,7 +32,6 @@ import java.io.IOException;
|
|||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -43,7 +42,6 @@ import nodomain.freeyourgadget.gadgetbridge.activities.CameraActivity;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCameraRemote;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCameraRemote;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventDisplayMessage;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
@ -51,6 +49,8 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.App;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Calls;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Calls;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.CameraRemote;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.CameraRemote;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.DeviceConfig;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.DeviceConfig;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Ephemeris;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.EphemerisFileUpload;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FindPhone;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FindPhone;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.GpsAndTime;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.GpsAndTime;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Menstrual;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Menstrual;
|
||||||
@ -59,7 +59,6 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileUpload;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.P2P;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.P2P;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Watchface;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Watchface;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.Request;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.Request;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetPhoneInfoRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetPhoneInfoRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendFileUploadComplete;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendFileUploadComplete;
|
||||||
@ -70,13 +69,11 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.Send
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendFileUploadHash;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendFileUploadHash;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWatchfaceConfirm;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWatchfaceConfirm;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWatchfaceOperation;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWatchfaceOperation;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWeatherDeviceRequest;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SetMusicStatusRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SetMusicStatusRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles responses that are not a reply to a request
|
* Handles responses that are not a reply to a request
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class AsynchronousResponse {
|
public class AsynchronousResponse {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(AsynchronousResponse.class);
|
private static final Logger LOG = LoggerFactory.getLogger(AsynchronousResponse.class);
|
||||||
@ -84,6 +81,7 @@ public class AsynchronousResponse {
|
|||||||
private final HuaweiSupportProvider support;
|
private final HuaweiSupportProvider support;
|
||||||
private final Handler mFindPhoneHandler = new Handler();
|
private final Handler mFindPhoneHandler = new Handler();
|
||||||
private final static HashMap<Integer, String> dayOfWeekMap = new HashMap<>();
|
private final static HashMap<Integer, String> dayOfWeekMap = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
dayOfWeekMap.put(Calendar.MONDAY, DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_MO);
|
dayOfWeekMap.put(Calendar.MONDAY, DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_MO);
|
||||||
dayOfWeekMap.put(Calendar.TUESDAY, DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_TU);
|
dayOfWeekMap.put(Calendar.TUESDAY, DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_TU);
|
||||||
@ -123,6 +121,8 @@ public class AsynchronousResponse {
|
|||||||
handleCameraRemote(response);
|
handleCameraRemote(response);
|
||||||
handleApp(response);
|
handleApp(response);
|
||||||
handleP2p(response);
|
handleP2p(response);
|
||||||
|
handleEphemeris(response);
|
||||||
|
handleEphemerisUploadService(response);
|
||||||
} catch (Request.ResponseParseException e) {
|
} catch (Request.ResponseParseException e) {
|
||||||
LOG.error("Response parse exception", e);
|
LOG.error("Response parse exception", e);
|
||||||
}
|
}
|
||||||
@ -226,13 +226,14 @@ public class AsynchronousResponse {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles asynchronous music packet, for the following events:
|
* Handles asynchronous music packet, for the following events:
|
||||||
* - The app is opened on the band (sends back music info)
|
* - The app is opened on the band (sends back music info)
|
||||||
* - A button is clicked
|
* - A button is clicked
|
||||||
* - Play
|
* - Play
|
||||||
* - Pause
|
* - Pause
|
||||||
* - Previous
|
* - Previous
|
||||||
* - Next
|
* - Next
|
||||||
* - The volume is adjusted
|
* - The volume is adjusted
|
||||||
|
*
|
||||||
* @param response Packet to be handled
|
* @param response Packet to be handled
|
||||||
*/
|
*/
|
||||||
private void handleMusicControls(HuaweiPacket response) throws Request.ResponseParseException {
|
private void handleMusicControls(HuaweiPacket response) throws Request.ResponseParseException {
|
||||||
@ -420,12 +421,12 @@ public class AsynchronousResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleFileUpload(HuaweiPacket response) throws Request.ResponseParseException {
|
private void handleFileUpload(HuaweiPacket response) throws Request.ResponseParseException {
|
||||||
if (response.serviceId == FileUpload.id) {
|
if (response.serviceId == FileUpload.id) {
|
||||||
if (response.commandId == FileUpload.FileInfoSend.id) {
|
if (response.commandId == FileUpload.FileInfoSend.id) {
|
||||||
if (!(response instanceof FileUpload.FileInfoSend.Response))
|
if (!(response instanceof FileUpload.FileInfoSend.Response))
|
||||||
throw new Request.ResponseTypeMismatchException(response, FileUpload.FileInfoSend.Response.class);
|
throw new Request.ResponseTypeMismatchException(response, FileUpload.FileInfoSend.Response.class);
|
||||||
if(support.huaweiUploadManager.getFileUploadInfo() == null) {
|
if (support.huaweiUploadManager.getFileUploadInfo() == null) {
|
||||||
LOG.error("Upload file info received but no file to upload");
|
LOG.error("Upload file info received but no file to upload");
|
||||||
} else {
|
} else {
|
||||||
FileUpload.FileInfoSend.Response resp = (FileUpload.FileInfoSend.Response) response;
|
FileUpload.FileInfoSend.Response resp = (FileUpload.FileInfoSend.Response) response;
|
||||||
@ -440,24 +441,24 @@ public class AsynchronousResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (response.commandId == FileUpload.FileHashSend.id) {
|
} else if (response.commandId == FileUpload.FileHashSend.id) {
|
||||||
if (!(response instanceof FileUpload.FileHashSend.Response))
|
if (!(response instanceof FileUpload.FileHashSend.Response))
|
||||||
throw new Request.ResponseTypeMismatchException(response, FileUpload.FileHashSend.Response.class);
|
throw new Request.ResponseTypeMismatchException(response, FileUpload.FileHashSend.Response.class);
|
||||||
if(support.huaweiUploadManager.getFileUploadInfo() == null) {
|
if (support.huaweiUploadManager.getFileUploadInfo() == null) {
|
||||||
LOG.error("Upload file hash requested but no file to upload");
|
LOG.error("Upload file hash requested but no file to upload");
|
||||||
} else {
|
} else {
|
||||||
FileUpload.FileHashSend.Response resp = (FileUpload.FileHashSend.Response) response;
|
FileUpload.FileHashSend.Response resp = (FileUpload.FileHashSend.Response) response;
|
||||||
support.huaweiUploadManager.getFileUploadInfo().setFileId(resp.fileId);
|
support.huaweiUploadManager.getFileUploadInfo().setFileId(resp.fileId);
|
||||||
try {
|
try {
|
||||||
SendFileUploadHash sendFileUploadHash = new SendFileUploadHash(support, support.huaweiUploadManager);
|
SendFileUploadHash sendFileUploadHash = new SendFileUploadHash(support, support.huaweiUploadManager);
|
||||||
sendFileUploadHash.doPerform();
|
sendFileUploadHash.doPerform();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.error("Could not send file upload hash request", e);
|
LOG.error("Could not send file upload hash request", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (response.commandId == FileUpload.FileUploadConsultAck.id) {
|
} else if (response.commandId == FileUpload.FileUploadConsultAck.id) {
|
||||||
if (!(response instanceof FileUpload.FileUploadConsultAck.Response))
|
if (!(response instanceof FileUpload.FileUploadConsultAck.Response))
|
||||||
throw new Request.ResponseTypeMismatchException(response, FileUpload.FileUploadConsultAck.Response.class);
|
throw new Request.ResponseTypeMismatchException(response, FileUpload.FileUploadConsultAck.Response.class);
|
||||||
if(support.huaweiUploadManager.getFileUploadInfo() == null) {
|
if (support.huaweiUploadManager.getFileUploadInfo() == null) {
|
||||||
LOG.error("Upload file ask requested but no file to upload");
|
LOG.error("Upload file ask requested but no file to upload");
|
||||||
} else {
|
} else {
|
||||||
FileUpload.FileUploadConsultAck.Response resp = (FileUpload.FileUploadConsultAck.Response) response;
|
FileUpload.FileUploadConsultAck.Response resp = (FileUpload.FileUploadConsultAck.Response) response;
|
||||||
@ -473,10 +474,10 @@ public class AsynchronousResponse {
|
|||||||
LOG.error("Could not send file upload ack request", e);
|
LOG.error("Could not send file upload ack request", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (response.commandId == FileUpload.FileNextChunkParams.id) {
|
} else if (response.commandId == FileUpload.FileNextChunkParams.id) {
|
||||||
if (!(response instanceof FileUpload.FileNextChunkParams))
|
if (!(response instanceof FileUpload.FileNextChunkParams))
|
||||||
throw new Request.ResponseTypeMismatchException(response, FileUpload.FileNextChunkParams.class);
|
throw new Request.ResponseTypeMismatchException(response, FileUpload.FileNextChunkParams.class);
|
||||||
if(support.huaweiUploadManager.getFileUploadInfo() == null) {
|
if (support.huaweiUploadManager.getFileUploadInfo() == null) {
|
||||||
LOG.error("Upload file next chunk requested but no file to upload");
|
LOG.error("Upload file next chunk requested but no file to upload");
|
||||||
} else {
|
} else {
|
||||||
FileUpload.FileNextChunkParams resp = (FileUpload.FileNextChunkParams) response;
|
FileUpload.FileNextChunkParams resp = (FileUpload.FileNextChunkParams) response;
|
||||||
@ -493,8 +494,8 @@ public class AsynchronousResponse {
|
|||||||
LOG.error("Could not send fileupload next chunk request", e);
|
LOG.error("Could not send fileupload next chunk request", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (response.commandId == FileUpload.FileUploadResult.id) {
|
} else if (response.commandId == FileUpload.FileUploadResult.id) {
|
||||||
if(support.huaweiUploadManager.getFileUploadInfo() == null) {
|
if (support.huaweiUploadManager.getFileUploadInfo() == null) {
|
||||||
LOG.error("Upload file result requested but no file to upload");
|
LOG.error("Upload file result requested but no file to upload");
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
@ -510,7 +511,7 @@ public class AsynchronousResponse {
|
|||||||
LOG.error("Could not send file upload result request", e);
|
LOG.error("Could not send file upload result request", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,7 +542,7 @@ public class AsynchronousResponse {
|
|||||||
if (response.commandId == 0x2) {
|
if (response.commandId == 0x2) {
|
||||||
try {
|
try {
|
||||||
byte status = response.getTlv().getByte(0x1);
|
byte status = response.getTlv().getByte(0x1);
|
||||||
if(status == (byte)0x66 || status == (byte)0x69) {
|
if (status == (byte) 0x66 || status == (byte) 0x69) {
|
||||||
this.support.getHuaweiAppManager().requestAppList();
|
this.support.getHuaweiAppManager().requestAppList();
|
||||||
}
|
}
|
||||||
} catch (HuaweiPacket.MissingTagException e) {
|
} catch (HuaweiPacket.MissingTagException e) {
|
||||||
@ -553,15 +554,15 @@ public class AsynchronousResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleP2p(HuaweiPacket response) throws Request.ResponseParseException {
|
private void handleP2p(HuaweiPacket response) throws Request.ResponseParseException {
|
||||||
if (response.serviceId == P2P.id && response.commandId == P2P.P2PCommand.id) {
|
if (response.serviceId == P2P.id && response.commandId == P2P.P2PCommand.id) {
|
||||||
if (!(response instanceof P2P.P2PCommand.Response))
|
if (!(response instanceof P2P.P2PCommand.Response))
|
||||||
throw new Request.ResponseTypeMismatchException(response, P2P.P2PCommand.class);
|
throw new Request.ResponseTypeMismatchException(response, P2P.P2PCommand.class);
|
||||||
try {
|
try {
|
||||||
this.support.getHuaweiP2PManager().handlePacket((P2P.P2PCommand.Response) response);
|
this.support.getHuaweiP2PManager().handlePacket((P2P.P2PCommand.Response) response);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error("Error in P2P service", e);
|
LOG.error("Error in P2P service", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleWeatherCheck(HuaweiPacket response) {
|
private void handleWeatherCheck(HuaweiPacket response) {
|
||||||
@ -589,6 +590,57 @@ public class AsynchronousResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleEphemeris(HuaweiPacket response) {
|
||||||
|
if (response.serviceId == Ephemeris.id && response.commandId == Ephemeris.OperatorData.id) {
|
||||||
|
if (!(response instanceof Ephemeris.OperatorData.OperatorIncomingRequest)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte operationInfo = ((Ephemeris.OperatorData.OperatorIncomingRequest) response).operationInfo;
|
||||||
|
int operationTime = ((Ephemeris.OperatorData.OperatorIncomingRequest) response).operationTime;
|
||||||
|
LOG.info("Ephemeris: operation: {} time: {}", operationInfo, operationTime);
|
||||||
|
support.getHuaweiEphemerisManager().handleOperatorRequest(operationInfo, operationTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleEphemerisUploadService(HuaweiPacket response) {
|
||||||
|
if (response.serviceId == EphemerisFileUpload.id) {
|
||||||
|
if (response.commandId == EphemerisFileUpload.FileList.id) {
|
||||||
|
if (!(response instanceof EphemerisFileUpload.FileList.FileListIncomingRequest)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
support.getHuaweiEphemerisManager().handleFileSendRequest(((EphemerisFileUpload.FileList.FileListIncomingRequest) response).fileType, ((EphemerisFileUpload.FileList.FileListIncomingRequest) response).productId);
|
||||||
|
} else if (response.commandId == EphemerisFileUpload.FileConsult.id) {
|
||||||
|
if (!(response instanceof EphemerisFileUpload.FileConsult.FileConsultIncomingRequest)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EphemerisFileUpload.FileConsult.FileConsultIncomingRequest res = (EphemerisFileUpload.FileConsult.FileConsultIncomingRequest) response;
|
||||||
|
support.getHuaweiEphemerisManager().handleFileConsultIncomingRequest(res.responseCode, res.protocolVersion, res.bitmapEnable, res.transferSize, res.maxDataSize, res.timeOut, res.fileType);
|
||||||
|
} else if (response.commandId == EphemerisFileUpload.QuerySingleFileInfo.id) {
|
||||||
|
if (!(response instanceof EphemerisFileUpload.QuerySingleFileInfo.QuerySingleFileInfoIncomingRequest)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
support.getHuaweiEphemerisManager().handleSingleFileIncomingRequest(((EphemerisFileUpload.QuerySingleFileInfo.QuerySingleFileInfoIncomingRequest) response).fileName);
|
||||||
|
} else if (response.commandId == EphemerisFileUpload.DataRequest.id) {
|
||||||
|
if (!(response instanceof EphemerisFileUpload.DataRequest.DataRequestIncomingRequest)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EphemerisFileUpload.DataRequest.DataRequestIncomingRequest res = (EphemerisFileUpload.DataRequest.DataRequestIncomingRequest) response;
|
||||||
|
support.getHuaweiEphemerisManager().handleDataRequestIncomingRequest(res.responseCode, res.fileName, res.offset, res.len, res.bitmap);
|
||||||
|
} else if (response.commandId == EphemerisFileUpload.UploadData.id) {
|
||||||
|
if (!(response instanceof EphemerisFileUpload.UploadData.UploadDataResponse)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
support.getHuaweiEphemerisManager().handleFileUploadResponse(((EphemerisFileUpload.UploadData.UploadDataResponse) response).responseCode);
|
||||||
|
} else if (response.commandId == EphemerisFileUpload.UploadDone.id) {
|
||||||
|
if (!(response instanceof EphemerisFileUpload.UploadDone.UploadDoneIncomingRequest)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
support.getHuaweiEphemerisManager().handleFileDoneRequest(((EphemerisFileUpload.UploadDone.UploadDoneIncomingRequest) response).uploadResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleCameraRemote(HuaweiPacket response) {
|
private void handleCameraRemote(HuaweiPacket response) {
|
||||||
if (response.serviceId == CameraRemote.id && response.commandId == CameraRemote.CameraRemoteStatus.id) {
|
if (response.serviceId == CameraRemote.id && response.commandId == CameraRemote.CameraRemoteStatus.id) {
|
||||||
if (!(response instanceof CameraRemote.CameraRemoteStatus.Response)) {
|
if (!(response instanceof CameraRemote.CameraRemoteStatus.Response)) {
|
||||||
|
@ -0,0 +1,563 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei;
|
||||||
|
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipException;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendEphemerisDataRequestResponse;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendEphemerisFileConsultResponse;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendEphemerisFileListResponse;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendEphemerisFileStatusRequest;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendEphemerisFileUploadChunk;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendEphemerisFileUploadDoneResponse;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendEphemerisOperatorResponse;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendEphemerisParameterConsultRequest;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendEphemerisSingleFileInfoResponse;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.CryptoUtils;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||||
|
|
||||||
|
public class HuaweiEphemerisManager {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(HuaweiEphemerisManager.class);
|
||||||
|
|
||||||
|
public static class UploadParameters {
|
||||||
|
//upload file related data
|
||||||
|
private final String protocolVersion;
|
||||||
|
private final byte bitmapEnable;
|
||||||
|
private final short transferSize;
|
||||||
|
private final int maxDataSize;
|
||||||
|
private final short timeOut;
|
||||||
|
private final byte fileType;
|
||||||
|
|
||||||
|
public UploadParameters(String protocolVersion, byte bitmapEnable, short transferSize, int maxDataSize, short timeOut, byte fileType) {
|
||||||
|
this.protocolVersion = protocolVersion;
|
||||||
|
this.bitmapEnable = bitmapEnable;
|
||||||
|
this.transferSize = transferSize;
|
||||||
|
this.maxDataSize = maxDataSize;
|
||||||
|
this.timeOut = timeOut;
|
||||||
|
this.fileType = fileType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProtocolVersion() {
|
||||||
|
return protocolVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getBitmapEnable() {
|
||||||
|
return bitmapEnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getTransferSize() {
|
||||||
|
return transferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxDataSize() {
|
||||||
|
return maxDataSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getTimeOut() {
|
||||||
|
return timeOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getFileType() {
|
||||||
|
return fileType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RequestInfo {
|
||||||
|
private int tagVersion = -1;
|
||||||
|
private String tagUUID = null;
|
||||||
|
private List<String> tagFiles = null;
|
||||||
|
|
||||||
|
private byte[] currentFileData = null;
|
||||||
|
private String currentFileName = null;
|
||||||
|
|
||||||
|
UploadParameters uploadParameters = null;
|
||||||
|
|
||||||
|
private List<String> processedFiles = new ArrayList<>();
|
||||||
|
|
||||||
|
public RequestInfo(int tagVersion, String tagUUID, List<String> tagFiles) {
|
||||||
|
this.tagVersion = tagVersion;
|
||||||
|
this.tagUUID = tagUUID;
|
||||||
|
this.tagFiles = tagFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTagVersion() {
|
||||||
|
return tagVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTagUUID() {
|
||||||
|
return tagUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getTagFiles() {
|
||||||
|
return tagFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getCurrentFileData() {
|
||||||
|
return currentFileData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrentFileName() {
|
||||||
|
return currentFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UploadParameters getUploadParameters() {
|
||||||
|
return uploadParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentFileData(byte[] currentFileData) {
|
||||||
|
this.currentFileData = currentFileData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentFileName(String currentFileName) {
|
||||||
|
this.currentFileName = currentFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUploadParameters(UploadParameters uploadParameters) {
|
||||||
|
this.uploadParameters = uploadParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addProcessedFile(String name) {
|
||||||
|
processedFiles.add(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAllProcessed() {
|
||||||
|
LOG.info("Ephemeris tagFiles: {}", tagFiles.toString());
|
||||||
|
LOG.info("Ephemeris processed: {}", processedFiles.toString());
|
||||||
|
return processedFiles.size() == tagFiles.size() && new HashSet<>(processedFiles).containsAll(tagFiles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final HuaweiSupportProvider support;
|
||||||
|
|
||||||
|
|
||||||
|
private JsonObject availableDataConfig = null;
|
||||||
|
|
||||||
|
|
||||||
|
private RequestInfo currentRequest = null;
|
||||||
|
|
||||||
|
|
||||||
|
public HuaweiEphemerisManager(HuaweiSupportProvider support) {
|
||||||
|
this.support = support;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getZIPFileContent(File file, String name) {
|
||||||
|
byte[] ret = null;
|
||||||
|
try {
|
||||||
|
ZipFile zipFile = new ZipFile(file);
|
||||||
|
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipEntry entry = entries.nextElement();
|
||||||
|
if (entry.getName().equals(name)) {
|
||||||
|
InputStream inputStream = zipFile.getInputStream(entry);
|
||||||
|
ret = new byte[inputStream.available()];
|
||||||
|
inputStream.read(ret);
|
||||||
|
inputStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zipFile.close();
|
||||||
|
} catch (ZipException e) {
|
||||||
|
LOG.error("zip exception", e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("zip IO exception", e);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkZIPFileExists(File file, String name) {
|
||||||
|
try {
|
||||||
|
ZipFile zipFile = new ZipFile(file);
|
||||||
|
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipEntry entry = entries.nextElement();
|
||||||
|
if (!entry.isDirectory() && entry.getName().equals(name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zipFile.close();
|
||||||
|
} catch (ZipException e) {
|
||||||
|
LOG.error("zip exception", e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("zip IO exception", e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleOperatorRequest(byte operationInfo, int operationTime) {
|
||||||
|
//TODO:
|
||||||
|
// 100007 - no network connection
|
||||||
|
if (operationInfo == 1) {
|
||||||
|
// NOTE: clear data on new request
|
||||||
|
currentRequest = null;
|
||||||
|
|
||||||
|
int responseCode = 100000;
|
||||||
|
try {
|
||||||
|
File filesDir = support.getContext().getExternalFilesDir(null);
|
||||||
|
File file = new File(filesDir, "ephemeris.zip");
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new Exception("Ephemeris file does not exists");
|
||||||
|
}
|
||||||
|
byte[] time = getZIPFileContent(file, "time");
|
||||||
|
byte[] config = getZIPFileContent(file, "ephemeris_config.json");
|
||||||
|
|
||||||
|
if (time == null || config == null) {
|
||||||
|
throw new Exception("Ephemeris no time or config in file");
|
||||||
|
}
|
||||||
|
|
||||||
|
long fileTime = Long.parseLong(new String(time));
|
||||||
|
if (fileTime < (System.currentTimeMillis() - (7200 * 1000))) { // 2 hours. Maybe should be decreased.
|
||||||
|
throw new Exception("Ephemeris file old");
|
||||||
|
}
|
||||||
|
|
||||||
|
availableDataConfig = JsonParser.parseString(new String(config)).getAsJsonObject();
|
||||||
|
|
||||||
|
LOG.info("Ephemeris Time: {} ConfigData: {}", fileTime, availableDataConfig.toString());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Ephemeris exception file or config processing", e);
|
||||||
|
availableDataConfig = null;
|
||||||
|
//responseCode = 100007; //no network connection
|
||||||
|
return; // NOTE: just ignore request if something wrong with data.
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
SendEphemerisOperatorResponse sendEphemerisOperatorResponse = new SendEphemerisOperatorResponse(this.support, responseCode);
|
||||||
|
sendEphemerisOperatorResponse.doPerform();
|
||||||
|
|
||||||
|
if (responseCode == 100000) {
|
||||||
|
SendEphemerisParameterConsultRequest sendEphemerisParameterConsultRequest = new SendEphemerisParameterConsultRequest(this.support);
|
||||||
|
sendEphemerisParameterConsultRequest.doPerform();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("Error send Ephemeris data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: operation code == 2 send file download progress
|
||||||
|
// Currently we do not need this code because everything is downloaded already. Maybe needed in the future
|
||||||
|
// 0x2: 02
|
||||||
|
// 0x3: operationTime
|
||||||
|
// 0x4: from 01 to 06 status
|
||||||
|
// in the container 0x81
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleParameterConsultResponse(int consultDeviceTime, byte downloadVersion, String downloadTag) {
|
||||||
|
LOG.info("consultDeviceTime: {}, downloadVersion: {}, downloadTag: {}", consultDeviceTime, downloadVersion, downloadTag);
|
||||||
|
byte status = 0x3; // ready to download
|
||||||
|
|
||||||
|
try {
|
||||||
|
File filesDir = support.getContext().getExternalFilesDir(null);
|
||||||
|
File file = new File(filesDir, "ephemeris.zip");
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new Exception("Ephemeris file does not exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (availableDataConfig == null) {
|
||||||
|
throw new Exception("Ephemeris no config data");
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject conf = availableDataConfig.getAsJsonObject(downloadTag);
|
||||||
|
|
||||||
|
int version = conf.get("ver").getAsInt();
|
||||||
|
if(version != downloadVersion) {
|
||||||
|
throw new Exception("Ephemeris version mismatch");
|
||||||
|
}
|
||||||
|
String uuid = conf.get("uuid").getAsString();
|
||||||
|
|
||||||
|
if(uuid.isEmpty())
|
||||||
|
throw new Exception("Ephemeris uuid is empty");
|
||||||
|
|
||||||
|
JsonArray filesJs = conf.get("files").getAsJsonArray();
|
||||||
|
|
||||||
|
List<String> files = new ArrayList<>();
|
||||||
|
for (int i = 0; i < filesJs.size(); i++) {
|
||||||
|
files.add(filesJs.get(i).getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(files.isEmpty())
|
||||||
|
throw new Exception("Ephemeris file list is empty");
|
||||||
|
|
||||||
|
for(String fl: files) {
|
||||||
|
if(!checkZIPFileExists(file, uuid + File.separator + fl)) {
|
||||||
|
throw new Exception("Ephemeris file does not exist in ZIP");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRequest = new RequestInfo(downloadVersion, uuid, files);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Ephemeris exception file or config processing", e);
|
||||||
|
availableDataConfig = null;
|
||||||
|
status = 0x5; //error or timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
SendEphemerisFileStatusRequest sendEphemerisFileStatusRequest = new SendEphemerisFileStatusRequest(this.support, status);
|
||||||
|
sendEphemerisFileStatusRequest.doPerform();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("Error to send SendEphemerisFileStatusRequest");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//File transfer related
|
||||||
|
public void handleFileSendRequest(byte fileType, String productId) {
|
||||||
|
if(currentRequest == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String fileList = "";
|
||||||
|
int responseCode = 0;
|
||||||
|
|
||||||
|
if(fileType == 0) {
|
||||||
|
//TODO: find all files that name contain productId and send
|
||||||
|
LOG.error("Currently not supported. File type: 0");
|
||||||
|
} else if(fileType == 1){
|
||||||
|
if(currentRequest.getTagVersion() == 0) {
|
||||||
|
//TODO: implement this type
|
||||||
|
//fileList = "gpslocation.dat";
|
||||||
|
LOG.error("Currently not supported. File type 1. Tag version 0");
|
||||||
|
} else if (currentRequest.getTagVersion() == 1 || currentRequest.getTagVersion() == 2 || currentRequest.getTagVersion() == 3){
|
||||||
|
int i = 0;
|
||||||
|
while (i < currentRequest.getTagFiles().size()) {
|
||||||
|
fileList += currentRequest.getTagFiles().get(i);
|
||||||
|
if (i == currentRequest.getTagFiles().size() - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fileList += ";";
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG.error("Unknown version");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG.error("Unknown file id");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(TextUtils.isEmpty(fileList)) {
|
||||||
|
responseCode = 100001;
|
||||||
|
cleanupUpload(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
SendEphemerisFileListResponse sendEphemerisFileListResponse = new SendEphemerisFileListResponse(this.support, responseCode, fileList);
|
||||||
|
sendEphemerisFileListResponse.doPerform();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("Error to send SendEphemerisFileListResponse");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleFileConsultIncomingRequest(int responseCode, String protocolVersion, byte bitmapEnable, short transferSize, int maxDataSize, short timeOut, byte fileType) {
|
||||||
|
if(currentRequest == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseCode != 0) {
|
||||||
|
LOG.error("Error on handleFileConsultIncomingRequest: {}", responseCode);
|
||||||
|
cleanupUpload(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transferSize == 0) {
|
||||||
|
LOG.error("transfer size is 0");
|
||||||
|
cleanupUpload(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRequest.setUploadParameters(new UploadParameters(protocolVersion, bitmapEnable, transferSize, maxDataSize, timeOut, fileType));
|
||||||
|
|
||||||
|
if((!TextUtils.isEmpty(protocolVersion) && fileType == 0) || fileType == 1) {
|
||||||
|
try {
|
||||||
|
SendEphemerisFileConsultResponse sendEphemerisFileConsultResponse = new SendEphemerisFileConsultResponse(this.support, 100000);
|
||||||
|
sendEphemerisFileConsultResponse.doPerform();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("Error to send SendEphemerisFileConsultResponse");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// I don't know how to properly process error in this case. Just cleanup.
|
||||||
|
cleanupUpload(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleSingleFileIncomingRequest(String filename) {
|
||||||
|
if(currentRequest == null || currentRequest.getUploadParameters() == null) {
|
||||||
|
cleanupUpload(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(TextUtils.isEmpty(filename) || !currentRequest.getTagFiles().contains(filename)) {
|
||||||
|
cleanupUpload(true);
|
||||||
|
try {
|
||||||
|
SendEphemerisSingleFileInfoResponse sendEphemerisSingleFileInfoResponse = new SendEphemerisSingleFileInfoResponse(this.support, 100001, 0, (short) 0);
|
||||||
|
sendEphemerisSingleFileInfoResponse.doPerform();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("Error to send sendEphemerisSingleFileInfoResponse");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRequest.addProcessedFile(filename);
|
||||||
|
|
||||||
|
int responseCode = 0;
|
||||||
|
try {
|
||||||
|
|
||||||
|
File filesDir = support.getContext().getExternalFilesDir(null);
|
||||||
|
File file = new File(filesDir, "ephemeris.zip");
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new Exception("Ephemeris handleSingleFileIncomingRequest file does not exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] currentFileData = getZIPFileContent(file, currentRequest.getTagUUID() + File.separator + filename);
|
||||||
|
if (currentFileData == null || currentFileData.length == 0) {
|
||||||
|
throw new Exception("Ephemeris handleSingleFileIncomingRequest file is empty");
|
||||||
|
}
|
||||||
|
currentRequest.setCurrentFileData(currentFileData);
|
||||||
|
currentRequest.setCurrentFileName(filename);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Ephemeris exception handleSingleFileIncomingRequest processing", e);
|
||||||
|
cleanupUpload(true);
|
||||||
|
responseCode = 100001;
|
||||||
|
}
|
||||||
|
|
||||||
|
short crc = 0;
|
||||||
|
if(currentRequest.getUploadParameters().getFileType() == 0) {
|
||||||
|
//TODO: implement this type
|
||||||
|
responseCode = 100001;
|
||||||
|
} else if(currentRequest.getUploadParameters().getFileType() == 1) {
|
||||||
|
crc = (short)CheckSums.getCRC16(currentRequest.getCurrentFileData(), 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = 0;
|
||||||
|
if(currentRequest.getCurrentFileData() == null || crc == 0) {
|
||||||
|
responseCode = 100001;
|
||||||
|
} else {
|
||||||
|
size = currentRequest.getCurrentFileData().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
SendEphemerisSingleFileInfoResponse sendEphemerisSingleFileInfoResponse = new SendEphemerisSingleFileInfoResponse(this.support, responseCode, size, crc);
|
||||||
|
sendEphemerisSingleFileInfoResponse.doPerform();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("Error to send SendEphemerisSingleFileInfoResponse");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getHexDigest(String str) {
|
||||||
|
if (TextUtils.isEmpty(str)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (str.contains(":")) {
|
||||||
|
str = str.replace(":", "");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
byte[] data = CryptoUtils.digest(str.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return StringUtils.bytesToHex(data);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
LOG.error("EncryptUtil getEncryption :{} ", e.getMessage());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleDataRequestIncomingRequest(int responseCode, String fileName, int offset, int len, byte bitmap) {
|
||||||
|
if(currentRequest == null || currentRequest.getUploadParameters() == null) {
|
||||||
|
cleanupUpload(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(offset == -1 || fileName == null || fileName.isEmpty()) {
|
||||||
|
cleanupUpload(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!currentRequest.getCurrentFileName().equals(fileName)) {
|
||||||
|
cleanupUpload(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int localResponseCode = 100000;
|
||||||
|
|
||||||
|
String localFilename = "";
|
||||||
|
|
||||||
|
if(currentRequest.getUploadParameters().getFileType() == 0) {
|
||||||
|
//TODO: implement this type
|
||||||
|
localResponseCode = 100001;
|
||||||
|
} else if(currentRequest.getUploadParameters().getFileType() == 1) {
|
||||||
|
localFilename = getHexDigest(support.deviceMac) + fileName;
|
||||||
|
} else {
|
||||||
|
LOG.error("Unsupported type: {}", currentRequest.getUploadParameters().getFileType());
|
||||||
|
localResponseCode = 100001;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
SendEphemerisDataRequestResponse sendEphemerisDataRequestResponse = new SendEphemerisDataRequestResponse(this.support, localResponseCode, localFilename, offset);
|
||||||
|
sendEphemerisDataRequestResponse.doPerform();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("Error to send SendEphemerisDataRequestResponse");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(localResponseCode == 100000) {
|
||||||
|
int dataSize = Math.min(currentRequest.getCurrentFileData().length - offset,currentRequest.getUploadParameters().getMaxDataSize());
|
||||||
|
int packetsCount = (int) Math.ceil((double) dataSize / currentRequest.getUploadParameters().getTransferSize());
|
||||||
|
byte[] chunk = new byte[dataSize];
|
||||||
|
System.arraycopy(currentRequest.getCurrentFileData(), offset, chunk, 0, dataSize);
|
||||||
|
|
||||||
|
try {
|
||||||
|
SendEphemerisFileUploadChunk sendEphemerisFileUploadChunk = new SendEphemerisFileUploadChunk(this.support, chunk, currentRequest.getUploadParameters().getTransferSize(), packetsCount);
|
||||||
|
sendEphemerisFileUploadChunk.doPerform();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("Error to send SendEphemerisFileUploadChunk");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleFileUploadResponse(int responseCode) {
|
||||||
|
LOG.info("handleFileUploadResponse {}", responseCode);
|
||||||
|
if(responseCode != 100000) {
|
||||||
|
cleanupUpload(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleFileDoneRequest(byte uploadResult) {
|
||||||
|
LOG.info("handleFileDoneRequest");
|
||||||
|
cleanupUpload(false);
|
||||||
|
try {
|
||||||
|
SendEphemerisFileUploadDoneResponse sendEphemerisFileUploadDoneResponse = new SendEphemerisFileUploadDoneResponse(this.support, 100000);
|
||||||
|
sendEphemerisFileUploadDoneResponse.doPerform();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("Error to send SendEphemerisFileUploadDoneResponse");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanupUpload(boolean force) {
|
||||||
|
if(currentRequest != null) {
|
||||||
|
currentRequest.setCurrentFileName(null);
|
||||||
|
currentRequest.setCurrentFileData(null);
|
||||||
|
currentRequest.setUploadParameters(null);
|
||||||
|
boolean isAllProcessed = currentRequest.isAllProcessed();
|
||||||
|
LOG.info("Ephemeris is Done: {}", isAllProcessed);
|
||||||
|
if(isAllProcessed || force) {
|
||||||
|
currentRequest = null;
|
||||||
|
LOG.info("Ephemeris All files uploaded. {} Cleanup...", force?"Force":"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -265,6 +265,8 @@ public class HuaweiSupportProvider {
|
|||||||
|
|
||||||
protected HuaweiWeatherManager huaweiWeatherManager = new HuaweiWeatherManager(this);
|
protected HuaweiWeatherManager huaweiWeatherManager = new HuaweiWeatherManager(this);
|
||||||
|
|
||||||
|
protected HuaweiEphemerisManager huaweiEphemerisManager = new HuaweiEphemerisManager(this);
|
||||||
|
|
||||||
//TODO: we need only one instance of manager and all it services.
|
//TODO: we need only one instance of manager and all it services.
|
||||||
protected HuaweiP2PManager huaweiP2PManager = new HuaweiP2PManager(this);
|
protected HuaweiP2PManager huaweiP2PManager = new HuaweiP2PManager(this);
|
||||||
|
|
||||||
@ -292,6 +294,10 @@ public class HuaweiSupportProvider {
|
|||||||
return huaweiP2PManager;
|
return huaweiP2PManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HuaweiEphemerisManager getHuaweiEphemerisManager() {
|
||||||
|
return huaweiEphemerisManager;
|
||||||
|
}
|
||||||
|
|
||||||
public HuaweiSupportProvider(HuaweiBRSupport support) {
|
public HuaweiSupportProvider(HuaweiBRSupport support) {
|
||||||
this.brSupport = support;
|
this.brSupport = support;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.EphemerisFileUpload;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||||
|
|
||||||
|
public class SendEphemerisDataRequestResponse extends Request {
|
||||||
|
final int responseCode;
|
||||||
|
final String fileName;
|
||||||
|
final int offset;
|
||||||
|
|
||||||
|
|
||||||
|
public SendEphemerisDataRequestResponse(HuaweiSupportProvider support, int responseCode, String fileName, int offset) {
|
||||||
|
super(support);
|
||||||
|
this.serviceId = EphemerisFileUpload.id;
|
||||||
|
this.commandId = EphemerisFileUpload.FileList.id;
|
||||||
|
this.responseCode = responseCode;
|
||||||
|
this.fileName = fileName;
|
||||||
|
this.offset = offset;
|
||||||
|
this.addToResponse = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<byte[]> createRequest() throws Request.RequestCreationException {
|
||||||
|
try {
|
||||||
|
return new EphemerisFileUpload.DataRequest.DataRequestResponse(this.paramsProvider, this.responseCode, this.fileName, this.offset).serialize();
|
||||||
|
} catch (HuaweiPacket.CryptoException e) {
|
||||||
|
throw new Request.RequestCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.EphemerisFileUpload;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||||
|
|
||||||
|
public class SendEphemerisFileConsultResponse extends Request {
|
||||||
|
final int responseCode;
|
||||||
|
|
||||||
|
public SendEphemerisFileConsultResponse(HuaweiSupportProvider support, int responseCode) {
|
||||||
|
super(support);
|
||||||
|
this.serviceId = EphemerisFileUpload.id;
|
||||||
|
this.commandId = EphemerisFileUpload.FileConsult.id;
|
||||||
|
this.responseCode = responseCode;
|
||||||
|
this.addToResponse = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||||
|
try {
|
||||||
|
return new EphemerisFileUpload.FileConsult.FileConsultResponse(this.paramsProvider, this.responseCode).serialize();
|
||||||
|
} catch (HuaweiPacket.CryptoException e) {
|
||||||
|
throw new RequestCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.EphemerisFileUpload;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||||
|
|
||||||
|
public class SendEphemerisFileListResponse extends Request {
|
||||||
|
final int responseCode;
|
||||||
|
final String files;
|
||||||
|
|
||||||
|
public SendEphemerisFileListResponse(HuaweiSupportProvider support, int responseCode, String files) {
|
||||||
|
super(support);
|
||||||
|
this.serviceId = EphemerisFileUpload.id;
|
||||||
|
this.commandId = EphemerisFileUpload.FileList.id;
|
||||||
|
this.responseCode = responseCode;
|
||||||
|
this.files = files;
|
||||||
|
this.addToResponse = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||||
|
try {
|
||||||
|
return new EphemerisFileUpload.FileList.FileListResponse(this.paramsProvider, this.responseCode, this.files).serialize();
|
||||||
|
} catch (HuaweiPacket.CryptoException e) {
|
||||||
|
throw new RequestCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Ephemeris;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||||
|
|
||||||
|
public class SendEphemerisFileStatusRequest extends Request {
|
||||||
|
private final Logger LOG = LoggerFactory.getLogger(SendEphemerisFileStatusRequest.class);
|
||||||
|
|
||||||
|
private final byte status;
|
||||||
|
public SendEphemerisFileStatusRequest(HuaweiSupportProvider support, byte status) {
|
||||||
|
super(support);
|
||||||
|
this.serviceId = Ephemeris.id;
|
||||||
|
this.commandId = Ephemeris.FileStatus.id;
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<byte[]> createRequest() throws Request.RequestCreationException {
|
||||||
|
try {
|
||||||
|
return new Ephemeris.FileStatus.Request(this.paramsProvider, status).serialize();
|
||||||
|
} catch (HuaweiPacket.CryptoException e) {
|
||||||
|
throw new Request.RequestCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processResponse() throws ResponseParseException {
|
||||||
|
if (!(receivedPacket instanceof Ephemeris.FileStatus.Response))
|
||||||
|
throw new ResponseTypeMismatchException(receivedPacket, Ephemeris.FileStatus.Response.class);
|
||||||
|
LOG.info("Ephemeris FileStatus Response code: {}", ((Ephemeris.FileStatus.Response) receivedPacket).responseCode);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.EphemerisFileUpload;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||||
|
|
||||||
|
|
||||||
|
public class SendEphemerisFileUploadChunk extends Request {
|
||||||
|
byte[] fileChunk;
|
||||||
|
short transferSize;
|
||||||
|
int packetCount;
|
||||||
|
public SendEphemerisFileUploadChunk(HuaweiSupportProvider support, byte[] fileChunk, short transferSize, int packetCount) {
|
||||||
|
super(support);
|
||||||
|
this.serviceId = EphemerisFileUpload.id;
|
||||||
|
this.commandId = EphemerisFileUpload.UploadData.id;
|
||||||
|
this.fileChunk = fileChunk;
|
||||||
|
this.transferSize = transferSize;
|
||||||
|
this.packetCount = packetCount;
|
||||||
|
this.addToResponse = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||||
|
try {
|
||||||
|
return new EphemerisFileUpload.UploadData.FileNextChunkSend(this.paramsProvider).serializeFileChunk1c(
|
||||||
|
fileChunk,
|
||||||
|
transferSize,
|
||||||
|
packetCount
|
||||||
|
);
|
||||||
|
} catch(HuaweiPacket.SerializeException e) {
|
||||||
|
throw new RequestCreationException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.EphemerisFileUpload;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||||
|
|
||||||
|
public class SendEphemerisFileUploadDoneResponse extends Request {
|
||||||
|
final int responseCode;
|
||||||
|
|
||||||
|
public SendEphemerisFileUploadDoneResponse(HuaweiSupportProvider support, int responseCode) {
|
||||||
|
super(support);
|
||||||
|
this.serviceId = EphemerisFileUpload.id;
|
||||||
|
this.commandId = EphemerisFileUpload.UploadDone.id;
|
||||||
|
this.responseCode = responseCode;
|
||||||
|
this.addToResponse = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||||
|
try {
|
||||||
|
return new EphemerisFileUpload.UploadDone.UploadDoneResponse(this.paramsProvider, this.responseCode).serialize();
|
||||||
|
} catch (HuaweiPacket.CryptoException e) {
|
||||||
|
throw new RequestCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Ephemeris;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||||
|
|
||||||
|
public class SendEphemerisOperatorResponse extends Request {
|
||||||
|
final int responseCode;
|
||||||
|
public SendEphemerisOperatorResponse(HuaweiSupportProvider support, int responseCode) {
|
||||||
|
super(support);
|
||||||
|
this.serviceId = Ephemeris.id;
|
||||||
|
this.commandId = Ephemeris.OperatorData.id;
|
||||||
|
this.responseCode = responseCode;
|
||||||
|
this.addToResponse = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||||
|
try {
|
||||||
|
return new Ephemeris.OperatorData.OperatorResponse(this.paramsProvider, this.responseCode).serialize();
|
||||||
|
} catch (HuaweiPacket.CryptoException e) {
|
||||||
|
throw new RequestCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Ephemeris;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||||
|
|
||||||
|
public class SendEphemerisParameterConsultRequest extends Request {
|
||||||
|
private Logger LOG = LoggerFactory.getLogger(SendEphemerisParameterConsultRequest.class);
|
||||||
|
|
||||||
|
public SendEphemerisParameterConsultRequest(HuaweiSupportProvider support) {
|
||||||
|
super(support);
|
||||||
|
this.serviceId = Ephemeris.id;
|
||||||
|
this.commandId = Ephemeris.ParameterConsult.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<byte[]> createRequest() throws Request.RequestCreationException {
|
||||||
|
try {
|
||||||
|
return new Ephemeris.ParameterConsult.Request(this.paramsProvider).serialize();
|
||||||
|
} catch (HuaweiPacket.CryptoException e) {
|
||||||
|
throw new Request.RequestCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processResponse() throws ResponseParseException {
|
||||||
|
if (!(receivedPacket instanceof Ephemeris.ParameterConsult.Response))
|
||||||
|
throw new ResponseTypeMismatchException(receivedPacket, Ephemeris.ParameterConsult.Response.class);
|
||||||
|
|
||||||
|
Ephemeris.ParameterConsult.Response resp = (Ephemeris.ParameterConsult.Response)receivedPacket;
|
||||||
|
supportProvider.getHuaweiEphemerisManager().handleParameterConsultResponse(resp.consultDeviceTime, resp.downloadVersion, resp.downloadTag);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.EphemerisFileUpload;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||||
|
|
||||||
|
public class SendEphemerisSingleFileInfoResponse extends Request {
|
||||||
|
final int responseCode;
|
||||||
|
final int fileSize;
|
||||||
|
final short crc;
|
||||||
|
|
||||||
|
public SendEphemerisSingleFileInfoResponse(HuaweiSupportProvider support, int responseCode, int fileSize, short crc) {
|
||||||
|
super(support);
|
||||||
|
this.serviceId = EphemerisFileUpload.id;
|
||||||
|
this.commandId = EphemerisFileUpload.FileList.id;
|
||||||
|
this.responseCode = responseCode;
|
||||||
|
this.fileSize = fileSize;
|
||||||
|
this.crc = crc;
|
||||||
|
this.addToResponse = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<byte[]> createRequest() throws Request.RequestCreationException {
|
||||||
|
try {
|
||||||
|
return new EphemerisFileUpload.QuerySingleFileInfo.QuerySingleFileInfoResponse(this.paramsProvider, this.responseCode, this.fileSize, this.crc).serialize();
|
||||||
|
} catch (HuaweiPacket.CryptoException e) {
|
||||||
|
throw new Request.RequestCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user