Ответ 1
Начиная с Android 8.1 нефильтрованное сканирование по Bluetooth блокируется при выключении экрана. Несмотря на то, что столь существенное изменение было внесено в небольшом выпуске Android, это, конечно же, намеренное изменение, основанное на комментариях в коммите: Остановите нефильтрованные сканирования BLE, когда экран выключится.
Обходной путь должен использовать ScanFilter со всеми сканированиями. Новый код операционной системы 8.1 просто подтверждает, что все активные сканирования, когда экран выключен, имеют хотя бы один фильтр сканирования. Если эти условия соблюдены, результаты сканирования выдаются как в Android 8.0.x и более ранних версиях.
Чтобы настроить такое сканирование, вы должны использовать API, представленные в Android 5.0, и создавать ScanFilter
при каждом сканировании. Ниже приведен фильтр, который найдет рекламу производителя для любого устройства Apple с идентификатором производителя 0x004c (включая iBeacons):
ScanFilter.Builder builder = new ScanFilter.Builder();
builder.setManufacturerData(0x004c, new byte[] {});
ScanFilter filter = builder.build();
Аналогичным образом, если вас интересуют рекламные объявления службы GATT (например, такие, которые используются с маяками Eddystone), вы можете выполнить поиск UUID службы GATT с помощью фильтра, подобного следующему:
ScanFilter.Builder builder = new ScanFilter.Builder();
String serviceUuidString = "0000feaa-0000-1000-8000-00805f9b34fb";
String serviceUuidMaskString = "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF";
ParcelUuid parcelUuid = ParcelUuid.fromString(serviceUuidString);
ParcelUuid parcelUuidMask = ParcelUuid.fromString(serviceUuidMaskString);
builder.setServiceUuid(parcelUuid, parcelUuidMask);
ScanFilter filter = builder.build();
При необходимости вы можете добавить несколько фильтров к одному сканированию, и любой из них будет возвращать результаты. Единственным реальным ограничением здесь является то, что вы должны знать все коды производителей или все идентификаторы UIID службы GATT, которые могут совпадать заранее, по крайней мере при сканировании с выключенным экраном.
Вы начинаете сканирование с помощью кода, подобного следующему:
bluetoothAdapter.getBluetoothLeScanner().startScan(filters, settings, scanCallback);
РЕДАКТИРОВАТЬ: Это также возможно сделать с пустым ScanFilter
который выглядит следующим образом:
ScanFilter.Builder builder = new ScanFilter.Builder();
ScanFilter filter = builder.build();
Если вы используете такой фильтр сканирования, он будет соответствовать любому рекламному пакету и по-прежнему разрешать обнаружение с выключенным экраном на Android 8.1, что фактически даст вам такое же поведение на Android 8.0.x и более ранних версиях.
РЕДАКТИРОВАТЬ 2: На Galaxy Note 9 с Android 8.1 и, возможно, на других устройствах Samsung с 8.1, сканирование блокируется с выключенным экраном даже при пустом фильтре сканирования. Сканирование разрешено с выключенным экраном с непустым фильтром сканирования, как описано выше.