Android monkey改造分析 (base uiautomation)
(1)看monkey就要看它底层如何触发操作,下面列举了几个send MotionEvent 的方法。
我们可以看到包括monkey和一些自动化框架都是基于什么去操作页面的。
Send Event
1.Monkey
MotionEvent me = getEvent(); InputManager.getInstance().injectInputEvent(me, 1)
2.Instrumentation
Instrumentation inst = new Instrumentation(); inst.sendPointerSync
3.Uiautomation
mUiAutomation.injectInputEvent
(2)改造
1.保留monkey的event分发机制
public MonkeySourceRandom(Random random, ArrayList<ComponentName> MainApps, long throttle, boolean randomizeThrottle, Display display) { // default values for random distributions // note, these are straight percentages, to match user input (cmd line // args) // but they will be converted to 0..1 values before the main loop runs. mFactors[FACTOR_TOUCH] = 47.0f; mFactors[FACTOR_MOTION] = 10.0f; mFactors[FACTOR_TRACKBALL] = 30.0f; mFactors[FACTOR_NAV] = 0.0f; mFactors[FACTOR_MAJORNAV] = 5.0f; mFactors[FACTOR_SYSOPS] = 2.0f; mFactors[FACTOR_APPSWITCH] = 0.0f; mFactors[FACTOR_FLIP] = 1.0f; mFactors[FACTOR_ANYTHING] = 3.0f; mFactors[FACTOR_PINCHZOOM] = 2.0f; mRandom = random; mMainApps = MainApps; mQ = new MonkeyEventQueue(random, throttle, randomizeThrottle); mDisplay = display; }
private void generateEvents() { float cls = mRandom.nextFloat(); int lastKey = 0; if (cls < mFactors[FACTOR_TOUCH]) { generatePointerEvent(mRandom, GESTURE_TAP); return; } else if (cls < mFactors[FACTOR_MOTION]) { generatePointerEvent(mRandom, GESTURE_DRAG); return; } else if (cls < mFactors[FACTOR_PINCHZOOM]) { generatePointerEvent(mRandom, GESTURE_PINCH_OR_ZOOM); return; } else if (cls < mFactors[FACTOR_TRACKBALL]) { generateTrackballEvent(mRandom); return; }
2.由于InputManager在安卓中无法直接调用,所以我们可以用Instrumentation或者Uiautomation去做操作。
再一步分析Instrumentation的Send Event只能基于app本身去操作(安卓权限问题,如果操作其他应用需要系统权限)
我们可以直接用uiautomator2.0,通过instrumentation获取Uiautomation
this.mInstrumentation = instrumentation; this.mUiDevice = UiDevice.getInstance(instrumentation);
调用:
public boolean injectInputEvent(InputEvent event, boolean sync) { synchronized (mLock) { throwIfNotConnectedLocked(); } try { if (DEBUG) { Log.i(LOG_TAG, "Injecting: " + event + " sync: " + sync); } // Calling out without a lock held. return mUiAutomationConnection.injectInputEvent(event, sync); } catch (RemoteException re) { Log.e(LOG_TAG, "Error while injecting input event!", re); } return false; }
3.改进
1.例如点击区域
2.点击方式
3.去掉一些无意义的keyevent
4.增加一些监听,例如页面死循环监听(图片对比),activity切换监听