【问题标题】:Detecting user activity in android检测android中的用户活动
【发布时间】:2014-02-11 14:09:10
【问题描述】:

我想检测用户最后一次与屏幕交互是什么时候。我对做任何恶意软件/间谍软件不感兴趣,只需要计算自用户上次点击屏幕以来已经过去了多少时间。

目标是实现类似于的功能。

我一直在做一些研究并关注网站上的一些问答(例如Android Best Way to Detect and Handle User INACTIVITYAndroid: Detect General Use by User 等),但是在检测 android 中的用户交互时,我还没有找到我需要的东西。

提前致谢。

【问题讨论】:

  • 虽然您可以为自己的活动检测到这一点,但我不知道您可以通过什么方式为整个系统检测到这一点,除非在有根设备上。
  • 我正在使用一种解决方案来检测我自己活动之外的每一次触摸。你可以给它一张支票吗?

标签: android user-interaction


【解决方案1】:

经过更多的研究和测试,我设法找到了解决方案。

我所做的是创建一个后台服务,在该服务中我得到一个 WindowManager 的实例并添加一个零大小的视图来通知用户 触及它之外......但是由于视图的大小为零,因此每次都可以调用它。 为此我们可以查看https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html

InactivityService.java 类检测用户每次点击屏幕并将其写入首选项,以便稍后在应用程序的其他组件中显示或使用。 请注意,我们可以广播时间,或将其传递给我们的应用程序对象或任何其他适合或需要的解决方案。

/**
 * Detects user taps on screen (user interaction).
 * 
 * @author Junior Buckeridge A.
 *
 */
public class InactivityService extends Service {

    protected static final String LOG_TAG = InactivityService.class.getSimpleName();
    private boolean isAdded = false;

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        if(!isAdded){
            WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                    0, 0, 0, 0,
                    WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                    PixelFormat.TRANSLUCENT);
            WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
            View view = new View(this);
            view.setOnTouchListener(new OnTouchListener() {

                @SuppressLint("DefaultLocale")
                @Override
                public boolean onTouch(View v, MotionEvent event) {

                    GregorianCalendar calendar = new GregorianCalendar();
                    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(InactivityService.this);
                    String log = prefs.getString(LOG_KEY, "");
                    log = String.format("User interaction detected at: %02d:%02d:%02d \n%s", 
                                calendar.get(Calendar.HOUR_OF_DAY),
                                calendar.get(Calendar.MINUTE),
                                calendar.get(Calendar.SECOND),
                                log);
                    prefs.edit().putString(LOG_KEY, log).commit();

                    return false;
                }
            });
            wm.addView(view, params);
        }

        return START_STICKY;
    }
}

我们应该在清单中添加以下权限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

同样值得一提的是,这种方法结合使用 ActivityManager 获取正在运行的任务是确定用户是否正在与手机交互的一种非常有效的方法。

【讨论】:

  • 拥有SYSTEM_ALERT_WINDOW 权限的用户将失去安全意识。我从不安装要求它并建议其他人也这样做的应用程序。在这种特殊情况下,似乎没有任何重大的隐私问题,因为提供给您的MotionEvent 是经过脑叶切除的(基于 4.4 模拟器上的轻量测试)。我不知道您是否会在使用同样使用这种技术的其他应用程序时遇到问题(例如,他们获取事件而不是您),但这不应该是该领域常见的所有问题。
  • 我知道它可以在许多用户中“触发警报”,但正如您所见,此代码没有安全问题(基于 android 文档)。无论如何,这是我找到实现目标的唯一方法。问候。
  • 谢谢;这行得通。但是,它仅检测触摸开始的时间。它不会检测到何时完成。
  • 哦,当用户触摸底部栏时,没有观察到触摸事件。
  • 请注意,这在 Android O 中会发生变化,并将始终在通知栏显示一个条目。此外,您需要在 Android 6 及更高版本中查询权限。
【解决方案2】:

您可以使用AccessibilityService,它可以让您监听点击、滚动和其他交互事件。一个限制是它不会报告原始触摸事件,除非它们触发操作。

【讨论】:

  • AccessibilityService 仅由用户在设备设置中明确打开服务触发。所以没有办法以编程方式打开它。
【解决方案3】:

我设法改进了 Junior Buckeridge 的解决方案,不再需要 SYSTEM_ALERT_WINDOW 权限。这个想法是一样的:我们添加一个接收所有 onpress 事件的视图。但我的解决方案只是在活动的 onCreate 中添加此视图,并在创建 LayoutParams 时使用 WindowManager.LayoutParams.TYPE_APPLICATION 而不是 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT。

    WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            0, 0, 0, 0,
            WindowManager.LayoutParams.TYPE_APPLICATION,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSLUCENT);
    WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
    View view = new View(this);
    view.setOnTouchListener(new View.OnTouchListener() {

        @SuppressLint("DefaultLocale")
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Log.d("Test", "Hello World!");

            return false;
        }
    });
    wm.addView(view, params);

【讨论】:

    【解决方案4】:

    所以我正在使用@Junior Buckeridge 解决方案,但实际上我遇到了崩溃,因为我们不允许在应用程序窗口上绘图。 (错误令牌异常)

    真正帮助我的是什么:

    windowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
    //here is all the science of params
    final LayoutParams myParams = new LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            LayoutParams.TYPE_SYSTEM_ERROR,
            WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                    | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
            PixelFormat.TRANSLUCENT
    );
    

    在您的活动中:

     if(Build.VERSION.SDK_INT >= 23) {
    if (!Settings.canDrawOverlays(Activity.this)) {
        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                Uri.parse("package:" + getPackageName()));
        startActivityForResult(intent, 1234);
    
    
       }
    }else{
        Intent intent = new Intent(Activity.this, Service.class);
        startService(intent);
    }
    

    并添加:

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    

    来源: Android: Unable to add window. Permission denied for this window type (阿南安萨里的回答)

    【讨论】:

      猜你喜欢
      • 2011-05-11
      • 1970-01-01
      • 1970-01-01
      • 2011-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-13
      相关资源
      最近更新 更多