mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2025-01-15 04:07:32 +01:00
added custom widgets
This commit is contained in:
parent
961c0aa97c
commit
0cf1b5966f
@ -532,6 +532,10 @@ public class QHybridSupport extends QHybridBaseSupport {
|
||||
}
|
||||
|
||||
public void notifiyException(Exception e){
|
||||
notifiyException("", e);
|
||||
}
|
||||
|
||||
public void notifiyException(String requestName, Exception e){
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
@ -544,7 +548,7 @@ public class QHybridSupport extends QHybridBaseSupport {
|
||||
notificationBuilder = new Notification.Builder(getContext());
|
||||
}
|
||||
notificationBuilder
|
||||
.setContentTitle("Q Error")
|
||||
.setContentTitle("Q Error " + requestName)
|
||||
.setSmallIcon(R.drawable.ic_notification_qhybrid)
|
||||
.setContentText(sStackTrace)
|
||||
.setStyle(new Notification.BigTextStyle())
|
||||
|
@ -460,7 +460,7 @@ public class FossilWatchAdapter extends WatchAdapter {
|
||||
requestFinished = fossilRequest.isFinished();
|
||||
} catch (RuntimeException e) {
|
||||
GB.log("error", GB.ERROR, e);
|
||||
getDeviceSupport().notifiyException(e);
|
||||
getDeviceSupport().notifiyException(fossilRequest.getName(), e);
|
||||
GB.toast(fossilRequest.getName() + " failed", Toast.LENGTH_SHORT, GB.ERROR);
|
||||
requestFinished = true;
|
||||
}
|
||||
|
@ -19,10 +19,12 @@ import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Random;
|
||||
import java.util.TimeZone;
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.Widget;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.HRConfigActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
@ -34,11 +36,13 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.encoder.RLEE
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.RequestMtuRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.SetDeviceStateRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.configuration.ConfigurationPutRequest.*;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FileDeleteRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayNotificationRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.authentication.VerifyPrivateKeyRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.buttons.ButtonConfigurationPutRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.configuration.ConfigurationGetRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.configuration.ConfigurationPutRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file.AssetFile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file.AssetFilePutRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.image.AssetImage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.image.AssetImageFactory;
|
||||
@ -46,6 +50,8 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fos
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.menu.SetCommuteMenuMessage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.music.MusicControlRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.music.MusicInfoSetRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomWidget;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomWidgetElement;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.utils.StringUtils;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.music.MusicControlRequest.*;
|
||||
@ -55,8 +61,12 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
||||
private byte[] phoneRandomNumber;
|
||||
private byte[] watchRandomNumber;
|
||||
|
||||
CustomWidget[] widgets;
|
||||
|
||||
private MusicSpec currentSpec = null;
|
||||
|
||||
int imageNameIndex = 0;
|
||||
|
||||
public FossilHRWatchAdapter(QHybridSupport deviceSupport) {
|
||||
super(deviceSupport);
|
||||
}
|
||||
@ -86,62 +96,89 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
||||
|
||||
overwriteButtons(null);
|
||||
|
||||
drawWidgetText("-");
|
||||
queueWrite(new FileDeleteRequest((short) 0x0700));
|
||||
|
||||
loadWidgets();
|
||||
renderWidgets();
|
||||
// dunno if there is any point in doing this at start since when no watch is connected the QHybridSupport will not receive any intents anyway
|
||||
|
||||
queueWrite(new SetDeviceStateRequest(GBDevice.State.INITIALIZED));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWidgetContent(String widgetID, String content) {
|
||||
drawWidgetText(content);
|
||||
private void loadWidgets() {
|
||||
CustomWidget ethWidget = new CustomWidget(0, 63);
|
||||
ethWidget.addElement(new CustomWidgetElement(CustomWidgetElement.WidgetElementType.TYPE_TEXT, "date", "-", CustomWidgetElement.X_CENTER, CustomWidgetElement.Y_UPPER_HALF));
|
||||
ethWidget.addElement(new CustomWidgetElement(CustomWidgetElement.WidgetElementType.TYPE_TEXT, "eth", "-", CustomWidgetElement.X_CENTER, CustomWidgetElement.Y_LOWER_HALF));
|
||||
|
||||
|
||||
CustomWidget btcWidget = new CustomWidget(90, 63);
|
||||
btcWidget.addElement(new CustomWidgetElement(CustomWidgetElement.WidgetElementType.TYPE_TEXT, "", "BTC", CustomWidgetElement.X_CENTER, CustomWidgetElement.Y_UPPER_HALF));
|
||||
btcWidget.addElement(new CustomWidgetElement(CustomWidgetElement.WidgetElementType.TYPE_TEXT, "btc", "wtf", CustomWidgetElement.X_CENTER, CustomWidgetElement.Y_LOWER_HALF));
|
||||
this.widgets = new CustomWidget[]{
|
||||
ethWidget,
|
||||
// btcWidget,
|
||||
};
|
||||
}
|
||||
|
||||
private void drawWidgetText(String text){
|
||||
|
||||
private void renderWidgets() {
|
||||
try {
|
||||
Bitmap testBitmap = Bitmap.createBitmap(76, 76, Bitmap.Config.ARGB_8888);
|
||||
AssetImage[] widgetImages = new AssetImage[this.widgets.length];
|
||||
|
||||
Canvas testCanvas = new Canvas(testBitmap);
|
||||
for (int i = 0; i < this.widgets.length; i++) {
|
||||
CustomWidget widget = widgets[i];
|
||||
|
||||
Paint circlePaint = new Paint();
|
||||
circlePaint.setColor(Color.WHITE);
|
||||
circlePaint.setStyle(Paint.Style.STROKE);
|
||||
circlePaint.setStrokeWidth(3);
|
||||
Bitmap widgetBitmap = Bitmap.createBitmap(76, 76, Bitmap.Config.ARGB_8888);
|
||||
|
||||
testCanvas.drawCircle(38, 38, 37, circlePaint);
|
||||
Canvas widgetCanvas = new Canvas(widgetBitmap);
|
||||
|
||||
circlePaint.setStrokeWidth(4);
|
||||
circlePaint.setTextSize(17f);
|
||||
circlePaint.setStyle(Paint.Style.FILL);
|
||||
circlePaint.setTextAlign(Paint.Align.CENTER);
|
||||
Paint circlePaint = new Paint();
|
||||
circlePaint.setColor(Color.WHITE);
|
||||
circlePaint.setStyle(Paint.Style.STROKE);
|
||||
circlePaint.setStrokeWidth(3);
|
||||
|
||||
testCanvas.drawText("ETH", 38, 76f / 3f * 1f - (circlePaint.descent() + circlePaint.ascent()) / 2f, circlePaint);
|
||||
testCanvas.drawText(text, 38, 76f / 3f * 2f - (circlePaint.descent() + circlePaint.ascent()) / 2f, circlePaint);
|
||||
widgetCanvas.drawCircle(38, 38, 37, circlePaint);
|
||||
|
||||
circlePaint.setStrokeWidth(1);
|
||||
circlePaint.setStyle(Paint.Style.STROKE);
|
||||
for (CustomWidgetElement element : widget.getElements()) {
|
||||
if (element.getWidgetElementType() == CustomWidgetElement.WidgetElementType.TYPE_TEXT) {
|
||||
Paint textPaint = new Paint();
|
||||
textPaint.setStrokeWidth(4);
|
||||
textPaint.setTextSize(17f);
|
||||
textPaint.setStyle(Paint.Style.FILL);
|
||||
textPaint.setColor(Color.WHITE);
|
||||
textPaint.setTextAlign(Paint.Align.CENTER);
|
||||
|
||||
// for(int i = 0; i <= 3; i++) testCanvas.drawLine(0, 76f / 3f * i - (i / 3), 76, 76f / 3f * i - (i / 3), circlePaint);
|
||||
widgetCanvas.drawText(element.getValue(), element.getX(), element.getY() - (textPaint.descent() + textPaint.ascent()) / 2f, textPaint);
|
||||
}
|
||||
}
|
||||
widgetImages[i] = AssetImageFactory.createAssetImage(
|
||||
StringUtils.bytesToHex(
|
||||
ByteBuffer.allocate(8)
|
||||
.putLong(System.currentTimeMillis() + imageNameIndex++)
|
||||
.array()
|
||||
)
|
||||
,
|
||||
widgetBitmap,
|
||||
true,
|
||||
widget.getAngle(),
|
||||
widget.getDistance(),
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
AssetImage image = AssetImageFactory.createAssetImage(
|
||||
StringUtils.bytesToHex(
|
||||
ByteBuffer.allocate(4)
|
||||
.putInt((int) System.currentTimeMillis())
|
||||
.array()
|
||||
)
|
||||
, testBitmap, true, 0, 60, 1);
|
||||
|
||||
AssetImage[] images = new AssetImage[]{
|
||||
image,
|
||||
};
|
||||
|
||||
queueWrite(new AssetFilePutRequest(
|
||||
images,
|
||||
new AssetFile[]{widgetImages[0]},
|
||||
this
|
||||
));
|
||||
|
||||
// for(int i = 0; i < widgetImages.length; i++){
|
||||
// queueWrite(new AssetFilePutRequest(widgetImages[i], i + 1, this));
|
||||
// }
|
||||
|
||||
// widgetImages[1].setFileName(widgetImages[0].getFileName());
|
||||
|
||||
queueWrite(new ImagesSetRequest(
|
||||
images,
|
||||
widgetImages,
|
||||
this
|
||||
));
|
||||
} catch (IOException e) {
|
||||
@ -149,6 +186,20 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWidgetContent(String widgetID, String content) {
|
||||
boolean update = false;
|
||||
for(CustomWidget widget : this.widgets){
|
||||
CustomWidgetElement element = widget.getElement(widgetID);
|
||||
if(element == null) continue;
|
||||
|
||||
element.setValue(content);
|
||||
update = true;
|
||||
}
|
||||
|
||||
if(update) renderWidgets();
|
||||
}
|
||||
|
||||
private void negotiateSymmetricKey() {
|
||||
queueWrite(new VerifyPrivateKeyRequest(
|
||||
this.getSecretKey(),
|
||||
@ -279,32 +330,31 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
||||
|
||||
if (requestType == (byte) 0x05) {
|
||||
handleMusicRequest(value);
|
||||
return;
|
||||
}
|
||||
}else if(requestType == (byte) 0x01) {
|
||||
int eventId = value[2];
|
||||
|
||||
int eventId = value[2];
|
||||
try {
|
||||
JSONObject requestJson = new JSONObject(new String(value, 3, value.length - 3));
|
||||
|
||||
try {
|
||||
JSONObject requestJson = new JSONObject(new String(value, 3, value.length - 3));
|
||||
String action = requestJson.getJSONObject("req").getJSONObject("commuteApp._.config.commute_info")
|
||||
.getString("dest");
|
||||
|
||||
String action = requestJson.getJSONObject("req").getJSONObject("commuteApp._.config.commute_info")
|
||||
.getString("dest");
|
||||
String startStop = requestJson.getJSONObject("req").getJSONObject("commuteApp._.config.commute_info")
|
||||
.getString("action");
|
||||
|
||||
String startStop = requestJson.getJSONObject("req").getJSONObject("commuteApp._.config.commute_info")
|
||||
.getString("action");
|
||||
if (startStop.equals("stop")) {
|
||||
// overwriteButtons(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (startStop.equals("stop")) {
|
||||
// overwriteButtons(null);
|
||||
return;
|
||||
queueWrite(new SetCommuteMenuMessage("Anfrage wird weitergeleitet...", false, this));
|
||||
|
||||
Intent menuIntent = new Intent(QHybridSupport.QHYBRID_EVENT_COMMUTE_MENU);
|
||||
menuIntent.putExtra("EXTRA_ACTION", action);
|
||||
getContext().sendBroadcast(menuIntent);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
queueWrite(new SetCommuteMenuMessage("Anfrage wird weitergeleitet...", false, this));
|
||||
|
||||
Intent menuIntent = new Intent(QHybridSupport.QHYBRID_EVENT_COMMUTE_MENU);
|
||||
menuIntent.putExtra("EXTRA_ACTION", action);
|
||||
getContext().sendBroadcast(menuIntent);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.FossilRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file.ResultCode;
|
||||
|
||||
public class FileDeleteRequest extends FossilRequest {
|
||||
private boolean finished = false;
|
||||
@ -53,7 +54,8 @@ public class FileDeleteRequest extends FossilRequest {
|
||||
|
||||
if(buffer.getShort(1) != this.handle) throw new RuntimeException("wrong response handle");
|
||||
|
||||
if(buffer.get(3) != 0) throw new RuntimeException("wrong response status: " + buffer.get(3));
|
||||
byte status = buffer.get(3);
|
||||
if(status != 0) throw new RuntimeException("wrong response status: " + ResultCode.fromCode(status) + "(" + status + ")");
|
||||
|
||||
this.finished = true;
|
||||
}
|
||||
|
@ -16,4 +16,8 @@ public class AssetFile {
|
||||
public byte[] getFileData() {
|
||||
return fileData;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,10 @@ public class AssetFilePutRequest extends FilePutRequest {
|
||||
super((short) 0x0700, prepareFileData(file), adapter);
|
||||
}
|
||||
|
||||
public AssetFilePutRequest(AssetFile file, int subHandle, FossilWatchAdapter adapter) throws IOException {
|
||||
super((short) (0x0700 | subHandle), prepareFileData(file), adapter);
|
||||
}
|
||||
|
||||
private static byte[] prepareFileData(AssetFile[] files) throws IOException {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
|
||||
|
@ -0,0 +1,40 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class CustomWidget {
|
||||
private HashMap<String, CustomWidgetElement> elements = new HashMap<>();
|
||||
private int angle, distance;
|
||||
|
||||
public CustomWidget(int angle, int distance) {
|
||||
this.angle = angle;
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
public int getAngle() {
|
||||
return angle;
|
||||
}
|
||||
|
||||
public int getDistance() {
|
||||
return distance;
|
||||
}
|
||||
|
||||
public Collection<CustomWidgetElement> getElements(){
|
||||
return this.elements.values();
|
||||
}
|
||||
|
||||
public void addElement(CustomWidgetElement element){
|
||||
this.elements.put(element.getId(), element);
|
||||
}
|
||||
|
||||
public CustomWidgetElement getElement(String id){
|
||||
return elements.get(id);
|
||||
}
|
||||
|
||||
public CustomWidgetElement removeElement(String id){
|
||||
return elements.remove(id);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget;
|
||||
|
||||
public class CustomWidgetElement {
|
||||
public enum WidgetElementType {
|
||||
TYPE_TEXT,
|
||||
TYPE_IMAGE,
|
||||
TYPE_BACKGROUND
|
||||
}
|
||||
|
||||
public final static int X_CENTER = 38;
|
||||
public final static int Y_UPPER_HALF = (int) (76f / 3 * 1);
|
||||
public final static int Y_LOWER_HALF = (int) (76f / 3 * 2);
|
||||
|
||||
private WidgetElementType widgetElementType;
|
||||
private String id, value;
|
||||
private int x, y;
|
||||
|
||||
public CustomWidgetElement(WidgetElementType widgetElementType, String id, String value, int x, int y) {
|
||||
this.widgetElementType = widgetElementType;
|
||||
this.id = id;
|
||||
this.value = value;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public WidgetElementType getWidgetElementType() {
|
||||
return widgetElementType;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user