1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-26 02:25:50 +01:00

Fossil Hybrid HR: Generate watchface preview image

This commit is contained in:
Arjan Schrijver 2022-06-13 16:38:10 +02:00 committed by Gitea
parent c2d98b5a24
commit 7f026edbd0
2 changed files with 115 additions and 74 deletions

View File

@ -351,79 +351,7 @@ public class HybridHRWatchfaceDesignerActivity extends AbstractGBActivity implem
for (int i = 0; i < layout.length(); i++) { for (int i = 0; i < layout.length(); i++) {
JSONObject layoutItem = layout.getJSONObject(i); JSONObject layoutItem = layout.getJSONObject(i);
if (layoutItem.getString("type").equals("comp")) { if (layoutItem.getString("type").equals("comp")) {
String widgetName = layoutItem.getString("name"); widgets.add(HybridHRWatchfaceFactory.parseWidgetJSON(layoutItem));
String widgetTimezone = null;
int widgetUpdateTimeout = -1;
boolean widgetTimeoutHideText = true;
boolean widgetTimeoutShowCircle = true;
switch (widgetName) {
case "dateSSE":
widgetName = "widgetDate";
break;
case "weatherSSE":
widgetName = "widgetWeather";
break;
case "stepsSSE":
widgetName = "widgetSteps";
break;
case "hrSSE":
widgetName = "widgetHR";
break;
case "batterySSE":
widgetName = "widgetBattery";
break;
case "caloriesSSE":
widgetName = "widgetCalories";
break;
case "activeMinutesSSE":
widgetName = "widgetActiveMins";
break;
case "chanceOfRainSSE":
widgetName = "widgetChanceOfRain";
break;
case "timeZone2SSE":
widgetName = "widget2ndTZ";
break;
}
int widgetColor = layoutItem.getString("color").equals("white") ? HybridHRWatchfaceWidget.COLOR_WHITE : HybridHRWatchfaceWidget.COLOR_BLACK;
if (widgetName.startsWith("widget2ndTZ")) {
try {
widgetName = "widget2ndTZ";
JSONObject widgetData = layoutItem.getJSONObject("data");
widgetTimezone = widgetData.getString("tzName");
widgets.add(new HybridHRWatchfaceWidget(widgetName,
layoutItem.getJSONObject("pos").getInt("x"),
layoutItem.getJSONObject("pos").getInt("y"),
layoutItem.getJSONObject("size").getInt("w"),
layoutItem.getJSONObject("size").getInt("h"),
widgetColor,
widgetTimezone));
} catch (JSONException e) {
LOG.error("Couldn't determine tzName!", e);
}
} else if (widgetName.startsWith("widgetCustom")) {
widgetName = "widgetCustom";
JSONObject widgetData = layoutItem.getJSONObject("data");
widgetUpdateTimeout = widgetData.getInt("update_timeout");
widgetTimeoutHideText = widgetData.getBoolean("timeout_hide_text");
widgetTimeoutShowCircle = widgetData.getBoolean("timeout_show_circle");
widgets.add(new HybridHRWatchfaceWidget(widgetName,
layoutItem.getJSONObject("pos").getInt("x"),
layoutItem.getJSONObject("pos").getInt("y"),
layoutItem.getJSONObject("size").getInt("w"),
layoutItem.getJSONObject("size").getInt("h"),
widgetColor,
widgetUpdateTimeout,
widgetTimeoutHideText,
widgetTimeoutShowCircle));
} else {
widgets.add(new HybridHRWatchfaceWidget(widgetName,
layoutItem.getJSONObject("pos").getInt("x"),
layoutItem.getJSONObject("pos").getInt("y"),
layoutItem.getJSONObject("size").getInt("w"),
layoutItem.getJSONObject("size").getInt("h"),
widgetColor));
}
} }
} }
} catch (JSONException e) { } catch (JSONException e) {
@ -838,6 +766,11 @@ public class HybridHRWatchfaceDesignerActivity extends AbstractGBActivity implem
GBApplication.deviceService().onInstallApp(tempAppFileUri); GBApplication.deviceService().onInstallApp(tempAppFileUri);
FossilHRInstallHandler.saveAppInCache(fossilFile, processedBackgroundImage, mCoordinator, HybridHRWatchfaceDesignerActivity.this); FossilHRInstallHandler.saveAppInCache(fossilFile, processedBackgroundImage, mCoordinator, HybridHRWatchfaceDesignerActivity.this);
} }
Bitmap previewImage = wfFactory.getPreviewImage(this);
File previewFile = new File(cacheDir, app.getUUID().toString() + "_preview.png");
FileOutputStream previewFOS = new FileOutputStream(previewFile);
previewImage.compress(Bitmap.CompressFormat.PNG, 9, previewFOS);
previewFOS.close();
} }
} catch (IOException e) { } catch (IOException e) {
LOG.warn("Error while creating and uploading watchface", e); LOG.warn("Error while creating and uploading watchface", e);

View File

@ -18,6 +18,7 @@ package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
@ -33,12 +34,16 @@ import java.util.LinkedHashMap;
import java.util.TimeZone; import java.util.TimeZone;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.image.ImageConverter; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.image.ImageConverter;
import nodomain.freeyourgadget.gadgetbridge.util.BitmapUtil;
public class HybridHRWatchfaceFactory { public class HybridHRWatchfaceFactory {
private final Logger LOG = LoggerFactory.getLogger(HybridHRWatchfaceFactory.class); private static final Logger LOG = LoggerFactory.getLogger(HybridHRWatchfaceFactory.class);
private String watchfaceName; private String watchfaceName;
private HybridHRWatchfaceSettings settings; private HybridHRWatchfaceSettings settings;
private Bitmap background; private Bitmap background;
private Bitmap previewImage;
private static final int PREVIEW_WIDTH = 192;
private static final int PREVIEW_HEIGHT = 192;
private ArrayList<JSONObject> widgets = new ArrayList<>(); private ArrayList<JSONObject> widgets = new ArrayList<>();
public HybridHRWatchfaceFactory(String name) { public HybridHRWatchfaceFactory(String name) {
@ -140,6 +145,8 @@ public class HybridHRWatchfaceFactory {
public byte[] getWapp(Context context) throws IOException { public byte[] getWapp(Context context) throws IOException {
byte[] backgroundBytes = ImageConverter.encodeToRawImage(ImageConverter.get2BitsRAWImageBytes(background)); byte[] backgroundBytes = ImageConverter.encodeToRawImage(ImageConverter.get2BitsRAWImageBytes(background));
InputStream backgroundStream = new ByteArrayInputStream(backgroundBytes); InputStream backgroundStream = new ByteArrayInputStream(backgroundBytes);
byte[] previewBytes = ImageConverter.encodeToRLEImage(ImageConverter.get2BitsRLEImageBytes(Bitmap.createScaledBitmap(getPreviewImage(context), PREVIEW_WIDTH, PREVIEW_HEIGHT, true)), PREVIEW_HEIGHT, PREVIEW_WIDTH);
InputStream previewStream = new ByteArrayInputStream(previewBytes);
LinkedHashMap<String, InputStream> code = new LinkedHashMap<>(); LinkedHashMap<String, InputStream> code = new LinkedHashMap<>();
try { try {
code.put(watchfaceName, context.getAssets().open("fossil_hr/openSourceWatchface.bin")); code.put(watchfaceName, context.getAssets().open("fossil_hr/openSourceWatchface.bin"));
@ -163,6 +170,7 @@ public class HybridHRWatchfaceFactory {
LinkedHashMap<String, InputStream> icons = new LinkedHashMap<>(); LinkedHashMap<String, InputStream> icons = new LinkedHashMap<>();
try { try {
icons.put("background.raw", backgroundStream); icons.put("background.raw", backgroundStream);
icons.put("!preview.rle", previewStream);
icons.put("icTrophy", context.getAssets().open("fossil_hr/icTrophy.rle")); icons.put("icTrophy", context.getAssets().open("fossil_hr/icTrophy.rle"));
if (includeWidget("widgetWeather") > 0) icons.put("icWthClearDay", context.getAssets().open("fossil_hr/icWthClearDay.rle")); if (includeWidget("widgetWeather") > 0) icons.put("icWthClearDay", context.getAssets().open("fossil_hr/icWthClearDay.rle"));
if (includeWidget("widgetWeather") > 0) icons.put("icWthClearNite", context.getAssets().open("fossil_hr/icWthClearNite.rle")); if (includeWidget("widgetWeather") > 0) icons.put("icWthClearNite", context.getAssets().open("fossil_hr/icWthClearNite.rle"));
@ -254,4 +262,104 @@ public class HybridHRWatchfaceFactory {
return configuration.toString(); return configuration.toString();
} }
public static HybridHRWatchfaceWidget parseWidgetJSON(JSONObject widgetJSON) throws JSONException {
HybridHRWatchfaceWidget parsedWidget = null;
String widgetName = widgetJSON.getString("name");
String widgetTimezone = null;
int widgetUpdateTimeout = -1;
boolean widgetTimeoutHideText = true;
boolean widgetTimeoutShowCircle = true;
switch (widgetName) {
case "dateSSE":
widgetName = "widgetDate";
break;
case "weatherSSE":
widgetName = "widgetWeather";
break;
case "stepsSSE":
widgetName = "widgetSteps";
break;
case "hrSSE":
widgetName = "widgetHR";
break;
case "batterySSE":
widgetName = "widgetBattery";
break;
case "caloriesSSE":
widgetName = "widgetCalories";
break;
case "activeMinutesSSE":
widgetName = "widgetActiveMins";
break;
case "chanceOfRainSSE":
widgetName = "widgetChanceOfRain";
break;
case "timeZone2SSE":
widgetName = "widget2ndTZ";
break;
}
int widgetColor = widgetJSON.getString("color").equals("white") ? HybridHRWatchfaceWidget.COLOR_WHITE : HybridHRWatchfaceWidget.COLOR_BLACK;
if (widgetName.startsWith("widget2ndTZ")) {
try {
widgetName = "widget2ndTZ";
JSONObject widgetData = widgetJSON.getJSONObject("data");
widgetTimezone = widgetData.getString("tzName");
parsedWidget = new HybridHRWatchfaceWidget(widgetName,
widgetJSON.getJSONObject("pos").getInt("x"),
widgetJSON.getJSONObject("pos").getInt("y"),
widgetJSON.getJSONObject("size").getInt("w"),
widgetJSON.getJSONObject("size").getInt("h"),
widgetColor,
widgetTimezone);
} catch (JSONException e) {
LOG.error("Couldn't determine tzName!", e);
}
} else if (widgetName.startsWith("widgetCustom")) {
widgetName = "widgetCustom";
JSONObject widgetData = widgetJSON.getJSONObject("data");
widgetUpdateTimeout = widgetData.getInt("update_timeout");
widgetTimeoutHideText = widgetData.getBoolean("timeout_hide_text");
widgetTimeoutShowCircle = widgetData.getBoolean("timeout_show_circle");
parsedWidget = new HybridHRWatchfaceWidget(widgetName,
widgetJSON.getJSONObject("pos").getInt("x"),
widgetJSON.getJSONObject("pos").getInt("y"),
widgetJSON.getJSONObject("size").getInt("w"),
widgetJSON.getJSONObject("size").getInt("h"),
widgetColor,
widgetUpdateTimeout,
widgetTimeoutHideText,
widgetTimeoutShowCircle);
} else {
parsedWidget = new HybridHRWatchfaceWidget(widgetName,
widgetJSON.getJSONObject("pos").getInt("x"),
widgetJSON.getJSONObject("pos").getInt("y"),
widgetJSON.getJSONObject("size").getInt("w"),
widgetJSON.getJSONObject("size").getInt("h"),
widgetColor);
}
return parsedWidget;
}
public Bitmap getPreviewImage(Context context) {
if (previewImage == null) {
previewImage = BitmapUtil.getCircularBitmap(background);
Canvas previewCanvas = new Canvas(previewImage);
int widgetSize = 50;
float scaleFactor = previewImage.getWidth() / 240;
for (int i=0; i<widgets.size(); i++) {
try {
HybridHRWatchfaceWidget parsedWidget = parseWidgetJSON(widgets.get(i));
Bitmap widgetPreview = Bitmap.createScaledBitmap(parsedWidget.getPreviewImage(context), (int)(widgetSize * scaleFactor), (int)(widgetSize * scaleFactor), true);
int offsetFromCenter = (int)((widgetSize/2) * scaleFactor);
previewCanvas.drawBitmap(widgetPreview, parsedWidget.getPosX() - offsetFromCenter, parsedWidget.getPosY() - offsetFromCenter, null);
} catch (JSONException e) {
LOG.warn("Couldn't parse widget JSON", e);
} catch (IOException e) {
LOG.warn("Couldn't parse widget JSON", e);
}
}
}
return previewImage;
}
} }