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:
parent
c2d98b5a24
commit
7f026edbd0
@ -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);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user