Android Question BeaconParser Service.StartForeground

Lisa I

Member
Licensed User
Hi, I've been using your example BeaconParser app https://www.b4x.com/android/forum/t...iscover-ibeacons-and-eddystone-beacons.61127/
I want to receive beacon data continuously from when a start button is pressed until a stop button is pressed even if the phone display turns off.
It works well when the phone display is on, stops receiving when the display turns off, then restarts when the phone wakes up.

I read I needed to create a new service module which I have done but I'm not sure what to do now. Can you give me some idea please.
Thank you

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

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Private nid As Int = 1
    Private lock As PhoneWakeState
End Sub

Sub Service_Create
    lock.PartialLock
End Sub

Sub Service_Start (StartingIntent As Intent)
    Service.StartForeground(nid, CreateNotification("..."))
End Sub


Sub CreateNotification (Body As String) As Notification
    Dim notification As Notification
    notification.Initialize2(notification.IMPORTANCE_LOW)
    notification.Icon = "icon"
    notification.SetInfo("Scanning", Body, Main)
    Return notification
End Sub

Sub Service_Destroy
    lock.ReleasePartialLock
End Sub
 

Lisa I

Member
Licensed User
Hi Erel

Here is the Starter code, it's identical to your Beacon Parser example but for some changes in Sub Manager_DeviceFound

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

Sub Process_Globals
    Public manager As BleManager2
    Public Parser As BeaconParser   
    Public currentStateText As String = "UNKNOWN"
    Public currentState As Int
    Public scanning As Boolean
    Public Provider As FileProvider
    Public beacons As Map
    Public const TIME_TO_LIVE_SECONDS As Int = 5
    Private Timer1 As Timer
    Public rp As RuntimePermissions
    Public rssisample As Double
    Public RSSIData(10000) As Double
    Public RSSITime(10000) As Long
    Private i As Int =0
End Sub

Sub Service_Create
    manager.Initialize("manager")
    beacons.Initialize
    Timer1.Initialize("timer1", TIME_TO_LIVE_SECONDS * DateTime.TicksPerSecond)
    Timer1.Enabled = True
    Parser.Initialize
    Provider.Initialize   
End Sub

Sub Service_Start (StartingIntent As Intent)
    
End Sub


Public Sub Scan
    manager.Scan2(Null, True)
    scanning = True
End Sub


Public Sub StopScan
    manager.StopScan
    scanning = False
End Sub

Private Sub Timer1_Tick
    CallSub(Main, "StateChanged")
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)
    
    Dim beacon As Beacon = Parser.Parse(AdvertisingData, RSSI)
    If beacon <> Null Then
        'beacons.Put(beacon.uniqueid, beacon)
        'CallSub(Main, "StateChanged")
        
        Select beacon.BeaconType
            Case Parser.TypeiBeacon
                Dim ib As iBeacon = beacon.SpecificData
                Log($"iBeacon: ${ib.uuid} (${ib.major}/${ib.minor})"$)
            Case Parser.TypeEddystoneUID
                Dim euid As EddystoneUID = beacon.SpecificData
                Log($"Eddystone UID: ${euid.Namespace}:${euid.Instance}"$)
                Log ("RSSI" & RSSI)
                rssisample = RSSI
                recordData
            Case Parser.TypeEddystoneURL
                Dim eurl As EddystoneURL = beacon.SpecificData
                Log($"Eddystone URL: ${eurl.url}"$)
        End Select
    End If
End Sub

Public Sub recordData
    RSSIData(i) = rssisample
    RSSITime(i) = DateTime.Now
    i = i +1
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

and here's the main, thank you
Main:
#Region  Project Attributes
    #ApplicationLabel: B4A Example
    #VersionCode: 1
    #VersionName: 
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes 
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
      'should be private
End Sub

Sub Globals
    Private btnDisconnect As Button
    Private btnScan As Button
    Private lblState As Label
    Private pbScan As ProgressBar
    Private clv As CustomListView
    Private uiitemas As Map
    Private xui As XUI
    
    Private Print As Button
    Private EmailBtn As Button
End Sub 

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
    uiitemas.Initialize
    'i = 0
End Sub

Sub Activity_Resume
    StateChanged
End Sub

Public Sub StateChanged
    lblState.Text = Starter.currentStateText
    btnDisconnect.Enabled = Starter.scanning
    pbScan.Visible = Starter.scanning
    btnScan.Enabled = (Starter.currentState = Starter.manager.STATE_POWERED_ON) And Starter.scanning = False
    Dim beaconsToRemove As List
    For Each beacon As Beacon In Starter.beacons.Values
        If uiitemas.ContainsKey(beacon.uniqueid) = False Then
            Dim p As Panel = CreateItem(beacon)
            clv.Add(p, "")
            uiitemas.Put(beacon.uniqueid, p)
        Else
            If beacon.time + Starter.TIME_TO_LIVE_SECONDS * DateTime.TicksPerSecond < DateTime.Now Then
                'remove old beacon. We need to do it after the For Each loop.
                If beaconsToRemove.IsInitialized = False Then beaconsToRemove.Initialize
                beaconsToRemove.Add(beacon)
            Else
                Dim p As Panel = uiitemas.Get(beacon.uniqueid)
                SetDistance(p.GetView(1), beacon)
            End If
        End If
    Next
    If beaconsToRemove.IsInitialized Then
        For Each beacon As Beacon In beaconsToRemove
            Dim p As Panel = uiitemas.Get(beacon.uniqueid)
            clv.RemoveAt(clv.GetItemFromView(p))
            uiitemas.Remove(beacon.uniqueid)
            Starter.beacons.Remove(beacon.uniqueid)
        Next
    End If
End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub btnScan_Click
    Starter.rp.CheckAndRequest(Starter.rp.PERMISSION_ACCESS_COARSE_LOCATION)
    Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
    If Result Then
        pbScan.Visible = True
        CallSub(Starter, "Scan")
        StateChanged
    Else
        ToastMessageShow("No permission...", True)
    End If
End Sub


Sub btnDisconnect_Click
    CallSub(Starter, "StopScan")
    StateChanged
End Sub


Sub CreateItem(beacon As Beacon) As Panel
    Dim pnl As B4XView = xui.CreatePanel("")
    pnl.SetLayoutAnimated(0, 0, 0, clv.AsView.Width, 50dip)
    pnl.LoadLayout("Item")
    Dim FirstLine As String
    Select beacon.BeaconType
        Case Starter.Parser.TypeiBeacon
            Dim ib As iBeacon = beacon.SpecificData
            FirstLine = $"iBeacon: ${ib.uuid} (${ib.major}/${ib.minor})"$
        Case Starter.Parser.TypeEddystoneUID
            Dim euid As EddystoneUID = beacon.SpecificData
            FirstLine = $"Eddystone UID: ${euid.Namespace}:${euid.Instance}"$
        Case Starter.Parser.TypeEddystoneURL
            Dim eurl As EddystoneURL = beacon.SpecificData
            FirstLine = $"Eddystone URL: ${eurl.url}"$
    End Select
    pnl.GetView(0).Text = FirstLine
    SetDistance(pnl.GetView(1), beacon)
    Return pnl
End Sub

Private Sub SetDistance(lbl As Label, beacon As Beacon)
    lbl.Text = $"Distance: $1.1{beacon.distance} meters"$
End Sub


Private Sub Print_Click
    Dim List1 As List
    List1.Initialize
    
    For i = 0 To 9999
        List1.Add((Starter.RSSIData(i) & "," &Starter.RSSITime(i)))
    Next
    
    
    If File.Exists(File.DirInternal, "RSSIdata.txt") Then
        File.Delete(File.DirInternal, "RSSIdata.txt")
    End If
    File.WriteList(File.DirInternal, "RSSIdata.txt", List1)
    

End Sub
 
Upvote 0
Top