Android Question BLE Android 8.1 and higher

Philip Prins

Active Member
Licensed User
Longtime User
From Android 8.1 you can not do a Bluetooth scan without a filter when the screen is off.
In BLE manager you can only filter on UUID however this doesn't work on iBeacons.
Is there a way to filter on name or manufacturer ?



Regards
Philip
 

Philip Prins

Active Member
Licensed User
Longtime User
You can only filter by services UUIDs.

Have you tried it when there is a foreground service?
Yes ,
You can not scan without a filter from 8.1 and higher:
Start Bluetooth LE scan with default parameters and no filters. The scan results will be delivered through callback. 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 startScan(java.util.List, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback) with desired ScanFilter.

However you can not scan ibeacons based on their UUID , you have to scan on name or manufacturar ID.
But with BLEmanager2 you can only set an UUID as filter.
Criteria for filtering result from Bluetooth LE scans. A ScanFilter allows clients to restrict scan results to only those that are of interest to them.

Current filtering on the following fields are supported:

  • Service UUIDs which identify the bluetooth gatt services running on the device.
  • Name of remote Bluetooth LE device.
  • Mac address of the remote device.
  • Service data which is the data associated with a service.
  • Manufacturer specific data which is the data associated with a particular manufacturer.
 
Upvote 0

Philip Prins

Active Member
Licensed User
Longtime User
Thanks Erel,

Got this working but now i want to add a second filter :
B4X:
Private Sub ScanWithLeScanner
    Dim ScanSettingsStatic As JavaObject
    ScanSettingsStatic.InitializeStatic("android.bluetooth.le.ScanSettings")
    Dim ScanSettingsBuilder As JavaObject
    ScanSettingsBuilder.InitializeNewInstance("android.bluetooth.le.ScanSettings.Builder", Null)
    'https://developer.android.com/reference/android/bluetooth/le/ScanSettings.Builder
    ScanSettingsBuilder.RunMethod("setScanMode", Array(ScanSettingsStatic.GetField("SCAN_MODE_LOW_LATENCY")))
    '----------------------------------------------------------------------
    
    Dim ScanFilterStatic As JavaObject
    ScanFilterStatic.InitializeStatic("android.bluetooth.le.ScanFilter")
    Dim ScanFilterBuilder As JavaObject
    ScanFilterBuilder.InitializeNewInstance("android.bluetooth.le.ScanFilter.Builder", Null)
    'https://developer.android.com/reference/android/bluetooth/le/ScanFilter.Builder
    'ScanFilterBuilder.RunMethod("setDeviceName", Array("CCheck"))
    '    Add Scan Filter
    Dim ParcelUuidStatic As JavaObject
    ParcelUuidStatic.InitializeStatic("android.os.ParcelUuid")
    Dim ParcelUuid As JavaObject
    ParcelUuid = ParcelUuidStatic.RunMethod("fromString",Array("00000001-0000-1000-8000-00805f9b34fb"))
    'Log("LOOK HERE => " & ParcelUuid.RunMethod("toString",Null))
  
    ScanFilterBuilder.RunMethod("setServiceUuid", Array(ParcelUuid))
    
    
'    ScanFilterBuilder.RunMethod("setDeviceName", Array("CCheck"))
    Dim Filters As List = Array(ScanFilterBuilder.RunMethod("build", Null))
    '---------------------------------------------------------------------------
    Scanner.RunMethod("startScan", Array(Filters, ScanSettingsBuilder.RunMethod("build", Null), ScanCallback))
End Sub

I want to add :ScanFilterBuilder.RunMethod("setDeviceName", Array("CCheck")) but when i insert this it will not work.
How can i add an extra filter item?
 
Upvote 0

Philip Prins

Active Member
Licensed User
Longtime User
In which way doesn't it work? Where is the error message?

With one scanfilter the scan filter works and finds the devices.

When i add the second it does not find any devices.
No error messages.


I assume i can only make scanlist for one type , so for example only UUID.
Not mixing between UUID and name in the same scanfilter.

Solved it by making 2 services, one for UUID and one for Name.
 
Last edited:
Upvote 0

Philip Prins

Active Member
Licensed User
Longtime User
One problem left , how to get the advertising data:

B4X:
Private Sub Scan_Result (Result As Object)
    'Log("Scan_Result")
    Dim ScanResult As JavaObject = Result
    Dim device As JavaObject = ScanResult.RunMethod("getDevice", Null)
    Dim address As String = device.RunMethod("getAddress", Null)
    ManagerJO.GetFieldJO("devices").RunMethod("put", Array(address, device))
    Dim name As String
    Dim o As Object = device.RunMethod("getName", Null)
    If o = Null Then name = "" Else name = o
    Dim ScanRecord As JavaObject = ScanResult.RunMethod("getScanRecord", Null)
    'Log(ScanRecord) 'you can extend the code to access the data.
    'https://developer.android.com/reference/android/bluetooth/le/ScanRecord
    Dim rssi As Double = ScanResult.RunMethod("getRssi", Null)
    [B]Manager_DeviceFound(name, address, CreateMap(), rssi)[/B]
End Sub

ManagerDevice found expect a map:

In the log the scanrecord : (ScanRecord) ScanRecord [mAdvertiseFlags=6, mServiceUuids=null, mManufacturerSpecificData={76=[2, 21, -3, -91, 6, -109, -92, -30, 79, -79, -81, -49, -58, -21, 7, 100, 120, 37, 18, 94, 86, 120, -61]}, mServiceData={00007364-0000-1000-8000-00805f9b34fb=[1, -86, -69, -52, -35, -18, -1, 0, 17, 34, 51, 68, 85]}, mTxPowerLevel=4, mDeviceName=CCheck]

When i get the manufacturer specific date like this :
B4X:
Dim B As Object =  ScanRecord.RunMethod("getManufacturerSpecificData", Null)

Result:{76=[B@39da68d}

How do i convert the result in a similar map like the advertising data from BLEmanager2 so i can parse it by the BeaconParser?
(MyMap) {1=[B@da87e20, -1=[B@3eba3d9, 10=[B@a17119e, 22=[B@164d47f, 9=[B@9e75c4c, 0=[B@469a495}
 
Last edited:
Upvote 0

Philip Prins

Active Member
Licensed User
Longtime User
Ok

For other people that want to scan for iBeacons in the background with Android 8.1 and up:

First create a scanfilter :
Scanfilter:
Private Sub ScanWithLeScanner
    
    Dim ScanSettingsStatic As JavaObject
    ScanSettingsStatic.InitializeStatic("android.bluetooth.le.ScanSettings")
    Dim ScanSettingsBuilder As JavaObject
    ScanSettingsBuilder.InitializeNewInstance("android.bluetooth.le.ScanSettings.Builder", Null)
    'https://developer.android.com/reference/android/bluetooth/le/ScanSettings.Builder
    ScanSettingsBuilder.RunMethod("setScanMode", Array(ScanSettingsStatic.GetField("MATCH_NUM_ONE_ADVERTISEMENT")))
    '----------------------------------------------------------------------
    
    Dim ScanFilterStatic As JavaObject
    ScanFilterStatic.InitializeStatic("android.bluetooth.le.ScanFilter")
    Dim ScanFilterBuilder As JavaObject
    ScanFilterBuilder.InitializeNewInstance("android.bluetooth.le.ScanFilter.Builder", Null)
    ScanFilterBuilder.RunMethod("setManufacturerData", Array(76,Null)) 'Apple ID
    Dim Filters As List = Array(ScanFilterBuilder.RunMethod("build", Null))
    '---------------------------------------------------------------------------
    Scanner.RunMethod("startScan", Array(Filters, ScanSettingsBuilder.RunMethod("build", Null), ScanCallback))
    Scanactive = True
    
End Sub

Then handle the result:
Scan result:
Private Sub Scan_Result (Result As Object)
    'Log("Scan_Result")
    Dim ScanResult As JavaObject = Result
    Dim device As JavaObject = ScanResult.RunMethod("getDevice", Null)
    Dim address As String = device.RunMethod("getAddress", Null)
    ManagerJO.GetFieldJO("devices").RunMethod("put", Array(address, device))
    Dim name As String
    Dim o As Object = device.RunMethod("getName", Null)
    If o = Null Then name = "" Else name = o
    Dim ScanRecord As JavaObject = ScanResult.RunMethod("getScanRecord", Null)
    Log(ScanRecord) 'you can extend the code to access the data.
    Dim data() As Byte = ScanRecord.RunMethod("getManufacturerSpecificData", Array(76)) '76 = apple id
 
    If data <> Null Then
        
        Private bc As ByteConverter
        
        
        Dim tx As Byte
        
        Dim raf As RandomAccessFile
        Dim ib As iBeacon
        raf.Initialize3(data, False)
        Dim hex As String = bc.HexFromBytes(data)
        Log(hex)
        ib.uuid = hex.SubString2(4, 36) 'bytes 4 - 19
'        beacon1.uniqueid = hex.SubString2(4, 46) 'this also includes the major and minor parts
        ib.major = raf.ReadShort(18)
        ib.minor = raf.ReadShort(20)
        tx = raf.ReadSignedByte(22)
        
        
        Log(ib.Uuid)
        Log(ib.Major)
        Log(ib.Minor)
    
    End If
    Dim rssi As Double = ScanResult.RunMethod("getRssi", Null)
    Manager_DeviceFound(name, address, ib, rssi)
    
End Sub
 
Last edited:
Upvote 0
Top