diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractDeviceSupport.java index 1451b8cf..73578f1f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractDeviceSupport.java @@ -13,6 +13,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventScreenshot; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSleepMonitorResult; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; @@ -74,6 +75,9 @@ public abstract class AbstractDeviceSupport implements DeviceSupport { case SLEEP_MONITOR_RES: handleGBDeviceEvent((GBDeviceEventSleepMonitorResult) deviceEvent); break; + case SCREENSHOT: + handleGBDeviceEvent((GBDeviceEventScreenshot) deviceEvent); + break; default: break; } @@ -135,4 +139,8 @@ public abstract class AbstractDeviceSupport implements DeviceSupport { LocalBroadcastManager.getInstance(context).sendBroadcast(sleepMontiorIntent); } + + private void handleGBDeviceEvent(GBDeviceEventScreenshot screenshot) { + GB.writeScreenshot(screenshot, null); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GB.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GB.java index 3818b5f6..c133a71c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GB.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GB.java @@ -13,6 +13,7 @@ import android.support.v4.app.NotificationCompat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventScreenshot; import nodomain.freeyourgadget.gadgetbridge.externalevents.K9Receiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.MusicPlaybackReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.PebbleReceiver; @@ -86,7 +87,7 @@ public class GB { } public static String hexdump(byte[] buffer, int offset, int length) { - if (length == -1 ) { + if (length == -1) { length = buffer.length; } final char[] hexArray = "0123456789ABCDEF".toCharArray(); @@ -102,4 +103,9 @@ public class GB { public static String formatRssi(short rssi) { return String.valueOf(rssi); } + + public static void writeScreenshot(GBDeviceEventScreenshot screenshot, String filename) { + LOG.info("got screenshot: " + screenshot.width + "x" + screenshot.height + "x" + screenshot.bpp + "bpp"); + // TODO encode bmp or something trivial + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEvent.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEvent.java index d84d6ee2..043faac2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEvent.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEvent.java @@ -13,6 +13,7 @@ public abstract class GBDeviceEvent { APP_MANAGEMENT_RES, SEND_BYTES, SLEEP_MONITOR_RES, + SCREENSHOT, } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventScreenshot.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventScreenshot.java new file mode 100644 index 00000000..4c75060f --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventScreenshot.java @@ -0,0 +1,13 @@ +package nodomain.freeyourgadget.gadgetbridge.deviceevents; + +public class GBDeviceEventScreenshot extends GBDeviceEvent { + public int width; + public int height; + public byte bpp; + public byte[] clut; + public byte[] data; + + public GBDeviceEventScreenshot() { + eventClass = EventClass.SCREENSHOT; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleProtocol.java index 84881f95..dc06038f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleProtocol.java @@ -20,6 +20,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagementResult; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventScreenshot; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceProtocol; @@ -168,6 +169,8 @@ public class PebbleProtocol extends GBDeviceProtocol { boolean isFw3x = false; boolean mForceProtocol = false; + GBDeviceEventScreenshot mDevEventScreenshot = null; + int mScreenshotRemaining = -1; byte last_id = -1; private ArrayList tmpUUIDS = new ArrayList<>(); @@ -533,7 +536,7 @@ public class PebbleProtocol extends GBDeviceProtocol { @Override public byte[] encodeScreenshotReq() { - return encodeSimpleMessage( ENDPOINT_SCREENSHOT, SCREENSHOT_TAKE ); + return encodeSimpleMessage(ENDPOINT_SCREENSHOT, SCREENSHOT_TAKE); } /* pebble specific install methods */ @@ -721,16 +724,54 @@ public class PebbleProtocol extends GBDeviceProtocol { } + private GBDeviceEvent decodeResponseScreenshot(ByteBuffer buf, int length) { + if (mDevEventScreenshot == null) { + byte result = buf.get(); + mDevEventScreenshot = new GBDeviceEventScreenshot(); + int version = buf.getInt(); + if (result != 0 || version != 1) { // pebble time not yet + return null; + } + mDevEventScreenshot.width = buf.getInt(); + mDevEventScreenshot.height = buf.getInt(); + mDevEventScreenshot.bpp = 1; + + mScreenshotRemaining = (mDevEventScreenshot.width * mDevEventScreenshot.height) / 8; + if (mScreenshotRemaining > 50000) { + mScreenshotRemaining = -1; // ignore too big values + return null; + } + mDevEventScreenshot.data = new byte[mScreenshotRemaining]; + length -= 13; + } + if (mScreenshotRemaining == -1) { + return null; + } + + buf.get(mDevEventScreenshot.data, mDevEventScreenshot.data.length - mScreenshotRemaining, length); + mScreenshotRemaining -= length; + LOG.info("Screenshot remaining bytes " + mScreenshotRemaining); + if (mScreenshotRemaining == 0) { + mScreenshotRemaining = -1; + LOG.info("Got screenshot : " + mDevEventScreenshot.width + "x" + mDevEventScreenshot.height + " " + "pixels"); + GBDeviceEventScreenshot devEventScreenshot = mDevEventScreenshot; + mDevEventScreenshot = null; + return devEventScreenshot; + } + return null; + } + @Override public GBDeviceEvent decodeResponse(byte[] responseData) { ByteBuffer buf = ByteBuffer.wrap(responseData); buf.order(ByteOrder.BIG_ENDIAN); short length = buf.getShort(); short endpoint = buf.getShort(); - byte pebbleCmd = buf.get(); GBDeviceEvent devEvt = null; + byte pebbleCmd = -1; switch (endpoint) { case ENDPOINT_MUSICCONTROL: + pebbleCmd = buf.get(); GBDeviceEventMusicControl musicCmd = new GBDeviceEventMusicControl(); switch (pebbleCmd) { case MUSICCONTROL_NEXT: @@ -760,6 +801,7 @@ public class PebbleProtocol extends GBDeviceProtocol { devEvt = musicCmd; break; case ENDPOINT_PHONECONTROL: + pebbleCmd = buf.get(); GBDeviceEventCallControl callCmd = new GBDeviceEventCallControl(); switch (pebbleCmd) { case PHONECONTROL_HANGUP: @@ -772,6 +814,7 @@ public class PebbleProtocol extends GBDeviceProtocol { devEvt = callCmd; break; case ENDPOINT_FIRMWAREVERSION: + pebbleCmd = buf.get(); GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo(); buf.getInt(); // skip @@ -791,6 +834,7 @@ public class PebbleProtocol extends GBDeviceProtocol { devEvt = versionCmd; break; case ENDPOINT_APPMANAGER: + pebbleCmd = buf.get(); switch (pebbleCmd) { case APPMANAGER_GETAPPBANKSTATUS: GBDeviceEventAppInfo appInfoCmd = new GBDeviceEventAppInfo(); @@ -864,6 +908,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } break; case ENDPOINT_PUTBYTES: + pebbleCmd = buf.get(); GBDeviceEventAppManagementResult installRes = new GBDeviceEventAppManagementResult(); installRes.type = GBDeviceEventAppManagementResult.EventType.INSTALL; switch (pebbleCmd) { @@ -879,6 +924,7 @@ public class PebbleProtocol extends GBDeviceProtocol { devEvt = installRes; break; case ENDPOINT_APPLICATIONMESSAGE: + pebbleCmd = buf.get(); last_id = buf.get(); long uuid_high = buf.getLong(); long uuid_low = buf.getLong(); @@ -909,6 +955,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } break; case ENDPOINT_DATALOG: + pebbleCmd = buf.get(); if (pebbleCmd != DATALOG_TIMEOUT) { byte id = buf.get(); LOG.info("DATALOG id " + id + " - sending 0x85 (ACK?)"); @@ -920,6 +967,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } break; case ENDPOINT_PHONEVERSION: + pebbleCmd = buf.get(); switch (pebbleCmd) { case PHONEVERSION_REQUEST: LOG.info("Pebble asked for Phone/App Version - repLYING!"); @@ -931,6 +979,9 @@ public class PebbleProtocol extends GBDeviceProtocol { break; } break; + case ENDPOINT_SCREENSHOT: + devEvt = decodeResponseScreenshot(buf, length); + break; default: break; }