上一篇文章《UiAutomator源代码分析之UiAutomatorBridge框架》中我们把UiAutomatorBridge以及它相关的类进行的描写叙述,往下我们会尝试依据两个实例将这些类给串联起来,我准备做的是用例如以下两个非常有代表性的实例:
- 注入事件
- 获取控件
1. UiObject.pressHome顺序图
2.这些类是什么时候初始化的
3.6章节“初始化UiDevice和UiAutomationBridge“。这里就不做累述。我们这里会看下在初始化UiAutomatorBridge的时候是怎样把QuneryControoler和InteractionController一并初始化了的。详细请看UiAutomatorBridge的构造函数:
/* */ UiAutomatorBridge(UiAutomation uiAutomation)
/* */ {
/* 48 */ this.mUiAutomation = uiAutomation;
/* 49 */ this.mInteractionController = new InteractionController(this);
/* 50 */ this.mQueryController = new QueryController(this);
/* */ }
3. 代码跟踪
public boolean pressHome() {
218 Tracer.trace();
219 waitForIdle();
220 return getAutomatorBridge().getInteractionController().sendKeyAndWaitForEvent(
221 KeyEvent.KEYCODE_HOME, 0, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED,
222 KEY_PRESS_EVENT_TIMEOUT);
223 }
- 获得UiDevice对象保存的UiAutomatorBridge对象。着两个对象都是在执行时初始化的,不清楚的话请翻看上面提到的文章
- 通过UiAutomatorBridge对象获得上面章节初始化的InteractionController对象
- 调用InteractionController对象的sendKeyAndWaitForEvent方法。里面參数关键是第一个keycode和第二个eventType
- keycode:代表我们要注入的是按下哪个按键的事件,比方这里我们是KEYCODE_HOME
- eventType:代表我们注射了该事件后预期会获得窗体返回来的哪种AccessibilityEvent类型,比方我们这里是TYPE_WINDOW_CONTENT_CHANGE
进入InteractionController类的sendKeyAndWaitForEvent:
/* */ public boolean sendKeyAndWaitForEvent(final int keyCode, final int metaState, int eventType, long timeout)
/* */ {
/* 188 */ Runnable command = new Runnable()
/* */ {
/* */ public void run() {
/* 191 */ long eventTime = SystemClock.uptimeMillis();
/* 192 */ KeyEvent downEvent = new KeyEvent(eventTime, eventTime, 0, keyCode, 0, metaState, -1, 0, 0, 257);
/* */
/* */
/* 195 */ if (InteractionController.this.injectEventSync(downEvent)) {
/* 196 */ KeyEvent upEvent = new KeyEvent(eventTime, eventTime, 1, keyCode, 0, metaState, -1, 0, 0, 257);
/* */
/* */
/* 199 */ InteractionController.this.injectEventSync(upEvent);
/* */ }
/* */
/* */ }
/* 203 */ };
/* 204 */ return runAndWaitForEvents(command, new WaitForAnyEventPredicate(eventType), timeout) != null;
/* */ }
代码中创建了一个Runnable的线程,线程里面run重写方法要做的事情就是去做注入事件的事情。那么为什么我们不直接去调用事件而须要创建一个线程了,这是由于我们在注入完事件之后还要去等待我们上面定义的预期的eventType是否有出现来推断我们的事件注入到底是否成功,这个就是204行runAndWaitForEvents做的事情。但我们这里还是先看下线程中是怎样注入事件的:
/* */ private boolean injectEventSync(InputEvent event) {
/* 655 */ return this.mUiAutomatorBridge.injectInputEvent(event, true);
/* */ }
再跟踪到UiAutomatorBridge对象:
/* */ public boolean injectInputEvent(InputEvent event, boolean sync) {
/* 70 */ return this.mUiAutomation.injectInputEvent(event, sync);
/* */ }
能够看到终于还是通过UiAutomation来注入事件的,和我们的预期是一致的。
/* */ private AccessibilityEvent runAndWaitForEvents(Runnable command, UiAutomation.AccessibilityEventFilter filter, long timeout)
/* */ {
/* */ try
/* */ {
/* 161 */ return this.mUiAutomatorBridge.executeCommandAndWaitForAccessibilityEvent(command, filter, timeout);
/* */ }
/* */ catch (TimeoutException e) {
/* 164 */ Log.w(LOG_TAG, "runAndwaitForEvent timedout waiting for events");
/* 165 */ return null;
/* */ } catch (Exception e) {
/* 167 */ Log.e(LOG_TAG, "exception from executeCommandAndWaitForAccessibilityEvent", e); }
/* 168 */ return null;
/* */ }
代码又跳到了UiAutomatorBridge这个类
/* */ public AccessibilityEvent executeCommandAndWaitForAccessibilityEvent(Runnable command, UiAutomation.AccessibilityEventFilter filter, long timeoutMillis) throws TimeoutException
/* */ {
/* 104 */ return this.mUiAutomation.executeAndWaitForEvent(command, filter, timeoutMillis);
/* */ }
终于把要运行的runnable运行注入事件的线程command和我们预期事件发生后返回来的窗体事件filter以及超时timeoutMillis传进去。UiAutomation就会和AccessibilityService进行交互以注入事件而且等待预期AccessibilityEvent发生或者超时返回。至于UiAutomation是怎样和AccessibilityService交互的,这就超出了这个系列文章的范畴了。
或许今后有充裕的时间的话我们再来深入去了解分析它。
作者 |
自主博客 |
微信 |
CSDN |
天地会珠海分舵 |
服务号:TechGoGoGo 扫描码: tp=webp" alt="" style="max-width:100%; margin:0px; padding:0px; height:auto!important; word-wrap:break-word!important; width:auto!important; visibility:visible!important"> |
http://blog.csdn.net/zhubaitian |
版权声明:本文博客原创文章。博客,未经同意,不得转载。