Disminución de BLE startScan detectó dispositivos en Android 5.0 Lollipop

Version corta:

En mis pruebas con Android 5.0 Lollipop he notadoandroid.bluetooth.le.BluetoothLeScanner detecta dispositivos BLE con menos frecuencia que Android 4.4 KitKat. ¿Por qué es esto y hay una alternativa?

Versión larga:

Estoy desarrollando una aplicación de Android, específicamente para la tableta Nexus 7, que se enfoca en detectar dispositivos Bluetooth de baja energía (BLE). La aplicación está principalmente interesada en el valor RSSI de las balizas, para determinar su proximidad a la tableta. Esto significa que no necesitaré conectarme al dispositivo BLE, ya que el valor RSSI se pasa a la devolución de llamada de escaneo cuando se detecta el dispositivo.

En Android 4.4 KitKat, cuando llamoBluetoothAdapter.startLeScan(LeScanCallback), mi devolución de llamada solo se llama UNA VEZ por cada dispositivo BLE detectado. (He vistoalgunas discusiones afirme que este comportamiento puede diferir según el dispositivo) Sin embargo, estoy interesado en el cambio constante del valor RSSI, por lo que la forma actualmente recomendada es hacer continuamente startLeScan y stopLeScan con un intervalo establecido (250 ms en mi caso):

public class TheOldWay {

    private static final int SCAN_INTERVAL_MS = 250;

    private Handler scanHandler = new Handler();
    private boolean isScanning = false;

    public void beginScanning() {
        scanHandler.post(scanRunnable);
    }

    private Runnable scanRunnable = new Runnable() {
        @Override
        public void run() {
            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

            if (isScanning) {
                adapter.stopLeScan(leScanCallback);
            } else if (!adapter.startLeScan(leScanCallback)) {
                // an error occurred during startLeScan
            }

            isScanning = !isScanning;

            scanHandler.postDelayed(this, SCAN_INTERVAL_MS);
        }
    };

    private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
            // use the RSSI value
        }
    };

}

Esencialmente, esto me da los resultados requeridos, pero este proceso requiere muchos recursos y finalmente conduce a un adaptador bluetooth que no responde.

Por estas razones, actualicé mi Nexus 7 a Android 5.0 Lollipop, para ver si se solucionarían mis problemas de BLE. En Lollipop, BluetoothAdapter.startLeScan (LeScanCallback) está en desuso y se reemplaza conuna nueva API eso permite un poco más de control sobre el proceso de escaneo. Desde mis primeras pruebas, parece que startScan no llama continuamente a mi devolución de llamada (en mi Nexus 7) cuando cambian los valores de RSSI, por lo que todavía necesito usar la implementación startScan / stopScan:

@TargetApi(21)
public class TheNewWay {

    private static final int SCAN_INTERVAL_MS = 250;

    private Handler scanHandler = new Handler();
    private List<ScanFilter> scanFilters = new ArrayList<ScanFilter>();
    private ScanSettings scanSettings;
    private boolean isScanning = false;

    public void beginScanning() {
        ScanSettings.Builder scanSettingsBuilder = new ScanSettings.Builder();
        scanSettingsBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
        scanSettings = scanSettingsBuilder.build();

        scanHandler.post(scanRunnable);
    }

    private Runnable scanRunnable = new Runnable() {
        @Override
        public void run() {
            BluetoothLeScanner scanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();

            if (isScanning) {
                scanner.stopScan(scanCallback);
            } else {
                scanner.startScan(scanFilters, scanSettings, scanCallback);
            }

            isScanning = !isScanning;

            scanHandler.postDelayed(this, SCAN_INTERVAL_MS);
        }
    };

    private ScanCallback scanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);

            int rssi = result.getRssi();

            // do something with RSSI value
        }

        @Override
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);

            // a scan error occurred
        }
    };

}

Como puede ver, he configurado el escáner utilizando la clase ScanSettings, que le permite configurar elscanMode. yo sueloScanSettings.SCAN_MODE_LOW_LATENCY, que tiene la siguiente documentación: "Escanee con el ciclo de trabajo más alto. Se recomienda usar este modo solo cuando la aplicación se ejecute en primer plano". Suena exactamente como lo que quiero, pero desafortunadamente solo obtengo una detección de baliza cada 15-30 segundos, donde la versión KitKat me muestra la misma baliza cada 1 a 2 segundos en este intervalo de escaneo.

¿Tienes alguna idea de cuál podría ser la razón de esta diferencia? ¿Me estoy perdiendo algo, tal vez algunas configuraciones nuevas? ¿Hay formas alternativas de hacer lo anterior?

¡Muchas gracias por adelantado!

Abel

PD: quería incluir más enlaces a los recursos que he usado, pero todavía no tengo los puntos de representación.

Respuestas a la pregunta(5)

Su respuesta a la pregunta