Android Question [Solved] Home Widget after reboot

udg

Expert
Licensed User
Longtime User
Hi all,
back in October 2023 I opened a similary named thread showing what hopefully could have been a solution to the problem that arises when the home widget is started through a receiver after boot/reboot while Internet access is not yet available.
Unfortunatley that solution didn't work 100% flawlessly so I tried a different approach. It worked very well.. but I forgot to publish it. :eek:

Sorry for the incovenience caused to those who used that approach. Anyway, here it is how I solved the problem (read the old thread if interested in the details of the problem and some possible solutions discussed with other forum's members).

For my convenience I use two ancillary classes: specialperm and clsCommons.
SpecialPerm is used to get the special permission Draw on other app (android.settings.action.MANAGE_OVERLAY_PERMISSION"). It's the code you find in the Forum
clCommons is where I store constants, structures and public variables used in other modules. The most important one (relative to the problem at hand) is the boolean InternetOk (when true it means we finally have access to the Internet).

Ok, ok. Here's the stripped down code.

Receiver dgmd (I have a second receiver where I call a different API service; anyway it's almost identical)
B4X:
Sub Process_Globals
    Private rv As RemoteViews
    Private LastUpdate As Long
    Private commons As clCommons
End Sub

'Called when an intent is received.
'Do not assume that anything else, including the starter service, has run before this method.
Private Sub Receiver_Receive (FirstTime As Boolean, StartingIntent As Intent)
    LogColor("dgmday: receiver_receive: "&FirstTime, 0xFFFF0000)
    Log("Intent: "&StartingIntent)
    Log("Action: "&StartingIntent.Action)
    Log("Extra: "&StartingIntent.ExtrasToString)
   
    If FirstTime Then
        rv = ConfigureHomeWidget("lytWidgetD", "rv", 30, "DG Meteo Day",True)  'run the home widget every 30 minutes
        commons.Initialize
        StartHttpUtils2Service
    End If
    rv.HandleWidgetEvents(StartingIntent)
   
    If StartingIntent.HasExtra("android.intent.extra.ALARM_TARGET_TIME") Then
        '(Intent) Intent { flg=0x14 cmp=eu.dgc.dgmeteo/.dgmd (has extras) }
        'Bundle[{android.intent.extra.ALARM_TARGET_TIME=1733507003773, android.intent.extra.ALARM_COUNT=1}]
        LogColor("dgmday:  called by StartReceiverAt", 0xFF0000FF)
        rv_RequestUpdate
    End If
End Sub

' It needs the conditional symbol H2U_PUBLIC  in Project-Build configuration
Private Sub StartHttpUtils2Service
    #if release
    Log("dgDay: forces WLAN activation")
    If HttpUtils2Service.TempFolder = "" Then
        Dim jo As JavaObject
        jo.InitializeNewInstance(Application.PackageName & ".httputils2service", Null)
        jo.RunMethod("onReceive", Array(Null, Null))
    End If
    If HttpUtils2Service.TempFolder <> "" Then Log ("okhttp good to go")
    #end if
End Sub

'Classic test for Internet availability.
Public Sub TestInternet As ResumableSub
    Dim j As HttpJob
    j.Initialize("", Me) 'name is empty as it is no longer needed
    j.Download("http://www.google.com/")
    j.GetRequest.Timeout = 10000
    Wait For (j) JobDone(j As HttpJob)
    commons.InternetOK = j.Success
    j.Release
    Return commons.InternetOK
End Sub

'Handles the widget items update or schedules the receiver to run again in 1 minute (if Internet is not available)
Private Sub rv_RequestUpdate
    LogColor("dgmDay: rv.RequestUpdate", 0xFFFF00FF)
   
    If Not(commons.InternetOK) Then
        Dim res1 As Boolean = False
        Log("no internet")
        'eventually inform the user that Internet is not available at this time
        'rv.SetText("lblTown", "Server unavailable")     'lblTown is a label I have on my home widget UI interface
        'rv.UpdateWidget
        Log(" Start Internet availability test")
        wait for (TestInternet) Complete(res1 As Boolean)
        Log(res1)
        commons.InternetOK = res1
    End If
  
    If Not(commons.InternetOK) Then        'Internet access is still not available. We try again in 1 minute
        Log("receiver start scheduled")
        StartReceiverAt(Me, DateTime.Now + (1 * DateTime.TicksPerMinute), False)  'run this receiver again in 1 minute
    Else                                                        'Internet available. We can call the API service for updated data
        Log("dgmDay: data update request")
        LastUpdate = DateTime.Now
        'here we call what we need in order to receive updated data from the API
        wait for (ReadCurrentData) Complete(res11 As Boolean)
        'if success, update data visible to the user
            '......
            'rv.UpdateWidget
       Log("dgmDay: data update done")
    End If
End Sub

Just for completeness, the Manifest
B4X:
This code will be applied to the manifest file during compilation.
'You do not need to modify it in most cases.
'See this link for for more information: https://www.b4x.com/forum/showthread.php?p=78136
AddManifestText(
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34"/>
<supports-screens android:largeScreens="true"
    android:normalScreens="true"
    android:smallScreens="true"
    android:anyDensity="true"/>)
SetApplicationAttribute(android:icon, "@drawable/icon")
SetApplicationAttribute(android:label, "$LABEL$")
CreateResourceFromFile(Macro, Themes.LightTheme)
'End of default text.

needed since API access is done using http instead of https
CreateResourceFromFile(Macro, Core.NetworkClearText)

'Draw on other app
AddPermission(android.permission.SYSTEM_ALERT_WINDOW)

That's all folks!
 

Sagenut

Expert
Licensed User
Longtime User
But in the manifest there is no declaration of what Receiver should be raised by which event (I hope it's clear what I wrote 🤪 ).
For example
B4X:
AddPermission(android.permission.RECEIVE_BOOT_COMPLETED)
AddReceiverText(MyReceiver, <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>)
 
Upvote 0

udg

Expert
Licensed User
Longtime User
It's almost an year that I wrote that code, so a few details are vanished from my mind.. :)

Anyway, from what I recall, the OS launches the Home Widget in its boot/reboot sequence.
On widget launch, the receiver_reveive sub is called with FirstTime set to True. This accounts for the standard "call me again in 30 minutes" so I can update. But, if I recall it correctly, it tries the rv_RequestUpdate too. This last action causes the widget to start itself again if Internet is not available.

So a separate service to manage the BOOT signal is not needed anymore.
 
Upvote 0
Top