2

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

我尝试了多种方法:

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

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

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


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

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


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

4

2 回答 2

3

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

以下是 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:

  1. 在代码中,在 onServiceConnected() 内部。(API 4 以上)

  2. 在 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 之前给定类型的最新事件之后的超时。

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

因此,请慷慨地设置超时值。

如果您决定使用 AccessibilityService 选项,您会发现此页面非常有用:开发可访问性服务

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

无障碍服务的生命周期完全由系统管理,并遵循既定的服务生命周期。此外,启动或停止可访问性服务仅由显式用户操作通过在设备设置中启用或禁用来触发

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

另一种选择是检查您的 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.

于 2013-09-25T22:53:01.257 回答
1

我相信您必须返回 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

于 2013-09-19T02:39:48.627 回答