Git Product home page Git Product logo

android-scanner-compat-library's Introduction

Android BLE Scanner Compat library

Download

The Scanner Compat library solves the problem with scanning for Bluetooth Low Energy devices on Android. The scanner API, initially created in Android 4.3, has changed in Android 5.0 and has been extended in 6.0 and 8.0. This library allows to use modern API even on older phones, emulating not supported features. If a feature (for example offloaded filtering or batching) is not available natively, it will be emulated by the compat library. Also, native filtering, batching and reporting first match or match lost may be disabled if you find them not working on some devices. Advertising Extension (ScanSetting#setLegacy(boolean) or setPhy(int)) is available only on Android Oreo or newer and such calls will be ignored on older platforms where only legacy advertising packets on PHY LE 1M will be reported, due to the Bluetooth chipset capabilities.

Background scanning

SCAN_MODE_LOW_POWER or SCAN_MODE_OPPORTUNISTIC should be used when scanning in background. Note, that newer Android versions will enforce using low power mode in background, even if another one has been set. This library allows to emulate scanning with PendingIntent on pre-Oreo devices by starting a background service that will scan with requested scan mode. This is much less battery friendly than when the original method is used, but works and saves a lot of development time if such feature should be implemented anyway. Please read below for more details.

Note, that for unfiltered scans, scanning is stopped on screen off to save power. Scanning is resumed when screen is turned on again. To avoid this, use scanning with desired ScanFilter.

Usage

The compat library may be found on Maven Central repository. Add it to your project by adding the following dependency:

implementation 'no.nordicsemi.android.support.v18:scanner:1.6.0'

Project not targeting API 31 (Android 12) or newer should use version 1.5.1.

Projects not migrated to Android Jetpack should use version 1.3.1, which is feature-equal to 1.4.0.

As JCenter has shut down, starting from version 1.4.4 the library is available only on Maven Central. Make sure you have mavenCentral() in your main build.gradle file:

buildscript {
    repositories {
        mavenCentral()
    }
}
allprojects {
    repositories {
        mavenCentral()
    }
}

Since version 1.5 you will need to enable desugaring of Java 8 language features if you have not already done so.(And if you are releasing an Android library, then anyone who uses that library will also have to enable desugaring.) We expect for nearly all Android projects to have already enabled desugaring. But if this causes problems for you, please use version 1.4.5.

Permissions

Following this link:

An app must have ACCESS_COARSE_LOCATION permission in order to get results. An App targeting Android Q or later must have ACCESS_FINE_LOCATION permission in order to get results. For apps targeting Build.VERSION_CODES#R or lower, this requires the Manifest.permission#BLUETOOTH_ADMIN permission which can be gained with a simple <uses-permission> manifest tag. For apps targeting Build.VERSION_CODES#S or or higher, this requires the Manifest.permission#BLUETOOTH_SCAN permission which can be gained with Activity.requestPermissions(String[], int). In addition, this requires either the Manifest.permission#ACCESS_FINE_LOCATION permission or a strong assertion that you will never derive the physical location of the device. You can make this assertion by declaring usesPermissionFlags="neverForLocation" on the relevant <uses-permission> manifest tag, but it may restrict the types of Bluetooth devices you can interact with.

API

The Scanner Compat API is very similar to the original one, known from Android Oreo.

Instead of getting it from the BluetoothAdapter, acquire the scanner instance using:

BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();

You also need to change the packets for ScanSettings, ScanFilter and ScanCallback classes to:

no.nordicsemi.android.support.v18.scanner

Sample

To start scanning use (example):

	BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
	ScanSettings settings = new ScanSettings.Builder()
				.setLegacy(false)
				.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
				.setReportDelay(5000)
				.setUseHardwareBatchingIfSupported(true)
				.build();
	List<ScanFilter> filters = new ArrayList<>();
	filters.add(new ScanFilter.Builder().setServiceUuid(mUuid).build());
	scanner.startScan(filters, settings, scanCallback);

to stop scanning use:

	BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
	scanner.stopScan(scanCallback);

Scanning modes

There are 4 scanning modes available in native ScanSettings. 3 of them are available since Android Lollipop while the opportunistic scan mode has been added in Marshmallow. This library tries to emulate them on platforms where they are not supported natively.

  1. SCAN_MODE_LOW_POWER - Perform Bluetooth LE scan in low power mode. This is the default scan mode as it consumes the least power. The scanner will scan for 0.5 second and rest for 4.5 seconds. A Bluetooth LE device should advertise very often (at least once per 100 ms) in order to be found with this mode, otherwise the scanning interval may miss some or even all advertising events. This mode may be enforced if the scanning application is not in foreground.
  2. SCAN_MODE_BALANCED - Perform Bluetooth LE scan in balanced power mode. Scan results are returned at a rate that provides a good trade-off between scan frequency and power consumption. The scanner will scan for 2 seconds followed by 3 seconds of idle.
  3. SCAN_MODE_LOW_LATENCY - Scan using highest duty cycle. It's recommended to only use this mode when the application is running in the foreground.
  4. SCAN_MODE_OPPORTUNISTIC - A special Bluetooth LE scan mode. Applications using this scan mode will passively listen for other scan results without starting BLE scans themselves.

3 first modes are emulated on Android 4.3 and 4.4.x by starting a handler task that scans for a period of time and rests in between. To set scanning and rest intervals use Builder#setPowerSave(long,long).

Opportunistic scanning is not possible to emulate and will fallback to SCAN_MODE_LOW_POWER on Lollipop and power save settings on pre-Lollipop devices. That means that this library actually will initiate scanning on its own. This may have impact on battery consumption and should be used with care.

Scan filters and batching

Offloaded filtering is available on Lollipop or newer devices where BluetoothAdapter#isOffloadedFilteringSupported() returns true (when Bluetooth is enabled). If it is not supported, this library will scan without a filter and apply the filter to the results. If you find offloaded filtering unreliable you may force using compat filtering by calling Builder#useHardwareFilteringIfSupported(false). Keep in mind that, newer Android versions may prohibit background scanning without native filters to save battery, so this method should be used with care.

Android Scanner Compat Library may also emulate batching. To enable scan batching call Builder#setScanDelay(interval) with an interval greater than 0. For intervals less 5 seconds the actual interval may vary. If you want to get results in lower intervals, call Builder#useHardwareBatchingIfSupported(false), which will start a normal scan and report results in given interval. Emulated batching uses significantly more battery than offloaded as it wakes CPU with every device found.

Scanning with Pending Intent

Android 8.0 Oreo introduced Background Execution Limits which made background running services short-lived. At the same time, to make background scanning possible, a new method was added to BluetoothLeScanner which allows registering a PendingIntent that will be sent whenever a device matching filter criteria is found. This will also work after your application has been killed (the receiver must be added in AndroidManifest and the PendingIntent must be created with an explicit Intent).

Starting from version 1.3.0, this library may emulate such feature on older Android versions. In order to do that, a background service will be started after calling scanner.startScan(filters, settings, context, pendingIntent, requestCode), which will be scanning in background with given settings and will send the given PendingIntent when a device matching filter is found. To lower battery consumption it is recommended to set ScanSettings.SCAN_MODE_LOW_POWER scanning mode and use filter, but even with those conditions fulfilled the battery consumption will be significantly higher than on Oreo+. To stop scanning call scanner.stopScan(context, pendingIntent, requestCode) with the same intent in parameter. The service will be stopped when the last scan was stopped.

On Android Oreo or newer this library will use the native scanning mechanism. However, as it may also emulate batching or apply filtering (when useHardwareBatchingIfSupported or useHardwareFilteringIfSupported were called with parameter false) the library will register its own broadcast receiver that will translate results from native to compat classes.

The receiver and service will be added automatically to the manifest even if they are not used by the application. No changes are required to make it work.

To use this feature:

    Intent intent = new Intent(context, MyReceiver.class); // explicit intent
	intent.setAction("com.example.ACTION_FOUND");
	intent.putExtra("some.extra", value); // optional
	PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
	
	BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
	ScanSettings settings = new ScanSettings.Builder()
				.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
				.setReportDelay(10000)
				.build();
	List<ScanFilter> filters = new ArrayList<>();
	filters.add(new ScanFilter.Builder().setServiceUuid(mUuid).build());
	scanner.startScan(filters, settings, context, pendingIntent, requestCode);

Add your MyReceiver to AndroidManifest, as the application context might have been released and all broadcast receivers registered to it together with it.

To stop scanning call:

	// To stop scanning use the same PendingIntent and request code as one used to start scanning.
    Intent intent = new Intent(context, MyReceiver.class);
	intent.setAction("com.example.ACTION_FOUND");
	PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);
	
	BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
	scanner.stopScan(context, pendingIntent, requestCode);

Note: Android versions 6 and 7 will not report any advertising packets when in Doze mode. Read more about it here: https://developer.android.com/training/monitoring-device-state/doze-standby

Note 2: An additional parameter called requestCode was added in version 1.4.5 to the above API. It is to ensure that the scanning would be correctly stopped. If not provided, a request code equal to 0 will be used preventing from having multiple scanning tasks.

Background scanning guidelines

To save power it is recommended to use as low power settings as possible and and use filters. However, the more battery friendly settings are used, the longest time to finding a device. In general, scanning with PendingIntent and SCAN_MODE_LOW_POWER or SCAN_MODE_OPPORTUNISTIC should be used, together with report delay set and filters used. useHardwareFilteringIfSupported and useHardwareBatchingIfSupported should be set to true (default).

Background scanning on Android 4.3 and 4.4.x will use a lot of power, as all those properties will have to be emulated. It is recommended to scan in background only on Lollipop or newer, or even Oreo or newer devices and giving the user an option to disable this feature.

Note, that for unfiltered scans, scanning is stopped on screen off to save power. Scanning is resumed when screen is turned on again. To avoid this, use scanning with desired ScanFilter.

License

The Scanner Compat library is available under BSD 3-Clause license. See the LICENSE file for more info.

android-scanner-compat-library's People

Contributors

hearsilent avatar lenguyenthanh avatar paulpv avatar philips77 avatar piotr-pawlowski avatar roshanrajaratnam avatar roum-old1 avatar ruslan-h avatar sureshjoshi avatar unverbraucht avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

android-scanner-compat-library's Issues

Extra in callback intent

Hi there,

as in the example code, I try to add an extra to a callback intent, but this leads to some interesting results:

First, only the added extra shows up in the intent, meaning that BluetoothLeScannerCompat.EXTRA_LIST_SCAN_RESULT was removed.

But also I get massive stacktraces in logcat:

2019-09-17 10:33:02.790 1365-3432/? E/Parcel: Class not found when unmarshalling: no.nordicsemi.android.support.v18.scanner.ScanResult
    java.lang.ClassNotFoundException: no.nordicsemi.android.support.v18.scanner.ScanResult
        at java.lang.Class.classForName(Native Method)
        at java.lang.Class.forName(Class.java:453)
        at android.os.Parcel.readParcelableCreator(Parcel.java:2811)
        at android.os.Parcel.readParcelable(Parcel.java:2765)
        at android.os.Parcel.readValue(Parcel.java:2668)
        at android.os.Parcel.readListInternal(Parcel.java:3098)
        at android.os.Parcel.readArrayList(Parcel.java:2319)
        at android.os.Parcel.readValue(Parcel.java:2689)
        at android.os.Parcel.readArrayMapInternal(Parcel.java:3037)
        at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:288)
        at android.os.BaseBundle.unparcel(BaseBundle.java:232)
        at android.os.Bundle.putAll(Bundle.java:288)
        at android.content.Intent.fillIn(Intent.java:9433)
        at com.android.server.am.PendingIntentRecord.sendInner(PendingIntentRecord.java:269)
        at com.android.server.am.PendingIntentRecord.sendWithResult(PendingIntentRecord.java:245)
        at com.android.server.am.ActivityManagerService.sendIntentSender(ActivityManagerService.java:10000)
        at android.app.IActivityManager$Stub.onTransact$sendIntentSender$(IActivityManager.java:11540)
        at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:3183)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3829)
        at android.os.Binder.execTransact(Binder.java:752)
     Caused by: java.lang.ClassNotFoundException: no.nordicsemi.android.support.v18.scanner.ScanResult
        at java.lang.Class.classForName(Native Method)
        at java.lang.BootClassLoader.findClass(ClassLoader.java:1346)
        at java.lang.BootClassLoader.loadClass(ClassLoader.java:1406)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
        at java.lang.Class.classForName(Native Method) 
        at java.lang.Class.forName(Class.java:453) 
        at android.os.Parcel.readParcelableCreator(Parcel.java:2811) 
        at android.os.Parcel.readParcelable(Parcel.java:2765) 
        at android.os.Parcel.readValue(Parcel.java:2668) 
        at android.os.Parcel.readListInternal(Parcel.java:3098) 
        at android.os.Parcel.readArrayList(Parcel.java:2319) 
        at android.os.Parcel.readValue(Parcel.java:2689) 
        at android.os.Parcel.readArrayMapInternal(Parcel.java:3037) 
        at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:288) 
        at android.os.BaseBundle.unparcel(BaseBundle.java:232) 
        at android.os.Bundle.putAll(Bundle.java:288) 
        at android.content.Intent.fillIn(Intent.java:9433) 
        at com.android.server.am.PendingIntentRecord.sendInner(PendingIntentRecord.java:269) 
        at com.android.server.am.PendingIntentRecord.sendWithResult(PendingIntentRecord.java:245) 
        at com.android.server.am.ActivityManagerService.sendIntentSender(ActivityManagerService.java:10000) 
        at android.app.IActivityManager$Stub.onTransact$sendIntentSender$(IActivityManager.java:11540) 
        at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:3183) 
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3829) 
        at android.os.Binder.execTransact(Binder.java:752) 
     Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available
2019-09-17 10:33:02.790 1365-3432/? W/Bundle: Failed to parse Bundle, but defusing quietly
    android.os.BadParcelableException: ClassNotFoundException when unmarshalling: no.nordicsemi.android.support.v18.scanner.ScanResult
        at android.os.Parcel.readParcelableCreator(Parcel.java:2839)
        at android.os.Parcel.readParcelable(Parcel.java:2765)
        at android.os.Parcel.readValue(Parcel.java:2668)
        at android.os.Parcel.readListInternal(Parcel.java:3098)
        at android.os.Parcel.readArrayList(Parcel.java:2319)
        at android.os.Parcel.readValue(Parcel.java:2689)
        at android.os.Parcel.readArrayMapInternal(Parcel.java:3037)
        at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:288)
        at android.os.BaseBundle.unparcel(BaseBundle.java:232)
        at android.os.Bundle.putAll(Bundle.java:288)
        at android.content.Intent.fillIn(Intent.java:9433)
        at com.android.server.am.PendingIntentRecord.sendInner(PendingIntentRecord.java:269)
        at com.android.server.am.PendingIntentRecord.sendWithResult(PendingIntentRecord.java:245)
        at com.android.server.am.ActivityManagerService.sendIntentSender(ActivityManagerService.java:10000)
        at android.app.IActivityManager$Stub.onTransact$sendIntentSender$(IActivityManager.java:11540)
        at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:3183)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3829)
        at android.os.Binder.execTransact(Binder.java:752)

I was testing my code on a OnePlus 5T running Android 9, scanner lib is at 1.4.3.

Does anyone know what's going on there?

Cheers,

Max

Bonding failed

Hello,
I tested this case with Samsung S9 (Android 9.0) and Sony (Android 7.0). Same problem appears.
I also downloaded from Play Store "nRF Connect for Mobile" to make sure my implementation is not the real issue here. Same happens there.

  1. I find BLE device in list
  2. I do connection (everything is fine here)
  3. I do "Bonding"
  4. Pop-up PIN dialog appears, I enter PIN, bond is made successfully.
  5. I go to Bluetooth setting and do "unpair" on my BLE device.

then I procceed 1.-2. steps. But then, when I do "bonding" it says "bonding failed" and no PIN pop-up is shown. I tried to delete app, delete cache data on Bluetooth and restart device. At some point I made it possible to do the bonding once again. Followed the same path and then again after I unpaired device, I could not find a way to create bond with it.

My question is - is this supposed to be like that? Could it be, that my device is configurated somehow wrongly (after unpairing which is from user side, bonding data is not deleted or smth)?
I did try to refresh device cache ect., but nothing changed.

https://i.imgur.com/gzpWIau.png

ScanFilter setServiceUuid doesn't work?

When I use the scanner library to filter my Bluetooth LE devices ,I use the method "setServiceUuid " but doesn't work?

final String uuid = "0000fff0-0000-1000-8000-00805f9b34fb";

setServiceUuid(ParcelUuid.fromString(uuid))

Scanning multiple iBeacon devices

Hello!
We are trying to use AndroidScannerCompatLibrary in our Android application to scan BLE devices and measure its RSSI level. BLE devices is mounted on ceiling with distance approximately 1m.
There is implementation of StartScan() action (its uses Xamarin Binding Library from Nordic AndroidScannerCompatLibrary .aar file):

var scanner = BluetoothLeScannerCompat.Scanner;
            ScanSettings settings = new ScanSettings.Builder()
               .SetLegacy(false)
               .SetScanMode(ScanSettings.ScanModeLowLatency)
               .SetMatchMode(ScanSettings.MatchModeAggressive)
               .SetNumOfMatches(ScanSettings.MatchNumMaxAdvertisement) использую
               .SetReportDelay(0)
               .SetUseHardwareBatchingIfSupported(false)
               .Build();
           List< ScanFilter > filters = new List<ScanFilter>();
scanner.StartScan(filters, settings, _signalsScanCallback);

_signalsScanCallback store signals in package. After some period of time application send package to server storage.
And this is our stored RSSI level data set (from two iBeacon devices):
1
It seems like we have data from “one-device-per-period-of-time”.
Should we StartScan() for each device separately with list of ScanFilters, or it’s ok to use one instance of Scanner for all of it? We try to compare our results with same measures from “nRf connect”, and it’s differing. Can someone explain what are we doing wrong?

Problems with scanning on Huawei P8 Lite

I was able to solve this with the following scanning options, just thought i'll open a ticket in case someone is looking for options to test when the scanning fails on a phone:

ScanSettings.Builder()
    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
    .setReportDelay(1000)
    .setUseHardwareBatchingIfSupported(false)
    .setUseHardwareFilteringIfSupported(false);

Connect hangs on some devices

Hi,

Using your scanner compat library I've noticed that the scanner sometimes discovers devices where the record.device.name is null. Whenever the scanner identifies one of your boards like this I cannot connect to it - BleManager.connect(device) simply times out without providing any callbacks.

To resolve this problem I start nRF Connect which then causes the scanner to correctly find the friendly name of the devices as well as allowing me to connect to them.

It feels like I am missing something with the scanner, you seem to somehow reset the adapter. How is this done?

Thanks for some great products!

BluetoothLeScannerImplOreo startScan PendingIntent causes leak that eventually fails all future scans

This problem might manifest itself with can't Register GATT client, MAX client reached: 32 output in an unfiltered log.

Please also refer to my StackOverflow question and self-answer:
https://stackoverflow.com/q/57104535/252308

Basically, BluetoothLeScannerImplOreo startScanInternal has the following code (I added the log line in my fork):

        final PendingIntent pendingIntent = createStartingPendingIntent(nonNullFilters,
                nonNullSettings, context, callbackIntent);
        Log.v(TAG, "#GATT startScanInternal: pendingIntent=" + pendingIntent);
        return scanner.startScan(nativeFilters, nativeSettings, pendingIntent);

stopScanInternal has the following code (log line added in my fork):

        final PendingIntent pendingIntent = createStoppingPendingIntent(context, callbackIntent);
        Log.v(TAG, "#GATT stopScanInternal: pendingIntent=" + pendingIntent);
        scanner.stopScan(pendingIntent);

Here is a log of my app starting and stopping a few scans:

2019-07-19 21:14:51.230 16905-16905/com.testapp V/BleScannerManager: scan: #GATT +bleScanner.startScan(...)
2019-07-19 21:14:58.424 16905-16905/com.testapp V/BleScannerImplOreo: #GATT startScanInternal: pendingIntent=PendingIntent{1dfc67: android.os.BinderProxy@e560a14}
2019-07-19 21:14:58.468 1447-1941/? I/bt_stack: [INFO:gatt_api.cc(948)] GATT_Register 3c2e1fd9-d3fd-6897-a113-863aa50df781
2019-07-19 21:14:58.468 1447-1941/? I/bt_stack: [INFO:gatt_api.cc(968)] allocated gatt_if=7
2019-07-19 21:14:58.478 16905-16905/com.testapp V/BleScannerManager: scan: #GATT bleScanner.startScan(...); result=SUCCESS(0)
2019-07-19 21:14:58.479 16905-16905/com.testapp V/BleScannerManager: scan: #GATT -bleScanner.startScan(...)
2019-07-19 21:14:58.481 16905-16905/com.testapp E/BleScannerManager: #GATT bleScannerStartScanCount=1, elapsedMillisSinceBleScannerStartScanFirstTime=0
2019-07-19 21:15:03.521 1447-1447/? D/BtGatt.ScanManager: awakened up at time 614650173
2019-07-19 21:15:08.250 16905-16905/com.testapp V/BleScannerManager: scan: #GATT +bleScanner.stopScan(...)
2019-07-19 21:15:08.255 16905-16905/com.testapp V/BleScannerImplOreo: #GATT stopScanInternal: pendingIntent=PendingIntent{dc4115f: android.os.BinderProxy@84087ac}
2019-07-19 21:15:08.259 1447-1982/? E/BtGatt.ContextMap: Context not found for info com.android.bluetooth.gatt.GattService$PendingIntentInfo@77d2d25
2019-07-19 21:15:08.260 16905-16905/com.testapp V/BleScannerManager: scan: #GATT -bleScanner.stopScan(...)
2019-07-19 21:15:08.556 1447-1447/? D/BtGatt.ScanManager: awakened up at time 614655208
2019-07-19 21:15:08.570 1447-1554/? E/BtGatt.GattService: Exception: android.app.PendingIntent$CanceledException
2019-07-19 21:15:20.556 16905-16905/com.testapp V/BleScannerManager: scan: #GATT +bleScanner.startScan(...)
2019-07-19 21:15:20.570 16905-16905/com.testapp V/BleScannerImplOreo: #GATT startScanInternal: pendingIntent=PendingIntent{2ce86d6: android.os.BinderProxy@84087ac}
2019-07-19 21:15:20.575 1447-1941/? I/bt_stack: [INFO:gatt_api.cc(948)] GATT_Register 6b444e39-d61a-1d92-52d6-afd6e901b56b
2019-07-19 21:15:20.575 1447-1941/? I/bt_stack: [INFO:gatt_api.cc(968)] allocated gatt_if=8
2019-07-19 21:15:20.576 16905-16905/com.testapp V/BleScannerManager: scan: #GATT bleScanner.startScan(...); result=SUCCESS(0)
2019-07-19 21:15:20.576 16905-16905/com.testapp V/BleScannerManager: scan: #GATT -bleScanner.startScan(...)
2019-07-19 21:15:20.576 16905-16905/com.testapp E/BleScannerManager: #GATT bleScannerStartScanCount=2, elapsedMillisSinceBleScannerStartScanFirstTime=22097
2019-07-19 21:15:23.264 16905-16905/com.testapp V/BleScannerManager: scan: #GATT +bleScanner.stopScan(...)
2019-07-19 21:15:23.269 16905-16905/com.testapp V/BleScannerImplOreo: #GATT stopScanInternal: pendingIntent=PendingIntent{ebafcb0: android.os.BinderProxy@ebb6729}
2019-07-19 21:15:23.272 1447-1982/? E/BtGatt.ContextMap: Context not found for info com.android.bluetooth.gatt.GattService$PendingIntentInfo@3abaefa
2019-07-19 21:15:23.272 16905-16905/com.testapp V/BleScannerManager: scan: #GATT -bleScanner.stopScan(...)
2019-07-19 21:15:24.968 16905-16905/com.testapp V/BleScannerManager: scan: #GATT +bleScanner.startScan(...)
2019-07-19 21:15:24.980 16905-16905/com.testapp V/BleScannerImplOreo: #GATT startScanInternal: pendingIntent=PendingIntent{8b1626b: android.os.BinderProxy@ebb6729}
2019-07-19 21:15:24.990 1447-1941/? I/bt_stack: [INFO:gatt_api.cc(948)] GATT_Register 0bbb0b8f-2c63-dfc2-268d-fbfe39360ddf
2019-07-19 21:15:24.990 1447-1941/? I/bt_stack: [INFO:gatt_api.cc(968)] allocated gatt_if=9
2019-07-19 21:15:24.990 16905-16905/com.testapp V/BleScannerManager: scan: #GATT bleScanner.startScan(...); result=SUCCESS(0)
2019-07-19 21:15:24.990 16905-16905/com.testapp V/BleScannerManager: scan: #GATT -bleScanner.startScan(...)
2019-07-19 21:15:24.991 16905-16905/com.testapp E/BleScannerManager: #GATT bleScannerStartScanCount=3, elapsedMillisSinceBleScannerStartScanFirstTime=26511
2019-07-19 21:15:25.019 1447-1554/? E/BtGatt.GattService: Exception: android.app.PendingIntent$CanceledException
2019-07-19 21:15:25.795 1447-1941/? I/bt_stack: [INFO:gatt_api.cc(948)] GATT_Register 32a50296-06f2-ed4d-f83c-25da059a4a19
2019-07-19 21:15:25.795 1447-1941/? I/bt_stack: [INFO:gatt_api.cc(968)] allocated gatt_if=10
2019-07-19 21:15:26.046 1447-1447/? D/BtGatt.ScanManager: awakened up at time 614672699
2019-07-19 21:15:27.000 16905-16905/com.testapp V/BleScannerManager: scan: #GATT +bleScanner.stopScan(...)
2019-07-19 21:15:27.005 16905-16905/com.testapp V/BleScannerImplOreo: #GATT stopScanInternal: pendingIntent=PendingIntent{40e339d: android.os.BinderProxy@6340012}
2019-07-19 21:15:27.008 1447-1982/? E/BtGatt.ContextMap: Context not found for info com.android.bluetooth.gatt.GattService$PendingIntentInfo@96b43b4
2019-07-19 21:15:27.009 16905-16905/com.testapp V/BleScannerManager: scan: #GATT -bleScanner.stopScan(...)
2019-07-19 21:15:28.679 1447-1941/? I/bt_stack: [INFO:gatt_api.cc(948)] GATT_Register f119757a-00ff-29b4-72e0-952c5e0db695
2019-07-19 21:15:28.679 1447-1941/? I/bt_stack: [INFO:gatt_api.cc(968)] allocated gatt_if=10
2019-07-19 21:15:28.810 1447-1447/? D/BtGatt.ScanManager: awakened up at time 614675462
2019-07-19 21:15:28.822 1447-1554/? E/BtGatt.GattService: Exception: android.app.PendingIntent$CanceledException

Notice that the pendingIntent= logged during a startScan and stopScan do not match.
This means that the code never actually stops any PendingIntent started scans.
The pendingIndent passed to stopScan must be the exact same one that was passed to startScan.

You can usually only start about 28, max of 32, scans before the OS blocks all future scans.
This repros on every API >= 26 phone I have tried.

I can look in to a fix and send a PR, but I wanted to open this issue to see if there is anything else to discuss.

How to check that bluetooth device is connected or not?

I have using this library to scan and connect the Bluetooth devices to android app. Its working fine. Now once device is connect then i set Connected text in ListAdapter textview in the app that user can see that device is connected. After if any device goes to out of range or disconnected then i need to update the state Connected to Connecting..... in the ListAdapter UI but how i know that device is connected or not?
One other thing is if device is connected and its state changed (means any kind of notify ) then how to know that ?
Help would be very appreciate and thanks

About Android9.0 scanning

hello,I can't get the scan result with Android 9.0. The callback result is empty. What's the solution?

NullPointerException with ScanFilter setManufacturerData

Great library! Encountered one problem.

With the normal ScanFilter object I can make this call to filter only advertisements that match the specific manufacturer ID (while not caring what the actual manufacturer data is).

private final ScanFilter mScanFilter = new ScanFilter.Builder()
            .setManufacturerData(MFG_ID, null)
            .build();

But making this call with this scanner compat library and running it on 5.0.1 (and possibly others) results in a crash due to the null byte array.

Here's the stack trace:

java.lang.NullPointerException: Attempt to get length of null array
            at no.nordicsemi.android.support.v18.scanner.ScanFilter.matchesPartialData(ScanFilter.java:345)
            at no.nordicsemi.android.support.v18.scanner.ScanFilter.matches(ScanFilter.java:302)
            at no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerCompat$ScanCallbackWrapper.matches(BluetoothLeScannerCompat.java:298)
            at no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerCompat$ScanCallbackWrapper.handleScanResult(BluetoothLeScannerCompat.java:248)
            at no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerImplLollipop$ScanCallbackImpl.onScanResult(BluetoothLeScannerImplLollipop.java:131)
            at android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper$1.run(BluetoothLeScanner.java:347)

[1.3.0][Android < Oreo] Scanning stops when app is swiped out of the "task-manager"

The new pendingIndent solution works great on Android >= Oreo.
I wrote a foreground service that handles the BLE stuff independently from the actual app. This service is the only place where startScan/stopScan is called.

When I call scanner.startScan(filters, settings, mService, pendingIntent); the scanning stops when i swipe the app out of the android "task-manager" (The foreground-service is still running). When I start the scan with scanner.startScan(filters, settings, scanCallback); scanning didn't stop.

I think this is the normal background task behavior when the task is started from an activity in the app. I wonder why the background task get destroyed when I start the scan in the foreground service.

Scanner scans for infinity when batching disabled and report delay is > 0

Issue initially reported here: https://stackoverflow.com/questions/47981327/scancallback-onbatchscanresults-is-getting-called-indefinitly (very long time ago).
I can confirm scanning started with the following settings does not stop when stopScan is called in onBatchedScanResults:

// Scanning settings
final ScanSettings settings = new ScanSettings.Builder()
	.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
	.setReportDelay(500)
	.setUseHardwareBatchingIfSupported(false)
	.build();

Logs from a sample app:

2019-01-18 16:28:56.831 29232-29232/no.nordicsemi.android.nrfblinky W/AA: callback used to start scan: no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerImplLollipop$ScanCallbackWrapperLollipop$1@f4e51ba
2019-01-18 16:28:57.331 29232-29232/no.nordicsemi.android.nrfblinky I/AA: onBatchScanResults: 16
2019-01-18 16:28:57.334 29232-29232/no.nordicsemi.android.nrfblinky W/AA: callback used to stop scan:  no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerImplLollipop$ScanCallbackWrapperLollipop$1@f4e51ba
2019-01-18 16:28:57.837 29232-29232/no.nordicsemi.android.nrfblinky I/AA: onBatchScanResults: 0
2019-01-18 16:28:59.844 29232-29232/no.nordicsemi.android.nrfblinky I/AA: onBatchScanResults: 0
2019-01-18 16:29:00.346 29232-29232/no.nordicsemi.android.nrfblinky I/AA: onBatchScanResults: 0
2019-01-18 16:29:00.847 29232-29232/no.nordicsemi.android.nrfblinky I/AA: onBatchScanResults: 0
2019-01-18 16:29:01.349 29232-29232/no.nordicsemi.android.nrfblinky I/AA: onBatchScanResults: 0
[...]

Tested with version 1.2.0 on Pixel 2 with Android Pie.

Scanner doesn't find device when using filters.

Hi,

Thanks for your great library. I tried to find a heart rate monitor gadget, but unfortunately scanner.startScan(filter, settings, callback) doesn't return any result. When I use scanner.startScan(callback) it found the device. I tested with both service UUID and device name. I used complete 128bit service uuid 0000180D-0000-1000-8000-00805f9b34fb.

Manufacturer Data / Mask seem to be ignored when filtering ScanResults

Hi,

I'm currently trying to set some ScanFilters when registering my BLEScanner to filter on service UUID and Manufacturer Data.

The thing is, while the ScanResults I get are properly filtered with service UUID, there is no filter applied on Manufacturer Data, resulting on inconsistent Scan Result filtering...

I tried the following:

filters.add(ScanFilter.Builder()
                .setServiceUuid(ParcelUuid.fromString(serviceUUID.toString()))
                .build())

filters.add(ScanFilter.Builder()
                .setManufacturerData(manufacturerId, manufacturerData, mask)
                .build())

or

filters.add(ScanFilter.Builder()
                .setManufacturerData(manufacturerId, manufacturerData, mask)
                .setServiceUuid(ParcelUuid.fromString(serviceUUID.toString()))
                .build())

coupled with scanner.startScan(filters, settings, callback)

Scan Results only seem to be filtered on Service UUID.

My manufacturerId is an int, manufacturerData is a ByteArray and mask is a ByteArray of the same size with full 1.

Can you please help me on this issue ?

SCAN_RESULT_TYPE_FULL

Hello,

SCAN_RESULT_TYPE_FULL and SCAN_RESULT_TYPE_ABBREVIATED are private but the method setScanResultType is public.

Mike

BluetoothLeScanner on android 6.0.1 (ss s6 edge) cannot found device android >= 6.0.1

Hi all,
this code for scanning BLE device:

if (mBluetoothLEScanner == null) {
// create bluetoothLE scanner if it is null
mBluetoothLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
}
// start scan bluetooth
mBluetoothLEScanner.startScan(
null,
buildScanSettings(),
mProxyScanCallback);

private ScanSettings buildScanSettings() {
ScanSettings.Builder builder = new ScanSettings.Builder();
builder.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER);
builder.setReportDelay(0);
return builder.build();
}

Setting:



I cannot found device android >= 6.0.1, but can scan other device

There are any problem?Thank you.

How to include this library in project where min SDK < 18?

I'd like to include Android-Scanner-Compat-Library in a project where min SDK < 18 so that if the device SDK is < 18, then I wouldn't use BLE capabilities, and otherwise I would use it per this library.

However, the manifest requires min SDK 18. Is there any way around this?

I can`t stop scan,After I call the stop scan method, the callback is still executed.

 override fun onBatchScanResults(results: List<ScanResult>?) {
            // This callback will be called only if the report delay set above is greater then 0.

            // If the packet has been obtained while Location was disabled, mark Location as not required
            if (Utils.isLocationRequired(application) && !Utils.isLocationEnabled(application))
                Utils.markLocationNotRequired(application)

            var atLeastOneMatchedFilter = false
            for (result in results!!)
                atLeastOneMatchedFilter = mDevicesData.deviceDiscovered(result) || atLeastOneMatchedFilter
            if (atLeastOneMatchedFilter) {
                mDevicesData.applyFilter()
                mScannerState.recordFound()
            }
            stopScan()
        }

fun stopScan(){
        val scanner = BluetoothLeScannerCompat.getScanner()
        scanner.stopScan(scanCallback)
    }

mUUid,

filters.add(new ScanFilter.Builder().setServiceUuid(mUuid).build());
I don't know this.mUUid what it is mean.please

In Android 9 and 10 if use filter peer not found on scan process

Hi.
Using this lib, I came across an unpleasant thing: if I set filter like as:

final List<ScanFilter> filters = new ArrayList<>();
filters.add(new ScanFilter.Builder().setDeviceName(KNOWN_DEV_NAME).build());
scanner.startScan(filters, settings, scanCallback);

then scanner do not return result and stop by timeout.

Any settings for "setScanMode" do not give a result.

When don`t use filter: all ok.

Code example:

final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
final ScanSettings settings = new ScanSettings.Builder()
                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                .setReportDelay(500)
                .build();
final List<ScanFilter> filters = new ArrayList<>();
filters.add(new ScanFilter.Builder().setDeviceName(working_device_name).build());
scanner.startScan(filters, settings, scanCallback);

Scan record is always a partial byte array

Not sure if I've configured this correctly, but I'm not seeing any scan results returned in my callback. It looks like the scanRecord byte[] is coming in as partial instead of complete when attempting to init a ScanRecord. When parseServiceUuid is called on line 224 inside ScanRecord.java, there is no data to parse, so I'm not seeing any returned scan results in my callback. I've implemented a different scanning service which returns the 128 bit complete data type from the same peripheral device. Am I missing some configuration settings that allows the scanner to return the completed byte[]?

I'm using the sample scanning code noted in your readme.

SCAN_MODE_OPPORTUNISTIC crashes on Lollipop

Samsung S5, on Android 5.0.

new no.nordicsemi.android.support.v18.scanner.ScanSettings.Builder()
  .setScanMode(ScanSettings.SCAN_MODE_OPPORTUNISTIC)
  .setUseHardwareBatchingIfSupported(false)
  .build();
java.lang.IllegalArgumentException: invalid scan mode -1
   at android.bluetooth.le.ScanSettings$Builder.setScanMode(ScanSettings.java:213)
   at no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerImplLollipop.toImpl(BluetoothLeScannerImplLollipop.java:186)
   at no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerImplLollipop.startScanInternal(BluetoothLeScannerImplLollipop.java:70)
   at no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerCompat.startScan(BluetoothLeScannerCompat.java:112)

It should fallback to a mode that it does support, which would probably be SCAN_MODE_LOW_POWER.

Scan result name is null

Hi, i have some weird behavior with ble scanning.
I implemented app that perform scanning and connection to ble devices with help of android scanner, the problem is i have some devices (for example samsung s8 android version 9) that the scan result not contains the device name, i checked from other android device i do see the name.
I downloaded the NrfConnect app from google play store and it seems that this app show the device name at 80 % of the time in the problematic device (samsung s8) , so i downloaded this library to see what is the 'magic' that helps to receive the name, but after building simple app that prints the name to log i seed that even with current library the names are null always.
The question is what can lead to this problem ? Do you use current library in the NrfConnect app ?

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
      if(checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
        requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 23);
      }
    }



    final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();

    final ScanSettings settings = new ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
            .setUseHardwareBatchingIfSupported(false)
            //.setReportDelay(5000)
            .build();
    final List<ScanFilter> filters = new ArrayList<>();
    filters.add(new ScanFilter.Builder().setServiceUuid(new ParcelUuid(UUID.fromString("XXXXXX-XXXX-0BAC-5241-XXXXXX"))).build());



    startScanBtn.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        scanner.startScan(filters, settings,listener);
      }
    });

    stopScanBtn.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        scanner.stopScan(listener);
      }
    });
  }

  private ScanCallback listener = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
      super.onScanResult(callbackType, result);
      String name = result.getDevice().getName();
      Log.d("OnMyScanResult", "DeviceName: "+name);
    }

    @Override
    public void onScanFailed(int errorCode) {
      super.onScanFailed(errorCode);
      Log.d("ScanResult", "Scan failed code: "+errorCode);
    }

    @Override
    public void onBatchScanResults(@NonNull List<ScanResult> results) {
      super.onBatchScanResults(results);

      for(ScanResult result : results){
        String name = result.getDevice().getName();
        Log.d("OnMyScanResult", "DeviceName: "+name);
      }
    }
  };

Emulate SCAN_MODE_OPPORTUNISTIC on older devices

SCAN_MODE_OPPORTUNISTIC has been added in Android Marshmallow.
Currently the library declares this constant, and even use it on Android Marshmallow+ devices, but:

  1. The documentation doesn't mention it:
    /**
    * Set scan mode for Bluetooth LE scan.
    *
    * @param scanMode The scan mode can be one of {@link ScanSettings#SCAN_MODE_LOW_POWER},
    * {@link ScanSettings#SCAN_MODE_BALANCED} or
    * {@link ScanSettings#SCAN_MODE_LOW_LATENCY}.
    * @throws IllegalArgumentException If the {@code scanMode} is invalid.
    */
    @NonNull
    public Builder setScanMode(final int scanMode) {
    if (scanMode < SCAN_MODE_OPPORTUNISTIC || scanMode > SCAN_MODE_LOW_LATENCY) {
    throw new IllegalArgumentException("invalid scan mode " + scanMode);
    }
    this.scanMode = scanMode;
    return this;
    }
  2. The library does not emulate this mode for older versions.

Although it is not possible to fully recreate the same behavior, this could be emulated as SCAN_MODE_LOW_POWER. With setPowerSave(...) method those settings would be applied for pre-Marshmallow devices just like they are when LOW_POWER mode is used. This would have to be documented.

The reason this mode should be supported on older platforms is that currently it is ignored.

Android P scanner compatibility

Hi,
Has anyone ever tested the library with the latest version of Android P.
The library is working flawlessly on devices from Lollipop to Android Oreo but for some reasons, it doesn't work on my Pixel 2.
What trouble me is that the NRF connect app seems to be able to discover the device without any issue.

Thanks for the feedback !

auto-stop scanning when BT turns off should 1) be option, 2) auto-resume when on (also optional)

Commit 8a20607 is nice, but I think will break my app.
My app already detects BT on/off and "pauses" or "resumes" scanning as necessary.
If Android-Scanner-Compat-Library automatically stops scanning then my app could see that has a hard stop and hard stop itself.

I haven't yet updated my dependency to confirm if you change breaks my app.
But, hear me out and please let me know if my opinion seems valid...

Again, nice change, but if you are going to automatically stop scanning then coolio, but that is only part of the story.
To make this a complete solution then you must also then detect when BT is turned on and automatically start scanning if the user of your library hasn't called stop.

Also, this auto-stop/start feature should be an option, which would be fine to default to on.

It is possible that this change doesn't break my code, but I think this library would benefit from a more complete solution.

BT Adapter is not turned ON

I got this crash, I've check BT is on by mBluetoothAdapter.isEnabled().
It's seems like sometimes mBluetoothAdapter.isEnabled() not the same mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON.

Do you have any suggestions?

Thx!

Fatal Exception: java.lang.IllegalStateException: BT Adapter is not turned ON
at no.nordicsemi.android.support.v18.scanner.BluetoothLeUtils.checkAdapterStateOn(BluetoothLeUtils.java:137)
at no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerImplLollipop.startScanInternal(BluetoothLeScannerImplLollipop.java:64)
at no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerCompat.startScan(BluetoothLeScannerCompat.java:123)

Scanning Problem in API 6.0.1

hello. i'm using your library in my project. Its working perfectly in API 5, But when i test it on 6.0.1 ScanCallBack didn't called.
i'm using scanner.startScan(mScanCallback) method and onScanResult never triggered.
Hope you will reply soon and guide me through. thanks

Disabling background scan when device is locked

Hi there,

I tried the background scanning and it works just perfectly except for devices running Android 7 or lower where this background scanning behavior is emulated as the battery drains really quickly.

On devices with O or P, I saw that the scanning is normally suspended by the OS some time after the device was locked. Is it possibly to do this too or (even better) to just throttle the background scanning then?

Regards

Max

Invoke ScanCallback in worker thread

Hello,
What do you think about calling ScanCallback methods in a worker thread? It would be useful for wrapping scanner in RxJava Observable class. Right now everything is invoked in the main thread. It is simple to implement, just add a Handler param in startScan method (like in Android SensorManager or LocationManager class).

Unable to scan devices

Hi,

I have used the Sample provided in the description, without any filter.
But still I am not getting callbacks. I have also referred to nrf-blinky example which uses this library.
My Scan code is exactly same as that provided in except filter part https://github.com/NordicSemiconductor/Android-nRF-Blinky. But still no callbacks are received.

Phone Model - Oneplus 3.
Note - I am trying to search and connect a non nordic BLE device. will that have any impact on this?
Please help I am stuck on this :(
Thanks,
sat

Caught a RuntimeException from the binder stub implementation

getting an unusual RuntimeException in Android 6.0.1 API23 with targetSdkVersion 23 (build.gradle)
It was OK in Android 6.0.1 API23 with targetSdkVersion 22 (build.gradle)

`02-20 13:08:53.919 12379-12513/ D/BluetoothLeScanner: onClientRegistered() - status=0 clientIf=5
02-20 13:08:53.923 12379-12513/ W/Binder: Caught a RuntimeException from the binder stub implementation.
java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results
at android.os.Parcel.readException(Parcel.java:1627)
at android.os.Parcel.readException(Parcel.java:1579)
at android.bluetooth.IBluetoothGatt$Stub$Proxy.startScan(IBluetoothGatt.java:772)
at android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper.onClientRegistered(BluetoothLeScanner.java:324)
at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:56)
at android.os.Binder.execTransact(Binder.java:453)

02-20 13:09:01.213 12379-12574/ V/RenderScript: 0x7f5fe7e000 Launching thread(s), CPUs 8
02-20 13:09:01.231 12379-12379/ I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@abbc528 time:42374438`

The time period opens the scanning, the scanning stops, sometimes does not scan the data, after a period of time only then normal.

private volatile boolean turnOnOff = false;

private void startTimer() {
    timer = new Timer();
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
            if (!turnOnOff) {
                scanner.startScan(null, scanSettings, scanCallback);
                Log.i("定时性", "扫描");
            } else {
                scanner.stopScan(scanCallback);
                Log.i("定时性", "停止");
            }
            turnOnOff = !turnOnOff;
        }
    } ,0 , 1000);
}

Handling of onScannerRegistered() status=6 (Scanning too frequently)

Hello,

If a scan is started too often it will fail silently, only printing a onScannerRegistered where you have to read the status code. Is there a way to catch this even? When a scan fails because user or app initiated the scan too often? The ScanCallback does not yeild a onScanFailed.

In my app a scan happens directly when a user enters a certain view, thus toggling in and out of the app (resume/pause) several times will cause the scan to start/stop several times. Sometimes the scan fails to start and thus user is unaware that the scan is not actually running because it fails silently.

The same issue can be found in the nRF Connect app and can be easily reproduced there, happily button mashing the Scan button will cause the app to show a state of scanning (button showing "STOP SCANNING") even though the starting of the scan failed.

I kept getting source code not matching byte code when trying to trace down the error so it was hard for me to research this issue further. Tried looking through the Android Source code but it seems like they are not propagating this information to layers above:
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/bluetooth/le/BluetoothLeScanner.java#394

Is there any way to know if you are scanning to often and let the user know or just delay the scan until the module is ready?

Best regards
David

ManufacturerSpecificData is not working properly

I have a low-power Bluetooth device that advertisement data like this:
[
02 01 05 08 09 61 6e 74 68 65 72 6f
09 ff 11 02 11 02 d9 21 a3 38
1e ff 11 02 11 02 d9 21 a3 38 21 43 01 d9 00 10 19 44 45 4c 20 68 73 65 4d 20 47 53 54 42
4a 00 00 00 00 00 00 00 00 00
]
// result.getScanRecord().getManufacturerSpecificData()
//or
//result.getScanRecord().getManufacturerSpecificData(0x0211)

The ManufacturerSpecificData I read sometimes is like this:
[ 11 02 d9 21 a3 38 ] (When the signal is weak, more is like this)
, sometimes it is like this:
[
11 02 d9 21 a3 38 21 43 01 d9 00 10 19 44 45 4c 20 68 73 65 4d 20 47 53 54 42
4a 00 00 00 00 00 00 00 00 00
]
And I want to get all the advertisement data, but I didn't find the relevant method.
I hope I can get your reply, thank you.

Device name is null on some conditions.

Hi,

Sometimes the device name is null on onBatchScanResults, switching bluetooth on/off doesn't help, but after scanning with nRFConnect, and rescan with library the problem resolved. Is there any configuration that nRFConnect use? or is there any cache that I should clear before starting scan?

Failed to resolve no.nordicsemi.android.support.v18:scanner

Its working fine in my current project. i am using Android Studio 3.2 and before 3.1. i have seen one warning message that change the compile to implementation. But when i change compile to implementation then this error is occur in android studio 3.2. As per google that compile is closed to end of the 2018 so i am trying to change it. So is there any update regarding this then its appreciate. I have checked this stack overflow link also.

onBatchScanResults continue to receive after stopScan

i have logged (can't reproduce, now under heavy test) cases where scanner.stopScan(nordic_scanCallback); has been issued in API 18 (Android 4.3 HTC phone) but the onBatchScanResults (...) still continue receiving (something like that shown below) and NO D/BluetoothAdapter: onScanResult() - Device=B4:99:4C:1E:7C:32 RSSI=-88 logged.

@OverRide
public void onBatchScanResults(List results)
{
Log.d(TAG, "nordic_scanCallback -> onBatchScanResults sz = " + results.size());
}

D/BluetoothAdapter: stopLeScan()
...
....
D/BLE_com: nordic_scanCallback -> onBatchScanResults sz = 0
D/BLE_com: nordic_scanCallback -> onBatchScanResults sz = 0
D/BLE_com: nordic_scanCallback -> onBatchScanResults sz = 0
D/BLE_com: nordic_scanCallback -> onBatchScanResults sz = 0
...
...
...

Add a scanning operation timeout

It would be good to have a scanning timeout to set a maximum of the process if desired. Something like this in the API would be nice:

@NonNull
public Builder setDuration(final long durationMillis) {
  if (durationMillis < 0) {
    throw new IllegalArgumentException("durationMillis must be > 0");
  }
  this.durationMillis = durationMillis;
  return this;
}

and start a Handlerwith that specific durationMillis until it is reached to stop the scanning process. I guess that would require a new onStop method in the ScanCallback abstract class.

What do you think guys? Is it something the library could handle or it's just better to manage ourselves those timeouts?

Android Lollipop "blocking" some devices on scan results

Hi,
I have one problem in scan devices on Android Lollipop (5.1.1).

I have one device advertising constantly and sometimes the library don't return this device in advertisement results.
I was investigating the problem and I noted that when the lib don't return the advertisement anyone BLE app returns that advertisement.
It's like the Android has blocked that "device" and anyone app can't identify.

On newer Android versions I don't have this problem.

Someone knows what's happening?

PS: There is a fun fact that looking the LOG, I can see de BLE Address with and error, but I don't found any explanation about that.

09-15 15:09:01.268 4379-4579/? E/bt-btm: new address: 55:44:33:22:11:00

where my BLE Address is 55:44:33:22:11:00 but the result don't appear in the return scanned devices on the lib.

I have tried to filter by BLE Address, services, manufacturer data, etc etc, but I have the same problem.

Thanks in advanced.

Problem in reliability of receiving advertisements. #41

Hello,
I am in the process of designing an app which listens for any BLE advertisements, and filters them according to their contents. Currently, I am testing the reliability of the nordic BluetoothLeScannerCompat - that is, I am seeing if it will receive all advertisement data. I have a peripheral emitting an advertisement on channels 37-39, once every 40ms.

In nRF connect, all of these advertisements are received with great consistency, as shown in the "History" tab of any device. However, when I use the nordic (and Android Standard) Scanner, I am much less consistent in receiving these advertisements. In a 15 second timespan, my application received about 40 advertisements from the peripheral, whereas nRF Connect received about 150.

My code for the scanner:

String desiredMacAddress = the peripherals mac address.
BluetoothAdapter mBTAdapter;
BluetoothLeScannerCompat mBleScanner;
ScanCallback scanCallback  = new ScanCallback (){
                @Override
                public void onScanResult(int callbackType, ScanResult result){
                    if ( result.getDevice().getAddress().equals(desiredMacAddress )
                          appendMyTextView("\n You received me!");
                    });
                }
            };

public void init(){
        final BluetoothManager btManager = (BluetoothManager) 
        scanActivity.getSystemService(Context.BLUETOOTH_SERVICE);
        mBTAdapter = btManager.getAdapter();
        mBleScanner = BluetoothLeScannerCompat.getScanner();

        scanLeDevice(true)
}

private void scanLeDevice(final boolean enable){
        if(enable) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    //BLEDevice Scan has ended
                   stop()
                }
            }, 15000);
            mLeScanner.startScan(scanCallback);
        }
        else{
            mScanning = false;
            mLeScanner.stopScan(scanCallback);
        }
    }

private void stop(){
     scanLeDevice(false)
}

Any advice on how to improve scan reliability would be much appreciated!

IllegalArgumentException in Android 7 and some Samsung devices

Hi, I'm seeing these crashes in Google Play console

java.lang.IllegalArgumentException: 
  at android.bluetooth.le.BluetoothLeScanner.stopScan (BluetoothLeScanner.java:226)
  at no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerImplLollipop.stopScan (BluetoothLeScannerImplLollipop.java:98)
 ...
  at android.os.Handler.dispatchMessage (Handler.java:98)
  at android.os.Looper.loop (Looper.java:154)
  at android.os.HandlerThread.run (HandlerThread.java:61)

I'm only seeing them on S8 and S3 devices, and only on Android 7.0, but we don't have that many users.

I can't see how stopScan can throw IllegalArgumentException (here's nougat's BluetoothLeScanner. I guess that's some Samsung fidling?

I've never been able to reproduce it, but I don't usually work with those devices

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.