Pebble: try to install app metadata on FW 3.x (untested)

live-activity-data
Andreas Shimokawa 2015-08-14 12:50:44 +02:00
parent 2e3de0cd0f
commit e28d6fa7cb
4 changed files with 108 additions and 15 deletions

View File

@ -70,7 +70,7 @@ public class PBWInstallHandler implements InstallHandler {
}
GBDeviceApp app = mPBWReader.getGBDeviceApp();
File pbwFile = new File(mPBWReader.getUri().getPath());
File pbwFile = new File(mUri.getPath());
try {
File destDir = new File(FileUtils.getExternalFilesDir() + "/pbw-cache");
destDir.mkdirs();

View File

@ -14,6 +14,8 @@ import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@ -50,6 +52,10 @@ public class PBWReader {
private boolean isFirmware = false;
private boolean isValid = false;
private String hwRevision = null;
private short mSdkVersion;
private short mAppVersion;
private int mIconId;
private int mFlags;
public PBWReader(Uri uri, Context context, String platform) {
String platformDir = "";
@ -70,7 +76,7 @@ public class PBWReader {
}
ZipInputStream zis = new ZipInputStream(fin);
ZipEntry ze;
pebbleInstallables = new ArrayList<PebbleInstallable>();
pebbleInstallables = new ArrayList<>();
byte[] buffer = new byte[1024];
int count;
try {
@ -149,6 +155,26 @@ public class PBWReader {
e.printStackTrace();
break;
}
} else if (fileName.equals(platformDir + "pebble-app.bin")) {
zis.read(buffer, 0, 108);
byte[] tmp_buf = new byte[32];
ByteBuffer buf = ByteBuffer.wrap(buffer);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.getLong(); // header, TODO: verifiy
buf.getShort(); // struct version, TODO: verify
mSdkVersion = buf.getShort();
mAppVersion = buf.getShort();
buf.getShort(); // size
buf.getInt(); // offset
buf.getInt(); // crc
buf.get(tmp_buf, 0, 32); // app name
buf.get(tmp_buf, 0, 32); // author
mIconId = buf.getInt();
LOG.info("got icon id from pebble-app.bin: " + mIconId);
buf.getInt(); // symbol table addr
mFlags = buf.getInt();
LOG.info("got flags from pebble-app.bin: " + mFlags);
// more follows but, not interesting for us
}
}
zis.close();
@ -206,7 +232,19 @@ public class PBWReader {
return hwRevision;
}
public Uri getUri() {
return uri;
public short getSdkVersion() {
return mSdkVersion;
}
public short getAppVersion() {
return mAppVersion;
}
public int getFlags() {
return mFlags;
}
public int getIconId() {
return mIconId;
}
}

View File

@ -26,6 +26,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagem
import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PBWReader;
import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleInstallable;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
import nodomain.freeyourgadget.gadgetbridge.service.bt.GBDeviceIoThread;
import nodomain.freeyourgadget.gadgetbridge.service.bt.GBDeviceProtocol;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
@ -42,8 +43,7 @@ public class PebbleIoThread extends GBDeviceIoThread {
private boolean mIsConnected = false;
private boolean mIsInstalling = false;
private int mConnectionAttempts = 0;
/* app installation */
private Uri mInstallURI = null;
private boolean mForceUntested = false;
private PBWReader mPBWReader = null;
private int mAppInstallToken = -1;
private ZipInputStream mZis = null;
@ -84,7 +84,7 @@ public class PebbleIoThread extends GBDeviceIoThread {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
mPebbleProtocol.setForceProtocol(sharedPrefs.getBoolean("pebble_force_protocol", false));
mForceUntested = sharedPrefs.getBoolean("pebble_force_untested", false);
gbDevice.setState(GBDevice.State.CONNECTED);
gbDevice.sendDeviceUpdateIntent(getContext());
@ -375,9 +375,8 @@ public class PebbleIoThread extends GBDeviceIoThread {
return;
}
mIsInstalling = true;
mInstallURI = uri;
mPBWReader = new PBWReader(mInstallURI, getContext(), gbDevice.getHardwareVersion().equals("dvt") ? "basalt" : "aplite");
mPBWReader = new PBWReader(uri, getContext(), gbDevice.getHardwareVersion().equals("dvt") ? "basalt" : "aplite");
mPebbleInstallables = mPBWReader.getPebbleInstallables();
mCurrentInstallableIndex = 0;
@ -399,8 +398,12 @@ public class PebbleIoThread extends GBDeviceIoThread {
mInstallSlot = 0;
mInstallState = PebbleAppInstallState.START_INSTALL;
} else {
writeInstallApp(mPebbleProtocol.encodeAppDelete(mPBWReader.getGBDeviceApp().getUUID()));
GBDeviceApp app = mPBWReader.getGBDeviceApp();
writeInstallApp(mPebbleProtocol.encodeAppDelete(app.getUUID()));
mInstallState = PebbleAppInstallState.WAIT_SLOT;
if (mPebbleProtocol.isFw3x && mForceUntested) {
writeInstallApp(mPebbleProtocol.encodeInstallMetadata(app.getUUID(), app.getName(), mPBWReader.getAppVersion(), mPBWReader.getSdkVersion()));
}
}
}

View File

@ -61,6 +61,15 @@ public class PebbleProtocol extends GBDeviceProtocol {
static final byte APPRUNSTATE_START = 1;
static final byte BLOBDB_INSERT = 1;
static final byte BLOBDB_DELETE = 4;
static final byte BLOBDB_CLEAR = 5;
static final byte BLOBDB_PIN = 1;
static final byte BLOBDB_APP = 2;
static final byte BLOBDB_REMINDER = 3;
static final byte BLOBDB_NOTIFICATION = 4;
static final byte NOTIFICATION_EMAIL = 0;
static final byte NOTIFICATION_SMS = 1;
static final byte NOTIFICATION_TWITTER = 2;
@ -179,6 +188,8 @@ public class PebbleProtocol extends GBDeviceProtocol {
static final short LENGTH_UPLOADCOMPLETE = 5;
static final short LENGTH_UPLOADCANCEL = 5;
static final byte LENGTH_UUID = 16;
private static final String[] hwRevisions = {"unknown", "ev1", "ev2", "ev2_3", "ev2_4", "v1_5", "v2_0", "evt2", "dvt"};
private static Random mRandom = new Random();
@ -406,11 +417,11 @@ public class PebbleProtocol extends GBDeviceProtocol {
buf.order(ByteOrder.LITTLE_ENDIAN);
// blobdb - 23 bytes
buf.put((byte) 0x01); // insert
buf.put(BLOBDB_INSERT);
buf.putShort((short) mRandom.nextInt()); // token
buf.put((byte) 0x04); // db id (0x04 = notification)
buf.put((byte) 16); // uuid length
byte[] uuid_buf = new byte[16];
buf.put(BLOBDB_NOTIFICATION);
buf.put(LENGTH_UUID); // uuid length
byte[] uuid_buf = new byte[LENGTH_UUID];
mRandom.nextBytes(uuid_buf);
buf.put(uuid_buf); // random UUID
buf.putShort(pin_length); // length of the encapsulated data
@ -458,6 +469,47 @@ public class PebbleProtocol extends GBDeviceProtocol {
return buf.array();
}
public byte[] encodeInstallMetadata(UUID uuid, String appName, short appVersion, short sdkVersion) {
// Calculate length first
final short BLOBDB_LENGTH = 23;
final short METADATA_LENGTH = 126;
final short length = (short) (BLOBDB_LENGTH + METADATA_LENGTH);
byte[] name_buf = new byte[96];
System.arraycopy(appName.getBytes(), 0, name_buf, 0, appName.length());
ByteBuffer buf = ByteBuffer.allocate(length + LENGTH_PREFIX);
// Encode Prefix
buf.order(ByteOrder.BIG_ENDIAN);
buf.putShort(length);
buf.putShort(ENDPOINT_BLOBDB);
buf.order(ByteOrder.LITTLE_ENDIAN);
// blobdb - 23 bytes
buf.put(BLOBDB_INSERT); // insert
buf.putShort((short) mRandom.nextInt()); // token
buf.put(BLOBDB_APP);
buf.put(LENGTH_UUID);
buf.order(ByteOrder.BIG_ENDIAN);
buf.putLong(uuid.getMostSignificantBits()); // watchapp uuid
buf.putLong(uuid.getLeastSignificantBits());
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.putShort(METADATA_LENGTH); // length of the encapsulated data
buf.order(ByteOrder.BIG_ENDIAN);
buf.putLong(uuid.getMostSignificantBits()); // watchapp uuid
buf.putLong(uuid.getLeastSignificantBits());
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.putInt(1); // icon_id
buf.putShort(appVersion);
buf.putShort(sdkVersion);
buf.put((byte) 0); // app_face_bgcolor
buf.put((byte) 0); // app_face_template_id
buf.put(name_buf); // 96 bytes
return buf.array();
}
public byte[] encodeGetTime() {
return encodeSimpleMessage(ENDPOINT_TIME, TIME_GETTIME);
}
@ -762,7 +814,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
}
byte[] encodeApplicationMessagePush(short endpoint, UUID uuid, ArrayList<Pair<Integer, Object>> pairs) {
int length = 16 + 3; // UUID + (PUSH + id + length of dict)
int length = LENGTH_UUID + 3; // UUID + (PUSH + id + length of dict)
for (Pair<Integer, Object> pair : pairs) {
length += 7; // key + type + length
if (pair.second instanceof Integer) {