AccessibilityService - performGlobalAction 在自己的应用程序中不起作用
AccessibilityService - performGlobalAction not working in own app
我正在尝试通过 AccessibilityService
发送系统返回按下事件,这工作正常,但前提是我不在我自己的应用程序中。
无论我是否在我自己的应用程序中,我总是从 performGlobalAction
获得 true
,但我只看到如果我不在我自己的应用程序,但在任何其他应用程序中(在显示之前的 activity 或类似的意义上)
知道为什么会这样吗?我的应用程序是一个侧边栏应用程序,在 WindowManager
的顶部绘制了一个叠加层,一切正常(AccessibilityService
是 运行 并且始终处理我的自定义事件和服务 returns我的事件的成功消息,但我自己的应用程序对后退按钮事件没有反应)。
我的服务如下所示:
public class MyAccessibilityService extends AccessibilityService {
public static void sendBackIntent(Context context) {
Intent intent = new Intent(context, MyAccessibilityService.class);
intent.putExtra("action", GLOBAL_ACTION_BACK);
context.startService(intent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Bundle extras = intent.getExtras();
Integer action = null;
if (extras != null) {
action = extras.getInt("action");
}
if (action != null) {
switch (action) {
case GLOBAL_ACTION_BACK:
boolean result = performGlobalAction(action);
L.d("Action %d executed: %b", action, result);
break;
default:
L.e("Unhandled action %d", action);
break;
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
}
@Override
public void onInterrupt() {
}
}
编辑
要明确这一点:
- 我不通过
MyAccessibilityService.sendBackIntent(context)
启动此服务,我发送如下意图:if (isAccessibilityserviceRunning) MyAccessibilityService.sendBackIntent(context)
- 我通过系统服务菜单启动我的服务,只需在此处启用它,然后让系统自动启动它
- 我已经在
accessibilityservice.xml
中设置了 AccessibilityService
的所有内容并使用它来定义我的服务设置,这也工作得很好,我想接收的所有事件都可靠地接收了并正确
编辑 2
在我的情况下,我的叠加层似乎仍在窃取焦点,使其可聚焦,并且没有时序问题,有时会出现问题。不过,我的解决方案可以通过使用 BroadcastReceiver
与服务进行通信来改进,因为 startService
调用并不安全,如已接受的答案
中所讨论的那样
我觉得你在做一些非常奇怪的事情。您似乎将 AccessibilityService
视为正常的 Service
。这部分表明这是您对方法的以下实现:
public static void sendBackIntent(Context context);
@Override
public int onStartCommand(Intent intent, int flags, int startId);
仅凭这两个方法的签名和您的调用
context.startService(intent);
在你的静态方法中,我可以看出你不理解 AccessibilityServices
以及他们应该如何执行他们的工作。您无法以您尝试的方式启动无障碍服务,也无法与之交互。当然,您可以使用辅助功能服务执行全局操作,但除非您从辅助功能服务菜单(您知道 TalkBack 出现的菜单)正确启动它们,否则它们不会准确和全局执行。
您的代码本质上不在 运行 您认为它在 运行 的上下文中。因此,它运行并执行操作。但是,AccessibilityServices
和它们各自的力量在于它们能够全局附加到操作系统。 android API 将无法正确绑定 AccessibilityService,当您尝试启动您的服务时:
context.startService(intent);
You have to launch your Accessibility Service from the Accessibility Services Settings menu.
即使您的服务已经启动,这样的调用也是不安全的!无法保证您的用户会在打开您的 Activity 之前启动该服务。一旦您调用 context.startService
并尝试以这种方式启动您的 AccessibilityService,它将阻止辅助功能设置菜单启动您的服务并正确绑定到 OS。事实上,一旦遇到这种情况,用户将不得不:在辅助功能设置菜单中关闭您服务的开关,强制停止(甚至卸载)您的应用程序,重新启动他们的设备,启动您的服务,然后启动您的 activity,以便实现正确的行为。
如果您不这样做,它将无法正确绑定到 OS 并且其行为未定义。现在,您实际上已经在 OS 中创建了一个 hack,并且 运行 反对所述未定义的行为,这可能因版本、制造商等而有很大差异,因为它的行为未包含在AOSP 集成测试。
事实上,您明确不能使用 context.startService()
调用启动辅助功能服务。这是 Android 的一项非常重要的安全功能,因为辅助功能服务可以获得对屏幕内容的访问权限,并且用户需要对他们允许此访问的提供商和应用程序进行精细控制。因此,虽然您可能会出现某些行为,但这是未定义的危险行为。你想要的是类似下面的东西:
使用以下服务配置 XML:
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/accessibility_service_description"
android:accessibilityEventTypes="typeWindowContentChanged"
android:accessibilityFlags="flagRequestTouchExplorationMode"
android:canRetrieveWindowContent="true"
android:canRequestTouchExplorationMode="true"
android:accessibilityFeedbackType="feedbackGeneric"
android:notificationTimeout="100"
android:settingsActivity="com.service.SettingsActivity"
/>
以及以下无障碍服务。
class MyA11yService extends AccessibilityService {
@Override public boolean onGesture(int gestureId) {
switch (gestureId) {
case GESTURE_SWIPE_UP_AND_DOWN:
CLog.d("Performing gesture.");
performGlobalAction(GLOBAL_ACTION_BACK);
return true;
default:
return false;
}
}
}
performGlobalAction
调用在任何 Context
中都可以正常工作。现在,而不是在 SWIPE_UP_DOWN 手势上执行此操作,您想要做的是与您希望能够触发 "global back button" 的部分建立某种进程间通信行动。但是,该信息是针对另一个问题的,不过如果您理解了此 post 中的信息,我相信您将清楚如何继续。
我正在尝试通过 AccessibilityService
发送系统返回按下事件,这工作正常,但前提是我不在我自己的应用程序中。
无论我是否在我自己的应用程序中,我总是从 performGlobalAction
获得 true
,但我只看到如果我不在我自己的应用程序,但在任何其他应用程序中(在显示之前的 activity 或类似的意义上)
知道为什么会这样吗?我的应用程序是一个侧边栏应用程序,在 WindowManager
的顶部绘制了一个叠加层,一切正常(AccessibilityService
是 运行 并且始终处理我的自定义事件和服务 returns我的事件的成功消息,但我自己的应用程序对后退按钮事件没有反应)。
我的服务如下所示:
public class MyAccessibilityService extends AccessibilityService {
public static void sendBackIntent(Context context) {
Intent intent = new Intent(context, MyAccessibilityService.class);
intent.putExtra("action", GLOBAL_ACTION_BACK);
context.startService(intent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Bundle extras = intent.getExtras();
Integer action = null;
if (extras != null) {
action = extras.getInt("action");
}
if (action != null) {
switch (action) {
case GLOBAL_ACTION_BACK:
boolean result = performGlobalAction(action);
L.d("Action %d executed: %b", action, result);
break;
default:
L.e("Unhandled action %d", action);
break;
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
}
@Override
public void onInterrupt() {
}
}
编辑
要明确这一点:
- 我不通过
MyAccessibilityService.sendBackIntent(context)
启动此服务,我发送如下意图:if (isAccessibilityserviceRunning) MyAccessibilityService.sendBackIntent(context)
- 我通过系统服务菜单启动我的服务,只需在此处启用它,然后让系统自动启动它
- 我已经在
accessibilityservice.xml
中设置了AccessibilityService
的所有内容并使用它来定义我的服务设置,这也工作得很好,我想接收的所有事件都可靠地接收了并正确
编辑 2
在我的情况下,我的叠加层似乎仍在窃取焦点,使其可聚焦,并且没有时序问题,有时会出现问题。不过,我的解决方案可以通过使用 BroadcastReceiver
与服务进行通信来改进,因为 startService
调用并不安全,如已接受的答案
我觉得你在做一些非常奇怪的事情。您似乎将 AccessibilityService
视为正常的 Service
。这部分表明这是您对方法的以下实现:
public static void sendBackIntent(Context context);
@Override
public int onStartCommand(Intent intent, int flags, int startId);
仅凭这两个方法的签名和您的调用
context.startService(intent);
在你的静态方法中,我可以看出你不理解 AccessibilityServices
以及他们应该如何执行他们的工作。您无法以您尝试的方式启动无障碍服务,也无法与之交互。当然,您可以使用辅助功能服务执行全局操作,但除非您从辅助功能服务菜单(您知道 TalkBack 出现的菜单)正确启动它们,否则它们不会准确和全局执行。
您的代码本质上不在 运行 您认为它在 运行 的上下文中。因此,它运行并执行操作。但是,AccessibilityServices
和它们各自的力量在于它们能够全局附加到操作系统。 android API 将无法正确绑定 AccessibilityService,当您尝试启动您的服务时:
context.startService(intent);
You have to launch your Accessibility Service from the Accessibility Services Settings menu.
即使您的服务已经启动,这样的调用也是不安全的!无法保证您的用户会在打开您的 Activity 之前启动该服务。一旦您调用 context.startService
并尝试以这种方式启动您的 AccessibilityService,它将阻止辅助功能设置菜单启动您的服务并正确绑定到 OS。事实上,一旦遇到这种情况,用户将不得不:在辅助功能设置菜单中关闭您服务的开关,强制停止(甚至卸载)您的应用程序,重新启动他们的设备,启动您的服务,然后启动您的 activity,以便实现正确的行为。
如果您不这样做,它将无法正确绑定到 OS 并且其行为未定义。现在,您实际上已经在 OS 中创建了一个 hack,并且 运行 反对所述未定义的行为,这可能因版本、制造商等而有很大差异,因为它的行为未包含在AOSP 集成测试。
事实上,您明确不能使用 context.startService()
调用启动辅助功能服务。这是 Android 的一项非常重要的安全功能,因为辅助功能服务可以获得对屏幕内容的访问权限,并且用户需要对他们允许此访问的提供商和应用程序进行精细控制。因此,虽然您可能会出现某些行为,但这是未定义的危险行为。你想要的是类似下面的东西:
使用以下服务配置 XML:
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/accessibility_service_description"
android:accessibilityEventTypes="typeWindowContentChanged"
android:accessibilityFlags="flagRequestTouchExplorationMode"
android:canRetrieveWindowContent="true"
android:canRequestTouchExplorationMode="true"
android:accessibilityFeedbackType="feedbackGeneric"
android:notificationTimeout="100"
android:settingsActivity="com.service.SettingsActivity"
/>
以及以下无障碍服务。
class MyA11yService extends AccessibilityService {
@Override public boolean onGesture(int gestureId) {
switch (gestureId) {
case GESTURE_SWIPE_UP_AND_DOWN:
CLog.d("Performing gesture.");
performGlobalAction(GLOBAL_ACTION_BACK);
return true;
default:
return false;
}
}
}
performGlobalAction
调用在任何 Context
中都可以正常工作。现在,而不是在 SWIPE_UP_DOWN 手势上执行此操作,您想要做的是与您希望能够触发 "global back button" 的部分建立某种进程间通信行动。但是,该信息是针对另一个问题的,不过如果您理解了此 post 中的信息,我相信您将清楚如何继续。