AccessibilityService - performGlobalAction无法在自己的应用程序中工作

时间:2017-09-13 10:01:39

标签: android service accessibilityservice

我正在尝试通过AccessibilityService发送系统返回新闻事件,这样可以正常工作,但前提是我不在我自己的应用中。

我总是从true获得performGlobalAction,无论我是否在自己的应用程序中,但我只看到如果我不在我自己的应用程序中,事件就会被执行应用程序,但在任何其他一个(从上面的活动显示或类似的意义上)

为什么会这样?我的应用是一个侧边栏应用,在WindowManager顶部显示了叠加层,一切正常(AccessibilityService正在运行,正在处理我的自定义事件,服务总是返回我的事件的成功消息,但我的自己的应用程序不会对后退按钮事件做出反应。)

我的服务如下:

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中的accessibilityservice.xml设置了所有内容,并使用它来定义我的服务设置,这也完美无缺,我想要接收的所有事件都可靠且正确地接收

编辑2

在我的情况下似乎我的叠加层仍在窃取焦点,使其可以集中注意力,并且没有时间问题,有时会产生问题。尽管如此,我可以使用BroadcastReceiver与服务进行通信来改进我的解决方案,因为startService调用不安全,如接受的答案所述

1 个答案:

答案 0 :(得分:2)

让我觉得你在做一些非常奇怪的事情。您似乎将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);
  

您必须从“辅助功能服务设置”菜单启动辅助功能服务。

即使您的服务已经启动,这样的通话也是不安全的!在打开您的活动之前,无法保证您的用户将启动该服务。调用context.startService并尝试以这种方式启动AccessibilityService后,它将阻止辅助功能设置菜单启动您的服务并正确绑定到操作系统。实际上,在这种情况下,用户必须:在“辅助功能设置”菜单中关闭服务开关,强制停止(甚至卸载)您的应用程序,重新启动设备,启动服务然后开始您的活动,为了实现正确的行为。

如果您不这样做,它将无法正确绑定到操作系统,并且其行为未定义。现在,你实际上已经在操作系统中创建了一个hack,并且正在遇到所谓的未定义行为,这种行为在版本,制造商等方面可能会有很大差异,因为它的行为不在AOSP集成测试中。

事实上,您明确无法使用context.startService()调用启动辅助功能服务。这是Android的一个非常重要的安全功能,因为Accessibility Services可以访问屏幕内容,用户需要对允许此访问的提供商和应用程序进行细粒度控制。所以,虽然你可能会得到一些行为,但这是不明确和危险的行为。你想要的是如下:

使用以下服务配置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手势上执行此操作,而是要设置某种进程间通信,并希望能够触发“全局后退按钮”操作。但是,这些信息是针对另一个问题的,但是如果你理解了这篇文章中的信息,我确定你需要继续进行的是明确的。