上一篇文章《UiAutomator源码分析之UiAutomatorBridge框架》中我们把UiAutomatorBridge以及它相关的类进行的描述,往下我们会尝试根据两个实例将这些类给串联起来,我准备做的是用如下两个很有代表性的实例:

  • 注入事件
  • 获取控件
这一篇文章我们会通过分析UiDevice的pressHome这个方法来分析UiAutomator是如何注入事件的,下一篇文章会描述如何获取控件,敬请期待。
 

1. UiObject.pressHome顺序图

首先我们看一下我手画的非规范的顺序图,从中我们可以看到pressHome这个动作究竟需要和多少个类进行交互,以及它们是怎么交互的。
 

2.这些类是什么时候初始化的

在我们编写测试用例脚本的时候我们不会对以上所有的类进行初始化,包括UiObject对象都是通过直接在脚本中调用父类UiAutomationTestCase的getUiDevice()这个方法来获得的。其实这些都是在uiautomator运行时由RunTestCommand类的start()这个方法进行初始化的,具体请看《UIAutomator源码分析之启动和运行》的 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. 代码跟踪

首先看UiDevice的pressHome方法:
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 }
220行:
  • 获得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来注入事件的,和我们的预期是一致的。

我们继续看InteractionController中真正执行注入事件线程的runAndWaitForEvents方法:
/*     */   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
天地会珠海分舵 http://techgogogo.com 服务号:TechGoGoGo扫描码: http://blog.csdn.net/zhubaitian

UiAutomator源码分析之注入事件的更多相关文章

  1. UiAutomator源码分析之获取控件信息

    根据上一篇文章<UiAutomator源码分析之注入事件>开始时提到的计划,这一篇文章我们要分析的是第二点: 如何获取控件信息 我们在测试脚本中初始化一个UiObject的时候通常是像以下 ...

  2. UiAutomator源码分析之UiAutomatorBridge框架

    上一篇文章<UIAutomator源码分析之启动和运行>我们描述了uitautomator从命令行运行到加载测试用例运行测试的整个流程,过程中我们也描述了UiAutomatorBridge ...

  3. [Abp vNext 源码分析] - 13. 本地事件总线与分布式事件总线 (Rabbit MQ)

    一.简要介绍 ABP vNext 封装了两种事件总线结构,第一种是 ABP vNext 自己实现的本地事件总线,这种事件总线无法跨项目发布和订阅.第二种则是分布式事件总线,ABP vNext 自己封装 ...

  4. [置顶] Android源码分析-点击事件派发机制

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17339857 概述 一直想写篇关于Android事件派发机制的文章,却一直没 ...

  5. Android源码分析-点击事件派发机制

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17339857 概述 一直想写篇关于Android事件派发机制的文章,却一直没 ...

  6. libevent源码分析二--timeout事件响应

    libevent不仅支持io事件,同时还支持timeout事件与signal事件,这篇文件将分析libevent是如何组织timeout事件以及如何响应timeout事件. 1.  min_heap ...

  7. libevent源码分析一--io事件响应

    这篇文章将分析libevent如何组织io事件,如何捕捉事件的发生并进行相应的响应.这里不会详细分析event与event_base的细节,仅描述io事件如何存储与如何响应. 1.  select l ...

  8. [Abp 源码分析]九、事件总线

    0.简介 事件总线就是订阅/发布模式的一种实现,本质上事件总线的存在是为了降低耦合而存在的. 从上图可以看到事件由发布者发布到事件总线处理器当中,然后经由事件总线处理器调用订阅者的处理方法,而发布者和 ...

  9. UIAutomator源码分析之启动和运行

    通过上一篇<Android4.3引入的UiAutomation新框架官方简介>我们可以看到UiAutomator其实就是使用了UiAutomation这个新框架,通过调用Accessibi ...

随机推荐

  1. 第二章_session管理

    2.1 URL重写 URL重写是Session追踪技术.须要将一个或多个token做为一个查询字符串加入到一个URL中. Token的格式通常是键=值. Url?key-1=value-1&k ...

  2. Ubuntu 下一个disk清理保护

    有很长一段时间ubuntu人,很多人会突然提示:磁盘空间不足1G. 然后很长一段时间分析..最近遇到的类别似问题.记录,如下面: 一个:.xsession-errors.old 能够在终端看到主用户文 ...

  3. jstack:将Process Explorer中看到的进程ID做16进制转换,到ThreadDump中加上0x 前缀即能找到对应线程(转)

    原文链接:http://www.iteye.com/topic/1133941 症状: 使用Eclipse win 64位版本,indigo及kepler都重现了,使用tomcat 6.0.39,jd ...

  4. 跨域 Iframe 通信解决方案(兼容 IE 系列浏览器。)

    实现思路: 1.postMessage(IE8+, Firefox 3.1+, Opera 9+, Safari, and Chrome) 2.利用window.navigator共享信息,使支持IE ...

  5. css3 的box-sizing属性理解

    * { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } 有时候在某些项目中 ...

  6. APP漏洞导致移动支付隐患重重,未来之路怎样走?

    没有一种支付是100%安全的,互联网及移动支付规模的增长,其交易的安全性须要银行.支付公司.App开发人员.用户等參与各方更加重视.当下手机支付似乎变成了一种时尚,用户们"刷手机" ...

  7. 【SSH三框架】Hibernate基金会七:许多附属业务

    相对于上述一关系,在这里,下一个一对多关系说明. 另外,在上述.我们描述了许多人描述的一一对应关系.在关系数据库是多对一的关系.但也有许多关系. 但,只知道它是不够的,Hibernate它是一种面向对 ...

  8. linux Apache rotatelogs 故障原因及解决方案未生效

    rotatelogs 截断日志.构造.但保存vhost.conf 之后.serverhttpd -k restart 还是无法成功重新启动. 日志文件: (2)No such file or dire ...

  9. Codeforces Round #277.5 (Div. 2)A——SwapSort

    A. SwapSort time limit per test 1 second memory limit per test 256 megabytes input standard input ou ...

  10. Matlab与.NET基于类型安全的接口混合编程入门

    原文:[原创]Matlab与.NET基于类型安全的接口混合编程入门 如果这些文章对你有用,有帮助,期待更多开源组件介绍,请不要吝啬手中的鼠标. [原创分享]Matlab.NET混编调用Figure窗体 ...