4

我发现如果无障碍服务停止工作,Android 9 现在会显示信息

对于试图利用可访问性 API 的开发人员来说,这一直是一个痛苦。

  • 辅助功能看起来已启用,但服务已停止。为了让它恢复工作,需要关闭并重新打开辅助功能。

  • 如果谷歌能彻底解决这个问题,我会很高兴,但现在他们只是暗示手动禁用-启用它是件好事。

不是最好的东西,但至少是一些东西。

  • 所以,我试图找出系统如何知道服务是否崩溃。碰巧有一个名为AccessibilityUtil的类,它包含hasServiceCrashed方法。

  • 不幸的是,它检查了 AccessibilityNodeInfo 中的一个隐藏字段crashed,第三方开发人员(因为反射拒绝)以及以前的 android 版本都无法使用该字段。

所以我想知道是否有另一种方法可以从系统中获取信息,以澄清我的无障碍服务已崩溃/停止工作并且需要用户的操作。从棒棒糖开始。提示赞赏。

4

3 回答 3

4

我想出了一个想法,使用一个静态布尔值来指示 Accessibility Service 的状态,并将其与Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES. 我已经在多台设备上进行了测试,没有发现这种方法有任何问题。

1.在无障碍服务中声明一个静态布尔值。

private static boolean bServiceRunning = false;

2.在无障碍服务中,设置布尔值onServiceConnectedonUnbind

@Override
protected void onServiceConnected() {

    super.onServiceConnected();
    bServiceRunning = true; //put this at the very beginning to reduce time gap
}

@Override
public boolean onUnbind(Intent intent) {
        
   bServiceRunning = false;
   return super.onUnbind(intent);
}

3.在Accessibility Service中创建静态函数

public static boolean bGetServiceStatus(){
    return bServiceRunning;
}

使用布尔标志,我可以知道无障碍服务是否以所需的状态运行。当服务被强制停止时,onUnbind将被调用,因此布尔值变为 false。

4.我们Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES用来获取无障​​碍服务切换状态

public static boolean bIsAccessibilityServiceEnabled(Context context, Class<?> accessibilityService) {

        ComponentName expectedComponentName = new ComponentName(context, accessibilityService);
        String strServicesSettingResult = Settings.Secure.getString(context.getContentResolver(),  Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
        if (strServicesSettingResult == null){
            return false;
        }

        TextUtils.SimpleStringSplitter colonSplitter = new TextUtils.SimpleStringSplitter(':');
        colonSplitter.setString(strServicesSettingResult);

        while (colonSplitter.hasNext()) {
            String strComponentName = colonSplitter.next();
            ComponentName enabledService = ComponentName.unflattenFromString(strComponentName);

            if (enabledService != null && enabledService.equals(expectedComponentName))
                return true;
        }

        return false;
    }

5.这就是我们想要的,我们用上面两种方法检查确定无障碍服务的真实状态。

public static int intIsAccessibilityServiceEnabled_WithCrashCheck(Context context, Class<?> accessibilityService){
        //return 0 if Accessibility Service enabled and running
        //return -1 if Accessibility Service disabled and not running
        //return -2 if Accessibility Service enabled but stopped working or crashed

        //first check Accessibility Service boolean

        if(bGetServiceStatus()){
            //service is running
            return 0;
        }else{
            //service not running, now double check with Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
            boolean bResult = bIsAccessibilityServiceEnabled(context, accessibilityService);

            if(!bResult){
                //Accessibility Service is disabled
                return -1;
            }else{
                //Accessibility Service is enabled, but service is not actually running, Accessibility Service is crashed
                return -2;
            }
        }

    }

使用“AccessibilityManager”也同样有效,但我更喜欢带有静态布尔值的更“轻量级”版本以获得更好的性能。


注意:Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES在没有其他双重检查的情况下使用会导致错误。该值未同步。结果并不总是代表真实的服务状态。以下步骤可以创建这样的案例:

  1. 启动辅助功能服务,然后转到应用设置强制停止应用。
  2. 现在您可以看到无障碍服务开关已关闭。(目前看来足够了,但下一步会产生问题)
  3. 再次启动无障碍服务,在Android 9.0+的设备上你会发现开关打开了,但服务实际上没有运行,现在它显示“不工作。点击获取信息。”
于 2021-02-18T06:47:37.673 回答
0

我不知道这是否是一个解决方案。但我确实发现它什么时候不起作用:如果我使用“ dumpsys access ”,服务部分是空的,看起来像:

User state[attributes:{id=0, 
                       currentUser=true, 
                       touchExplorationEnabled=false,  
                       displayMagnificationEnabled=false,   
                       navBarMagnificationEnabled=false,  
                       autoclickEnabled=false}
           services:{}]

也许您可以检查服务是否为空。

于 2019-12-25T09:52:22.330 回答
0

如果应用程序反复崩溃,Android 通常会阻止它们运行。无障碍服务的这种行为显然会影响依赖该服务的用户,但由于这些服务可以有效地控制 UI,因此反复崩溃也可能导致设备无法使用。

我没有想到其他人会对 AccessibilityServiceInfo 中的崩溃字段感兴趣。不幸的是,我使用只有系统可用的数据填充了该字段。我将启用的服务列表与绑定的服务列表进行比较。

如果您对您的服务是否被阻止运行感兴趣,您可以通过跟踪何时调用 onBind 和 onUnbind 并查看 AccessibilityManager 中启用的服务列表来执行类似的操作。

于 2019-03-08T18:11:56.410 回答