diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java
index d65a167516..0c4d9b374e 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2024 Andreas Shimokawa, Daniel Dakhno, José Rebelo
+/* Copyright (C) 2016-2025 Andreas Shimokawa, Daniel Dakhno, José Rebelo, Thomas Kuehne
This file is part of Gadgetbridge.
@@ -16,6 +16,9 @@
along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.externalevents;
+import static nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State.WAITING_FOR_RECONNECT;
+import static nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State.WAITING_FOR_SCAN;
+
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -26,6 +29,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
+import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
@@ -33,10 +37,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
public class BluetoothConnectReceiver extends BroadcastReceiver {
private static final Logger LOG = LoggerFactory.getLogger(BluetoothConnectReceiver.class);
- final DeviceCommunicationService service;
-
- public BluetoothConnectReceiver(final DeviceCommunicationService service) {
- this.service = service;
+ public BluetoothConnectReceiver(final DeviceCommunicationService ignored) {
}
@Override
@@ -56,26 +57,38 @@ public class BluetoothConnectReceiver extends BroadcastReceiver {
return;
}
- LOG.info("connection attempt detected from {}", device.getAddress());
+ final String address = device.getAddress();
+ LOG.debug("observed device {} via ACL_CONNECTED", address);
- final GBDevice gbDevice = GBApplication.app().getDeviceManager().getDeviceByAddress(device.getAddress());
+ observedDevice(address);
+ }
+
+ public static void observedDevice(String address) {
+ final DeviceManager manager = GBApplication.app().getDeviceManager();
+ final GBDevice gbDevice = manager.getDeviceByAddress(address);
if (gbDevice == null) {
- LOG.info("Connected device {} unknown", device.getAddress());
+ LOG.debug("observed non-GB device {}", address);
return;
}
- final SharedPreferences deviceSpecificPreferences = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress());
- if (deviceSpecificPreferences == null) {
- LOG.warn("no preferences found for connecting device {}", device.getAddress());
- return;
+
+ final GBDevice.State state = gbDevice.getState();
+ if (state == WAITING_FOR_RECONNECT || state == WAITING_FOR_SCAN) {
+ LOG.debug("re-connecting to observed device due to state {}", state);
+ } else {
+ final SharedPreferences pref = GBApplication.getDeviceSpecificSharedPrefs(address);
+ if (pref == null) {
+ LOG.warn("no preferences found for connecting device {}", address);
+ return;
+ }
+
+ if (pref.getBoolean(GBPrefs.DEVICE_CONNECT_BACK, false)) {
+ LOG.debug("re-connecting to observed device due DEVICE_CONNECT_BACK preference");
+ } else {
+ LOG.info("ignoring observed device {} {}", address, state);
+ return;
+ }
}
- boolean reactToConnection = deviceSpecificPreferences.getBoolean(GBPrefs.DEVICE_CONNECT_BACK, false);
- reactToConnection |= gbDevice.getState() == GBDevice.State.WAITING_FOR_RECONNECT;
- reactToConnection |= gbDevice.getState() == GBDevice.State.WAITING_FOR_SCAN;
- if (!reactToConnection) {
- LOG.info("Ignoring connection attempt from {}", device.getAddress());
- return;
- }
- LOG.info("Will re-connect to {} ({})", gbDevice.getAddress(), gbDevice.getName());
+
GBApplication.deviceService(gbDevice).connect();
}
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/GBCompanionDeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/GBCompanionDeviceService.java
index f13838d999..42482d35d5 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/GBCompanionDeviceService.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/GBCompanionDeviceService.java
@@ -18,8 +18,10 @@
package nodomain.freeyourgadget.gadgetbridge.service;
import android.companion.AssociationInfo;
+import android.companion.CompanionDeviceManager;
import android.companion.CompanionDeviceService;
import android.companion.DevicePresenceEvent;
+import android.net.MacAddress;
import android.os.Build;
import androidx.annotation.DeprecatedSinceApi;
@@ -30,14 +32,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothConnectReceiver;
-import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
-import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEQueue;
-import nodomain.freeyourgadget.gadgetbridge.service.receivers.AutoConnectIntervalReceiver;
+import nodomain.freeyourgadget.gadgetbridge.util.BondingUtil;
/**
- * For now this service only ensures that GB is less likely to get killed.
- * See {@link #maybeConnect}. Android API documentation:
+ * Potentially {@link BluetoothConnectReceiver#observedDevice(String) reconnects} observed
+ * companion devices. Android API documentation:
*
* The system binding CompanionDeviceService elevates the priority of the process that the service
* is running in, and thus may prevent the Low-memory killer from killing the process at expense of
@@ -52,8 +52,8 @@ public class GBCompanionDeviceService extends CompanionDeviceService {
@Override
public void onDeviceAppeared(@NonNull String address) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
- LOG.debug("onDeviceAppeared address:{}", address);
- maybeConnect();
+ LOG.debug("observed device {} via onDeviceAppeared(old {})", address, Build.VERSION.SDK_INT);
+ BluetoothConnectReceiver.observedDevice(address);
}
}
@@ -68,8 +68,12 @@ public class GBCompanionDeviceService extends CompanionDeviceService {
@Override
public void onDeviceAppeared(@NonNull AssociationInfo associationInfo) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.BAKLAVA) {
- LOG.debug("onDeviceAppeared association:{}", associationInfo.getDeviceMacAddress());
- maybeConnect();
+ MacAddress mac = associationInfo.getDeviceMacAddress();
+ if (mac != null) {
+ String address = mac.toString();
+ LOG.debug("observed device {} via onDeviceAppeared(new {})", address, Build.VERSION.SDK_INT);
+ BluetoothConnectReceiver.observedDevice(address);
+ }
}
}
@@ -95,29 +99,31 @@ public class GBCompanionDeviceService extends CompanionDeviceService {
"EVENT_SELF_MANAGED_DISAPPEARED";
default -> Integer.toString(code);
};
- LOG.debug("onDevicePresenceEvent {} association:{}", type, event.getAssociationId());
switch (code) {
case DevicePresenceEvent.EVENT_BLE_APPEARED:
case DevicePresenceEvent.EVENT_BT_CONNECTED:
case DevicePresenceEvent.EVENT_SELF_MANAGED_APPEARED:
- maybeConnect();
+ CompanionDeviceManager manager = BondingUtil.getCompanionDeviceManager(getBaseContext());
+ if (manager == null) {
+ LOG.error("CompanionDeviceManager is null");
+ return;
+ }
+ for (final AssociationInfo info : manager.getMyAssociations()) {
+ if (info.getId() == event.getAssociationId()) {
+ MacAddress mac = info.getDeviceMacAddress();
+ if (mac != null) {
+ String address = mac.toString();
+ LOG.debug("observed device {} via {}", address, type);
+ BluetoothConnectReceiver.observedDevice(address);
+ return;
+ }
+ }
+ }
+ LOG.warn("no matching AssociationInfo for {}", event);
break;
+ default:
+ LOG.debug("onDevicePresenceEvent {} association:{}", type, event.getAssociationId());
}
}
-
- /**
- * FIXME {@link DeviceCommunicationService#connectToDevice} has to play nicer with
- * concurrent reconnect triggers before code can be added here
- *
- * - {@link AutoConnectIntervalReceiver}
- * - {@link BluetoothConnectReceiver}
- * - {@link DeviceService#ACTION_CONNECT}
- * - device specific - e.g. {@link BtLEQueue#maybeReconnect}'s {@code mBluetoothGatt.connect}
- *
- */
- private void maybeConnect() {
- // TODO check DEVICE_CONNECT_BACK, WAITING_FOR_RECONNECT and WAITING_FOR_SCAN
- // and conditionally try to establish a connection
- }
}