Pebble: Fix pebble time 2 and core 2 duo not immediately showing up in device list

This commit is contained in:
Benjamin Temple
2026-05-16 12:02:09 -07:00
parent d5643468b9
commit f95273100e
4 changed files with 47 additions and 40 deletions
@@ -29,6 +29,7 @@ import java.util.HashMap;
import java.util.Map;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
/**
* Unified source of truth for Pebble hardware definitions.
@@ -469,6 +470,20 @@ public class PebbleHardware {
return name != null && (name.startsWith("Pebble-LE ") || name.startsWith("Pebble Time LE "));
}
/**
* Check if a device candidate needs connect-first pairing (GATT connection before createBond).
* Uses manufacturer data for reliable identification, falling back to name-based detection.
*/
public static boolean needsConnectFirstPairing(GBDeviceCandidate candidate) {
if (candidate == null) {
return false;
}
if (isBleOnly(candidate.getManufacturerSpecificData())) {
return true;
}
return isBleOnly(candidate.getDevice());
}
// ======================= Platform Utilities =======================
/**
@@ -130,8 +130,8 @@ public class PebblePairingActivity extends AbstractGBActivity implements Bonding
// Note: These devices are BLE-only, so we don't need the "pebble_force_le" setting -
// PebbleIoThread automatically uses BLE based on isPebble2() detection.
// Use deviceCandidate to leverage manufacturer data for reliable device identification.
if (BondingUtil.needsConnectFirstPairing(deviceCandidate)) {
LOG.info("Pebble 2/Time 2/2 Duo detected via manufacturer data - using connect-first pairing (BLE-only device)");
if (PebbleHardware.needsConnectFirstPairing(deviceCandidate)) {
LOG.info("BLE-only device detected - using connect-first pairing");
registerBroadcastReceivers();
@@ -198,7 +198,8 @@ public class PebblePairingActivity extends AbstractGBActivity implements Bonding
LOG.debug("ONBONDINGCOMPLETE");
unregisterBroadcastReceivers();
// Trigger device list refresh so the new device appears immediately
BluetoothDevice btDevice = deviceCandidate != null ? deviceCandidate.getDevice() : null;
if (success) {
LocalBroadcastManager.getInstance(this).sendBroadcast(
new Intent(DeviceManager.ACTION_REFRESH_DEVICELIST));
@@ -210,9 +211,8 @@ public class PebblePairingActivity extends AbstractGBActivity implements Bonding
startActivity(new Intent(this, DiscoveryActivityV2.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
}
// If it's not a LE Pebble, initiate a connection when bonding is complete
if (!PebbleHardware.isLePebbleCompanion(getCurrentTarget().getDevice()) && success) {
BondingUtil.attemptToFirstConnect(getCurrentTarget().getDevice());
if (btDevice != null && success && getAttemptToConnect() && shouldReconnectAfterBond()) {
BondingUtil.attemptToFirstConnect(btDevice);
}
finish();
}
@@ -224,7 +224,14 @@ public class PebblePairingActivity extends AbstractGBActivity implements Bonding
@Override
public boolean getAttemptToConnect() {
return true;
// LE companion manages its own connection via connectThenComplete
return deviceCandidate == null || !PebbleHardware.isLePebbleCompanion(deviceCandidate.getDevice());
}
@Override
public boolean shouldReconnectAfterBond() {
// Connect-first pairing: bonding occurred within the existing GATT connection
return !PebbleHardware.needsConnectFirstPairing(deviceCandidate);
}
@Override
@@ -54,6 +54,15 @@ public interface BondingInterface {
}
boolean getAttemptToConnect();
/**
* Whether the connection should be restarted after bonding completes.
* Return false for connect-first pairing flows where bonding occurs within an existing
* GATT connection — the connection should not be interrupted.
*/
default boolean shouldReconnectAfterBond() {
return true;
}
/**
* This forces bonding activities to handle the addition
* of all broadcast receivers in the same place
@@ -134,14 +134,18 @@ public class BondingUtil {
} else {
switch (bondState) {
case BluetoothDevice.BOND_BONDED: {
LOG.info("Bonded with {}", device.getAddress());
if (PebbleHardware.isLePebbleCompanion(device) || PebbleHardware.isBleOnly(device) || !bondingInterface.getAttemptToConnect()) {
// Do not initiate connection to LE Pebble and Pebble 2/Time 2/2 Duo
// For Pebble 2/Time 2/2 Duo, the connection was already started before bonding
// Just signal that bonding is complete
LOG.info("LE/Pebble2/Pebble2Duo device bonded - signaling completion");
if (!bondingInterface.getAttemptToConnect()) {
LOG.info("Device bonded - notifying onBondingComplete without reconnecting.");
bondingInterface.onBondingComplete(true);
} else if (!bondingInterface.shouldReconnectAfterBond()) {
// connect-first pairing, existing connection completes to INITIALIZED
// Don't interrupt by disconnecting and reconnecting in the middle of the pairing flow.
LOG.info("Device bonded - connect first pairing, connection already established.");
} else {
// Bond-then-connect flow: reconnect now that bonding is complete.
LOG.info("Device bonded - reconnecting and waiting for initialization");
attemptToFirstConnect(device);
}
return;
@@ -334,34 +338,6 @@ public class BondingUtil {
}
}
/**
* Checks if device needs connect-first pairing (GATT connection before createBond).
* Pebble 2, Pebble Time 2, and Pebble 2 Duo require writing to a pairing trigger
* characteristic before Android's createBond() will succeed.
*
* @param candidate Device candidate with manufacturer data from BLE scan
* @return true if this device needs connect-first pairing
*/
public static boolean needsConnectFirstPairing(GBDeviceCandidate candidate) {
if (candidate == null) {
return false;
}
// First try manufacturer data - this is the most reliable method
if (PebbleHardware.isBleOnly(candidate.getManufacturerSpecificData())) {
return true;
}
// Fall back to name-based detection
return PebbleHardware.isBleOnly(candidate.getDevice());
}
/**
* Checks if device needs connect-first pairing (GATT connection before createBond).
* Uses name-based detection when GBDeviceCandidate is not available.
*/
public static boolean needsConnectFirstPairing(BluetoothDevice device) {
return PebbleHardware.isBleOnly(device);
}
/**
* Uses the CompanionDeviceManager bonding method
*/