mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-08-31 19:45:27 +02:00
Huawei: Basic support for the installation of the applications
This commit is contained in:
parent
d75ae6b54d
commit
e54fd95a8b
@ -0,0 +1,65 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.huawei;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class HuaweiAppParser {
|
||||
|
||||
public static class AppFileEntry {
|
||||
public String filename;
|
||||
public String folder;
|
||||
public String unknown;
|
||||
public byte[] content;
|
||||
}
|
||||
|
||||
private String packageName;
|
||||
private final ArrayList<AppFileEntry> entries = new ArrayList<>();
|
||||
|
||||
public String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
public byte[] getEntryContent(String filename) {
|
||||
for(AppFileEntry en: entries) {
|
||||
if(en.filename.equals(filename)) {
|
||||
return en.content;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[] readData(ByteBuffer data) {
|
||||
int len = data.getInt();
|
||||
byte[] newPayload = new byte[len];
|
||||
data.get(newPayload, 0, len);
|
||||
return newPayload;
|
||||
}
|
||||
|
||||
private String readString(ByteBuffer data) {
|
||||
return new String(readData(data));
|
||||
}
|
||||
|
||||
public void parseData(byte[] in) throws Exception {
|
||||
|
||||
ByteBuffer data = ByteBuffer.wrap(in);
|
||||
|
||||
byte magic = data.get();
|
||||
if(magic != (byte)0xbe){
|
||||
throw new Exception("Invalid magic");
|
||||
}
|
||||
this.packageName = readString(data);
|
||||
while(data.remaining() > 0) {
|
||||
int pos = data.position();
|
||||
byte a = data.get();
|
||||
if(a != 0x00)
|
||||
break;
|
||||
data.position(pos);
|
||||
AppFileEntry ent = new AppFileEntry();
|
||||
ent.filename = readString(data);
|
||||
ent.folder = readString(data);
|
||||
ent.unknown = readString(data);
|
||||
ent.content = readData(data);
|
||||
entries.add(ent);
|
||||
}
|
||||
}
|
||||
}
|
@ -22,7 +22,6 @@ import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
@ -37,6 +36,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AppManagerActi
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsScreen;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.App;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Notifications;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Notifications.NotificationConstraintsType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Watchface;
|
||||
@ -59,6 +59,8 @@ public class HuaweiCoordinator {
|
||||
|
||||
private Watchface.WatchfaceDeviceParams watchfaceDeviceParams;
|
||||
|
||||
private App.AppDeviceParams appDeviceParams;
|
||||
|
||||
private final HuaweiCoordinatorSupplier parent;
|
||||
|
||||
private boolean transactionCrypted=true;
|
||||
@ -405,6 +407,8 @@ public class HuaweiCoordinator {
|
||||
|
||||
public boolean supportsWatchfaceParams(){ return supportsCommandForService(0x27, 0x01);}
|
||||
|
||||
public boolean supportsAppParams(){ return supportsCommandForService(0x2a, 0x06);}
|
||||
|
||||
public boolean supportsWeather() {
|
||||
return supportsCommandForService(0x0f, 0x01);
|
||||
}
|
||||
@ -584,20 +588,26 @@ public class HuaweiCoordinator {
|
||||
this.watchfaceDeviceParams = watchfaceDeviceParams;
|
||||
}
|
||||
|
||||
public void setAppDeviceParams(App.AppDeviceParams appDeviceParams) {
|
||||
this.appDeviceParams = appDeviceParams;
|
||||
}
|
||||
|
||||
public App.AppDeviceParams getAppDeviceParams() {
|
||||
return appDeviceParams;
|
||||
}
|
||||
|
||||
public Class<? extends Activity> getAppManagerActivity() {
|
||||
return AppManagerActivity.class;
|
||||
}
|
||||
|
||||
public boolean getSupportsAppListFetching() {
|
||||
return true;
|
||||
}
|
||||
public boolean getSupportsAppListFetching() { return true; }
|
||||
|
||||
public boolean getSupportsAppsManagement(GBDevice device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean getSupportsInstalledAppManagement(GBDevice device) {
|
||||
return false;
|
||||
return this.supportsAppParams(); // NOTE: this check can be incorrect. But looks like it works
|
||||
}
|
||||
|
||||
public boolean getSupportsCachedAppManagement(GBDevice device) {
|
||||
|
@ -29,6 +29,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiAppManager;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiFwHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiWatchfaceManager;
|
||||
|
||||
@ -56,57 +57,108 @@ public class HuaweiInstallHandler implements InstallHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
final HuaweiCoordinatorSupplier huaweiCoordinatorSupplier = (HuaweiCoordinatorSupplier) coordinator;
|
||||
if(helper.isWatchface()) {
|
||||
final HuaweiCoordinatorSupplier huaweiCoordinatorSupplier = (HuaweiCoordinatorSupplier) coordinator;
|
||||
|
||||
HuaweiWatchfaceManager.WatchfaceDescription description = helper.getWatchfaceDescription();
|
||||
HuaweiWatchfaceManager.WatchfaceDescription description = helper.getWatchfaceDescription();
|
||||
|
||||
HuaweiWatchfaceManager.Resolution resolution = new HuaweiWatchfaceManager.Resolution();
|
||||
String deviceScreen = String.format("%d*%d",huaweiCoordinatorSupplier.getHuaweiCoordinator().getHeight(),
|
||||
huaweiCoordinatorSupplier.getHuaweiCoordinator().getWidth());
|
||||
this.valid = resolution.isValid(description.screen, deviceScreen);
|
||||
HuaweiWatchfaceManager.Resolution resolution = new HuaweiWatchfaceManager.Resolution();
|
||||
String deviceScreen = String.format("%d*%d", huaweiCoordinatorSupplier.getHuaweiCoordinator().getHeight(),
|
||||
huaweiCoordinatorSupplier.getHuaweiCoordinator().getWidth());
|
||||
this.valid = resolution.isValid(description.screen, deviceScreen);
|
||||
|
||||
installActivity.setInstallEnabled(true);
|
||||
installActivity.setInstallEnabled(true);
|
||||
|
||||
GenericItem installItem = new GenericItem();
|
||||
GenericItem installItem = new GenericItem();
|
||||
|
||||
|
||||
if (helper.getWatchfacePreviewBitmap() != null) {
|
||||
installItem.setPreview(helper.getWatchfacePreviewBitmap());
|
||||
if (helper.getWatchfacePreviewBitmap() != null) {
|
||||
installItem.setPreview(helper.getWatchfacePreviewBitmap());
|
||||
}
|
||||
|
||||
installItem.setName(description.title);
|
||||
installActivity.setInstallItem(installItem);
|
||||
if (device.isBusy()) {
|
||||
LOG.error("Firmware cannot be installed (device busy)");
|
||||
installActivity.setInfoText("Firmware cannot be installed (device busy)");
|
||||
installActivity.setInfoText(device.getBusyTask());
|
||||
installActivity.setInstallEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!device.isConnected()) {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.valid) {
|
||||
LOG.error("Watchface cannot be installed");
|
||||
installActivity.setInfoText(context.getString(R.string.watchface_resolution_doesnt_match,
|
||||
resolution.screenByThemeVersion(description.screen), deviceScreen));
|
||||
installActivity.setInstallEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
installItem.setDetails(description.version);
|
||||
|
||||
installItem.setIcon(R.drawable.ic_watchface);
|
||||
installActivity.setInfoText(context.getString(R.string.watchface_install_info, installItem.getName(), description.version, description.author));
|
||||
|
||||
LOG.debug("Initialized HuaweiInstallHandler");
|
||||
} else if (helper.isAPP()) {
|
||||
final HuaweiCoordinatorSupplier huaweiCoordinatorSupplier = (HuaweiCoordinatorSupplier) coordinator;
|
||||
|
||||
String screenWindow = String.format("%d*%d", huaweiCoordinatorSupplier.getHuaweiCoordinator().getAppDeviceParams().height,
|
||||
huaweiCoordinatorSupplier.getHuaweiCoordinator().getAppDeviceParams().width);
|
||||
|
||||
String screenShape = huaweiCoordinatorSupplier.getHuaweiCoordinator().getAppDeviceParams().screenShape;
|
||||
|
||||
HuaweiAppManager.AppConfig config = helper.getAppconfig();
|
||||
|
||||
this.valid = config.checkDistroFilters(screenShape, screenWindow);
|
||||
|
||||
installActivity.setInstallEnabled(true);
|
||||
|
||||
GenericItem installItem = new GenericItem();
|
||||
|
||||
if (helper.getWatchfacePreviewBitmap() != null) {
|
||||
installItem.setPreview(helper.getWatchfacePreviewBitmap());
|
||||
}
|
||||
|
||||
installItem.setName(config.bundleName);
|
||||
installActivity.setInstallItem(installItem);
|
||||
if (device.isBusy()) {
|
||||
LOG.error("Firmware cannot be installed (device busy)");
|
||||
installActivity.setInfoText("Firmware cannot be installed (device busy)");
|
||||
installActivity.setInfoText(device.getBusyTask());
|
||||
installActivity.setInstallEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!device.isConnected()) {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.valid) {
|
||||
LOG.error("App cannot be installed");
|
||||
installActivity.setInstallEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
installItem.setDetails(config.version);
|
||||
|
||||
installItem.setIcon(R.drawable.ic_watchapp);
|
||||
|
||||
installActivity.setInfoText(context.getString(R.string.app_install_info, installItem.getName(), config.version, config.vendor));
|
||||
|
||||
LOG.debug("Initialized HuaweiInstallHandler");
|
||||
}
|
||||
|
||||
installItem.setName(description.title);
|
||||
installActivity.setInstallItem(installItem);
|
||||
if (device.isBusy()) {
|
||||
LOG.error("Firmware cannot be installed (device busy)");
|
||||
installActivity.setInfoText("Firmware cannot be installed (device busy)");
|
||||
installActivity.setInfoText(device.getBusyTask());
|
||||
installActivity.setInstallEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !device.isConnected()) {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.valid) {
|
||||
LOG.error("Watchface cannot be installed");
|
||||
installActivity.setInfoText(context.getString(R.string.watchface_resolution_doesnt_match,
|
||||
resolution.screenByThemeVersion(description.screen), deviceScreen));
|
||||
installActivity.setInstallEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//installItem.setDetails(description.version);
|
||||
|
||||
installItem.setIcon(R.drawable.ic_watchface);
|
||||
installActivity.setInfoText(context.getString(R.string.watchface_install_info, installItem.getName(), description.version, description.author));
|
||||
|
||||
LOG.debug("Initialized HuaweiInstallHandler");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Alarms;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.AccountRelated;
|
||||
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.FileDownloadService0A;
|
||||
@ -616,6 +617,16 @@ public class HuaweiPacket {
|
||||
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
|
||||
return this;
|
||||
}
|
||||
case App.id:
|
||||
switch (this.commandId) {
|
||||
case App.AppNames.id:
|
||||
return new App.AppNames.Response(paramsProvider).fromPacket(this);
|
||||
case App.AppInfoParams.id:
|
||||
return new App.AppInfoParams.Response(paramsProvider).fromPacket(this);
|
||||
default:
|
||||
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
|
||||
return this;
|
||||
}
|
||||
default:
|
||||
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
|
||||
return this;
|
||||
|
@ -0,0 +1,139 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV;
|
||||
|
||||
public class App {
|
||||
public static final byte id = 0x2a;
|
||||
|
||||
public static class AppDeviceParams {
|
||||
public byte unknown1 = 0;
|
||||
public int unknown2 = 0;
|
||||
public String osVersion = "";
|
||||
public String screenShape = "";
|
||||
public int width = 0;
|
||||
public int height = 0;
|
||||
public int unknown3 = 0;
|
||||
public String buildType = "";
|
||||
}
|
||||
|
||||
public static class InstalledAppInfo {
|
||||
public String packageName;
|
||||
public String version;
|
||||
public int unknown1;
|
||||
public String appName;
|
||||
public int unknown2;
|
||||
public int versionCode;
|
||||
public byte unknown4;
|
||||
public byte unknown6;
|
||||
|
||||
public InstalledAppInfo(HuaweiTLV tlv) throws HuaweiPacket.MissingTagException {
|
||||
this.packageName = tlv.getString(0x03);
|
||||
this.version = tlv.getString(0x04);
|
||||
this.unknown1 = tlv.getInteger(0x05);
|
||||
this.appName = tlv.getString(0x06);
|
||||
this.unknown2 = tlv.getInteger(0x07);
|
||||
this.versionCode = tlv.getInteger(0x09);
|
||||
this.unknown4 = tlv.getByte(0x0a);
|
||||
//{tag: b - Value: } -
|
||||
this.unknown6 = tlv.getByte(0x0d);
|
||||
}
|
||||
}
|
||||
|
||||
public static class AppDelete {
|
||||
public static final byte id = 0x01;
|
||||
|
||||
public static class Request extends HuaweiPacket {
|
||||
public Request(ParamsProvider paramsProvider,
|
||||
String packageName) {
|
||||
super(paramsProvider);
|
||||
this.serviceId = App.id;
|
||||
this.commandId = id;
|
||||
this.tlv = new HuaweiTLV()
|
||||
.put(0x01, (byte)1)
|
||||
.put(0x02, packageName);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Response extends HuaweiPacket {
|
||||
public Response (ParamsProvider paramsProvider) {
|
||||
super(paramsProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class AppNames {
|
||||
public static final byte id = 0x03;
|
||||
|
||||
public static class Request extends HuaweiPacket {
|
||||
public Request(ParamsProvider paramsProvider) {
|
||||
super(paramsProvider);
|
||||
this.serviceId = App.id;
|
||||
this.commandId = id;
|
||||
this.tlv = new HuaweiTLV()
|
||||
.put(0x81);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Response extends HuaweiPacket {
|
||||
|
||||
public List<App.InstalledAppInfo> appInfoList;
|
||||
public Response (ParamsProvider paramsProvider) {
|
||||
super(paramsProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseTlv() throws HuaweiPacket.ParseException {
|
||||
appInfoList = new ArrayList<>();
|
||||
if(this.tlv.contains(0x81)) {
|
||||
for (HuaweiTLV subTlv : this.tlv.getObject(0x81).getObjects(0x82)) {
|
||||
appInfoList.add(new InstalledAppInfo(subTlv));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class AppInfoParams {
|
||||
public static final byte id = 0x06;
|
||||
public static class Request extends HuaweiPacket {
|
||||
|
||||
public Request(ParamsProvider paramsProvider) {
|
||||
super(paramsProvider);
|
||||
this.serviceId = App.id;
|
||||
this.commandId = id;
|
||||
|
||||
this.tlv = new HuaweiTLV()
|
||||
.put(0x81);
|
||||
|
||||
this.complete = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Response extends HuaweiPacket {
|
||||
public AppDeviceParams params = new AppDeviceParams();
|
||||
public Response (ParamsProvider paramsProvider) {
|
||||
super(paramsProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseTlv() throws ParseException {
|
||||
if(this.tlv.contains(0x81)) {
|
||||
HuaweiTLV subTlv = this.tlv.getObject(0x81).getObject(0x82);
|
||||
this.params.unknown1 = subTlv.getByte(0x03);
|
||||
this.params.unknown2 = subTlv.getInteger(0x04);
|
||||
this.params.osVersion = subTlv.getString(0x05);
|
||||
this.params.screenShape = subTlv.getString(0x06);
|
||||
this.params.width = subTlv.getShort(0x07);
|
||||
this.params.height = subTlv.getShort(0x08);
|
||||
this.params.unknown3 = subTlv.getInteger(0x09);
|
||||
this.params.buildType = subTlv.getString(0x0a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -39,7 +39,8 @@ public class FileUpload {
|
||||
public static final byte watchface = 1;
|
||||
public static final byte music = 2;
|
||||
public static final byte backgroundImage = 3;
|
||||
public static final byte app = 7;
|
||||
public static final byte app = 6;
|
||||
public static final byte firmware = 7;
|
||||
}
|
||||
|
||||
|
||||
|
@ -46,6 +46,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventDisplayMes
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||
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;
|
||||
@ -117,6 +118,7 @@ public class AsynchronousResponse {
|
||||
handleFileUpload(response);
|
||||
handleWatchface(response);
|
||||
handleCameraRemote(response);
|
||||
handleApp(response);
|
||||
} catch (Request.ResponseParseException e) {
|
||||
LOG.error("Response parse exception", e);
|
||||
}
|
||||
@ -503,6 +505,22 @@ public class AsynchronousResponse {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleApp(HuaweiPacket response) throws Request.ResponseParseException {
|
||||
if (response.serviceId == App.id) {
|
||||
if (response.commandId == 0x2) {
|
||||
try {
|
||||
byte status = response.getTlv().getByte(0x1);
|
||||
if(status == (byte)0x66 || status == (byte)0x69) {
|
||||
this.support.getHuaweiAppManager().requestAppList();
|
||||
}
|
||||
} catch (HuaweiPacket.MissingTagException e) {
|
||||
LOG.error("Could not send watchface confirm request", e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleWeatherCheck(HuaweiPacket response) {
|
||||
if (response.serviceId == Weather.id && response.commandId == 0x04) {
|
||||
// Send back ok
|
||||
|
@ -0,0 +1,162 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.App;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetAppNames;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendAppDelete;
|
||||
|
||||
public class HuaweiAppManager {
|
||||
|
||||
static Logger LOG = LoggerFactory.getLogger(HuaweiAppManager.class);
|
||||
|
||||
public static class AppConfig {
|
||||
|
||||
public String bundleName;
|
||||
public String vendor;
|
||||
public String version;
|
||||
|
||||
JSONObject distroFilters = null;
|
||||
|
||||
public AppConfig(String jsonStr) {
|
||||
|
||||
try {
|
||||
JSONObject config = new JSONObject(jsonStr);
|
||||
this.bundleName = config.getJSONObject("app").getString("bundleName");
|
||||
this.vendor = config.getJSONObject("app").getString("vendor");
|
||||
this.version = config.getJSONObject("app").getJSONObject("version").getString("name");
|
||||
|
||||
parseDistroFilters(config);
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error decode app config", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseDistroFilters(JSONObject config) {
|
||||
try {
|
||||
distroFilters = config.getJSONObject("module").getJSONObject("distroFilter");
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error decode app config distroFilter", e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValInArray(JSONArray arr, String value) throws JSONException {
|
||||
for (int i = 0; i < arr.length(); i++) {
|
||||
if (arr.getString(i).equals(value))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean checkDistroFilters(String screenShape, String screenWindow) {
|
||||
if (distroFilters == null)
|
||||
return false;
|
||||
try {
|
||||
boolean screenShapeSupported = false;
|
||||
boolean screenWindowSupported = false;
|
||||
if (distroFilters.has("screenShape")) {
|
||||
JSONArray values = distroFilters.getJSONObject("screenShape").getJSONArray("value");
|
||||
String policy = distroFilters.getJSONObject("screenShape").getString("policy");
|
||||
screenShapeSupported = isValInArray(values, screenShape) && policy.equals("include");
|
||||
}
|
||||
if (distroFilters.has("screenWindow")) {
|
||||
JSONArray values = distroFilters.getJSONObject("screenWindow").getJSONArray("value");
|
||||
String policy = distroFilters.getJSONObject("screenWindow").getString("policy");
|
||||
screenWindowSupported = isValInArray(values, screenWindow) && policy.equals("include");
|
||||
}
|
||||
return screenShapeSupported && screenWindowSupported;
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error decode app config distroFilter", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final HuaweiSupportProvider support;
|
||||
|
||||
private List<App.InstalledAppInfo> installedAppList = null;
|
||||
|
||||
public HuaweiAppManager(HuaweiSupportProvider support) {
|
||||
this.support = support;
|
||||
}
|
||||
|
||||
public void setInstalledAppList(List<App.InstalledAppInfo> installedAppList) {
|
||||
this.installedAppList = installedAppList;
|
||||
handleAppList();
|
||||
}
|
||||
|
||||
public void handleAppList() {
|
||||
if (this.installedAppList == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<GBDeviceApp> gbDeviceApps = new ArrayList<>();
|
||||
|
||||
for (final App.InstalledAppInfo appInfo : installedAppList) {
|
||||
final UUID uuid = UUID.nameUUIDFromBytes(appInfo.packageName.getBytes());
|
||||
GBDeviceApp gbDeviceApp = new GBDeviceApp(
|
||||
uuid,
|
||||
appInfo.appName,
|
||||
"",
|
||||
appInfo.version,
|
||||
GBDeviceApp.Type.APP_GENERIC
|
||||
);
|
||||
gbDeviceApps.add(gbDeviceApp);
|
||||
}
|
||||
support.setGbWatchApps(gbDeviceApps);
|
||||
}
|
||||
|
||||
public void requestAppList() {
|
||||
if (!this.support.getHuaweiCoordinator().supportsAppParams())
|
||||
return;
|
||||
try {
|
||||
GetAppNames getAppNames = new GetAppNames(support);
|
||||
getAppNames.doPerform();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Error request applications list", e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean startApp(UUID uuid) {
|
||||
if (this.installedAppList == null)
|
||||
return false;
|
||||
|
||||
for (final App.InstalledAppInfo appInfo : installedAppList) {
|
||||
final UUID appUuid = UUID.nameUUIDFromBytes(appInfo.packageName.getBytes());
|
||||
if (appUuid.equals(uuid))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean deleteApp(UUID uuid) {
|
||||
if (this.installedAppList == null)
|
||||
return false;
|
||||
|
||||
for (final App.InstalledAppInfo appInfo : installedAppList) {
|
||||
final UUID appUuid = UUID.nameUUIDFromBytes(appInfo.packageName.getBytes());
|
||||
if (appUuid.equals(uuid)) {
|
||||
try {
|
||||
SendAppDelete sendAppDelete = new SendAppDelete(support, appInfo.packageName);
|
||||
sendAppDelete.doPerform();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Could not delete app: " + appInfo.packageName, e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -25,10 +25,13 @@ import android.net.Uri;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiAppParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileUpload;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile;
|
||||
@ -47,6 +50,7 @@ public class HuaweiFwHelper {
|
||||
|
||||
Bitmap watchfacePreviewBitmap;
|
||||
HuaweiWatchfaceManager.WatchfaceDescription watchfaceDescription;
|
||||
HuaweiAppManager.AppConfig appConfig;
|
||||
Context mContext;
|
||||
|
||||
public HuaweiFwHelper(final Uri uri, final Context context) {
|
||||
@ -65,13 +69,67 @@ public class HuaweiFwHelper {
|
||||
}
|
||||
|
||||
private void parseFile() {
|
||||
if (parseAsWatchFace()) {
|
||||
if(parseAsApp()) {
|
||||
assert appConfig.bundleName != null;
|
||||
assert appConfig.distroFilters != null;
|
||||
fileType = FileUpload.Filetype.app;
|
||||
} else if (parseAsWatchFace()) {
|
||||
assert watchfaceDescription.screen != null;
|
||||
assert watchfaceDescription.title != null;
|
||||
fileType = FileUpload.Filetype.watchface;
|
||||
}
|
||||
}
|
||||
|
||||
boolean parseAsApp() {
|
||||
|
||||
try {
|
||||
final UriHelper uriHelper = UriHelper.get(uri, this.mContext);
|
||||
|
||||
InputStream inputStream = uriHelper.openInputStream();
|
||||
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
int nRead;
|
||||
byte[] data = new byte[4];
|
||||
|
||||
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, nRead);
|
||||
}
|
||||
|
||||
buffer.flush();
|
||||
byte[] hap_data = buffer.toByteArray();
|
||||
|
||||
HuaweiAppParser app = new HuaweiAppParser();
|
||||
app.parseData(hap_data);
|
||||
|
||||
byte[] config = app.getEntryContent("config.json");
|
||||
if(config == null)
|
||||
return false;
|
||||
appConfig = new HuaweiAppManager.AppConfig(new String(config));
|
||||
fileName = app.getPackageName() + "_INSTALL"; //TODO: INSTALL or UPDATE suffix
|
||||
|
||||
fw = hap_data;
|
||||
fileSize = fw.length;
|
||||
|
||||
byte[] icon = app.getEntryContent("icon_small.png");
|
||||
if(icon != null) {
|
||||
watchfacePreviewBitmap = BitmapFactory.decodeByteArray(icon, 0, icon.length);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
LOG.error("The watchface file was not found.", e);
|
||||
} catch (IOException e) {
|
||||
LOG.error("General IO error occurred.", e);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Unknown error occurred.", e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public byte[] getBytes() {
|
||||
return fw;
|
||||
}
|
||||
@ -137,8 +195,13 @@ public class HuaweiFwHelper {
|
||||
public boolean isWatchface() {
|
||||
return fileType == FileUpload.Filetype.watchface;
|
||||
}
|
||||
|
||||
public boolean isAPP() {
|
||||
return fileType == FileUpload.Filetype.app;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return isWatchface();
|
||||
return isWatchface() || isAPP();
|
||||
}
|
||||
|
||||
public Bitmap getWatchfacePreviewBitmap() {
|
||||
@ -149,6 +212,10 @@ public class HuaweiFwHelper {
|
||||
return watchfaceDescription;
|
||||
}
|
||||
|
||||
public HuaweiAppManager.AppConfig getAppconfig() {
|
||||
return appConfig;
|
||||
}
|
||||
|
||||
public byte getFileType() {
|
||||
return fileType;
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSett
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCameraRemote;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventDisplayMessage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||
@ -78,6 +79,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||
@ -89,6 +91,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.AcceptAgreementsRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetAppInfoParams;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetEventAlarmList;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetGpsParameterRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetNotificationConstraintsRequest;
|
||||
@ -204,6 +207,8 @@ public class HuaweiSupportProvider {
|
||||
|
||||
protected HuaweiFileDownloadManager huaweiFileDownloadManager = new HuaweiFileDownloadManager(this);
|
||||
|
||||
protected HuaweiAppManager huaweiAppManager = new HuaweiAppManager(this);
|
||||
|
||||
public HuaweiCoordinatorSupplier getCoordinator() {
|
||||
return ((HuaweiCoordinatorSupplier) this.gbDevice.getDeviceCoordinator());
|
||||
}
|
||||
@ -215,6 +220,9 @@ public class HuaweiSupportProvider {
|
||||
return huaweiWatchfaceManager;
|
||||
}
|
||||
|
||||
public HuaweiAppManager getHuaweiAppManager() {
|
||||
return huaweiAppManager;
|
||||
}
|
||||
public HuaweiSupportProvider(HuaweiBRSupport support) {
|
||||
this.brSupport = support;
|
||||
}
|
||||
@ -802,6 +810,11 @@ public class HuaweiSupportProvider {
|
||||
SendCameraRemoteSetupEvent sendCameraRemoteSetupEvent = new SendCameraRemoteSetupEvent(this, CameraRemote.CameraRemoteSetup.Request.Event.ENABLE_CAMERA);
|
||||
sendCameraRemoteSetupEvent.doPerform();
|
||||
}
|
||||
|
||||
if (getHuaweiCoordinator().supportsAppParams()) {
|
||||
GetAppInfoParams getAppInfoParams = new GetAppInfoParams(this);
|
||||
getAppInfoParams.doPerform();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
GB.toast(getContext(), "Initialize dynamic services of Huawei device failed", Toast.LENGTH_SHORT, GB.ERROR,
|
||||
e);
|
||||
@ -2029,19 +2042,50 @@ public class HuaweiSupportProvider {
|
||||
LOG.error("Failed to update progress notification", e);
|
||||
}
|
||||
}
|
||||
private List<GBDeviceApp> gbWatchFaces = null;
|
||||
private List<GBDeviceApp> gbWatchApps = null;
|
||||
|
||||
public void setGbWatchFaces(List<GBDeviceApp> gbWatchFaces) {
|
||||
this.gbWatchFaces = gbWatchFaces;
|
||||
updateAppList();
|
||||
}
|
||||
|
||||
public void setGbWatchApps(List<GBDeviceApp> gbWatchApps) {
|
||||
this.gbWatchApps = gbWatchApps;
|
||||
updateAppList();
|
||||
}
|
||||
private void updateAppList() {
|
||||
ArrayList<GBDeviceApp> gbDeviceApps=new ArrayList<>();
|
||||
if(this.gbWatchFaces != null)
|
||||
gbDeviceApps.addAll(this.gbWatchFaces);
|
||||
if(this.gbWatchApps != null)
|
||||
gbDeviceApps.addAll(this.gbWatchApps);
|
||||
final GBDeviceEventAppInfo appInfoCmd = new GBDeviceEventAppInfo();
|
||||
appInfoCmd.apps = gbDeviceApps.toArray(new GBDeviceApp[0]);
|
||||
evaluateGBDeviceEvent(appInfoCmd);
|
||||
}
|
||||
|
||||
public void onAppInfoReq() {
|
||||
this.gbWatchFaces = null;
|
||||
this.gbWatchApps = null;
|
||||
huaweiWatchfaceManager.requestWatchfaceList();
|
||||
huaweiAppManager.requestAppList();
|
||||
}
|
||||
|
||||
public void onAppStart(final UUID uuid, boolean start) {
|
||||
if (start) {
|
||||
huaweiWatchfaceManager.setWatchface(uuid);
|
||||
//NOTE: to prevent exception in watchfaces code
|
||||
if(!huaweiAppManager.startApp(uuid)) {
|
||||
huaweiWatchfaceManager.setWatchface(uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onAppDelete(final UUID uuid) {
|
||||
huaweiWatchfaceManager.deleteWatchface(uuid);
|
||||
//NOTE: to prevent exception in watchfaces code
|
||||
if(!huaweiAppManager.deleteApp(uuid)){
|
||||
huaweiWatchfaceManager.deleteWatchface(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
public void onCameraStatusChange(GBDeviceEventCameraRemote.Event event, String filename) {
|
||||
|
@ -24,6 +24,7 @@ import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileUpload;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileUpload.FileUploadParams;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
@ -132,7 +133,11 @@ public class HuaweiUploadManager {
|
||||
|
||||
public void setDeviceBusy() {
|
||||
final GBDevice device = support.getDevice();
|
||||
device.setBusyTask(support.getContext().getString(R.string.uploading_watchface));
|
||||
if(fileType == FileUpload.Filetype.watchface) {
|
||||
device.setBusyTask(support.getContext().getString(R.string.uploading_watchface));
|
||||
} else {
|
||||
device.setBusyTask(support.getContext().getString(R.string.updating_firmware));
|
||||
}
|
||||
device.sendDeviceUpdateIntent(support.getContext());
|
||||
}
|
||||
|
||||
|
@ -26,20 +26,16 @@ import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Watchface;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Watchface.WatchfaceDeviceParams;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetWatchfacesList;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetWatchfacesNames;
|
||||
@ -195,10 +191,7 @@ public class HuaweiWatchfaceManager
|
||||
);
|
||||
gbDeviceApps.add(gbDeviceApp);
|
||||
}
|
||||
|
||||
final GBDeviceEventAppInfo appInfoCmd = new GBDeviceEventAppInfo();
|
||||
appInfoCmd.apps = gbDeviceApps.toArray(new GBDeviceApp[0]);
|
||||
support.evaluateGBDeviceEvent(appInfoCmd);
|
||||
support.setGbWatchFaces(gbDeviceApps);
|
||||
}
|
||||
|
||||
public void updateWatchfaceNames() {
|
||||
|
@ -0,0 +1,35 @@
|
||||
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.App;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||
|
||||
public class GetAppInfoParams extends Request{
|
||||
|
||||
public GetAppInfoParams(HuaweiSupportProvider support) {
|
||||
super(support);
|
||||
this.serviceId = App.id;
|
||||
this.commandId = App.AppInfoParams.id;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||
try {
|
||||
return new App.AppInfoParams.Request(paramsProvider).serialize();
|
||||
} catch (HuaweiPacket.CryptoException e) {
|
||||
throw new RequestCreationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processResponse() throws ResponseParseException {
|
||||
if (!(receivedPacket instanceof App.AppInfoParams.Response))
|
||||
throw new ResponseTypeMismatchException(receivedPacket, App.AppInfoParams.Response.class);
|
||||
|
||||
App.AppInfoParams.Response resp = (App.AppInfoParams.Response)(receivedPacket);
|
||||
supportProvider.getHuaweiCoordinator().setAppDeviceParams(resp.params);
|
||||
}
|
||||
}
|
@ -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.App;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||
|
||||
public class GetAppNames extends Request{
|
||||
public GetAppNames(HuaweiSupportProvider support) {
|
||||
super(support);
|
||||
this.serviceId = App.id;
|
||||
this.commandId = App.AppNames.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||
try {
|
||||
return new App.AppNames.Request(paramsProvider).serialize();
|
||||
} catch (HuaweiPacket.CryptoException e) {
|
||||
throw new RequestCreationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processResponse() throws ResponseParseException {
|
||||
if (!(receivedPacket instanceof App.AppNames.Response))
|
||||
throw new ResponseTypeMismatchException(receivedPacket, App.AppNames.Response.class);
|
||||
|
||||
App.AppNames.Response resp = (App.AppNames.Response)(receivedPacket);
|
||||
supportProvider.getHuaweiAppManager().setInstalledAppList(resp.appInfoList);
|
||||
}
|
||||
}
|
@ -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.App;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||
|
||||
public class SendAppDelete extends Request {
|
||||
private final String packageName;
|
||||
public SendAppDelete(HuaweiSupportProvider support, String packageName) {
|
||||
super(support);
|
||||
this.serviceId = App.id;
|
||||
this.commandId = App.AppDelete.id;
|
||||
this.packageName = packageName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||
try {
|
||||
return new App.AppDelete.Request(this.paramsProvider, this.packageName).serialize();
|
||||
} catch (HuaweiPacket.CryptoException e) {
|
||||
throw new RequestCreationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user