Huawei: watchface upload - SendWatchfaceInfo
* Added HuaweiWatchfaceManager to store current watchface info * implemented SendWatchfaceInfo request * added code to handle onInstallApp for BRCoordinator and LECoordinator
This commit is contained in:
parent
054e8e18ee
commit
8e71487092
|
@ -208,9 +208,11 @@ public abstract class HuaweiBRCoordinator extends AbstractBLClassicDeviceCoordin
|
|||
return huaweiCoordinator.supportsMusic();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public InstallHandler findInstallHandler(Uri uri, Context context) {
|
||||
return null;
|
||||
HuaweiInstallHandler handler = new HuaweiInstallHandler(uri, context);
|
||||
return handler.isValid() ? handler : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -5,24 +5,19 @@ import android.graphics.Bitmap;
|
|||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.InstallActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.ZipFileException;
|
||||
|
@ -40,14 +35,11 @@ public class HuaweiInstallHandler implements InstallHandler {
|
|||
|
||||
UriHelper uriHelper;
|
||||
|
||||
|
||||
|
||||
try {
|
||||
uriHelper = UriHelper.get(uri, this.context);
|
||||
|
||||
GBZipFile watchfacePackage = new GBZipFile(uriHelper.openInputStream());
|
||||
String watchfaceDescription = new String(watchfacePackage.getFileFromZip("description.xml"));
|
||||
watchfaceBin = watchfacePackage.getFileFromZip("com.huawei.watchface");
|
||||
final byte[] preview = watchfacePackage.getFileFromZip("preview/cover.jpg");
|
||||
previewbMap = BitmapFactory.decodeByteArray(preview, 0, preview.length);
|
||||
|
||||
|
@ -65,17 +57,6 @@ public class HuaweiInstallHandler implements InstallHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
MessageDigest m = MessageDigest.getInstance("SHA256");
|
||||
m.update(watchfaceBin, 0, watchfaceBin.length);
|
||||
watchfaceSHA256 = m.digest();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LOG.error("Digest alghoritm not found.", e);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.info("watchface loaded, SHA256: "+ GB.hexdump(watchfaceSHA256));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -97,7 +78,7 @@ public class HuaweiInstallHandler implements InstallHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
if (device.getType() != DeviceType.HUAWEIBAND7 || !device.isConnected()) { //FIXME: Add all tested huawei devices?
|
||||
if ( !device.isConnected()) { //FIXME: Add all tested huawei devices?
|
||||
LOG.error("Firmware cannot be installed (not connected or wrong device)");
|
||||
installActivity.setInfoText("Firmware cannot be installed (not connected or wrong device)");
|
||||
installActivity.setInstallEnabled(false);
|
||||
|
|
|
@ -213,7 +213,6 @@ public abstract class HuaweiLECoordinator extends AbstractBLEDeviceCoordinator i
|
|||
public InstallHandler findInstallHandler(Uri uri, Context context) {
|
||||
HuaweiInstallHandler handler = new HuaweiInstallHandler(uri, context);
|
||||
return handler.isValid() ? handler : null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV;
|
||||
|
||||
public class WatchfaceUpload {
|
||||
public static final byte id = 0x28;
|
||||
public static class WatchfaceStartSend {
|
||||
public static final byte id = 0x02;
|
||||
public static class Request extends HuaweiPacket {
|
||||
|
||||
public Request(ParamsProvider paramsProvider,
|
||||
int fileSize,
|
||||
String watchfaceName,
|
||||
String watchfaceVersion) {
|
||||
super(paramsProvider);
|
||||
this.serviceId = WatchfaceUpload.id;
|
||||
this.commandId = id;
|
||||
String filename = watchfaceName + "_" + watchfaceVersion;
|
||||
|
||||
this.tlv = new HuaweiTLV()
|
||||
.put(0x01, filename)
|
||||
.put(0x02, fileSize)
|
||||
.put(0x03, (byte) 0x1) // ???
|
||||
.put(0x05, watchfaceName)
|
||||
.put(0x06, watchfaceVersion);
|
||||
|
||||
this.complete = true;
|
||||
|
||||
}
|
||||
|
||||
public static class Response extends HuaweiPacket {
|
||||
public Response (ParamsProvider paramsProvider) {
|
||||
super(paramsProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class WatchfaceSendHash {
|
||||
public static final byte id = 0x03;
|
||||
|
||||
public static class Request extends HuaweiPacket {
|
||||
|
||||
public Request(ParamsProvider paramsProvider,
|
||||
byte[] hash) {
|
||||
super(paramsProvider);
|
||||
this.serviceId = WatchfaceUpload.id;
|
||||
this.commandId = id;
|
||||
|
||||
this.tlv = new HuaweiTLV()
|
||||
.put(0x01, (byte) 1) //???
|
||||
.put(0x03, hash);
|
||||
|
||||
this.complete = true;
|
||||
|
||||
}
|
||||
|
||||
public static class Response extends HuaweiPacket {
|
||||
public Response (ParamsProvider paramsProvider) {
|
||||
|
||||
super(paramsProvider);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -48,6 +48,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FindPhone;
|
|||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.GpsAndTime;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Menstrual;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.MusicControl;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.WatchfaceUpload;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.Request;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetPhoneInfoRequest;
|
||||
|
@ -100,6 +101,7 @@ public class AsynchronousResponse {
|
|||
handleMenstrualModifyTime(response);
|
||||
handleWeatherCheck(response);
|
||||
handleGpsRequest(response);
|
||||
handleWatchfaceHash(response);
|
||||
} catch (Request.ResponseParseException e) {
|
||||
LOG.error("Response parse exception", e);
|
||||
}
|
||||
|
@ -384,6 +386,12 @@ public class AsynchronousResponse {
|
|||
}
|
||||
}
|
||||
|
||||
private void handleWatchfaceHash(HuaweiPacket response) {
|
||||
if (response.serviceId == WatchfaceUpload.id && response.commandId == WatchfaceUpload.WatchfaceSendHash.id) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void handleWeatherCheck(HuaweiPacket response) {
|
||||
if (response.serviceId == Weather.id && response.commandId == 0x04) {
|
||||
// Send back ok
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei;
|
||||
|
||||
import android.location.Location;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -130,4 +131,9 @@ public class HuaweiBRSupport extends AbstractBTBRDeviceSupport {
|
|||
public void onSetGpsLocation(Location location) {
|
||||
supportProvider.onSetGpsLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInstallApp(Uri uri) {
|
||||
supportProvider.onInstallApp(uri);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei;
|
|||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.location.Location;
|
||||
import android.net.Uri;
|
||||
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -137,4 +139,9 @@ public class HuaweiLESupport extends AbstractBTLEDeviceSupport {
|
|||
public void onSetGpsLocation(Location location) {
|
||||
supportProvider.onSetGpsLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInstallApp(Uri uri) {
|
||||
supportProvider.onInstallApp(uri);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import android.bluetooth.BluetoothGattCharacteristic;
|
|||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.location.Location;
|
||||
import android.net.Uri;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -87,6 +88,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetS
|
|||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendExtendedAccountRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendGpsAndTimeToDeviceRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendGpsDataRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWatchfaceInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWeatherCurrentRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendNotifyHeartRateCapabilityRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendNotifyRestHeartRateCapabilityRequest;
|
||||
|
@ -178,6 +180,7 @@ public class HuaweiSupportProvider {
|
|||
private final HuaweiPacket.ParamsProvider paramsProvider = new HuaweiPacket.ParamsProvider();
|
||||
|
||||
protected ResponseManager responseManager = new ResponseManager(this);
|
||||
protected HuaweiWatchfaceManager huaweiWatchfaceManager = new HuaweiWatchfaceManager(this);
|
||||
|
||||
public HuaweiCoordinatorSupplier getCoordinator() {
|
||||
return ((HuaweiCoordinatorSupplier) this.gbDevice.getDeviceCoordinator());
|
||||
|
@ -1822,4 +1825,23 @@ public class HuaweiSupportProvider {
|
|||
LOG.error("Failed to send GPS data", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onInstallApp(Uri uri) {
|
||||
LOG.info("enter onAppInstall uri: "+uri);
|
||||
huaweiWatchfaceManager.setWatchfaceUri(uri);
|
||||
|
||||
SendWatchfaceInfo sendWatchfaceInfo = new SendWatchfaceInfo(this, huaweiWatchfaceManager);
|
||||
|
||||
|
||||
try {
|
||||
sendWatchfaceInfo.doPerform();
|
||||
} catch (IOException e) {
|
||||
GB.toast(context, "Failed to send watchface info", Toast.LENGTH_SHORT, GB.ERROR, e);
|
||||
LOG.error("Failed to send watchface info", e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.ZipFileException;
|
||||
|
||||
public class HuaweiWatchfaceManager {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HuaweiWatchfaceManager.class);
|
||||
private final HuaweiSupportProvider support;
|
||||
byte[] watchfaceBin;
|
||||
byte[] watchfaceSHA256;
|
||||
int fileSize = 0;
|
||||
|
||||
String watchfaceName = "413493857";
|
||||
String watchfaceVersion = "1.0.0";
|
||||
public HuaweiWatchfaceManager(HuaweiSupportProvider support) {
|
||||
this.support=support;
|
||||
}
|
||||
|
||||
public void setWatchfaceUri(Uri uri) {
|
||||
|
||||
UriHelper uriHelper;
|
||||
|
||||
try {
|
||||
uriHelper = UriHelper.get(uri, support.getContext());
|
||||
|
||||
GBZipFile watchfacePackage = new GBZipFile(uriHelper.openInputStream());
|
||||
String watchfaceDescription = new String(watchfacePackage.getFileFromZip("description.xml"));
|
||||
watchfaceBin = watchfacePackage.getFileFromZip("com.huawei.watchface");
|
||||
fileSize = watchfaceBin.length;
|
||||
|
||||
|
||||
} catch (ZipFileException e) {
|
||||
LOG.error("Unable to read watchface file.", e);
|
||||
return;
|
||||
} catch (FileNotFoundException e) {
|
||||
LOG.error("The watchface file was not found.", e);
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
LOG.error("General IO error occurred.", e);
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
LOG.error("Unknown error occurred.", e);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
MessageDigest m = MessageDigest.getInstance("SHA256");
|
||||
m.update(watchfaceBin, 0, watchfaceBin.length);
|
||||
watchfaceSHA256 = m.digest();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LOG.error("Digest alghoritm not found.", e);
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: generate random watchfaceName and watchfaceVersion
|
||||
LOG.info("watchface loaded, SHA256: "+ GB.hexdump(watchfaceSHA256) + " watchfaceName: " + watchfaceName + " watchfaceVersion: "+watchfaceVersion);
|
||||
|
||||
}
|
||||
|
||||
public int getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
public String getWatchfaceName() {
|
||||
return watchfaceName;
|
||||
}
|
||||
|
||||
public String getWatchfaceVersion() {
|
||||
return watchfaceVersion;
|
||||
}
|
||||
|
||||
}
|
|
@ -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.WatchfaceUpload;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiWatchfaceManager;
|
||||
|
||||
public class SendWatchfaceInfo extends Request{
|
||||
HuaweiWatchfaceManager huaweiWatchfaceManager;
|
||||
public SendWatchfaceInfo(HuaweiSupportProvider support,
|
||||
HuaweiWatchfaceManager huaweiWatchfaceManager) {
|
||||
super(support);
|
||||
this.huaweiWatchfaceManager = huaweiWatchfaceManager;
|
||||
this.serviceId = WatchfaceUpload.id;
|
||||
this.commandId = WatchfaceUpload.WatchfaceStartSend.id;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||
try {
|
||||
return new WatchfaceUpload.WatchfaceStartSend.Request(this.paramsProvider,
|
||||
huaweiWatchfaceManager.getFileSize(),
|
||||
huaweiWatchfaceManager.getWatchfaceName(),
|
||||
huaweiWatchfaceManager.getWatchfaceVersion()
|
||||
).serialize();
|
||||
} catch (HuaweiPacket.CryptoException e) {
|
||||
throw new RequestCreationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue