Uiautomator source code analysis to obtain control information

Source: Internet
Author: User

According to the plan mentioned at the beginning of the previous article "injection event of uiautomator source code analysis", we need to analyze the second point:

  • How to obtain control information
We initialize a uiobject in the test script as follows:
UiObject appsTab = new UiObject(new UiSelector().text("Apps"));appsTab.click()
So what happened in this process? This is what we will talk about next.
1. obtains the control information sequence diagram, which is still a hand-drawn nonstandard sequence diagram. It describes the interaction with related classes when a uiobject tries to obtain a control, the relationships between these classes have been described in the uiautomatorbridge framework for uiautomator source code analysis.
The entire process is not complex. Here is a brief description of these points:
  • After several twists and turns, A uiobject finally contacts uiautomation through different classes, and then notifies the uiautomation object that it wants to obtain the root node of the accessibilitynodeinfo type for all elements in the current activity window.
  • Accessibilitynodeinfo represents a node of the control element on the screen. It also has some member methods that can be used to obtain other target nodes based on the current node. You can think of the nodes on the screen as organized in a format similar to XML, so once you know the root node and the target control information specified by the Selection Sub-uiselector, we can traverse the entire window control.
  • After the querycontroller object obtains the root node, it calls the tranlatecompoundselector method to traverse all controls in the window until it finds the control specified by the sub-uiselector.
  • Note that an accessibilitynodeinfo represents only one control. During traversal, the information of the next control must be obtained through uiautomation again.
2. Trigger the control to find the real location

Before I analyzed the source code of uiautomator, I always thought that the space search occurred when initializing a uiobject through uiselector:

UiObject appsTab = new UiObject(new UiSelector().text("Apps"));

This gives me the feeling of being preemptible. After a control object is initialized, all the information about the nodes represented by the control should be obtained, however, after reading the source code, we found that this is not the case. The above is just to prepare uiselector in a certain format and select Sub-scripts, when a control event is triggered, for example:

appsTab.click()
We can go to the operation control method corresponding to the uiobject of a control to see it clearly. The preceding click is used as an example:

/*      */   public boolean click()/*      */     throws UiObjectNotFoundException/*      */   {/*  389 */     Tracer.trace(new Object[0]);/*  390 */     AccessibilityNodeInfo node = findAccessibilityNodeInfo(this.mConfig.getWaitForSelectorTimeout());/*  391 */     if (node == null) {/*  392 */       throw new UiObjectNotFoundException(getSelector().toString());/*      */     }/*  394 */     Rect rect = getVisibleBounds(node);/*  395 */     return getInteractionController().clickAndSync(rect.centerX(), rect.centerY(), this.mConfig.getActionAcknowledgmentTimeout());/*      */   }
The call to the second row triggers uiautomator to call uiautomation to obtain the desired control node accessibilitynodeinfo.


3. Get the root node

Next, let's take a look at how uiautomator gets the root node representing the root of all the controls in the window. We enter the findaccessibilitynodeinfo method of the uiobject:

/*      */   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;/*      */   }
The uiobject first obtains a querycontroller object, and then calls the method with the same name as findaccessibilitynodeinfo of the object:

/*     */   protected AccessibilityNodeInfo findAccessibilityNodeInfo(UiSelector selector, boolean isCounting)/*     */   {/* 143 */     this.mUiAutomatorBridge.waitForIdle();/* 144 */     initializeNewSearch();/*     */     /* 146 */     if (DEBUG) {/* 147 */       Log.d(LOG_TAG, "Searching: " + selector);/*     */     }/* 149 */     synchronized (this.mLock) {/* 150 */       AccessibilityNodeInfo rootNode = getRootNode();/* 151 */       if (rootNode == null) {/* 152 */         Log.e(LOG_TAG, "Cannot proceed when root node is null. Aborted search");/* 153 */         return null;/*     */       }/*     */       /*     */ /* 157 */       UiSelector uiSelector = new UiSelector(selector);/* 158 */       return translateCompoundSelector(uiSelector, rootNode, isCounting);/*     */     }/*     */   }
Here we have done two important things:

  • Row 150: Call getrootnode to obtain the root node. This is the focus of this chapter.
  • Row 158: Call translatecompoundselector to retrieve the root node from the above and traverse the window control tree based on the uiselector format specified by the user to obtain our target control.
Okay. Proceed to getrootnode:
/*     */   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;/*     */   }
172 call the method of the uiautomatorbridge object. Through the previous articles, we know that most of the methods provided by uiautomatorbridge call the method of uiautomation directly. Let's check whether this is the case:
/*     */   public AccessibilityNodeInfo getRootInActiveWindow() {/*  66 */     return this.mUiAutomation.getRootInActiveWindow();/*     */   }
Naturally, the getrootinactivewindow of uiautomation is called directly to obtain the root accessibilitynodeinfo.
4. traverse the root node to obtain the control specified by the Selection Sub-uiselector. As described above, the querycontroller method findaccessibilitynodeinfo does the second thing after obtaining the root node:
  • Row 158: Call translatecompoundselector to retrieve the root node from the above and traverse the window control tree based on the uiselector format specified by the user to obtain our target control.
I am not going to study the algorithm details. Considering the selection of subnesting, the analysis is also laborious, having understood its algorithm does not help me very much in the running principle of uiautomator. I only need to know the root of a given tree, then the attributes of the desired leaves are defined, so I can traverse the entire tree to find the desired controls that meet the requirements. If you are interested in learning about the algorithm, you should study it on your own.
5. finally, after clicking the click method of uiobject on the control through the coordinate point, the new framework on uiautomation obtained the accessibilitynodeinfo representing our target control, is the click method of the node directly called for clicking? Actually not. First, accessibilitynodeinfo does not have the click method. Let's continue to look at the Code:
/*      */   public boolean click()/*      */     throws UiObjectNotFoundException/*      */   {/*  389 */     Tracer.trace(new Object[0]);/*  390 */     AccessibilityNodeInfo node = findAccessibilityNodeInfo(this.mConfig.getWaitForSelectorTimeout());/*  391 */     if (node == null) {/*  392 */       throw new UiObjectNotFoundException(getSelector().toString());/*      */     }/*  394 */     Rect rect = getVisibleBounds(node);/*  395 */     return getInteractionController().clickAndSync(rect.centerX(), rect.centerY(), this.mConfig.getActionAcknowledgmentTimeout());/*      */   }
From Row 3, we can see that the control node information is finally converted into the control coordinate point for clicking. As for how to click, you can refer to the previous article, it is nothing more than injecting click events by creating a runnable thread.
6. series of conclusions: uiautomator source code analysis. This series is complete in this article, from startup, to the core uiautomatorbridge architecture, to instance anatomy, through these articles, I believe that you know exactly what is going on with the uiautomation framework and the test framework for communications between the accessibilityservice, and what is going on with the five classes dedicated to test case calls in uiautomation or, there is a lot of information available on the Internet, so there is no need to create new things here. Besides, these are not the core of the uiautomator framework, they only use the core class of uiautomatorbridge.




Uiautomator source code analysis to obtain control information

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.