服务如何监听触摸手势/事件?

时间:2011-07-15 22:57:09

标签: android events service touch gesture

我想知道像SwipePad和Wave Launcher这样的应用程序如何能够通过服务检测触摸手势/事件。这些应用程序能够检测到触摸手势,即使它不在自己的活动中。我看过整个互联网,但没有找到他们如何做到这一点。

我的主要问题是服务如何监听触摸客户/事件,就像常规活动可能会收到MotionEvent一样,即使它可能不在原始活动或上下文中。我本质上是在尝试构建一个应用程序,它将从用户那里重新获得特定的触摸手势,无论哪个Activity位于顶部,并在该手势被识别时执行某些操作。触摸重现将是一个在后台作为服务运行的线程。

5 个答案:

答案 0 :(得分:18)

我遇到了同样的问题,我终于弄明白了!感谢这篇文章:Creating a system overlay window (always on top)。您需要使用警报窗口而不是叠加层(这也意味着您可以在Andoid ICS中使用它):

WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                PixelFormat.TRANSLUCENT);

然后以这种方式附加一个GestureListener:

GestureDetector gestureDetector = new GestureDetector(this, new AwesomeGestureListener());
View.OnTouchListener gestureListener = new View.OnTouchListener() {
      public boolean onTouch(View v, MotionEvent event) {
            return gestureDetector.onTouchEvent(event);
      }
};

overlayView.setOnTouchListener(gestureListener);

耶!

答案 1 :(得分:5)

有趣的问题。我不知道他们是怎么做到的,我发现谷歌小组的帖子告诉我没有全球性的触摸倾听者。但无论如何我有一个想法......

我发现this post有人成功地从服务中显示弹出窗口。如果我将该弹出窗口设置为透明和全屏,我确信我可以捕获触摸,因为我可以设置touch interceptor

修改:请在尝试时报告结果,知道这是否有效会很有趣......

答案 2 :(得分:3)

我测试了所有可能的解决方案,但没有任何工作,有些没有触发触摸事件,他们冻结了屏幕。

所以我做了一些逆向工程,现在发布有效的解决方案

  WindowManager.LayoutParams params = new android.view.WindowManager.LayoutParams(0, 0, 0, 0, 2003, 0x40028, -3);
        View mView = new View(this);

        mView.setOnTouchListener(this);

        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(mView, params);

答案 3 :(得分:3)

我在API 21和nexus 5上对此进行了测试,并且当系统触发触摸事件时,我能够从服务中记录。但是,MotionEvent对象内的数据(例如坐标)在看似我应用程序包的OUTSIDE时返回0.0。

两个来源  integration,  permission

我很好奇为什么event.getX(),event.getY()和event.getPressure()在不在服务所在应用的活动中时返回0.0。

修改

此解决方案不会阻止其他侦听器因

而接收由服务承保的触摸事件
public boolean onTouch(View v, MotionEvent e){
    Log.d(LOG_TAG, "Touch event captured");
    return false;      

通过返回false,它允许其他侦听器接收事件。

<强> EDIT2

显然,如果当前活动和监听器不共享UID,OS中的输入调度程序会将坐标和压力设置为0,这里是source

答案 4 :(得分:0)

我已经搜索了很多SO线程,但出于安全考虑,我不认为这对系统上的所有软件包都有可能。它当然适用于您自己的应用程序。

窗口管理

 WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
            WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSLUCENT);

浮动/叠加布局

floatyView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate
            (R.layout.floating_view, null);

    floatyView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Log.d(TAG, "event.x " + event.getX());
            Log.d(TAG, "event.y " + event.getY());
            if (event.getAction() == MotionEvent.ACTION_UP) {
                v.performClick();
            }
            return false;
        }
    });

布局

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:background="@android:color/transparent"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>