【问题标题】:How to Programmatically Enable/Disable Accessibility Service in Android如何在 Android 中以编程方式启用/禁用辅助功能服务
【发布时间】:2012-04-21 02:44:53
【问题描述】:

我想以编程方式启用/禁用“设置”->“辅助功能”选项下列出的辅助功能服务。

我可以像下面这样启动辅助功能意图:

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

但我不知道如何通过我的代码启用视图中列出的服务。

请给我你的意见。

【问题讨论】:

    标签: android service accessibility


    【解决方案1】:

    我通过调用找到了适合我的解决方案

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

    pkgname 是您的包名,classname 是无障碍服务的类名。

    如果您需要启用多项服务,或者您不想破坏之前的设置,您可能需要使用: 来分隔其他服务。

    此外,您可能需要作为系统应用程序运行,并且您可能需要以下权限

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

    但是,根据@Rupert Rawnsley,这可能不适用于某些版本的 Android,我正在使用 Android 4.0.4,希望它对您有用。

    PS。如果它不起作用,也许你可以在/data/data/com.android.providers.settings/databases/settings.db/secure 找到一些运气,那是 Android 存储安全设置的地方。

    【讨论】:

    • 仅适用于系统应用程序,因此此解决方案不适用于非系统应用程序
    • @Kushal 是的,此解决方案仅适用于系统应用程序(如果您的手机已植根,则为非系统应用程序)。而且我认为由于安全问题,非系统应用程序可能无法以编程方式启用辅助功能服务。
    • 也许是个愚蠢的问题。包名和类名是什么? com.somepackage/MyAcessibilityService 这是正确的方法吗?
    • @Alex 抱歉,已经很久了,我现在没有代码。但据我记忆,应该是 com.somepackage/.MyAcessibilityService 或 com.somepackage/com.sompackage.MyAcessibilityService。此外,我发现较新版本的 Android 可能会简单地忽略此代码。我不得不直接写数据库。可能有点难看,但它确实有效。仅供参考
    • 你们是如何成功使用这个的?它向我显示了一个异常:java.lang.SecurityException: Permission denial: writing to settings requires:android.permission.WRITE_SECURE_SETTINGS
    【解决方案2】:

    从 Android 6.0 你可以使用:

    adb shell settings put secure enabled_accessibility_services packagname/servicename
    

    旧版本的 settings.db 在 Android 6.0 上不再存在。

    【讨论】:

    • 它甚至可以在 android 7 上运行吗?另外,如何通过 adb 启用使用访问权限?
    • OP 是关于如何在不使用 adb shell 的情况下以编程方式启用/禁用无障碍服务
    • 如果你可以在控制台运行它,那么你可以在测试中以编程方式运行它:InstrumentationRegistry.getInstrumentation().getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES).executeShellCommand("...")
    • 我在试图弄清楚如何通过 adb 为 DarQ 启用时遇到了这个问题......这是有效的命令:adb shell settings put secure enabled_accessibility_services com.kieronquinn.app.darq/.services.DarqBackgroundService
    【解决方案3】:

    在 Android 7 (API 24) 中,AccessibilityService 可以通过调用disableSelf() 方法以编程方式禁用自身。

    【讨论】:

    • 但是如何获取服务的实例呢?我认为我不能简单地调用主构造函数:/
    • 使用这样的静态引用:static WeakReference&lt;MyAccessibilityService&gt; ref = null,然后在您的服务的onCreate() 中使用if(ref != null &amp;&amp; ref.get() != null) ref.get().disableSelf();。使用 Wea​​kReference 避免内存泄漏
    【解决方案4】:

    AccessibilityService 比较特殊,不能以编程方式启动。

    【讨论】:

    • 来自this,启用的AccessibilityService 存储为来自Settings.Secure.getString(getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES) 的字符串。是不是可以按照String格式开启AccessibilityService,一旦app有系统权限就调用Settings.Secure.putString(...)
    • @Yeung 原则上,但在实践中,我发现这取决于 Android 和设备的版本。控制辅助功能服务的进程在不重新启动的情况下并不总是看到这些更改。在我们的应用中,我们将用户引导至设置页面并让他们为我们启用服务。
    • @Yeung Settings.Secure.putString(...) 仅适用于系统应用程序。对于其他应用,Android 不允许以编程方式开启无障碍服务
    • @Kushal 您可以从 adb 授予此权限( adb shell pm grant yourpackagename android.permission.WRITE_SECURE_SETTINGS)
    【解决方案5】:

    您可以做的最好的事情是手动打开辅助功能设置:

    意图意图 = 新意图(Settings.ACTION_ACCESSIBILITY_SETTINGS)

    并启动意图 - 您也可以从首选 xml 文件中执行此操作:

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

    【讨论】:

    • 是否可以直接进入具有切换功能的特定应用屏幕?
    【解决方案6】:

    以防万一当您卡在锁屏界面输入密码或 PIN 码时,仍然有人试图关闭来自 adb 的对讲。您可以尝试的一件事是adb shell am force-stop com.google.android.marvin.talkback

    【讨论】:

      【解决方案7】:

      在仪器测试中,我像这样启动无障碍服务:

      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)
      }
      

      我在 Android 6 和 8 上进行了测试。这也适用于非系统应用。

      【讨论】:

        【解决方案8】:

        这是可行的解决方案(如果您的活动未运行,它将自行禁用)

        @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;
        }
        

        【讨论】:

          【解决方案9】:

          您可以通过用冒号分隔多个应用来启用无障碍服务,如下所示:

          adb shell settings put secure enabled_accessibility_services com.app1/com.app1.MyAccessibilityService:com.app2/com.app2.MyAccessibilityService
          

          【讨论】:

            【解决方案10】:

            enabled_accessibility_services 包含所有启用的服务,用':'分隔。类似于'serviceA:serviceB:serviceC'

            如果您替换字符串,它将启用您的服务,但您也会禁用其他所有人的服务。

            正确的代码是:

                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"
                    )
                }
            

            你只需要声明这个权限:

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

            只有 root 或通过 adb 才能启用此权限。

            【讨论】:

              【解决方案11】:

              我发现了这篇文章:How to programmatically check if a service is declared in AndroidManifest.xml?。最佳答案是关于 PackageManager,它会告诉您正在运行什么。

              【讨论】:

                猜你喜欢
                • 2016-11-16
                • 1970-01-01
                • 2022-11-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多