From f727f2fdcbaa192a0dc5d5ad4c0a421f1aef6fe9 Mon Sep 17 00:00:00 2001 From: Arjan Schrijver Date: Mon, 8 May 2023 22:44:43 +0200 Subject: [PATCH] Fossil/Skagen Hybrids: Pair watch to phone, fixes repeating confirmation request --- CHANGELOG.md | 1 + .../fossil_hr/FossilHRWatchAdapter.java | 37 +++++++++++++--- .../CheckDevicePairingRequest.java | 44 +++++++++++++++++++ .../PerformDevicePairingRequest.java | 8 ++++ app/src/main/res/values/strings.xml | 6 +++ 5 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/CheckDevicePairingRequest.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/PerformDevicePairingRequest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index f5f555c22..b1c64ba55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * Amazfit GTR 4: Whitelist fw 3.18.1.1 diff from 3.17.0.2 * Amazfit GTS 2 Mini: Add missing alexa menu item * Bangle.js: Fix updating timezone in settings.json if the timezone is zero +* Fossil/Skagen Hybrids: Pair watch to phone, fixes repeating confirmation request * Huami: Implement repeated activity fetching * Sony WH-1000XM4: Add speak-to-chat * Sony Headphones: Add button modes help 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 53369c669..402f05272 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 @@ -122,7 +122,9 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fos 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.CheckDevicePairingRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.authentication.ConfirmOnDeviceRequest; +import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.authentication.PerformDevicePairingRequest; 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; @@ -269,7 +271,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { } boolean shouldAuthenticateOnWatch = getDeviceSpecificPreferences().getBoolean("enable_on_device_confirmation", true); if (!shouldAuthenticateOnWatch) { - GB.toast("Skipping on-device confirmation", Toast.LENGTH_SHORT, GB.INFO); + GB.toast(getContext().getString(R.string.fossil_hr_confirmation_skipped), Toast.LENGTH_SHORT, GB.INFO); initializeAfterWatchConfirmation(false); return; } @@ -282,7 +284,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { if (!(fossilRequest instanceof ConfirmOnDeviceRequest)) { return; } - GB.toast("Confirmation timeout, continuing", Toast.LENGTH_SHORT, GB.INFO); + GB.toast(getContext().getString(R.string.fossil_hr_confirmation_timeout), Toast.LENGTH_SHORT, GB.INFO); ((ConfirmOnDeviceRequest) fossilRequest).onResult(false); } }; @@ -294,14 +296,16 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { GB.log("needs confirmation: " + needsConfirmation, GB.INFO, null); if (needsConfirmation) { final Timer timer = new Timer(); - GB.toast("please confirm on device.", Toast.LENGTH_SHORT, GB.INFO); + GB.toast(getContext().getString(R.string.fossil_hr_confirm_connection), Toast.LENGTH_SHORT, GB.INFO); queueWrite(new ConfirmOnDeviceRequest() { @Override public void onResult(boolean confirmationSuccess) { isFinished = true; timer.cancel(); - if (!confirmationSuccess) { - GB.toast("connection unconfirmed on watch, unauthenticated mode", Toast.LENGTH_LONG, GB.ERROR); + if (confirmationSuccess) { + pairToWatch(); + } else { + GB.toast(getContext().getString(R.string.fossil_hr_connection_not_confirmed), Toast.LENGTH_LONG, GB.ERROR); } initializeAfterWatchConfirmation(confirmationSuccess); } @@ -314,6 +318,29 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { }); } + private void pairToWatch() { + queueWrite(new CheckDevicePairingRequest() { + @Override + public void onResult(boolean pairingStatus) { + GB.log("watch pairing status: " + pairingStatus, GB.INFO, null); + if (!pairingStatus) { + queueWrite(new PerformDevicePairingRequest() { + @Override + public void onResult(boolean pairingSuccess) { + isFinished = true; + GB.log("watch pairing result: " + pairingSuccess, GB.INFO, null); + if (pairingSuccess) { + GB.toast(getContext().getString(R.string.fossil_hr_pairing_successful), Toast.LENGTH_LONG, GB.ERROR); + } else { + GB.toast(getContext().getString(R.string.fossil_hr_pairing_failed), Toast.LENGTH_LONG, GB.ERROR); + } + } + }, true); + } + } + }); + } + private void respondToAlexa(String message, boolean isResponse){ queueWrite(new AlexaMessageSetRequest(message, isResponse, this)); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/CheckDevicePairingRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/CheckDevicePairingRequest.java new file mode 100644 index 000000000..207953e9d --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/CheckDevicePairingRequest.java @@ -0,0 +1,44 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.authentication; + +import android.bluetooth.BluetoothGattCharacteristic; + +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.FossilRequest; + +public class CheckDevicePairingRequest extends FossilRequest { + protected boolean isFinished = false; + + @Override + public byte[] getStartSequence() { + return new byte[]{0x01, 0x16}; + } + + @Override + public void handleResponse(BluetoothGattCharacteristic characteristic) { + if(!characteristic.getUuid().equals(getRequestUUID())){ + throw new RuntimeException("wrong characteristic responded to pairing"); + } + byte[] value = characteristic.getValue(); + if(value.length != 3){ + throw new RuntimeException("wrong pairing response length"); + } + if(value[0] != 0x03 || value[1] != 0x16){ + throw new RuntimeException("wrong pairing response bytes"); + } + this.onResult(value[2] == 0x01); + this.isFinished = true; + } + + public void onResult(boolean confirmationSuccess){}; + + @Override + public boolean isFinished() { + return isFinished; + } + + @Override + public UUID getRequestUUID() { + return UUID.fromString("3dda0002-957f-7d4a-34a6-74696673696d"); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/PerformDevicePairingRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/PerformDevicePairingRequest.java new file mode 100644 index 000000000..5490c2385 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/authentication/PerformDevicePairingRequest.java @@ -0,0 +1,8 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.authentication; + +public class PerformDevicePairingRequest extends CheckDevicePairingRequest { + @Override + public byte[] getStartSequence() { + return new byte[]{0x02, 0x16}; + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ef8801043..ef1103b6a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2083,4 +2083,10 @@ Root Directory Address Username + Please confirm on your watch + Connection not confirmed on watch, using unauthenticated mode + Pairing with watch successful + Pairing with watch failed + Skipping on-device confirmation + Confirmation timeout, continuing