Learn Accessibility service in android

Introduction

Hello Everyone, So in today’s article we are going to learn about accessibility service in android. I will teach you how to implement accessibility service and track different feedbacks from the device. Implementing acccessibilty service consist of majorly 5 steps. We are going to talk about those steps one by one so that you can understand the way to implement the whole process with ease. So without wasting any time let’s get started.

Implementation of Accessibility service

So in this artcle we are going to create an app which will track and tell us the package name of current opened app using accessibility and we will also track user actions such as click, scroll, long click. There are many other user actions we can track with accessibility service but if I start telling all of them then this article will become quite confusing. The implementation to listen all other user event will be the same just chose the accessibility condition according to that. So let’s jump to step 1.

Step 1 : Create Activity xml

First create an activity.xml file. So that our app can ask for the accessibility service permission to the user. Accessibility service is necessary to allow if we wan to extract user feedback from device.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:weightSum="2"
    android:gravity="center"
    android:layout_gravity="center"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".StartServiceScreen">


    <TextView
        android:id="@+id/PrmTxt"
        android:layout_gravity="center"
        android:textSize="18sp"
        android:gravity="center"
        android:text="Please provide us the below mentioned permissions"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/AccessibilityServiceBtn"
        android:text="Allow Accessbility "
        android:layout_gravity="center"
        android:layout_marginTop="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

Step 2 : Create .java file for activity

Now connect the activity.xml file to an backend. So that when user clicked on button then we can redirect user to accessibility service screen. Were user can allow or deny the permission to our application.

package com.two;

import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class StartServiceScreen extends AppCompatActivity {


    androidx.appcompat.widget.AppCompatButton AccessibilityServiceBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_start_service_screen);


        AccessibilityServiceBtn = findViewById(R.id.AccessibilityServiceBtn);


        AccessibilityServiceBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                // request permission via start activity for result
                startActivity(intent);
            }
        });


    }

}

Step 3 : Create Accessibility service class

This accessibility service class is important because we will define our operations in this class. In this class we can get every information which an accessibility service provides such as click, long click, scroll, window content change etc. If you wan to know more about the action provides by the accessibility service. You can directly by clicking here.

package com.two;


import android.accessibilityservice.AccessibilityService;
import android.os.Handler;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;

import android.view.accessibility.AccessibilityNodeInfo;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class TrackUserActivity extends AccessibilityService {

    // Tag for logging
    private static final String TAG = "MyAccessibilityService";

    // Variable to hold the last detected package name
    private String lastPackageName = "";

    // Handler to handle delayed tasks
    private Handler handler = new Handler();

    // Variable to hold the currently potential package name
    private String currentPotentialPackageName = "";

    // Set of package names to ignore (e.g., system UI packages)
    private Set<String> ignoredPackageNames = new HashSet<>(Arrays.asList(
            "com.android.systemui", "com.android.settings", "com.google.android.googlequicksearchbox"
    ));

    // Runnable to handle the debounce logic
    private Runnable debounceRunnable = new Runnable() {
        @Override
        public void run() {
            // If the potential package name has changed, update the last package name and log it
            if (!currentPotentialPackageName.equals(lastPackageName)) {
                lastPackageName = currentPotentialPackageName;
                Log.d(TAG, "Current app package name: " + lastPackageName);
            }
        }
    };

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        // Check if the event type is window state changed or window content changed
        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED ||
                event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {

            // Get the root node info of the currently active window
            AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
            if (nodeInfo != null) {
                // Extract package name information from the node info
                CharSequence packageName = nodeInfo.getPackageName();
                if (packageName != null) {
                    String packageNameString = packageName.toString();
                    // Check if the package name is not in the ignored package names and has changed
                    if (!ignoredPackageNames.contains(packageNameString) &&
                            !packageNameString.equals(currentPotentialPackageName)) {

                        // Update the current potential package name
                        currentPotentialPackageName = packageNameString;

                        // Remove any pending debounce runnable
                        handler.removeCallbacks(debounceRunnable);

                        // Post the debounce runnable with a delay of 500ms
                        handler.postDelayed(debounceRunnable, 500);
                    }
                }
            }
        }
        // We are checking is the event type is just user click
        else if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {
            Log.d(TAG, "User clicked");

        }// We are checking is the event type is just user long click
        else if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_LONG_CLICKED) {
            Log.d(TAG, "User long clicked");

        }
        // We are checking is the event type is just user long click
        else if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
            Log.d(TAG, "User long clicked");

        }
    }

    @Override
    public void onInterrupt() {
        // Remove any pending debounce runnable when the service is interrupted
        handler.removeCallbacks(debounceRunnable);
    }

    @Override
    public void onDestroy() {
        // Clean up by removing any pending debounce runnable when the service is destroyed
        super.onDestroy();
        handler.removeCallbacks(debounceRunnable);
    }

}

Step 4 : Create .xml for accessibility

Create this file in res > xml > create_file.xml. We will user this file later on in our AndroidMainfest.xml.

<accessibility-service
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeWindowStateChanged"
    android:accessibilityFeedbackType="feedbackSpoken"
    android:notificationTimeout="100"
    android:canRetrieveWindowContent="true" />

Step 5 : AndroidMainfest.xml

In AndroidMainfest.xml define the Accessibility Service. So that android knows that our app uses Accessibility Service.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Prototype"
        tools:targetApi="31">
        <activity
            android:name=".StartServiceScreen"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".TrackUserActivity"
            android:exported="true"
            android:label="@string/app_name"
            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/accessibility_service_config" />
        </service>

    </application>

</manifest>

Output

Conclusion

So I hope you guys understood that how you can implement accessbility service in android. I tried to explain you about this in an easy way. My suggestion to you guys is just don’t only read this article but also try to implement the accessbility service and still if you have any doubt then comment section is all yours. Ask me your doubts in the comment section and I will provide you solutions of your questions. If you have any suggestions please let us know by clicking on this link Contact us.

Leave a Comment