Android Question NB6 Notification Activity displayed behind the Main Activity

Anser

Well-Known Member
Licensed User
Longtime User
Hi,

My requirement:-

Whenever a Notification is received and clicked, the desired Activity should be displayed on the users App, and when the user press the back button, he should reach the HomePage.

I am able to get the above said requirement done via the solution provided in this thread by our friend DonManfred https://www.b4x.com/android/forum/threads/nb6-how-to-pass-multiple-information-using-tag.94639/

ie All notification will call HomePage and from HomePage Activity_Resume, based on the Notification type the required Activity is called.

Everything working fine except for one single Notification type. Here in this case the desired activity is not displayed instead it goes behind the HomePage ie the user sees the Activity ONLY when he closes the HomePage and leave the application.

The ONLY difference in this notification is that, I am calling an activity that contains a WebView. I send a URL via Message.Data and then this Activity displays that Webpage on the WebView. Now, this activity and webpage is displayed, but it goes behind the HomePage

I am puzzled why it is behaving so. Is there anything special to deal with when we call an activity that contains a Webview that loads an external webpage ?

Any hint in the right direction will be appreciated
 

DonManfred

Expert
Licensed User
Longtime User
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
When the user clicks on the Notification, it is supposed to show NotificationWebView_Activity and when he closes NotificationWebView_Activity, HomePage_Activity should be displayed. Unfortunately, here the HomePage_Activity is displayed and remains there. I am able to see the NotificationWebView_Activity only when I close the HomePage_Activity

Sub Activity_Resume of HomePage Activity
B4X:
Sub Activity_Resume
 
    Dim in As Intent = Activity.GetStartingIntent
 
    If in.IsInitialized And in <> OldIntent Then
        OldIntent = in
        Dim intentExtra As String
        If in.HasExtra("Notification_Tag") Then
            intentExtra = in.GetExtra("Notification_Tag")

            Dim jp As JSONParser
            jp.Initialize(intentExtra)
       
            Dim mapParameters As Map = jp.NextObject
            Dim cNotificationType As String = mapParameters.Get("NotificationType")
       
            If cNotificationType = "Notification1" Then
        
            Else If cNotificationType = "Notification2" Then
                CallSubDelayed2(MyActivity2,"StartWithParameter",mapParameters.Get("MyID2") )
            Else If cNotificationType = "SchmDetails" Then
                CallSubDelayed2(MyActivity3,"StartWithParameter",mapParameters.Get("MyID3") )
            Else If cNotificationType = "NotificationWebView" Then
                Log("cUrl : " & mapParameters.Get("cUrl"))
                Log("cTitle : " & mapParameters.Get("cTitle"))
'Here is the problamatic Activity containing a WebView
                CallSubDelayed3(NotificationWebView,"StartWithParameter",mapParameters.Get("cUrl"), mapParameters.Get("cTitle") )
            End If
        End If
    End If
 
End Sub

In the NotificationWebView Activity
B4X:
Sub StartWithParameter(cUrl As String,cTitle As String)
   
    cUrlFromNotification = cUrl
    'Set Title and Subtitle for the ToolBar
    ActionBar.Title = cTitle  
    WebView1.LoadUrl(cUrl)
    ProgressDialogShow2("Loading...",False)
End Sub
 
Last edited:
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Instead of using CallsubDelayed...

I think i would directly point the notification to the right activity.

I mean. based on the data in the fb notification i would decive which activity should handle the notification i build with the Builder.

To be honest: i would send all needed Infos directly with the FB Notification.

In firebase messaging i would then check the given values and based on them i create different notifications resp. notification-receiver (when user click on the notif).

B4X:
    Dim mapParameters As Map    : mapParameters.Initialize
    If Message.GetData.ContainsKey("promo") Then
        mapParameters.Put("promourl",Message.GetData.Get("promo"))
        mapParameters.Put("Title", Message.GetData.Get("title"))
        mapParameters.Put("Body", Message.GetData.Get("body"))
    End If
    If Message.GetData.ContainsKey("OfferID") Then
        mapParameters.Put("OfferID", Message.GetData.Get("OfferID"))
    End If

and later (still firebase messaging )

B4X:
    If mapParameters.ContainsKey("OfferID") Then
' Send offers to Main
        n.Build(Message.GetData.Get("title"), Message.GetData.Get("body"), jgen.ToString, Main).Notify(4)
    Else If mapParameters.ContainsKey("promourl") Then
' Send PromoURL to webview-activity
        n.Build(Message.GetData.Get("title"), Message.GetData.Get("body"), jgen.ToString, Promo).Notify(4)
    Else
' Everything else to Main
        n.Build(Message.GetData.Get("title"), Message.GetData.Get("body"), jgen.ToString, Main).Notify(4)
    End If
 
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
Yes. I was following this method until I was using NotificationBuilder library from BarX

May be my requirement is very specific.
  • When the Notification is arrived on my users device, I would like my user to be taken to a particular activity that is related with the type of Notification that he received
  • After viewing the contents on that activity when he leaves the Activity by pressing the back key, I want my user to be taken to the Homepage. This was achieved in NotificationBuilder library by using a simple statement while building the notification as given below
    B4X:
    nb.setActivity(TipsDisplay)  'Activity to be loaded when the user clicks on the notification
    nb.setParentActivity(HomePage) 'Activity to be loaded when the user closes the above activity
When I moved to the new NB6, this feature is not available, so to imitate the same, I was advised to load HomePage from firebase messaging service irrespective of the message received and after reaching the HomePage, decide and load the required Activity. So that when the user closes the activity, he will naturally come back to the HomePage. That's the reason that I took this route. Of course, I had to change the work flow of my Notification handling to get this done. Except the issue with this particular Notification, rest of the Notifications are working fine as I described in the above bullet points.
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
When the Notification is arrived on my users device, I would like my user to be taken to a particular activity that is related with the type of Notification that he received
Possible with the above. I just tried it in my Testproject. (***)
After viewing the contents on that activity when he leaves the Activity by pressing the back key, I want my user to be taken to the Homepage.
In my testapp i am using this in the webview activity
B4X:
Sub Activity_KeyPress(KeyCode As Int) As Boolean'Return True to consume the event
    If KeyCode = KeyCodes.KEYCODE_BACK Then
        ' Handle KeyCodes
        Activity.Finish
        CallSubDelayed(Main,"Init")
        Return True
        'StartActivity(Main)
    End If
    Return False
End Sub

It is working as expected for me.


(***): I am using FirebaseAdmin on my VPS to send the Notifications together with aditional infos. Not just Title and Body.
As seen in the other thread i am using specific Small and Big Icons for the Notifications.

In this case here i just added the promourl which will arrive in the Firebasemessagin new message event.

B4X:
Sub fm_MessageArrived (Message As RemoteMessage)
    Log("Message arrived")
    Log($"Message data: ID ${Message.MessageId}, Data ${Message.GetData}"$)
    Dim mapParameters As Map    : mapParameters.Initialize
    If Message.GetData.ContainsKey("promo") Then
        mapParameters.Put("promourl",Message.GetData.Get("promo"))
        mapParameters.Put("Title", Message.GetData.Get("title"))
        mapParameters.Put("Body", Message.GetData.Get("body"))
    End If
    If Message.GetData.ContainsKey("OfferID") Then
        mapParameters.Put("OfferID", Message.GetData.Get("OfferID"))
    End If
   
    Dim jgen As JSONGenerator
    jgen.Initialize(mapParameters)

    Dim n As NB6
    n.Initialize("default", Application.LabelName, "DEFAULT").AutoCancel(True)

    If Message.GetData.ContainsKey("imgbig") Then
        Dim j As HttpJob
        j.Initialize("", Me)
        j.Download(Message.GetData.Get("imgbig"))
        Wait For (j) JobDone(j As HttpJob)
        If j.Success Then
            Dim img_big As Bitmap
            img_big = j.GetBitmap
            n.LargeIcon(img_big)
        End If
        j.Release
    End If
    If Message.GetData.ContainsKey("imgsmall") Then
        Dim j As HttpJob
        j.Initialize("", Me)
        j.Download(Message.GetData.Get("imgsmall"))
        Wait For (j) JobDone(j As HttpJob)
        If j.Success Then
            Dim img_small As Bitmap
            img_small = j.GetBitmap
            n.SmallIcon(img_small)
        End If
        j.Release
    Else
        Dim smallbmp As Bitmap
        smallbmp.Initialize(File.DirAssets,"firebase24.png")
        n.SmallIcon(smallbmp)
    End If
    If mapParameters.ContainsKey("OfferID") Then
        n.Build(Message.GetData.Get("title"), Message.GetData.Get("body"), jgen.ToString, Main).Notify(4)
    Else If mapParameters.ContainsKey("promourl") Then
        n.Build(Message.GetData.Get("title"), Message.GetData.Get("body"), jgen.ToString, promo).Notify(4) ' The promo url is opened on another activity.
    Else
        n.Build(Message.GetData.Get("title"), Message.GetData.Get("body"), jgen.ToString, Main).Notify(4)
    End If

End Sub

The code from the webview activity (promo) is basically

B4X:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Private oldintent As Intent
    Private www As WebView
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("LayoutPromo")
   

End Sub

Sub Activity_Resume
    Dim in As Intent = Activity.GetStartingIntent
 
    If in.IsInitialized And in <> oldintent Then
        oldintent = in
        Dim intentExtra As String
        If in.HasExtra("Notification_Tag") Then
            intentExtra = in.GetExtra("Notification_Tag")
            Log("PROMO XTRA="&intentExtra)
            'If intentExtra = "Offers" Then 'The tag 'Offer Notification
            '{"OfferID":"123","Title":"What ever Title"}

            Dim jp As JSONParser
            jp.Initialize(intentExtra)
            Dim root As Map = jp.NextObject
            Dim promourl As String = root.Get("promourl")
            Dim Title As String = root.Get("Title")
            Dim Body As String = root.Get("Body")
            www.LoadUrl(promourl)
            'CallSubDelayed2(MyActivityName,"StartWithParameter",root)
            'End If
        End If
    End If

End Sub

Sub Activity_KeyPress(KeyCode As Int) As Boolean'Return True to consume the event
    If KeyCode = KeyCodes.KEYCODE_BACK Then
        ' Handle KeyCodes
        Activity.Finish
        CallSubDelayed(Main,"Init")
        Return True
        'StartActivity(Main)
    End If
    Return False
End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub


Sub www_PageFinished (Url As String)
   
End Sub

Sub www_OverrideUrl (Url As String) As Boolean
   
End Sub

Sub www_UserAndPasswordRequired (Host As String, Realm As String) As String()
   
End Sub
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
Possible with the above. I just tried it in my Testproject. (***)

In my testapp i am using this in the webview activity
B4X:
Sub Activity_KeyPress(KeyCode As Int) As Boolean'Return True to consume the event
    If KeyCode = KeyCodes.KEYCODE_BACK Then
        ' Handle KeyCodes
        Activity.Finish
        CallSubDelayed(Main,"Init")
        Return True
        'StartActivity(Main)
    End If
    Return False
End Sub

It is working as expected for me.


(***): I am using FirebaseAdmin on my VPS to send the Notifications together with aditional infos. Not just Title and Body.
As seen in the other thread i am using specific Small and Big Icons for the Notifications.

In this case here i just added the promourl which will arrive in the Firebasemessagin new message event.

B4X:
Sub fm_MessageArrived (Message As RemoteMessage)
    Log("Message arrived")
    Log($"Message data: ID ${Message.MessageId}, Data ${Message.GetData}"$)
    Dim mapParameters As Map    : mapParameters.Initialize
    If Message.GetData.ContainsKey("promo") Then
        mapParameters.Put("promourl",Message.GetData.Get("promo"))
        mapParameters.Put("Title", Message.GetData.Get("title"))
        mapParameters.Put("Body", Message.GetData.Get("body"))
    End If
    If Message.GetData.ContainsKey("OfferID") Then
        mapParameters.Put("OfferID", Message.GetData.Get("OfferID"))
    End If
  
    Dim jgen As JSONGenerator
    jgen.Initialize(mapParameters)

    Dim n As NB6
    n.Initialize("default", Application.LabelName, "DEFAULT").AutoCancel(True)

    If Message.GetData.ContainsKey("imgbig") Then
        Dim j As HttpJob
        j.Initialize("", Me)
        j.Download(Message.GetData.Get("imgbig"))
        Wait For (j) JobDone(j As HttpJob)
        If j.Success Then
            Dim img_big As Bitmap
            img_big = j.GetBitmap
            n.LargeIcon(img_big)
        End If
        j.Release
    End If
    If Message.GetData.ContainsKey("imgsmall") Then
        Dim j As HttpJob
        j.Initialize("", Me)
        j.Download(Message.GetData.Get("imgsmall"))
        Wait For (j) JobDone(j As HttpJob)
        If j.Success Then
            Dim img_small As Bitmap
            img_small = j.GetBitmap
            n.SmallIcon(img_small)
        End If
        j.Release
    Else
        Dim smallbmp As Bitmap
        smallbmp.Initialize(File.DirAssets,"firebase24.png")
        n.SmallIcon(smallbmp)
    End If
    If mapParameters.ContainsKey("OfferID") Then
        n.Build(Message.GetData.Get("title"), Message.GetData.Get("body"), jgen.ToString, Main).Notify(4)
    Else If mapParameters.ContainsKey("promourl") Then
        n.Build(Message.GetData.Get("title"), Message.GetData.Get("body"), jgen.ToString, promo).Notify(4) ' The promo url is opened on another activity.
    Else
        n.Build(Message.GetData.Get("title"), Message.GetData.Get("body"), jgen.ToString, Main).Notify(4)
    End If

End Sub

The code from the webview activity (promo) is basically

B4X:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Private oldintent As Intent
    Private www As WebView
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("LayoutPromo")
  

End Sub

Sub Activity_Resume
    Dim in As Intent = Activity.GetStartingIntent
 
    If in.IsInitialized And in <> oldintent Then
        oldintent = in
        Dim intentExtra As String
        If in.HasExtra("Notification_Tag") Then
            intentExtra = in.GetExtra("Notification_Tag")
            Log("PROMO XTRA="&intentExtra)
            'If intentExtra = "Offers" Then 'The tag 'Offer Notification
            '{"OfferID":"123","Title":"What ever Title"}

            Dim jp As JSONParser
            jp.Initialize(intentExtra)
            Dim root As Map = jp.NextObject
            Dim promourl As String = root.Get("promourl")
            Dim Title As String = root.Get("Title")
            Dim Body As String = root.Get("Body")
            www.LoadUrl(promourl)
            'CallSubDelayed2(MyActivityName,"StartWithParameter",root)
            'End If
        End If
    End If

End Sub

Sub Activity_KeyPress(KeyCode As Int) As Boolean'Return True to consume the event
    If KeyCode = KeyCodes.KEYCODE_BACK Then
        ' Handle KeyCodes
        Activity.Finish
        CallSubDelayed(Main,"Init")
        Return True
        'StartActivity(Main)
    End If
    Return False
End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub


Sub www_PageFinished (Url As String)
  
End Sub

Sub www_OverrideUrl (Url As String) As Boolean
  
End Sub

Sub www_UserAndPasswordRequired (Host As String, Realm As String) As String()
  
End Sub
Thank you. I too followed this method. When the activity is loaded via notification I set a variable to True. Now when the user press the back key I check this variable's value and then decide whether to call HomePage or not.

Unfortunately, sometimes I was getting weird results, especially when the App is not used for more than 10 to 12 hours and when a Notification arrived and clicked I could see lot of flickering etc. I though that may be I was not following the right way, hence I dropped the idea and reached here.

Now the ONLY difference that I see is that you are calling the Main activity using CallSubDelayed ie whn the user clicks the back key. In my case I was calling StartActivity(HomePage)
 
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
Call to NB6
B4X:
nb.Build(cSubject,cMsg,jgen.ToString,HomePage).Notify(nNotificationCount)
These are the log results starting from the moment the FCM Message reaches the device and then clicked

** Receiver (firebasemessaging) OnReceive **
** Service (firebasemessaging) Start **
*** Service (fcmnotificationsnew) Create ***
** Service (fcmnotificationsnew) Start **
** Activity (homepage) Create, isFirst = false **
** Activity (homepage) Resume **
About to make a Call -> CallSubDelayed(notificationwebview,"StartWithParameter",myParameter)
** Activity (homepage) Pause, UserClosed = false **
** Activity (notificationwebview) Create, isFirst = true **
** Activity (notificationwebview) Resume **
Reached inside the Sub StartWithParameter of Activity named notificationwebview. Now the WebView is invoked with the URL in the Activity notificationwebview, but HomePage is still the active Activity in Forefront
** Activity (homepage) Pause, UserClosed = false **
** Activity (notificationwebview) Pause, UserClosed = false **
** Activity (homepage) Pause, UserClosed = false **
** Activity (homepage) Resume **
** Activity (homepage) Resume **

The notificationwebview activity is paused and homepage activity is resumed. In fact the activity notificationwebview should be the activity in the forefront. Any hint why it is so ? Is there anything specific with WebView in such situation ?
 
Last edited:
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
I think that the problem may be because of the incomplete Jobdone in HomePage, may be that is the reason the Homepage activity is coming to the forefront. But I don't understand that why the Jobdone is causing issue ONLY to this particular Activity. There are other activities that are called from the HomePage in the similar way, I mean via Activity_Resume and NB6
 
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
It is the common Sub JobDone for the jRDC in my HomePage for all the database related operations in the HomePage Activity.
Even if I move all my jRDC calls to a Service module, how do I handle the return calls to the Sub's that are inside the Jobdone sub ?. What I mean is that once the application flow reaches JobDone, it will be calling other Sub's in the HomePage Activity from the JobDone. So this problem will still be there. How do I block that ?

From the Jobdone, how do I check whether the HomePage activity is the Actvity that is in the ForeFront (ie Active activity), or else do not call the subs that are in the HomePage.

Another thing that is coming into my mind is :-

If I make a jRDC query, until the JobDone is completed, all other calls/process should be blocked. In other words the system should wait till the all the JobDone is completed.

May be I am over complicating things. It seems that my brain is not functioning properly at the moment, lack of ideas ;)

May be I will have to rework on the whole application flow OR it will be much better to directly call the required activity from the Notification itself and in the called activity to track whether the current activity was activated via Notification and if yes, call HomePage when the user presses the back key. It seems that will be much simple solution
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Even if I move all my jRDC calls to a Service module
This is what you should do. Preferably in the Starter service.

If I make a jRDC query, until the JobDone is completed, all other calls/process should be blocked. In other words the system should wait till the all the JobDone is completed.
1. There shouldn't be any JobDone sub in your code. Use Wait For instead.

2. Why? jRDC2 can send any number of requests at the same time.

how do I check whether the HomePage activity is the Actvity that is in the ForeFront (ie Active activity), or else do not call the subs that are in the HomePage.
B4X:
CallSub2(HomePage, "SomeSub", Data)
It will not do anything if HomePage is paused. You can also check it with IsPaused.
 
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
B4X:
CallSub2(HomePage, "SomeSub", Data)
It will not do anything if HomePage is paused. You can also check it with IsPaused.
Will that be kept in 'Q' and gets executed when the Activity is resumed.
 
Upvote 0
Top