2011-07-15 82 views
58

我想知道SwipePad和Wave Launcher等应用程序如何通过服务简单地检测触摸手势/事件。即使这些应用不在自己的活动中,这些应用也能够检测到触摸手势。我已经浏览了整个互联网,并没有找到他们如何做到这一点。服务如何监听触摸手势/事件?

我的主要问题是服务如何能够监听客户端/事件,就像普通Activity可能会接收到MotionEvents一样,即使它可能不在原始的Activity或上下文中。我基本上正在尝试构建一个应用程序,该应用程序将识别来自用户的特定触摸手势,而不管哪个活动位于顶部,并在该手势被识别时执行某些操作。触摸重新分配将作为服务在后台运行。

+1

SwipePad看起来可能只是对可触摸区域使用透明系统警报窗口而不是整个屏幕。 – Sam

回答

5

有趣的问题。我不知道他们是怎么做到的,我发现谷歌的帖子告诉我,没有全球触摸监听器。但我有一个想法反正...

我发现this post某人成功显示从服务的popupwindow。如果我将弹出的透明和全屏,我敢肯定我可以捕捉触摸,因为我可以设置一个touch interceptor

编辑:当您尝试,将是有趣的知道这是否正常工作,请报告结果...

+0

这似乎是一个有趣的方法。我已经看到PopupWindows以前用于类似的事情,但我将不得不尝试一下。目前,我感到沮丧的是,从服务获取触摸事件有多困难。在我有机会尝试这一点之前还需要一段时间,但我会让你知道它是怎么回事! – Brian

+0

我刚试过这个,我甚至无法看到提示对话框。 'show'方法抛出了'BadTokenException'。 – Sam

+0

异常消息是“无法添加窗口 - 标记null无效;你的活动正在运行吗?' – Sam

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

耶!

+0

这会干扰用户点击他们认为他们正在查看的活动中的按钮的能力 – ChuckKelly

+0

@ChuckKelly是的,它会干扰 –

+3

我想从服务中听水龙头,服务附带一个活动。活动照常使用,但服务保持记录水龙头。当使用TYPE_SYSTEM_OVERLAY时,它在Android 2.3上的工作非常好,但在4.1上,onTouchEvent未被调用。使用TYPE_SYSTEM_ALERT时,会调用onTouchEvent,但触摸事件不会传递给该活动,并且它变得无响应。请帮助 –

2

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

所以我做了一些逆向工程和现在发布解决方案,它的工作原理

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); 
+0

这似乎只适用于第一个视图/活动。不适用于以后创建的活动。我得到以下警告: W/ViewRootImpl:由于没有窗口焦点而导致的事件丢失:MotionEvent {action = ACTION_OUTSIDE,actionButton = 0,id [0] = 0,x [0] = 0.0,y [0] = 0.0,toolType [0] = TOOL_TYPE_FINGER,buttonState = 0,metaState = 0,flags = 0x0,edgeFlags = 0x0,pointerCount = 1,historySize = 0,eventTime = 220247332,downTime = 220247332,deviceId = 4,source = 0x1002} –

3

我测试了这个在API 21和Nexus 5的,我是能够登录,从服务,当触摸事件被解雇由系统。但是,当我看到应用程序包的外观时,MotionEvent对象中的数据(例如坐标)返回0.0。

两个来源 integrationpermission

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

编辑

该解决方案并不能阻止其他侦听器接收,因为

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

服务capured触摸事件通过返回假的,它允许其他听众接收事件。

EDIT2

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

+0

一种解决这个问题的方法?像动态改变UID? – keinabel

+0

除非你有自己的操作系统,否则我不认为这是可能的。也许如果服务被注册为系统服务?我的意思是这些值在那里,但操作系统将删除感兴趣的值并将触摸事件传播给其他任何听众。 – Clocker