Уменьшено BLE startScan обнаруженных устройств на Android 5.0 Lollipop

Укороченная версия:

В моих тестах с Android 5.0 Lollipop я заметилandroid.bluetooth.le.BluetoothLeScanner обнаруживает устройства BLE менее часто, чем Android 4.4 KitKat. Почему это и есть ли альтернатива?

Длинная версия:

Я разрабатываю приложение для Android, специально для планшета Nexus 7, которое предназначено для обнаружения устройств Bluetooth с низким энергопотреблением (BLE). Приложение в основном заинтересовано в значении RSSI маяков, чтобы определить их близость к планшету. Это означает, что мне не нужно подключаться к устройству BLE, поскольку значение RSSI передается обратному вызову сканирования при обнаружении устройства.

В Android 4.4 KitKat, когда я звонюBluetoothAdapter.startLeScan(LeScanCallback)мой обратный вызов вызывается только ОДИН РАЗ для каждого обнаруженного устройства BLE. (Я виделнекоторые обсуждения утверждают, что это поведение может отличаться в зависимости от устройства) Однако меня интересует постоянно меняющееся значение RSSI, поэтому рекомендуемый в настоящее время способ состоит в том, чтобы непрерывно выполнять startLeScan и stopLeScan с заданным интервалом (250 мс в моем случае):

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
        }
    };

}

По сути, это дает мне требуемые результаты, но этот процесс очень ресурсоемкий и в итоге приводит к не отвечающему адаптеру Bluetooth.

По этим причинам я обновил свой Nexus 7 до Android 5.0 Lollipop, чтобы посмотреть, будут ли исправлены проблемы с BLE. В Lollipop BluetoothAdapter.startLeScan (LeScanCallback) устарел и заменен нановый API это позволяет еще больше контролировать процесс сканирования. Из моих первых тестов выясняется, что startScan не выполняет непрерывный вызов моего обратного вызова (на моем Nexus 7) при изменении значений RSSI, поэтому мне все еще нужно использовать реализацию 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
        }
    };

}

Как видите, я настроил сканер с помощью класса ScanSettings, который позволяет вам установитьscanMode, я используюScanSettings.SCAN_MODE_LOW_LATENCY, который имеет следующую документацию: «Сканирование с использованием наибольшего коэффициента заполнения. Рекомендуется использовать этот режим, только когда приложение работает на переднем плане». Звучит точно так, как я хочу, но, к сожалению, я получаю сигнал маяка только каждые 15–30 секунд, когда версия KitKat показывает мне один и тот же маяк каждые 1–2 секунды на этом интервале сканирования.

У вас есть идеи, что может быть причиной этой разницы? Я что-то упустил, может быть, какие-то новые настройки? Есть ли альтернативные способы сделать выше?

Заранее большое спасибо!

Абель

PS: я хотел включить больше ссылок на ресурсы, которые я использовал, но у меня пока нет точек повторения для этого.

Ответы на вопрос(5)

Ваш ответ на вопрос