Uiautomator界面中存在的控件,但是無法被點擊的問題解決

在Android P出來後,開展自動化測試的路上一些地方有些磕磕絆絆。先說說之前發現的一種必現的無法點擊到桌面控件的問題,明明界面中存在,但是無法被點擊,Uiautomator運行時並沒有拋出這一步的異常,但是下一步就拋異常了。

詳細的實例如下:case刪除全部聯繫人的操作步驟(點擊刪除--選擇確定--驗證是否正確刪除)

而因爲無法點擊到刪除這個控件,導致沒有彈出確認窗口,導致下一步的點擊“確定”按鈕這一步拋UiObjectNotFound異常。


    @Test
    public void testCase() throws UiObjectNotFoundException {
        UiObject deleteBtn=new UiObject(new UiSelector().text("刪除"));//未正確點擊,但未拋出異常
        deleteBtn.click();
        UiObject okBtn=new UiObject(new UiSelector().text("確定"));//拋異常
        okBtn.click();
    }

那麼,接下來,分析下,爲什麼出錯了。使用UiautomatorViewer同步快照後,發現刪除按鈕被截取掉一部分了。

可見,控件確實存在,但是其中有一部分被幹掉了,整個屏幕被切割掉了一小部分。

從Uiautomator源碼中,我們可以知道,Uiautomator其實獲取控件後,會獲取該控件的中心點座標,隨後點擊座標,從而實現點擊控件。上源碼:

UiObject類的click()方法:

/**
     * Performs a click at the center of the visible bounds of the UI element represented
     * by this UiObject.
     *
     * @return true id successful else false
     * @throws UiObjectNotFoundException
     * @since API Level 16
     */
    public boolean click() throws UiObjectNotFoundException {
        Tracer.trace();
        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
        if(node == null) {
            throw new UiObjectNotFoundException(mUiSelector.toString());
        }
        Rect rect = getVisibleBounds(node);
        return getInteractionController().clickAndSync(rect.centerX(), rect.centerY(),
                mConfig.getActionAcknowledgmentTimeout());//rect.centerX(), rect.centerY()。中心點
    }

跳轉到etInteractionController().clickAndSync()方法中:

/**
     * Click at coordinates and blocks until either accessibility event TYPE_WINDOW_CONTENT_CHANGED
     * or TYPE_VIEW_SELECTED are received.
     *
     * @param x
     * @param y
     * @param timeout waiting for event
     * @return true if events are received, else false if timeout.
     */
    public boolean clickAndSync(final int x, final int y, long timeout) {

        String logString = String.format("clickAndSync(%d, %d)", x, y);
        Log.d(LOG_TAG, logString);

        return runAndWaitForEvents(clickRunnable(x, y), new WaitForAnyEventPredicate(
                AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED |
                AccessibilityEvent.TYPE_VIEW_SELECTED), timeout) != null;
    }

不確定是開發全面屏機器都這樣還是部分ROM的開發者不小心留的坑,但,無力吐槽,更無力修復這種軟件狀態,只能尋找解決方案。

多方嘗試後,發現adb shell input tap <x> <y> 可以實現屏幕點擊,而滑動(長按)則可以通過adb shell input swipe <x1> <y1> <x2> <y2> [duration(ms)]來實現。而且,上面的切割部分的座標,也是可以點擊到的。辣麼,解決方案便出來了。只要修改下點擊的方式更換爲Runtime.getRuntime().exec("input tap "+rect.centerX()+" "+ rect.centerY()),可以是在源碼上做修改,也可以是在自己二次封裝的代碼上替換掉就可以了。貼上adb shell input 幫助文檔:


C:\Users>adb shell input
Usage: input [<source>] <command> [<arg>...]

The sources are:
      dpad
      keyboard
      mouse
      touchpad
      gamepad
      touchnavigation
      joystick
      touchscreen
      stylus
      trackball

The commands and default sources are:
      text <string> (Default: touchscreen)
      keyevent [--longpress] <key code number or name> ... (Default: keyboard)
      tap <x> <y> (Default: touchscreen)
      swipe <x1> <y1> <x2> <y2> [duration(ms)] (Default: touchscreen)
      draganddrop <x1> <y1> <x2> <y2> [duration(ms)] (Default: touchscreen)
      press (Default: trackball)
      roll <dx> <dy> (Default: trackball)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章