1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-06-20 03:50:43 +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)); mGBDeviceIoThread.write(mGBDeviceProtocol.encodeAppDelete(id, index));
} else if (action.equals(ACTION_INSTALL_PEBBLEAPP)) { } else if (action.equals(ACTION_INSTALL_PEBBLEAPP)) {
String uriString = intent.getStringExtra("app_uri"); String uriString = intent.getStringExtra("app_uri");
if (uriString != null && mGBDevice.getFreeAppSlot() != -1) { int slot = mGBDevice.getFreeAppSlot();
Log.i(TAG, "will try to install app in slot " + mGBDevice.getFreeAppSlot()); if (uriString != null && slot != -1) {
((PebbleIoThread) mGBDeviceIoThread).installApp(Uri.parse(uriString)); Log.i(TAG, "will try to install app in slot " + slot);
((PebbleIoThread) mGBDeviceIoThread).installApp(Uri.parse(uriString), slot);
} }
} else if (action.equals(ACTION_START)) { } else if (action.equals(ACTION_START)) {
startForeground(NOTIFICATION_ID, createNotification("Gadgetbridge running")); startForeground(NOTIFICATION_ID, createNotification("Gadgetbridge running"));
@ -449,10 +450,7 @@ public class BluetoothCommunicationService extends Service {
APP_UPLOAD_COMMIT, APP_UPLOAD_COMMIT,
APP_WAIT_COMMMIT, APP_WAIT_COMMMIT,
APP_UPLOAD_COMPLETE, APP_UPLOAD_COMPLETE,
RES_START_INSTALL, APP_REFRESH,
RES_WAIT_TOKEN,
RES_UPLOAD_CHUNK,
RES_UPLOAD_COMPLETE,
} }
private class PebbleIoThread extends GBDeviceIoThread { private class PebbleIoThread extends GBDeviceIoThread {
@ -471,6 +469,9 @@ public class BluetoothCommunicationService extends Service {
private ZipInputStream mmZis = null; private ZipInputStream mmZis = null;
private STM32CRC mmSTM32CRC = new STM32CRC(); private STM32CRC mmSTM32CRC = new STM32CRC();
private PebbleAppInstallState mmInstallState = PebbleAppInstallState.UNKNOWN; private PebbleAppInstallState mmInstallState = PebbleAppInstallState.UNKNOWN;
private String[] mmFilesToInstall = null;
private int mmCurrentFileIndex = -1;
private int mmInstallSlot = -1;
public PebbleIoThread(String btDeviceAddress) { public PebbleIoThread(String btDeviceAddress) {
super(btDeviceAddress); super(btDeviceAddress);
@ -514,10 +515,33 @@ public class BluetoothCommunicationService extends Service {
case APP_START_INSTALL: case APP_START_INSTALL:
Log.i(TAG, "start installing app binary"); Log.i(TAG, "start installing app binary");
mmSTM32CRC.reset(); mmSTM32CRC.reset();
mmPBWReader = new PBWReader(mmInstallURI, getApplicationContext()); if (mmPBWReader == null) {
mmZis = mmPBWReader.getInputStreamAppBinary(); mmPBWReader = new PBWReader(mmInstallURI, getApplicationContext());
int binarySize = mmPBWReader.getAppBinarySize(); mmFilesToInstall = mmPBWReader.getFilesToInstall();
writeInstallApp(mmPebbleProtocol.encodeUploadStart(PebbleProtocol.PUTBYTES_TYPE_BINARY, mGBDevice.getFreeAppSlot(), binarySize), -1); 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; mmInstallState = PebbleAppInstallState.APP_WAIT_TOKEN;
break; break;
case APP_WAIT_TOKEN: case APP_WAIT_TOKEN:
@ -540,24 +564,33 @@ public class BluetoothCommunicationService extends Service {
continue; continue;
} }
break; break;
case APP_UPLOAD_COMMIT: case APP_UPLOAD_COMMIT:
writeInstallApp(mmPebbleProtocol.encodeUploadCommit(mmAppInstallToken, mmSTM32CRC.getResult()),-1); writeInstallApp(mmPebbleProtocol.encodeUploadCommit(mmAppInstallToken, mmSTM32CRC.getResult()), -1);
mmAppInstallToken = -1; mmAppInstallToken = -1;
mmInstallState = PebbleAppInstallState.APP_WAIT_COMMMIT; mmInstallState = PebbleAppInstallState.APP_WAIT_COMMMIT;
break; break;
case APP_WAIT_COMMMIT: case APP_WAIT_COMMMIT:
if (mmAppInstallToken != -1) { if (mmAppInstallToken != -1) {
Log.i(TAG, "got token " + mmAppInstallToken); Log.i(TAG, "got token " + mmAppInstallToken);
mmInstallState = PebbleAppInstallState.APP_UPLOAD_COMPLETE; mmInstallState = PebbleAppInstallState.APP_UPLOAD_COMPLETE;
continue; continue;
} }
break; break;
case APP_UPLOAD_COMPLETE: case APP_UPLOAD_COMPLETE:
writeInstallApp(mmPebbleProtocol.encodeUploadComplete(mmAppInstallToken),-1); writeInstallApp(mmPebbleProtocol.encodeUploadComplete(mmAppInstallToken), -1);
mmInstallState = PebbleAppInstallState.UNKNOWN; 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; mmIsInstalling = false;
mmZis = null; mmZis = null;
mmAppInstallToken = -1; mmAppInstallToken = -1;
mmInstallSlot = -1;
break; break;
default: default:
break; 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; mmInstallState = PebbleAppInstallState.APP_START_INSTALL;
mmIsInstalling = true;
mmInstallURI = uri; mmInstallURI = uri;
mmInstallSlot = slot;
mmIsInstalling = true;
} }
public void quit() { public void quit() {

View File

@ -12,6 +12,7 @@ import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
@ -21,6 +22,7 @@ public class PBWReader {
private GBDeviceApp app; private GBDeviceApp app;
private final Uri uri; private final Uri uri;
private final ContentResolver cr; private final ContentResolver cr;
private ArrayList<String> filesToInstall;
public PBWReader(Uri uri, Context context) { public PBWReader(Uri uri, Context context) {
this.uri = uri; this.uri = uri;
@ -36,9 +38,13 @@ public class PBWReader {
} }
ZipInputStream zis = new ZipInputStream(fin); ZipInputStream zis = new ZipInputStream(fin);
ZipEntry ze = null; ZipEntry ze = null;
filesToInstall = new ArrayList<String>();
try { try {
while ((ze = zis.getNextEntry()) != null) { 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(); long bytes = ze.getSize();
if (bytes > 8192) // that should be too much if (bytes > 8192) // that should be too much
break; break;
@ -127,28 +133,8 @@ public class PBWReader {
return -1; return -1;
} }
public ZipInputStream getInputStreamAppBinary() { public String[] getFilesToInstall() {
return getInputStreamFile("pebble-app.bin"); return filesToInstall.toArray(new String[filesToInstall.size()]);
}
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");
} }
} }

View File

@ -34,8 +34,8 @@ public class PebbleAppInstallerActivity extends Activity {
debugTextView.setText("contents:\n"); debugTextView.setText("contents:\n");
final Uri uri = getIntent().getData(); final Uri uri = getIntent().getData();
PBWReader pbwReader = new PBWReader(uri, getApplicationContext()); PBWReader pbwReader = new PBWReader(uri, getApplicationContext());
GBDeviceApp app = pbwReader.getGBDeviceApp(); GBDeviceApp app = pbwReader.getGBDeviceApp();
if (pbwReader != null && app != null) { 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"); 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); installButton.setEnabled(true);

View File

@ -71,6 +71,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
static final byte APPMANAGER_GETAPPBANKSTATUS = 1; static final byte APPMANAGER_GETAPPBANKSTATUS = 1;
static final byte APPMANAGER_REMOVEAPP = 2; static final byte APPMANAGER_REMOVEAPP = 2;
static final byte APPMANAGER_REFRESHAPP = 3;
static final int APPMANAGER_RES_SUCCESS = 1; 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_FIRMWARE = 1;
static final byte PUTBYTES_TYPE_RECOVERY = 2; static final byte PUTBYTES_TYPE_RECOVERY = 2;
static final byte PUTBYTES_TYPE_SYSRESOURCES = 3; 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; public static final byte PUTBYTES_TYPE_BINARY = 5;
static final byte PUTBYTES_TYPE_FILE = 6; 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_MAGIC = 2; // increase this if pebble complains
static final byte PHONEVERSION_APPVERSION_MAJOR = 2; 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 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_TELEPHONY = 0x00000010;
static final int PHONEVERSION_REMOTE_CAPS_SMS = 0x00000020; 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_PREFIX = 4;
static final short LENGTH_SETTIME = 5; static final short LENGTH_SETTIME = 5;
static final short LENGTH_REMOVEAPP = 9; static final short LENGTH_REMOVEAPP = 9;
static final short LENGTH_REFRESHAPP = 5;
static final short LENGTH_PHONEVERSION = 17; static final short LENGTH_PHONEVERSION = 17;
static final short LENGTH_UPLOADSTART = 7; static final short LENGTH_UPLOADSTART = 7;
static final short LENGTH_UPLOADCHUNK = 9; static final short LENGTH_UPLOADCHUNK = 9;
@ -329,6 +331,16 @@ public class PebbleProtocol extends GBDeviceProtocol {
return buf.array(); 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) { public GBDeviceCommand decodeResponse(byte[] responseData) {
ByteBuffer buf = ByteBuffer.wrap(responseData); ByteBuffer buf = ByteBuffer.wrap(responseData);