1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-06-19 03:20:21 +02:00

Pebble app installation: first successful installation :)

KNOWN PROBLEMS
- expected filenames inside pbw files are hardcoded (pebble-app.bin etc)
- long delay before installation starts
- must be in app mananger at least once before installation in possible
- errors while installing are not always recognized
This commit is contained in:
Andreas Shimokawa 2015-04-07 19:33:23 +02:00
parent 3498ddfc7a
commit ebdf514c0e
4 changed files with 87 additions and 52 deletions

View File

@ -351,9 +351,10 @@ public class BluetoothCommunicationService extends Service {
mGBDeviceIoThread.write(mGBDeviceProtocol.encodeAppDelete(id, index));
} else if (action.equals(ACTION_INSTALL_PEBBLEAPP)) {
String uriString = intent.getStringExtra("app_uri");
if (uriString != null && mGBDevice.getFreeAppSlot() != -1) {
Log.i(TAG, "will try to install app in slot " + mGBDevice.getFreeAppSlot());
((PebbleIoThread) mGBDeviceIoThread).installApp(Uri.parse(uriString));
int slot = mGBDevice.getFreeAppSlot();
if (uriString != null && slot != -1) {
Log.i(TAG, "will try to install app in slot " + slot);
((PebbleIoThread) mGBDeviceIoThread).installApp(Uri.parse(uriString), slot);
}
} else if (action.equals(ACTION_START)) {
startForeground(NOTIFICATION_ID, createNotification("Gadgetbridge running"));
@ -449,10 +450,7 @@ public class BluetoothCommunicationService extends Service {
APP_UPLOAD_COMMIT,
APP_WAIT_COMMMIT,
APP_UPLOAD_COMPLETE,
RES_START_INSTALL,
RES_WAIT_TOKEN,
RES_UPLOAD_CHUNK,
RES_UPLOAD_COMPLETE,
APP_REFRESH,
}
private class PebbleIoThread extends GBDeviceIoThread {
@ -471,6 +469,9 @@ public class BluetoothCommunicationService extends Service {
private ZipInputStream mmZis = null;
private STM32CRC mmSTM32CRC = new STM32CRC();
private PebbleAppInstallState mmInstallState = PebbleAppInstallState.UNKNOWN;
private String[] mmFilesToInstall = null;
private int mmCurrentFileIndex = -1;
private int mmInstallSlot = -1;
public PebbleIoThread(String btDeviceAddress) {
super(btDeviceAddress);
@ -514,10 +515,33 @@ public class BluetoothCommunicationService extends Service {
case APP_START_INSTALL:
Log.i(TAG, "start installing app binary");
mmSTM32CRC.reset();
mmPBWReader = new PBWReader(mmInstallURI, getApplicationContext());
mmZis = mmPBWReader.getInputStreamAppBinary();
int binarySize = mmPBWReader.getAppBinarySize();
writeInstallApp(mmPebbleProtocol.encodeUploadStart(PebbleProtocol.PUTBYTES_TYPE_BINARY, mGBDevice.getFreeAppSlot(), binarySize), -1);
if (mmPBWReader == null) {
mmPBWReader = new PBWReader(mmInstallURI, getApplicationContext());
mmFilesToInstall = mmPBWReader.getFilesToInstall();
mmCurrentFileIndex = 0;
}
String fileName = mmFilesToInstall[mmCurrentFileIndex];
mmZis = mmPBWReader.getInputStreamFile(fileName);
int binarySize = mmPBWReader.getFileSize(fileName);
// FIXME: do not assume type from filename, parse json correctly in PBWReader
byte type = -1;
if (fileName.equals("pebble-app.bin")) {
type = PebbleProtocol.PUTBYTES_TYPE_BINARY;
} else if (fileName.equals("pebble-worker.bin")) {
type = PebbleProtocol.PUTBYTES_TYPE_WORKER;
} else if (fileName.equals("app_resources.pbpack")) {
type = PebbleProtocol.PUTBYTES_TYPE_RESOURCES;
} else {
// FIXME: proper state for cancellation
mmInstallState = PebbleAppInstallState.UNKNOWN;
mmPBWReader = null;
mmIsInstalling = false;
mmZis = null;
mmAppInstallToken = -1;
mmInstallSlot = -1;
}
writeInstallApp(mmPebbleProtocol.encodeUploadStart(type, (byte)mmInstallSlot, binarySize), -1);
mmInstallState = PebbleAppInstallState.APP_WAIT_TOKEN;
break;
case APP_WAIT_TOKEN:
@ -540,24 +564,33 @@ public class BluetoothCommunicationService extends Service {
continue;
}
break;
case APP_UPLOAD_COMMIT:
writeInstallApp(mmPebbleProtocol.encodeUploadCommit(mmAppInstallToken, mmSTM32CRC.getResult()),-1);
mmAppInstallToken = -1;
mmInstallState = PebbleAppInstallState.APP_WAIT_COMMMIT;
case APP_UPLOAD_COMMIT:
writeInstallApp(mmPebbleProtocol.encodeUploadCommit(mmAppInstallToken, mmSTM32CRC.getResult()), -1);
mmAppInstallToken = -1;
mmInstallState = PebbleAppInstallState.APP_WAIT_COMMMIT;
break;
case APP_WAIT_COMMMIT:
if (mmAppInstallToken != -1) {
Log.i(TAG, "got token " + mmAppInstallToken);
mmInstallState = PebbleAppInstallState.APP_UPLOAD_COMPLETE;
continue;
}
case APP_WAIT_COMMMIT:
if (mmAppInstallToken != -1) {
Log.i(TAG, "got token " + mmAppInstallToken);
mmInstallState = PebbleAppInstallState.APP_UPLOAD_COMPLETE;
continue;
}
break;
case APP_UPLOAD_COMPLETE:
writeInstallApp(mmPebbleProtocol.encodeUploadComplete(mmAppInstallToken),-1);
mmInstallState = PebbleAppInstallState.UNKNOWN;
writeInstallApp(mmPebbleProtocol.encodeUploadComplete(mmAppInstallToken), -1);
if (++mmCurrentFileIndex < mmFilesToInstall.length) {
mmInstallState = PebbleAppInstallState.APP_START_INSTALL;
} else {
mmInstallState = PebbleAppInstallState.APP_REFRESH;
}
break;
case APP_REFRESH:
writeInstallApp(mmPebbleProtocol.encodeAppRefresh(mmInstallSlot), -1);
mmPBWReader = null;
mmIsInstalling = false;
mmZis = null;
mmAppInstallToken = -1;
mmInstallSlot = -1;
break;
default:
break;
@ -690,10 +723,14 @@ public class BluetoothCommunicationService extends Service {
}
}
public void installApp(Uri uri) {
public void installApp(Uri uri, int slot) {
if (mmIsInstalling) {
return;
}
mmInstallState = PebbleAppInstallState.APP_START_INSTALL;
mmIsInstalling = true;
mmInstallURI = uri;
mmInstallSlot = slot;
mmIsInstalling = true;
}
public void quit() {

View File

@ -12,6 +12,7 @@ import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@ -21,6 +22,7 @@ public class PBWReader {
private GBDeviceApp app;
private final Uri uri;
private final ContentResolver cr;
private ArrayList<String> filesToInstall;
public PBWReader(Uri uri, Context context) {
this.uri = uri;
@ -36,9 +38,13 @@ public class PBWReader {
}
ZipInputStream zis = new ZipInputStream(fin);
ZipEntry ze = null;
filesToInstall = new ArrayList<String>();
try {
while ((ze = zis.getNextEntry()) != null) {
if (ze.getName().equals("appinfo.json")) {
String fileName = ze.getName();
if (fileName.equals("pebble-app.bin") || fileName.equals("pebble-worker.bin") || fileName.equals("app_resources.pbpack")) {
filesToInstall.add(fileName); // FIXME: do not hardcode filenames above
} else if (fileName.equals("appinfo.json")) {
long bytes = ze.getSize();
if (bytes > 8192) // that should be too much
break;
@ -127,28 +133,8 @@ public class PBWReader {
return -1;
}
public ZipInputStream getInputStreamAppBinary() {
return getInputStreamFile("pebble-app.bin");
}
public int getAppBinarySize() {
return getFileSize("pebble-app.bin");
}
public ZipInputStream getInputStreamAppWorker() {
return getInputStreamFile("pebble-worker.bin");
}
public int getAppWorkerSize() {
return getFileSize("pebble-worker.bin");
}
public ZipInputStream getInputStreamAppResources() {
return getInputStreamFile("app_resources.pbpack");
}
public int getAppResourcesSize() {
return getFileSize("pebble-resources.pbpack");
public String[] getFilesToInstall() {
return filesToInstall.toArray(new String[filesToInstall.size()]);
}
}

View File

@ -34,8 +34,8 @@ public class PebbleAppInstallerActivity extends Activity {
debugTextView.setText("contents:\n");
final Uri uri = getIntent().getData();
PBWReader pbwReader = new PBWReader(uri, getApplicationContext());
GBDeviceApp app = pbwReader.getGBDeviceApp();
if (pbwReader != null && app != null) {
debugTextView.setText("This is just a test, you cant install anything yet \n\n" + app.getName() + " Version " + app.getVersion() + " by " + app.getCreator() + "\n");
installButton.setEnabled(true);

View File

@ -71,6 +71,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
static final byte APPMANAGER_GETAPPBANKSTATUS = 1;
static final byte APPMANAGER_REMOVEAPP = 2;
static final byte APPMANAGER_REFRESHAPP = 3;
static final int APPMANAGER_RES_SUCCESS = 1;
@ -83,10 +84,10 @@ public class PebbleProtocol extends GBDeviceProtocol {
static final byte PUTBYTES_TYPE_FIRMWARE = 1;
static final byte PUTBYTES_TYPE_RECOVERY = 2;
static final byte PUTBYTES_TYPE_SYSRESOURCES = 3;
static final byte PUTBYTES_TYPE_RESOURCES = 4;
public static final byte PUTBYTES_TYPE_RESOURCES = 4;
public static final byte PUTBYTES_TYPE_BINARY = 5;
static final byte PUTBYTES_TYPE_FILE = 6;
static final byte PUTBYTES_TYPE_WORKER = 7;
public static final byte PUTBYTES_TYPE_WORKER = 7;
static final byte PHONEVERSION_APPVERSION_MAGIC = 2; // increase this if pebble complains
static final byte PHONEVERSION_APPVERSION_MAJOR = 2;
@ -94,7 +95,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
static final byte PHONEVERSION_APPVERSION_PATCH = 0;
static final int PHONEVERSION_SESSION_CAPS_GAMMARAY = (int)0x80000000;
static final int PHONEVERSION_SESSION_CAPS_GAMMARAY = (int) 0x80000000;
static final int PHONEVERSION_REMOTE_CAPS_TELEPHONY = 0x00000010;
static final int PHONEVERSION_REMOTE_CAPS_SMS = 0x00000020;
@ -116,6 +117,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
static final short LENGTH_PREFIX = 4;
static final short LENGTH_SETTIME = 5;
static final short LENGTH_REMOVEAPP = 9;
static final short LENGTH_REFRESHAPP = 5;
static final short LENGTH_PHONEVERSION = 17;
static final short LENGTH_UPLOADSTART = 7;
static final short LENGTH_UPLOADCHUNK = 9;
@ -329,6 +331,16 @@ public class PebbleProtocol extends GBDeviceProtocol {
return buf.array();
}
public byte[] encodeAppRefresh(int index) {
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_REFRESHAPP);
buf.order(ByteOrder.BIG_ENDIAN);
buf.putShort(LENGTH_REFRESHAPP);
buf.putShort(ENDPOINT_APPMANAGER);
buf.put(APPMANAGER_REFRESHAPP);
buf.putInt(index);
return buf.array();
}
public GBDeviceCommand decodeResponse(byte[] responseData) {
ByteBuffer buf = ByteBuffer.wrap(responseData);