40

I would like to programmatically enable/disable Accessibility Services listed under Settings->Accessibility option.

I could start Accessibility Intent like below:

Intent intent = new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivityForResult(intent, 0);

But I don't have any idea on how to enable the services listed in the view through my code.

Please, provide me your views.

Alex Kulinkovich
  • 4,408
  • 15
  • 46
  • 50
Abilash
  • 1,143
  • 3
  • 14
  • 20

11 Answers11

29

I found a solution worked for me by calling

Settings.Secure.putString(getContentResolver(), 
    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "pkgname/classname");
Settings.Secure.putString(getContentResolver(), 
    Settings.Secure.ACCESSIBILITY_ENABLED, "1");

Where the pkgname is your package name and the classname is the class name of your accessibility service.

If you need to enable several services or you don't want to destory the previous settings you might want to use : to seperate other services.

Also you might need to run as a system application and you might need the following permissions

<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />

However, according to @Rupert Rawnsley this might not work on some versions of Android, I am working on Android 4.0.4 and hope it works for you.

PS. If it doesn't work, maybe you could find some luck in /data/data/com.android.providers.settings/databases/settings.db/secure, that's where Android stores secure settings.

Community
  • 1
  • 1
Kevin
  • 366
  • 4
  • 5
  • 6
    is given to only system applications so this solution will not work for non-system applications – Kushal Mar 12 '15 at 07:14
  • @Kushal Yes, this solution works only for system applications (or non-sys apps if your phone is rooted). And I think a non-system app might not be able to programmically enable an Accessibility Service due to security issues. – Kevin Mar 13 '15 at 09:17
  • Maybe a stupid question. Whats the packagename and whats the classname? com.somepackage/MyAcessibilityService is this the right way? – Alex Sep 22 '15 at 00:01
  • 2
    @Alex Sorry it's been quite a long time and I don't have the code now. But as far as I remember, it should be com.somepackage/.MyAcessibilityService or com.somepackage/com.sompackage.MyAcessibilityService. Also, I found that a newer version of Android might simply ignore this code. I had to write the database directly. Might be a little bit ugly, but it worked. FYI – Kevin Sep 23 '15 at 17:02
  • How did you guys succeed using this? It shows me an exception: java.lang.SecurityException: Permission denial: writing to settings requires:android.permission.WRITE_SECURE_SETTINGS – android developer May 16 '17 at 13:10
  • @androiddeveloper android.permission.WRITE_SECURE_SETTINGS is given to System apps only! – Dhruv Kaushal Apr 24 '18 at 14:11
  • Well I don't see the folder "/data/data/com.android.providers.settings/databases/" at all either, even though I have a rooted device. – android developer Apr 24 '18 at 17:05
17

From Android 6.0 you can use:

adb shell settings put secure enabled_accessibility_services packagname/servicename

The settings.db from old releases is no longer present on Android 6.0.

Zoli_K
  • 916
  • 7
  • 7
  • Does it work even on android 7? Also, how do I enable usage access via adb? – android developer Oct 03 '16 at 07:06
  • OP is about how to programmatically enable/disable the accessibility service not using adb shell – Vadiraj Purohit Feb 27 '18 at 09:12
  • If you can run it in console, then you can run it programmatically in test: `InstrumentationRegistry.getInstrumentation().getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES).executeShellCommand("...")` – Maxim Blumental Aug 02 '18 at 18:52
  • I came across this while trying to figure out how to enable via adb for DarQ... Here is the command that worked: `adb shell settings put secure enabled_accessibility_services com.kieronquinn.app.darq/.services.DarqBackgroundService` – MyPreciousss Feb 19 '20 at 01:48
15

In Android 7 (API 24), an AccessibilityService can programmatically disable itself by calling the disableSelf() method.

Sam
  • 40,644
  • 36
  • 176
  • 219
  • But how to get the instance of the service? I don't think I could simply call the primary constructor :/ – 4face Aug 05 '18 at 04:47
  • 2
    use a static reference like this: `static WeakReference ref = null` and then in your service's `onCreate()` use `if(ref != null && ref.get() != null) ref.get().disableSelf();`. Use the WeakReference to avoid memory leaks – binarynoise Apr 04 '20 at 16:04
6

AccessibilityService is special and cannot be started programmatically.

Rupert Rawnsley
  • 2,622
  • 1
  • 29
  • 40
  • From [this](http://stackoverflow.com/questions/5081145/android-how-do-you-check-if-a-particular-accessibilityservice-is-enabled/5106419#5106419), the enabled AccessibilityService is stored as a String from `Settings.Secure.getString(getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES)`. Isn't it possible to enable AccessibilityService by following the String format and call `Settings.Secure.putString(...)` once the app has system privilege? – Yeung Jun 30 '14 at 10:01
  • @Yeung In principle, but in practice I've found this to be hit-and-miss depending on the version of Android and the device. The process that controls Accessibility Services doesn't always see those changes without a reboot. In our app we direct the user to the settings page and have them enable the service for us. – Rupert Rawnsley Jun 30 '14 at 10:23
  • 1
    @Yeung Settings.Secure.putString(...) works only for system applications. For other applications, Android do not allow to turn accessibility service programmatically – Kushal Mar 12 '15 at 08:20
  • @Kushal you can grant this permission from adb ( adb shell pm grant yourpackagename android.permission.WRITE_SECURE_SETTINGS) – letroll Sep 28 '20 at 11:56
5

The best you can do is manualy open the accessibilty settings with:

Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)

and start the intent - you can also do it from the prefernece xml file:

intent android:action="android.settings.ACCESSIBILITY_SETTINGS"

Eran Katsav
  • 1,324
  • 15
  • 16
4

In instrumented tests I start my accessibility service like this:

private fun enableAccessibilityService() {
    val packageName = "com.example"
    val className = "$packageName.service.MyService"
    val string = "enabled_accessibility_services"
    val cmd = "settings put secure $string $packageName/$className"
    InstrumentationRegistry.getInstrumentation()
      .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES)
      .executeShellCommand(cmd)
      .close()
    TimeUnit.SECONDS.sleep(3)
}

I tested on Android 6 and 8. This also works for non-system apps.

Maxim Blumental
  • 763
  • 5
  • 26
3

Just in case anybody still seeks to turn off talkback from adb when you are stuck in your lock screen entering the password or pin. One thing you can try is adb shell am force-stop com.google.android.marvin.talkback

adb_user
  • 31
  • 1
3

Here is the working solution (if your activity is not running it will disable itself)

@Override
protected void onServiceConnected() {
    super.onServiceConnected();
    Toast.makeText(this, "Connected!",Toast.LENGTH_SHORT).show();
    ScheduledExecutorService scheduleTaskExecutor = Executors.newScheduledThreadPool(1);
    scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() {
        public void run() {
            serviceChecker();
        }
    }, 0, 5, TimeUnit.SECONDS);
}

private void serviceChecker(){
    if(!isActivityRunning(MainActivity.class)) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            disableSelf();
        }
    }
}
protected Boolean isActivityRunning(Class activityClass)
{
    ActivityManager activityManager = (ActivityManager) getBaseContext().getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);

    for (ActivityManager.RunningTaskInfo task : tasks) {
        if (activityClass.getCanonicalName().equalsIgnoreCase(task.baseActivity.getClassName()))
            return true;
    }

    return false;
}
3

You can enable accessibility services for multiple apps by separating them by a colon, like this:

adb shell settings put secure enabled_accessibility_services com.app1/com.app1.MyAccessibilityService:com.app2/com.app2.MyAccessibilityService
Tyler
  • 6,741
  • 3
  • 22
  • 19
0

enabled_accessibility_services contains all the enabled services separated by ':'. It's something like 'serviceA:serviceB:serviceC'

If you replace the string, it will enable your service, but you will also disable everyone else's.

The correct code would be:

    fun enableAccessibility(activity: Activity) {
        var accessibilityServices: String? = Settings.Secure.getString(
            activity.contentResolver,
            Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
        )

        if (accessibilityServices == null) {
            accessibilityServices = ""
        } else if (accessibilityServices.isNotEmpty()) {
            accessibilityServices = ":$accessibilityServices"
        }
        Settings.Secure.putString(
            activity.contentResolver,
            Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
            "${activity.applicationInfo.packageName}/${ForegroundDetectorService::class.java.canonicalName}$accessibilityServices"
        )
        Settings.Secure.putString(
            activity.contentResolver,
            Settings.Secure.ACCESSIBILITY_ENABLED, "1"
        )
    }

You only need to declare this permission:

<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>

You can only enable this permission if you are rooted or via adb.

Naprzod
  • 1
  • 1
-7

I found this post: How to programmatically check if a service is declared in AndroidManifest.xml?. The top answer talks about PackageManager, which tells you what is running.

Community
  • 1
  • 1
Ryan B
  • 3,364
  • 21
  • 35