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 442d644fe..c6f21498e 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
@@ -169,6 +169,7 @@ public class FossilWatchAdapter extends WatchAdapter {
requestQueue.clear();
}
log("characteristic write failed: " + status);
+ GB.toast(fossilRequest.getName() + " characteristic write failed: " + status, Toast.LENGTH_SHORT, GB.ERROR);
fossilRequest = null;
queueNextRequest();
@@ -583,7 +584,7 @@ public class FossilWatchAdapter extends WatchAdapter {
requestFinished = fossilRequest.isFinished();
} catch (RuntimeException e) {
if (characteristic.getUuid().toString().equals("3dda0005-957f-7d4a-34a6-74696673696d")) {
- GB.log("authentication failed", GB.ERROR, null);
+ GB.log("authentication failed", GB.ERROR, e);
// setDeviceState(GBDevice.State.AUTHENTICATION_REQUIRED);
}else {
GB.log("error", GB.ERROR, e);
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 ee7dfedcb..3ba3ee631 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
@@ -110,6 +110,8 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fos
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.application.ApplicationInformation;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.application.ApplicationsListRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.async.ConfirmAppStatusRequest;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.authentication.CheckDeviceNeedsConfirmationRequest;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.authentication.ConfirmOnDeviceRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.authentication.VerifyPrivateKeyRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.buttons.ButtonConfiguration;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.buttons.ButtonConfigurationPutRequest;
@@ -211,9 +213,44 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
private void initializeAfterAuthentication(boolean authenticated) {
queueWrite(new SetDeviceStateRequest(GBDevice.State.INITIALIZING));
- if (!authenticated)
+ if (!authenticated) {
GB.toast(getContext().getString(R.string.fossil_hr_auth_failed), Toast.LENGTH_LONG, GB.ERROR);
+ initializeAfterWatchConfirmation(false);
+ return;
+ }
+ boolean shouldAuthenticateOnWatch = getDeviceSpecificPreferences().getBoolean("enable_on_device_confirmation", true);
+ if(!shouldAuthenticateOnWatch){
+ GB.toast("Skipping on-device confirmation", Toast.LENGTH_SHORT, GB.INFO);
+ initializeAfterWatchConfirmation(false);
+ return;
+ }
+ confirmOnWatch();
+ }
+ private void confirmOnWatch() {
+ queueWrite(new CheckDeviceNeedsConfirmationRequest() {
+ @Override
+ public void onResult(boolean needsConfirmation) {
+ GB.log("needs confirmation: " + needsConfirmation, GB.INFO, null);
+ if(needsConfirmation){
+ GB.toast("please confirm on device.", Toast.LENGTH_SHORT, GB.INFO);
+ queueWrite( new ConfirmOnDeviceRequest(){
+ @Override
+ public void onResult(boolean confirmationSuccess) {
+ if(!confirmationSuccess){
+ GB.toast("connection unconfirmed on watch, unauthenticated mode", Toast.LENGTH_LONG, GB.ERROR);
+ }
+ initializeAfterWatchConfirmation(confirmationSuccess);
+ }
+ }, true);
+ }else{
+ initializeAfterWatchConfirmation(true);
+ }
+ }
+ });
+ }
+
+ private void initializeAfterWatchConfirmation(boolean authenticated){
setNotificationConfigurations();
setQuickRepliesConfiguration();
@@ -1224,22 +1261,23 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
@Override
public void onTestNewFunction() {
+ queueWrite(new FossilRequest() {
+ @Override
+ public boolean isFinished() {
+ return true;
+ }
- try{
- JSONObject data = new JSONObject()
- .put("push", new JSONObject()
- .put("set", new JSONObject()
- .put("widgetCustom0._.config.upper_text", "0 up")
- .put("widgetCustom0._.config.lower_text", "0 low")
+ @Override
+ public byte[] getStartSequence() {
+ return new byte[]{0x01, 0x07};
+ }
- .put("widgetCustom1._.config.upper_text", "1 up")
- .put("widgetCustom1._.config.lower_text", "1 low")
- )
- );
- queueWrite(new JsonPutRequest(data, this));
- }catch (Exception e) {
- e.printStackTrace();
- }
+ @Override
+ public UUID getRequestUUID() {
+ return UUID.fromString("3dda0005-957f-7d4a-34a6-74696673696d");
+ }
+ });
+ queueWrite(new ConfirmOnDeviceRequest());
}
public byte[] getSecretKey() throws IllegalAccessException {
@@ -1483,6 +1521,14 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
}
}
+ @Override
+ public void onFindDevice(boolean start) {
+ super.onFindDevice(start);
+ if(start){
+ queueWrite(new ConfirmOnDeviceRequest());
+ }
+ }
+
private void handleDeleteNotification(byte[] value) {
ByteBuffer buffer = ByteBuffer.wrap(value);
buffer.order(ByteOrder.LITTLE_ENDIAN);
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/AuthenticationRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/AuthenticationRequest.java
new file mode 100644
index 000000000..94a38b062
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/AuthenticationRequest.java
@@ -0,0 +1,12 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.authentication;
+
+import java.util.UUID;
+
+import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.FossilRequest;
+
+public abstract class AuthenticationRequest extends FossilRequest {
+ @Override
+ public UUID getRequestUUID() {
+ return UUID.fromString("3dda0005-957f-7d4a-34a6-74696673696d");
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/CheckDeviceNeedsConfirmationRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/CheckDeviceNeedsConfirmationRequest.java
new file mode 100644
index 000000000..38d49f949
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/CheckDeviceNeedsConfirmationRequest.java
@@ -0,0 +1,34 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.authentication;
+
+import android.bluetooth.BluetoothGattCharacteristic;
+
+public abstract class CheckDeviceNeedsConfirmationRequest extends AuthenticationRequest {
+ private boolean isFinished = false;
+ @Override
+ public byte[] getStartSequence() {
+ return new byte[]{0x01, 0x07};
+ }
+
+ @Override
+ public void handleResponse(BluetoothGattCharacteristic characteristic) {
+ if(!characteristic.getUuid().equals(getRequestUUID())){
+ throw new RuntimeException("wrong characteristic responded to authentication");
+ }
+ byte[] value = characteristic.getValue();
+ if(value.length != 3){
+ throw new RuntimeException("wrong authentication response length");
+ }
+ if(value[0] != 0x03 || value[1] != 0x07){
+ throw new RuntimeException("wrong authentication response bytes");
+ }
+ this.onResult(value[2] == 0x00);
+ this.isFinished = true;
+ }
+
+ public abstract void onResult(boolean needsConfirmation);
+
+ @Override
+ public boolean isFinished() {
+ return isFinished;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/ConfirmOnDeviceRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/ConfirmOnDeviceRequest.java
new file mode 100644
index 000000000..fc9012b78
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/ConfirmOnDeviceRequest.java
@@ -0,0 +1,35 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.authentication;
+
+import android.bluetooth.BluetoothGattCharacteristic;
+
+public class ConfirmOnDeviceRequest extends AuthenticationRequest {
+ protected boolean isFinished = false;
+
+ @Override
+ public byte[] getStartSequence() {
+ return new byte[]{0x02, 0x06, 0x30, 0x75, 0x00, 0x00, 0x00};
+ }
+
+ @Override
+ public void handleResponse(BluetoothGattCharacteristic characteristic) {
+ if(!characteristic.getUuid().equals(getRequestUUID())){
+ throw new RuntimeException("wrong characteristic responded to authentication");
+ }
+ byte[] value = characteristic.getValue();
+ if(value.length != 4){
+ throw new RuntimeException("wrong authentication response length");
+ }
+ if(value[0] != 0x03 || value[1] != 0x06 || value[2] != 0x00){
+ throw new RuntimeException("wrong authentication response bytes");
+ }
+ this.onResult(value[3] == 0x01);
+ this.isFinished = true;
+ }
+
+ public void onResult(boolean confirmationSuccess){};
+
+ @Override
+ public boolean isFinished() {
+ return isFinished;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/VerifyPrivateKeyRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/VerifyPrivateKeyRequest.java
index 78865ea2d..abbe36730 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/VerifyPrivateKeyRequest.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/VerifyPrivateKeyRequest.java
@@ -37,7 +37,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.foss
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.FossilRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file.ResultCode;
-public class VerifyPrivateKeyRequest extends FossilRequest {
+public class VerifyPrivateKeyRequest extends AuthenticationRequest {
private final FossilHRWatchAdapter adapter;
private byte[] key, randomPhoneNumber;
private boolean isFinished = false;
@@ -132,9 +132,4 @@ public class VerifyPrivateKeyRequest extends FossilRequest {
return buffer.array();
}
-
- @Override
- public UUID getRequestUUID() {
- return UUID.fromString("3dda0005-957f-7d4a-34a6-74696673696d");
- }
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 248e01fed..4bf0c53a0 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1392,5 +1392,7 @@
Update timeout in minutes:
Hide text on timeout:
Show circle on timeout:
+ Enable on-device pairing confirmation
+ On-device pairing confirmations can get annoying. Disabling them might lose you functionality.
diff --git a/app/src/main/res/xml/devicesettings_fossilhybridhr.xml b/app/src/main/res/xml/devicesettings_fossilhybridhr.xml
index 3fcafff70..5332ca6fd 100644
--- a/app/src/main/res/xml/devicesettings_fossilhybridhr.xml
+++ b/app/src/main/res/xml/devicesettings_fossilhybridhr.xml
@@ -124,6 +124,12 @@
android:targetClass="nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.FileManagementActivity" />
+
+