1e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu/* 2e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Copyright (C) 2012 The Android Open Source Project 3e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 4e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Licensed under the Apache License, Version 2.0 (the "License"); 5e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * you may not use this file except in compliance with the License. 6e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * You may obtain a copy of the License at 7e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 8e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * http://www.apache.org/licenses/LICENSE-2.0 9e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 10e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Unless required by applicable law or agreed to in writing, software 11e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * distributed under the License is distributed on an "AS IS" BASIS, 12e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * See the License for the specific language governing permissions and 14e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * limitations under the License. 15e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 16e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 17e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupackage com.android.uiautomator.core; 18e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 19e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.content.Context; 209fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhuimport android.graphics.Bitmap; 219fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhuimport android.graphics.Canvas; 229fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhuimport android.graphics.Matrix; 23e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.graphics.Point; 24d80b91ded7ae7e80da1c8466c554e8b03bdfb6b6Jeff Brownimport android.hardware.display.DisplayManagerGlobal; 25d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhuimport android.os.Build; 26e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.Environment; 27e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.RemoteException; 28e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.ServiceManager; 29e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.SystemClock; 30d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhuimport android.util.DisplayMetrics; 31e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.util.Log; 32e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.Display; 33e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.KeyEvent; 34e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.Surface; 35e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.accessibility.AccessibilityEvent; 36e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.accessibility.AccessibilityNodeInfo; 37e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 38e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport com.android.internal.statusbar.IStatusBarService; 39e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport com.android.internal.util.Predicate; 40e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 41e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport java.io.File; 429fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhuimport java.io.FileOutputStream; 439fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhuimport java.io.IOException; 44e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport java.util.ArrayList; 45e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport java.util.HashMap; 46e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport java.util.List; 47e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport java.util.concurrent.TimeoutException; 48e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 49e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu/** 5046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * UiDevice provides access to state information about the device. 5146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * You can also use this class to simulate user actions on the device, 5246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * such as pressing the d-pad or pressing the Home and Menu buttons. 53e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 54e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupublic class UiDevice { 55e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final String LOG_TAG = UiDevice.class.getSimpleName(); 56e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 57e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final long DEFAULT_TIMEOUT_MILLIS = 10 * 1000; 58e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 596088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz // Sometimes HOME and BACK key presses will generate no events if already on 606088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz // home page or there is nothing to go back to, Set low timeouts. 616088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz private static final long KEY_PRESS_EVENT_TIMEOUT = 1 * 1000; 626088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz 63e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // store for registered UiWatchers 64e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private final HashMap<String, UiWatcher> mWatchers = new HashMap<String, UiWatcher>(); 65e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private final List<String> mWatchersTriggers = new ArrayList<String>(); 66e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 67e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // remember if we're executing in the context of a UiWatcher 68e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private boolean mInWatcherContext = false; 69e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 70e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // provides access the {@link QueryController} and {@link InteractionController} 71e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private final UiAutomatorBridge mUiAutomationBridge; 72e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 73e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // reference to self 74e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static UiDevice mDevice; 75e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 76e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private UiDevice() { 77e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mUiAutomationBridge = new UiAutomatorBridge(); 78e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mDevice = this; 79e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 80e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 81e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu boolean isInWatcherContext() { 82e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mInWatcherContext; 83e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 84e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 85e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 86e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Provides access the {@link QueryController} and {@link InteractionController} 87e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link UiAutomatorBridge} 88e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 89e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu UiAutomatorBridge getAutomatorBridge() { 90e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge; 91e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 92e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 9346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Retrieves a singleton instance of UiDevice 9446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 95e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return UiDevice instance 96e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 97e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public static UiDevice getInstance() { 98e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (mDevice == null) { 99e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mDevice = new UiDevice(); 100e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 101e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mDevice; 102e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 103e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 104e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 105d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu * Returns the display size in dp (device-independent pixel) 106d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu * 107d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu * The returned display size is adjusted per screen rotation 108d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu * 10946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return a Point containing the display size in dp 110d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu */ 111d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu public Point getDisplaySizeDp() { 112e7ef253585665720f73b8b2cefc591ffb3314a68Jeff Brown Display display = getDefaultDisplay(); 113d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu Point p = new Point(); 114d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu display.getSize(p); 115d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu DisplayMetrics metrics = new DisplayMetrics(); 116d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu display.getMetrics(metrics); 117d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu float dpx = p.x / metrics.density; 118d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu float dpy = p.y / metrics.density; 119d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu p.x = Math.round(dpx); 120d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu p.y = Math.round(dpy); 121d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu return p; 122d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu } 123d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu 124d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu /** 12546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Retrieves the product name of the device. 12646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 12746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * This method provides information on what type of device the 12846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * test is running on. If you are trying to test for different types of 12946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * UI screen sizes, your test should use 13046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * {@link UiDevice#getDisplaySizeDp()} instead. This value is the same 13146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * returned by invoking #adb shell getprop ro.product.name. 132d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu * 13346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return product name of the device 134d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu */ 135d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu public String getProductName() { 136d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu return Build.PRODUCT; 137d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu } 138d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu 139d367349218c5e12feb6f0de732293da45f5e9af3Guang Zhu /** 14046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Retrieves the text from the last UI traversal event received. 14146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 14246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * You can use this method to read the contents in a WebView container 14346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * because the accessibility framework fires events 14446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * as each text is highlighted. You can write a test to perform 14546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * directional arrow presses to focus on different elements inside a WebView, 14646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * and call this method to get the text from each traversed element. 14746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If you are testing a view container that can return a reference to a 14846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Document Object Model (DOM) object, your test should use the view's 1493d50587be8ff021369c90554d814839335b445b0Adam Momtaz * DOM instead. 15046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 15146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return text of the last traversal event, else return an empty string 152e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 153e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getLastTraversedText() { 154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getQueryController().getLastTraversedText(); 155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 156e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 157e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 15846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Clears the text from the last UI traversal event. 1593d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link #getLastTraversedText()}. 160e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 161e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void clearLastTraversedText() { 162e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mUiAutomationBridge.getQueryController().clearLastTraversedText(); 163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 164e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 165e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 16646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates a short press on the MENU button. 16746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if successful, else return false 168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 169e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressMenu() { 17065430f29b4305e4dd8ea42650d40896f34486518Adam Momtaz waitForIdle(); 17165430f29b4305e4dd8ea42650d40896f34486518Adam Momtaz return mUiAutomationBridge.getInteractionController().sendKeyAndWaitForEvent( 17265430f29b4305e4dd8ea42650d40896f34486518Adam Momtaz KeyEvent.KEYCODE_MENU, 0, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED, 17365430f29b4305e4dd8ea42650d40896f34486518Adam Momtaz KEY_PRESS_EVENT_TIMEOUT); 174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 175e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 176e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 17746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates a short press on the BACK button. 17846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if successful, else return false 179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressBack() { 1816088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz waitForIdle(); 1826088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz return mUiAutomationBridge.getInteractionController().sendKeyAndWaitForEvent( 1836088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz KeyEvent.KEYCODE_BACK, 0, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED, 1846088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz KEY_PRESS_EVENT_TIMEOUT); 185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 186e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 187e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 18846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates a short press on the HOME button. 18946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if successful, else return false 190e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 191e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressHome() { 1926088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz waitForIdle(); 1936088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz return mUiAutomationBridge.getInteractionController().sendKeyAndWaitForEvent( 1946088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz KeyEvent.KEYCODE_HOME, 0, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED, 1956088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz KEY_PRESS_EVENT_TIMEOUT); 196e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 197e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 198e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 19946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates a short press on the SEARCH button. 20046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if successful, else return false 201e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 202e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressSearch() { 203e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_SEARCH); 204e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 205e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 206e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 20746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates a short press on the CENTER button. 20846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if successful, else return false 209e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 210e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressDPadCenter() { 211e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_DPAD_CENTER); 212e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 213e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 214e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 21546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates a short press on the DOWN button. 21646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if successful, else return false 217e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 218e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressDPadDown() { 219e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_DPAD_DOWN); 220e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 221e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 222e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 22346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates a short press on the UP button. 22446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if successful, else return false 225e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 226e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressDPadUp() { 227e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_DPAD_UP); 228e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 229e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 230e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 23146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates a short press on the LEFT button. 23246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if successful, else return false 233e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 234e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressDPadLeft() { 235e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_DPAD_LEFT); 236e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 237e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 238e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 23946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates a short press on the RIGHT button. 24046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if successful, else return false 241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 242e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressDPadRight() { 243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_DPAD_RIGHT); 244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 245e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 246e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 24746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates a short press on the DELETE key. 24846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if successful, else return false 249e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 250e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressDelete() { 251e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_DEL); 252e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 253e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 254e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 25546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates a short press on the ENTER key. 25646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if successful, else return false 257e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 258e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressEnter() { 259e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_ENTER); 260e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 261e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 262e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 26346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates a short press using a key code. 26446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 26546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * See {@link KeyEvent} 26646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if successful, else return false 267e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 268e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressKeyCode(int keyCode) { 269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu waitForIdle(); 270e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getInteractionController().sendKey(keyCode, 0); 271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 272e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 273e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 27446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates a short press using a key code. 27546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 27646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * See {@link KeyEvent}. 27746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param keyCode the key code of the event. 27846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param metaState an integer in which each bit set to 1 represents a pressed meta key 27946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if successful, else return false 280e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressKeyCode(int keyCode, int metaState) { 282e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu waitForIdle(); 283e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getInteractionController().sendKey(keyCode, metaState); 284e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 285e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 286e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 28746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates a short press on the Recent Apps button. 28846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 28946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if successful, else return false 290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressRecentApps() throws RemoteException { 293e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu waitForIdle(); 294e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu final IStatusBarService statusBar = IStatusBarService.Stub.asInterface( 295e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu ServiceManager.getService(Context.STATUS_BAR_SERVICE)); 296e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 297e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (statusBar != null) { 298e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu statusBar.toggleRecentApps(); 299e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 300e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 303e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 305835cffbc85a560a2454fd417073a127895335122Jeff Brown * Gets the width of the display, in pixels. The width and height details 306835cffbc85a560a2454fd417073a127895335122Jeff Brown * are reported based on the current orientation of the display. 307835cffbc85a560a2454fd417073a127895335122Jeff Brown * @return width in pixels or zero on failure 308835cffbc85a560a2454fd417073a127895335122Jeff Brown */ 309835cffbc85a560a2454fd417073a127895335122Jeff Brown public int getDisplayWidth() { 310e7ef253585665720f73b8b2cefc591ffb3314a68Jeff Brown Display display = getDefaultDisplay(); 31159b4c820f01d48a41d944239290028411528db25Guang Zhu Point p = new Point(); 31259b4c820f01d48a41d944239290028411528db25Guang Zhu display.getSize(p); 31359b4c820f01d48a41d944239290028411528db25Guang Zhu return p.x; 314835cffbc85a560a2454fd417073a127895335122Jeff Brown } 315835cffbc85a560a2454fd417073a127895335122Jeff Brown 316835cffbc85a560a2454fd417073a127895335122Jeff Brown /** 3173d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Gets the height of the display, in pixels. The size is adjusted based 3183d50587be8ff021369c90554d814839335b445b0Adam Momtaz * on the current orientation of the display. 319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return height in pixels or zero on failure 320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public int getDisplayHeight() { 322e7ef253585665720f73b8b2cefc591ffb3314a68Jeff Brown Display display = getDefaultDisplay(); 32359b4c820f01d48a41d944239290028411528db25Guang Zhu Point p = new Point(); 32459b4c820f01d48a41d944239290028411528db25Guang Zhu display.getSize(p); 32559b4c820f01d48a41d944239290028411528db25Guang Zhu return p.y; 326e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 327e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 328e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3294ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * Perform a click at arbitrary coordinates specified by the user 3303d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 331e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param x coordinate 332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param y coordinate 3334ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @return true if the click succeeded else false 334e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 3354ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public boolean click(int x, int y) { 336e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (x >= getDisplayWidth() || y >= getDisplayHeight()) { 337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return (false); 338e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 3394ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getAutomatorBridge().getInteractionController().click(x, y); 340e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 341e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 342e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 343e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Performs a swipe from one coordinate to another using the number of steps 344467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * to determine smoothness and speed. Each step execution is throttled to 5ms 345467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * per step. So for a 100 steps, the swipe will take about 1/2 second to complete. 3463d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 347e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param startX 348e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param startY 349e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param endX 350e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param endY 351e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param steps is the number of move steps sent to the system 352e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return false if the operation fails or the coordinates are invalid 353e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 354e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipe(int startX, int startY, int endX, int endY, int steps) { 355e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getInteractionController() 356e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu .scrollSwipe(startX, startY, endX, endY, steps); 357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3603d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Performs a swipe between points in the Point array. Each step execution is throttled 361467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * to 5ms per step. So for a 100 steps, the swipe will take about 1/2 second to complete 3623d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 363e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param segments is Point array containing at least one Point object 364e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param segmentSteps steps to inject between two Points 365e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 366e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 367e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipe(Point[] segments, int segmentSteps) { 368e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getInteractionController().swipe(segments, segmentSteps); 369e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 370e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 37146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz /** 37246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Waits for the current application to idle. 37346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Default wait timeout is 10 seconds 37446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz */ 375e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void waitForIdle() { 376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu waitForIdle(DEFAULT_TIMEOUT_MILLIS); 377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 37946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz /** 38046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Waits for the current application to idle. 38146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param timeout in milliseconds 38246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz */ 383e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void waitForIdle(long time) { 384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mUiAutomationBridge.waitForIdle(time); 385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 386e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 387e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 38846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Retrieves the last activity to report accessibility events. 3890bb49719aab950cc522c2c56f7adce750c656012Adam Momtaz * @deprecated The results returned should be considered unreliable 390e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return String name of activity 391e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 3920bb49719aab950cc522c2c56f7adce750c656012Adam Momtaz @Deprecated 393e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getCurrentActivityName() { 394e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getQueryController().getCurrentActivityName(); 395e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 396e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 39846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Retrieves the name of the last package to report accessibility events. 399e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return String name of package 400e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 401e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getCurrentPackageName() { 402e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getQueryController().getCurrentPackageName(); 403e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 404e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 405e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 40646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Registers a {@link UiWatcher} to run automatically when the testing framework is unable to 40746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * find a match using a {@link UiSelector}. See {@link #runWatchers()} 4083d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 40946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param name to register the UiWatcher 410e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param watcher {@link UiWatcher} 411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void registerWatcher(String name, UiWatcher watcher) { 413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (mInWatcherContext) { 414e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new IllegalStateException("Cannot register new watcher from within another"); 415e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 416e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mWatchers.put(name, watcher); 417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 42046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Removes a previously registered {@link UiWatcher}. 4213d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 42246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * See {@link #registerWatcher(String, UiWatcher)} 42346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param name used to register the UiWatcher 424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiAutomationException 425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 426e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void removeWatcher(String name) { 427e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (mInWatcherContext) { 428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new IllegalStateException("Cannot remove a watcher from within another"); 429e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 430e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mWatchers.remove(name); 431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 432e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 433e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 43446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * This method forces all registered watchers to run. 43546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * See {@link #registerWatcher(String, UiWatcher)} 436e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 437e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void runWatchers() { 438e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (mInWatcherContext) { 439e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return; 440e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 441e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 442e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu for (String watcherName : mWatchers.keySet()) { 443e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu UiWatcher watcher = mWatchers.get(watcherName); 444e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (watcher != null) { 445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu try { 446e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mInWatcherContext = true; 447e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (watcher.checkForCondition()) { 448e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu setWatcherTriggered(watcherName); 449e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 450e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } catch (Exception e) { 451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.e(LOG_TAG, "Exceuting watcher: " + watcherName, e); 452e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } finally { 453e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mInWatcherContext = false; 454e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 455e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 457e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 458e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 459e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 46046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Resets a {@link UiWatcher} that has been triggered. 46146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If a UiWatcher runs and its {@link UiWatcher#checkForCondition()} call 46246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * returned <code>true</code>, then the UiWatcher is considered triggered. 46346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * See {@link #registerWatcher(String, UiWatcher)} 464e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 465e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void resetWatcherTriggers() { 466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mWatchersTriggers.clear(); 467e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 469e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 47046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Checks if a specific registered {@link UiWatcher} has triggered. 47146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * See {@link #registerWatcher(String, UiWatcher)}. If a UiWatcher runs and its 47246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * {@link UiWatcher#checkForCondition()} call returned <code>true</code>, then 47346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * the UiWatcher is considered triggered. This is helpful if a watcher is detecting errors 4743d50587be8ff021369c90554d814839335b445b0Adam Momtaz * from ANR or crash dialogs and the test needs to know if a UiWatcher has been triggered. 47546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 47646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param watcherName 47746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if triggered else false 478e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean hasWatcherTriggered(String watcherName) { 480e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mWatchersTriggers.contains(watcherName); 481e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 482e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 483e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 48446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Checks if any registered {@link UiWatcher} have triggered. 48546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 48646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * See {@link #registerWatcher(String, UiWatcher)} 48746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * See {@link #hasWatcherTriggered(String)} 488e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 489e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean hasAnyWatcherTriggered() { 490e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mWatchersTriggers.size() > 0; 491e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 492e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 49346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz /** 49446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Used internally by this class to set a {@link UiWatcher} state as triggered. 49546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param watcherName 49646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz */ 497e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private void setWatcherTriggered(String watcherName) { 498e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (!hasWatcherTriggered(watcherName)) { 499e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mWatchersTriggers.add(watcherName); 500e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 501e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 502e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 503e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5043d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the device is in its natural orientation. This is determined by checking if the 5053d50587be8ff021369c90554d814839335b445b0Adam Momtaz * orientation is at 0 or 180 degrees. 506e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is in natural orientation 507e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 5083d50587be8ff021369c90554d814839335b445b0Adam Momtaz public boolean isNaturalOrientation() { 509e7ef253585665720f73b8b2cefc591ffb3314a68Jeff Brown Display display = getDefaultDisplay(); 5103d50587be8ff021369c90554d814839335b445b0Adam Momtaz return display.getRotation() == Surface.ROTATION_0 || 5113d50587be8ff021369c90554d814839335b445b0Adam Momtaz display.getRotation() == Surface.ROTATION_180; 512e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 513e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 514e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 51559b4c820f01d48a41d944239290028411528db25Guang Zhu * Returns the current rotation of the display, as defined in {@link Surface} 51659b4c820f01d48a41d944239290028411528db25Guang Zhu * @return 51759b4c820f01d48a41d944239290028411528db25Guang Zhu */ 51859b4c820f01d48a41d944239290028411528db25Guang Zhu public int getDisplayRotation() { 51959b4c820f01d48a41d944239290028411528db25Guang Zhu return getDefaultDisplay().getRotation(); 52059b4c820f01d48a41d944239290028411528db25Guang Zhu } 52159b4c820f01d48a41d944239290028411528db25Guang Zhu 52259b4c820f01d48a41d944239290028411528db25Guang Zhu /** 523e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Disables the sensors and freezes the device rotation at its 524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * current rotation state. 525e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 526e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 527e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void freezeRotation() throws RemoteException { 528e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().getInteractionController().freezeRotation(); 529e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 530e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 531e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5323d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Re-enables the sensors and un-freezes the device rotation allowing its contents 53346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * to rotate with the device physical rotation. During a test execution, it is best to 53446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * keep the device frozen in a specific orientation until the test case execution has completed. 535e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 536e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 537e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void unfreezeRotation() throws RemoteException { 538e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().getInteractionController().unfreezeRotation(); 539e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 540e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 541e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 54246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates orienting the device to the left and also freezes rotation 54346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by disabling the sensors. 54446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 54546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If you want to un-freeze the rotation and re-enable the sensors 54646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * see {@link #unfreezeRotation()}. 547e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 548e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 5493d50587be8ff021369c90554d814839335b445b0Adam Momtaz public void setOrientationLeft() throws RemoteException { 550e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().getInteractionController().setRotationLeft(); 551e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 552e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 553e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 55446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates orienting the device to the right and also freezes rotation 55546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by disabling the sensors. 55646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 55746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If you want to un-freeze the rotation and re-enable the sensors 55846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * see {@link #unfreezeRotation()}. 559e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 560e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 5613d50587be8ff021369c90554d814839335b445b0Adam Momtaz public void setOrientationRight() throws RemoteException { 562e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().getInteractionController().setRotationRight(); 563e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 564e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 565e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 56646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Simulates orienting the device into its natural orientation and also freezes rotation 56746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by disabling the sensors. 56846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 56946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If you want to un-freeze the rotation and re-enable the sensors 57046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * see {@link #unfreezeRotation()}. 571e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 572e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 5733d50587be8ff021369c90554d814839335b445b0Adam Momtaz public void setOrientationNatural() throws RemoteException { 574e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().getInteractionController().setRotationNatural(); 575e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 576e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 577e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 57846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * This method simulates pressing the power button if the screen is OFF else 57946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * it does nothing if the screen is already ON. 58046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 58146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If the screen was OFF and it just got turned ON, this method will insert a 500ms delay 58246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * to allow the device time to wake up and accept input. 583e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 584e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 585e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void wakeUp() throws RemoteException { 586e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(getAutomatorBridge().getInteractionController().wakeDevice()) { 587e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // sync delay to allow the window manager to start accepting input 588e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // after the device is awakened. 589e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(500); 590e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 591e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 592e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 593e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 59446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Checks the power manager if the screen is ON. 59546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 596e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the screen is ON else false 597e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 598e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 599e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isScreenOn() throws RemoteException { 600e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getAutomatorBridge().getInteractionController().isScreenOn(); 601e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 602e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 603e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 604e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This method simply presses the power button if the screen is ON else 605e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * it does nothing if the screen is already OFF. 60646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 607e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 608e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 609e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void sleep() throws RemoteException { 610e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().getInteractionController().sleepDevice(); 611e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 612e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 613e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 614e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method used for debugging to dump the current window's layout hierarchy. 615e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * The file root location is /data/local/tmp 6163d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 617e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param fileName 618e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 619e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void dumpWindowHierarchy(String fileName) { 620e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo root = 621e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().getQueryController().getAccessibilityRootNode(); 622e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(root != null) { 623e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfoDumper.dumpWindowToFile( 624e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu root, new File(new File(Environment.getDataDirectory(), 625e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu "local/tmp"), fileName)); 626e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 627e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 628e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 629e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 63046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Waits for a window content update event to occur. 631e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 63246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If a package name for the window is specified, but the current window 63346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * does not have the same package name, the function returns immediately. 634e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 63546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param packageName the specified window package name (can be <code>null</code>). 63646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If <code>null</code>, a window update from any front-end window will end the wait 637e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param timeout the timeout for the wait 638e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 63946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if a window update occurred, false if timeout has elapsed or if the current 64046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * window does not have the specified package name 641e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 642e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitForWindowUpdate(final String packageName, long timeout) { 643e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (packageName != null) { 644e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (!packageName.equals(getCurrentPackageName())) { 645e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 646e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 647e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 648e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Runnable emptyRunnable = new Runnable() { 649e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu @Override 650e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void run() { 651e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 652e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu }; 653e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Predicate<AccessibilityEvent> checkWindowUpdate = new Predicate<AccessibilityEvent>() { 654e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu @Override 655e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean apply(AccessibilityEvent t) { 656e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (t.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) { 657e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return packageName == null || packageName.equals(t.getPackageName()); 658e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 659e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 660e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 661e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu }; 662e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu try { 663e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().executeCommandAndWaitForAccessibilityEvent( 664e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu emptyRunnable, checkWindowUpdate, timeout); 665e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } catch (TimeoutException e) { 666e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 667e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } catch (Exception e) { 668e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.e(LOG_TAG, "waitForWindowUpdate: general exception from bridge", e); 669e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 670e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 671e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 672e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 673e7ef253585665720f73b8b2cefc591ffb3314a68Jeff Brown 674e7ef253585665720f73b8b2cefc591ffb3314a68Jeff Brown private static Display getDefaultDisplay() { 675d80b91ded7ae7e80da1c8466c554e8b03bdfb6b6Jeff Brown return DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 676e7ef253585665720f73b8b2cefc591ffb3314a68Jeff Brown } 6779fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu 6789fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu /** 6799fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu * @return the current display rotation in degrees 6809fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu */ 6819fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu private static float getDegreesForRotation(int value) { 6829fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu switch (value) { 6839fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu case Surface.ROTATION_90: 6849fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu return 360f - 90f; 6859fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu case Surface.ROTATION_180: 6869fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu return 360f - 180f; 6879fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu case Surface.ROTATION_270: 6889fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu return 360f - 270f; 6899fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu } 6909fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu return 0f; 6919fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu } 6929fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu 6939fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu /** 6949fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu * Take a screenshot of current window and store it as PNG 6959fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu * 6969fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu * Default scale of 1.0f (original size) and 90% quality is used 697ebc5898540750b5758a21d5f98a2c24f2cf8b75bGuang Zhu * The screenshot is adjusted per screen rotation 6989fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu * 6999fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu * @param storePath where the PNG should be written to 7009fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu * @return 7019fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu */ 7029fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu public boolean takeScreenshot(File storePath) { 7039fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu return takeScreenshot(storePath, 1.0f, 90); 7049fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu } 7059fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu 7069fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu /** 7079fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu * Take a screenshot of current window and store it as PNG 7089fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu * 709ebc5898540750b5758a21d5f98a2c24f2cf8b75bGuang Zhu * The screenshot is adjusted per screen rotation 7109fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu * 7119fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu * @param storePath where the PNG should be written to 7129fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu * @param scale scale the screenshot down if needed; 1.0f for original size 7139fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu * @param quality quality of the PNG compression; range: 0-100 7149fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu * @return 7159fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu */ 7169fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu public boolean takeScreenshot(File storePath, float scale, int quality) { 7179fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu // This is from com.android.systemui.screenshot.GlobalScreenshot#takeScreenshot 7189fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu // We need to orient the screenshot correctly (and the Surface api seems to take screenshots 7199fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu // only in the natural orientation of the device :!) 7209fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu DisplayMetrics displayMetrics = new DisplayMetrics(); 7219fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu Display display = getDefaultDisplay(); 7229fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu display.getRealMetrics(displayMetrics); 7239fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu float[] dims = {displayMetrics.widthPixels, displayMetrics.heightPixels}; 7249fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu float degrees = getDegreesForRotation(display.getRotation()); 7259fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu boolean requiresRotation = (degrees > 0); 7269fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu Matrix matrix = new Matrix(); 7279fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu matrix.reset(); 7289fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu if (scale != 1.0f) { 7299fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu matrix.setScale(scale, scale); 7309fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu } 7319fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu if (requiresRotation) { 7329fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu // Get the dimensions of the device in its native orientation 7339fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu matrix.preRotate(-degrees); 7349fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu } 7359fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu matrix.mapPoints(dims); 7369fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu dims[0] = Math.abs(dims[0]); 7379fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu dims[1] = Math.abs(dims[1]); 7389fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu 7399fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu // Take the screenshot 7409fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu Bitmap screenShot = Surface.screenshot((int) dims[0], (int) dims[1]); 7419fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu if (screenShot == null) { 7429fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu return false; 7439fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu } 7449fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu 7459fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu if (requiresRotation) { 7469fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu // Rotate the screenshot to the current orientation 7479fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu int width = displayMetrics.widthPixels; 7489fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu int height = displayMetrics.heightPixels; 7499fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu if (scale != 1.0f) { 7509fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu width = Math.round(scale * width); 7519fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu height = Math.round(scale * height); 7529fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu } 7539fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu Bitmap ss = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 7549fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu Canvas c = new Canvas(ss); 7559fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu c.translate(ss.getWidth() / 2, ss.getHeight() / 2); 7569fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu c.rotate(degrees); 7579fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu c.translate(-dims[0] / 2, -dims[1] / 2); 7589fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu c.drawBitmap(screenShot, 0, 0, null); 7599fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu c.setBitmap(null); 7609fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu screenShot = ss; 7619fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu } 7629fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu 7639fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu // Optimizations 7649fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu screenShot.setHasAlpha(false); 7659fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu 7669fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu try { 7679fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu FileOutputStream fos = new FileOutputStream(storePath); 7689fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu screenShot.compress(Bitmap.CompressFormat.PNG, quality, fos); 7699fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu fos.flush(); 7709fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu fos.close(); 7719fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu } catch (IOException ioe) { 7729fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu Log.e(LOG_TAG, "failed to save screen shot to file", ioe); 7739fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu return false; 7749fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu } finally { 7759fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu screenShot.recycle(); 7769fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu } 7779fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu return true; 7789fe7f8d9e5f83bd13bc2b06c672d3cd93f619be0Guang Zhu } 779e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu} 780