android自动化测试Uiautomator API分析之二

来源:互联网 发布:ssm会员管理系统源码 编辑:程序博客网 时间:2024/06/05 17:23

对控件的操作,主要在UiObject中。例如各种点击事件。

以长按事件来论述详细的流程。

UiObject的longClick方法如下,

public boolean longClick() throws UiObjectNotFoundException  {        Tracer.trace();        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());        if(node == null) {            throw new UiObjectNotFoundException(getSelector().toString());        }        Rect rect = getVisibleBounds(node);        return getInteractionController().longTapNoSync(rect.centerX(), rect.centerY());    }

首先调用findAccessibilityNodeInfo方法在当前屏幕重新查找该控件,

然后调用InteractionController 的longTapNoSync方法写入事件。

1.1 findAccessibilityNodeInfo

protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) {        AccessibilityNodeInfo node = null;        long startMills = SystemClock.uptimeMillis();        long currentMills = 0;        while (currentMills <= timeout) {            node = getQueryController().findAccessibilityNodeInfo(getSelector());            if (node != null) {                break;            } else {                // does nothing if we're reentering another runWatchers()                UiDevice.getInstance().runWatchers();            }            currentMills = SystemClock.uptimeMillis() - startMills;            if(timeout > 0) {                SystemClock.sleep(WAIT_FOR_SELECTOR_POLL);            }        }        return node;    }

getQueryController方法返回的是QueryController对象,然后调用findAccessibilityNodeInfo,

public AccessibilityNodeInfo findAccessibilityNodeInfo(UiSelector selector) {        return findAccessibilityNodeInfo(selector, false);    }    protected AccessibilityNodeInfo findAccessibilityNodeInfo(UiSelector selector,            boolean isCounting) {        mUiAutomatorBridge.waitForIdle();        initializeNewSearch();        if (DEBUG)            Log.d(LOG_TAG, "Searching: " + selector);        synchronized (mLock) {            AccessibilityNodeInfo rootNode = getRootNode();            if (rootNode == null) {                Log.e(LOG_TAG, "Cannot proceed when root node is null. Aborted search");                return null;            }            // Copy so that we don't modify the original's sub selectors            UiSelector uiSelector = new UiSelector(selector);            return translateCompoundSelector(uiSelector, rootNode, isCounting);        }    }

首先调用getRootNode来获得根节点,

然后调用translateCompoundSelector来根据用户指定的UiSelector格式从上面获得根节点开始遍历窗口控件树,以获得目标控件。

1.1.1 getRootNode

getRootNode方法如下,

protected AccessibilityNodeInfo getRootNode() {        final int maxRetry = 4;        final long waitInterval = 250;        AccessibilityNodeInfo rootNode = null;        for(int x = 0; x < maxRetry; x++) {            rootNode = mUiAutomatorBridge.getRootInActiveWindow();            if (rootNode != null) {                return rootNode;            }            if(x < maxRetry - 1) {                Log.e(LOG_TAG, "Got null root node from accessibility - Retrying...");                SystemClock.sleep(waitInterval);            }        }        return rootNode;}

调用UiAutomatorBridge 的getRootInActiveWindow方法,

public AccessibilityNodeInfo getRootInActiveWindow() {        return mUiAutomation.getRootInActiveWindow();    }

直接调用UiAutomation的getRootInActiveWindow方法,

public AccessibilityNodeInfo getRootInActiveWindow() {        final int connectionId;        synchronized (mLock) {            throwIfNotConnectedLocked();            connectionId = mConnectionId;        }        // Calling out without a lock held.        return AccessibilityInteractionClient.getInstance()                .getRootInActiveWindow(connectionId);    }

很明显调用AccessibilityInteractionClient的getRootInActiveWindow方法,

AccessibilityInteractionClient是framework中的类,在此就不论述了。

1.1.2 translateCompoundSelector

translateCompoundSelector方法如下,

private AccessibilityNodeInfo translateCompoundSelector(UiSelector selector,            AccessibilityNodeInfo fromNode, boolean isCounting) {        // Start translating compound selectors by translating the regular_selector first        // The regular_selector is then used as a container for any optional pattern_selectors        // that may or may not be specified.        if(selector.hasContainerSelector())            // nested pattern selectors            if(selector.getContainerSelector().hasContainerSelector()) {                fromNode = translateCompoundSelector(                        selector.getContainerSelector(), fromNode, false);                initializeNewSearch();            } else                fromNode = translateReqularSelector(selector.getContainerSelector(), fromNode);        else            fromNode = translateReqularSelector(selector, fromNode);        if(fromNode == null) {            if (DEBUG)                Log.d(LOG_TAG, "Container selector not found: " + selector.dumpToString(false));            return null;        }        if(selector.hasPatternSelector()) {            fromNode = translatePatternSelector(selector.getPatternSelector(),                    fromNode, isCounting);            if (isCounting) {                Log.i(LOG_TAG, String.format(                        "Counted %d instances of: %s", mPatternCounter, selector));                return null;            } else {                if(fromNode == null) {                    if (DEBUG)                        Log.d(LOG_TAG, "Pattern selector not found: " +                                selector.dumpToString(false));                    return null;                }            }        }        // translate any additions to the selector that may have been added by tests        // with getChild(By selector) after a container and pattern selectors        if(selector.hasContainerSelector() || selector.hasPatternSelector()) {            if(selector.hasChildSelector() || selector.hasParentSelector())                fromNode = translateReqularSelector(selector, fromNode);        }        if(fromNode == null) {            if (DEBUG)                Log.d(LOG_TAG, "Object Not Found for selector " + selector);            return null;        }        Log.i(LOG_TAG, String.format("Matched selector: %s <<==>> [%s]", selector, fromNode));        return fromNode;    }

循环嵌套调用,获取目标控件。

1.2 longTapNoSync

InteractionController的longTapNoSync方法如下,

public boolean longTapNoSync(int x, int y) {        if (DEBUG) {            Log.d(LOG_TAG, "longTapNoSync (" + x + ", " + y + ")");        }        if (touchDown(x, y)) {            SystemClock.sleep(mUiAutomatorBridge.getSystemLongPressTime());            if(touchUp(x, y)) {                return true;            }        }        return false;    }

两个方法touchDown和touchUp方法。touchDown方法如下,

private boolean touchDown(int x, int y) {        if (DEBUG) {            Log.d(LOG_TAG, "touchDown (" + x + ", " + y + ")");        }        mDownTime = SystemClock.uptimeMillis();        MotionEvent event = MotionEvent.obtain(                mDownTime, mDownTime, MotionEvent.ACTION_DOWN, x, y, 1);        event.setSource(InputDevice.SOURCE_TOUCHSCREEN);        return injectEventSync(event);    }

首先构造一个MotionEvent对象,然后调用injectEventSync方法向系统注入该事件。

private boolean injectEventSync(InputEvent event) {        return mUiAutomatorBridge.injectInputEvent(event, true);    }

当然依次调用UiAutomatorBridge,UiAutomation

最后在UiAutomationConnection的injectInputEvent方法中完成实际的操作。

0 0