标签:截取 border sdn lap action_up 进程启动 方法 模拟 view
本系列的上一篇文章《Monkey源代码分析之事件源》中我们描写叙述了monkey是怎么从事件源取得命令。然后将命令转换成事件放到事件队列里面的。可是到如今位置我们还没有了解monkey里面的事件是怎么一回事,本篇文章就以这个问题作为切入点。尝试去搞清楚monkey的event架构是怎么样的。然后为什么是这样架构的,以及它又是怎么注入事件来触发点击等动作的。
在看这篇文章之前,希望大家最好先去看下另外几篇博文,这样理解起来就会更easy更清晰了:
public class MonkeyKeyEvent extends MonkeyEvent { private long mDownTime = -1; private int mMetaState = -1; private int mAction = -1; private int mKeyCode = -1; private int mScancode = -1; private int mRepeatCount = -1; private int mDeviceId = -1; private long mEventTime = -1; private KeyEvent keyEvent = null; public MonkeyKeyEvent(int action, int keycode) { super(EVENT_TYPE_KEY); mAction = action; mKeyCode = keycode; } public MonkeyKeyEvent(KeyEvent e) { super(EVENT_TYPE_KEY); keyEvent = e; } public MonkeyKeyEvent(long downTime, long eventTime, int action, int code, int repeat, int metaState, int device, int scancode) { super(EVENT_TYPE_KEY); mAction = action; mKeyCode = code; mMetaState = metaState; mScancode = scancode; mRepeatCount = repeat; mDeviceId = device; mDownTime = downTime; mEventTime = eventTime; }MonkeyKeyEvent有多个构造函数,參数都不一样,可是目的都仅仅有一个,通过传进来的參数获得足够的信息保存成成员变量。以便今后创建一个android.view.KeyEvent,皆因该系统事件就是能够依据不同的參数进行初始化的。比方以下的getEvent方法就是依据不同的參数创建相应的KeyEvent的。注意这系统KeyEvent是很重要的,由于我们今后通过WindowManager注入事件就要把它的对象传进去去驱动相应的按键相关的事件。
* @return the key event */ private KeyEvent getEvent() { if (keyEvent == null) { if (mDeviceId < 0) { keyEvent = new KeyEvent(mAction, mKeyCode); } else { // for scripts keyEvent = new KeyEvent(mDownTime, mEventTime, mAction, mKeyCode, mRepeatCount, mMetaState, mDeviceId, mScancode); } } return keyEvent; }支持的成员变量比較多,名字都挺浅显易懂,我这里就简单描写叙述两个我们最经常使用的:
public static final int KEYCODE_MENU = 82;
private int run(String[] args) { ... if (!getSystemInterfaces()) { return -3; } .... }那么我们进入该方法看下我们须要的WindowManager是怎么初始化的。
private boolean getSystemInterfaces() { mAm = ActivityManagerNative.getDefault(); if (mAm == null) { System.err.println("** Error: Unable to connect to activity manager; is the system " + "running?"); return false; } mWm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); if (mWm == null) { System.err.println("** Error: Unable to connect to window manager; is the system " + "running?"); return false; } mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); if (mPm == null) { System.err.println("** Error: Unable to connect to package manager; is the system " + "running?"); return false; } try { mAm.setActivityController(new ActivityController()); mNetworkMonitor.register(mAm); } catch (RemoteException e) { System.err.println("** Failed talking with activity manager!"); return false; } return true; }
这里事实上我们真正值得关注的就是WindowManager这个类,由于我们注入真实时间的时候事实上就是调用了它的方法。其它的类事实上在我们这篇文章中并没实用到的,可是既然看到了就顺便了解下吧。
在ServiceManager中有两个比較重要的方法:add_service、check_service。系统的service须要通过add_service把自己的信息注冊到ServiceManager中。当须要使用时,通过check_service检查该service是否存在
我们定位到injectEvent这种方法。
@Override public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) { if (verbose > 1) { String note; if (mAction == KeyEvent.ACTION_UP) { note = "ACTION_UP"; } else { note = "ACTION_DOWN"; } try { System.out.println(":Sending Key (" + note + "): " + mKeyCode + " // " + MonkeySourceRandom.getKeyName(mKeyCode)); } catch (ArrayIndexOutOfBoundsException e) { System.out.println(":Sending Key (" + note + "): " + mKeyCode + " // Unknown key event"); } } // inject key event try { if (!iwm.injectKeyEvent(getEvent(), false)) { return MonkeyEvent.INJECT_FAIL; } } catch (RemoteException ex) { return MonkeyEvent.INJECT_ERROR_REMOTE_EXCEPTION; } return MonkeyEvent.INJECT_SUCCESS; }注意传入參数
@Override public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) { if (verbose > 1) { System.out.println("Sleeping for " + mThrottle + " milliseconds"); } try { Thread.sleep(mThrottle); } catch (InterruptedException e1) { System.out.println("** Monkey interrupted in sleep."); return MonkeyEvent.INJECT_FAIL; } return MonkeyEvent.INJECT_SUCCESS; }所以尽管不同的MonkeyEvent实现类都实现了父类的injectEvent方法,可是并非全部的的MonkeyEvent都须要注入事件的。全部这个接口方法的名字我认为Google project师起得不好,比方叫做handleEvent就不会造成混乱了(个人见解)
事件处理方式 |
MonkeyEvent实现类 |
关键代码 |
凝视 |
通过WindowManager注入事件 |
MonkeyKeyEvent |
injectKeyiwm.injectKeyEvent(getEvent(),false)Event |
|
MonkeyTouchEvent |
iwm.injectPointerEvent(me,false) |
|
|
MonkeyTrackballEvent |
iwm.injectTrackballEvent(me,false) |
|
|
通过往事件设备/dev/input/event0发送命令注入事件 |
MonkeyFlipEvent |
FileOutputStream("/dev/input/event0") |
|
通过ActvityManager的startInstrumentation方法启动一个应用 |
MonkeyInstrumentationEvent |
iam.startInstrumentation(cn,null, 0,args,null) |
|
睡眠 |
MonkeyThrottleEvent |
Thread.sleep(mThrottle) |
|
MonkeyWaitEvent |
Thread.sleep(mWaitTime) |
|
所以Monkey在这里既扮演饿Command角色,又扮演了Invoker这个角色。
monkey中就是把全部的事件抽象成MonkeyEvent然后放到我们的EventQueque里面的
只是假设用在文档编辑的undo功能中应该是挺不错的
标签:截取 border sdn lap action_up 进程启动 方法 模拟 view
原文地址:http://www.cnblogs.com/yfceshi/p/6866960.html