1
0
mirror of https://github.com/oliexdev/openScale.git synced 2025-08-28 18:49:56 +02:00

Run a LE scan for the device before connecting

Seems to be a requirement for some scales (e.g. Medisana BS444) and we
might as well do it for all scales since it should hopefully improve
connectivity for others as well.

If no location permission is given, or if no device is found within 10
seconds, we try to connect directly to the scale.

As of this, #278 should be fixed.
This commit is contained in:
Erik Johansson
2018-06-15 21:18:22 +02:00
parent a4a27d2f7e
commit ae07a7f5d3
2 changed files with 55 additions and 41 deletions

View File

@@ -30,6 +30,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.SystemClock;
import android.support.v4.content.ContextCompat;
import com.health.openscale.core.datatypes.ScaleMeasurement;
@@ -49,9 +50,12 @@ public abstract class BluetoothCommunication {
public enum BT_MACHINE_STATE {BT_INIT_STATE, BT_CMD_STATE, BT_CLEANUP_STATE}
private static final long LE_SCAN_TIMEOUT_MS = 10 * 1000;
protected Context context;
private Handler callbackBtHandler;
private Handler handler;
private BluetoothGatt bluetoothGatt;
private boolean connectionEstablished;
private BluetoothGattCallback gattCallback;
@@ -81,6 +85,7 @@ public abstract class BluetoothCommunication {
public BluetoothCommunication(Context context)
{
this.context = context;
handler = new Handler();
btAdapter = BluetoothAdapter.getDefaultAdapter();
gattCallback = new GattCallback();
bluetoothGatt = null;
@@ -96,10 +101,6 @@ public abstract class BluetoothCommunication {
return bluetoothGatt.getServices();
}
protected boolean discoverDeviceBeforeConnecting() {
return false;
}
/**
* Register a callback Bluetooth handler that notify any BT_STATUS_CODE changes for GUI/CORE.
*
@@ -384,48 +385,29 @@ public abstract class BluetoothCommunication {
*
* @param hwAddress the Bluetooth address to connect to
*/
public void connect(final String hwAddress) {
Timber.i("Connecting to [%s] (driver: %s)", hwAddress, driverName());
public void connect(String hwAddress) {
logBluetoothStatus();
// Some good tips to improve BLE connections:
// https://android.jlelse.eu/lessons-for-first-time-android-bluetooth-le-developers-i-learned-the-hard-way-fee07646624
final boolean doDiscoveryFirst = discoverDeviceBeforeConnecting();
// Running an LE scan during connect improves connectivity on some phones
// (e.g. Sony Xperia Z5 compact, Android 7.1.1).
btAdapter.cancelDiscovery();
if (leScanCallback == null) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
Timber.d("Starting LE scan");
leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
Timber.d("Found LE device %s [%s]", device.getName(), device.getAddress());
if (!doDiscoveryFirst || !device.getAddress().equals(hwAddress)) {
return;
}
synchronized (lock) {
stopLeScan();
connectGatt(device);
}
}
};
btAdapter.startLeScan(leScanCallback);
}
else {
Timber.d("No coarse location permission, skipping LE scan");
}
}
stopLeScan();
// Don't do any cleanup if disconnected before fully connected
btMachineState = BT_MACHINE_STATE.BT_CLEANUP_STATE;
if (!doDiscoveryFirst || leScanCallback == null) {
connectGatt(btAdapter.getRemoteDevice(hwAddress));
// Running an LE scan during connect improves connectivity on some phones
// (e.g. Sony Xperia Z5 compact, Android 7.1.1). For some scales (e.g. Medisana BS444)
// it seems to be a requirement that the scale is discovered before connecting to it.
// Otherwise the connection almost never succeeds.
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
startLeScanForDevice(hwAddress);
}
else {
Timber.d("No coarse location permission, connecting without LE scan");
connectGatt(hwAddress);
}
}
@@ -447,6 +429,8 @@ public abstract class BluetoothCommunication {
}
private void connectGatt(BluetoothDevice device) {
Timber.i("Connecting to [%s] (driver: %s)", device.getAddress(), driverName());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
bluetoothGatt = device.connectGatt(
context, false, gattCallback, BluetoothDevice.TRANSPORT_LE);
@@ -456,10 +440,45 @@ public abstract class BluetoothCommunication {
}
}
private void connectGatt(String hwAddress) {
connectGatt(btAdapter.getRemoteDevice(hwAddress));
}
private void startLeScanForDevice(final String hwAddress) {
leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
Timber.d("Found LE device %s [%s]", device.getName(), device.getAddress());
if (!device.getAddress().equals(hwAddress)) {
return;
}
synchronized (lock) {
stopLeScan();
connectGatt(device);
}
}
};
Timber.d("Starting LE scan for device [%s]", hwAddress);
btAdapter.startLeScan(leScanCallback);
handler.postAtTime(new Runnable() {
@Override
public void run() {
Timber.d("Device not found in LE scan, connecting directly");
synchronized (lock) {
stopLeScan();
connectGatt(hwAddress);
}
}
}, leScanCallback, SystemClock.uptimeMillis() + LE_SCAN_TIMEOUT_MS);
}
private void stopLeScan() {
if (leScanCallback != null) {
Timber.d("Stopping LE scan");
btAdapter.stopLeScan(leScanCallback);
handler.removeCallbacksAndMessages(leScanCallback);
leScanCallback = null;
}
}

View File

@@ -44,11 +44,6 @@ public class BluetoothMedisanaBS444 extends BluetoothCommunication {
btScaleMeasurement = new ScaleMeasurement();
}
@Override
protected boolean discoverDeviceBeforeConnecting() {
return true;
}
@Override
public String driverName() {
return "Medisana BS44x";