diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8c89312be..5d444a7a4 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -507,6 +507,9 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HRConfigActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HRConfigActivity.java
index ba104f634..680348269 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HRConfigActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HRConfigActivity.java
@@ -4,7 +4,10 @@ import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.net.Uri;
import android.os.Bundle;
+import android.provider.MediaStore;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
@@ -26,6 +29,7 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -53,6 +57,9 @@ public class HRConfigActivity extends AbstractGBActivity implements View.OnClick
SparseArray widgetButtonsMapping = new SparseArray<>(4);
static public final String CONFIG_KEY_Q_ACTIONS = "Q_ACTIONS";
+ private static final int REQUEST_CODE_WIDGET_EDIT = 0;
+ private static final int REQUEST_CODE_IMAGE_PICK = 1;
+ private static final int REQUEST_CODE_IMAGE_EDIT = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -84,7 +91,7 @@ public class HRConfigActivity extends AbstractGBActivity implements View.OnClick
startIntent.putExtra("EXTRA_WIDGET", widget);
startIntent.putExtra("EXTRA_WIDGET_IDNEX", position);
- startActivityForResult(startIntent, 0);
+ startActivityForResult(startIntent, REQUEST_CODE_WIDGET_EDIT);
}
});
loadCustomWidgetList();
@@ -94,7 +101,27 @@ public class HRConfigActivity extends AbstractGBActivity implements View.OnClick
public void onClick(View v) {
Intent startIntent = new Intent(HRConfigActivity.this, WidgetSettingsActivity.class);
- startActivityForResult(startIntent, 0);
+ startActivityForResult(startIntent, REQUEST_CODE_WIDGET_EDIT);
+ }
+ });
+
+ findViewById(R.id.qhybrid_set_background).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ new AlertDialog.Builder(HRConfigActivity.this)
+ .setTitle("whoop whoop")
+ .setMessage("background has to be pushed every time a custom widget changes, causing traffic and battery drain. Consider that when using custom widgets.")
+ .setPositiveButton("ok", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ Intent pickIntent = new Intent(Intent.ACTION_PICK);
+ pickIntent.setType("image/*");
+
+ startActivityForResult(pickIntent, REQUEST_CODE_IMAGE_PICK);
+ }
+ })
+ .setNegativeButton("nah", null)
+ .show();
}
});
@@ -138,34 +165,50 @@ public class HRConfigActivity extends AbstractGBActivity implements View.OnClick
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(data == null) return;
- if (resultCode == WidgetSettingsActivity.RESULT_CODE_WIDGET_CREATED) {
- CustomWidget widget = (CustomWidget) data.getExtras().get("EXTRA_WIDGET");
- this.customWidgets.add(widget);
- refreshWidgetList();
- saveCustomWidgetList();
+ if(requestCode == REQUEST_CODE_WIDGET_EDIT) {
+ if (resultCode == WidgetSettingsActivity.RESULT_CODE_WIDGET_CREATED) {
+ CustomWidget widget = (CustomWidget) data.getExtras().get("EXTRA_WIDGET");
+ this.customWidgets.add(widget);
+ refreshWidgetList();
+ saveCustomWidgetList();
- LocalBroadcastManager.getInstance(HRConfigActivity.this).sendBroadcast(new Intent(QHYBRID_COMMAND_UPDATE_WIDGETS));
- } else if (resultCode == WidgetSettingsActivity.RESULT_CODE_WIDGET_UPDATED) {
- CustomWidget widget = (CustomWidget) data.getExtras().get("EXTRA_WIDGET");
- int updateIndex = data.getIntExtra("EXTRA_WIDGET_IDNEX", -1);
+ LocalBroadcastManager.getInstance(HRConfigActivity.this).sendBroadcast(new Intent(QHYBRID_COMMAND_UPDATE_WIDGETS));
+ } else if (resultCode == WidgetSettingsActivity.RESULT_CODE_WIDGET_UPDATED) {
+ CustomWidget widget = (CustomWidget) data.getExtras().get("EXTRA_WIDGET");
+ int updateIndex = data.getIntExtra("EXTRA_WIDGET_IDNEX", -1);
- this.customWidgets.set(updateIndex, widget);
+ this.customWidgets.set(updateIndex, widget);
- refreshWidgetList();
- saveCustomWidgetList();
+ refreshWidgetList();
+ saveCustomWidgetList();
- LocalBroadcastManager.getInstance(HRConfigActivity.this).sendBroadcast(new Intent(QHYBRID_COMMAND_UPDATE_WIDGETS));
- } else if (resultCode == WidgetSettingsActivity.RESULT_CODE_WIDGET_DELETED){
- int updateIndex = data.getIntExtra("EXTRA_WIDGET_IDNEX", -1);
+ LocalBroadcastManager.getInstance(HRConfigActivity.this).sendBroadcast(new Intent(QHYBRID_COMMAND_UPDATE_WIDGETS));
+ } else if (resultCode == WidgetSettingsActivity.RESULT_CODE_WIDGET_DELETED) {
+ int updateIndex = data.getIntExtra("EXTRA_WIDGET_IDNEX", -1);
- this.customWidgets.remove(updateIndex);
+ this.customWidgets.remove(updateIndex);
- refreshWidgetList();
- saveCustomWidgetList();
+ refreshWidgetList();
+ saveCustomWidgetList();
- LocalBroadcastManager.getInstance(HRConfigActivity.this).sendBroadcast(new Intent(QHYBRID_COMMAND_UPDATE_WIDGETS));
+ LocalBroadcastManager.getInstance(HRConfigActivity.this).sendBroadcast(new Intent(QHYBRID_COMMAND_UPDATE_WIDGETS));
+ }
+ }else if(requestCode == REQUEST_CODE_IMAGE_PICK){
+ if (resultCode == RESULT_OK)
+ {
+ Uri imageUri = data.getData();
+ Intent activityIntent = new Intent();
+ activityIntent.setClass(this, ImageEditActivity.class);
+ activityIntent.setData(imageUri);
+
+ startActivityForResult(activityIntent, REQUEST_CODE_IMAGE_EDIT);
+ }
+ }else if(requestCode == REQUEST_CODE_IMAGE_EDIT){
+ if(resultCode == ImageEditActivity.RESULT_CODE_EDIT_SUCCESS){
+ data.setAction(QHybridSupport.QHYBRID_COMMAND_SET_BACKGROUND_IMAGE);
+ LocalBroadcastManager.getInstance(this).sendBroadcast(data);
+ }
}
-
}
private void saveCustomWidgetList() {
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/ImageEditActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/ImageEditActivity.java
new file mode 100644
index 000000000..a6d336f81
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/ImageEditActivity.java
@@ -0,0 +1,260 @@
+package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
+
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.MediaStore;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.Toast;
+
+import java.io.IOException;
+
+import nodomain.freeyourgadget.gadgetbridge.R;
+import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.image.AssetImage;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.image.AssetImageFactory;
+import nodomain.freeyourgadget.gadgetbridge.util.GB;
+
+public class ImageEditActivity extends AbstractGBActivity implements View.OnTouchListener {
+ static final public int RESULT_CODE_EDIT_SUCCESS = 0;
+
+ ImageView overlay;
+ Canvas overlayCanvas;
+ Paint overlayPaint;
+ Bitmap overlayBitmap, mainBitmap;
+
+ float x = 0, y = 0, diameter = 0, imageDimension = 0;
+ int imageWidth, imageHeight;
+
+ private enum MovementState {
+ MOVE_UPPER_LEFT,
+ MOVE_LOWER_RIGHT,
+ MOVE_FRAME
+ }
+ private MovementState movementState;
+ float movementStartX, movementStartY, movementStartFrameX, movementStartFrameY, movementStartDiameter, leftUpperDeltaX, leftUpperDeltaY;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_qhybrid_image_edit);
+
+ final RelativeLayout mainLayout = findViewById(R.id.qhybrid_image_edit_container);
+ overlay = findViewById(R.id.qhybrid_image_edit_image_overlay);
+ overlay.setOnTouchListener(this);
+
+ findViewById(R.id.qhybrid_image_edit_okay).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ finalizeImage();
+ }
+ });
+
+ mainLayout.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ fitImageToLayout(mainLayout);
+ } catch (IOException | RuntimeException e) {
+ GB.log("Error formatting image", GB.ERROR, e);
+ GB.toast("Error formatting image", Toast.LENGTH_LONG, GB.ERROR);
+ finish();
+ }
+ }
+ });
+ }
+
+ private void finalizeImage(){
+ Bitmap cropped = Bitmap.createBitmap(this.mainBitmap, (int) this.x, (int) this.y, (int) this.diameter, (int) this.diameter);
+ Bitmap scaled = Bitmap.createScaledBitmap(cropped, 400, 400, false);
+ cropped.recycle();
+
+ try {
+ AssetImage image = AssetImageFactory.createAssetImage(scaled, false, 0, 0, 0);
+
+ Intent resultIntent = new Intent();
+ resultIntent.putExtra("EXTRA_PIXELS_ENCODED", image.getFileData());
+ setResult(RESULT_CODE_EDIT_SUCCESS, resultIntent);
+ finish();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+
+ scaled.recycle();
+ }
+ }
+
+ private void fitImageToLayout(RelativeLayout mainLayout) throws IOException, RuntimeException {
+ float containerHeight = mainLayout.getHeight();
+ float containerWidth = mainLayout.getWidth();
+ float containerRelation = containerHeight / containerWidth;
+
+ Bitmap bitmap = this.createImageFromURI();
+ float imageHeight = bitmap.getHeight();
+ float imageWidth = bitmap.getWidth();
+ float imageRelation = imageHeight / imageWidth;
+
+ float scaleRatio;
+ if(imageRelation > containerRelation){
+ scaleRatio = containerHeight / imageHeight;
+ }else{
+ scaleRatio = containerWidth / imageWidth;
+ }
+
+ int scaledHeight = (int)(imageHeight * scaleRatio);
+ int scaledWidth = (int)(imageWidth * scaleRatio);
+
+ this.imageHeight = scaledHeight;
+ this.imageWidth = scaledWidth;
+
+ this.imageDimension = this.diameter = Math.min(scaledHeight, scaledWidth);
+
+ mainBitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, false);
+
+ ImageView mainImageView = findViewById(R.id.qhybrid_image_edit_image);
+ mainImageView.setImageBitmap(mainBitmap);
+ createOverlay(scaledWidth, scaledHeight);
+ }
+
+ private void createOverlay(int width, int height){
+ this.overlayBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
+ this.overlayCanvas = new Canvas(this.overlayBitmap);
+
+ this.overlayPaint = new Paint();
+ this.overlayPaint.setColor(Color.BLACK);
+ this.overlayPaint.setStyle(Paint.Style.STROKE);
+ this.overlayPaint.setStrokeWidth(imageDimension / 100);
+
+ renderOverlay();
+ }
+
+ private Bitmap createImageFromURI() throws IOException, RuntimeException {
+ Uri imageURI = getIntent().getData();
+ if (imageURI == null) {
+ throw new RuntimeException("no image attached");
+ }
+
+ ContentResolver resolver = getContentResolver();
+ Cursor c = resolver.query(imageURI, new String[]{MediaStore.Images.ImageColumns.ORIENTATION}, null, null, null);
+ c.moveToFirst();
+ int orientation = c.getInt(c.getColumnIndex(MediaStore.Images.ImageColumns.ORIENTATION));
+ c.close();
+ Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageURI);
+ if (orientation != 0) {
+ Matrix matrix = new Matrix();
+ matrix.postRotate(90);
+
+ bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
+ }
+
+ return bitmap;
+ }
+
+ private void renderOverlay() {
+ overlayCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
+
+ overlayCanvas.drawCircle(x, y, imageDimension / 15, overlayPaint);
+ overlayCanvas.drawCircle(x + diameter, y + diameter, imageDimension / 15, overlayPaint);
+
+ overlayCanvas.drawCircle(x + diameter / 2, y + diameter / 2, diameter / 2, overlayPaint);
+
+ overlay.setImageBitmap(overlayBitmap);
+ }
+
+ private void forceImageBoundaries(){
+ this.x = Math.max(this.x, 0);
+ this.y = Math.max(this.y, 0);
+
+ this.x = Math.min(this.x, this.imageWidth - diameter);
+ this.y = Math.min(this.y, this.imageHeight - diameter);
+ }
+
+ @Override
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+ if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
+ handleTouchDown(motionEvent);
+ }else if(motionEvent.getAction() == MotionEvent.ACTION_MOVE){
+ handleTouchMove(motionEvent);
+ }
+ return true;
+ }
+
+ private void handleTouchMove(MotionEvent motionEvent){
+ if(movementState == MovementState.MOVE_UPPER_LEFT){
+ float moveDeltaX = motionEvent.getX() - this.movementStartX;
+ float moveDeltaY = motionEvent.getY() - this.movementStartY;
+
+ float mid = (moveDeltaX + moveDeltaY) / 2;
+
+ this.diameter = this.movementStartDiameter - mid;
+ this.x = this.movementStartX + mid + this.leftUpperDeltaX;
+ this.y = this.movementStartY + mid + this.leftUpperDeltaY;
+ }else if(movementState == MovementState.MOVE_LOWER_RIGHT) {
+ float moveDeltaX = motionEvent.getX() - this.movementStartX;
+ float moveDeltaY = motionEvent.getY() - this.movementStartY;
+
+ float mid = (moveDeltaX + moveDeltaY) / 2;
+
+ this.diameter = this.movementStartDiameter + mid;
+ }else if(movementState == MovementState.MOVE_FRAME){
+ this.x = this.movementStartFrameX + (motionEvent.getX() - this.movementStartX);
+ this.y = this.movementStartFrameY + (motionEvent.getY() - this.movementStartY);
+ }
+
+ this.forceImageBoundaries();
+ renderOverlay();
+ }
+
+ private void handleTouchDown(MotionEvent motionEvent) {
+ this.movementStartX = motionEvent.getX();
+ this.movementStartY = motionEvent.getY();
+ this.movementStartFrameX = this.x;
+ this.movementStartFrameY = this.y;
+ this.movementStartDiameter = this.diameter;
+
+ final float threshold = imageDimension / 15;
+
+ float upperLeftDeltaX = this.x - motionEvent.getX();
+ float upperLeftDeltaY = this.y - motionEvent.getY();
+
+ float upperLeftDistance = (float) Math.sqrt(upperLeftDeltaX * upperLeftDeltaX + upperLeftDeltaY * upperLeftDeltaY);
+
+ if(upperLeftDistance < threshold){
+ // Toast.makeText(this, "upper left", 0).show();
+ this.leftUpperDeltaX = upperLeftDeltaX;
+ this.leftUpperDeltaY = upperLeftDeltaY;
+ this.movementState = MovementState.MOVE_UPPER_LEFT;
+ return;
+ }
+
+ float lowerLeftX = this.x + diameter;
+ float lowerLeftY = this.y + diameter;
+
+ float lowerRightDeltaX = lowerLeftX - motionEvent.getX();
+ float lowerRightDeltaY = lowerLeftY - motionEvent.getY();
+
+ float lowerRightDistance = (float) Math.sqrt(lowerRightDeltaX * lowerRightDeltaX + lowerRightDeltaY * lowerRightDeltaY);
+
+ if(lowerRightDistance < threshold){
+ // Toast.makeText(this, "lower right", 0).show();
+ this.movementState = MovementState.MOVE_LOWER_RIGHT;
+ return;
+ }
+
+ // Toast.makeText(this, "anywhere else", 0).show();
+ this.movementState = MovementState.MOVE_FRAME;
+ }
+}
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 e5a44b693..cb2d1eced 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
@@ -89,6 +89,7 @@ public class QHybridSupport extends QHybridBaseSupport {
public static final String QHYBRID_COMMAND_SET_MENU_MESSAGE = "nodomain.freeyourgadget.gadgetbridge.Q_SET_MENU_MESSAGE";
public static final String QHYBRID_COMMAND_SEND_MENU_ITEMS = "nodomain.freeyourgadget.gadgetbridge.Q_SEND_MENU_ITEMS";
public static final String QHYBRID_COMMAND_SET_WIDGET_CONTENT = "nodomain.freeyourgadget.gadgetbridge.Q_SET_WIDGET_CONTENT";
+ public static final String QHYBRID_COMMAND_SET_BACKGROUND_IMAGE = "nodomain.freeyourgadget.gadgetbridge.Q_SET_BACKGROUND_IMAGE";
private static final String QHYBRID_ACTION_SET_ACTIVITY_HAND = "nodomain.freeyourgadget.gadgetbridge.Q_SET_ACTIVITY_HAND";
@@ -144,6 +145,7 @@ public class QHybridSupport extends QHybridBaseSupport {
commandFilter.addAction(QHYBRID_COMMAND_NOTIFICATION_CONFIG_CHANGED);
commandFilter.addAction(QHYBRID_COMMAND_UPDATE_WIDGETS);
commandFilter.addAction(QHYBRID_COMMAND_SEND_MENU_ITEMS);
+ commandFilter.addAction(QHYBRID_COMMAND_SET_BACKGROUND_IMAGE);
commandReceiver = new BroadcastReceiver() {
@Override
@@ -230,6 +232,11 @@ public class QHybridSupport extends QHybridBaseSupport {
watchAdapter.updateWidgets();
break;
}
+ case QHYBRID_COMMAND_SET_BACKGROUND_IMAGE:{
+ byte[] pixels = intent.getByteArrayExtra("EXTRA_PIXELS_ENCODED");
+ watchAdapter.setBackgroundImage(pixels);
+ break;
+ }
}
}
};
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/WatchAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/WatchAdapter.java
index 629b14e21..634fde4fb 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/WatchAdapter.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/WatchAdapter.java
@@ -130,4 +130,7 @@ public abstract class WatchAdapter {
public void onSendWeather(WeatherSpec weatherSpec) {
}
+
+ public void setBackgroundImage(byte[] pixels) {
+ }
}
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 9d7721a20..b3aae5b96 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
@@ -1,6 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil_hr;
import android.bluetooth.BluetoothGattCharacteristic;
+import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
@@ -9,12 +10,16 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
+import android.widget.Toast;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.BufferOverflowException;
import java.util.ArrayList;
@@ -26,6 +31,7 @@ import java.util.TimeZone;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
+import nodomain.freeyourgadget.gadgetbridge.activities.GBActivity;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
@@ -145,21 +151,53 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
};
}
- private void loadBackground(){
- Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDeviceSupport().getDevice().getAddress()));
- boolean forceWhiteBackground = prefs.getBoolean("force_white_color_scheme", false);
- if (forceWhiteBackground) {
- Bitmap whiteBitmap = Bitmap.createBitmap(239, 239, Bitmap.Config.ARGB_8888);
- new Canvas(whiteBitmap).drawColor(Color.WHITE);
+ private File getBackgroundFile(){
+ return new File(getContext().getExternalFilesDir(null), "hr_background.bin");
+ }
- try {
- this.backGroundImage = AssetImageFactory.createAssetImage(whiteBitmap, true, 0, 1, 0);
- } catch (IOException e) {
- logger.error("Backgroundimage error", e);
+ private void loadBackground(){
+ try {
+ FileInputStream fis = new FileInputStream(getBackgroundFile());
+ int count = fis.available();
+ if(count != 14400){
+ throw new RuntimeException("wrong background file length");
}
+ byte[] file = new byte[14400];
+ fis.read(file);
+ fis.close();
+ this.backGroundImage = AssetImageFactory.createAssetImage(file, 0, 0, 0);
+ } catch (FileNotFoundException e) {
+ SharedPreferences preferences = getDeviceSpecificPreferences();
+ if (preferences.getBoolean("force_white_color_scheme", false)) {
+ Bitmap whiteBitmap = Bitmap.createBitmap(239, 239, Bitmap.Config.ARGB_8888);
+ new Canvas(whiteBitmap).drawColor(Color.WHITE);
+
+ try {
+ this.backGroundImage = AssetImageFactory.createAssetImage(whiteBitmap, true, 0, 1, 0);
+ queueWrite(new AssetFilePutRequest(this.backGroundImage, (byte) 0x00, this));
+ } catch (IOException e2) {
+ logger.error("Backgroundimage error", e2);
+ }
+ }
+ } catch (IOException | RuntimeException e) {
+ GB.log("error opening background file", GB.ERROR, e);
+ GB.toast("error opening background file", Toast.LENGTH_LONG, GB.ERROR);
}
}
+ @Override
+ public void setBackgroundImage(byte[] pixels) {
+ this.backGroundImage = AssetImageFactory.createAssetImage(pixels, 0, 0, 0);
+ try {
+ FileOutputStream fos = new FileOutputStream(getBackgroundFile(), false);
+ fos.write(pixels);
+ } catch (IOException e) {
+ GB.log("error saving background", GB.ERROR, e);
+ GB.toast("error persistent saving background", Toast.LENGTH_LONG, GB.ERROR);
+ }
+ renderWidgets();
+ }
+
private void loadWidgets() {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDeviceSupport().getDevice().getAddress()));
boolean forceWhiteBackground = prefs.getBoolean("force_white_color_scheme", false);
@@ -250,10 +288,6 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
try {
ArrayList widgetImages = new ArrayList<>();
- if(this.backGroundImage != null){
- widgetImages.add(this.backGroundImage);
- }
-
for (int i = 0; i < this.widgets.size(); i++) {
Widget w = widgets.get(i);
@@ -329,18 +363,19 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
));
}
- AssetImage[] images = widgetImages.toArray(new AssetImage[0]);
- // queueWrite(new FileDeleteRequest((short) 0x0700));
+ if(this.backGroundImage != null){
+ widgetImages.add(this.backGroundImage);
+ }
+
queueWrite(new AssetFilePutRequest(
- images,
+ widgetImages.toArray(new AssetImage[0]),
(byte) 0x00,
this
));
-
// queueWrite(new FileDeleteRequest((short) 0x0503));
queueWrite(new ImagesSetRequest(
- images,
+ widgetImages.toArray(new AssetImage[0]),
this
));
} catch (IOException e) {
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 4c33a686f..447be3e6f 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
@@ -17,6 +17,13 @@ public class AssetImage extends AssetFile {
this.indexZ = indexZ;
}
+ protected AssetImage(byte[] fileData, String fileName, int angle, int distance, int indexZ) {
+ super(fileName, fileData);
+ this.angle = angle;
+ this.distance = distance;
+ this.indexZ = indexZ;
+ }
+
@NonNull
@Override
public String toString() {
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 0426ef3ac..13162f110 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
@@ -16,7 +16,13 @@ public class AssetImageFactory {
return new AssetImage(fileData, angle, distance, indexZ);
}
+ // method created for creating empty files, which turned out not to work anyway
+ private static AssetImage createAssetImage(byte[] fileData, String fileName, int angle, int distance, int indexZ){
+ return new AssetImage(fileData, fileName, angle, distance, indexZ);
+ }
+
public static AssetImage createAssetImage(Bitmap fileData, boolean RLEencode, int angle, int distance, int indexZ) throws IOException {
+ if(RLEencode == (distance == 0)) throw new RuntimeException("when RLEencoding distance must be 0, image must be at center of screen");
if(RLEencode){
int height = fileData.getHeight();
int width = fileData.getWidth();
diff --git a/app/src/main/res/layout/activity_qhybrid_hr_settings.xml b/app/src/main/res/layout/activity_qhybrid_hr_settings.xml
index cc6a7bf82..778ea7d66 100644
--- a/app/src/main/res/layout/activity_qhybrid_hr_settings.xml
+++ b/app/src/main/res/layout/activity_qhybrid_hr_settings.xml
@@ -96,4 +96,11 @@
android:layout_height="wrap_content"
android:text="add widget" />
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_qhybrid_image_edit.xml b/app/src/main/res/layout/activity_qhybrid_image_edit.xml
new file mode 100644
index 000000000..709638d41
--- /dev/null
+++ b/app/src/main/res/layout/activity_qhybrid_image_edit.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file