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; 20e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.graphics.Point; 21e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.Environment; 22e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.RemoteException; 23e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.ServiceManager; 24e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.SystemClock; 25e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.util.DisplayMetrics; 26e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.util.Log; 27e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.Display; 28e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.IWindowManager; 29e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.KeyEvent; 30e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.Surface; 31e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.WindowManagerImpl; 32e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.accessibility.AccessibilityEvent; 33e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.accessibility.AccessibilityNodeInfo; 34e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 35e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport com.android.internal.statusbar.IStatusBarService; 36e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport com.android.internal.util.Predicate; 37e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 38e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport java.io.File; 39e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport java.util.ArrayList; 40e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport java.util.HashMap; 41e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport java.util.List; 42e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport java.util.concurrent.TimeoutException; 43e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 44e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu/** 45e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * UiDevice provides access to device wide states. Also provides methods to simulate 46e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * pressing hardware buttons such as DPad or the soft buttons such as Home and Menu. 47e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 48e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupublic class UiDevice { 49e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final String LOG_TAG = UiDevice.class.getSimpleName(); 50e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 51e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final long DEFAULT_TIMEOUT_MILLIS = 10 * 1000; 52e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 53e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // store for registered UiWatchers 54e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private final HashMap<String, UiWatcher> mWatchers = new HashMap<String, UiWatcher>(); 55e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private final List<String> mWatchersTriggers = new ArrayList<String>(); 56e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 57e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // remember if we're executing in the context of a UiWatcher 58e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private boolean mInWatcherContext = false; 59e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 60e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // provides access the {@link QueryController} and {@link InteractionController} 61e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private final UiAutomatorBridge mUiAutomationBridge; 62e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 63e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // reference to self 64e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static UiDevice mDevice; 65e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 66e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private Boolean mIsPhone = null; 67e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 68e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private UiDevice() { 69e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mUiAutomationBridge = new UiAutomatorBridge(); 70e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mDevice = this; 71e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 72e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 73e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu boolean isInWatcherContext() { 74e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mInWatcherContext; 75e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 76e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 77e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 78e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Provides access the {@link QueryController} and {@link InteractionController} 79e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link UiAutomatorBridge} 80e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 81e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu UiAutomatorBridge getAutomatorBridge() { 82e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge; 83e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 84e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 85e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Allow both the direct creation of a UiDevice and retrieving a existing 86e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * instance of UiDevice. This helps tests and their libraries to have access 87e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * to UiDevice with necessitating having to always pass copies of UiDevice 88e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * instances around. 89e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return UiDevice instance 90e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 91e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public static UiDevice getInstance() { 92e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (mDevice == null) { 93e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mDevice = new UiDevice(); 94e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 95e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mDevice; 96e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 97e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 98e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 99e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This forces the return value of {@link #isPhone()} to be a specific device type. 100e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * For example, on certain devices the {@link #isPhone} may return true when an application 101e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * is actually behaving as if it is on a tablet. For these types of devices, it would be 102e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * best if the test forces the issue by invoking this method accordingly. 103e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param val true for phone behavior else false for all other 104e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 105e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void setTypeAsPhone(boolean val) { 106e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mIsPhone = val; 107e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 108e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 109e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 110e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Check if the tests are running on a phone screen. This method assumes a 111e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * phone is a device that its natural rotation has a height > width or when 112e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * rotated it has a width > height. This API is deprecated. Use the UI to 113e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * determine the layout. For example if on larger screen devices your app displays 114e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * two ListViews but on a small screen one, then count the ListViews to decide. see 115e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link UiObject#getMatchesCount()} 116e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the device has a phone else false 117e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 118e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu @Deprecated 119e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isPhone() { 120e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(mIsPhone == null) { 121e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu DisplayMetrics metrics = new DisplayMetrics(); 122e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Display display = WindowManagerImpl.getDefault().getDefaultDisplay(); 123e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu display.getMetrics(metrics); 124e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 125e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(isOrientationNatural()) { 126e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // we assume a phone has a natural orientation that has height > width 127e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(metrics.heightPixels > metrics.widthPixels) 128e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 129e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 130e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // we assume a phone has a rotated orientation that has height < width 131e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(metrics.heightPixels < metrics.widthPixels) 132e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 133e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 134e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 135e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // not a phone 136e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 137e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 138e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 139e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mIsPhone; 140e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 141e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 142e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 143e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Check the current device orientation 144e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if in natural orientation 145e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 146e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isOrientationNatural() { 147e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Display display = WindowManagerImpl.getDefault().getDefaultDisplay(); 148e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return display.getRotation() == Surface.ROTATION_0 || 149e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu display.getRotation() == Surface.ROTATION_180; 150e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 151e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 152e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 153e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Every event received from accessibility may or may not contain text. This 154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * method returns the text from the last UI traversal event received that had text. 155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This is helpful in web views when the test performs down arrow presses to focus 156e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * on different elements inside the web view, the accessibility will fire events 157e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * with the text just highlighted. In effect once can read the contents of a 158e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * web view this way. 159e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return text of the last traversal event else an empty string 160e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 161e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getLastTraversedText() { 162e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getQueryController().getLastTraversedText(); 163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 164e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 165e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 166e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper to clear the text saved of the last accessibility UI traversal event that had 167e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * any text in it. See {@link #getLastTraversedText()}. 168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 169e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void clearLastTraversedText() { 170e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mUiAutomationBridge.getQueryController().clearLastTraversedText(); 171e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 172e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 173e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method to do a short press on MENU button 175e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if successful else false 176e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 177e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressMenu() { 178e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_MENU); 179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method to do a short press on BACK button 183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if successful else false 184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressBack() { 186e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_BACK); 187e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 188e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 189e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 190e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method to do a short press on HOME button 191e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if successful else false 192e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 193e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressHome() { 194e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_HOME); 195e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 196e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 197e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 198e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method to do a short press on SEARCH button 199e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if successful else false 200e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 201e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressSearch() { 202e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_SEARCH); 203e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 204e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 205e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 206e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method to do a short press on DOWN button 207e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if successful else false 208e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 209e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressDPadCenter() { 210e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_DPAD_CENTER); 211e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 212e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 213e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 214e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method to do a short press on DOWN button 215e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if successful else false 216e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 217e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressDPadDown() { 218e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_DPAD_DOWN); 219e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 220e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 221e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 222e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method to do a short press on UP button 223e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if successful else false 224e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 225e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressDPadUp() { 226e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_DPAD_UP); 227e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 228e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 229e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 230e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method to do a short press on LEFT button 231e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if successful else false 232e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 233e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressDPadLeft() { 234e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_DPAD_LEFT); 235e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 236e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 237e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 238e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method to do a short press on RIGTH button 239e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if successful else false 240e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressDPadRight() { 242e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_DPAD_RIGHT); 243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 245e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 246e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method to do a short press on DELETE 247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if successful else false 248e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 249e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressDelete() { 250e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_DEL); 251e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 252e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 253e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 254e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method to do a short press on ENTER 255e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if successful else false 256e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 257e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressEnter() { 258e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return pressKeyCode(KeyEvent.KEYCODE_ENTER); 259e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 260e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 261e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 262e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method to do a short press using a key code. See {@link KeyEvent} 263e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if successful else false 264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 265e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressKeyCode(int keyCode) { 266e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu waitForIdle(); 267e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getInteractionController().sendKey(keyCode, 0); 268e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 270e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method to do a short press using a key code. See {@link KeyEvent} 272e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param keyCode See {@link KeyEvent} 273e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param metaState See {@link KeyEvent} 274e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if successful else false 275e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 276e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressKeyCode(int keyCode, int metaState) { 277e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu waitForIdle(); 278e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getInteractionController().sendKey(keyCode, metaState); 279e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 280e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 282e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Gets the raw width of the display, in pixels. The size is adjusted based 283e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * on the current rotation of the display. 284e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return width in pixels or zero on failure 285e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 286e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public int getDisplayWidth() { 287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu IWindowManager wm = IWindowManager.Stub.asInterface( 288e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu ServiceManager.getService(Context.WINDOW_SERVICE)); 289e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Point p = new Point(); 290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu try { 291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu wm.getDisplaySize(p); 292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } catch (RemoteException e) { 293e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return 0; 294e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 295e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return p.x; 296e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 297e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 298e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 299e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Press recent apps soft key 300e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if successful 301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 303e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean pressRecentApps() throws RemoteException { 304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu waitForIdle(); 305e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu final IStatusBarService statusBar = IStatusBarService.Stub.asInterface( 306e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu ServiceManager.getService(Context.STATUS_BAR_SERVICE)); 307e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 308e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (statusBar != null) { 309e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu statusBar.toggleRecentApps(); 310e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 311e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 312e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 313e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 314e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 315e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 316e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Gets the raw height of the display, in pixels. The size is adjusted based 317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * on the current rotation of the display. 318e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return height in pixels or zero on failure 319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public int getDisplayHeight() { 321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu IWindowManager wm = IWindowManager.Stub.asInterface( 322e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu ServiceManager.getService(Context.WINDOW_SERVICE)); 323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Point p = new Point(); 324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu try { 325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu wm.getDisplaySize(p); 326e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } catch (RemoteException e) { 327e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return 0; 328e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return p.y; 330e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 331e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3334ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * Perform a click at arbitrary coordinates specified by the user 334e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param x coordinate 335e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param y coordinate 3364ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @return true if the click succeeded else false 337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 3384ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public boolean click(int x, int y) { 339e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (x >= getDisplayWidth() || y >= getDisplayHeight()) { 340e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return (false); 341e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 3424ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getAutomatorBridge().getInteractionController().click(x, y); 343e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 346e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Performs a swipe from one coordinate to another using the number of steps 347e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * to determine smoothness and speed. The more steps the slower and smoother 348e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * the swipe will be. 349e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param startX 350e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param startY 351e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param endX 352e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param endY 353e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param steps is the number of move steps sent to the system 354e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return false if the operation fails or the coordinates are invalid 355e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 356e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipe(int startX, int startY, int endX, int endY, int steps) { 357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getInteractionController() 358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu .scrollSwipe(startX, startY, endX, endY, steps); 359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 360e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 361e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 362e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Performs a swipe between points in the Point array. 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 371e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void waitForIdle() { 372e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu waitForIdle(DEFAULT_TIMEOUT_MILLIS); 373e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 374e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 375e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void waitForIdle(long time) { 376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mUiAutomationBridge.waitForIdle(time); 377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 380e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Last activity to report accessibility events 381e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return String name of activity 382e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 383e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getCurrentActivityName() { 384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getQueryController().getCurrentActivityName(); 385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 386e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 387e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 388e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Last package to report accessibility events 389e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return String name of package 390e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 391e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getCurrentPackageName() { 392e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getQueryController().getCurrentPackageName(); 393e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 394e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 395e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 396e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Enables the test script to register a condition watcher to be called by 398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * the automation library. The automation library will invoke 399e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link UiWatcher#checkForCondition} only when a regular API call is in 400e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * retry mode when it is unable to locate its selector yet. Only during this 401e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * time, the watchers are invoked to check if there is something else 402e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * unexpected on the screen that may be causing the delay in detecting the 403e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * required UI object. 404e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param name of watcher 405e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param watcher {@link UiWatcher} 406e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 407e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void registerWatcher(String name, UiWatcher watcher) { 408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (mInWatcherContext) { 409e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new IllegalStateException("Cannot register new watcher from within another"); 410e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mWatchers.put(name, watcher); 412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 414e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 415e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Removes a previously registered {@link #registerWatcher(String, UiWatcher)}. 416e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param name of watcher used when <code>registerWatcher</code> was called. 417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiAutomationException 418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void removeWatcher(String name) { 420e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (mInWatcherContext) { 421e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new IllegalStateException("Cannot remove a watcher from within another"); 422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 423e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mWatchers.remove(name); 424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 426e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 427e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Watchers are generally not run unless a certain UI object is not being 428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * found. This will help improve performance of tests until there is a good 429e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * reason to check for possible exceptions on the display.<b/><b/> However, 430e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * in some cases it may be desirable to force run the watchers. Calling this 431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * method will execute all registered watchers. 432e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 433e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void runWatchers() { 434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (mInWatcherContext) { 435e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return; 436e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 437e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 438e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu for (String watcherName : mWatchers.keySet()) { 439e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu UiWatcher watcher = mWatchers.get(watcherName); 440e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (watcher != null) { 441e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu try { 442e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mInWatcherContext = true; 443e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (watcher.checkForCondition()) { 444e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu setWatcherTriggered(watcherName); 445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 446e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } catch (Exception e) { 447e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.e(LOG_TAG, "Exceuting watcher: " + watcherName, e); 448e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } finally { 449e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mInWatcherContext = false; 450e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 452e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 453e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 454e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 455e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * If you have used {@link #registerWatcher(String, UiWatcher)} then this 457e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * method can be used to reset reported UiWatcher triggers. 458e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * A {@link UiWatcher} reports it is triggered by returning true 459e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * from its implementation of {@link UiWatcher#checkForCondition()} 460e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 461e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void resetWatcherTriggers() { 462e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mWatchersTriggers.clear(); 463e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 464e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 465e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * If you have used {@link #registerWatcher(String, UiWatcher)} then this 467e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * method can be used to check if a specific UiWatcher has ever triggered during the 468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * test. For a {@link UiWatcher} to report it is triggered it needs to return true 469e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * from its implementation of {@link UiWatcher#checkForCondition()} 470e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 471e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean hasWatcherTriggered(String watcherName) { 472e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mWatchersTriggers.contains(watcherName); 473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 474e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 475e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 476e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * If you have used {@link #registerWatcher(String, UiWatcher)} then this 477e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * method can be used to check if any of those have ever triggered during the 478e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * test. For a {@link UiWatcher} to report it is triggered it needs to return true 479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * from its implementation of {@link UiWatcher#checkForCondition()} 480e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 481e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean hasAnyWatcherTriggered() { 482e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mWatchersTriggers.size() > 0; 483e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 484e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 485e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private void setWatcherTriggered(String watcherName) { 486e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (!hasWatcherTriggered(watcherName)) { 487e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mWatchersTriggers.add(watcherName); 488e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 489e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 490e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 491e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 492e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Check if the device is in its natural orientation. This is determined by 493e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * checking whether the orientation is at 0 or 180 degrees. 494e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is in natural orientation 495e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 496e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 497e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isNaturalRotation() throws RemoteException { 498e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getAutomatorBridge().getInteractionController().isNaturalRotation(); 499e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 500e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 501e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 502e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Disables the sensors and freezes the device rotation at its 503e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * current rotation state. 504e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 505e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 506e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void freezeRotation() throws RemoteException { 507e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().getInteractionController().freezeRotation(); 508e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 509e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 510e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 511e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Re-enables the sensors and un-freezes the device rotation 512e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * allowing its contents to rotate with the device physical rotation. 513e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 514e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 515e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void unfreezeRotation() throws RemoteException { 516e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().getInteractionController().unfreezeRotation(); 517e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 518e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 519e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 520e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Rotates left and also freezes rotation in that position by 521e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * disabling the sensors. If you want to un-freeze the rotation 522e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * and re-enable the sensors see {@link #unfreezeRotation()}. Note 523e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * that doing so may cause the screen contents to rotate 524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * depending on the current physical position of the test device. 525e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 526e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 527e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void setRotationLeft() throws RemoteException { 528e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().getInteractionController().setRotationLeft(); 529e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 530e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 531e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 532e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Rotates right and also freezes rotation in that position by 533e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * disabling the sensors. If you want to un-freeze the rotation 534e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * and re-enable the sensors see {@link #unfreezeRotation()}. Note 535e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * that doing so may cause the screen contents to rotate 536e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * depending on the current physical position of the test device. 537e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 538e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 539e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void setRotationRight() throws RemoteException { 540e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().getInteractionController().setRotationRight(); 541e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 542e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 543e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 544e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Check if the device is in its natural orientation. This is determined by 545e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * checking whether the orientation is at 0 or 180 degrees. 546e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is in natural orientation 547e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 548e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 549e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void setRotationNatural() throws RemoteException { 550e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().getInteractionController().setRotationNatural(); 551e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 552e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 553e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 554e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This method simply presses the power button if the screen is OFF else 555e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * it does nothing if the screen is already ON. If the screen was OFF and 556e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * it just got turned ON, this method will insert a 500ms delay to allow 557e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * the device time to wake up and accept input. 558e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 559e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 560e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void wakeUp() throws RemoteException { 561e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(getAutomatorBridge().getInteractionController().wakeDevice()) { 562e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // sync delay to allow the window manager to start accepting input 563e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // after the device is awakened. 564e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(500); 565e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 566e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 567e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 568e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 569e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Checks the power manager if the screen is ON 570e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the screen is ON else false 571e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 572e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 573e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isScreenOn() throws RemoteException { 574e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getAutomatorBridge().getInteractionController().isScreenOn(); 575e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 576e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 577e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 578e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This method simply presses the power button if the screen is ON else 579e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * it does nothing if the screen is already OFF. 580e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws RemoteException 581e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 582e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void sleep() throws RemoteException { 583e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().getInteractionController().sleepDevice(); 584e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 585e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 586e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 587e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method used for debugging to dump the current window's layout hierarchy. 588e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * The file root location is /data/local/tmp 589e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param fileName 590e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 591e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void dumpWindowHierarchy(String fileName) { 592e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo root = 593e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().getQueryController().getAccessibilityRootNode(); 594e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(root != null) { 595e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfoDumper.dumpWindowToFile( 596e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu root, new File(new File(Environment.getDataDirectory(), 597e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu "local/tmp"), fileName)); 598e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 599e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 600e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 601e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 602e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 603e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Waits for a window content update event to occur 604e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 605e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * if a package name for window is specified, but current window is not with the same package 606e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * name, the function will return immediately 607e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 608e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param packageName the specified window package name; maybe <code>null</code>, and a window 609e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * update from any frontend window will end the wait 610e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param timeout the timeout for the wait 611e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 612e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if a window update occured, false if timeout has reached or current window is 613e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * not the specified package name 614e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 615e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitForWindowUpdate(final String packageName, long timeout) { 616e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (packageName != null) { 617e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (!packageName.equals(getCurrentPackageName())) { 618e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 619e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 620e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 621e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Runnable emptyRunnable = new Runnable() { 622e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu @Override 623e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void run() { 624e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 625e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu }; 626e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Predicate<AccessibilityEvent> checkWindowUpdate = new Predicate<AccessibilityEvent>() { 627e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu @Override 628e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean apply(AccessibilityEvent t) { 629e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (t.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) { 630e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return packageName == null || packageName.equals(t.getPackageName()); 631e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 632e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 633e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 634e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu }; 635e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu try { 636e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getAutomatorBridge().executeCommandAndWaitForAccessibilityEvent( 637e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu emptyRunnable, checkWindowUpdate, timeout); 638e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } catch (TimeoutException e) { 639e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 640e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } catch (Exception e) { 641e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.e(LOG_TAG, "waitForWindowUpdate: general exception from bridge", e); 642e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 643e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 644e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 645e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 646e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu} 647