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命令、檢查電源管理器,螢幕是否開啟、等待螢幕更新、獲取當前視窗的佈局層次結構、截圖等。