首页 文章

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

提问于
浏览
58

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

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

5 回答

  • 18

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

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

    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);
    
  • 5

    我搜索了很多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"/>
    
  • 3

    我有同样的问题,我终于搞清楚了!感谢这篇文章: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);
    

    好极了!

  • 3

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

    两个来源integrationpermission

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

    Edit

    此解决方案不会阻止其他侦听器接收由服务承保的触摸事件

    public boolean onTouch(View v, MotionEvent e){
        Log.d(LOG_TAG, "Touch event captured");
        return false;
    

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

    Edit2

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

  • 0

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

    我找到this post,有人成功地从服务中显示一个弹出窗口 . 如果我将该弹出窗口设为透明和全屏,我允许'm sure I could capture the touches since I' m设置touch interceptor .

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

相关问题