Android monitoring notification using Accessibility Service

Time:2021-3-9

demand

In the development of micro gestures, a notification trigger function is made, which automatically triggers an action when a preset notification is received, so it is necessary to monitor the notification message.

programme

At first, I wanted to use the traditional notificationlistenerservice, but this micro gesture app just used Android’s accessibility service. When I looked through this document, I found that notification events can be monitored in the accessibility service. The following table shows the event types that the accessibility service can provide:

Event types
AccessibilityEvent#TYPE_VIEW_CLICKED
AccessibilityEvent#TYPE_VIEW_LONG_CLICKED
AccessibilityEvent#TYPE_VIEW_FOCUSED
AccessibilityEvent#TYPE_VIEW_SELECTED
AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED
AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED
AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START
AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END
AccessibilityEvent#TYPE_VIEW_HOVER_ENTER
AccessibilityEvent#TYPE_VIEW_HOVER_EXIT
AccessibilityEvent#TYPE_VIEW_SCROLLED
AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED
AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED
AccessibilityEvent#TYPE_ANNOUNCEMENT
AccessibilityEvent#TYPE_GESTURE_DETECTION_START
AccessibilityEvent#TYPE_GESTURE_DETECTION_END
AccessibilityEvent#TYPE_TOUCH_INTERACTION_START
AccessibilityEvent#TYPE_TOUCH_INTERACTION_END
AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED
AccessibilityEvent#TYPE_WINDOWS_CHANGED
AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED

There are many types. The notification is the event in bold in the figure above, which saves the need for separate notification listener service and additional permissions. It’s naturally better for this app.

realization

The solution is found, and the implementation is not complicated.

  1. stay AndroidManifest.xml Registration of barrier free services
<service
    android:name=".ServicePlus"
    android:label="@string/service_plus"
    android:stopWithTask="false"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>
    <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/service_plus" />
</service>

above android:stopWithTask It is an interesting sign. According to the description of the document, it should mean that the service will not exit with the exit of the front desk

FLAG_STOP_WITH_TASK Added in API level 14

public static final int FLAG_STOP_WITH_TASK
Bit in flags: If set, the service will automatically be stopped by the system if the user removes a task that is rooted in one of the application’s activities. Set from the R.attr.stopWithTask attribute.

Constant Value: 1 (0x00000001)

But in the domestic android environment, I think it should not work. 😉

  1. Using XML to configure parameters for accessibility service is the above android:resource Point to XML:
<accessibility-service
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:accessibilityEventTypes="typeNotificationStateChanged"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:notificationTimeout="100"
    android:accessibilityFlags="flagRequestFilterKeyEvents"
    android:description="@string/service_plus_tip"
    tools:targetApi="n" />

The accessibilityevents type specifies the event of notification type.

  1. Can receive the event, take a look at the corresponding code
public class ServiceBase extends AccessibilityService {

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        try {
            if(event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {
                Notification notif = (Notification) event.getParcelableData();
                if (notif != null) {
                    String title = notif.extras.getString(Notification.EXTRA_TITLE);
                    String text =  notif.extras.getString(Notification.EXTRA_TEXT);
                    // ...
                }
            }
        } catch(Exception e) {
            Log.e(Consts.LOG, "event", e);
        }
     }
}

This code is very easy to understand. There are many ways to get notification related information in the notification class. Please refer to the Google documentation.

summary

If you develop an app that uses accessibility services, there is an easier way to listen for notifications.