Pebble: WIP support for flashing language files (.pbl)

NOTES:
- YOU SHOULD NOT TRY THIS YET ;)
- This was only tested with the unoffical japansese language pack
- Problably needs proper crc calculation (I just hardcoded the one for the japanese language pack)
here
Andreas Shimokawa 2015-10-06 23:56:01 +09:00
parent 7dce1d62b0
commit 5860c4f4f9
5 changed files with 64 additions and 19 deletions

View File

@ -125,6 +125,7 @@
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbz" />
<data android:pathPattern="/.*\\.pbl" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@ -170,6 +171,7 @@
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbz" />
<data android:pathPattern="/.*\\.pbl" />
</intent-filter>
<!-- to receive the firmwares from the donwload content provider -->

View File

@ -41,7 +41,7 @@ public class MiBandFWHelper {
this.uri = uri;
cr = context.getContentResolver();
String pebblePattern = ".*\\.(pbw|pbz)";
String pebblePattern = ".*\\.(pbw|pbz|pbl)";
if (uri.getPath().matches(pebblePattern)) {
throw new IOException("Firmware has a filename that looks like a Pebble app/firmware.");

View File

@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@ -50,6 +51,7 @@ public class PBWReader {
private GBDeviceApp app;
private ArrayList<PebbleInstallable> pebbleInstallables;
private boolean isFirmware = false;
private boolean isLanguage = false;
private boolean isValid = false;
private String hwRevision = null;
private short mSdkVersion;
@ -58,14 +60,25 @@ public class PBWReader {
private int mFlags;
public PBWReader(Uri uri, Context context, String platform) {
this.uri = uri;
cr = context.getContentResolver();
if (uri.toString().endsWith(".pbl") && platform.equals("aplite")) {
// language file
app = new GBDeviceApp(UUID.randomUUID(), "Language File", "unknown", "unknown", GBDeviceApp.Type.UNKNOWN);
File f = new File(uri.getPath());
pebbleInstallables = new ArrayList<>();
pebbleInstallables.add(new PebbleInstallable("lang", (int) f.length(), (int)4218691521L, PebbleProtocol.PUTBYTES_TYPE_FILE));
isValid = true;
isLanguage = true;
return;
}
String platformDir = "";
if (!uri.toString().endsWith(".pbz") && !platform.equals("aplite")) {
platformDir = platform + "/";
}
this.uri = uri;
cr = context.getContentResolver();
InputStream fin;
try {
fin = new BufferedInputStream(cr.openInputStream(uri));
@ -186,6 +199,10 @@ public class PBWReader {
return isFirmware;
}
public boolean isLanguage() {
return isLanguage;
}
public boolean isValid() {
return isValid;
}
@ -194,11 +211,13 @@ public class PBWReader {
return app;
}
public ZipInputStream getInputStreamFile(String filename) {
public InputStream getInputStreamFile(String filename) {
InputStream fin;
try {
fin = new BufferedInputStream(cr.openInputStream(uri));
if (isLanguage) {
return fin;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;

View File

@ -26,7 +26,6 @@ import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.UUID;
import java.util.zip.ZipInputStream;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
@ -75,7 +74,7 @@ public class PebbleIoThread extends GBDeviceIoThread {
private PBWReader mPBWReader = null;
private int mAppInstallToken = -1;
private ZipInputStream mZis = null;
private InputStream mFis = null;
private PebbleAppInstallState mInstallState = PebbleAppInstallState.UNKNOWN;
private PebbleInstallable[] mPebbleInstallables = null;
private int mCurrentInstallableIndex = -1;
@ -223,11 +222,11 @@ public class PebbleIoThread extends GBDeviceIoThread {
case START_INSTALL:
LOG.info("start installing app binary");
PebbleInstallable pi = mPebbleInstallables[mCurrentInstallableIndex];
mZis = mPBWReader.getInputStreamFile(pi.getFileName());
mFis = mPBWReader.getInputStreamFile(pi.getFileName());
mCRC = pi.getCRC();
mBinarySize = pi.getFileSize();
mBytesWritten = 0;
writeInstallApp(mPebbleProtocol.encodeUploadStart(pi.getType(), mInstallSlot, mBinarySize));
writeInstallApp(mPebbleProtocol.encodeUploadStart(pi.getType(), mInstallSlot, mBinarySize, mPBWReader.isLanguage() ? "lang" : null));
mAppInstallToken = -1;
mInstallState = PebbleAppInstallState.WAIT_TOKEN;
break;
@ -241,7 +240,7 @@ public class PebbleIoThread extends GBDeviceIoThread {
case UPLOAD_CHUNK:
int bytes = 0;
do {
int read = mZis.read(buffer, bytes, 2000 - bytes);
int read = mFis.read(buffer, bytes, 2000 - bytes);
if (read <= 0) break;
bytes += read;
} while (bytes < 2000);
@ -285,7 +284,12 @@ public class PebbleIoThread extends GBDeviceIoThread {
} else if (mPebbleProtocol.isFw3x) {
finishInstall(false); // FIXME: dont know yet how to detect success
} else {
writeInstallApp(mPebbleProtocol.encodeAppRefresh(mInstallSlot));
if (mPBWReader.isLanguage()) {
finishInstall(false);
write(mPebbleProtocol.encodeReboot());
} else {
writeInstallApp(mPebbleProtocol.encodeAppRefresh(mInstallSlot));
}
}
break;
default:
@ -589,8 +593,16 @@ public class PebbleIoThread extends GBDeviceIoThread {
}
} else {
mIsInstalling = true;
mInstallState = PebbleAppInstallState.WAIT_SLOT;
writeInstallApp(mPebbleProtocol.encodeAppDelete(app.getUUID()));
if (mPBWReader.isLanguage()) {
mInstallSlot = 0;
mInstallState = PebbleAppInstallState.START_INSTALL;
// unblock HACK
writeInstallApp(mPebbleProtocol.encodeGetTime());
} else {
mInstallState = PebbleAppInstallState.WAIT_SLOT;
writeInstallApp(mPebbleProtocol.encodeAppDelete(app.getUUID()));
}
}
}
}
@ -612,14 +624,14 @@ public class PebbleIoThread extends GBDeviceIoThread {
mPBWReader = null;
mIsInstalling = false;
if (mZis != null) {
if (mFis != null) {
try {
mZis.close();
mFis.close();
} catch (IOException e) {
// ignore
}
}
mZis = null;
mFis = null;
mAppInstallToken = -1;
mInstallSlot = -2;
}

View File

@ -155,7 +155,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
public static final byte PUTBYTES_TYPE_SYSRESOURCES = 3;
public static final byte PUTBYTES_TYPE_RESOURCES = 4;
public static final byte PUTBYTES_TYPE_BINARY = 5;
static final byte PUTBYTES_TYPE_FILE = 6;
public static final byte PUTBYTES_TYPE_FILE = 6;
public static final byte PUTBYTES_TYPE_WORKER = 7;
static final byte RESET_REBOOT = 0;
@ -1027,7 +1027,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
}
/* pebble specific install methods */
public byte[] encodeUploadStart(byte type, int app_id, int size) {
public byte[] encodeUploadStart(byte type, int app_id, int size, String filename) {
short length;
if (isFw3x) {
length = LENGTH_UPLOADSTART_3X;
@ -1035,6 +1035,11 @@ public class PebbleProtocol extends GBDeviceProtocol {
} else {
length = LENGTH_UPLOADSTART_2X;
}
if (type == PUTBYTES_TYPE_FILE && filename != null) {
length += filename.getBytes().length + 1;
}
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + length);
buf.order(ByteOrder.BIG_ENDIAN);
buf.putShort(length);
@ -1042,12 +1047,19 @@ public class PebbleProtocol extends GBDeviceProtocol {
buf.put(PUTBYTES_INIT);
buf.putInt(size);
buf.put(type);
if (isFw3x) {
buf.putInt(app_id);
} else {
// slot
buf.put((byte) app_id);
}
if (type == PUTBYTES_TYPE_FILE && filename != null) {
buf.put(filename.getBytes());
buf.put((byte) 0);
}
return buf.array();
}