180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov/* 280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Copyright (C) 2013 The Android Open Source Project 380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License"); 580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * you may not use this file except in compliance with the License. 680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * You may obtain a copy of the License at 780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * http://www.apache.org/licenses/LICENSE-2.0 980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 1080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Unless required by applicable law or agreed to in writing, software 1180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS, 1280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * See the License for the specific language governing permissions and 1480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * limitations under the License. 1580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 1680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 1780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovpackage android.app; 1880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 1980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.accessibilityservice.AccessibilityService.Callbacks; 2080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.accessibilityservice.AccessibilityService.IAccessibilityServiceClientWrapper; 21bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslavimport android.accessibilityservice.AccessibilityServiceInfo; 2280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.accessibilityservice.IAccessibilityServiceClient; 23bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslavimport android.accessibilityservice.IAccessibilityServiceConnection; 2480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.graphics.Bitmap; 2580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.graphics.Canvas; 2680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.graphics.Point; 2780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.hardware.display.DisplayManagerGlobal; 2880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.os.Looper; 2980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.os.RemoteException; 3080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.os.SystemClock; 3180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.util.Log; 3280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.view.Display; 3380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.view.InputEvent; 34c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslavimport android.view.KeyEvent; 3580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.view.Surface; 3680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent; 3780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.view.accessibility.AccessibilityInteractionClient; 3880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo; 3980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.view.accessibility.IAccessibilityInteractionConnection; 4080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 4180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport java.util.ArrayList; 4280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport java.util.concurrent.TimeoutException; 4380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 4480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov/** 4580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Class for interacting with the device's UI by simulation user actions and 4680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * introspection of the screen content. It relies on the platform accessibility 4780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * APIs to introspect the screen and to perform some actions on the remote view 4880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * tree. It also allows injecting of arbitrary raw input events simulating user 49bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * interaction with keyboards and touch devices. One can think of a UiAutomation 50bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * as a special type of {@link android.accessibilityservice.AccessibilityService} 51bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * which does not provide hooks for the service life cycle and exposes other 52bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * APIs that are useful for UI test automation. 5380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * <p> 5480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * The APIs exposed by this class are low-level to maximize flexibility when 5580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * developing UI test automation tools and libraries. Generally, a UiAutomation 5680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * client should be using a higher-level library or implement high-level functions. 5780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * For example, performing a tap on the screen requires construction and injecting 5880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * of a touch down and up events which have to be delivered to the system by a 5980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * call to {@link #injectInputEvent(InputEvent, boolean)}. 6080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * </p> 6180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * <p> 6280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * The APIs exposed by this class operate across applications enabling a client 6380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * to write tests that cover use cases spanning over multiple applications. For 6480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * example, going to the settings application to change a setting and then 6580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * interacting with another application whose behavior depends on that setting. 6680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * </p> 6780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 6880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovpublic final class UiAutomation { 6980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 7080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private static final String LOG_TAG = UiAutomation.class.getSimpleName(); 7180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 7280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private static final boolean DEBUG = false; 7380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 7480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private static final int CONNECTION_ID_UNDEFINED = -1; 7580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 7680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private static final long CONNECT_TIMEOUT_MILLIS = 5000; 7780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 7880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** Rotation constant: Unfreeze rotation (rotating the device changes its rotation state). */ 7980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public static final int ROTATION_UNFREEZE = -2; 8080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 8180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** Rotation constant: Freeze rotation to its current state. */ 8280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public static final int ROTATION_FREEZE_CURRENT = -1; 8380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 8480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** Rotation constant: Freeze rotation to 0 degrees (natural orientation) */ 8580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public static final int ROTATION_FREEZE_0 = Surface.ROTATION_0; 8680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 8780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** Rotation constant: Freeze rotation to 90 degrees . */ 8880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public static final int ROTATION_FREEZE_90 = Surface.ROTATION_90; 8980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 9080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** Rotation constant: Freeze rotation to 180 degrees . */ 9180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public static final int ROTATION_FREEZE_180 = Surface.ROTATION_180; 9280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 9380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** Rotation constant: Freeze rotation to 270 degrees . */ 9480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public static final int ROTATION_FREEZE_270 = Surface.ROTATION_270; 9580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 9680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private final Object mLock = new Object(); 9780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 9880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private final ArrayList<AccessibilityEvent> mEventQueue = new ArrayList<AccessibilityEvent>(); 9980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 10080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private final IAccessibilityServiceClient mClient; 10180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 10280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private final IUiAutomationConnection mUiAutomationConnection; 10380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 10480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private int mConnectionId = CONNECTION_ID_UNDEFINED; 10580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 10680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private OnAccessibilityEventListener mOnAccessibilityEventListener; 10780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 10880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private boolean mWaitingForEventDelivery; 10980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 11080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private long mLastEventTimeMillis; 11180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 11280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private boolean mIsConnecting; 11380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 11480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 11580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Listener for observing the {@link AccessibilityEvent} stream. 11680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 11780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public static interface OnAccessibilityEventListener { 11880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 11980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 12080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Callback for receiving an {@link AccessibilityEvent}. 12180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * <p> 12280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * <strong>Note:</strong> This method is <strong>NOT</strong> executed 12380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * on the main test thread. The client is responsible for proper 12480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * synchronization. 12580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * </p> 12680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * <p> 12780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * <strong>Note:</strong> It is responsibility of the client 12880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * to recycle the received events to minimize object creation. 12980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * </p> 13080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 13180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @param event The received event. 13280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 13380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public void onAccessibilityEvent(AccessibilityEvent event); 13480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 13580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 13680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 137550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav * Listener for filtering accessibility events. 138550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav */ 139550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav public static interface AccessibilityEventFilter { 140550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav 141550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav /** 142550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav * Callback for determining whether an event is accepted or 143550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav * it is filtered out. 144550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav * 145550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav * @param event The event to process. 146550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav * @return True if the event is accepted, false to filter it out. 147550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav */ 148550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav public boolean accept(AccessibilityEvent event); 149550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav } 150550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav 151550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav /** 15280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Creates a new instance that will handle callbacks from the accessibility 15380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * layer on the thread of the provided looper and perform requests for privileged 15480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * operations on the provided connection. 15580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 15680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @param looper The looper on which to execute accessibility callbacks. 15780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @param connection The connection for performing privileged operations. 15880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 15980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @hide 16080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 16180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public UiAutomation(Looper looper, IUiAutomationConnection connection) { 16280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (looper == null) { 16380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new IllegalArgumentException("Looper cannot be null!"); 16480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 16580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (connection == null) { 16680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new IllegalArgumentException("Connection cannot be null!"); 16780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 16880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mUiAutomationConnection = connection; 16980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mClient = new IAccessibilityServiceClientImpl(looper); 17080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 17180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 17280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 17380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Connects this UiAutomation to the accessibility introspection APIs. 17480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 17580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @hide 17680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 17780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public void connect() { 17880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 17980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throwIfConnectedLocked(); 18080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (mIsConnecting) { 18180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return; 18280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 18380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mIsConnecting = true; 18480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 18580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 18680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov try { 18780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Calling out without a lock held. 18880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mUiAutomationConnection.connect(mClient); 18980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } catch (RemoteException re) { 19080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new RuntimeException("Error while connecting UiAutomation", re); 19180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 19280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 19380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 19480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long startTimeMillis = SystemClock.uptimeMillis(); 19580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov try { 19680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov while (true) { 19780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (isConnectedLocked()) { 19880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov break; 19980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 20080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; 20180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long remainingTimeMillis = CONNECT_TIMEOUT_MILLIS - elapsedTimeMillis; 20280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (remainingTimeMillis <= 0) { 20380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new RuntimeException("Error while connecting UiAutomation"); 20480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 20580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov try { 20680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLock.wait(remainingTimeMillis); 20780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } catch (InterruptedException ie) { 20880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /* ignore */ 20980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 21080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 21180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } finally { 21280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mIsConnecting = false; 21380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 21480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 21580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 21680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 21780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 21880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Disconnects this UiAutomation from the accessibility introspection APIs. 21980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 22080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @hide 22180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 22280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public void disconnect() { 22380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 22480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (mIsConnecting) { 22580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new IllegalStateException( 22680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov "Cannot call disconnect() while connecting!"); 22780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 22880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throwIfNotConnectedLocked(); 22980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mConnectionId = CONNECTION_ID_UNDEFINED; 23080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 23180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov try { 23280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Calling out without a lock held. 23380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mUiAutomationConnection.disconnect(); 23480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } catch (RemoteException re) { 23580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new RuntimeException("Error while disconnecting UiAutomation", re); 23680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 23780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 23880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 23980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 24080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * The id of the {@link IAccessibilityInteractionConnection} for querying 24180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * the screen content. This is here for legacy purposes since some tools use 24280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * hidden APIs to introspect the screen. 24380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 24480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @hide 24580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 24680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public int getConnectionId() { 24780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 24880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throwIfNotConnectedLocked(); 24980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return mConnectionId; 25080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 25180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 25280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 25380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 25480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Sets a callback for observing the stream of {@link AccessibilityEvent}s. 25580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 25680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @param listener The callback. 25780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 25880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public void setOnAccessibilityEventListener(OnAccessibilityEventListener listener) { 25980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 26080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mOnAccessibilityEventListener = listener; 26180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 26280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 26380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 26480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 265bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * Performs a global action. Such an action can be performed at any moment 266bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * regardless of the current application or user location in that application. 267bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * For example going back, going home, opening recents, etc. 268bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * 269bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * @param action The action to perform. 270bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * @return Whether the action was successfully performed. 271bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * 272bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * @see AccessibilityService#GLOBAL_ACTION_BACK 273bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * @see AccessibilityService#GLOBAL_ACTION_HOME 274bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * @see AccessibilityService#GLOBAL_ACTION_NOTIFICATIONS 275bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * @see AccessibilityService#GLOBAL_ACTION_RECENTS 276bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav */ 277bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav public final boolean performGlobalAction(int action) { 278bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav final IAccessibilityServiceConnection connection; 279bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav synchronized (mLock) { 280bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav throwIfNotConnectedLocked(); 281bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav connection = AccessibilityInteractionClient.getInstance() 282bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav .getConnection(mConnectionId); 283bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } 284bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav // Calling out without a lock held. 285bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav if (connection != null) { 286bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav try { 287bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav return connection.performGlobalAction(action); 288bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } catch (RemoteException re) { 289bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav Log.w(LOG_TAG, "Error while calling performGlobalAction", re); 290bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } 291bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } 292bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav return false; 293bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } 294bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav 295bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav /** 296bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * Gets the an {@link AccessibilityServiceInfo} describing this UiAutomation. 297bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * This method is useful if one wants to change some of the dynamically 298bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * configurable properties at runtime. 299bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * 300bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * @return The accessibility service info. 301bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * 302bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * @see AccessibilityServiceInfo 303bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav */ 304bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav public final AccessibilityServiceInfo getServiceInfo() { 305bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav final IAccessibilityServiceConnection connection; 306bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav synchronized (mLock) { 307bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav throwIfNotConnectedLocked(); 308bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav connection = AccessibilityInteractionClient.getInstance() 309bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav .getConnection(mConnectionId); 310bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } 311bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav // Calling out without a lock held. 312bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav if (connection != null) { 313bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav try { 314bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav return connection.getServiceInfo(); 315bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } catch (RemoteException re) { 316bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re); 317bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } 318bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } 319bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav return null; 320bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } 321bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav 322bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav /** 323bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * Sets the {@link AccessibilityServiceInfo} that describes how this 324bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * UiAutomation will be handled by the platform accessibility layer. 325bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * 326bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * @param info The info. 327bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * 328bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * @see AccessibilityServiceInfo 329bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav */ 330bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav public final void setServiceInfo(AccessibilityServiceInfo info) { 331bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav final IAccessibilityServiceConnection connection; 332bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav synchronized (mLock) { 333bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav throwIfNotConnectedLocked(); 334bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav AccessibilityInteractionClient.getInstance().clearCache(); 335bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav connection = AccessibilityInteractionClient.getInstance() 336bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav .getConnection(mConnectionId); 337bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } 338bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav // Calling out without a lock held. 339bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav if (connection != null) { 340bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav try { 341bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav connection.setServiceInfo(info); 342bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } catch (RemoteException re) { 343bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re); 344bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } 345bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } 346bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav } 347bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav 348bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav /** 34980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Gets the root {@link AccessibilityNodeInfo} in the active window. 35080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 35180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @return The root info. 35280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 35380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public AccessibilityNodeInfo getRootInActiveWindow() { 35480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final int connectionId; 35580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 35680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throwIfNotConnectedLocked(); 35780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov connectionId = mConnectionId; 35880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 35980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Calling out without a lock held. 36080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return AccessibilityInteractionClient.getInstance() 36180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov .getRootInActiveWindow(connectionId); 36280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 36380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 36480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 36580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * A method for injecting an arbitrary input event. 36680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * <p> 36780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * <strong>Note:</strong> It is caller's responsibility to recycle the event. 36880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * </p> 36980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @param event The event to inject. 37080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @param sync Whether to inject the event synchronously. 37180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @return Whether event injection succeeded. 37280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 37380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public boolean injectInputEvent(InputEvent event, boolean sync) { 37480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 37580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throwIfNotConnectedLocked(); 37680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 37780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov try { 37880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (DEBUG) { 37980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Log.i(LOG_TAG, "Injecting: " + event + " sync: " + sync); 38080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 38180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Calling out without a lock held. 38280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return mUiAutomationConnection.injectInputEvent(event, sync); 38380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } catch (RemoteException re) { 38480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Log.e(LOG_TAG, "Error while injecting input event!", re); 38580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 38680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return false; 38780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 38880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 38980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 39080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Sets the device rotation. A client can freeze the rotation in 39180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * desired state or freeze the rotation to its current state or 39280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * unfreeze the rotation (rotating the device changes its rotation 39380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * state). 39480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 39580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @param rotation The desired rotation. 39680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @return Whether the rotation was set successfully. 39780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 39880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @see #ROTATION_FREEZE_0 39980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @see #ROTATION_FREEZE_90 40080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @see #ROTATION_FREEZE_180 40180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @see #ROTATION_FREEZE_270 40280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @see #ROTATION_FREEZE_CURRENT 40380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @see #ROTATION_UNFREEZE 40480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 40580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public boolean setRotation(int rotation) { 40680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 40780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throwIfNotConnectedLocked(); 40880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 40980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov switch (rotation) { 41080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case ROTATION_FREEZE_0: 41180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case ROTATION_FREEZE_90: 41280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case ROTATION_FREEZE_180: 41380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case ROTATION_FREEZE_270: 41480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case ROTATION_UNFREEZE: 41580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case ROTATION_FREEZE_CURRENT: { 41680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov try { 41780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Calling out without a lock held. 41880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mUiAutomationConnection.setRotation(rotation); 41980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return true; 42080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } catch (RemoteException re) { 42180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Log.e(LOG_TAG, "Error while setting rotation!", re); 42280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 42380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } return false; 42480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov default: { 42580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new IllegalArgumentException("Invalid rotation."); 42680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 42780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 42880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 42980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 43080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 43180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Executes a command and waits for a specific accessibility event up to a 43280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * given wait timeout. To detect a sequence of events one can implement a 43380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * filter that keeps track of seen events of the expected sequence and 43480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * returns true after the last event of that sequence is received. 43580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * <p> 43680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * <strong>Note:</strong> It is caller's responsibility to recycle the returned event. 43780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * </p> 43880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @param command The command to execute. 43980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @param filter Filter that recognizes the expected event. 44080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @param timeoutMillis The wait timeout in milliseconds. 44180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 44280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @throws TimeoutException If the expected event is not received within the timeout. 44380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 44480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public AccessibilityEvent executeAndWaitForEvent(Runnable command, 445550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav AccessibilityEventFilter filter, long timeoutMillis) throws TimeoutException { 446db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav // Acquire the lock and prepare for receiving events. 44780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 44880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throwIfNotConnectedLocked(); 44980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mEventQueue.clear(); 45080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Prepare to wait for an event. 45180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mWaitingForEventDelivery = true; 452db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav } 45380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 454db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav // Note: We have to release the lock since calling out with this lock held 455db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav // can bite. We will correctly filter out events from other interactions, 456db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav // so starting to collect events before running the action is just fine. 45780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 458db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav // We will ignore events from previous interactions. 459db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav final long executionStartTimeMillis = SystemClock.uptimeMillis(); 460db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav // Execute the command *without* the lock being held. 461db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav command.run(); 462db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav 463db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav // Acquire the lock and wait for the event. 464db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav synchronized (mLock) { 46580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov try { 46680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Wait for the event. 46780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long startTimeMillis = SystemClock.uptimeMillis(); 46880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov while (true) { 46980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Drain the event queue 47080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov while (!mEventQueue.isEmpty()) { 47180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov AccessibilityEvent event = mEventQueue.remove(0); 47280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Ignore events from previous interactions. 473db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav if (event.getEventTime() < executionStartTimeMillis) { 47480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov continue; 47580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 476550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav if (filter.accept(event)) { 47780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return event; 47880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 47980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov event.recycle(); 48080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 48180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Check if timed out and if not wait. 48280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; 48380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis; 48480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (remainingTimeMillis <= 0) { 48580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new TimeoutException("Expected event not received within: " 48680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov + timeoutMillis + " ms."); 48780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 48880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov try { 48980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLock.wait(remainingTimeMillis); 49080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } catch (InterruptedException ie) { 49180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /* ignore */ 49280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 49380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 49480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } finally { 49580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mWaitingForEventDelivery = false; 49680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mEventQueue.clear(); 49780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLock.notifyAll(); 49880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 49980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 50080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 50180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 50280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 50380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Waits for the accessibility event stream to become idle, which is not to 50480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * have received an accessibility event within <code>idleTimeoutMillis</code>. 50580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * The total time spent to wait for an idle accessibility event stream is bounded 50680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * by the <code>globalTimeoutMillis</code>. 50780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 50880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @param idleTimeoutMillis The timeout in milliseconds between two events 50980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * to consider the device idle. 51080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @param globalTimeoutMillis The maximal global timeout in milliseconds in 51180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * which to wait for an idle state. 51280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 51380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @throws TimeoutException If no idle state was detected within 51480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * <code>globalTimeoutMillis.</code> 51580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 51680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public void waitForIdle(long idleTimeoutMillis, long globalTimeoutMillis) 51780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throws TimeoutException { 51880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 51980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throwIfNotConnectedLocked(); 52080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 52180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long startTimeMillis = SystemClock.uptimeMillis(); 52280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (mLastEventTimeMillis <= 0) { 52380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLastEventTimeMillis = startTimeMillis; 52480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 52580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 52680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov while (true) { 52780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long currentTimeMillis = SystemClock.uptimeMillis(); 52880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Did we get idle state within the global timeout? 52980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long elapsedGlobalTimeMillis = currentTimeMillis - startTimeMillis; 53080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long remainingGlobalTimeMillis = 53180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov globalTimeoutMillis - elapsedGlobalTimeMillis; 53280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (remainingGlobalTimeMillis <= 0) { 53380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new TimeoutException("No idle state with idle timeout: " 53480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov + idleTimeoutMillis + " within global timeout: " 53580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov + globalTimeoutMillis); 53680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 53780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Did we get an idle state within the idle timeout? 53880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long elapsedIdleTimeMillis = currentTimeMillis - mLastEventTimeMillis; 53980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long remainingIdleTimeMillis = idleTimeoutMillis - elapsedIdleTimeMillis; 54080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (remainingIdleTimeMillis <= 0) { 54180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return; 54280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 54380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov try { 54480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLock.wait(remainingIdleTimeMillis); 54580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } catch (InterruptedException ie) { 54680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /* ignore */ 54780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 54880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 54980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 55080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 55180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 55280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 55380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Takes a screenshot. 55480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 55580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @return The screenshot bitmap on success, null otherwise. 55680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 55780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public Bitmap takeScreenshot() { 55880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 55980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throwIfNotConnectedLocked(); 56080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 56180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Display display = DisplayManagerGlobal.getInstance() 56280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov .getRealDisplay(Display.DEFAULT_DISPLAY); 56380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Point displaySize = new Point(); 56480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov display.getRealSize(displaySize); 56580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final int displayWidth = displaySize.x; 56680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final int displayHeight = displaySize.y; 56780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 56880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final float screenshotWidth; 56980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final float screenshotHeight; 57080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 57180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final int rotation = display.getRotation(); 57280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov switch (rotation) { 57380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case ROTATION_FREEZE_0: { 57480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotWidth = displayWidth; 57580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotHeight = displayHeight; 57680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } break; 57780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case ROTATION_FREEZE_90: { 57880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotWidth = displayHeight; 57980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotHeight = displayWidth; 58080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } break; 58180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case ROTATION_FREEZE_180: { 58280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotWidth = displayWidth; 58380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotHeight = displayHeight; 58480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } break; 58580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case ROTATION_FREEZE_270: { 58680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotWidth = displayHeight; 58780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotHeight = displayWidth; 58880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } break; 58980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov default: { 59080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new IllegalArgumentException("Invalid rotation: " 59180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov + rotation); 59280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 59380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 59480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 59580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Take the screenshot 59680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Bitmap screenShot = null; 59780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov try { 59880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Calling out without a lock held. 59980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenShot = mUiAutomationConnection.takeScreenshot((int) screenshotWidth, 60080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov (int) screenshotHeight); 60180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (screenShot == null) { 60280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return null; 60380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 60480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } catch (RemoteException re) { 60580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Log.e(LOG_TAG, "Error while taking screnshot!", re); 60680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return null; 60780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 60880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 60980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Rotate the screenshot to the current orientation 61080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (rotation != ROTATION_FREEZE_0) { 61180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Bitmap unrotatedScreenShot = Bitmap.createBitmap(displayWidth, displayHeight, 61280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Bitmap.Config.ARGB_8888); 61380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Canvas canvas = new Canvas(unrotatedScreenShot); 61480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov canvas.translate(unrotatedScreenShot.getWidth() / 2, 61580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov unrotatedScreenShot.getHeight() / 2); 61680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov canvas.rotate(getDegreesForRotation(rotation)); 61780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov canvas.translate(- screenshotWidth / 2, - screenshotHeight / 2); 61880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov canvas.drawBitmap(screenShot, 0, 0, null); 61980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov canvas.setBitmap(null); 62080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenShot = unrotatedScreenShot; 62180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 62280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 62380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Optimization 62480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenShot.setHasAlpha(false); 62580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 62680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return screenShot; 62780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 62880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 6298f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz /** 6308f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz * Sets whether this UiAutomation to run in a "monkey" mode. Applications can query whether 6318f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz * they are executed in a "monkey" mode, i.e. run by a test framework, and avoid doing 6328f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz * potentially undesirable actions such as calling 911 or posting on public forums etc. 6338f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz * 6348f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz * @param enable whether to run in a "monkey" mode or not. Default is not. 6358f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz * @see {@link ActivityManager#isUserAMonkey()} 6368f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz */ 6378f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz public void setRunAsMonkey(boolean enable) { 6388f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz synchronized (mLock) { 6398f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz throwIfNotConnectedLocked(); 6408f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz } 6418f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz try { 6428f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz ActivityManagerNative.getDefault().setUserIsMonkey(enable); 6438f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz } catch (RemoteException re) { 6448f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz Log.e(LOG_TAG, "Error while setting run as monkey!", re); 6458f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz } 6468f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz } 6478f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz 64880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private static float getDegreesForRotation(int value) { 64980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov switch (value) { 65080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case Surface.ROTATION_90: { 65180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return 360f - 90f; 65280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 65380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case Surface.ROTATION_180: { 65480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return 360f - 180f; 65580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 65680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case Surface.ROTATION_270: { 65780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return 360f - 270f; 65880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } default: { 65980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return 0; 66080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 66180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 66280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 66380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 66480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private boolean isConnectedLocked() { 66580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return mConnectionId != CONNECTION_ID_UNDEFINED; 66680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 66780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 66880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private void throwIfConnectedLocked() { 66980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (mConnectionId != CONNECTION_ID_UNDEFINED) { 67080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new IllegalStateException("UiAutomation not connected!"); 67180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 67280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 67380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 67480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private void throwIfNotConnectedLocked() { 67580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (!isConnectedLocked()) { 67680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new IllegalStateException("UiAutomation not connected!"); 67780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 67880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 67980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 68080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private class IAccessibilityServiceClientImpl extends IAccessibilityServiceClientWrapper { 68180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 68280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public IAccessibilityServiceClientImpl(Looper looper) { 68380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov super(null, looper, new Callbacks() { 68480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov @Override 68580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public void onSetConnectionId(int connectionId) { 68680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 68780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mConnectionId = connectionId; 68880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLock.notifyAll(); 68980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 69080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 69180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 69280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov @Override 69380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public void onServiceConnected() { 69480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /* do nothing */ 69580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 69680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 69780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov @Override 69880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public void onInterrupt() { 69980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /* do nothing */ 70080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 70180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 70280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov @Override 70380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public boolean onGesture(int gestureId) { 70480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /* do nothing */ 70580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return false; 70680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 70780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 70880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov @Override 70980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public void onAccessibilityEvent(AccessibilityEvent event) { 71080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 71180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLastEventTimeMillis = event.getEventTime(); 71280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (mWaitingForEventDelivery) { 71380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mEventQueue.add(AccessibilityEvent.obtain(event)); 71480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 71580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLock.notifyAll(); 71680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 71780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Calling out only without a lock held. 71880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final OnAccessibilityEventListener listener = mOnAccessibilityEventListener; 71980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (listener != null) { 72080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov listener.onAccessibilityEvent(AccessibilityEvent.obtain(event)); 72180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 72280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 723c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav 724c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav @Override 725c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav public boolean onKeyEvent(KeyEvent event) { 726c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav return false; 727c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav } 72880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov }); 72980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 73080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 73180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov} 732