Android Mutlitouch Input Architecture

現在的任務是要在Android 上面啟用 Mutlitouch的功能,首先找了一下網路上的做法,要改Synaptics的Driver,因為G1是使用Snaptics的觸控版,在別人patch過的很明顯可以看到Driver可以拿到兩個座標,可是Android所定義的 MotionEvent只能傳遞X, Y, Pressure, Size,Size的定義是觸控版手指頭上面壓下去之後的圈圈大小,這個值可能沒甚麼用,人家就拿來給Mutlitouch應用了。

先說明修改過之後 User看到的是甚麼,如果收到的Size <=1 的話,那麼就是代表是 Single Touch,否則 X, Y 就是兩個點的中心點,Size的左 16 bit 則是 abs(x1-x2), 右 16 bit則是 abs(y1-y2),這樣在User Level就可以得到旋轉跟放大縮小。

目前只有iPhone的SDK是可以直接把點座標全部傳給User Level去,這樣如果要作多人遊戲的話,才可以使用座標,特地看了一下Windows 7 的SDK,看起來在 .Net 新增的 NameSpace: Windows7.Mutlitouch 也是沒有傳遞多點座標,只有Rotate 跟 Zoom 的事件,我沒有實際寫程式試試,可能有辦法取得座標也不一定。

透過Synaptics 的source 發現他是使用

input_report_abs(ts->input_dev, ABS_X, x); 來傳遞值的,所以就找ABS_X是在哪裡定義的,在linux/include/linux/input.h 下面有定所有輸入的值為何,可以看到絕對值系列還有一個ABS_RX,原本是給搖桿用的,但透過這個值,我們應該可以傳遞兩個座標了。

Driver回報上去之後,User Level要怎麼接收呢?我以為是某一個類似scanf的函式,找到就OK了,freedom問file descriptor 是甚麼?我才想到把file operations串起來的就是要透過file descriptor,試了一下G1,發現他的TouchPanel 是 /dev/input/event2,所以我就在Android Source裡面搜尋 /dev/input,發現了 EventHub.cpp 這個檔案,在此檔案裡面搜尋一下有沒有讀 ABS_X的Code,沒想到竟然沒有,但整個frameworks也沒有其他地方會開啟/dev/input啦。再試一下 Touch,喔~看到東西了,會根據下層傳上來的某個bit判斷此device是不是 TouchScreen,然後設定其 Classes 為 CLASS_TOUCHSCREEN。EventHub跟Driver中間是 Linux Input SubSystem,有興趣的可以自己查網路,有滿好的分析。

接下來要找出EventHub上面那一層,在JAVA環境要用C讀取系統資訊要透過JNI,使用EventHub.cpp 裡面的某一個函式 getAbsoluteInfo,就找到了KeyInputQueue.java 跟 com_android_server_KeyInputQueue.cpp,所以是KeyInputQueue這個Class會來跟 EventHub讀取資料,KeyInputQueue裡面有一個 run 的函式會使用while(true) 一直 readEvent,然後看到此Class有定義一個叫做 getEvent的function,應該是給上層呼叫的,就再用此為關鍵字搜尋找到 WindowManagerService,一樣也是透過一個while(true) 從 KeyInputEvent讀event上來,再根據是甚麼類型的輸入呼叫不同的dispatch[Key|Pointer|Trackball],while 裡面就找到現在的前景視窗,檢查一下權限,就把event傳給他了,我查到是 IWindow 有定義了dispatch[Key|Pointer|Trackball],但找不到是哪個class有實作,目前猜上面還有 ViewRoot 跟 View,會檢查User Program有沒有設定相關的listener,如果就傳遞data過去。

這裡比較特別的是,我以為會像底層driver一樣一次拿到byte array,然後根據第幾欄位是甚麼資料寫入相對應的欄位,沒想到在 KeyInputQueue 讀取 X, Y, Pressure, Size 的時候竟然是分次讀取

absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_X, "X");

absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_Y, "Y");

absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_PRESSURE, "Pressure");

absSize = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_TOOL_WIDTH, "Size");

熊熊想起,Driver在將資訊往上報的時候也是一個一個報的啊,input_report_abs

 

而且我不應該自己搜尋source的,在 google 上搜尋 Android input 流程,就會有人家說流程是怎麼呼叫的了,結果我都快找完了才看到google,衰~

myandroid/frameworks/base/services/java/com/android/server/InputDevice.java

有把軌跡球轉成key event 的函式

接下來分析一下如果要讓我們的User Program可以讀到多點座標要怎麼辦,目前看起來 Android Framework從下面讀取的資料只有 X, Y, Pressure, Size,如果不想改Android Framework的話,那我們就要自己encode Data了,ex: 把 X左16 bit存X1, 右 16bit 存 X2,使用模擬器,除非解析度會大於65535才有問題,但要犧牲一點精確度就是了。原本X 的type 是 float。如果像我的主管要求要能支援三個點以上的話,那就麻煩了,首先Linux沒有定義那麼多Data Type,linux/include/linux/input.h,如果還要透過標準的Linux Input SubSystem的Interface的話,我覺得要改的東西還滿多的,而且還要想辦法encode 座標。像是driver一次就是回報n個點,如果沒按那麼多的話,該點就填-1,-1 之類的。然後 Android Framework 也要extend MotionEvent給他多一個ArrayList 來存多點座標。

檔案路徑:

myandroid/frameworks/base/libs/ui/EventHub.cpp

myandroid/frameworks/base/core/java/android/view/MotionEvent.java

myandroid/frameworks/base/services/java/com/android/server/KeyInputQueue.java

myandroid/frameworks/base/services/jni/com_android_server_KeyInputQueue.cpp

myandroid/frameworks/base/services/java/com/android/server/WindowManagerService.java

myandroid/frameworks/base/core/java/android/view/View.java

google 可以搜尋的關鍵字

linux 內核輸入子系統分析、Android 輸入事件流程、Android 輸入流程分析、輸入子系統 event、Android Input Event Dispatching、Android Event 傳遞流程

This entry was posted in 工作. Bookmark the permalink.

4 Responses to Android Mutlitouch Input Architecture

  1. 之雄 says:

    寫得真好~厲害可不可以請教一下~不知道你有沒有分析過為什麼iphone手機的觸控反應到目前為止還是比Android任一手機還來的快(不會像android有種lag的感覺,儘管已經把所有其他的AP都kill掉,也把3party的軟體都移除掉了還是會頓頓的)不知道這是不是跟Android的framework有直接關係?還有請問圖中底下的 "I2C" 是甚麼意思?謝謝

  2. cary says:

    您好!請問一下你有完成讓Android支援三個點以上的程式嗎?最近老闆要求要支援10點座標,原本跟你最初的想法一樣用陣列傳,改到JAVA程式就卡住了,用ABS_HAT1X、ABS_HAT2X、ABS_HAT3X傳,到KeyInputQueue.java 資料就不見了,不知道要改哪些地方,希望能指點一下,謝謝!

  3. 浩洋 says:

    sorry,現在才回應,cary,因為Android 系統只讀Single Touch的四個值而已,X Y Pressure Size,所以你的Driver只能回報這四種資料,當然,這裡的Pressure的實際意義你可以自己定義,只要你寫的apk知道是甚麼就好~杜之雄的問題沒想過,我用hero初始機覺得也滿快的,反而ipod用久之後也會變慢XDI2C 是 某種BUS,可以搜尋一下wiki

  4. Jackson says:

    com_android_server_KeyInputQueue.cpp此檔案在2010年的時候移除了!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s