Huawei: Initial ephemeris update support

This commit is contained in:
Me7c7 2024-10-05 16:23:39 +03:00 committed by José Rebelo
parent 5272d017ac
commit cf7fa3adde
15 changed files with 1431 additions and 48 deletions

View File

@ -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.CameraRemote;
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.FileDownloadService2C;
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.Notifications;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileUpload;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Ephemeris;
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
public class HuaweiPacket {
@ -664,6 +666,36 @@ public class HuaweiPacket {
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
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:
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
return this;
@ -864,6 +896,63 @@ public class HuaweiPacket {
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 {
// TODO: necessary for this to work:
// - serviceId

View File

@ -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);
}
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -32,7 +32,6 @@ import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
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.deviceevents.GBDeviceEventCallControl;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCameraRemote;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventDisplayMessage;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
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.CameraRemote;
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.GpsAndTime;
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.Watchface;
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.GetPhoneInfoRequest;
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.SendWatchfaceConfirm;
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.util.GB;
/**
* Handles responses that are not a reply to a request
*
*/
public class AsynchronousResponse {
private static final Logger LOG = LoggerFactory.getLogger(AsynchronousResponse.class);
@ -84,6 +81,7 @@ public class AsynchronousResponse {
private final HuaweiSupportProvider support;
private final Handler mFindPhoneHandler = new Handler();
private final static HashMap<Integer, String> dayOfWeekMap = new HashMap<>();
static {
dayOfWeekMap.put(Calendar.MONDAY, DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_MO);
dayOfWeekMap.put(Calendar.TUESDAY, DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_TU);
@ -123,6 +121,8 @@ public class AsynchronousResponse {
handleCameraRemote(response);
handleApp(response);
handleP2p(response);
handleEphemeris(response);
handleEphemerisUploadService(response);
} catch (Request.ResponseParseException e) {
LOG.error("Response parse exception", e);
}
@ -226,13 +226,14 @@ public class AsynchronousResponse {
/**
* Handles asynchronous music packet, for the following events:
* - The app is opened on the band (sends back music info)
* - A button is clicked
* - Play
* - Pause
* - Previous
* - Next
* - The volume is adjusted
* - The app is opened on the band (sends back music info)
* - A button is clicked
* - Play
* - Pause
* - Previous
* - Next
* - The volume is adjusted
*
* @param response Packet to be handled
*/
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.commandId == FileUpload.FileInfoSend.id) {
if (!(response instanceof FileUpload.FileInfoSend.Response))
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");
} else {
FileUpload.FileInfoSend.Response resp = (FileUpload.FileInfoSend.Response) response;
@ -440,24 +441,24 @@ public class AsynchronousResponse {
}
}
} else if (response.commandId == FileUpload.FileHashSend.id) {
if (!(response instanceof FileUpload.FileHashSend.Response))
throw new Request.ResponseTypeMismatchException(response, FileUpload.FileHashSend.Response.class);
if(support.huaweiUploadManager.getFileUploadInfo() == null) {
LOG.error("Upload file hash requested but no file to upload");
} else {
FileUpload.FileHashSend.Response resp = (FileUpload.FileHashSend.Response) response;
support.huaweiUploadManager.getFileUploadInfo().setFileId(resp.fileId);
try {
SendFileUploadHash sendFileUploadHash = new SendFileUploadHash(support, support.huaweiUploadManager);
sendFileUploadHash.doPerform();
} catch (IOException e) {
LOG.error("Could not send file upload hash request", e);
}
}
} else if (response.commandId == FileUpload.FileUploadConsultAck.id) {
if (!(response instanceof FileUpload.FileUploadConsultAck.Response))
if (!(response instanceof FileUpload.FileHashSend.Response))
throw new Request.ResponseTypeMismatchException(response, FileUpload.FileHashSend.Response.class);
if (support.huaweiUploadManager.getFileUploadInfo() == null) {
LOG.error("Upload file hash requested but no file to upload");
} else {
FileUpload.FileHashSend.Response resp = (FileUpload.FileHashSend.Response) response;
support.huaweiUploadManager.getFileUploadInfo().setFileId(resp.fileId);
try {
SendFileUploadHash sendFileUploadHash = new SendFileUploadHash(support, support.huaweiUploadManager);
sendFileUploadHash.doPerform();
} catch (IOException e) {
LOG.error("Could not send file upload hash request", e);
}
}
} else if (response.commandId == FileUpload.FileUploadConsultAck.id) {
if (!(response instanceof FileUpload.FileUploadConsultAck.Response))
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");
} else {
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);
}
}
} else if (response.commandId == FileUpload.FileNextChunkParams.id) {
if (!(response instanceof FileUpload.FileNextChunkParams))
throw new Request.ResponseTypeMismatchException(response, FileUpload.FileNextChunkParams.class);
if(support.huaweiUploadManager.getFileUploadInfo() == null) {
} else if (response.commandId == FileUpload.FileNextChunkParams.id) {
if (!(response instanceof FileUpload.FileNextChunkParams))
throw new Request.ResponseTypeMismatchException(response, FileUpload.FileNextChunkParams.class);
if (support.huaweiUploadManager.getFileUploadInfo() == null) {
LOG.error("Upload file next chunk requested but no file to upload");
} else {
FileUpload.FileNextChunkParams resp = (FileUpload.FileNextChunkParams) response;
@ -493,8 +494,8 @@ public class AsynchronousResponse {
LOG.error("Could not send fileupload next chunk request", e);
}
}
} else if (response.commandId == FileUpload.FileUploadResult.id) {
if(support.huaweiUploadManager.getFileUploadInfo() == null) {
} else if (response.commandId == FileUpload.FileUploadResult.id) {
if (support.huaweiUploadManager.getFileUploadInfo() == null) {
LOG.error("Upload file result requested but no file to upload");
} else {
try {
@ -510,7 +511,7 @@ public class AsynchronousResponse {
LOG.error("Could not send file upload result request", e);
}
}
}
}
}
}
@ -541,7 +542,7 @@ public class AsynchronousResponse {
if (response.commandId == 0x2) {
try {
byte status = response.getTlv().getByte(0x1);
if(status == (byte)0x66 || status == (byte)0x69) {
if (status == (byte) 0x66 || status == (byte) 0x69) {
this.support.getHuaweiAppManager().requestAppList();
}
} catch (HuaweiPacket.MissingTagException e) {
@ -553,15 +554,15 @@ public class AsynchronousResponse {
}
private void handleP2p(HuaweiPacket response) throws Request.ResponseParseException {
if (response.serviceId == P2P.id && response.commandId == P2P.P2PCommand.id) {
if (!(response instanceof P2P.P2PCommand.Response))
throw new Request.ResponseTypeMismatchException(response, P2P.P2PCommand.class);
try {
this.support.getHuaweiP2PManager().handlePacket((P2P.P2PCommand.Response) response);
} catch (Exception e) {
LOG.error("Error in P2P service", e);
}
}
if (response.serviceId == P2P.id && response.commandId == P2P.P2PCommand.id) {
if (!(response instanceof P2P.P2PCommand.Response))
throw new Request.ResponseTypeMismatchException(response, P2P.P2PCommand.class);
try {
this.support.getHuaweiP2PManager().handlePacket((P2P.P2PCommand.Response) response);
} catch (Exception e) {
LOG.error("Error in P2P service", e);
}
}
}
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) {
if (response.serviceId == CameraRemote.id && response.commandId == CameraRemote.CameraRemoteStatus.id) {
if (!(response instanceof CameraRemote.CameraRemoteStatus.Response)) {

View File

@ -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":"");
}
}
}
}

View File

@ -265,6 +265,8 @@ public class HuaweiSupportProvider {
protected HuaweiWeatherManager huaweiWeatherManager = new HuaweiWeatherManager(this);
protected HuaweiEphemerisManager huaweiEphemerisManager = new HuaweiEphemerisManager(this);
//TODO: we need only one instance of manager and all it services.
protected HuaweiP2PManager huaweiP2PManager = new HuaweiP2PManager(this);
@ -292,6 +294,10 @@ public class HuaweiSupportProvider {
return huaweiP2PManager;
}
public HuaweiEphemerisManager getHuaweiEphemerisManager() {
return huaweiEphemerisManager;
}
public HuaweiSupportProvider(HuaweiBRSupport support) {
this.brSupport = support;
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}