方法1:使用内部apis
该方法和其他所有内部没有向外正式公布的apis一样存在它自己的风险。原理是通过获得windowmanager的一个实例来访问injectkeyevent/injectpointerevent这两个事件注入方法。
ibinder wmbinder = servicemanager.getservice( "window" );
iwindowmanager m_wndmanager = iwindowmanager.stub.asinterface( wmbinder );
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 );
发送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);
这种方法能在你的应用中很好的工作,但,也仅仅只能在你的应用中而已
一旦你想要往其他窗口注入keys/touch事件,你将会得到一个强制关闭的消息:
方法2: 使用instrumentation对象
相对以上的隐藏接口和方法,这个是比较干净(上面的是隐藏的,故需要用到android不干净不推荐的方法去获取)的方式,但不幸的事它依然有上面的jinect_events这个只有系统应用(基本上就是android自己提供的,如monkey)才被允许的权限问题。
instrumentation m_instrumentation = new instrumentation();
m_instrumentation.sendkeydownupsync( keyevent.keycode_b );
以下是触摸事件实例:
//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);
在应用内操作的话完全没有问题,但一旦跳出这个应用去触发按键事件的话就会崩溃。不是因为这个方法不工作,而是因为android开发人员做了限制。谢谢你们,android的开发者们,你牛逼!个屁。
通过分析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) {
}
}
方法3:直接注入事件到设备/dev/input/eventx
linux以系统设备的方式向用户暴露了一套统一的事件注入接口/dev/input/eventx(其中x代表一个整数)。我们可以直接跳用而跳过以上的平台(android这个机遇linux的平台)限制问题。但是这需要工作的话,你需要rooted过的设备。
设备文件eventx默认是被设置为660这个权限的(owner和同组成员有读写,而owner是root)。为了向这个设备注入事件,你必须让它能可写。所以请先做以下动作:
adb shell
su
chmod 666 /dev/input/event3
你将需要root权限来运行chmod命令。