GBDeviceProtocol::decodeResponse() now returns an array GBDeviceEvents

This allowed to remove some ugly hacks from pebble code,  when encoding a
response in a GBDeviceEventSendBytes  and at the same time trying to notify
generic code via another GBDeviceEnvent.
live-activity-data
Andreas Shimokawa 2015-08-27 15:02:29 +02:00
parent 027e6fe8c3
commit 44c7f99c58
6 changed files with 104 additions and 90 deletions

View File

@ -33,7 +33,7 @@ public class GadgetbridgePblSupport {
mPebbleProtocol = pebbleProtocol; mPebbleProtocol = pebbleProtocol;
} }
public GBDeviceEvent handleMessage(ArrayList<Pair<Integer, Object>> pairs) { public GBDeviceEvent[] handleMessage(ArrayList<Pair<Integer, Object>> pairs) {
int timestamp = 0; int timestamp = 0;
for (Pair<Integer, Object> pair : pairs) { for (Pair<Integer, Object> pair : pairs) {
switch (pair.first) { switch (pair.first) {
@ -75,6 +75,6 @@ public class GadgetbridgePblSupport {
} }
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
sendBytes.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(uuid, mPebbleProtocol.last_id); sendBytes.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(uuid, mPebbleProtocol.last_id);
return sendBytes; return new GBDeviceEvent[]{sendBytes};
} }
} }

View File

@ -5,7 +5,6 @@ import android.util.Pair;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.SimpleTimeZone; import java.util.SimpleTimeZone;
import java.util.TimeZone; import java.util.TimeZone;
@ -41,7 +40,6 @@ public class MorpheuzSupport {
public static final UUID uuid = UUID.fromString("5be44f1d-d262-4ea6-aa30-ddbec1e3cab2"); public static final UUID uuid = UUID.fromString("5be44f1d-d262-4ea6-aa30-ddbec1e3cab2");
private final PebbleProtocol mPebbleProtocol; private final PebbleProtocol mPebbleProtocol;
private boolean sent_to_gadgetbridge = false;
// data received from Morpheuz in native format // data received from Morpheuz in native format
private int smartalarm_from = -1; // time in minutes relative from 0:00 for smart alarm (earliest) private int smartalarm_from = -1; // time in minutes relative from 0:00 for smart alarm (earliest)
private int smartalarm_to = -1;// time in minutes relative from 0:00 for smart alarm (latest) private int smartalarm_to = -1;// time in minutes relative from 0:00 for smart alarm (latest)
@ -57,21 +55,15 @@ public class MorpheuzSupport {
private byte[] encodeMorpheuzMessage(int key, int value) { private byte[] encodeMorpheuzMessage(int key, int value) {
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>(); ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>();
pairs.add(new Pair<Integer, Object>(key, value)); pairs.add(new Pair<Integer, Object>(key, value));
byte[] ackMessage = mPebbleProtocol.encodeApplicationMessageAck(uuid, mPebbleProtocol.last_id);
byte[] testMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, uuid, pairs);
ByteBuffer buf = ByteBuffer.allocate(ackMessage.length + testMessage.length); return mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, uuid, pairs);
// encode ack and put in front of push message (hack for acknowledging the last message)
buf.put(ackMessage);
buf.put(testMessage);
return buf.array();
} }
public GBDeviceEvent handleMessage(ArrayList<Pair<Integer, Object>> pairs) { public GBDeviceEvent[] handleMessage(ArrayList<Pair<Integer, Object>> pairs) {
int ctrl_message = 0;
GBDeviceEventSleepMonitorResult sleepMonitorResult = null;
for (Pair<Integer, Object> pair : pairs) { for (Pair<Integer, Object> pair : pairs) {
int ctrl_message = 0;
switch (pair.first) { switch (pair.first) {
case KEY_TRANSMIT: case KEY_TRANSMIT:
case KEY_GONEOFF: case KEY_GONEOFF:
@ -79,22 +71,11 @@ public class MorpheuzSupport {
alarm_gone_off = (int) pair.second; alarm_gone_off = (int) pair.second;
LOG.info("got gone off: " + alarm_gone_off / 60 + ":" + alarm_gone_off % 60); LOG.info("got gone off: " + alarm_gone_off / 60 + ":" + alarm_gone_off % 60);
} }
/* super-ugly hack: if if did not notice GadgetBridge yet, do so and delay confirmation so Morpheuz sleepMonitorResult = new GBDeviceEventSleepMonitorResult();
* will resend gone off data. The second time, we acknowledge it. sleepMonitorResult.smartalarm_from = smartalarm_from;
* sleepMonitorResult.smartalarm_to = smartalarm_to;
* this can be fixed by allowing to return multiple GBDeviceCommands sleepMonitorResult.alarm_gone_off = alarm_gone_off;
*/ sleepMonitorResult.recording_base_timestamp = recording_base_timestamp;
if (sent_to_gadgetbridge) {
ctrl_message = MorpheuzSupport.CTRL_VERSION_DONE | MorpheuzSupport.CTRL_GONEOFF_DONE | MorpheuzSupport.CTRL_TRANSMIT_DONE | MorpheuzSupport.CTRL_SET_LAST_SENT;
} else {
GBDeviceEventSleepMonitorResult sleepMonitorResult = new GBDeviceEventSleepMonitorResult();
sleepMonitorResult.smartalarm_from = smartalarm_from;
sleepMonitorResult.smartalarm_to = smartalarm_to;
sleepMonitorResult.alarm_gone_off = alarm_gone_off;
sleepMonitorResult.recording_base_timestamp = recording_base_timestamp;
sent_to_gadgetbridge = true;
return sleepMonitorResult;
}
break; break;
case KEY_POINT: case KEY_POINT:
if (recording_base_timestamp == -1) { if (recording_base_timestamp == -1) {
@ -140,7 +121,6 @@ public class MorpheuzSupport {
case KEY_VERSION: case KEY_VERSION:
LOG.info("got version: " + ((float) ((int) pair.second) / 10.0f)); LOG.info("got version: " + ((float) ((int) pair.second) / 10.0f));
ctrl_message = MorpheuzSupport.CTRL_VERSION_DONE | MorpheuzSupport.CTRL_SET_LAST_SENT; ctrl_message = MorpheuzSupport.CTRL_VERSION_DONE | MorpheuzSupport.CTRL_SET_LAST_SENT;
sent_to_gadgetbridge = false;
break; break;
case KEY_BASE: case KEY_BASE:
// fix timestamp // fix timestamp
@ -156,14 +136,20 @@ public class MorpheuzSupport {
LOG.info("unhandled key: " + pair.first); LOG.info("unhandled key: " + pair.first);
break; break;
} }
if (ctrl_message > 0) {
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
sendBytes.encodedBytes = encodeMorpheuzMessage(MorpheuzSupport.KEY_CTRL, ctrl_message);
return sendBytes;
}
} }
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
sendBytes.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(uuid, mPebbleProtocol.last_id); // always ack
return sendBytes; GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes();
sendBytesAck.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(uuid, mPebbleProtocol.last_id);
// sometimes send control message
GBDeviceEventSendBytes sendBytesCtrl = null;
if (ctrl_message > 0) {
sendBytesCtrl = new GBDeviceEventSendBytes();
sendBytesCtrl.encodedBytes = encodeMorpheuzMessage(MorpheuzSupport.KEY_CTRL, ctrl_message);
}
// ctrl and sleep monitor might be null, thats okay
return new GBDeviceEvent[]{sendBytesAck, sendBytesCtrl, sleepMonitorResult};
} }
} }

View File

@ -237,12 +237,17 @@ public class PebbleIoThread extends GBDeviceIoThread {
mInStream.skip(2); mInStream.skip(2);
} }
GBDeviceEvent deviceEvent = mPebbleProtocol.decodeResponse(buffer); GBDeviceEvent deviceEvents[] = mPebbleProtocol.decodeResponse(buffer);
if (deviceEvent == null) { if (deviceEvents == null) {
LOG.info("unhandled message to endpoint " + endpoint + " (" + length + " bytes)"); LOG.info("unhandled message to endpoint " + endpoint + " (" + length + " bytes)");
} else { } else {
if (!evaluateGBDeviceEventPebble(deviceEvent)) { for (GBDeviceEvent deviceEvent : deviceEvents) {
mPebbleSupport.evaluateGBDeviceEvent(deviceEvent); if (deviceEvent == null) {
continue;
}
if (!evaluateGBDeviceEventPebble(deviceEvent)) {
mPebbleSupport.evaluateGBDeviceEvent(deviceEvent);
}
} }
} }
try { try {

View File

@ -1059,15 +1059,31 @@ public class PebbleProtocol extends GBDeviceProtocol {
return null; return null;
} }
private GBDeviceEventDismissNotification decodeNotificationAction(ByteBuffer buf) { private GBDeviceEventDismissNotification decodeNotificationAction2x(ByteBuffer buf) {
buf.order(ByteOrder.LITTLE_ENDIAN); buf.order(ByteOrder.LITTLE_ENDIAN);
byte command = buf.get(); byte command = buf.get();
if (command == 0x02) { // dismiss notification ? if (command == 0x02) { // dismiss notification ?
if (isFw3x) { int id = buf.getInt();
buf.getLong(); // skip 8 bytes of UUID short action = buf.getShort(); // at least the low byte should be the action - or not?
buf.getInt(); // skip 4 bytes of UUID if (action == 0x0001) {
GBDeviceEventDismissNotification devEvtDismissNotification = new GBDeviceEventDismissNotification();
devEvtDismissNotification.notificationID = id;
return devEvtDismissNotification;
} }
LOG.info("unexpected paramerter in dismiss action: " + action);
}
return null;
}
private GBDeviceEventDismissNotification decodeNotificationAction3x(ByteBuffer buf) {
buf.order(ByteOrder.LITTLE_ENDIAN);
byte command = buf.get();
if (command == 0x02) { // dismiss notification ?
buf.getLong(); // skip 8 bytes of UUID
buf.getInt(); // skip 4 bytes of UUID
int id = buf.getInt(); int id = buf.getInt();
short action = buf.getShort(); // at least the low byte should be the action - or not? short action = buf.getShort(); // at least the low byte should be the action - or not?
if (action == 0x0001) { if (action == 0x0001) {
@ -1114,26 +1130,31 @@ public class PebbleProtocol extends GBDeviceProtocol {
private GBDeviceEventSendBytes decodeDatalog(ByteBuffer buf, short length) { private GBDeviceEventSendBytes decodeDatalog(ByteBuffer buf, short length) {
byte command = buf.get(); byte command = buf.get();
byte id = buf.get(); byte id = buf.get();
if (command == DATALOG_TIMEOUT) { switch (command) {
LOG.info("DATALOG TIMEOUT. id=" + (id & 0xff) + " - ignoring"); case DATALOG_TIMEOUT:
return null; LOG.info("DATALOG TIMEOUT. id=" + (id & 0xff) + " - ignoring");
} return null;
if (command == DATALOG_SENDDATA) { case DATALOG_SENDDATA:
buf.order(ByteOrder.LITTLE_ENDIAN); buf.order(ByteOrder.LITTLE_ENDIAN);
int items_left = buf.getInt(); int items_left = buf.getInt();
int crc = buf.getInt(); int crc = buf.getInt();
LOG.info("DATALOG SENDDATA. id=" + (id & 0xff) + ", items_left=" + items_left + ", total length=" + (length - 9)); LOG.info("DATALOG SENDDATA. id=" + (id & 0xff) + ", items_left=" + items_left + ", total length=" + (length - 9));
} else if (command == DATALOG_OPENSESSION) { break;
buf.order(ByteOrder.BIG_ENDIAN); case DATALOG_OPENSESSION:
long uuid_high = buf.getLong(); buf.order(ByteOrder.BIG_ENDIAN);
long uuid_low = buf.getLong(); long uuid_high = buf.getLong();
UUID uuid = new UUID(uuid_high, uuid_low); long uuid_low = buf.getLong();
buf.order(ByteOrder.LITTLE_ENDIAN); UUID uuid = new UUID(uuid_high, uuid_low);
int timestamp = buf.getInt(); buf.order(ByteOrder.LITTLE_ENDIAN);
int log_tag = buf.getInt(); int timestamp = buf.getInt();
byte item_type = buf.get(); int log_tag = buf.getInt();
short item_size = buf.get(); byte item_type = buf.get();
LOG.info("DATALOG OPENSESSION. id=" + (id & 0xff) + ", App UUID=" + uuid.toString() + ", item_type=" + item_type + ", item_size=" + item_size); short item_size = buf.get();
LOG.info("DATALOG OPENSESSION. id=" + (id & 0xff) + ", App UUID=" + uuid.toString() + ", item_type=" + item_type + ", item_size=" + item_size);
break;
default:
LOG.info("unknown DATALOG command: " + (command & 0xff));
break;
} }
LOG.info("sending ACK (0x85)"); LOG.info("sending ACK (0x85)");
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
@ -1142,12 +1163,12 @@ public class PebbleProtocol extends GBDeviceProtocol {
} }
@Override @Override
public GBDeviceEvent decodeResponse(byte[] responseData) { public GBDeviceEvent[] decodeResponse(byte[] responseData) {
ByteBuffer buf = ByteBuffer.wrap(responseData); ByteBuffer buf = ByteBuffer.wrap(responseData);
buf.order(ByteOrder.BIG_ENDIAN); buf.order(ByteOrder.BIG_ENDIAN);
short length = buf.getShort(); short length = buf.getShort();
short endpoint = buf.getShort(); short endpoint = buf.getShort();
GBDeviceEvent devEvt = null; GBDeviceEvent devEvts[] = null;
byte pebbleCmd = -1; byte pebbleCmd = -1;
switch (endpoint) { switch (endpoint) {
case ENDPOINT_MUSICCONTROL: case ENDPOINT_MUSICCONTROL:
@ -1178,7 +1199,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
default: default:
break; break;
} }
devEvt = musicCmd; devEvts = new GBDeviceEvent[]{musicCmd};
break; break;
case ENDPOINT_PHONECONTROL: case ENDPOINT_PHONECONTROL:
pebbleCmd = buf.get(); pebbleCmd = buf.get();
@ -1191,7 +1212,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
LOG.info("Unknown PHONECONTROL event" + pebbleCmd); LOG.info("Unknown PHONECONTROL event" + pebbleCmd);
break; break;
} }
devEvt = callCmd; devEvts = new GBDeviceEvent[]{callCmd};
break; break;
case ENDPOINT_FIRMWAREVERSION: case ENDPOINT_FIRMWAREVERSION:
pebbleCmd = buf.get(); pebbleCmd = buf.get();
@ -1213,7 +1234,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
} else if (hwRev == -3) { // basalt emulator } else if (hwRev == -3) { // basalt emulator
versionCmd.hwVersion = "dvt"; versionCmd.hwVersion = "dvt";
} }
devEvt = versionCmd; devEvts = new GBDeviceEvent[]{versionCmd};
break; break;
case ENDPOINT_APPMANAGER: case ENDPOINT_APPMANAGER:
pebbleCmd = buf.get(); pebbleCmd = buf.get();
@ -1253,12 +1274,12 @@ public class PebbleProtocol extends GBDeviceProtocol {
break; break;
} }
} }
devEvt = appInfoCmd; devEvts = new GBDeviceEvent[]{appInfoCmd};
break; break;
case APPMANAGER_GETUUIDS: case APPMANAGER_GETUUIDS:
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
sendBytes.encodedBytes = encodeSimpleMessage(ENDPOINT_APPMANAGER, APPMANAGER_GETAPPBANKSTATUS); sendBytes.encodedBytes = encodeSimpleMessage(ENDPOINT_APPMANAGER, APPMANAGER_GETAPPBANKSTATUS);
devEvt = sendBytes; devEvts = new GBDeviceEvent[]{sendBytes};
tmpUUIDS.clear(); tmpUUIDS.clear();
slotsUsed = buf.getInt(); slotsUsed = buf.getInt();
for (int i = 0; i < slotsUsed; i++) { for (int i = 0; i < slotsUsed; i++) {
@ -1282,7 +1303,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
deleteRes.event = GBDeviceEventAppManagement.Event.FAILURE; deleteRes.event = GBDeviceEventAppManagement.Event.FAILURE;
break; break;
} }
devEvt = deleteRes; devEvts = new GBDeviceEvent[]{deleteRes};
break; break;
default: default:
LOG.info("Unknown APPMANAGER event" + pebbleCmd); LOG.info("Unknown APPMANAGER event" + pebbleCmd);
@ -1303,7 +1324,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
installRes.event = GBDeviceEventAppManagement.Event.FAILURE; installRes.event = GBDeviceEventAppManagement.Event.FAILURE;
break; break;
} }
devEvt = installRes; devEvts = new GBDeviceEvent[]{installRes};
break; break;
case ENDPOINT_APPLICATIONMESSAGE: case ENDPOINT_APPLICATIONMESSAGE:
pebbleCmd = buf.get(); pebbleCmd = buf.get();
@ -1317,13 +1338,13 @@ public class PebbleProtocol extends GBDeviceProtocol {
LOG.info("got APPLICATIONMESSAGE PUSH from UUID " + uuid); LOG.info("got APPLICATIONMESSAGE PUSH from UUID " + uuid);
if (WeatherNeatSupport.uuid.equals(uuid)) { if (WeatherNeatSupport.uuid.equals(uuid)) {
ArrayList<Pair<Integer, Object>> dict = decodeDict(buf); ArrayList<Pair<Integer, Object>> dict = decodeDict(buf);
devEvt = mWeatherNeatSupport.handleMessage(dict); devEvts = mWeatherNeatSupport.handleMessage(dict);
} else if (MorpheuzSupport.uuid.equals(uuid)) { } else if (MorpheuzSupport.uuid.equals(uuid)) {
ArrayList<Pair<Integer, Object>> dict = decodeDict(buf); ArrayList<Pair<Integer, Object>> dict = decodeDict(buf);
devEvt = mMorpheuzSupport.handleMessage(dict); devEvts = mMorpheuzSupport.handleMessage(dict);
} else if (GadgetbridgePblSupport.uuid.equals(uuid)) { } else if (GadgetbridgePblSupport.uuid.equals(uuid)) {
ArrayList<Pair<Integer, Object>> dict = decodeDict(buf); ArrayList<Pair<Integer, Object>> dict = decodeDict(buf);
devEvt = mGadgetbridgePblSupport.handleMessage(dict); devEvts = mGadgetbridgePblSupport.handleMessage(dict);
} }
break; break;
case APPLICATIONMESSAGE_ACK: case APPLICATIONMESSAGE_ACK:
@ -1346,33 +1367,35 @@ public class PebbleProtocol extends GBDeviceProtocol {
LOG.info("Pebble asked for Phone/App Version - repLYING!"); LOG.info("Pebble asked for Phone/App Version - repLYING!");
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
sendBytes.encodedBytes = encodePhoneVersion(PHONEVERSION_REMOTE_OS_ANDROID); sendBytes.encodedBytes = encodePhoneVersion(PHONEVERSION_REMOTE_OS_ANDROID);
devEvt = sendBytes; devEvts = new GBDeviceEvent[]{sendBytes};
break; break;
default: default:
break; break;
} }
break; break;
case ENDPOINT_DATALOG: case ENDPOINT_DATALOG:
devEvt = decodeDatalog(buf, length); devEvts = new GBDeviceEvent[]{decodeDatalog(buf, length)};
break; break;
case ENDPOINT_SCREENSHOT: case ENDPOINT_SCREENSHOT:
devEvt = decodeScreenshot(buf, length); devEvts = new GBDeviceEvent[]{decodeScreenshot(buf, length)};
break; break;
case ENDPOINT_EXTENSIBLENOTIFS: case ENDPOINT_EXTENSIBLENOTIFS:
devEvts = new GBDeviceEvent[]{decodeNotificationAction2x(buf)};
break;
case ENDPOINT_NOTIFICATIONACTION: case ENDPOINT_NOTIFICATIONACTION:
devEvt = decodeNotificationAction(buf); devEvts = new GBDeviceEvent[]{decodeNotificationAction3x(buf)};
break; break;
case ENDPOINT_PING: case ENDPOINT_PING:
devEvt = decodePing(buf); devEvts = new GBDeviceEvent[]{decodePing(buf)};
break; break;
case ENDPOINT_APPFETCH: case ENDPOINT_APPFETCH:
devEvt = decodeAppFetch(buf); devEvts = new GBDeviceEvent[]{decodeAppFetch(buf)};
break; break;
default: default:
break; break;
} }
return devEvt; return devEvts;
} }
public void setForceProtocol(boolean force) { public void setForceProtocol(boolean force) {

View File

@ -48,9 +48,9 @@ public class WeatherNeatSupport {
return buf.array(); return buf.array();
} }
public GBDeviceEvent handleMessage(ArrayList<Pair<Integer, Object>> pairs) { public GBDeviceEvent[] handleMessage(ArrayList<Pair<Integer, Object>> pairs) {
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
sendBytes.encodedBytes = encodeWeatherNeatMessage("Berlin", "22 C", "cloudy", 0); sendBytes.encodedBytes = encodeWeatherNeatMessage("Berlin", "22 C", "cloudy", 0);
return sendBytes; return new GBDeviceEvent[] {sendBytes};
} }
} }

View File

@ -63,7 +63,7 @@ public abstract class GBDeviceProtocol {
return null; return null;
} }
public GBDeviceEvent decodeResponse(byte[] responseData) { public GBDeviceEvent[] decodeResponse(byte[] responseData) {
return null; return null;
} }
} }