Pebble: blindly implement missing parts for app installation on FW 3.x
This is expected to fail and needs to be enable in preferences (untested features).
This commit is contained in:
parent
567f27b0f4
commit
a4f5524f6e
|
@ -10,7 +10,7 @@ public abstract class GBDeviceEvent {
|
||||||
CALL_CONTROL,
|
CALL_CONTROL,
|
||||||
APP_INFO,
|
APP_INFO,
|
||||||
VERSION_INFO,
|
VERSION_INFO,
|
||||||
APP_MANAGEMENT_RES,
|
APP_MANAGEMENT,
|
||||||
SEND_BYTES,
|
SEND_BYTES,
|
||||||
SLEEP_MONITOR_RES,
|
SLEEP_MONITOR_RES,
|
||||||
SCREENSHOT,
|
SCREENSHOT,
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
package nodomain.freeyourgadget.gadgetbridge.deviceevents;
|
package nodomain.freeyourgadget.gadgetbridge.deviceevents;
|
||||||
|
|
||||||
public class GBDeviceEventAppManagementResult extends GBDeviceEvent {
|
import java.util.UUID;
|
||||||
public Result result = Result.UNKNOWN;
|
|
||||||
|
public class GBDeviceEventAppManagement extends GBDeviceEvent {
|
||||||
|
public Event event = Event.UNKNOWN;
|
||||||
public EventType type = EventType.UNKNOWN;
|
public EventType type = EventType.UNKNOWN;
|
||||||
public int token = -1;
|
public int token = -1;
|
||||||
|
public UUID uuid = null;
|
||||||
|
|
||||||
public GBDeviceEventAppManagementResult() {
|
public GBDeviceEventAppManagement() {
|
||||||
eventClass = EventClass.APP_MANAGEMENT_RES;
|
eventClass = EventClass.APP_MANAGEMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum EventType {
|
public enum EventType {
|
||||||
|
@ -15,10 +18,11 @@ public class GBDeviceEventAppManagementResult extends GBDeviceEvent {
|
||||||
DELETE,
|
DELETE,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Result {
|
public enum Event {
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
SUCCESS,
|
SUCCESS,
|
||||||
ACKNOLEDGE,
|
ACKNOLEDGE,
|
||||||
FAILURE,
|
FAILURE,
|
||||||
|
REQUEST,
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,6 +12,7 @@ import android.preference.PreferenceManager;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -22,13 +23,14 @@ import java.util.zip.ZipInputStream;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagementResult;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagement;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PBWReader;
|
import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PBWReader;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleInstallable;
|
import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleInstallable;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.bt.GBDeviceIoThread;
|
import nodomain.freeyourgadget.gadgetbridge.service.bt.GBDeviceIoThread;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.bt.GBDeviceProtocol;
|
import nodomain.freeyourgadget.gadgetbridge.service.bt.GBDeviceProtocol;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
public class PebbleIoThread extends GBDeviceIoThread {
|
public class PebbleIoThread extends GBDeviceIoThread {
|
||||||
|
@ -122,7 +124,7 @@ public class PebbleIoThread extends GBDeviceIoThread {
|
||||||
mCRC = pi.getCRC();
|
mCRC = pi.getCRC();
|
||||||
mBinarySize = pi.getFileSize();
|
mBinarySize = pi.getFileSize();
|
||||||
mBytesWritten = 0;
|
mBytesWritten = 0;
|
||||||
writeInstallApp(mPebbleProtocol.encodeUploadStart(pi.getType(), (byte) mInstallSlot, mBinarySize));
|
writeInstallApp(mPebbleProtocol.encodeUploadStart(pi.getType(), mInstallSlot, mBinarySize));
|
||||||
mInstallState = PebbleAppInstallState.WAIT_TOKEN;
|
mInstallState = PebbleAppInstallState.WAIT_TOKEN;
|
||||||
break;
|
break;
|
||||||
case WAIT_TOKEN:
|
case WAIT_TOKEN:
|
||||||
|
@ -282,12 +284,12 @@ public class PebbleIoThread extends GBDeviceIoThread {
|
||||||
}
|
}
|
||||||
gbDevice.setState(GBDevice.State.INITIALIZED);
|
gbDevice.setState(GBDevice.State.INITIALIZED);
|
||||||
return false;
|
return false;
|
||||||
case APP_MANAGEMENT_RES:
|
case APP_MANAGEMENT:
|
||||||
GBDeviceEventAppManagementResult appMgmtRes = (GBDeviceEventAppManagementResult) deviceEvent;
|
GBDeviceEventAppManagement appMgmt = (GBDeviceEventAppManagement) deviceEvent;
|
||||||
switch (appMgmtRes.type) {
|
switch (appMgmt.type) {
|
||||||
case DELETE:
|
case DELETE:
|
||||||
// right now on the Pebble we also receive this on a failed/successful installation ;/
|
// right now on the Pebble we also receive this on a failed/successful installation ;/
|
||||||
switch (appMgmtRes.result) {
|
switch (appMgmt.event) {
|
||||||
case FAILURE:
|
case FAILURE:
|
||||||
if (mIsInstalling) {
|
if (mIsInstalling) {
|
||||||
if (mInstallState == PebbleAppInstallState.WAIT_SLOT) {
|
if (mInstallState == PebbleAppInstallState.WAIT_SLOT) {
|
||||||
|
@ -320,13 +322,21 @@ public class PebbleIoThread extends GBDeviceIoThread {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case INSTALL:
|
case INSTALL:
|
||||||
switch (appMgmtRes.result) {
|
switch (appMgmt.event) {
|
||||||
case FAILURE:
|
case FAILURE:
|
||||||
LOG.info("failure installing app"); // TODO: report to Installer
|
LOG.info("failure installing app"); // TODO: report to Installer
|
||||||
finishInstall(true);
|
finishInstall(true);
|
||||||
break;
|
break;
|
||||||
case SUCCESS:
|
case SUCCESS:
|
||||||
setToken(appMgmtRes.token);
|
setToken(appMgmt.token);
|
||||||
|
break;
|
||||||
|
case REQUEST:
|
||||||
|
LOG.info("APPFETCH request: " + appMgmt.uuid + " / " + appMgmt.token);
|
||||||
|
try {
|
||||||
|
installApp(Uri.fromFile(new File(FileUtils.getExternalFilesDir() + "/pbw-cache/" + appMgmt.uuid.toString() + ".pbw")), appMgmt.token);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -369,18 +379,21 @@ public class PebbleIoThread extends GBDeviceIoThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void installApp(Uri uri) {
|
public void installApp(Uri uri, int appId) {
|
||||||
if (mIsInstalling) {
|
if (mIsInstalling) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mIsInstalling = true;
|
|
||||||
|
|
||||||
mPBWReader = new PBWReader(uri, getContext(), gbDevice.getHardwareVersion().equals("dvt") ? "basalt" : "aplite");
|
mPBWReader = new PBWReader(uri, getContext(), gbDevice.getHardwareVersion().equals("dvt") ? "basalt" : "aplite");
|
||||||
mPebbleInstallables = mPBWReader.getPebbleInstallables();
|
mPebbleInstallables = mPBWReader.getPebbleInstallables();
|
||||||
mCurrentInstallableIndex = 0;
|
mCurrentInstallableIndex = 0;
|
||||||
|
|
||||||
if (mPBWReader.isFirmware()) {
|
if (mPBWReader.isFirmware()) {
|
||||||
|
LOG.info("starting firmware installation");
|
||||||
|
mIsInstalling = true;
|
||||||
|
mInstallSlot = 0;
|
||||||
writeInstallApp(mPebbleProtocol.encodeInstallFirmwareStart());
|
writeInstallApp(mPebbleProtocol.encodeInstallFirmwareStart());
|
||||||
|
mInstallState = PebbleAppInstallState.START_INSTALL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a hack for recovery mode, in which the blocking read has no timeout and the
|
* This is a hack for recovery mode, in which the blocking read has no timeout and the
|
||||||
|
@ -392,16 +405,25 @@ public class PebbleIoThread extends GBDeviceIoThread {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
writeInstallApp(mPebbleProtocol.encodeGetTime());
|
writeInstallApp(mPebbleProtocol.encodeGetTime());
|
||||||
|
|
||||||
LOG.info("starting firmware installation");
|
|
||||||
mInstallSlot = 0;
|
|
||||||
mInstallState = PebbleAppInstallState.START_INSTALL;
|
|
||||||
} else {
|
} else {
|
||||||
GBDeviceApp app = mPBWReader.getGBDeviceApp();
|
GBDeviceApp app = mPBWReader.getGBDeviceApp();
|
||||||
writeInstallApp(mPebbleProtocol.encodeAppDelete(app.getUUID()));
|
|
||||||
mInstallState = PebbleAppInstallState.WAIT_SLOT;
|
|
||||||
if (mPebbleProtocol.isFw3x && mForceUntested) {
|
if (mPebbleProtocol.isFw3x && mForceUntested) {
|
||||||
writeInstallApp(mPebbleProtocol.encodeInstallMetadata(app.getUUID(), app.getName(), mPBWReader.getAppVersion(), mPBWReader.getSdkVersion()));
|
if (appId == 0) {
|
||||||
|
// only install metadata - not the binaries
|
||||||
|
write(mPebbleProtocol.encodeInstallMetadata(app.getUUID(), app.getName(), mPBWReader.getAppVersion(), mPBWReader.getSdkVersion()));
|
||||||
|
GB.toast("To finish installation please start the watchapp on your Pebble", 5, GB.INFO);
|
||||||
|
} else {
|
||||||
|
// this came from an app fetch request, so do the real stuff
|
||||||
|
mIsInstalling = true;
|
||||||
|
mInstallSlot = appId;
|
||||||
|
mInstallState = PebbleAppInstallState.START_INSTALL;
|
||||||
|
|
||||||
|
writeInstallApp(mPebbleProtocol.encodeGetTime()); // EVIL HACK see hack above
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mIsInstalling = true;
|
||||||
|
mInstallState = PebbleAppInstallState.WAIT_SLOT;
|
||||||
|
writeInstallApp(mPebbleProtocol.encodeAppDelete(app.getUUID()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import java.util.UUID;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagementResult;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagement;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventDismissNotification;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventDismissNotification;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
|
||||||
|
@ -182,7 +182,8 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
||||||
static final short LENGTH_REFRESHAPP = 5;
|
static final short LENGTH_REFRESHAPP = 5;
|
||||||
static final short LENGTH_SETTIME = 5;
|
static final short LENGTH_SETTIME = 5;
|
||||||
static final short LENGTH_SYSTEMMESSAGE = 2;
|
static final short LENGTH_SYSTEMMESSAGE = 2;
|
||||||
static final short LENGTH_UPLOADSTART = 7;
|
static final short LENGTH_UPLOADSTART_2X = 7;
|
||||||
|
static final short LENGTH_UPLOADSTART_3X = 10;
|
||||||
static final short LENGTH_UPLOADCHUNK = 9;
|
static final short LENGTH_UPLOADCHUNK = 9;
|
||||||
static final short LENGTH_UPLOADCOMMIT = 9;
|
static final short LENGTH_UPLOADCOMMIT = 9;
|
||||||
static final short LENGTH_UPLOADCOMPLETE = 5;
|
static final short LENGTH_UPLOADCOMPLETE = 5;
|
||||||
|
@ -658,15 +659,27 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pebble specific install methods */
|
/* pebble specific install methods */
|
||||||
public byte[] encodeUploadStart(byte type, byte index, int size) {
|
public byte[] encodeUploadStart(byte type, int app_id, int size) {
|
||||||
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_UPLOADSTART);
|
short length;
|
||||||
|
if (isFw3x) {
|
||||||
|
length = LENGTH_UPLOADSTART_3X;
|
||||||
|
type |= 0b10000000;
|
||||||
|
} else {
|
||||||
|
length = LENGTH_UPLOADSTART_2X;
|
||||||
|
}
|
||||||
|
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + length);
|
||||||
buf.order(ByteOrder.BIG_ENDIAN);
|
buf.order(ByteOrder.BIG_ENDIAN);
|
||||||
buf.putShort(LENGTH_UPLOADSTART);
|
buf.putShort(length);
|
||||||
buf.putShort(ENDPOINT_PUTBYTES);
|
buf.putShort(ENDPOINT_PUTBYTES);
|
||||||
buf.put(PUTBYTES_INIT);
|
buf.put(PUTBYTES_INIT);
|
||||||
buf.putInt(size);
|
buf.putInt(size);
|
||||||
buf.put(type);
|
buf.put(type);
|
||||||
buf.put(index);
|
if (isFw3x) {
|
||||||
|
buf.putInt(app_id);
|
||||||
|
} else {
|
||||||
|
// slot
|
||||||
|
buf.put((byte) app_id);
|
||||||
|
}
|
||||||
return buf.array();
|
return buf.array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -940,7 +953,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GBDeviceEvent decodeAppFetch(ByteBuffer buf) {
|
private GBDeviceEventAppManagement decodeAppFetch(ByteBuffer buf) {
|
||||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
byte command = buf.get();
|
byte command = buf.get();
|
||||||
if (command == 0x01) {
|
if (command == 0x01) {
|
||||||
|
@ -948,7 +961,12 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
||||||
long uuid_low = buf.getLong();
|
long uuid_low = buf.getLong();
|
||||||
UUID uuid = new UUID(uuid_high, uuid_low);
|
UUID uuid = new UUID(uuid_high, uuid_low);
|
||||||
int app_id = buf.getInt();
|
int app_id = buf.getInt();
|
||||||
LOG.info("APPFETCH request: " + uuid + " / " + app_id);
|
GBDeviceEventAppManagement fetchRequest = new GBDeviceEventAppManagement();
|
||||||
|
fetchRequest.type = GBDeviceEventAppManagement.EventType.INSTALL;
|
||||||
|
fetchRequest.event = GBDeviceEventAppManagement.Event.REQUEST;
|
||||||
|
fetchRequest.token = app_id;
|
||||||
|
fetchRequest.uuid = uuid;
|
||||||
|
return fetchRequest;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1080,16 +1098,16 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case APPMANAGER_REMOVEAPP:
|
case APPMANAGER_REMOVEAPP:
|
||||||
GBDeviceEventAppManagementResult deleteRes = new GBDeviceEventAppManagementResult();
|
GBDeviceEventAppManagement deleteRes = new GBDeviceEventAppManagement();
|
||||||
deleteRes.type = GBDeviceEventAppManagementResult.EventType.DELETE;
|
deleteRes.type = GBDeviceEventAppManagement.EventType.DELETE;
|
||||||
|
|
||||||
int result = buf.getInt();
|
int result = buf.getInt();
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case APPMANAGER_RES_SUCCESS:
|
case APPMANAGER_RES_SUCCESS:
|
||||||
deleteRes.result = GBDeviceEventAppManagementResult.Result.SUCCESS;
|
deleteRes.event = GBDeviceEventAppManagement.Event.SUCCESS;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
deleteRes.result = GBDeviceEventAppManagementResult.Result.FAILURE;
|
deleteRes.event = GBDeviceEventAppManagement.Event.FAILURE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
devEvt = deleteRes;
|
devEvt = deleteRes;
|
||||||
|
@ -1101,16 +1119,16 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
||||||
break;
|
break;
|
||||||
case ENDPOINT_PUTBYTES:
|
case ENDPOINT_PUTBYTES:
|
||||||
pebbleCmd = buf.get();
|
pebbleCmd = buf.get();
|
||||||
GBDeviceEventAppManagementResult installRes = new GBDeviceEventAppManagementResult();
|
GBDeviceEventAppManagement installRes = new GBDeviceEventAppManagement();
|
||||||
installRes.type = GBDeviceEventAppManagementResult.EventType.INSTALL;
|
installRes.type = GBDeviceEventAppManagement.EventType.INSTALL;
|
||||||
switch (pebbleCmd) {
|
switch (pebbleCmd) {
|
||||||
case PUTBYTES_INIT:
|
case PUTBYTES_INIT:
|
||||||
installRes.token = buf.getInt();
|
installRes.token = buf.getInt();
|
||||||
installRes.result = GBDeviceEventAppManagementResult.Result.SUCCESS;
|
installRes.event = GBDeviceEventAppManagement.Event.SUCCESS;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
installRes.token = buf.getInt();
|
installRes.token = buf.getInt();
|
||||||
installRes.result = GBDeviceEventAppManagementResult.Result.FAILURE;
|
installRes.event = GBDeviceEventAppManagement.Event.FAILURE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
devEvt = installRes;
|
devEvt = installRes;
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class PebbleSupport extends AbstractBTDeviceSupport {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInstallApp(Uri uri) {
|
public void onInstallApp(Uri uri) {
|
||||||
getDeviceIOThread().installApp(uri);
|
getDeviceIOThread().installApp(uri, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue