Подтвердить что ты не робот

Снижение 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), мой callback вызывается только ONCE для каждого обнаруженного устройства 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: Я хотел добавить больше ссылок на ресурсы, которые я использовал, но у меня пока нет репутационных баллов.

4b9b3361

Ответ 1

У меня получились очень разные результаты, когда Nexus 5 работает с новыми API-интерфейсами сканирования Android 5.0. Обнаружение пакетов BLE приходилось в почти реальном времени при использовании SCAN_MODE_LOW_LATENCY на каждые 100 мс для маяков BLE, передающих с частотой 10 Гц.

Здесь вы можете прочитать полные результаты:

http://developer.radiusnetworks.com/2014/10/28/android-5.0-scanning.html

Эти тесты основаны на использовании экспериментальной ветки Android Beacon Library 2.0 экспериментального андроида-l-apis здесь.

Неясно, в чем разница в результатах теста, но возможно, что запуск и остановка сканирования меняют результаты.

РЕДАКТИРОВАТЬ: возможно аппаратное обеспечение. См. Отчет о аналогичных таймингах на Nexus 4: https://github.com/AltBeacon/android-beacon-library/issues/59#issuecomment-64281446

Ответ 2

У меня еще нет репутации 50 для комментария, так что несите меня, этот комментарий будет в форме ответа. В вашем коде не должна находиться эта часть:

if (isScanning) { scanner.startScan(...)

вместо этого:

if (!isScanning) {
 scanner.startScan(...)

Поскольку после вашего кода вы вызываете stopScan() перед началом сканирования. Это может не оказать прямого влияния на результат, если метод stopScan() является идемпотентным/безопасным. Но вы знаете, ради разборчивости кода вы должны отредактировать вопрос. И делайте то же самое со своим кодом, иногда в игре играют византийские вещи;)

Пробовали ли вы более крупные значения для SCAN_INTERVAL_MS? Если да, то насколько велика?

Ответ 3

Я испытал очень похожие результаты с моим Nexus 4, как в KitKat, так и в Lollipop.

С KitKat адаптер Bluetooth также в конечном итоге не реагировал; вначале я, хотя это могло быть связано с коротким интервалом сканирования (200 мс), но увеличение этого числа до второй секунды не помогло, в этом вопросе я обнаружил, что при безусловном отключении и включении адаптера программным путем иногда решает проблему, К сожалению, я не могу сказать, что он работает все время.

Теперь с Lollipop, в котором я возлагал большие надежды на решение этих проблем, я испытал такое же поведение, которое вы описываете. Мне также пришлось использовать реализацию startScan/stopScan, получая аналогичные результаты в отношении времени обнаружения. К сожалению, я не нашел работу, чтобы быстрее получить результаты.

Основываясь на том, что вы описываете, я полагаю, что это может быть проблема с оборудованием, хотя Nexus 7 и Nexus 4 от разных производителей (Asus и LG).

Я знаю, что я не очень помогаю здесь, кроме того, чтобы ответить на ваш вопрос о том, что вы что-то упустили; Я так не думаю, я думаю, что проблема в чем-то похожа на аппаратное обеспечение или интерфейс Bluetooth, который по-прежнему не ведет себя так, как должен быть на разных устройствах.

Ответ 4

По сравнению с API 21 Android использует SCAN_MODE_LOW_POWER по умолчанию. SCAN_MODE_LOW_POWER

Попробуйте SCAN_MODE_BALANCED и посмотрите, улучшится ли он. SCAN_MODE_BALANCED

Ответ 5

если вы ищете BW13_DayOne_Session1 Bluetooth Advanced в google, вы найдете pdf-документ, который дает вам задержки для устройств на основе настроек обнаружения (см. стр. 8). Я предполагаю, что ваша проблема связана с этими таймингами. Вы можете проверить, указав конфигурацию рекламы для тестируемого устройства (Adv Int, Duty Cycle), затем выясните, какие настройки API выполняют для настройки интервала сканирования и т.д. После этого вы можете использовать эту таблицу для интерполяции, чтобы узнать, есть ли у вас ожидаемые результаты.

Я знаю, что это сайт программного обеспечения, но часто при взаимодействии с оборудованием вам нужно знать протокол, иначе вы стреляете в темноте.