我发现Android 9现在shows info if accessibility service stopped working。
对于尝试利用可访问性API的开发人员而言,这始终是一个痛苦。
辅助功能似乎已启用,但服务已停止。为了使其恢复正常工作,需要关闭并重新打开辅助功能。
如果Google能够完全解决该问题,我会很高兴,但是现在他们只是暗示手动禁用它会很好。
不是最好的东西,但至少是一些东西。
因此,我试图找出系统如何知道服务是否崩溃。碰巧有一个名为AccessibilityUtil的类,它包含DataSet
方法。
不幸的是,它会检查AccessibilityNodeInfo中的隐藏字段hasServiceCrashed
,该字段对于第三方开发人员(由于拒绝反射)以及以前的android版本均不可用。
因此,我想知道是否还有其他方法可以从系统中获取信息,从而阐明我的可访问性服务已崩溃/停止工作并且需要用户采取措施。从棒棒糖开始。提示表示赞赏。
答案 0 :(得分:2)
我想出了一个想法,即使用一个静态布尔值来指示无障碍服务的状态,并将其与 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
进行比较。我已经在多台设备上测试过,没有发现这种方法有任何问题。
1.在无障碍服务中声明一个静态布尔值。
private static boolean bServiceRunning = false;
2.在无障碍服务中,设置onServiceConnected
和onUnbind
@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.在无障碍服务中创建一个静态函数
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 :(得分:0)
Android通常会阻止应用程序反复崩溃而无法运行。可访问性服务的这种行为显然可以影响依赖该服务的用户,但是由于这些服务可以有效地控制UI,因此反复崩溃会导致该设备不可用。
在我看来,没有其他人会对AccessibilityServiceInfo中崩溃的字段感兴趣。不幸的是,我使用仅适用于系统的数据填充了该字段。我将启用的服务列表与绑定的服务列表进行比较。
如果您对阻止服务运行感兴趣,可以通过跟踪何时调用onBind和onUnbind并从AccessibilityManager查看启用的服务列表来做类似的事情。
答案 2 :(得分:0)
我不知道这是否是解决方案。但是我确实发现它什么时候不起作用:如果我使用“ dumpsys可访问性”,则服务部分为空,如下所示:
User state[attributes:{id=0,
currentUser=true,
touchExplorationEnabled=false,
displayMagnificationEnabled=false,
navBarMagnificationEnabled=false,
autoclickEnabled=false}
services:{}]
也许您可以检查服务是否为空。