UiAutomator源代碼分析之UiAutomatorBridge框架

上一篇文章《UIAutomator源代碼分析之啓動和執行》咱們描寫敘述了uitautomator從命令行執行到載入測試用例執行測試的整個流程。過程當中咱們也描寫敘述了UiAutomatorBridge這個類的重要性,說它至關於UiAutomation的代理(咱們都知道UiAutomator是經過UiAutomation和AccessibilityService進行鏈接而後獲取界面空間信息和注入事件的).那麼今天開始咱們就環繞這個類以及跟它有關係的類進行進一步的分析。java


1. UiAutomatorBridge框架

這一章節咱們會先看UiAutomatorBridge的整體框架,日後我會編寫其它文章經過一些詳細的樣例把它們串起來。因爲個人mackbook pro上沒有安裝類圖軟件,所下面圖是手畫的node


往下咱們就去初步描寫敘述下UiAutomatorBridge跟每一個相關的類的關係。android


2. UiAutomatorBridge與UiAutomation的聚合關係

UiAutomatorBridge擁有一個UiAutomation的成員變量,它們是聚合的關係,注意不是組合,因爲UiAutomation不必定僅僅能依賴UiAutomatorBridge而存在,咱們上一章節的UiAutomatorTestRunner就擁有一個UiAutomation的成員變量。微信

一旦UiAutomator工具需要經過UiAutomatorBridge獲取界面或者注入事件的時候。就會調用該成員變量.比方如下這個很是關鍵的去獲取當前界面的Root Node的方法:app

/*     */   public AccessibilityNodeInfo getRootInActiveWindow() {
/*  66 */     return this.mUiAutomation.getRootInActiveWindow();
/*     */   }


3. UiAutomatorBridge與QueryController的關聯關係

QueryController作的所有事情就是去把UiSelector這個UI控件選擇子翻譯成真實的適合咱們使用的android.view.accessibility.AccessibilityNodeInfo。框架

UiAutomatorBridge擁有一個成員變量mQueryController保存了QueryController的一個實例:工具

/*     */   private final QueryController mQueryController;
/*     */   
當UiObject需要獲取一個UiSelector指定的控件信息時,會去調用UiAutomatorBridge的getQueryController方法來得到這個mQueryController對象來進行對應的操做。例如如下面的UiObject的方法findAccessibilityNodeInfo就是這樣作的:

/*      */   protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout)
/*      */   {
/*  164 */     AccessibilityNodeInfo node = null;
/*  165 */     long startMills = SystemClock.uptimeMillis();
/*  166 */     long currentMills = 0L;
/*  167 */     while (currentMills <= timeout) {
/*  168 */       node = getQueryController().findAccessibilityNodeInfo(getSelector());
/*  169 */       if (node != null) {
/*      */         break;
/*      */       }
/*      */       
/*  173 */       UiDevice.getInstance().runWatchers();
/*      */       
/*  175 */       currentMills = SystemClock.uptimeMillis() - startMills;
/*  176 */       if (timeout > 0L) {
/*  177 */         SystemClock.sleep(1000L);
/*      */       }
/*      */     }
/*  180 */     return node;
/*      */   }

該getQueryController方法會去調用UiAutomatorBridge的getQueryController方法:
ui

/*      */   QueryController getQueryController()
/*      */   {
/*  100 */     return UiDevice.getInstance().getAutomatorBridge().getQueryController();
/*      */   }
從上面的類圖咱們可以看到,除了UiAutomatorBridge會調用QueryController作事情外,QueryController又會反過來調用UiAutomatorBridge來作事情,因爲如圖所描寫敘述的,僅僅有UiAutomatorBridge擁有UiAutomation的實例,因此QueryController會持有一個UiAutomatorBridge的實例:

/*     */   private final UiAutomatorBridge mUiAutomatorBridge;
而後在需要的時候再調用UiAutomatorBridge,如如下的得到Root Node的方法:

/*     */   protected AccessibilityNodeInfo getRootNode()
/*     */   {
/* 168 */     int maxRetry = 4;
/* 169 */     long waitInterval = 250L;
/* 170 */     AccessibilityNodeInfo rootNode = null;
/* 171 */     for (int x = 0; x < 4; x++) {
/* 172 */       rootNode = this.mUiAutomatorBridge.getRootInActiveWindow();
/* 173 */       if (rootNode != null) {
/* 174 */         return rootNode;
/*     */       }
/* 176 */       if (x < 3) {
/* 177 */         Log.e(LOG_TAG, "Got null root node from accessibility - Retrying...");
/* 178 */         SystemClock.sleep(250L);
/*     */       }
/*     */     }
/* 181 */     return rootNode;
/*     */   }

4. UiAutomatorBridge與InteractionController的關聯關係

道理與以上的QueryController同樣。僅僅是 UiAutomatorBridge需要經過InteractionController作的事情不是去得到控件信息。而是去注入事件



5. UiAutomatorBridge與ShellUiAutomatorBridge的繼承關係

UiAutomatorBridge是一個抽象類,裏面的方法有下面幾個:

  • getRootInActiveWindow :經過UiAutomation獲取當前窗體控件xml信息的根節點(經過它可以循環獲取所有控件)
  • injectInputEvent :經過UiAutomation注入事件
  • waitForIdle :   經過UiAutomation睡眠指定時間this

  • executeCommandAndWaitForAccessibilityEvent:經過UiAutomation運行指定線程的操做而後等待預期的時間返回
    google

  • takeScreenshot :經過UiAutomation進行截圖

  • performGlobalAction :  經過UiAutomation去運行一些全局的動做。如打開近期打開過的app列表,回到home界面等

從中可以看到這些動過都是需要經過UiAutomation來運行的,但也有一些動做是不需要用UiAutomation運行的,因此我相信google是爲了代碼清晰和可維護性,提供了子類ShellUiAutomatorBridge來專門處理那些不需要用到UiAutomation的狀況,比方下面的isScreenOn方法就不需要用到UiAutomation,而是直接用PowerManager服務來推斷當前屏幕是不是打開的:

/*     */   public boolean isScreenOn()
/*     */   {
/* 111 */     IPowerManager pm = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
/*     */     
/* 113 */     boolean ret = false;
/*     */     try {
/* 115 */       ret = pm.isScreenOn();
/*     */     } catch (RemoteException e) {
/* 117 */       Log.e(LOG_TAG, "Error getting screen status", e);
/* 118 */       throw new RuntimeException(e);
/*     */     }
/* 120 */     return ret;
/*     */   }


 

做者

自主博客

微信

CSDN

天地會珠海分舵

http://techgogogo.com


服務號:TechGoGoGo

掃描碼:

http://blog.csdn.net/zhubaitian

相關文章
相關標籤/搜索