標籤:
原文:http://www.pocketmagic.net/2012/04/injecting-events-programatically-on-android/#.VEoIoIuUcaV 往下分析monkey事件注入源碼之前先瞭解下在android系統下事件注入的方式,翻譯一篇國外文章如下。
Method 1: Using internal APIs方法1:使用內部APIsThis approach has its risks, like it is always with internal, unpublished APIs.
該方法和其他所有內部沒有向外正式公布的APIs一樣存在它自己的風險。 The idea is to get an instance of WindowManager in order to access the injectKeyEvent / injectPointerEvent methods. 原理是通過獲得WindowManager的一個執行個體來訪問injectKeyEvent/injectPointerEvent這兩個事件注入方法。
IBinder wmbinder = ServiceManager.getService( "window" ); IWindowManager m_WndManager = IWindowManager.Stub.asInterface( wmbinder );
The ServiceManager and WindowsManager are defined as Stubs. We can then bind to these services and call the methods we need. ServiceManager和Windowsmanager被定義為存根Stubs類。我們根據我們的需要綁定上這些服務並訪問裡面的方法。 To send a key do the following: 通過以下方式發送一個事件:
// key downm_WndManager.injectKeyEvent( new KeyEvent( KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A ),true );// key upm_WndManager.injectKeyEvent( new KeyEvent( KeyEvent.ACTION_UP, KeyEvent.KEYCODE_A ),true );
To send touch/mouse events use: 發送touch/mouse事件:
//pozx goes from 0 to SCREEN WIDTH , pozy goes from 0 to SCREEN HEIGHTm_WndManager.injectPointerEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis(),MotionEvent.ACTION_DOWN,pozx, pozy, 0), true);m_WndManager.injectPointerEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis(),MotionEvent.ACTION_UP,pozx, pozy, 0), true);
This works fine, but only inside your application 這種方法能在你的應用中很好的工作,但,也僅僅只能在你的應用中而已 The moment you‘re trying to inject keys/touch events to any other window, you‘ll get a force close because of the following exception: 一旦你想要往其他視窗注入keys/touch事件,你將會得到一個強制關閉的訊息:
E/AndroidRuntime(4908): java.lang.SecurityException: Injecting to another application requires INJECT_EVENTS permission
Not much joy, as INJECT_EVENTS is a system permission. A possible solution is discussed here and here. 苦逼了吧,畢竟INJECT_EVENTS是需要系統許可權的,一些可能解決的方案在這裡和這裡有討論到。 (譯者註:請查看本人上一篇翻譯的《Monkey源碼分析番外篇之WindowManager注入事件如何跳出進程間安全限制》裡面有更詳細針對這個問題的描述)
Method 2: Using an instrumentation object方法2: 使用instrumentation對象
This is a clean solution based on public API, but unfortunately it still requires that INJECT_EVENTS permission. 相對以上的隱藏介面和方法,這個是比較乾淨(上面的是隱藏的,故需要用到android不乾淨不推薦的方法去擷取)的方式,但不幸的事它依然有上面的JINECT_EVENTS這個只有系統應用(基本上就是android自己提供的,如monkey)才被允許的許可權問題。
Instrumentation m_Instrumentation = new Instrumentation();m_Instrumentation.sendKeyDownUpSync( KeyEvent.KEYCODE_B );
For touch events you can use: 以下是觸摸事件執行個體:
//pozx goes from 0 to SCREEN WIDTH , pozy goes from 0 to SCREEN HEIGHTm_Instrumentation.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis(),MotionEvent.ACTION_DOWN,pozx, pozy, 0);m_Instrumentation.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis(),MotionEvent.ACTION_UP,pozx, pozy, 0);
All good inside the test application, and will crash instantly when trying to inject keys to outside apps, not because the approach doesn‘t work, but because Android Developers have chosen so. Thanks guys, you rock! Not. 在應用內操作的話完全沒有問題,但一旦跳出這個應用去觸發按鍵事件的話就會崩潰。不是因為這個方法不工作,而是因為android開發人員做了限制。謝謝你們,android的開發人員們,你牛逼!個屁。 By looking at sendPointerSync‘s code, you will quickly see it uses the same approach as presented in method 1). So this is the same thing, but packed nicely in a easy to use API: 通過分析sendPointerSync的對應代碼,可以看到其實instrumentation使用到的注入事件方式其實和方法一提到的通過WindowManager.injectPointerEvents是一樣的,所以穿的都是同一條內褲,只是Robotium出來走動的時候套上條時尚喇叭褲,而以上直接調用WindowManager的方式就猶如只穿一條內褲出街的區別而已。
public void sendPointerSync(MotionEvent event) {validateNotAppThread();try {(IWindowManager.Stub.asInterface(ServiceManager.getService("window"))).injectPointerEvent(event, true);} catch (RemoteException e) {}}Method 3: Direct event injection to /dev/input/eventX方法3:直接注入事件到裝置/dev/input/eventX
Linux exposes a uniform input event interface for each device as /dev/input/eventX where X is an integer. We can use it directly and skip the above Android Platform permission issues. linux以系統裝置的方式向使用者暴露了一套統一的事件注入介面/dev/input/eventX(其中X代表一個整數)。我們可以直接跳用而跳過以上的平台(android這個機遇linux的平台)限制問題。 For this to work, we will need root access, so this approach only works on a rooted device. 但是這需要工作的話,你需要rooted過的裝置。 By default the eventX files have the permission set for 660 (read and write for Owner and Group only). To inject keys from our application, we need to make it writable. So do this first: 裝置檔案eventX預設是被設定為660這個許可權的(Owner和同群組成員有讀寫,而owner是root)。為了向這個裝置注入事件,你必須讓它能可寫。所以請先做以下動作:
adb shellsuchmod 666 /dev/input/event3
You will need root to run the chmod command. 你將需要root許可權來運行chmod命令。
| 作者 |
自主部落格 |
服務號及掃描碼 |
CSDN |
| 天地會珠海分舵 |
http://techgogogo.com |
服務號:TechGoGoGo掃描碼: |
http://blog.csdn.net/zhubaitian |
Monkey源碼分析番外篇之Android注入事件的三種方法比較