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" /> + +