Uiautomator界面中存在的控件,但是无法被点击的问题解决

在Android P出来后,开展自动化测试的路上一些地方有些磕磕绊绊。先说说之前发现的一种必现的无法点击到桌面控件的问题,明明界面中存在,但是无法被点击,Uiautomator运行时并没有抛出这一步的异常,但是下一步就抛异常了。

详细的实例如下:case删除全部联系人的操作步骤(点击删除--选择确定--验证是否正确删除)

Uiautomator界面中存在的控件,但是无法被点击的问题解决_第1张图片

而因为无法点击到删除这个控件,导致没有弹出确认窗口,导致下一步的点击“确定”按钮这一步抛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界面中存在的控件,但是无法被点击的问题解决_第2张图片

可见,控件确实存在,但是其中有一部分被干掉了,整个屏幕被切割掉了一小部分。

从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  可以实现屏幕点击,而滑动(长按)则可以通过adb shell input swipe  [duration(ms)]来实现。而且,上面的切割部分的坐标,也是可以点击到的。辣么,解决方案便出来了。只要修改下点击的方式更换为Runtime.getRuntime().exec("input tap "+rect.centerX()+" "+ rect.centerY()),可以是在源码上做修改,也可以是在自己二次封装的代码上替换掉就可以了。贴上adb shell input 帮助文档:


C:\Users>adb shell input
Usage: input []  [...]

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

The commands and default sources are:
      text  (Default: touchscreen)
      keyevent [--longpress]  ... (Default: keyboard)
      tap   (Default: touchscreen)
      swipe     [duration(ms)] (Default: touchscreen)
      draganddrop     [duration(ms)] (Default: touchscreen)
      press (Default: trackball)
      roll   (Default: trackball)

 

你可能感兴趣的:(UiAutomator1.0,Android测试)