Android - 不活动/活动,无论***应用程序

Posted

技术标签:

【中文标题】Android - 不活动/活动,无论***应用程序【英文标题】:Android - Inactivity/Activity regardless of top app 【发布时间】:2013-09-18 21:04:58 【问题描述】:

我需要找出最后一次用户交互是什么时候,无论哪个应用程序在最前面。我不在乎事件发生在哪里或发生了什么,我只需要知道它是什么时候发生的。或者,当它发生时,我收到一个事件。

我尝试了多种方法:

    使用窗口创建服务并添加触摸侦听器。这吃掉了触摸事件并没有传递下去 寻找一个shell命令。 getevent 有效(每次收到触摸时都会输入新行)但是您需要 root,所以这对我来说不是一个合适的解决方案。 寻找“距离锁定的时间”,但一无所获。

另请注意:这没有安全问题,因为我不需要任何识别信息,例如触摸位置。只是一个类型印章(或现场活动)。

我也愿意使用反射来解决这个问题。


@user2558882 有一个很好的解决方案。到目前为止,这是我遇到的最好的方法。

虽然这很好,但它仍然需要用户在辅助功能控件中手动启用我们的应用程序。我们的客户拥有数千台设备,我们有办法自动更新和更改设置。我们尝试将手动配置保持在最低限度,但有些事情仍然需要用户输入,例如启用设备管理模式。所以这个解决方案是可以接受的,但是我仍然愿意接受一种不需要任何用户输入来启用的方式。


我最终实现了@user2558882 使用无障碍服务的想法。虽然欢迎其他想法。

【问题讨论】:

【参考方案1】:

这只是一个想法,可能无法完全转移。

以下是 AccessibilityService 的功能:

无障碍服务在后台运行并接收回调 触发 AccessibilityEvents 时由系统执行。此类事件表示 用户界面中的一些状态转换,例如焦点 已更改,已单击按钮等。

onAccessibilityEvent(AccessibilityEvent)里面的活动会通知你:

@Override
public void onAccessibilityEvent(AccessibilityEvent event) 

    // Some event

    timeSinceLastInteraction = System.currentTimeMillis();


您可以定期记录更新:

Log.i("LOG_TIME_ELAPSED", "Last user interaction was " + 
             ((System.currentTimeMillis() - timeSinceLastInteraction) / 1000) + 
                      " seconds ago.");

您可以通过两种方式配置 AccessibilityService:

    在代码中,在 onServiceConnected() 内部。 (从 API 4 开始)

    在 xml 中,在您的服务中使用 meta-data 标记。 (从 API 14 开始)

在您的应用程序中,您可以将AccessibilityServiceInfo.eventTypes 设置为:

accessibilitySeviceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;

但是,TYPES_ALL_MASK 将包括通知,例如:AccessibilityEvent.TYPE_ANNOUNCEMENT、AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED 等,我猜你不想拦截这些通知。因此,您需要选择 AccessibilityEvent.TYPE_X 的一个子集。

您应该注意的另一件事是通知超时:

在给定类型的最近事件之后的超时时间之前 通知 AccessibilityService。

事件通知超时对于避免传播事件很有用 过于频繁地向客户发送,因为这是通过 an 完成的 昂贵的进程间调用。可以将超时视为 确定事件生成何时稳定的标准。

所以,请尽量设置超时值。

如果您决定使用 AccessibilityService 选项,您会发现此页面非常有用:Developing an Accessibility Service。

从您的 cmets 到 Chloe 的回答,该设备似乎在您的控制之下:这意味着,在某种程度上,您不必依赖用户来启用该服务:

无障碍服务的生命周期完全由 系统并遵循既定的服务生命周期。 此外,启动或停止无障碍服务是 通过启用或由显式用户操作专门触发 在设备设置中禁用它

您可以在部署时启用 AccessibilityService,也可以使用 AppLock 之类的应用程序限制对“设置”菜单的访问。

另一种选择是不时检查您的 AccessibilityService 是否启用:

AccessibilityManager am = (AccessibilityManager)
                               getSystemService(ACCESSIBILITY_SERVICE);

List<AccessibilityServiceInfo> listOfServices = 
                             am.getEnabledAccessibilityServiceList(
                               AccessibilityServiceInfo.FEEDBACK_ALL_MASK);

for (AccessibilityServiceInfo asi : listOfServices) 

    // Check if your AccessibilityService is running


如果 AccessibilityService 已被好奇/臭名昭著的用户禁用,您可以通过显示带有文本的全屏视图来锁定设备:Device has been locked. Contact a Sales Rep to unlock this device

【讨论】:

哇。大量信息,非常感谢。我明天某个时候会调查一下,然后告诉你我的结果。 我更新了我的问题。您的解决方案效果很好,但想要一种无需用户输入即可启用的方式。如果没有这样的事情,我肯定会使用AccessibilityService @Randy 很高兴知道。在每台设备上启用服务听起来确实是个问题。您可以做的最好的事情是:在第一次运行时将用户带到“辅助功能设置”页面。更多信息在这里:Link。希望有人能提出更好的解决方案。 @Randy Hey Randy,只是想知道这个解决方案是否确实可行 &|可实施。 这是我们最终实施的解决方案,但它并不完美。如果用户使用 Chrome 并滚动网页,则它不会注册为可访问性事件,因此我们不会将其视为用户交互。【参考方案2】:

我相信你必须返回 false 以表明你的透明服务窗口没有消耗触摸事件。这样,事件循环会将其向下传递到堆栈中的较低窗口。

https://developer.android.com/reference/android/view/View.OnTouchListener.html

另一种可能性是添加一个监听运动/加速度计事件的服务。

https://developer.android.com/guide/topics/sensors/sensors_motion.html

另一种可能是监听 ACTION_USER_PRESENT

https://developer.android.com/reference/android/content/Intent.html#ACTION_USER_PRESENT

或 ACTION_SCREEN_ON

https://developer.android.com/reference/android/content/Intent.html#ACTION_SCREEN_ON

【讨论】:

我知道的 OnTouchListener 不起作用。一旦你注册了一个监听器,窗口就会捕获点击,它并不关心哪个视图实际使用它。我真的很喜欢运动/加速度计的想法,但是,它不适用于我的应用程序。我正在开发一个信息亭应用程序,其中设备可能位于一个外壳中,从不移动。 另外请注意,如果简单地返回 false 工作,它会带来安全问题。您在 onTouch 事件中收到触摸类型和位置。而且,如果您可以在所有内容之上放置一个透明视图,您将能够准确判断触摸的位置(甚至在键盘上)。 @Randy Ok 添加了更多想法。 遗憾的是,这两种解决方案都不行。

以上是关于Android - 不活动/活动,无论***应用程序的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PhoneGap 应用启动时启动 Android 活动?

设备重新启动后,地理围栏是不是在 android 中保持活动状态

创建新活动错误:RED SQUIGGLYS EVERYWHERE

如何从活动中调用片段方法?

Android :: 需要在android应用程序恢复不活动时执行一些任务

在不强制用户登录/允许的情况下嵌入公共 Facebook 页面的活动源