专栏首页小满UiAutomator源码学习(1)-- UiDevice

UiAutomator源码学习(1)-- UiDevice

UiDevice提供对设备状态信息的访问。 也可以使用此类来模拟设备上的用户操作,例如按键盘或按Home和Menu按钮。UiDevice类的完整源码 UiDevice.java

废话不多说,我们首先根据用法来来看看Android Uiautomator 访问设备的原理。

 device = UiDevice.getInstance(getInstrumentation());
 device.pressHome();

    // Bring up the default launcher by searching for a UI component
    // that matches the content description for the launcher button.
 UiObject allAppsButton = device
            .findObject(new UiSelector().description("Apps"));

    // Perform a click on the button to load the launcher.
 allAppsButton.clickAndWaitForNewWindow();

根据这个用法实例,我们先看一下它的构造函数:

 /** Private constructor. Clients should use {@link UiDevice#getInstance(Instrumentation)}. */
    private UiDevice(Instrumentation instrumentation) {
        mInstrumentation = instrumentation;
        UiAutomation uiAutomation = instrumentation.getUiAutomation();
        mUiAutomationBridge = new InstrumentationUiAutomatorBridge(
                instrumentation.getContext(), uiAutomation);
        // Enable multi-window support for API level 21 and up
        if (UiDevice.API_LEVEL_ACTUAL >= Build.VERSION_CODES.LOLLIPOP) {
            // Subscribe to window information
            AccessibilityServiceInfo info = uiAutomation.getServiceInfo();
            info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
            uiAutomation.setServiceInfo(info);
        }
    }
    /**
     * Retrieves a singleton instance of UiDevice
     *
     * @return UiDevice instance
     */
    public static UiDevice getInstance(Instrumentation instrumentation) {
        if (sInstance == null) {
            sInstance = new UiDevice(instrumentation);
        }
        return sInstance;
    }

这是一个单例模式的类,负责创建自己的对象,以确保UiDevcie对象的唯一性。在构造方法中除了初始化唯一的uiDevice对象,还初始化了UiAutomoatorBridge对象。UiAutomatorBridge这个类非常的重要,获取设备界面信息、注入事件以及截图都需要经过UiAutomatorBridge。稍后会做详细的介绍。

接下来我们来看,是如何获取设备信息以及模拟用户操作的。

 /**
     * Returns the display size in dp (device-independent pixel)
     *
     * The returned display size is adjusted per screen rotation. Also this will return the actual
     * size of the screen, rather than adjusted per system decorations (like status bar).
     *
     * @return a Point containing the display size in dp
     */
    public Point getDisplaySizeDp() {
        Tracer.trace();
        Display display = getAutomatorBridge().getDefaultDisplay();
        Point p = new Point();
        display.getRealSize(p);
        DisplayMetrics metrics = new DisplayMetrics();
        display.getRealMetrics(metrics);
        float dpx = p.x / metrics.density;
        float dpy = p.y / metrics.density;
        p.x = Math.round(dpx);
        p.y = Math.round(dpy);
        return p;
    }
getDisplaySizeDp()方法返回的是一个以dp为单位的坐标点。同样可以获取设备的宽度或者高度:
  /**
     * Gets the width of the display, in pixels. The width and height details
     * are reported based on the current orientation of the display.
     * @return width in pixels or zero on failure
     */
    public int getDisplayWidth() {
        Display display = getDefaultDisplay();
        Point p = new Point();
        display.getSize(p);
        return p.x;
    }

以上都是设备属性,接下来看模拟用户的操作。操作的第一步就是获取屏幕的焦点。获取到UiObject后就可以对屏幕上的这些控件进行模拟用户操作。

/**
     * Returns a UiObject which represents a view that matches the specified selector criteria.
     *
     * @param selector
     * @return UiObject object
     */
    public UiObject findObject(UiSelector selector) {
        return new UiObject(this, selector);
    }

获取到屏幕上布局对象以后,操作无外乎就是点击、长按、滑动 以及键盘等操作。

   /**
     * Simulates a short press on the HOME button.
     * @return true if successful, else return false
     * @since API Level 16
     */
    public boolean pressHome() {
        Tracer.trace();
        waitForIdle();
        return getAutomatorBridge().getInteractionController().sendKeyAndWaitForEvent(
                KeyEvent.KEYCODE_HOME, 0, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED,
                KEY_PRESS_EVENT_TIMEOUT);
    }

 /**
     * Perform a click at arbitrary coordinates specified by the user
     *
     * @param x coordinate
     * @param y coordinate
     * @return true if the click succeeded else false
     * @since API Level 16
     */
    public boolean click(int x, int y) {
        Tracer.trace(x, y);
        if (x >= getDisplayWidth() || y >= getDisplayHeight()) {
            return (false);
        }
        return getAutomatorBridge().getInteractionController().clickNoSync(x, y);
    }
    /**
     * Performs a swipe from one coordinate to another using the number of steps
     * to determine smoothness and speed. Each step execution is throttled to 5ms
     * per step. So for a 100 steps, the swipe will take about 1/2 second to complete.
     *
     * @param startX
     * @param startY
     * @param endX
     * @param endY
     * @param steps is the number of move steps sent to the system
     * @return false if the operation fails or the coordinates are invalid
     * @since API Level 16
     */
    public boolean swipe(int startX, int startY, int endX, int endY, int steps) {
        Tracer.trace(startX, startY, endX, endY, steps);
        return getAutomatorBridge().getInteractionController()
                .swipe(startX, startY, endX, endY, steps);
    }

不难看出,所有的操作都离不开 uiAutomatorBridge。在该类的方法getInteractionController()获取InteractionController 对象。InteractionController类将用户的键盘事件注入到android系统中,与系统进行交互。稍后会做详细的介绍。

除了这些操作,UiDevice还提供了其他的方法,如打开通知栏、点亮屏幕、执行adb命令、检查电源管理器,屏幕是否打开、等待屏幕更新、获取当前窗口的布局层次结构、截图等。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • UiAutomator源码学习(2)-- UiAutomationBridge

    从上一章对UiDevice的学习,可以看出几乎所有的操作都离不开 UiAutomationBridge。重新看一下UIDevice的构造方法:

    yuanyuan
  • Mock接口平台Moco学习

    Moco源码和jar下载地址: git jar 下载moco-runner-xxxx-standalone.jar

    yuanyuan
  • UiAutomator源码学习(3)-- UiObject

    UiAutomator是由谷歌在Android4.1版本发布时推出的一款用Java编写的UI自动化测试框架。 基于Accessibility服务,该工具提供了对...

    yuanyuan
  • [C语言]N阶勒让德公式

    雨落凋殇
  • LeetCode 387: 字符串中的第一个唯一字符

    给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。

    爱写bug
  • JS监听页面关闭

    JS可以监听浏览器页面的关闭,主要使用了window对象的onbeforeunload方法

    书童小二
  • python中return如何写

    程序运行到所遇到的第一个return即返回(退出def块),不会再运行第二个return。

    砸漏
  • 数字问题-LeetCode 507、508、513、515、516、520、518(DP、BFS)

    LeetCode # 507 508 509 513 515 516 520 518

    算法工程师之路
  • return的值都去哪了?去哪了,“谁伸手了,return的结果就给谁”

    事情是这样,今天的前端零基础课在讲购物车模块,其中的全部商品中的被选中商品的总数和价格,是先要获得所有被选中的单项商品数量和单价,然后发送给接口进行计算的。这其...

    web前端教室
  • Python finally的用法

    try语句有一个可选finally子句,用于定义在所有情况下都必须执行的finally操作

    于小勇

扫码关注云+社区

领取腾讯云代金券