1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-06-16 10:00:08 +02:00

Fossil Hybrid: added hands calibration

This commit is contained in:
Daniel Dakhno 2020-10-22 12:43:40 +02:00
parent 4131f19f8d
commit c85e30cb07
13 changed files with 389 additions and 31 deletions

View File

@ -573,5 +573,6 @@
<activity
android:name=".devices.qhybrid.FileManagementActivity"
android:exported="true" />
<activity android:name=".devices.qhybrid.CalibrationActivity" />
</application>
</manifest>

View File

@ -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<HAND>(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));
}
}

View File

@ -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));
}
}

View File

@ -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: {

View File

@ -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();

View File

@ -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));

View File

@ -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));

View File

@ -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;
}
}
}

View File

@ -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};
}
}

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/qhybrid_calibration_align_hint" />
<Spinner
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/qhybrid_calibration_hand_spinner" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="2">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="counter-dlockwise"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/qhybrid_calibration_counter_clockwise_1"
android:text="1" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/qhybrid_calibration_counter_clockwise_10"
android:text="10" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/qhybrid_calibration_counter_clockwise_100"
android:text="100" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="clockwise"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/qhybrid_calibration_clockwise_1"
android:text="1" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/qhybrid_calibration_clockwise_10"
android:text="10" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/qhybrid_calibration_clockwise_100"
android:text="100" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -118,11 +118,16 @@
</LinearLayout>
<Button
android:id="@+id/qhybrid_file_management_trigger"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="File management" />
<Button
android:id="@+id/calibration_trigger"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Calibration" />
</LinearLayout>

View File

@ -1106,4 +1106,5 @@
<string name="pref_title_middle_button_function_short">Mittlere Taste kurz</string>
<string name="pref_title_upper_button_function_short">Obere Taste kurz</string>
<string name="activity_prefs_step_length_cm">Schrittlänge in cm</string>
<string name="qhybrid_calibration_align_hint">Zeiger auf 12:00 ausrichten</string>
</resources>

View File

@ -1063,6 +1063,7 @@
<string name="backstroke">Backstroke</string>
<string name="medley">Medley</string>
<string name="devicetype_nut_mini">Nut mini</string>
<string name="qhybrid_calibration_align_hint">align hands to 12:00</string>
<plurals name="widget_alarm_target_hours">
<item quantity="one">%d hour</item>
<item quantity="two">%d hours</item>