Pebble: Implement WIP outbound communication with PebbleKit Android Apps
This improves #106 Pebblebike aka Ventoo works to some extent sometimes now ;)
This commit is contained in:
parent
502c005a0e
commit
a5ef952e37
|
@ -0,0 +1,9 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.deviceevents;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class GBDeviceEventAppMessage extends GBDeviceEvent {
|
||||
public UUID appUUID;
|
||||
public int id;
|
||||
public String message;
|
||||
}
|
|
@ -32,6 +32,7 @@ import nodomain.freeyourgadget.gadgetbridge.R;
|
|||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagement;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppMessage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PBWReader;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleInstallable;
|
||||
|
@ -92,10 +93,11 @@ public class PebbleIoThread extends GBDeviceIoThread {
|
|||
case PEBBLEKIT_ACTION_APP_STOP:
|
||||
uuid = (UUID) intent.getSerializableExtra("uuid");
|
||||
if (uuid != null) {
|
||||
write(mPebbleProtocol.encodeAppStart(uuid, action == PEBBLEKIT_ACTION_APP_START));
|
||||
write(mPebbleProtocol.encodeAppStart(uuid, action.equals(PEBBLEKIT_ACTION_APP_START)));
|
||||
}
|
||||
break;
|
||||
case PEBBLEKIT_ACTION_APP_SEND:
|
||||
int transaction_id = intent.getIntExtra("transaction_id", -1);
|
||||
uuid = (UUID) intent.getSerializableExtra("uuid");
|
||||
String jsonString = intent.getStringExtra("msg_data");
|
||||
LOG.info("json string: " + jsonString);
|
||||
|
@ -103,14 +105,48 @@ public class PebbleIoThread extends GBDeviceIoThread {
|
|||
try {
|
||||
JSONArray jsonArray = new JSONArray(jsonString);
|
||||
write(mPebbleProtocol.encodeApplicationMessageFromJSON(uuid, jsonArray));
|
||||
sendAppMessageAck(transaction_id);
|
||||
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
case PEBBLEKIT_ACTION_APP_ACK:
|
||||
// we do not get a uuid and cannot map a transaction id to it, so we ack in PebbleProtocol early
|
||||
/*
|
||||
uuid = (UUID) intent.getSerializableExtra("uuid");
|
||||
int transaction_id = intent.getIntExtra("transaction_id", -1);
|
||||
if (transaction_id >= 0 && transaction_id <= 255) {
|
||||
write(mPebbleProtocol.encodeApplicationMessageAck(uuid, (byte) transaction_id));
|
||||
} else {
|
||||
LOG.warn("illegal transacktion id " + transaction_id);
|
||||
}
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void sendAppMessageIntent(GBDeviceEventAppMessage appMessage) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(PEBBLEKIT_ACTION_APP_RECEIVE);
|
||||
intent.putExtra("uuid", appMessage.appUUID);
|
||||
intent.putExtra("msg_data", appMessage.message);
|
||||
intent.putExtra("transaction_id", appMessage.id);
|
||||
LOG.info("broadcasting to uuid " + appMessage.appUUID + " transaction id: " + appMessage.id + " JSON: " + appMessage.message);
|
||||
getContext().sendBroadcast(intent);
|
||||
}
|
||||
|
||||
private void sendAppMessageAck(int transactionId) {
|
||||
if (transactionId > 0 && transactionId <= 255) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(PEBBLEKIT_ACTION_APP_RECEIVE_ACK);
|
||||
intent.putExtra("transaction_id", transactionId);
|
||||
LOG.info("broadcasting ACK (transaction id " + transactionId + ")");
|
||||
getContext().sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public PebbleIoThread(PebbleSupport pebbleSupport, GBDevice gbDevice, GBDeviceProtocol gbDeviceProtocol, BluetoothAdapter btAdapter, Context context) {
|
||||
super(gbDevice, context);
|
||||
mPebbleProtocol = (PebbleProtocol) gbDeviceProtocol;
|
||||
|
@ -347,14 +383,9 @@ public class PebbleIoThread extends GBDeviceIoThread {
|
|||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(PEBBLEKIT_ACTION_APP_ACK);
|
||||
intentFilter.addAction(PEBBLEKIT_ACTION_APP_NACK);
|
||||
intentFilter.addAction(PEBBLEKIT_ACTION_APP_RECEIVE);
|
||||
intentFilter.addAction(PEBBLEKIT_ACTION_APP_RECEIVE_ACK);
|
||||
intentFilter.addAction(PEBBLEKIT_ACTION_APP_RECEIVE_NACK);
|
||||
intentFilter.addAction(PEBBLEKIT_ACTION_APP_SEND);
|
||||
intentFilter.addAction(PEBBLEKIT_ACTION_APP_START);
|
||||
intentFilter.addAction(PEBBLEKIT_ACTION_APP_STOP);
|
||||
intentFilter.addAction(PEBBLEKIT_ACTION_PEBBLE_CONNECTED);
|
||||
intentFilter.addAction(PEBBLEKIT_ACTION_PEBBLE_DISCONNECTED);
|
||||
try {
|
||||
getContext().registerReceiver(mPebbleKitReceiver, intentFilter);
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
@ -475,7 +506,13 @@ public class PebbleIoThread extends GBDeviceIoThread {
|
|||
GBDeviceEventAppInfo appInfoEvent = (GBDeviceEventAppInfo) deviceEvent;
|
||||
setInstallSlot(appInfoEvent.freeSlot);
|
||||
return false;
|
||||
} else if (deviceEvent instanceof GBDeviceEventAppMessage) {
|
||||
if (sharedPrefs.getBoolean("pebble_force_untested", false)) {
|
||||
LOG.info("Got AppMessage event");
|
||||
sendAppMessageIntent((GBDeviceEventAppMessage) deviceEvent);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.UUID;
|
|||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagement;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppMessage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificationControl;
|
||||
|
@ -189,8 +190,8 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
|
||||
static final byte TYPE_BYTEARRAY = 0;
|
||||
static final byte TYPE_CSTRING = 1;
|
||||
static final byte TYPE_UINT32 = 2;
|
||||
static final byte TYPE_INT32 = 3;
|
||||
static final byte TYPE_UINT = 2;
|
||||
static final byte TYPE_INT = 3;
|
||||
|
||||
static final short LENGTH_PREFIX = 4;
|
||||
static final short LENGTH_SIMPLEMESSAGE = 1;
|
||||
|
@ -1123,10 +1124,10 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
while (dictSize-- > 0) {
|
||||
Integer key = buf.getInt();
|
||||
byte type = buf.get();
|
||||
short length = buf.getShort(); // length
|
||||
short length = buf.getShort();
|
||||
switch (type) {
|
||||
case TYPE_INT32:
|
||||
case TYPE_UINT32:
|
||||
case TYPE_INT:
|
||||
case TYPE_UINT:
|
||||
dict.add(new Pair<Integer, Object>(key, buf.getInt()));
|
||||
break;
|
||||
case TYPE_CSTRING:
|
||||
|
@ -1145,6 +1146,72 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
return dict;
|
||||
}
|
||||
|
||||
private GBDeviceEvent[] decodeDictToJSONAppMessage(UUID uuid, ByteBuffer buf) throws JSONException {
|
||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||
byte dictSize = buf.get();
|
||||
if (dictSize == 0) {
|
||||
LOG.info("dict size is 0, ignoring");
|
||||
return null;
|
||||
}
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
while (dictSize-- > 0) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
Integer key = buf.getInt();
|
||||
byte type = buf.get();
|
||||
short length = buf.getShort();
|
||||
jsonObject.put("key", key);
|
||||
jsonObject.put("length", length);
|
||||
switch (type) {
|
||||
case TYPE_UINT:
|
||||
jsonObject.put("type", "uint");
|
||||
if (length == 1) {
|
||||
jsonObject.put("value", buf.get() & 0xff);
|
||||
} else if (length == 2) {
|
||||
jsonObject.put("value", buf.getShort() & 0xffff);
|
||||
} else {
|
||||
jsonObject.put("value", buf.getInt() & 0xffffffffL);
|
||||
}
|
||||
break;
|
||||
case TYPE_INT:
|
||||
jsonObject.put("type", "int");
|
||||
if (length == 1) {
|
||||
jsonObject.put("value", buf.get());
|
||||
} else if (length == 2) {
|
||||
jsonObject.put("value", buf.getShort());
|
||||
} else {
|
||||
jsonObject.put("value", buf.getInt());
|
||||
}
|
||||
break;
|
||||
case TYPE_BYTEARRAY:
|
||||
case TYPE_CSTRING:
|
||||
byte[] bytes = new byte[length];
|
||||
buf.get(bytes);
|
||||
if (type == TYPE_BYTEARRAY) {
|
||||
jsonObject.put("type", "bytes");
|
||||
jsonObject.put("value", Base64.encode(bytes, Base64.NO_WRAP));
|
||||
} else {
|
||||
jsonObject.put("type", "string");
|
||||
jsonObject.put("value", Arrays.toString(bytes));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG.info("unknown type in appmessage, ignoring");
|
||||
return null;
|
||||
}
|
||||
jsonArray.put(jsonObject);
|
||||
}
|
||||
|
||||
// this is a hack we send an ack to the Pebble immediately because we cannot map the transaction_id from the intent back to a uuid yet
|
||||
GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes();
|
||||
sendBytesAck.encodedBytes = encodeApplicationMessageAck(uuid, last_id);
|
||||
|
||||
GBDeviceEventAppMessage appMessage = new GBDeviceEventAppMessage();
|
||||
appMessage.appUUID = uuid;
|
||||
appMessage.id = last_id & 0xff;
|
||||
appMessage.message = jsonArray.toString();
|
||||
return new GBDeviceEvent[]{appMessage, sendBytesAck};
|
||||
}
|
||||
|
||||
byte[] encodeApplicationMessagePush(short endpoint, UUID uuid, ArrayList<Pair<Integer, Object>> pairs) {
|
||||
int length = LENGTH_UUID + 3; // UUID + (PUSH + id + length of dict)
|
||||
for (Pair<Integer, Object> pair : pairs) {
|
||||
|
@ -1172,7 +1239,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
for (Pair<Integer, Object> pair : pairs) {
|
||||
buf.putInt(pair.first);
|
||||
if (pair.second instanceof Integer) {
|
||||
buf.put(TYPE_INT32);
|
||||
buf.put(TYPE_INT);
|
||||
buf.putShort((short) 4); // length of int
|
||||
buf.putInt((int) pair.second);
|
||||
} else if (pair.second instanceof String) {
|
||||
|
@ -1599,6 +1666,13 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
} else if (GadgetbridgePblSupport.uuid.equals(uuid)) {
|
||||
ArrayList<Pair<Integer, Object>> dict = decodeDict(buf);
|
||||
devEvts = mGadgetbridgePblSupport.handleMessage(dict);
|
||||
} else {
|
||||
try {
|
||||
devEvts = decodeDictToJSONAppMessage(uuid, buf);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case APPLICATIONMESSAGE_ACK:
|
||||
|
|
Loading…
Reference in New Issue