B4A Library NotificationListener library (NotificationListenerService)

Status
Not open for further replies.
The NotificationListener library allows you to access the device notifications.

With this library you can listen to new notifications and removed notifications.

You can also clear existing notifications.

There are some steps that you need to follow in order to use this feature:
- Make sure that the IDE references android.jar from API level 18+.
- Download the attached library and copy it to the libraries folder.
- Add a Service module named NotificationService (must be this exact name).
- Add the following code to the manifest editor:
B4X:
AddApplicationText(
<service android:name="anywheresoftware.b4a.objects.NotificationListenerWrapper"
   android:label="Notification Listener"
   android:exported="false"
  android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
  <intent-filter>
  <action android:name="android.service.notification.NotificationListenerService" />
  </intent-filter>
</service>)
You can change the value of android:label.

- The user must enable your app before it can listen to notifications. This is done by sending the following intent:
B4X:
Sub btnEnableNotifications_Click
   Dim In As Intent
   In.Initialize("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS", "")
   StartActivity(In)
End Sub

The user will see the following screen:

SS-2013-12-12_13.06.15.png


In the service you should create a NotificationListener object and let it handle the StartingIntent:
B4X:
Sub Process_Globals
   Private listener As NotificationListener
End Sub
Sub Service_Create
   listener.Initialize("listener")
End Sub

Sub Service_Start (StartingIntent As Intent)
   If listener.HandleIntent(StartingIntent) Then Return
End Sub
The following events will be raised: NotificationPosted and NotificationRemoved.

See the attached example. It extracts data out of the notifications and print it to the logs:
SS-2013-12-12_13.08.18.png



Tips

- The notifications will also be handled when your app is not running. The service will first be created.
- There is no way to check whether the app is enabled or not.
- If your service is configured incorrectly when you enable the app then nothing will work and there will be no error message. Even after you reinstall the app. In that case you should either change the app package name or restart the device.
- You can also reach the settings screen by going to Settings > Security > Notification Access.

Updates:

- Example updated with targetSdkVersion=34 - android:exported="false" added to the service declaration and the permission to post notifications is requested.
 

Attachments

  • NotificationListener.zip
    6.4 KB · Views: 2,764
  • NotificationListenerExample.zip
    9.1 KB · Views: 213
Last edited:

bitstra

Member
Licensed User
Longtime User
Hi Erel,

could you extend the NotificationListener library with the code below? It enables determining, if the notification access ist set in security settings.
So we can test if the acces is enabled and programaticaly open the 'acces activity' sor setting the permission by user...

It would be great, if you could publish an updatet version of your library:)

I've tested it in your java source code for the library - and it works like a charm:

the additional java code:

B4X:
        /**
      * additional imports to the java package
      */

import android.content.Context;
import android.content.ContentResolver;
import android.provider.Settings;

        /**
        * determine if notification Access is enabled.
        */
        public static int notificationAccessEnabled() {
 
            ContentResolver contentResolver = BA.applicationContext.getContentResolver();
            int srvAccessIsEnabled=0;
            String ensv = Settings.Secure.getString(contentResolver, "enabled_notification_listeners");
            String myPackageName = BA.applicationContext.getPackageName();
       
            if (ensv == null || !ensv.contains(myPackageName))
            {
                // in this situation we know that the user has not granted the app the Notification access permission
                //throw new Exception();
                srvAccessIsEnabled=0;
         
            } else {
                srvAccessIsEnabled=1;
            }
     
        
            return srvAccessIsEnabled;
        }


the sample basic sub:
B4X:
Sub isNotifyAccesEnabled()

If (listener.notificationAccessEnabled=0) Then

NotifyAccessEnabled=False

'do hat you wat here...

'i.e. open the security settings activity for user permission:

'Dim InNoti As Intent

'InNoti.Initialize("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS", "")

'StartActivity(InNoti)

Else

NotifyAccessEnabled=True

'do what you want here..

EndIf




Return


End Sub
BTW: It seems your published source code for your lib is a bit older than the published lib, because I couldn't find the 'void getAllNotifications' in the code... :(

kind regards

bitstra
 
Last edited:

bitstra

Member
Licensed User
Longtime User
@Erel,

is it possible, to determine if a notification isOngoing with your lib?

Or, if not - could you add this to your lib?

B4X:
        /**
        * Returns if the notification isOngoing (Boolean).
        */
        public boolean isOngoing() {
            return getObject().isOngoing();

Or could you post the source code for your latest lib?

thank you and regards

bitstra
 

NeoTechni

Well-Known Member
Licensed User
Longtime User
You can use Phone.GetSettings to implement the above logic:
B4X:
  Dim p As Phone
   p.GetSettings("enabled_notification_listeners")

I tried this, it only returns a number. How do I check if a specific app is registered as a listener?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
is it possible, to determine if a notification isOngoing with your lib?
You can easily implement this code with JavaObject:
B4X:
Dim jo As JavaObject = sbn
Log(jo.RunMethod("isOngoing", null))

I tried this, it only returns a number. How do I check if a specific app is registered as a listener?
Have you enabled your app? I haven't tested this code. I just helped bitstra to convert the Java code he posted.
 

bitstra

Member
Licensed User
Longtime User
You can easily implement this code with JavaObject:
B4X:
Dim jo As JavaObject = sbn
Log(jo.RunMethod("isOngoing", null)) . . .

I've tried this already before - but seems, it returns 'false' also for truly onGoing-Notifications (Android L preview)???

Edit: Oh - I had a typo in my Code before - It works!!!

Thank you Erel
 
Last edited:

pesquera

Active Member
Licensed User
Longtime User
Hi, I have a problem getting the text
When I receive the first notification all is Ok.. I can get both the title an the text
But, on the second notification I can just get the title.. the text is null
What am I doing wrong?

B4X:
Sub Listener_NotificationPosted (SBN As StatusBarNotification)
    Dim p As Phone
    If p.SdkVersion >= 19 Then
        Dim jno As JavaObject = SBN.Notification
        Dim extras As JavaObject = jno.GetField("extras")
        extras.RunMethod("size", Null)
            Dim title As String = extras.RunMethod("getString", Array As Object("android.title"))
            LogColor("Title = " & title, Colors.Blue)
            Dim text As String = extras.RunMethod("getString", Array As Object("android.text"))
            LogColor("text = " & text, Colors.Blue)
End Sub

extras contents:

first notification:
(Bundle) Bundle[{android.title=John, android.subText=null, android.showChronometer=false, android.support.isGroupSummary=true, android.icon=2130838978, android.text=all right?, android.progress=0, android.progressMax=0, android.showWhen=true, android.infoText=null, android.wearable.EXTENSIONS=Bundle[mParcelledData.dataSize=5616], android.progressIndeterminate=false, android.scoreModified=false, android.summaryText=1 mensaje nuevo, android.support.groupKey=group_key_messages}]

second notification: (text=null)
(Bundle) Bundle[{android.title=John, android.textLines=[Ljava.lang.CharSequence;@424f2428, android.subText=null, android.showChronometer=false, android.support.isGroupSummary=true, android.icon=2130838978, android.text=null, android.progress=0, android.progressMax=0, android.support.localOnly=true, android.showWhen=true, android.infoText=null, android.progressIndeterminate=false, android.scoreModified=false, android.summaryText=2 mensajes nuevos, android.support.groupKey=group_key_messages}]
 
Last edited:

pesquera

Active Member
Licensed User
Longtime User
yes, it is! :)
thanks so much
now, can I convert line Object to a string? this hangs my app
B4X:
Dim Text1 As String=""
Dim lines() As Object = extras.RunMethod("getCharSequenceArray", Array("android.textLines"))
For Each line As Object In lines
  Log(line)
   Text1 = line
  Log(Text1)
Next
This line is the problem: Text1 = line
I don´t know how I should assign the line (object) to the Text1 (string)
 
Last edited:

pesquera

Active Member
Licensed User
Longtime User
sorry Erel, you are right.. debugging now I can see what I was doing wrong.. the code on #28 works Ok.. thanks for your help, you are a genius!!
 

pesquera

Active Member
Licensed User
Longtime User
I want to share this code to read the Whatsapp's income messages, it works perfect! (thanks Erel)


B4X:
Sub Listener_NotificationPosted (SBN As StatusBarNotification)
    Dim p As Phone
    If p.SdkVersion >= 19 Then
        Dim jno As JavaObject = SBN.Notification
        Dim extras As JavaObject = jno.GetField("extras")
        extras.RunMethod("size", Null)
       If SBN.PackageName.Contains("whatsapp") Then
            Dim title As String = extras.RunMethod("getString", Array As Object("android.title"))
            LogColor("Name = " & title, Colors.Blue)
            Dim cu As Contacts
            For Each c As Contact In cu.FindByName(title,True)
                Dim loc_Phones As Map
                loc_Phones.Initialize
                loc_Phones = c.GetPhones
                Dim loc_NumberFrom As String = ""
                Dim x As Int=0
                For x=0 To loc_Phones.Size-1
                   If loc_Phones.GetValueAt(x) = c.PHONE_MOBILE Then
                       loc_NumberFrom = loc_Phones.GetKeyAt(x)
                        loc_NumberFrom = loc_NumberFrom.Replace(" ","")
                        loc_NumberFrom = loc_NumberFrom.Replace("-","")
                        LogColor("Number = " & loc_NumberFrom, Colors.Blue)
                    End If
                Next
            Next
            Dim text As String = extras.RunMethod("getString", Array As Object("android.text"))
           'LogColor("text = " & text, Colors.Blue)
            Dim loc_message As String = text
            If text = "null" Then
                Try
                    Dim lines() As Object = extras.RunMethod("getCharSequenceArray", Array("android.textLines"))
                    For Each line As Object In lines
                         'Log(line)
                         loc_message = line
                    Next
                Catch
                    LogColor("Error!" & title, Colors.Red)
                End Try
            End If   
            LogColor("Message = " & loc_message, Colors.Blue)
            listener.ClearNotification(SBN)
        End If
    End If
End Sub
 

Massimo Linossi

Member
Licensed User
Longtime User
Hi.
I'm looking to all this post and it is very interesting.
Is there a way of sending a text notification to a phone ? I explain better. I have an application running on some phones and I want to
send a notification to the phone of a certain person or number. How can this be done ?
Thanks a lot.
Massimo
 

scarr

Member
Licensed User
Longtime User
I have purchased and installed the latest B4A and downloaded the NotificationListener example, but when I run it I get the following log

B4X:
LogCat connected to: B4A-Bridge: samsung GT-I9300
--------- beginning of /dev/log/main
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Service (service1) Create **
** Service (service1) Start **
Connected to B4A-Bridge (Wifi)
libcore.io.ErrnoException: recvfrom failed: ECONNRESET (Connection reset by peer)
** Activity (main) Pause, UserClosed = true **
Connected to B4A-Bridge (Wifi)
sending message to waiting queue (CallSubDelayed - UpdateStatus)
Installing file.
Installing file.
PackageAdded: package:baxi.usb
Installing file.
PackageAdded: package:baxi.usb
Copying updated assets files (13)
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = true **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = true **
libcore.io.ErrnoException: recvfrom failed: ECONNRESET (Connection reset by peer)
sending message to waiting queue (CallSubDelayed - UpdateStatus)
Connected to B4A-Bridge (Wifi)
sending message to waiting queue (CallSubDelayed - UpdateStatus)
Installing file.
PackageAdded: package:anywheresoftware.b4a.designer
Installing file.
PackageAdded: package:baxi.usb
Installing file.
PackageAdded: package:baxi.usb
Installing file.
PackageAdded: package:baxi.usb
libcore.io.ErrnoException: recvfrom failed: ECONNRESET (Connection reset by peer)
sending message to waiting queue (CallSubDelayed - UpdateStatus)
Connected to B4A-Bridge (Wifi)
sending message to waiting queue (CallSubDelayed - UpdateStatus)
Installing file.
PackageAdded: package:b4a.notificationlistener
Installing file.
PackageAdded: package:b4a.notificationlistener
Installing file.
PackageAdded: package:b4a.notificationlistener
Installing file.
PackageAdded: package:b4a.notificationlistener
Installing file.
PackageAdded: package:b4a.notificationlistener
Installing file.
PackageAdded: package:b4a.notificationlistener
Installing file.
PackageAdded: package:b4a.notificationlistener
Installing file.
PackageAdded: package:b4a.notificationlistener
Copying updated assets files (1)
** Activity (main) Create, isFirst = true **
Started
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
** Activity (main) Resume **
** Service (notificationservice) Create **
** Service (notificationservice) Start **
Unexpected event (missing RaiseSynchronousEvents): listener_notificationposted
Check the unfiltered logs for the full stack trace.
NotificationPosted, package = com.android.mms, id = 123, text = New message arrived
Error occurred on line: 20 (notificationservice)
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
    at android.view.ViewRootImpl.setView(ViewRootImpl.java:800)
    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:288)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:73)
    at android.app.Dialog.show(Dialog.java:287)
    at anywheresoftware.b4a.Msgbox.msgbox(Msgbox.java:136)
    at anywheresoftware.b4a.keywords.Common.Msgbox2(Common.java:438)
    at anywheresoftware.b4a.keywords.Common.Msgbox(Common.java:404)
    at b4a.notificationlistener.notificationservice._listener_notificationposted(notificationservice.java:129)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:636)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:305)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:238)
    at anywheresoftware.b4a.shell.Shell$1.run(Shell.java:276)
    at android.os.Handler.handleCallback(Handler.java:730)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:176)
    at android.app.ActivityThread.main(ActivityThread.java:5419)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
    at dalvik.system.NativeStart.main(Native Method)
** Activity (main) Pause, UserClosed = true **
** Activity (main) Create, isFirst = true **
Started
** Activity (main) Resume **
** Service (notificationservice) Create **
** Service (notificationservice) Start **
Unexpected event (missing RaiseSynchronousEvents): listener_notificationremoved
Check the unfiltered logs for the full stack trace.
NotificationRemoved, package = com.android.mms, id = 123, text = New message arrived
** Service (notificationservice) Start **
Unexpected event (missing RaiseSynchronousEvents): listener_notificationposted
Check the unfiltered logs for the full stack trace.
NotificationPosted, package = com.android.mms, id = 123, text = New message arrived
** Activity (main) Pause, UserClosed = true **
** Service (notificationservice) Destroy **
** Activity (main) Create, isFirst = true **
Started
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = true **
** Activity (main) Create, isFirst = true **
Started
** Activity (main) Resume **
** Service (notificationservice) Create **
** Service (notificationservice) Start **
Unexpected event (missing RaiseSynchronousEvents): listener_notificationremoved
Check the unfiltered logs for the full stack trace.
NotificationRemoved, package = com.android.mms, id = 123, text = New message arrived
** Service (notificationservice) Start **
Unexpected event (missing RaiseSynchronousEvents): listener_notificationposted
Check the unfiltered logs for the full stack trace.
NotificationPosted, package = com.android.mms, id = 123, text = New message arrived
libcore.io.ErrnoException: recvfrom failed: ECONNRESET (Connection reset by peer)
sending message to waiting queue (CallSubDelayed - UpdateStatus)
Connected to B4A-Bridge (Wifi)
sending message to waiting queue (CallSubDelayed - UpdateStatus)
Installing file.
PackageAdded: package:b4a.notificationlistener
** Activity (main) Create, isFirst = false **
running waiting messages (7)
** Activity (main) Resume **
** Service (service1) Destroy **
** Service (service1) Create **
** Service (service1) Start **
Connected to B4A-Bridge (Wifi)
** Service (service1) Destroy **
Ignoring event as service was destroyed: streams_newdata
Ignoring event as service was destroyed: streams_newdata
** Activity (main) Pause, UserClosed = false **
** Activity (main) Resume **
Ignoring event as service was destroyed: server_newconnection
** Activity (main) Pause, UserClosed = false **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Service (service1) Create **
** Service (service1) Start **
Connected to B4A-Bridge (Wifi)
Installing file.
** Activity (main) Pause, UserClosed = false **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
Installing file.
PackageAdded: package:b4a.notificationlistener
Copying updated assets files (1)
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **

What am I doing wrong?

Steve
 
Last edited:

wes58

Active Member
Licensed User
Longtime User
I have a problem with this library on Android 5.
When I compile my application with this library using android:targetSdkVersion="21", notifications are received from other applications but can't be cleared by my application - i.e. listener.ClearNotification(sbn) doesn't clear notification.

When I compile using targetSdkVersion less than 21, everything works OK. Notifications are received and can be cleared by my application. I am using Galaxy S5 with Lollipop.

Any suggestions? I have spent a lot of time before I have realised that the problem was targetSdkVersion 21.

I have attached a photo with some descriptions.
 

Attachments

  • Screenshot.png
    Screenshot.png
    70.5 KB · Views: 469
Last edited:

wes58

Active Member
Licensed User
Longtime User
Hi Erel,

Did you have a chance to have a look at, why the .ClearNotification(sbn) doesn't work with application compiled with targetSdkVersion 21? See my previous post.
Thanks,
 
Status
Not open for further replies.
Top