2011-07-15 40 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