【问题标题】:AccessibilityService - performGlobalAction not working in own appAccessibilityService - performGlobalAction 在自己的应用程序中不起作用
【发布时间】:2017-09-13 10:01:39
【问题描述】:

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

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

任何想法为什么会发生这种情况?我的应用程序是一个侧边栏应用程序,在 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.xml 中设置了 AccessibilityService 的所有内容,并使用它来定义我的服务设置,这也工作得很好,我想要接收的所有事件都能可靠且正确地接收

编辑 2

似乎在我的情况下,我的叠加层仍在窃取焦点,使其可聚焦,并且没有有时会出现问题的时间问题。不过,我的解决方案可以通过使用BroadcastReceiver 与服务进行通信来改进,因为startService 调用并不安全,正如接受的答案中所讨论的那样

【问题讨论】:

    标签: android service accessibilityservice


    【解决方案1】:

    我觉得你在做一些非常奇怪的事情。看来您将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,它将阻止 Accessibility Settings Menu 启动您的服务并正确绑定到操作系统。事实上,一旦在这种情况下,用户必须:在“辅助功能设置”菜单中为您的服务关闭开关,强制停止(甚至可能卸载)您的应用程序,重新启动他们的设备,启动您的服务,然后启动您的活动,在为了实现正确的行为。

    如果您不这样做,它将无法正确绑定到操作系统,并且其行为未定义。现在,您实际上已经在操作系统中创建了一个 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 手势上执行此操作,您想要做的是与您希望能够触发“全局后退按钮”操作的部分设置某种进程间通信。但是,该信息是针对另一个问题的,但如果您了解这篇文章中的信息,我相信您将清楚您需要如何进行。

    【讨论】:

    • 评论不适用于扩展讨论或调试会话;这个对话是moved to chat。如果这里有重要信息,应该编辑成问题或答案。
    • 因此,在该威胁的某个时刻,我发布了一条关于在移动其中一些内容后删除 cmets 的评论。有人用核弹炸过它,现在它消失了。删除这么多内容之前的警告将不胜感激。 @prom85:如果您在另一篇文章中提出其他问题,我确实认为这是该特定问题的正确答案(或者至少是其他与类似问题混淆的人需要看到的信息)。
    • 我在已删除的 cmets 中没有看到您发布的任何相关内容。无论如何,信息没有被删除;它已在聊天中存档。除了留下另一个嘈杂的评论外,没有真正的方法可以警告您,我们强烈建议不要这样做。当评论线程过长时,我们会收到自动标记,建议的操作是将其移至聊天。如果您对如何改进工作流程有任何建议,或者对政策有疑问,您可以在 Meta Stack Overflow 上发布问题。您将得到的基本信息是 cmets 是临时的,不用于讨论。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多