From c08285a3568bae3d4135aecc08602688997bf85c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rebelo?= Date: Sun, 2 Feb 2025 16:25:41 +0000 Subject: [PATCH] Oppo Headphones: Retry battery requests if unknown status --- .../devices/oppo/OppoHeadphonesIoThread.java | 43 +++++++++++++++++++ .../headphones/SonyHeadphonesIoThread.java | 6 +++ 2 files changed, 49 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/oppo/OppoHeadphonesIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/oppo/OppoHeadphonesIoThread.java index a67f6677e..b06731577 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/oppo/OppoHeadphonesIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/oppo/OppoHeadphonesIoThread.java @@ -20,6 +20,7 @@ import static nodomain.freeyourgadget.gadgetbridge.util.GB.hexdump; import android.bluetooth.BluetoothAdapter; import android.content.Context; +import android.os.Handler; import android.os.ParcelUuid; import androidx.annotation.NonNull; @@ -33,6 +34,7 @@ import java.util.Arrays; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.BatteryState; import nodomain.freeyourgadget.gadgetbridge.service.btclassic.BtClassicIoThread; import nodomain.freeyourgadget.gadgetbridge.service.serial.AbstractSerialDeviceSupport; @@ -41,6 +43,34 @@ public class OppoHeadphonesIoThread extends BtClassicIoThread { private final OppoHeadphonesProtocol mProtocol; + private final Handler handler = new Handler(); + + // Some devices will not reply to the first battery request, so we need to retry a few times + private int batteryRetries = 0; + private final Runnable batteryReqRunnable = new Runnable() { + public void run() { + final int batteryCount = getDevice().getDeviceCoordinator().getBatteryCount(getDevice()); + boolean knownBattery = false; + for (int i = 0; i < batteryCount; i++) { + if (getDevice().getBatteryState(i) != BatteryState.UNKNOWN) { + knownBattery = true; + break; + } + } + if (!knownBattery) { + if (batteryRetries++ < 2) { + LOG.warn("Battery request retry {}", batteryRetries); + + write(mProtocol.encodeBatteryReq()); + scheduleBatteryRequestRetry(); + } else { + LOG.error("Failed to get battery after {} tries", batteryRetries); + // Since this is not fatal, we stay connected + } + } + } + }; + public OppoHeadphonesIoThread(final GBDevice gbDevice, final Context context, final OppoHeadphonesProtocol deviceProtocol, @@ -61,9 +91,16 @@ public class OppoHeadphonesIoThread extends BtClassicIoThread { write(mProtocol.encodeFirmwareVersionReq()); write(mProtocol.encodeConfigurationReq()); write(mProtocol.encodeBatteryReq()); + scheduleBatteryRequestRetry(); setUpdateState(GBDevice.State.INITIALIZED); } + @Override + public void quit() { + handler.removeCallbacksAndMessages(null); + super.quit(); + } + @Override protected byte[] parseIncoming(final InputStream inStream) throws IOException { final byte[] buffer = new byte[1048576]; //HUGE read @@ -72,4 +109,10 @@ public class OppoHeadphonesIoThread extends BtClassicIoThread { LOG.debug("Read {} bytes: {}", bytes, hexdump(buffer, 0, bytes)); return Arrays.copyOf(buffer, bytes); } + + private void scheduleBatteryRequestRetry() { + LOG.info("Scheduling battery request retry"); + + handler.postDelayed(batteryReqRunnable, 2000); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/SonyHeadphonesIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/SonyHeadphonesIoThread.java index cc12743a0..5fb1413ef 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/SonyHeadphonesIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/SonyHeadphonesIoThread.java @@ -88,6 +88,12 @@ public class SonyHeadphonesIoThread extends BtClassicIoThread { setUpdateState(GBDevice.State.INITIALIZING); } + @Override + public void quit() { + handler.removeCallbacksAndMessages(null); + super.quit(); + } + @Override public synchronized void write(final byte[] bytes) { // Log the human-readable message, for debugging