uiautomator一个简单的脚本
public class UiautomatorTest extends UiAutomatorTestCase{
public void testDemo() throws UiObjectNotFoundException {
// 模拟 HOME 键点击事件
getUiDevice().pressHome();
}
1、uiautomatorTest继承于UiAutomatorTestCase,通过父类获得Uidevice类实例,并调用父类方法pressHome();
2、查看pressHome方法源码
/**
* Simulates a short press on the HOME button.
* @return true if successful, else return false
* @since API Level 16
*/
public boolean pressHome() {
Tracer.trace();
waitForIdle();
return getAutomatorBridge().getInteractionController().sendKeyAndWaitForEvent(
KeyEvent.KEYCODE_HOME, 0, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED,
KEY_PRESS_EVENT_TIMEOUT);
}
getAutomatorBridge()方法获得InstrumentationUiAutomatorBridge实例,UiDevice类保存了
InstrumentationUiAutomatorBridge getAutomatorBridge() {
if (mUiAutomationBridge == null) {
throw new RuntimeException("UiDevice not initialized");
}
return mUiAutomationBridge;
}
3、先来看下UiAutomatorBridge类何时初始化的还有InteractionController对象又是什么?
/**
* @hide
*/
public void initialize(InstrumentationUiAutomatorBridge uiAutomatorBridge) {
mUiAutomationBridge = uiAutomatorBridge;
}
这个是隐藏的方法,初始化UiDevice类时直接传入UiAutomatorBridge对象,那么改函数何时执行尼?
查看源码发现这个函数是在UiDevice类里面调用的
/**
* Initializes this test case.
*
* @param params Instrumentation arguments.
*/
void initialize(Bundle params) {
mParams = params;
// check if this is a monkey test mode
String monkeyVal = mParams.getString("monkey");
if (monkeyVal != null) {
// only if the monkey key is specified, we alter the state of monkey
// else we should leave things as they are.
getInstrumentation().getUiAutomation().setRunAsMonkey(Boolean.valueOf(monkeyVal));
}
//这里传入new一个InstrumentationUiAutomatorBridge,参数一:上下文对象,参数二:UiAutomation实例
UiDevice.getInstance().initialize(new InstrumentationUiAutomatorBridge(
getInstrumentation().getContext(),
getInstrumentation().getUiAutomation()));
}
InstrumentationUiAutomatorBridge类继承于UiAutomatorBridge,看其构造函数
public InstrumentationUiAutomatorBridge(Context context, UiAutomation uiAutomation) {
super(uiAutomation);
mContext = context;
}
说明一下:context上下问对象是在启动设备的时候获取的,通过Instrumentation类,在android中Instrumentation类是属于观察者的角色,在Activity 的onCreate方法执行是进行实例化。如果不明白可以看看Instrumentation相关文章,这里不扯远了
说下InteractionController这个类,看下类的隶属关系InstrumentationUiAutomatorBridge extends UiAutomatorBridge,getInteractionController方法是在UiAutomatorBridge里面的。UiAutomatorBridge(UiAutomation uiAutomation) { //new UiAutomatorBridge对象的时候直接初始化参数
mUiAutomation = uiAutomation; mInteractionController = new InteractionController(this); mQueryController = new QueryController(this); // } InteractionController getInteractionController() { return mInteractionController; }这个uiAutomator参数又是上面提到的initialize()这个方法传递进去的
InteractionController这个类是主要提供操作控件的方法,比如touchUp(int x, int y)、scrollSwipe、sendKeyAndWaitForEvent等等方法。
4、回到上面sendKeyAndWaitForEvent()方法,看一下源码
/**
* Send keys and blocks until the first specified accessibility event.
*
* Most key presses will cause some UI change to occur. If the device is busy, this will
* block until the device begins to process the key press at which point the call returns
* and normal wait for idle processing may begin. If no events are detected for the
* timeout period specified, the call will return anyway with false.
*
* @param keyCode //key类型代码
* @param metaState //代表设备状态,忙或是空闲
* @param eventType //事件类型
* @param timeout //超时时间
* @return true if events is received, otherwise false.
*/
public boolean sendKeyAndWaitForEvent(final int keyCode, final int metaState,
final int eventType, long timeout) {
Runnable command = new Runnable() {
@Override
public void run() {
final long eventTime = SystemClock.uptimeMillis();
KeyEvent downEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN,
keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0,
InputDevice.SOURCE_KEYBOARD); //转换成对应的event类型
if (injectEventSync(downEvent)) { //down 按下
KeyEvent upEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP,
keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0,
InputDevice.SOURCE_KEYBOARD);
injectEventSync(upEvent); //up抬起
}
}
};
return runAndWaitForEvents(command, new WaitForAnyEventPredicate(eventType), timeout)
!= null; //等待操作完成,真正执行run操作在这个函数,看 runAndWaitForEvents }
private AccessibilityEvent runAndWaitForEvents(Runnable command,
AccessibilityEventFilter filter, long timeout) {
try {
return mUiAutomatorBridge.executeCommandAndWaitForAccessibilityEvent(command, filter,
timeout); //执行相关命令 注意command这个是线程对象
} catch (TimeoutException e) {
Log.w(LOG_TAG, "runAndwaitForEvent timedout waiting for events");
return null;
} catch (Exception e) {
Log.e(LOG_TAG, "exception from executeCommandAndWaitForAccessibilityEvent", e);
return null;
}
}
这里又回到了UiAutomatorBridge类
public AccessibilityEvent executeCommandAndWaitForAccessibilityEvent(Runnable command,
AccessibilityEventFilter filter, long timeoutMillis) throws TimeoutException {
return mUiAutomation.executeAndWaitForEvent(command,
filter, timeoutMillis);
}
继续跳到Uiautomator这个类,最终是通过同步操作的方法进行,其他都是一些等待事件超时的函数检测机制,具体怎么实现也是不太看得懂
* @param command The command to execute.
* @param filter Filter that recognizes the expected event.
* @param timeoutMillis The wait timeout in milliseconds.
*
* @throws TimeoutException If the expected event is not received within the timeout.
*/
public AccessibilityEvent executeAndWaitForEvent(Runnable command,
AccessibilityEventFilter filter, long timeoutMillis) throws TimeoutException {
// Acquire the lock and prepare for receiving events.
synchronized (mLock) {
throwIfNotConnectedLocked();
mEventQueue.clear();
// Prepare to wait for an event.
mWaitingForEventDelivery = true;
}
// Note: We have to release the lock since calling out with this lock held
// can bite. We will correctly filter out events from other interactions,
// so starting to collect events before running the action is just fine.
// We will ignore events from previous interactions.
final long executionStartTimeMillis = SystemClock.uptimeMillis();
// Execute the command *without* the lock being held.
command.run(); //运行刚才的注入操作事件
// Acquire the lock and wait for the event.
synchronized (mLock) {
try {
// Wait for the event.
final long startTimeMillis = SystemClock.uptimeMillis();
while (true) {
// Drain the event queue
while (!mEventQueue.isEmpty()) {
AccessibilityEvent event = mEventQueue.remove(0);
// Ignore events from previous interactions.
if (event.getEventTime() < executionStartTimeMillis) {
continue;
}
if (filter.accept(event)) {
return event;
}
event.recycle();
}
// Check if timed out and if not wait.
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis;
if (remainingTimeMillis <= 0) {
throw new TimeoutException("Expected event not received within: "
+ timeoutMillis + " ms.");
}
try {
mLock.wait(remainingTimeMillis);
} catch (InterruptedException ie) {
/* ignore */
}
}
} finally {
mWaitingForEventDelivery = false;
mEventQueue.clear();
mLock.notifyAll();
}
}
}
5、返回来看看刚才上面的inject操作
private boolean injectEventSync(InputEvent event) {
return mUiAutomatorBridge.injectInputEvent(event, true);
}
同样是使用UiAutomatorBridge类的injectInputEvent方法进行,最终还是和executeAndWaitForEvent方法同一个类
public boolean injectInputEvent(InputEvent event, boolean sync) {
return mUiAutomation.injectInputEvent(event, sync);
}
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;
}
这里用到了IUiAutomationConnection类,这个类是什么鬼尼,不知道没找到源码但是可以找到该类实例是如何过来的,是在Instrumentation类初始化函数里面
/*package*/ final void init(ActivityThread thread,
Context instrContext, Context appContext, ComponentName component,
IInstrumentationWatcher watcher, IUiAutomationConnection uiAutomationConnection) {
mThread = thread;
mMessageQueue = mThread.getLooper().myQueue();
mInstrContext = instrContext;
mAppContext = appContext;
mComponent = component;
mWatcher = watcher;
mUiAutomationConnection = uiAutomationConnection; //在这里,应该是activity启动时给初始化的同Instrumentation一样 }
Instrumentation类是前文提到的UiAutomatorTestCase类初始化来的。
至此分析到这里,这里的关系错综复杂,自己都搞蒙了只能慢慢看慢慢消化了,最后简单说明下各个类之间的关系,是别人整理过的: