Android Question BLE scanSettings?

JordiCP

Expert
Licensed User
Longtime User
I have a "conflictive" BLE device with a quite-limited pairing time-window, as the user must perform some actions on it at the same time for security reasons.

Using BLEManager2, pairing usually works but only after a number of retries (different delays depending on the Android device), and this turns the process into something hard for the final user.

--> Is there any way by means of JavaObject to access the native BluetoothLEScanner in order to pass custom scanSettings built with scanSettings.Builder?

Thanks in advance :)
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Modified starter service that shows how to use BluetoothLeScanner:

B4X:
#Region  Service Attributes
   #StartAtBoot: False
   #ExcludeFromLibrary: True
#End Region

Sub Process_Globals
   Public manager As BleManager2
   Public currentStateText As String = "UNKNOWN"
   Public currentState As Int
   Public connected As Boolean = False
   Public ConnectedName As String
   Private ConnectedServices As List
   Public rp As RuntimePermissions
   Private ManagerJO As JavaObject
   Private Adapter As JavaObject
   Private Scanner As JavaObject
   Private ScanCallback As JavaObject
End Sub

Sub Service_Create
   manager.Initialize("manager")
   ManagerJO = manager
   Adapter = ManagerJO.GetField("blueAdapter")
   Scanner = Adapter.RunMethod("getBluetoothLeScanner", Null)
   ScanCallback.InitializeNewInstance(Application.PackageName & ".starter$MyScanCallback", Null)
   
End Sub

Sub Service_Start (StartingIntent As Intent)

End Sub

Public Sub ReadData
   For Each s As String In ConnectedServices
       manager.ReadData(s)
   Next
End Sub

Public Sub Disconnect
   manager.Disconnect
   Manager_Disconnected
End Sub

Sub Manager_StateChanged (State As Int)
   Select State
       Case manager.STATE_POWERED_OFF
           currentStateText = "POWERED OFF"
       Case manager.STATE_POWERED_ON
           currentStateText = "POWERED ON"
       Case manager.STATE_UNSUPPORTED
           currentStateText = "UNSUPPORTED"
   End Select
   currentState = State
   CallSub(Main, "StateChanged")
End Sub

Sub Manager_DeviceFound (Name As String, Id As String, AdvertisingData As Map, RSSI As Double)
   Log("Found: " & Name & ", " & Id & ", RSSI = " & RSSI & ", " & AdvertisingData)
   ConnectedName = Name
   StopScanWithLeScanner
   manager.Connect2(Id, False) 'disabling auto connect can make the connection quicker
End Sub

Public Sub StartScan
   If manager.State <> manager.STATE_POWERED_ON Then
       Log("Not powered on.")
   Else If rp.Check(rp.PERMISSION_ACCESS_COARSE_LOCATION) = False Then
       Log("No location permission.")
   Else
       ScanWithLeScanner
   End If
End Sub


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)
   Manager_DeviceFound(name, address, CreateMap(), rssi)
End Sub

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")))
   
   Scanner.RunMethod("startScan", Array(Null, ScanSettingsBuilder.RunMethod("build", Null), ScanCallback))
End Sub

Private Sub StopScanWithLeScanner
   Scanner.RunMethod("stopScan", Array(ScanCallback))
End Sub

Sub Manager_DataAvailable (ServiceId As String, Characteristics As Map)
   CallSub3(Main, "DataAvailable", ServiceId, Characteristics)
End Sub

Sub Manager_Disconnected
   Log("Disconnected")
   connected = False
   CallSub(Main, "StateChanged")
End Sub

Sub Manager_Connected (services As List)
   Log("Connected")
   connected = True
   ConnectedServices = services
   CallSub(Main, "StateChanged")
End Sub

'Return true to allow the OS default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
   Return True
End Sub

Sub Service_Destroy

End Sub

#if Java
import android.bluetooth.le.*;
public static class MyScanCallback extends ScanCallback {
 public void onScanResult(int callbackType, ScanResult result) {
         processBA.raiseEvent(this, "scan_result", result);
    }

   

    /**
     * Callback when scan could not be started.
     *
     * @param errorCode Error code (one of SCAN_FAILED_*) for scan failure.
     */
    public void onScanFailed(int errorCode) {
       BA.Log("Error: " + errorCode);
    }
}
#End If

Based on the BLE example.
 
Upvote 0
Top