From e4d8f5f3e29cb3584f835f6b14553b4d25839494 Mon Sep 17 00:00:00 2001 From: Arjan Schrijver Date: Tue, 22 Mar 2022 20:52:43 +0100 Subject: [PATCH] Fossil Hybrid HR: Add flexible custom menu on watch (#2616) This PR adds support for a new custom menu system on the Fossil Hybrid HR, developed by @dakhnod. For regular users this PR will change nothing, apart from also giving an extra option to light up the display when receiving new notifications. For more advanced users, there's the [Fossil HR Menu Companion app](https://github.com/dakhnod/Fossil-HR-Menu-Companion) that's needed to enable and configure the new menu system. Just disable one or more of the physical buttons in Gadgetbridge and configure them instead in the companion app to get started. Co-authored-by: Daniel Dakhno Co-authored-by: Arjan Schrijver Reviewed-on: https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/2616 --- .gitmodules | 2 +- .../main/assets/fossil_hr/battery_layout.json | 1 + .../assets/fossil_hr/complication_layout.json | 1 + .../main/assets/fossil_hr/image_layout.json | 1 + .../main/assets/fossil_hr/menu_layout.json | 207 ++++++++++++++++++ .../assets/fossil_hr/openSourceWatchface.bin | Bin 3438 -> 7814 bytes .../devices/qhybrid/FossilAppWriter.java | 21 +- .../HybridHRWatchfaceDesignerActivity.java | 3 + .../qhybrid/HybridHRWatchfaceFactory.java | 202 +---------------- .../qhybrid/HybridHRWatchfaceSettings.java | 9 + .../HybridHRWatchfaceSettingsActivity.java | 7 + .../fossil_hr/FossilHRWatchAdapter.java | 2 - app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values/strings.xml | 1 + .../res/xml/devicesettings_fossilhybridhr.xml | 9 +- .../res/xml/fossil_hr_watchface_settings.xml | 5 + external/fossil-hr-watchface | 2 +- 17 files changed, 266 insertions(+), 209 deletions(-) create mode 100644 app/src/main/assets/fossil_hr/battery_layout.json create mode 100644 app/src/main/assets/fossil_hr/complication_layout.json create mode 100644 app/src/main/assets/fossil_hr/image_layout.json create mode 100644 app/src/main/assets/fossil_hr/menu_layout.json diff --git a/.gitmodules b/.gitmodules index 4c058130a..19b292ea4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "fossil-hr-watchface"] path = external/fossil-hr-watchface - url = https://github.com/arjan-s/fossil-hr-watchface + url = https://codeberg.org/Freeyourgadget/fossil-hr-watchface [submodule "jerryscript"] path = external/jerryscript url = https://github.com/jerryscript-project/jerryscript diff --git a/app/src/main/assets/fossil_hr/battery_layout.json b/app/src/main/assets/fossil_hr/battery_layout.json new file mode 100644 index 000000000..4d35d4c85 --- /dev/null +++ b/app/src/main/assets/fossil_hr/battery_layout.json @@ -0,0 +1 @@ +[{"id":0,"type":"complication_background","background":"#background","goal_ring":{"is_enable":"#goal_ring","end_angle":"#fi","is_invert":"#$e"},"dimension":{"type":"rigid","width":"#size.w","height":"#size.h"},"placement":{"type":"absolute","left":"#pos.Ue","top":"#pos.Qe"},"visible":true,"inversion":false},{"id":1,"parent_id":0,"type":"complication_content","icon":"icBattery","text_low":"#ci","dimension":{"type":"rigid","width":76,"height":76},"placement":{"type":"relative"},"visible":true,"inversion":"#$e"},{"id":2,"parent_id":1,"type":"solid","placement":{"type":"absolute","left":29,"top":23},"color":"#nt","dimension":{"type":"rigid","height":6,"width":"#it"},"visible":true,"inversion":false},{"id":3,"parent_id":1,"type":"image","image_name":"icBattCharging","draw_mode":1,"placement":{"type":"absolute","left":34,"top":21},"dimension":{"width":6,"height":9},"visible":"#et","inversion":false}] diff --git a/app/src/main/assets/fossil_hr/complication_layout.json b/app/src/main/assets/fossil_hr/complication_layout.json new file mode 100644 index 000000000..42be572d2 --- /dev/null +++ b/app/src/main/assets/fossil_hr/complication_layout.json @@ -0,0 +1 @@ +[{"id":0,"type":"complication_background","background":"#background","goal_ring":{"is_enable":"#goal_ring","end_angle":"#fi","is_invert":"#$e"},"dimension":{"type":"rigid","width":"#size.w","height":"#size.h"},"placement":{"type":"absolute","left":"#pos.Ue","top":"#pos.Qe"},"visible":true,"inversion":false},{"id":1,"parent_id":0,"type":"complication_content","icon":"#icon","text_high":"#dt","text_low":"#ci","dimension":{"type":"rigid","width":76,"height":76},"placement":{"type":"relative"},"visible":true,"inversion":"#$e"}] \ No newline at end of file diff --git a/app/src/main/assets/fossil_hr/image_layout.json b/app/src/main/assets/fossil_hr/image_layout.json new file mode 100644 index 000000000..1ed732279 --- /dev/null +++ b/app/src/main/assets/fossil_hr/image_layout.json @@ -0,0 +1 @@ +[{"id":0,"type":"container","direction":1,"main_alignment":1,"cross_alignment":1,"dimension":{"type":"rigid","width":240,"height":240},"placement":{"type":"absolute","left":0,"top":0},"visible":true,"inversion":false},{"id":1,"parent_id":0,"type":"image","image_name":"#name","draw_mode":1,"placement":{"type":"absolute","left":"#pos.Ue","top":"#pos.Qe"},"dimension":{"width":"#size.w","height":"#size.h"},"visible":true,"inversion":false}] \ No newline at end of file diff --git a/app/src/main/assets/fossil_hr/menu_layout.json b/app/src/main/assets/fossil_hr/menu_layout.json new file mode 100644 index 000000000..6be3d627d --- /dev/null +++ b/app/src/main/assets/fossil_hr/menu_layout.json @@ -0,0 +1,207 @@ +[ + { + "id": 0, + "type": "container", + "direction": 1, + "main_alignment": 0, + "cross_alignment": 1, + "dimension": { + "type": "rigid", + "width": 240, + "height": 240 + }, + "placement": { + "type": "absolute", + "left": 0, + "top": 0 + }, + "visible": true, + "inversion": false + }, + { + "id": 1, + "parent_id": 0, + "type": "container", + "direction": 1, + "main_alignment": 1, + "cross_alignment": 2, + "dimension": { + "type": "rigid", + "width": 130, + "height": 34 + }, + "placement": { + "type": "absolute", + "left": 75, + "top": 45 + }, + "visible": true, + "inversion": false + }, + { + "id": 2, + "parent_id": 1, + "type": "text", + "text": "#top_short_press_label", + "ppem": 17, + "color": 3, + "placement": { + "type": "relative" + }, + "visible": true, + "inversion": false + }, + { + "id": 3, + "parent_id": 1, + "type": "text", + "text": "#top_long_press_label", + "ppem": 17, + "color": 3, + "ascent": 17, + "placement": { + "type": "relative" + }, + "visible": true, + "inversion": false + }, + { + "id": 4, + "parent_id": 0, + "type": "container", + "direction": 1, + "main_alignment": 1, + "cross_alignment": 2, + "dimension": { + "type": "rigid", + "width": 80, + "height": 34 + }, + "placement": { + "type": "absolute", + "left": 135, + "top": 103 + }, + "visible": true, + "inversion": false + }, + { + "id": 5, + "parent_id": 4, + "type": "text", + "text": "#middle_short_press_label", + "ppem": 17, + "color": 3, + "placement": { + "type": "relative" + }, + "visible": true, + "inversion": false + }, + { + "id": 6, + "parent_id": 4, + "type": "text", + "text": "#middle_long_press_label", + "ppem": 17, + "color": 3, + "ascent": 17, + "placement": { + "type": "relative" + }, + "visible": true, + "inversion": false + }, + { + "id": 7, + "parent_id": 0, + "type": "container", + "direction": 1, + "main_alignment": 1, + "cross_alignment": 2, + "dimension": { + "type": "rigid", + "width": 130, + "height": 34 + }, + "placement": { + "type": "absolute", + "left": 75, + "top": 161 + }, + "visible": true, + "inversion": false + }, + { + "id": 8, + "parent_id": 7, + "type": "text", + "text": "#bottom_short_press_label", + "ppem": 17, + "color": 3, + "placement": { + "type": "relative" + }, + "visible": true, + "inversion": false + }, + { + "id": 9, + "parent_id": 7, + "type": "text", + "text": "#bottom_long_press_label", + "ppem": 17, + "color": 3, + "ascent": 17, + "placement": { + "type": "relative" + }, + "visible": true, + "inversion": false + }, + { + "id": 10, + "parent_id": 0, + "type": "text", + "text": "#menu_title", + "ppem": 25, + "color": 3, + "ascent": 35, + "placement": { + "type": "relative" + }, + "visible": true, + "inversion": false + }, + { + "id": 11, + "parent_id": 0, + "type": "text_page", + "text": "#message_to_display", + "ppem": 17, + "color": 3, + "ascent": 17, + "cross_alignment": 2, + "line_width": [ + 80, + 85, + 90, + 90, + 85, + 80 + ], + "dimension": { + "type": "rigid", + "width": 80, + "height": 100 + }, + "placement": { + "type": "absolute", + "left": 20, + "top": 60 + }, + "visible": true, + "inversion": false + } + ] + \ No newline at end of file diff --git a/app/src/main/assets/fossil_hr/openSourceWatchface.bin b/app/src/main/assets/fossil_hr/openSourceWatchface.bin index e6cbe5917d80c7e0d46d50cdc482c998623b2bab..41e239c15ac06bb0583ff15c9d11c6151e937d05 100644 GIT binary patch literal 7814 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 literal 3438 zcmaJ?-*4O275*-Nh@xm&p)A{sf5cW|MN|^INfuIF>UK?k#7fg7O;-oq6Gw|zG!u#x zNXoAFl$XKS1{4^uhXF%@y=jl>ON#*;5)9bv*8;)xCkXp1I$Tn6>UNy~N#~w(&%O72 z-*?ab;Ny>fp<(>V0|WpYUjRWB5tafGrLdw*T$O-7Nk;>9#F(>KyRY4OpzM{#Mil%6V zC2gvO;`QmzOP`<7rmw$|{;L~Wc|)7o&?@WNY-@h5byi!~7FtV-t#iw*wUt(FwRKTx z)vGQ2e5-Nc{S>6@DJ}{GxmsnoxU0Zn6*xK%j4ot24Ay{p4LGa;qZ+VvF+2C*A|Tbr z_^|&v;5J^>&1ycn^a`W;l?+3M-QWsRoSL#xfVc}`n3@KLWS0ob`G!agy}{c~jV#6M52p4b{$JF!=Zb~1l~Or6+^kUzf-JWBZx zIYGXDeQO;UYygL^0b5sr!8M@%lT0^^i>(`gYXBny7??o42^=;vZH-NkPG%}l4G zH-N28;BXVDzX`Z+0`<4Dd%(2Mw9WL-xRHLAY1(}|)Aivk;P9P{$HRBW_oJNM6{dBj zamF>%JG(C%L(YV(<~Iuskbjy`+$r@;gA^;RX{B|hbj*>zGN-D(y;-ibW|Y=!<@x%M zTYovH3ttcU2AQvz{8>#i`9*DELt8r5#pbepuDSAzPp#Ev^%>8Rge`KuT5Mi;u$=#G1O1Ca48n`fB54jV%4YJcVskuWF4v*g3xBtHq}N zYEO+-(NJCtxmV}p@b6PetKUyrTpw~--g8zrD=;mKe8KWAsUKv))}<7hR|}`srRL>l ze6yxr(50_Z$Cc*#vlO@HhNd-N(-xXnwWVWL*!}DnN_O@uU-Ig?A1{@xve}JgX|t^3 z#px==^&zKo>m60vyrz@qx5q8Ek?J*11Ziz;(mzJ;jr%5m!TZ4BZD6nkj9S3p4p9Ff z)1-74aPI;~cYoMt1|K5rFZFu>N||<9?@4>|y{rd~?g91tfO{Vp-3JZ_1k7 zQVK0$YDp_LOKMI(Lj+ybrq{Ld@y5&2wIONF7!`=WgD~WnX>db+mrvUcZ_Ki`9%UgeCR8=CZ-YH?|+2Qw3s}kc^^EDkiTn0k3E) zCcmmpnf!VCf>u3lGhR7Cn4V^D;o#x8|9_nIoWakt-of4l)_b-- z0h)p#LcE-UDi|UI)kMzZrH)!|kbI>j=S*JF3a#SQG2~h*p+dS(j^lVmk+uPM8yIW@ z^+!m#UuAF7BVh0-(?I17PB0;wB=>viw=Xn49m*ytq{ICCGWvl-J6=E?$OuA*T7liA z0P^VCf!CpNl0)KkX%tVR-*fDQT0J{TJlj_$<4)iAA!64KoEQake6Rh)viI$S9NJ;f z@!TTXVYladZ9DP8Acg=ZviIlV1#x2gK6R|q@f;lL1zvJ4-8t+hlPxXBi+jF(U}Yy+ zJc+X-d@qO@q~3^jA{y^n0i_OgprRM<(_=XlSXqUWvoLhReuA^7qUky(v4#H;i>PlW-X5Jj73+q3)Y=XE5$1pB?|MN$p%B2( zky6Bc8lf^_;uMTC6hz=g^@ zsT@u?LJ2NSGG|6BCXIYY(1owRqYj@>@-}Q s!o)}Sl03p54J^CYlgG^1y&eSIvy)v8+f+oy55ouqpMk?eN^pSx0t!kfL;wH) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/FossilAppWriter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/FossilAppWriter.java index fc8b199c7..4917e879a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/FossilAppWriter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/FossilAppWriter.java @@ -39,11 +39,11 @@ public class FossilAppWriter { private String version; private LinkedHashMap code; private LinkedHashMap icons; - private LinkedHashMap layout; + private LinkedHashMap layout; private LinkedHashMap displayName; private LinkedHashMap config; - public FossilAppWriter(Context context, String version, LinkedHashMap code, LinkedHashMap icons, LinkedHashMap layout, LinkedHashMap displayName, LinkedHashMap config) { + public FossilAppWriter(Context context, String version, LinkedHashMap code, LinkedHashMap icons, LinkedHashMap layout, LinkedHashMap displayName, LinkedHashMap config) { this.mContext = context; if (this.mContext == null) throw new AssertionError("context cannot be null"); this.version = version; @@ -61,9 +61,9 @@ public class FossilAppWriter { } public byte[] getWapp() throws IOException { - byte[] codeData = loadFiles(code); - byte[] iconsData = loadFiles(icons); - byte[] layoutData = loadStringFiles(layout); + byte[] codeData = loadFiles(code, false); + byte[] iconsData = loadFiles(icons, false); + byte[] layoutData = loadFiles(layout, true); byte[] displayNameData = loadStringFiles(displayName); byte[] configData = loadStringFiles(config); @@ -118,16 +118,23 @@ public class FossilAppWriter { return wapp.toByteArray(); } - public byte[] loadFiles(LinkedHashMap filesMap) throws IOException { + public byte[] loadFiles(LinkedHashMap filesMap, boolean appendNull) throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); for (String filename : filesMap.keySet()) { InputStream in = filesMap.get(filename); output.write((byte)filename.length() + 1); output.write(StringUtils.terminateNull(filename).getBytes(StandardCharsets.UTF_8)); - output.write(shortToLEBytes((short)in.available())); + int fileLength = in.available(); + if(appendNull){ + fileLength++; + } + output.write(shortToLEBytes((short)fileLength)); byte[] fileBytes = new byte[in.available()]; in.read(fileBytes); output.write(fileBytes); + if(appendNull){ + output.write(0x00); + } } return output.toByteArray(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceDesignerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceDesignerActivity.java index 685586979..3464ca3a5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceDesignerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceDesignerActivity.java @@ -456,6 +456,9 @@ public class HybridHRWatchfaceDesignerActivity extends AbstractGBActivity implem if (watchfaceConfig.has("powersave_hands")) { watchfaceSettings.setPowersaveHands(watchfaceConfig.getBoolean("powersave_hands")); } + if (watchfaceConfig.has("light_up_on_notification")) { + watchfaceSettings.setLightUpOnNotification(watchfaceConfig.getBoolean("light_up_on_notification")); + } } catch (JSONException e) { LOG.warn("JSON parsing error", e); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceFactory.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceFactory.java index b0cdfd227..be473880a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceFactory.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceFactory.java @@ -185,22 +185,15 @@ public class HybridHRWatchfaceFactory { } catch (IOException e) { LOG.warn("Unable to read asset file", e); } - LinkedHashMap layout = new LinkedHashMap<>(); - try { - layout.put("complication_layout", getComplicationLayout()); - } catch (JSONException e) { - LOG.warn("Could not generate complication_layout", e); - } - try { - layout.put("image_layout", getImageLayout()); - } catch (JSONException e) { - LOG.warn("Could not generate image_layout", e); - } - try { - if (includeWidget("widgetBattery") > 0) layout.put("battery_layout", getBatteryLayout()); - } catch (JSONException e) { - LOG.warn("Could not generate battery_layout", e); + LinkedHashMap layout = new LinkedHashMap<>(); + layout.put("complication_layout", context.getAssets().open("fossil_hr/complication_layout.json")); + layout.put("image_layout", context.getAssets().open("fossil_hr/image_layout.json")); + layout.put("menu_layout", context.getAssets().open("fossil_hr/menu_layout.json")); + + if (includeWidget("widgetBattery") > 0) { + layout.put("battery_layout", context.getAssets().open("fossil_hr/battery_layout.json")); } + LinkedHashMap displayName = new LinkedHashMap<>(); displayName.put("display_name", watchfaceName); displayName.put("theme_class", "complications"); @@ -214,184 +207,6 @@ public class HybridHRWatchfaceFactory { return appWriter.getWapp(); } - private String getBatteryLayout() throws JSONException { - JSONArray batteryLayout = new JSONArray(); - - JSONObject complicationBackground = new JSONObject(); - complicationBackground.put("id", 0); - complicationBackground.put("type", "complication_background"); - complicationBackground.put("background", "#background"); - complicationBackground.put("visible", true); - complicationBackground.put("inversion", false); - JSONObject goalRing = new JSONObject(); - goalRing.put("is_enable", "#goal_ring"); - goalRing.put("end_angle", "#fi"); - goalRing.put("is_invert", "#$e"); - complicationBackground.put("goal_ring", goalRing); - JSONObject dimension = new JSONObject(); - dimension.put("type", "rigid"); - dimension.put("width", "#size.w"); - dimension.put("height", "#size.h"); - complicationBackground.put("dimension", dimension); - JSONObject placement = new JSONObject(); - placement.put("type", "absolute"); - placement.put("left", "#pos.Ue"); - placement.put("top", "#pos.Qe"); - complicationBackground.put("placement", placement); - batteryLayout.put(complicationBackground); - - JSONObject complicationContent = new JSONObject(); - complicationContent.put("id", 1); - complicationContent.put("parent_id", 0); - complicationContent.put("type", "complication_content"); - complicationContent.put("icon", "icBattery"); - complicationContent.put("text_low", "#ci"); - complicationContent.put("visible", true); - complicationContent.put("inversion", "#$e"); - dimension = new JSONObject(); - dimension.put("type", "rigid"); - dimension.put("width", 76); - dimension.put("height", 76); - complicationContent.put("dimension", dimension); - placement = new JSONObject(); - placement.put("type", "relative"); - complicationContent.put("placement", placement); - batteryLayout.put(complicationContent); - - JSONObject chargingStatus = new JSONObject(); - chargingStatus.put("id", 2); - chargingStatus.put("parent_id", 1); - chargingStatus.put("type", "solid"); - chargingStatus.put("color", "#nt"); - chargingStatus.put("visible", true); - chargingStatus.put("inversion", false); - dimension = new JSONObject(); - dimension.put("type", "rigid"); - dimension.put("width", "#it"); - dimension.put("height", 6); - chargingStatus.put("dimension", dimension); - placement = new JSONObject(); - placement.put("type", "absolute"); - placement.put("left", 29); - placement.put("top", 23); - chargingStatus.put("placement", placement); - batteryLayout.put(chargingStatus); - - JSONObject image = new JSONObject(); - image.put("id", 3); - image.put("parent_id", 1); - image.put("type", "image"); - image.put("image_name", "icBattCharging"); - image.put("draw_mode", 1); - image.put("visible", "#et"); - image.put("inversion", false); - placement = new JSONObject(); - placement.put("type", "absolute"); - placement.put("left", 34); - placement.put("top", 21); - image.put("placement", placement); - dimension = new JSONObject(); - dimension.put("width", 6); - dimension.put("height", 9); - image.put("dimension", dimension); - batteryLayout.put(image); - - return batteryLayout.toString(); - } - - private String getComplicationLayout() throws JSONException { - JSONArray complicationLayout = new JSONArray(); - - JSONObject complicationBackground = new JSONObject(); - complicationBackground.put("id", 0); - complicationBackground.put("type", "complication_background"); - complicationBackground.put("background", "#background"); - complicationBackground.put("visible", true); - complicationBackground.put("inversion", false); - JSONObject goalRing = new JSONObject(); - goalRing.put("is_enable", "#goal_ring"); - goalRing.put("end_angle", "#fi"); - goalRing.put("is_invert", "#$e"); - complicationBackground.put("goal_ring", goalRing); - JSONObject dimension = new JSONObject(); - dimension.put("type", "rigid"); - dimension.put("width", "#size.w"); - dimension.put("height", "#size.h"); - complicationBackground.put("dimension", dimension); - JSONObject placement = new JSONObject(); - placement.put("type", "absolute"); - placement.put("left", "#pos.Ue"); - placement.put("top", "#pos.Qe"); - complicationBackground.put("placement", placement); - complicationLayout.put(complicationBackground); - - JSONObject complicationContent = new JSONObject(); - complicationContent.put("id", 1); - complicationContent.put("parent_id", 0); - complicationContent.put("type", "complication_content"); - complicationContent.put("icon", "#icon"); - complicationContent.put("text_high", "#dt"); - complicationContent.put("text_low", "#ci"); - complicationContent.put("visible", true); - complicationContent.put("inversion", "#$e"); - dimension = new JSONObject(); - dimension.put("type", "rigid"); - dimension.put("width", "#size.w"); - dimension.put("height", "#size.h"); - complicationContent.put("dimension", dimension); - placement = new JSONObject(); - placement.put("type", "relative"); - complicationContent.put("placement", placement); - complicationLayout.put(complicationContent); - - return complicationLayout.toString(); - } - - private String getImageLayout() throws JSONException { - JSONArray imageLayout = new JSONArray(); - - JSONObject container = new JSONObject(); - container.put("id", 0); - container.put("type", "container"); - container.put("direction", 1); - container.put("main_alignment", 1); - container.put("cross_alignment", 1); - container.put("visible", true); - container.put("inversion", false); - JSONObject dimension = new JSONObject(); - dimension.put("type", "rigid"); - dimension.put("width", 240); - dimension.put("height", 240); - container.put("dimension", dimension); - JSONObject placement = new JSONObject(); - placement.put("type", "absolute"); - placement.put("left", 0); - placement.put("top", 0); - container.put("placement", placement); - imageLayout.put(container); - - JSONObject image = new JSONObject(); - image.put("id", 1); - image.put("parent_id", 0); - image.put("type", "image"); - image.put("image_name", "#name"); - image.put("draw_mode", 1); - image.put("visible", true); - image.put("inversion", false); - placement = new JSONObject(); - placement.put("type", "absolute"); - placement.put("left", "#pos.Ue"); - placement.put("top", "#pos.Qe"); - image.put("placement", placement); - dimension = new JSONObject(); - dimension.put("width", "#size.w"); - dimension.put("height", "#size.h"); - image.put("dimension", dimension); - imageLayout.put(image); - - return imageLayout.toString(); - } - private String getConfiguration() throws JSONException { JSONObject configuration = new JSONObject(); @@ -432,6 +247,7 @@ public class HybridHRWatchfaceFactory { config.put("wrist_flick_duration", settings.getWristFlickDuration()); config.put("wrist_flick_move_hour", settings.getWristFlickMoveHour()); config.put("wrist_flick_move_minute", settings.getWristFlickMoveMinute()); + config.put("light_up_on_notification", settings.getLightUpOnNotification()); config.put("powersave_display", settings.getPowersaveDisplay()); config.put("powersave_hands", settings.getPowersaveHands()); configuration.put("config", config); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceSettings.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceSettings.java index cd402da3e..ef3ebe074 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceSettings.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceSettings.java @@ -27,6 +27,7 @@ public class HybridHRWatchfaceSettings implements Serializable { private int wristFlickMoveMinute = -360; private boolean powersaveDisplay = false; private boolean powersaveHands = false; + private boolean lightUpOnNotification = false; public HybridHRWatchfaceSettings() { } @@ -63,6 +64,14 @@ public class HybridHRWatchfaceSettings implements Serializable { this.wristFlickDuration = wristFlickDuration; } + public boolean getLightUpOnNotification() { + return lightUpOnNotification; + } + + public void setLightUpOnNotification(boolean lightUpOnNotification) { + this.lightUpOnNotification = lightUpOnNotification; + } + public int getWristFlickMoveHour() { return wristFlickMoveHour; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceSettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceSettingsActivity.java index 2fb1a9725..50485eb99 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceSettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HybridHRWatchfaceSettingsActivity.java @@ -111,6 +111,10 @@ public class HybridHRWatchfaceSettingsActivity extends AbstractSettingsActivity SwitchPreference power_saving_hands = (SwitchPreference) findPreference("pref_hybridhr_watchface_power_saving_hands"); power_saving_hands.setOnPreferenceChangeListener(new PreferenceChangeListener()); power_saving_hands.setChecked(settings.getPowersaveHands()); + + SwitchPreference light_up_on_notification = (SwitchPreference) findPreference("pref_hybridhr_watchface_light_up_on_notification"); + light_up_on_notification.setOnPreferenceChangeListener(new PreferenceChangeListener()); + light_up_on_notification.setChecked(settings.getLightUpOnNotification()); } private static class PreferenceChangeListener implements Preference.OnPreferenceChangeListener { @@ -136,6 +140,9 @@ public class HybridHRWatchfaceSettingsActivity extends AbstractSettingsActivity settings.setWristFlickMoveMinute(Integer.parseInt(newValue.toString())); preference.setSummary(newValue.toString()); break; + case "pref_hybridhr_watchface_light_up_on_notification": + settings.setLightUpOnNotification((boolean) newValue); + break; case "pref_hybridhr_watchface_wrist_flick_duration": settings.setWristFlickDuration(Integer.parseInt(newValue.toString())); preference.setSummary(newValue.toString()); 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 7e2e57498..3f17f3029 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 @@ -1559,8 +1559,6 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { return; } - queueWrite(new SetCommuteMenuMessage(getContext().getString(R.string.fossil_hr_commute_processing), false, this)); - Intent menuIntent = new Intent(QHybridSupport.QHYBRID_EVENT_COMMUTE_MENU); menuIntent.putExtra("EXTRA_ACTION", action); getContext().sendBroadcast(menuIntent); diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 35b64d571..c7a592dad 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1593,4 +1593,4 @@ Dient zum Starten/Stoppen der GPS-Track-Aufzeichnung in der externen Fitness-App. Android-Benachrichtigungseinstellungen setze position auf %s - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e9f23b49b..c6d82b9f3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1528,4 +1528,5 @@ OpenTracks package name Used for starting/stopping GPS track recording in external fitness app. pre-setting position to %s + Light up on new notification diff --git a/app/src/main/res/xml/devicesettings_fossilhybridhr.xml b/app/src/main/res/xml/devicesettings_fossilhybridhr.xml index f0c9c022b..cc36f29d4 100644 --- a/app/src/main/res/xml/devicesettings_fossilhybridhr.xml +++ b/app/src/main/res/xml/devicesettings_fossilhybridhr.xml @@ -41,11 +41,12 @@ android:key="button_3_function_short" android:summary="%s" android:title="@string/pref_title_lower_button_function_short" /> - + \ No newline at end of file diff --git a/external/fossil-hr-watchface b/external/fossil-hr-watchface index 44a70cf7c..aad2a141c 160000 --- a/external/fossil-hr-watchface +++ b/external/fossil-hr-watchface @@ -1 +1 @@ -Subproject commit 44a70cf7c3a783d07d0fdab8b4b15e677da63af2 +Subproject commit aad2a141cb2e151431f8354e52d9b74f6829855a