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

编辑

要明确这一点:

编辑 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 中的信息,我相信您将清楚如何继续。