原文:http://www.pocketmagic.net/2012/04/injecting-events-programatically-on-android/#.VEoIoIuUcaV

往下分析monkey事件注入源码之前先了解下在android系统下事件注入的方式,翻译一篇国外文章如下。


Method 1: Using internal APIs

方法1:使用内部APIs
This 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 down m_WndManager.injectKeyEvent( new KeyEvent( KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A ),true ); // key up m_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 HEIGHT m_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

这种方法能在你的应用中很好的工作,但,也仅仅只能在你的应用中而已
Monkey源码分析番外篇之Android注入事件的三种方法比较_第1张图片
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事件,你将会得到一个强制关闭的消息:
Monkey源码分析番外篇之Android注入事件的三种方法比较_第2张图片

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 HEIGHT m_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);
Monkey源码分析番外篇之Android注入事件的三种方法比较_第3张图片
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)。为了向这个设备注入事件,你必须让它能可写。所以请先做以下动作:
Monkey源码分析番外篇之Android注入事件的三种方法比较_第4张图片

adb shell su chmod 666 /dev/input/event3 
You will need root to run the chmod command.

你将需要root权限来运行chmod命令。


 

作者

自主博客

微信

CSDN

天地会珠海分舵

http://techgogogo.com


服务号:TechGoGoGo

扫描码:

©著作权归作者所有:来自51CTO博客作者zhukev的原创作品,如需转载,请注明出处,否则将追究法律责任

Monkey InjectEvent Instrumentation

0

收藏

上一篇:Monkey源码分析之事件注入 下一篇:Monkey源码分析番外篇之Wi...
noavatar_middle.gif
zhukev

117篇文章,7W+人气,0粉丝

noavatar_middle.gif

Ctrl+Enter 发布

发布

取消

猜你喜欢

我的友情链接 最新HTML BroadcastChannel API引荐 Matrix源码分析之第一篇 使用LiveDataBus进行组件通信,让你永无后顾之忧 React Native集成到Android项目当中 面试经历:记一次Android面试 Android:实现模块 api 化 在Android中集成flutter 带你深入理解Android中的自定义属性!!! 程序员笔记|JSBridge框架解决通信问题实现移动端跨平台开发 Java注解实战之APT构建模块化的第一步 怎么让软键盘弹出时,部分控件上移 MVVM 架构与数据绑定库 Android自定义Dialog及与Activity的交互 开发十年,就只剩下这套架构体系了! Flutter交互实战-即刻App探索页下拉&拖拽效果 Fragments片段
left-qr.jpg

扫一扫,领取大礼包

0

分享
zhukev
noavatar_middle.gif