diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9e0131889..18dd3b14f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -573,5 +573,6 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/CalibrationActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/CalibrationActivity.java
new file mode 100644
index 000000000..a231ee236
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/CalibrationActivity.java
@@ -0,0 +1,131 @@
+package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+
+import nodomain.freeyourgadget.gadgetbridge.GBApplication;
+import nodomain.freeyourgadget.gadgetbridge.R;
+import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
+import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
+import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport;
+
+public class CalibrationActivity extends AbstractGBActivity {
+ enum HAND{
+ MINUTE,
+ HOUR,
+ SUB;
+
+ public String getDisplayName(){
+ return name().substring(0, 1).toUpperCase() + name().substring(1).toLowerCase();
+ }
+
+ public String getVariableName(){
+ return name();
+ }
+
+
+ @NonNull
+ @Override
+ public String toString() {
+ return getDisplayName();
+ }
+ }
+
+ enum MOVE_BUTTON{
+ CLOCKWISE_ONE(R.id.qhybrid_calibration_clockwise_1, 1),
+ CLOCKWISE_TEN(R.id.qhybrid_calibration_clockwise_10, 10),
+ CLOCKWISE_HUNRED(R.id.qhybrid_calibration_clockwise_100, 100),
+
+ COUNTER_CLOCKWISE_ONE(R.id.qhybrid_calibration_counter_clockwise_1, -1),
+ COUNTER_CLOCKWISE_TEN(R.id.qhybrid_calibration_counter_clockwise_10, -10),
+ COUNTER_CLOCKWISE_HUNRED(R.id.qhybrid_calibration_counter_clockwise_100, -100),
+ ;
+
+ int layoutId;
+ int distance;
+
+ MOVE_BUTTON(int layoutId, int distance) {
+ this.layoutId = layoutId;
+ this.distance = distance;
+ }
+ }
+
+ HAND selectedHand = HAND.MINUTE;
+ LocalBroadcastManager localBroadcastManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_qhybrid_calibration);
+
+ GBDevice device = GBApplication.app().getDeviceManager().getSelectedDevice();
+
+ if(device == null || device.getType() != DeviceType.FOSSILQHYBRID){
+ Toast.makeText(this, R.string.watch_not_connected, Toast.LENGTH_LONG).show();
+ finish();
+ return;
+ }
+
+ localBroadcastManager = LocalBroadcastManager.getInstance(this);
+
+ localBroadcastManager.sendBroadcast(
+ new Intent(QHybridSupport.QHYBRID_COMMAND_CONTROL)
+ );
+
+ initViews();
+ }
+
+ private void initViews(){
+ Spinner handSpinner = findViewById(R.id.qhybrid_calibration_hand_spinner);
+ handSpinner.setAdapter(new ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, HAND.values()));
+ handSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ selectedHand = (HAND) parent.getSelectedItem();
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) {
+
+ }
+ });
+
+ for(final MOVE_BUTTON buttonDeclaration : MOVE_BUTTON.values()) {
+ final Button button = findViewById(buttonDeclaration.layoutId);
+
+ button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(QHybridSupport.QHYBRID_COMMAND_MOVE);
+ intent.putExtra("EXTRA_DISTANCE_" + selectedHand.getVariableName(), (short) buttonDeclaration.distance);
+
+ localBroadcastManager.sendBroadcast(intent);
+ }
+ });
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ finish();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ localBroadcastManager.sendBroadcast(new Intent(QHybridSupport.QHYBRID_COMMAND_SAVE_CALIBRATION));
+ localBroadcastManager.sendBroadcast(new Intent(QHybridSupport.QHYBRID_COMMAND_UNCONTROL));
+ }
+}
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 9c35bb33b..51dd69778 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
@@ -69,6 +69,7 @@ public class HRConfigActivity extends AbstractGBActivity implements View.OnClick
findViewById(R.id.qhybrid_action_add).setOnClickListener(this);
findViewById(R.id.qhybrid_file_management_trigger).setOnClickListener(this);
+ findViewById(R.id.calibration_trigger).setOnClickListener(this);
sharedPreferences = GBApplication.getPrefs().getPreferences();
@@ -405,6 +406,9 @@ public class HRConfigActivity extends AbstractGBActivity implements View.OnClick
} else if(v.getId() == R.id.qhybrid_file_management_trigger) {
finish();
startActivity(new Intent(getApplicationContext(), FileManagementActivity.class));
+ } else if(v.getId() == R.id.calibration_trigger) {
+ finish();
+ startActivity(new Intent(getApplicationContext(), CalibrationActivity.class));
}
}
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 8dd76b685..42a2b6323 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
@@ -72,6 +72,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.foss
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil_hr.FossilHRWatchAdapter;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.file.FileHandle;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.DownloadFileRequest;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.MoveHandsRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
@@ -80,6 +81,8 @@ public class QHybridSupport extends QHybridBaseSupport {
public static final String QHYBRID_COMMAND_CONTROL = "qhybrid_command_control";
public static final String QHYBRID_COMMAND_UNCONTROL = "qhybrid_command_uncontrol";
public static final String QHYBRID_COMMAND_SET = "qhybrid_command_set";
+ public static final String QHYBRID_COMMAND_MOVE = "qhybrid_command_move";
+ public static final String QHYBRID_COMMAND_SAVE_CALIBRATION = "qhybrid_command_save_calibration";
public static final String QHYBRID_COMMAND_VIBRATE = "qhybrid_command_vibrate";
public static final String QHYBRID_COMMAND_UPDATE = "qhybrid_command_update";
public static final String QHYBRID_COMMAND_UPDATE_TIMEZONE = "qhybrid_command_update_timezone";
@@ -143,6 +146,8 @@ public class QHybridSupport extends QHybridBaseSupport {
IntentFilter commandFilter = new IntentFilter(QHYBRID_COMMAND_CONTROL);
commandFilter.addAction(QHYBRID_COMMAND_UNCONTROL);
commandFilter.addAction(QHYBRID_COMMAND_SET);
+ commandFilter.addAction(QHYBRID_COMMAND_MOVE);
+ commandFilter.addAction(QHYBRID_COMMAND_SAVE_CALIBRATION);
commandFilter.addAction(QHYBRID_COMMAND_VIBRATE);
commandFilter.addAction(QHYBRID_COMMAND_UPDATE);
commandFilter.addAction(QHYBRID_COMMAND_UPDATE_TIMEZONE);
@@ -169,10 +174,17 @@ public class QHybridSupport extends QHybridBaseSupport {
case QHYBRID_COMMAND_CONTROL: {
log("sending control request");
watchAdapter.requestHandsControl();
+ MoveHandsRequest.MovementConfiguration movement = new MoveHandsRequest.MovementConfiguration(false);
if (config != null) {
- watchAdapter.setHands(config.getHour(), config.getMin());
+ if(config.getHour() != -1) movement.setHourDegrees(config.getHour());
+ if(config.getMin() != -1) movement.setHourDegrees(config.getMin());
+ if(config.getSubEye() != -1) movement.setHourDegrees(config.getSubEye());
+ watchAdapter.setHands(movement);
} else {
- watchAdapter.setHands((short) 0, (short) 0);
+ movement.setHourDegrees(0);
+ movement.setMinuteDegrees(0);
+ movement.setSubDegrees(0);
+ watchAdapter.setHands(movement);
}
break;
}
@@ -181,9 +193,24 @@ public class QHybridSupport extends QHybridBaseSupport {
break;
}
case QHYBRID_COMMAND_SET: {
- if (config != null) {
- watchAdapter.setHands(config.getHour(), config.getMin());
- }
+ if(config == null) break;
+ MoveHandsRequest.MovementConfiguration movement = new MoveHandsRequest.MovementConfiguration(false);
+ if(config.getHour() != -1) movement.setHourDegrees(config.getHour());
+ if(config.getMin() != -1) movement.setHourDegrees(config.getMin());
+ if(config.getSubEye() != -1) movement.setHourDegrees(config.getSubEye());
+ watchAdapter.setHands(movement);
+ break;
+ }
+ case QHYBRID_COMMAND_MOVE: {
+ MoveHandsRequest.MovementConfiguration movement = new MoveHandsRequest.MovementConfiguration(true);
+ if(extras.containsKey("EXTRA_DISTANCE_HOUR")) movement.setHourDegrees(extras.getShort("EXTRA_DISTANCE_HOUR"));
+ if(extras.containsKey("EXTRA_DISTANCE_MINUTE")) movement.setMinuteDegrees(extras.getShort("EXTRA_DISTANCE_MINUTE"));
+ if(extras.containsKey("EXTRA_DISTANCE_SUB")) movement.setSubDegrees(extras.getShort("EXTRA_DISTANCE_SUB"));
+ watchAdapter.setHands(movement);
+ break;
+ }
+ case QHYBRID_COMMAND_SAVE_CALIBRATION: {
+ watchAdapter.saveCalibration();
break;
}
case QHYBRID_COMMAND_VIBRATE: {
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 68abc1ebd..7bc9f40bd 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
@@ -31,6 +31,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.file.FileHandle;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.MoveHandsRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest;
public abstract class WatchAdapter {
@@ -55,7 +56,8 @@ public abstract class WatchAdapter {
public abstract void setTime();
public abstract void overwriteButtons(String buttonConfigJson);
public abstract void setActivityHand(double progress);
- public abstract void setHands(short hour, short minute);
+ public abstract void setHands(MoveHandsRequest.MovementConfiguration movement);
+ public abstract void saveCalibration();
public abstract void vibrate(PlayNotificationRequest.VibrationType vibration);
public abstract void vibrateFindMyDevicePattern();
public abstract void requestHandsControl();
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil/FossilWatchAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil/FossilWatchAdapter.java
index c8d2302ae..975e98a02 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil/FossilWatchAdapter.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil/FossilWatchAdapter.java
@@ -63,6 +63,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.mis
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.MoveHandsRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.ReleaseHandsControlRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.RequestHandControlRequest;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.SaveCalibrationRequest;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport.ITEM_STEP_GOAL;
@@ -279,10 +280,14 @@ public class FossilWatchAdapter extends WatchAdapter {
}
@Override
- public void setHands(short hour, short minute) {
- queueWrite(new MoveHandsRequest(false, minute, hour, (short) -1), false);
+ public void setHands(MoveHandsRequest.MovementConfiguration movement) {
+ queueWrite(new MoveHandsRequest(movement), false);
}
+ @Override
+ public void saveCalibration() {
+ queueWrite(new SaveCalibrationRequest());
+ }
public void vibrate(nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest.VibrationType vibration) {
// queueWrite(new nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest(vibration, -1, -1));
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/misfit/MisfitWatchAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/misfit/MisfitWatchAdapter.java
index b40119ca5..a3eceeacb 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/misfit/MisfitWatchAdapter.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/misfit/MisfitWatchAdapter.java
@@ -68,6 +68,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.mis
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.ReleaseHandsControlRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.RequestHandControlRequest;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.SaveCalibrationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.SetCurrentStepCountRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.SetStepGoalRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.SetTimeRequest;
@@ -368,11 +369,6 @@ public class MisfitWatchAdapter extends WatchAdapter {
queueWrite(new SetCurrentStepCountRequest(Math.min((int) (1000000 * progress), 999999)));
}
-
- public void setHands(short hour, short minute) {
- queueWrite(new MoveHandsRequest(false, minute, hour, (short) -1));
- }
-
public void vibrate(PlayNotificationRequest.VibrationType vibration) {
queueWrite(new PlayNotificationRequest(vibration, -1, -1));
}
@@ -382,7 +378,6 @@ public class MisfitWatchAdapter extends WatchAdapter {
queueWrite(new VibrateRequest(false, (short) 4, (short) 1));
}
-
@Override
public void requestHandsControl() {
queueWrite(new RequestHandControlRequest());
@@ -393,6 +388,16 @@ public class MisfitWatchAdapter extends WatchAdapter {
queueWrite(new ReleaseHandsControlRequest());
}
+ @Override
+ public void setHands(MoveHandsRequest.MovementConfiguration movement) {
+ queueWrite(new MoveHandsRequest(movement));
+ }
+
+ @Override
+ public void saveCalibration() {
+ queueWrite(new SaveCalibrationRequest());
+ }
+
@Override
public void setStepGoal(int stepGoal) {
queueWrite(new SetStepGoalRequest(stepGoal));
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/misfit/MoveHandsRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/misfit/MoveHandsRequest.java
index 0868da136..007d7cb84 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/misfit/MoveHandsRequest.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/misfit/MoveHandsRequest.java
@@ -22,36 +22,50 @@ import java.nio.ByteBuffer;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.Request;
public class MoveHandsRequest extends Request {
- public MoveHandsRequest(boolean moveRelative, short degreesMin, short degreesHour, short degreesSub){
- init(moveRelative, degreesMin, degreesHour, degreesSub);
+ public MoveHandsRequest(MovementConfiguration movement){
+ init(movement);
}
- private void init(boolean moveRelative, short degreesMin, short degreesHour, short degreesSub) {
+ private void init(MovementConfiguration movement) {
int count = 0;
- if(degreesHour != -1) count++;
- if(degreesMin != -1) count++;
- if(degreesSub != -1) count++;
+ if(movement.isHourSet()) count++;
+ if(movement.isMinuteSet()) count++;
+ if(movement.isSubSet()) count++;
ByteBuffer buffer = createBuffer(count * 5 + 5);
- buffer.put(moveRelative ? 1 : (byte)2);
+ buffer.put(movement.isRelativeMovement() ? 1 : (byte)2);
buffer.put((byte)count);
- if(degreesHour > -1){
+ if(movement.isHourSet()){
buffer.put((byte)1);
- buffer.putShort(degreesHour);
- buffer.put((byte)3);
+ buffer.putShort((short)Math.abs(movement.getHourDegrees()));
+ if(movement.isRelativeMovement()){
+ buffer.put(movement.getHourDegrees() >= 0 ? (byte) 1 : (byte) 2);
+ }else {
+ buffer.put((byte)3);
+ }
buffer.put((byte)1);
}
- if(degreesMin > -1){
+
+ if(movement.isMinuteSet()){
buffer.put((byte)2);
- buffer.putShort(degreesMin);
- buffer.put((byte)3);
+ buffer.putShort((short)Math.abs(movement.getMinuteDegrees()));
+ if(movement.isRelativeMovement()){
+ buffer.put(movement.getMinuteDegrees() >= 0 ? (byte) 1 : (byte) 2);
+ }else {
+ buffer.put((byte)3);
+ }
buffer.put((byte)1);
}
- if(degreesSub > -1){
- buffer.put((byte)3);
- buffer.putShort(degreesSub);
+
+ if(movement.isSubSet()){
buffer.put((byte)3);
+ buffer.putShort((short)Math.abs(movement.getSubDegrees()));
+ if(movement.isRelativeMovement()){
+ buffer.put(movement.getSubDegrees() >= 0 ? (byte) 1 : (byte) 2);
+ }else {
+ buffer.put((byte)3);
+ }
buffer.put((byte)1);
}
@@ -62,4 +76,61 @@ public class MoveHandsRequest extends Request {
public byte[] getStartSequence() {
return new byte[]{2, 21, 3};
}
+
+ static public class MovementConfiguration{
+ private int hourDegrees, minuteDegrees, subDegrees;
+ private boolean hourSet = false, minuteSet = false, subSet = false;
+ private boolean relativeMovement;
+
+ public MovementConfiguration(boolean relativeMovement) {
+ this.relativeMovement = relativeMovement;
+ }
+
+ public boolean isRelativeMovement() {
+ return relativeMovement;
+ }
+
+ public void setRelativeMovement(boolean relativeMovement) {
+ this.relativeMovement = relativeMovement;
+ }
+
+ public int getHourDegrees() {
+ return hourDegrees;
+ }
+
+ public void setHourDegrees(int hourDegrees) {
+ this.hourDegrees = hourDegrees;
+ this.hourSet = true;
+ }
+
+ public int getMinuteDegrees() {
+ return minuteDegrees;
+ }
+
+ public void setMinuteDegrees(int minuteDegrees) {
+ this.minuteDegrees = minuteDegrees;
+ this.minuteSet = true;
+ }
+
+ public int getSubDegrees() {
+ return subDegrees;
+ }
+
+ public void setSubDegrees(int subDegrees) {
+ this.subDegrees = subDegrees;
+ this.subSet = true;
+ }
+
+ public boolean isHourSet() {
+ return hourSet;
+ }
+
+ public boolean isMinuteSet() {
+ return minuteSet;
+ }
+
+ public boolean isSubSet() {
+ return subSet;
+ }
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/misfit/SaveCalibrationRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/misfit/SaveCalibrationRequest.java
new file mode 100644
index 000000000..f064c9c8a
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/misfit/SaveCalibrationRequest.java
@@ -0,0 +1,10 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
+
+import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.Request;
+
+public class SaveCalibrationRequest extends Request {
+ @Override
+ public byte[] getStartSequence() {
+ return new byte[]{0x02, (byte) 0xF2, 0x0E};
+ }
+}
diff --git a/app/src/main/res/layout/activity_qhybrid_calibration.xml b/app/src/main/res/layout/activity_qhybrid_calibration.xml
new file mode 100644
index 000000000..ff4dedb6e
--- /dev/null
+++ b/app/src/main/res/layout/activity_qhybrid_calibration.xml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
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 3404d617a..461306874 100644
--- a/app/src/main/res/layout/activity_qhybrid_hr_settings.xml
+++ b/app/src/main/res/layout/activity_qhybrid_hr_settings.xml
@@ -118,11 +118,16 @@
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index aac65c2ff..d36520c29 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -1106,4 +1106,5 @@
Mittlere Taste kurz
Obere Taste kurz
Schrittlänge in cm
+ Zeiger auf 12:00 ausrichten
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7cde1ece4..303942cca 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1063,6 +1063,7 @@
Backstroke
Medley
Nut mini
+ align hands to 12:00
- %d hour
- %d hours