diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java index 28e5fcf8..f27a8290 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java @@ -1,9 +1,39 @@ package nodomain.freeyourgadget.gadgetbridge.devices; +import android.bluetooth.BluetoothClass; +import android.bluetooth.BluetoothDevice; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; public abstract class AbstractDeviceCoordinator implements DeviceCoordinator { + private static final Logger LOG = LoggerFactory.getLogger(AbstractDeviceCoordinator.class); + public boolean allowFetchActivityData(GBDevice device) { return device.isInitialized() && !device.isBusy() && supportsActivityDataFetching(); } + + public boolean isHealthWearable(BluetoothDevice device) { + BluetoothClass bluetoothClass = device.getBluetoothClass(); + if (bluetoothClass == null) { + LOG.warn("unable to determine bluetooth device class of " + device); + return false; + } + if (bluetoothClass.getMajorDeviceClass() == BluetoothClass.Device.Major.WEARABLE + || bluetoothClass.getMajorDeviceClass() == BluetoothClass.Device.Major.UNCATEGORIZED) { + int deviceClasses = + BluetoothClass.Device.HEALTH_BLOOD_PRESSURE + | BluetoothClass.Device.HEALTH_DATA_DISPLAY + | BluetoothClass.Device.HEALTH_PULSE_RATE + | BluetoothClass.Device.HEALTH_WEIGHING + | BluetoothClass.Device.HEALTH_UNCATEGORIZED + | BluetoothClass.Device.HEALTH_PULSE_OXIMETER + | BluetoothClass.Device.HEALTH_GLUCOSE; + + return (bluetoothClass.getDeviceClass() & deviceClasses) != 0; + } + return false; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java index ca8b9e64..8dca9b5f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java @@ -24,6 +24,7 @@ public final class MiBandConst { public static final String ORIGIN_K9MAIL = "k9mail"; public static final String ORIGIN_PEBBLEMSG = "pebblemsg"; public static final String ORIGIN_GENERIC = "generic"; + public static final String MI_GENERAL_NAME_PREFIX = "MI"; public static final String MI_1 = "1"; public static final String MI_1A = "1A"; public static final String MI_1S = "1S"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java index 3fba2bc0..509f4e68 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java @@ -32,8 +32,22 @@ public class MiBandCoordinator extends AbstractDeviceCoordinator { @Override public boolean supports(GBDeviceCandidate candidate) { String macAddress = candidate.getMacAddress().toUpperCase(); - return macAddress.startsWith(MiBandService.MAC_ADDRESS_FILTER_1_1A) - || macAddress.startsWith(MiBandService.MAC_ADDRESS_FILTER_1S); + if (macAddress.startsWith(MiBandService.MAC_ADDRESS_FILTER_1_1A) + || macAddress.startsWith(MiBandService.MAC_ADDRESS_FILTER_1S)) { + return true; + } + if (candidate.supportsService(MiBandService.UUID_SERVICE_MIBAND_SERVICE)) { + return true; + } + // and a heuristic + try { + if (isHealthWearable(candidate.getDevice())) { + return candidate.getName().toUpperCase().startsWith(MiBandConst.MI_GENERAL_NAME_PREFIX.toUpperCase()); + } + } catch (Exception ex) { + LOG.error("unable to check device support", ex); + } + return false; } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceCandidate.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceCandidate.java index d0755636..286e5897 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceCandidate.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceCandidate.java @@ -2,8 +2,14 @@ package nodomain.freeyourgadget.gadgetbridge.impl; import android.bluetooth.BluetoothDevice; import android.os.Parcel; +import android.os.ParcelUuid; import android.os.Parcelable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.UUID; + import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; @@ -14,6 +20,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; * support this candidate, will the candidate be promoted to a GBDevice. */ public class GBDeviceCandidate implements Parcelable { + private static final Logger LOG = LoggerFactory.getLogger(GBDeviceCandidate.class); + private final BluetoothDevice device; private final short rssi; private DeviceType deviceType = DeviceType.UNKNOWN; @@ -40,6 +48,10 @@ public class GBDeviceCandidate implements Parcelable { dest.writeString(deviceType.name()); } + public BluetoothDevice getDevice() { + return device; + } + public DeviceType getDeviceType() { return deviceType; } @@ -48,6 +60,21 @@ public class GBDeviceCandidate implements Parcelable { return device != null ? device.getAddress() : GBApplication.getContext().getString(R.string._unknown_); } + public boolean supportsService(UUID aService) { + ParcelUuid[] uuids = device.getUuids(); + if (uuids == null) { + LOG.warn("no cached services available for " + this); + return false; + } + + for (ParcelUuid uuid : uuids) { + if (uuid != null && aService.equals(uuid.getUuid())) { + return true; + } + } + return false; + } + public String getName() { String name = null; if (device != null) { @@ -85,4 +112,9 @@ public class GBDeviceCandidate implements Parcelable { public int hashCode() { return device.getAddress().hashCode() ^ 37; } + + @Override + public String toString() { + return getName() + ": " + getMacAddress(); + } }