diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/QHybridSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/QHybridSupport.java index 9c0ffe960..951c6224e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/QHybridSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/QHybridSupport.java @@ -241,6 +241,7 @@ public class QHybridSupport extends QHybridBaseSupport { globalCommandReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + if(watchAdapter == null) return; //noinspection SwitchStatementWithTooFewBranches switch (intent.getAction()) { case QHYBRID_ACTION_SET_ACTIVITY_HAND: { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java index 64de2fefe..69723b93a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java @@ -18,6 +18,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Date; import java.util.GregorianCalendar; import java.util.Random; @@ -82,6 +83,8 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { int imageNameIndex = 0; private byte jsonIndex = 0; + private AssetImage backGroundImage = null; + public FossilHRWatchAdapter(QHybridSupport deviceSupport) { super(deviceSupport); } @@ -103,18 +106,17 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { loadNotificationConfigurations(); // queueWrite(new NotificationFilterPutHRRequest(this.notificationConfigurations,this)); - String[] appNames = {"instagram", "snapchat", "line", "whatsapp"}; - String[] paths = { - "/storage/emulated/0/Q/images/icInstagram.icon", - "/storage/emulated/0/Q/images/icSnapchat.icon", - "/storage/emulated/0/Q/images/icLine.icon", - "/storage/emulated/0/Q/images/icWhatsapp.icon" - }; - /*NotificationHRConfiguration[] configs = new NotificationHRConfiguration[4]; - NotificationImage[] images = new NotificationImage[4]; + /*try { + final String[] appNames = {"instagram", "snapchat", "line", "whatsapp"}; + final String[] paths = { + "/storage/emulated/0/Q/images/icInstagram.icon", + "/storage/emulated/0/Q/images/icSnapchat.icon", + "/storage/emulated/0/Q/images/icLine.icon", + "/storage/emulated/0/Q/images/icWhatsapp.icon" + }; - - try { + NotificationHRConfiguration[] configs = new NotificationHRConfiguration[4]; + NotificationImage[] images = new NotificationImage[4]; for(int i = 0; i < 4; i++){ FileInputStream fis = new FileInputStream(paths[i]); byte[] imageData = new byte[fis.available()]; @@ -125,22 +127,20 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { } queueWrite(new NotificationImagePutRequest(images, this)); queueWrite(new NotificationFilterPutHRRequest(configs, this)); + + for(String appName : appNames){ + queueWrite(new PlayNotificationHRRequest( + appName, + appName.toUpperCase(), + "this is some strange message", + this + )); + } } catch (Exception e) { e.printStackTrace(); - } - - for(String appName : appNames){ - queueWrite(new PlayNotificationHRRequest( - appName, - appName.toUpperCase(), - "this is some strange message", - this - )); }*/ - // no effect - // negotiateSymmetricKey(); - // queueWrite(new ConfigurationPutRequest(new nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.configuration.ConfigurationPutRequest.HeartRateMeasurementModeItem((byte) 2), this)); + setVibrationStrength((short) 75); syncSettings(); @@ -155,12 +155,27 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { queueWrite(new SetDeviceStateRequest(GBDevice.State.INITIALIZED)); } + @Override + public void setVibrationStrength(short strength) { + negotiateSymmetricKey(); + queueWrite(new ConfigurationPutRequest(new nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.configuration.ConfigurationPutRequest.VibrationStrengthConfigItem((byte) strength), this)); + } + private void loadNotificationConfigurations(){ this.notificationConfigurations = new NotificationHRConfiguration[]{ new NotificationHRConfiguration("generic", 0), }; } + private void loadBackground(){ + Bitmap backgroundBitmap = BitmapFactory.decodeFile(""); + try { + this.backGroundImage = AssetImageFactory.createAssetImage(backgroundBitmap, false, 0, 0, 0); + } catch (IOException e) { + GB.log("Backgroundimage error", GB.ERROR, e); + } + } + private void loadWidgets() { CustomWidget ethWidget = new CustomWidget(90, 63); // ethWidget.addElement(new CustomWidgetElement(CustomWidgetElement.WidgetElementType.TYPE_TEXT, "date", "-", CustomWidgetElement.X_CENTER, CustomWidgetElement.Y_UPPER_HALF)); @@ -190,7 +205,11 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { private void renderWidgets() { try { - AssetImage[] widgetImages = new AssetImage[this.widgets.length]; + ArrayList widgetImages = new ArrayList<>(); + + if(this.backGroundImage != null){ + widgetImages.add(this.backGroundImage); + } for (int i = 0; i < this.widgets.length; i++) { CustomWidget widget = widgets[i]; @@ -239,32 +258,27 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { paint); } } - widgetImages[i] = AssetImageFactory.createAssetImage( - StringUtils.bytesToHex( - ByteBuffer.allocate(8) - .putLong(System.currentTimeMillis() + imageNameIndex++) - .array() - ) - , + widgetImages.add(AssetImageFactory.createAssetImage( widgetBitmap, true, widget.getAngle(), widget.getDistance(), 1 - ); + )); } + AssetImage[] images = widgetImages.toArray(new AssetImage[0]); // queueWrite(new FileDeleteRequest((short) 0x0700)); queueWrite(new AssetFilePutRequest( - widgetImages, + images, (byte) 0x00, this )); // queueWrite(new FileDeleteRequest((short) 0x0503)); queueWrite(new ImagesSetRequest( - widgetImages, + images, this )); } catch (IOException e) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/AssetFile.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/AssetFile.java index 189dd5b9d..9973cae47 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/AssetFile.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/file/AssetFile.java @@ -1,14 +1,32 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file; +import java.nio.ByteBuffer; +import java.util.zip.CRC32; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.utils.StringUtils; + public class AssetFile { private String fileName; private byte[] fileData; - public AssetFile(String fileName, byte[] fileData) { + protected AssetFile(String fileName, byte[] fileData) { this.fileName = fileName; this.fileData = fileData; } + public AssetFile(byte[] fileData) { + CRC32 crc = new CRC32(); + crc.update(fileData); + + this.fileName = StringUtils.bytesToHex( + ByteBuffer.allocate(4) + .putInt((int) crc.getValue()) + .array() + ); + + this.fileData = fileData; + } + public String getFileName() { return fileName; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/image/AssetImage.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/image/AssetImage.java index b6d42a688..4c33a686f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/image/AssetImage.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/image/AssetImage.java @@ -10,8 +10,8 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fos public class AssetImage extends AssetFile { private int angle, distance, indexZ; - protected AssetImage(String fileName, byte[] fileData, int angle, int distance, int indexZ) { - super(fileName, fileData); + protected AssetImage(byte[] fileData, int angle, int distance, int indexZ) { + super(fileData); this.angle = angle; this.distance = distance; this.indexZ = indexZ; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/image/AssetImageFactory.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/image/AssetImageFactory.java index acb890f1b..4920fe34d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/image/AssetImageFactory.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/image/AssetImageFactory.java @@ -9,11 +9,11 @@ import androidx.annotation.ColorInt; import java.io.IOException; public class AssetImageFactory { - public static AssetImage createAssetImage(String fileName, byte[] fileData, int angle, int distance, int indexZ){ - return new AssetImage(fileName, fileData, angle, distance, indexZ); + public static AssetImage createAssetImage(byte[] fileData, int angle, int distance, int indexZ){ + return new AssetImage(fileData, angle, distance, indexZ); } - public static AssetImage createAssetImage(String fileName, Bitmap fileData, boolean RLEencode, int angle, int distance, int indexZ) throws IOException { + public static AssetImage createAssetImage(Bitmap fileData, boolean RLEencode, int angle, int distance, int indexZ) throws IOException { int height = fileData.getHeight(); int width = fileData.getWidth(); @@ -33,7 +33,9 @@ public class AssetImageFactory { } if(RLEencode){ - return new AssetImage(fileName, ImageConverter.encodeToRLEImage(pixelBytes, height, width), angle, distance, indexZ); + return new AssetImage(ImageConverter.encodeToRLEImage(pixelBytes, height, width), angle, distance, indexZ); + }else{ + } return null; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/image/ImageConverter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/image/ImageConverter.java index 1699bd45b..e130a3445 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/image/ImageConverter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/image/ImageConverter.java @@ -1,5 +1,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.image; +import android.graphics.Bitmap; + import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -23,4 +25,19 @@ public class ImageConverter { return bos.toByteArray(); } + + public static byte[] encodeToRawImage(byte[] monochromeImage, int height, int width){ + int pixelCount = height * width; + + byte[] result = new byte[pixelCount / 4]; // 4 pixels per byte e.g. 2 bits per pixel + + for(int i = 0; i < pixelCount; i++){ + int resultPixelIndex = i / 4; + int shiftIndex = i % 4 * 2; + + result[resultPixelIndex] = (byte) ((monochromeImage[i] >> 6) << shiftIndex); + } + + return result; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationImage.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationImage.java index a8139947e..98626fea2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationImage.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationImage.java @@ -8,7 +8,7 @@ public class NotificationImage extends AssetFile { public NotificationImage(String packageName, byte[] imageData) { //TODO this is defo not functional - super("whatever", imageData); + super(packageName, imageData); this.packageName = packageName; this.imageData = imageData; }