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