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).
live-activity-data
Andreas Shimokawa 2015-08-16 00:32:36 +02:00
parent 567f27b0f4
commit a4f5524f6e
5 changed files with 84 additions and 40 deletions

View File

@ -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,

View File

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

View File

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

View File

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

View File

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