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;
24214fb68767502f5fede643a062c1dc5975d75b27Alan Viveretteimport android.annotation.NonNull;
25a73b8fd1f4faaad00d8a49d6e496aaf249fa7003Jeff Sharkeyimport android.annotation.TestApi;
2680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.graphics.Bitmap;
2780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.graphics.Canvas;
2880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.graphics.Point;
29214fb68767502f5fede643a062c1dc5975d75b27Alan Viveretteimport android.graphics.Region;
3080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.hardware.display.DisplayManagerGlobal;
313a5c721072c60c7ed9c8a95d0a65d0e3cb4eb9bbSvetoslavimport android.os.IBinder;
3280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.os.Looper;
33121e0c073992658ca0ba055f40bf3b130caa819aSvetoslavimport android.os.ParcelFileDescriptor;
3480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.os.RemoteException;
3580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.os.SystemClock;
3652153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganovimport android.os.UserHandle;
3780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.util.Log;
3880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.view.Display;
3980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.view.InputEvent;
40c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslavimport android.view.KeyEvent;
4180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.view.Surface;
421376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslavimport android.view.WindowAnimationFrameStats;
431376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslavimport android.view.WindowContentFrameStats;
4480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
4580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.view.accessibility.AccessibilityInteractionClient;
4680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo;
478e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslavimport android.view.accessibility.AccessibilityWindowInfo;
4880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport android.view.accessibility.IAccessibilityInteractionConnection;
49121e0c073992658ca0ba055f40bf3b130caa819aSvetoslavimport libcore.io.IoUtils;
5080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
51121e0c073992658ca0ba055f40bf3b130caa819aSvetoslavimport java.io.IOException;
5280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport java.util.ArrayList;
538e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslavimport java.util.List;
5480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovimport java.util.concurrent.TimeoutException;
5580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
5680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov/**
5780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Class for interacting with the device's UI by simulation user actions and
5880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * introspection of the screen content. It relies on the platform accessibility
5980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * APIs to introspect the screen and to perform some actions on the remote view
6080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * tree. It also allows injecting of arbitrary raw input events simulating user
61bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * interaction with keyboards and touch devices. One can think of a UiAutomation
62bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * as a special type of {@link android.accessibilityservice.AccessibilityService}
63bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * which does not provide hooks for the service life cycle and exposes other
64bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav * APIs that are useful for UI test automation.
6580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * <p>
6680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * The APIs exposed by this class are low-level to maximize flexibility when
6780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * developing UI test automation tools and libraries. Generally, a UiAutomation
6880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * client should be using a higher-level library or implement high-level functions.
6980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * For example, performing a tap on the screen requires construction and injecting
7080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * of a touch down and up events which have to be delivered to the system by a
7180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * call to {@link #injectInputEvent(InputEvent, boolean)}.
7280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * </p>
7380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * <p>
7480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * The APIs exposed by this class operate across applications enabling a client
7580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * to write tests that cover use cases spanning over multiple applications. For
7680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * example, going to the settings application to change a setting and then
7780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * interacting with another application whose behavior depends on that setting.
7880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * </p>
7980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */
8080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganovpublic final class UiAutomation {
8180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
8280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private static final String LOG_TAG = UiAutomation.class.getSimpleName();
8380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
8480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private static final boolean DEBUG = false;
8580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
8680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private static final int CONNECTION_ID_UNDEFINED = -1;
8780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
8880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private static final long CONNECT_TIMEOUT_MILLIS = 5000;
8980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
9080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /** Rotation constant: Unfreeze rotation (rotating the device changes its rotation state). */
9180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public static final int ROTATION_UNFREEZE = -2;
9280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
9380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /** Rotation constant: Freeze rotation to its current state. */
9480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public static final int ROTATION_FREEZE_CURRENT = -1;
9580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
9680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /** Rotation constant: Freeze rotation to 0 degrees (natural orientation) */
9780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public static final int ROTATION_FREEZE_0 = Surface.ROTATION_0;
9880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
9980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /** Rotation constant: Freeze rotation to 90 degrees . */
10080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public static final int ROTATION_FREEZE_90 = Surface.ROTATION_90;
10180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
10280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /** Rotation constant: Freeze rotation to 180 degrees . */
10380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public static final int ROTATION_FREEZE_180 = Surface.ROTATION_180;
10480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
10580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /** Rotation constant: Freeze rotation to 270 degrees . */
10680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public static final int ROTATION_FREEZE_270 = Surface.ROTATION_270;
10780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
1081dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    /**
1091dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * UiAutomation supresses accessibility services by default. This flag specifies that
1101dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * existing accessibility services should continue to run, and that new ones may start.
1111dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * This flag is set when obtaining the UiAutomation from
1121dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * {@link Instrumentation#getUiAutomation(int)}.
1131dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     */
1141dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 0x00000001;
1151dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver
11680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private final Object mLock = new Object();
11780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
11880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private final ArrayList<AccessibilityEvent> mEventQueue = new ArrayList<AccessibilityEvent>();
11980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
12080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private final IAccessibilityServiceClient mClient;
12180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
12280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private final IUiAutomationConnection mUiAutomationConnection;
12380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
12480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private int mConnectionId = CONNECTION_ID_UNDEFINED;
12580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
12680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private OnAccessibilityEventListener mOnAccessibilityEventListener;
12780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
12880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private boolean mWaitingForEventDelivery;
12980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
13080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private long mLastEventTimeMillis;
13180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
13280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private boolean mIsConnecting;
13380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
1341dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    private boolean mIsDestroyed;
1351dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver
1361dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    private int mFlags;
1371dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver
13880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /**
13980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * Listener for observing the {@link AccessibilityEvent} stream.
14080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     */
14180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public static interface OnAccessibilityEventListener {
14280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
14380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        /**
14480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov         * Callback for receiving an {@link AccessibilityEvent}.
14580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov         * <p>
14680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov         * <strong>Note:</strong> This method is <strong>NOT</strong> executed
14780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov         * on the main test thread. The client is responsible for proper
14880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov         * synchronization.
14980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov         * </p>
15080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov         * <p>
15180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov         * <strong>Note:</strong> It is responsibility of the client
15280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov         * to recycle the received events to minimize object creation.
15380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov         * </p>
15480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov         *
15580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov         * @param event The received event.
15680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov         */
15780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        public void onAccessibilityEvent(AccessibilityEvent event);
15880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
15980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
16080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /**
161550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav     * Listener for filtering accessibility events.
162550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav     */
163550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav    public static interface AccessibilityEventFilter {
164550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav
165550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav        /**
166550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav         * Callback for determining whether an event is accepted or
167550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav         * it is filtered out.
168550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav         *
169550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav         * @param event The event to process.
170550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav         * @return True if the event is accepted, false to filter it out.
171550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav         */
172550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav        public boolean accept(AccessibilityEvent event);
173550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav    }
174550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav
175550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav    /**
17680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * Creates a new instance that will handle callbacks from the accessibility
17780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * layer on the thread of the provided looper and perform requests for privileged
17880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * operations on the provided connection.
17980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *
18080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @param looper The looper on which to execute accessibility callbacks.
18180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @param connection The connection for performing privileged operations.
18280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *
18380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @hide
18480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     */
18580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public UiAutomation(Looper looper, IUiAutomationConnection connection) {
18680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        if (looper == null) {
18780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throw new IllegalArgumentException("Looper cannot be null!");
18880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
18980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        if (connection == null) {
19080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throw new IllegalArgumentException("Connection cannot be null!");
19180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
19280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        mUiAutomationConnection = connection;
19380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        mClient = new IAccessibilityServiceClientImpl(looper);
19480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
19580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
19680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /**
1971dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * Connects this UiAutomation to the accessibility introspection APIs with default flags.
19880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *
19980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @hide
20080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     */
20180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public void connect() {
2021dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver        connect(0);
2031dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    }
2041dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver
2051dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    /**
2061dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * Connects this UiAutomation to the accessibility introspection APIs.
2071dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     *
2081dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * @param flags Any flags to apply to the automation as it gets connected
2091dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     *
2101dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * @hide
2111dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     */
2121dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    public void connect(int flags) {
21380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        synchronized (mLock) {
21480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throwIfConnectedLocked();
21580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            if (mIsConnecting) {
21680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                return;
21780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            }
21880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            mIsConnecting = true;
21980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
22080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
22180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        try {
22280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            // Calling out without a lock held.
2231dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver            mUiAutomationConnection.connect(mClient, flags);
2241dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver            mFlags = flags;
22580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        } catch (RemoteException re) {
22680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throw new RuntimeException("Error while connecting UiAutomation", re);
22780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
22880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
22980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        synchronized (mLock) {
23080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            final long startTimeMillis = SystemClock.uptimeMillis();
23180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            try {
23280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                while (true) {
23380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    if (isConnectedLocked()) {
23480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                        break;
23580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    }
23680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
23780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    final long remainingTimeMillis = CONNECT_TIMEOUT_MILLIS - elapsedTimeMillis;
23880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    if (remainingTimeMillis <= 0) {
23980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                        throw new RuntimeException("Error while connecting UiAutomation");
24080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    }
24180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    try {
24280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                        mLock.wait(remainingTimeMillis);
24380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    } catch (InterruptedException ie) {
24480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                        /* ignore */
24580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    }
24680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                }
24780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            } finally {
24880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                mIsConnecting = false;
24980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            }
25080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
25180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
25280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
25380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /**
2541dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * Get the flags used to connect the service.
2551dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     *
2561dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * @return The flags used to connect
2571dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     *
2581dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * @hide
2591dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     */
2601dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    public int getFlags() {
2611dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver        return mFlags;
2621dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    }
2631dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver
2641dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    /**
26580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * Disconnects this UiAutomation from the accessibility introspection APIs.
26680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *
26780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @hide
26880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     */
26980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public void disconnect() {
27080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        synchronized (mLock) {
27180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            if (mIsConnecting) {
27280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                throw new IllegalStateException(
27380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                        "Cannot call disconnect() while connecting!");
27480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            }
27580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throwIfNotConnectedLocked();
27680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            mConnectionId = CONNECTION_ID_UNDEFINED;
27780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
27880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        try {
27980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            // Calling out without a lock held.
28080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            mUiAutomationConnection.disconnect();
28180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        } catch (RemoteException re) {
28280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throw new RuntimeException("Error while disconnecting UiAutomation", re);
28380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
28480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
28580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
28680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /**
28780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * The id of the {@link IAccessibilityInteractionConnection} for querying
28880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * the screen content. This is here for legacy purposes since some tools use
28980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * hidden APIs to introspect the screen.
29080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *
29180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @hide
29280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     */
29380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public int getConnectionId() {
29480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        synchronized (mLock) {
29580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throwIfNotConnectedLocked();
29680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            return mConnectionId;
29780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
29880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
29980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
30080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /**
3011dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * Reports if the object has been destroyed
3021dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     *
3031dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * @return {code true} if the object has been destroyed.
3041dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     *
3051dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * @hide
3061dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     */
3071dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    public boolean isDestroyed() {
3081dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver        return mIsDestroyed;
3091dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    }
3101dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver
3111dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    /**
31280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * Sets a callback for observing the stream of {@link AccessibilityEvent}s.
31380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *
31480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @param listener The callback.
31580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     */
31680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public void setOnAccessibilityEventListener(OnAccessibilityEventListener listener) {
31780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        synchronized (mLock) {
31880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            mOnAccessibilityEventListener = listener;
31980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
32080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
32180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
32280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /**
3231dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * Destroy this UiAutomation. After calling this method, attempting to use the object will
3241dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     * result in errors.
325e6269c3f1d93582f0bcc18e37227ed4eec001a17Phil Weaver     *
326e6269c3f1d93582f0bcc18e37227ed4eec001a17Phil Weaver     * @hide
3271dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver     */
328e6269c3f1d93582f0bcc18e37227ed4eec001a17Phil Weaver    @TestApi
3291dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    public void destroy() {
3301dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver        disconnect();
3311dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver        mIsDestroyed = true;
3321dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    }
3331dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver
3341dd872260b3ccfbe492d1be0bdbb3f98235b3ba3Phil Weaver    /**
335bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     * Performs a global action. Such an action can be performed at any moment
336bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     * regardless of the current application or user location in that application.
337bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     * For example going back, going home, opening recents, etc.
338bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     *
339bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     * @param action The action to perform.
340bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     * @return Whether the action was successfully performed.
341bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     *
3428e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * @see android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_BACK
3438e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * @see android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_HOME
3448e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * @see android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_NOTIFICATIONS
3458e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * @see android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_RECENTS
346bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     */
347bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav    public final boolean performGlobalAction(int action) {
348bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        final IAccessibilityServiceConnection connection;
349bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        synchronized (mLock) {
350bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            throwIfNotConnectedLocked();
351bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            connection = AccessibilityInteractionClient.getInstance()
352bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav                    .getConnection(mConnectionId);
353bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        }
354bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        // Calling out without a lock held.
355bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        if (connection != null) {
356bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            try {
357bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav                return connection.performGlobalAction(action);
358bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            } catch (RemoteException re) {
359bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav                Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
360bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            }
361bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        }
362bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        return false;
363bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav    }
364bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav
365bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav    /**
3661e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     * Find the view that has the specified focus type. The search is performed
3671e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     * across all windows.
3681e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     * <p>
3691e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     * <strong>Note:</strong> In order to access the windows you have to opt-in
3701e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     * to retrieve the interactive windows by setting the
3711e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     * {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} flag.
3721e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     * Otherwise, the search will be performed only in the active window.
3731e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     * </p>
3741e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     *
3751e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
3761e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     *         {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
3771e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     * @return The node info of the focused view or null.
3781e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     *
3791e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     * @see AccessibilityNodeInfo#FOCUS_INPUT
3801e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
3811e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav     */
3821e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav    public AccessibilityNodeInfo findFocus(int focus) {
3831e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav        return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
384f00cd14f17c0acd6bffe78947d32ea0a2900d139Phil Weaver                AccessibilityWindowInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
3851e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav    }
3861e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav
3871e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav    /**
388bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     * Gets the an {@link AccessibilityServiceInfo} describing this UiAutomation.
389bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     * This method is useful if one wants to change some of the dynamically
390bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     * configurable properties at runtime.
391bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     *
392bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     * @return The accessibility service info.
393bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     *
394bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     * @see AccessibilityServiceInfo
395bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     */
396bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav    public final AccessibilityServiceInfo getServiceInfo() {
397bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        final IAccessibilityServiceConnection connection;
398bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        synchronized (mLock) {
399bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            throwIfNotConnectedLocked();
400bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            connection = AccessibilityInteractionClient.getInstance()
401bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav                    .getConnection(mConnectionId);
402bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        }
403bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        // Calling out without a lock held.
404bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        if (connection != null) {
405bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            try {
406bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav                return connection.getServiceInfo();
407bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            } catch (RemoteException re) {
408bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav                Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
409bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            }
410bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        }
411bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        return null;
412bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav    }
413bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav
414bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav    /**
415bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     * Sets the {@link AccessibilityServiceInfo} that describes how this
416bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     * UiAutomation will be handled by the platform accessibility layer.
417bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     *
418bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     * @param info The info.
419bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     *
420bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     * @see AccessibilityServiceInfo
421bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav     */
422bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav    public final void setServiceInfo(AccessibilityServiceInfo info) {
423bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        final IAccessibilityServiceConnection connection;
424bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        synchronized (mLock) {
425bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            throwIfNotConnectedLocked();
426bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            AccessibilityInteractionClient.getInstance().clearCache();
427bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            connection = AccessibilityInteractionClient.getInstance()
428bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav                    .getConnection(mConnectionId);
429bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        }
430bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        // Calling out without a lock held.
431bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        if (connection != null) {
432bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            try {
433bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav                connection.setServiceInfo(info);
434bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            } catch (RemoteException re) {
435bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav                Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
436bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav            }
437bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav        }
438bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav    }
439bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav
440bbfa585d70a6e406ccb59c17eec73ccd55e5c8e0Svetoslav    /**
4418e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * Gets the windows on the screen. This method returns only the windows
4428e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * that a sighted user can interact with, as opposed to all windows.
4438e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * For example, if there is a modal dialog shown and the user cannot touch
4448e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * anything behind it, then only the modal window will be reported
4458e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * (assuming it is the top one). For convenience the returned windows
4468e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * are ordered in a descending layer order, which is the windows that
4478e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * are higher in the Z-order are reported first.
4488e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * <p>
4498e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * <strong>Note:</strong> In order to access the windows you have to opt-in
4508e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * to retrieve the interactive windows by setting the
4518e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} flag.
4528e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * </p>
4538e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     *
4548e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     * @return The windows if there are windows such, otherwise an empty list.
4558e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav     */
4568e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav    public List<AccessibilityWindowInfo> getWindows() {
4578e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav        final int connectionId;
4588e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav        synchronized (mLock) {
4598e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav            throwIfNotConnectedLocked();
4608e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav            connectionId = mConnectionId;
4618e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav        }
4628e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav        // Calling out without a lock held.
4638e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav        return AccessibilityInteractionClient.getInstance()
4648e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav                .getWindows(connectionId);
4658e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav    }
4668e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav
4678e3feb15c5aec2c72b0ef120a1da325e1e8f0ddaSvetoslav    /**
46880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * Gets the root {@link AccessibilityNodeInfo} in the active window.
46980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *
47080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @return The root info.
47180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     */
47280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public AccessibilityNodeInfo getRootInActiveWindow() {
47380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        final int connectionId;
47480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        synchronized (mLock) {
47580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throwIfNotConnectedLocked();
47680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            connectionId = mConnectionId;
47780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
47880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        // Calling out without a lock held.
47980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        return AccessibilityInteractionClient.getInstance()
48080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                .getRootInActiveWindow(connectionId);
48180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
48280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
48380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /**
48480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * A method for injecting an arbitrary input event.
48580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * <p>
48680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * <strong>Note:</strong> It is caller's responsibility to recycle the event.
48780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * </p>
48880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @param event The event to inject.
48980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @param sync Whether to inject the event synchronously.
49080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @return Whether event injection succeeded.
49180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     */
49280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public boolean injectInputEvent(InputEvent event, boolean sync) {
49380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        synchronized (mLock) {
49480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throwIfNotConnectedLocked();
49580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
49680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        try {
49780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            if (DEBUG) {
49880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                Log.i(LOG_TAG, "Injecting: " + event + " sync: " + sync);
49980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            }
50080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            // Calling out without a lock held.
50180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            return mUiAutomationConnection.injectInputEvent(event, sync);
50280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        } catch (RemoteException re) {
50380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            Log.e(LOG_TAG, "Error while injecting input event!", re);
50480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
50580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        return false;
50680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
50780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
50880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /**
50980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * Sets the device rotation. A client can freeze the rotation in
51080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * desired state or freeze the rotation to its current state or
51180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * unfreeze the rotation (rotating the device changes its rotation
51280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * state).
51380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *
51480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @param rotation The desired rotation.
51580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @return Whether the rotation was set successfully.
51680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *
51780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @see #ROTATION_FREEZE_0
51880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @see #ROTATION_FREEZE_90
51980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @see #ROTATION_FREEZE_180
52080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @see #ROTATION_FREEZE_270
52180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @see #ROTATION_FREEZE_CURRENT
52280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @see #ROTATION_UNFREEZE
52380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     */
52480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public boolean setRotation(int rotation) {
52580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        synchronized (mLock) {
52680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throwIfNotConnectedLocked();
52780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
52880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        switch (rotation) {
52980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            case ROTATION_FREEZE_0:
53080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            case ROTATION_FREEZE_90:
53180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            case ROTATION_FREEZE_180:
53280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            case ROTATION_FREEZE_270:
53380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            case ROTATION_UNFREEZE:
53480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            case ROTATION_FREEZE_CURRENT: {
53580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                try {
53680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    // Calling out without a lock held.
53780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    mUiAutomationConnection.setRotation(rotation);
53880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    return true;
53980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                } catch (RemoteException re) {
54080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    Log.e(LOG_TAG, "Error while setting rotation!", re);
54180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                }
54280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            } return false;
54380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            default: {
54480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                throw new IllegalArgumentException("Invalid rotation.");
54580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            }
54680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
54780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
54880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
54980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /**
55080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * Executes a command and waits for a specific accessibility event up to a
55180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * given wait timeout. To detect a sequence of events one can implement a
55280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * filter that keeps track of seen events of the expected sequence and
55380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * returns true after the last event of that sequence is received.
55480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * <p>
55580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * <strong>Note:</strong> It is caller's responsibility to recycle the returned event.
55680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * </p>
55780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @param command The command to execute.
55880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @param filter Filter that recognizes the expected event.
55980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @param timeoutMillis The wait timeout in milliseconds.
56080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *
56180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @throws TimeoutException If the expected event is not received within the timeout.
56280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     */
56380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public AccessibilityEvent executeAndWaitForEvent(Runnable command,
564550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav            AccessibilityEventFilter filter, long timeoutMillis) throws TimeoutException {
565db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav        // Acquire the lock and prepare for receiving events.
56680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        synchronized (mLock) {
56780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throwIfNotConnectedLocked();
56880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            mEventQueue.clear();
56980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            // Prepare to wait for an event.
57080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            mWaitingForEventDelivery = true;
571db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav        }
57280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
573db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav        // Note: We have to release the lock since calling out with this lock held
574db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav        // can bite. We will correctly filter out events from other interactions,
575db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav        // so starting to collect events before running the action is just fine.
57680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
577db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav        // We will ignore events from previous interactions.
578db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav        final long executionStartTimeMillis = SystemClock.uptimeMillis();
579db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav        // Execute the command *without* the lock being held.
580db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav        command.run();
581db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav
582db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav        // Acquire the lock and wait for the event.
5834d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver        try {
5844d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver            // Wait for the event.
5854d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver            final long startTimeMillis = SystemClock.uptimeMillis();
5864d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver            while (true) {
5874d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                List<AccessibilityEvent> localEvents = new ArrayList<>();
5884d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                synchronized (mLock) {
5894d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                    localEvents.addAll(mEventQueue);
5904d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                    mEventQueue.clear();
5914d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                }
5924d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                // Drain the event queue
5934d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                while (!localEvents.isEmpty()) {
5944d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                    AccessibilityEvent event = localEvents.remove(0);
5954d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                    // Ignore events from previous interactions.
5964d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                    if (event.getEventTime() < executionStartTimeMillis) {
5974d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                        continue;
59880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    }
5994d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                    if (filter.accept(event)) {
6004d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                        return event;
60180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    }
6024d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                    event.recycle();
6034d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                }
6044d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                // Check if timed out and if not wait.
6054d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
6064d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis;
6074d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                if (remainingTimeMillis <= 0) {
6084d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                    throw new TimeoutException("Expected event not received within: "
6094d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                            + timeoutMillis + " ms.");
6104d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                }
6114d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                synchronized (mLock) {
6124d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                    if (mEventQueue.isEmpty()) {
6134d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                        try {
6144d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                            mLock.wait(remainingTimeMillis);
6154d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                        } catch (InterruptedException ie) {
6164d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                            /* ignore */
6174d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver                        }
61880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    }
61980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                }
6204d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver            }
6214d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver        } finally {
6224d3eec411b3a1337083fe93bfd5385a7f26c30f6Phil Weaver            synchronized (mLock) {
62380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                mWaitingForEventDelivery = false;
62480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                mEventQueue.clear();
62580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                mLock.notifyAll();
62680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            }
62780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
62880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
62980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
63080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /**
63180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * Waits for the accessibility event stream to become idle, which is not to
63280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * have received an accessibility event within <code>idleTimeoutMillis</code>.
63380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * The total time spent to wait for an idle accessibility event stream is bounded
63480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * by the <code>globalTimeoutMillis</code>.
63580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *
63680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @param idleTimeoutMillis The timeout in milliseconds between two events
63780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *            to consider the device idle.
63880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @param globalTimeoutMillis The maximal global timeout in milliseconds in
63980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *            which to wait for an idle state.
64080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *
64180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @throws TimeoutException If no idle state was detected within
64280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *            <code>globalTimeoutMillis.</code>
64380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     */
64480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public void waitForIdle(long idleTimeoutMillis, long globalTimeoutMillis)
64580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throws TimeoutException {
64680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        synchronized (mLock) {
64780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throwIfNotConnectedLocked();
64880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
64980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            final long startTimeMillis = SystemClock.uptimeMillis();
65080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            if (mLastEventTimeMillis <= 0) {
65180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                mLastEventTimeMillis = startTimeMillis;
65280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            }
65380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
65480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            while (true) {
65580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                final long currentTimeMillis = SystemClock.uptimeMillis();
65680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                // Did we get idle state within the global timeout?
65780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                final long elapsedGlobalTimeMillis = currentTimeMillis - startTimeMillis;
65880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                final long remainingGlobalTimeMillis =
65980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                        globalTimeoutMillis - elapsedGlobalTimeMillis;
66080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                if (remainingGlobalTimeMillis <= 0) {
66180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    throw new TimeoutException("No idle state with idle timeout: "
66280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                            + idleTimeoutMillis + " within global timeout: "
66380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                            + globalTimeoutMillis);
66480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                }
66580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                // Did we get an idle state within the idle timeout?
66680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                final long elapsedIdleTimeMillis = currentTimeMillis - mLastEventTimeMillis;
66780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                final long remainingIdleTimeMillis = idleTimeoutMillis - elapsedIdleTimeMillis;
66880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                if (remainingIdleTimeMillis <= 0) {
66980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    return;
67080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                }
67180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                try {
67280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                     mLock.wait(remainingIdleTimeMillis);
67380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                } catch (InterruptedException ie) {
67480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                     /* ignore */
67580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                }
67680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            }
67780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
67880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
67980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
68080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    /**
68180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * Takes a screenshot.
68280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     *
68380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     * @return The screenshot bitmap on success, null otherwise.
68480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov     */
68580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    public Bitmap takeScreenshot() {
68680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        synchronized (mLock) {
68780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throwIfNotConnectedLocked();
68880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
68980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        Display display = DisplayManagerGlobal.getInstance()
69080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                .getRealDisplay(Display.DEFAULT_DISPLAY);
69180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        Point displaySize = new Point();
69280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        display.getRealSize(displaySize);
69380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        final int displayWidth = displaySize.x;
69480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        final int displayHeight = displaySize.y;
69580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
69680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        final float screenshotWidth;
69780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        final float screenshotHeight;
69880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
69980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        final int rotation = display.getRotation();
70080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        switch (rotation) {
70180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            case ROTATION_FREEZE_0: {
70280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                screenshotWidth = displayWidth;
70380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                screenshotHeight = displayHeight;
70480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            } break;
70580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            case ROTATION_FREEZE_90: {
70680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                screenshotWidth = displayHeight;
70780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                screenshotHeight = displayWidth;
70880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            } break;
70980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            case ROTATION_FREEZE_180: {
71080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                screenshotWidth = displayWidth;
71180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                screenshotHeight = displayHeight;
71280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            } break;
71380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            case ROTATION_FREEZE_270: {
71480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                screenshotWidth = displayHeight;
71580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                screenshotHeight = displayWidth;
71680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            } break;
71780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            default: {
71880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                throw new IllegalArgumentException("Invalid rotation: "
71980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                        + rotation);
72080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            }
72180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
72280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
72380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        // Take the screenshot
72480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        Bitmap screenShot = null;
72580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        try {
72680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            // Calling out without a lock held.
72780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            screenShot = mUiAutomationConnection.takeScreenshot((int) screenshotWidth,
72880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    (int) screenshotHeight);
72980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            if (screenShot == null) {
73080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                return null;
73180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            }
73280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        } catch (RemoteException re) {
73380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            Log.e(LOG_TAG, "Error while taking screnshot!", re);
73480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            return null;
73580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
73680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
73780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        // Rotate the screenshot to the current orientation
73880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        if (rotation != ROTATION_FREEZE_0) {
73980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            Bitmap unrotatedScreenShot = Bitmap.createBitmap(displayWidth, displayHeight,
74080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    Bitmap.Config.ARGB_8888);
74180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            Canvas canvas = new Canvas(unrotatedScreenShot);
74280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            canvas.translate(unrotatedScreenShot.getWidth() / 2,
74380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    unrotatedScreenShot.getHeight() / 2);
74480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            canvas.rotate(getDegreesForRotation(rotation));
74580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            canvas.translate(- screenshotWidth / 2, - screenshotHeight / 2);
74680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            canvas.drawBitmap(screenShot, 0, 0, null);
74780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            canvas.setBitmap(null);
748b101ebe8a63ee1b6fc90135d661f4fe19c2e5f07Leon Scroggins III            screenShot.recycle();
74980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            screenShot = unrotatedScreenShot;
75080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
75180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
75280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        // Optimization
75380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        screenShot.setHasAlpha(false);
75480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
75580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        return screenShot;
75680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
75780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
7588f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz    /**
7598f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz     * Sets whether this UiAutomation to run in a "monkey" mode. Applications can query whether
7608f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz     * they are executed in a "monkey" mode, i.e. run by a test framework, and avoid doing
7618f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz     * potentially undesirable actions such as calling 911 or posting on public forums etc.
7628f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz     *
7638f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz     * @param enable whether to run in a "monkey" mode or not. Default is not.
764a9f6a9b769b71d89382b9b8c158b168cd7b4c692Quddus Chong     * @see ActivityManager#isUserAMonkey()
7658f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz     */
7668f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz    public void setRunAsMonkey(boolean enable) {
7678f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz        synchronized (mLock) {
7688f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz            throwIfNotConnectedLocked();
7698f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz        }
7708f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz        try {
771dc589ac82b5fe2063f4cfd94c8ae26d43d5420a0Sudheer Shanka            ActivityManager.getService().setUserIsMonkey(enable);
7728f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz        } catch (RemoteException re) {
7738f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz            Log.e(LOG_TAG, "Error while setting run as monkey!", re);
7748f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz        }
7758f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz    }
7768f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz
7771376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav    /**
7781376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * Clears the frame statistics for the content of a given window. These
7791376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * statistics contain information about the most recently rendered content
7801376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * frames.
7811376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     *
7821376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @param windowId The window id.
7831376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @return Whether the window is present and its frame statistics
7841376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     *         were cleared.
7851376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     *
7861376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @see android.view.WindowContentFrameStats
7871376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @see #getWindowContentFrameStats(int)
7881376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @see #getWindows()
7891376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @see AccessibilityWindowInfo#getId() AccessibilityWindowInfo.getId()
7901376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     */
7911376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav    public boolean clearWindowContentFrameStats(int windowId) {
7921376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        synchronized (mLock) {
7931376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            throwIfNotConnectedLocked();
7941376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        }
7951376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        try {
7961376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            if (DEBUG) {
7971376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav                Log.i(LOG_TAG, "Clearing content frame stats for window: " + windowId);
7981376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            }
7991376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            // Calling out without a lock held.
8001376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            return mUiAutomationConnection.clearWindowContentFrameStats(windowId);
8011376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        } catch (RemoteException re) {
8021376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            Log.e(LOG_TAG, "Error clearing window content frame stats!", re);
8031376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        }
8041376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        return false;
8051376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav    }
8061376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav
8071376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav    /**
8081376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * Gets the frame statistics for a given window. These statistics contain
8091376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * information about the most recently rendered content frames.
8101376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * <p>
8111376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * A typical usage requires clearing the window frame statistics via {@link
8121376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * #clearWindowContentFrameStats(int)} followed by an interaction with the UI and
8131376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * finally getting the window frame statistics via calling this method.
8141376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * </p>
8151376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * <pre>
8161376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * // Assume we have at least one window.
8171376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * final int windowId = getWindows().get(0).getId();
8181376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     *
8191376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * // Start with a clean slate.
8201376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * uiAutimation.clearWindowContentFrameStats(windowId);
8211376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     *
8221376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * // Do stuff with the UI.
8231376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     *
8241376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * // Get the frame statistics.
8251376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * WindowContentFrameStats stats = uiAutomation.getWindowContentFrameStats(windowId);
8261376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * </pre>
8271376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     *
8281376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @param windowId The window id.
8291376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @return The window frame statistics, or null if the window is not present.
8301376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     *
8311376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @see android.view.WindowContentFrameStats
8321376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @see #clearWindowContentFrameStats(int)
8331376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @see #getWindows()
8341376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @see AccessibilityWindowInfo#getId() AccessibilityWindowInfo.getId()
8351376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     */
8361376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav    public WindowContentFrameStats getWindowContentFrameStats(int windowId) {
8371376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        synchronized (mLock) {
8381376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            throwIfNotConnectedLocked();
8391376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        }
8401376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        try {
8411376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            if (DEBUG) {
8421376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav                Log.i(LOG_TAG, "Getting content frame stats for window: " + windowId);
8431376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            }
8441376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            // Calling out without a lock held.
8451376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            return mUiAutomationConnection.getWindowContentFrameStats(windowId);
8461376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        } catch (RemoteException re) {
8471376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            Log.e(LOG_TAG, "Error getting window content frame stats!", re);
8481376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        }
8491376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        return null;
8501376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav    }
8511376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav
8521376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav    /**
8531376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * Clears the window animation rendering statistics. These statistics contain
8541376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * information about the most recently rendered window animation frames, i.e.
8551376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * for window transition animations.
8561376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     *
8571376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @see android.view.WindowAnimationFrameStats
8581376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @see #getWindowAnimationFrameStats()
8591376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @see android.R.styleable#WindowAnimation
8601376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     */
8611376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav    public void clearWindowAnimationFrameStats() {
8621376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        synchronized (mLock) {
8631376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            throwIfNotConnectedLocked();
8641376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        }
8651376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        try {
8661376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            if (DEBUG) {
8671376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav                Log.i(LOG_TAG, "Clearing window animation frame stats");
8681376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            }
8691376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            // Calling out without a lock held.
8701376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            mUiAutomationConnection.clearWindowAnimationFrameStats();
8711376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        } catch (RemoteException re) {
8721376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            Log.e(LOG_TAG, "Error clearing window animation frame stats!", re);
8731376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        }
8741376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav    }
8751376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav
8761376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav    /**
8771376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * Gets the window animation frame statistics. These statistics contain
8781376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * information about the most recently rendered window animation frames, i.e.
8791376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * for window transition animations.
8801376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     *
8811376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * <p>
8821376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * A typical usage requires clearing the window animation frame statistics via
8831376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * {@link #clearWindowAnimationFrameStats()} followed by an interaction that causes
8841376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * a window transition which uses a window animation and finally getting the window
8851376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * animation frame statistics by calling this method.
8861376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * </p>
8871376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * <pre>
8881376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * // Start with a clean slate.
8891376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * uiAutimation.clearWindowAnimationFrameStats();
8901376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     *
8911376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * // Do stuff to trigger a window transition.
8921376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     *
8931376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * // Get the frame statistics.
8941376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * WindowAnimationFrameStats stats = uiAutomation.getWindowAnimationFrameStats();
8951376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * </pre>
8961376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     *
8971376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @return The window animation frame statistics.
8981376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     *
8991376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @see android.view.WindowAnimationFrameStats
9001376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @see #clearWindowAnimationFrameStats()
9011376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     * @see android.R.styleable#WindowAnimation
9021376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav     */
9031376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav    public WindowAnimationFrameStats getWindowAnimationFrameStats() {
9041376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        synchronized (mLock) {
9051376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            throwIfNotConnectedLocked();
9061376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        }
9071376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        try {
9081376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            if (DEBUG) {
9091376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav                Log.i(LOG_TAG, "Getting window animation frame stats");
9101376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            }
9111376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            // Calling out without a lock held.
9121376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            return mUiAutomationConnection.getWindowAnimationFrameStats();
9131376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        } catch (RemoteException re) {
9141376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav            Log.e(LOG_TAG, "Error getting window animation frame stats!", re);
9151376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        }
9161376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav        return null;
9171376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav    }
9181376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav
919121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav    /**
92052153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov     * Grants a runtime permission to a package for a user.
92152153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov     * @param packageName The package to which to grant.
92252153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov     * @param permission The permission to grant.
92352153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov     * @return Whether granting succeeded.
92452153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov     *
92552153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov     * @hide
92652153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov     */
927a73b8fd1f4faaad00d8a49d6e496aaf249fa7003Jeff Sharkey    @TestApi
92852153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov    public boolean grantRuntimePermission(String packageName, String permission,
92952153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            UserHandle userHandle) {
93052153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov        synchronized (mLock) {
93152153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            throwIfNotConnectedLocked();
93252153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov        }
93352153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov        try {
93452153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            if (DEBUG) {
93552153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov                Log.i(LOG_TAG, "Granting runtime permission");
93652153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            }
93752153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            // Calling out without a lock held.
93852153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            mUiAutomationConnection.grantRuntimePermission(packageName,
93952153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov                    permission, userHandle.getIdentifier());
94052153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            // TODO: The package manager API should return boolean.
94152153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            return true;
94252153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov        } catch (RemoteException re) {
94352153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            Log.e(LOG_TAG, "Error granting runtime permission", re);
94452153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov        }
94552153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov        return false;
94652153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov    }
94752153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov
94852153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov    /**
94952153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov     * Revokes a runtime permission from a package for a user.
95052153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov     * @param packageName The package from which to revoke.
95152153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov     * @param permission The permission to revoke.
95252153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov     * @return Whether revoking succeeded.
95352153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov     *
95452153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov     * @hide
95552153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov     */
956a73b8fd1f4faaad00d8a49d6e496aaf249fa7003Jeff Sharkey    @TestApi
95752153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov    public boolean revokeRuntimePermission(String packageName, String permission,
95852153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            UserHandle userHandle) {
95952153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov        synchronized (mLock) {
96052153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            throwIfNotConnectedLocked();
96152153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov        }
96252153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov        try {
96352153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            if (DEBUG) {
96452153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov                Log.i(LOG_TAG, "Revoking runtime permission");
96552153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            }
96652153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            // Calling out without a lock held.
96752153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            mUiAutomationConnection.revokeRuntimePermission(packageName,
96852153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov                    permission, userHandle.getIdentifier());
96952153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            // TODO: The package manager API should return boolean.
97052153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            return true;
97152153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov        } catch (RemoteException re) {
97252153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov            Log.e(LOG_TAG, "Error revoking runtime permission", re);
97352153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov        }
97452153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov        return false;
97552153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov    }
97652153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov
97752153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov    /**
978121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav     * Executes a shell command. This method returs a file descriptor that points
979121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav     * to the standard output stream. The command execution is similar to running
980121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav     * "adb shell <command>" from a host connected to the device.
981121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav     * <p>
982121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav     * <strong>Note:</strong> It is your responsibility to close the retunred file
983121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav     * descriptor once you are done reading.
984121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav     * </p>
985121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav     *
986121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav     * @param command The command to execute.
987121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav     * @return A file descriptor to the standard output stream.
988121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav     */
989121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav    public ParcelFileDescriptor executeShellCommand(String command) {
990121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav        synchronized (mLock) {
991121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav            throwIfNotConnectedLocked();
992121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav        }
993121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav
994121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav        ParcelFileDescriptor source = null;
995121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav        ParcelFileDescriptor sink = null;
996121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav
997121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav        try {
998121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav            ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
999121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav            source = pipe[0];
1000121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav            sink = pipe[1];
1001121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav
1002121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav            // Calling out without a lock held.
1003121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav            mUiAutomationConnection.executeShellCommand(command, sink);
1004121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav        } catch (IOException ioe) {
1005121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav            Log.e(LOG_TAG, "Error executing shell command!", ioe);
1006121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav        } catch (RemoteException re) {
1007121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav            Log.e(LOG_TAG, "Error executing shell command!", re);
1008121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav        } finally {
1009121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav            IoUtils.closeQuietly(sink);
1010121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav        }
1011121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav
1012121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav        return source;
1013121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav    }
1014121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav
101580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private static float getDegreesForRotation(int value) {
101680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        switch (value) {
101780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            case Surface.ROTATION_90: {
101880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                return 360f - 90f;
101980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            }
102080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            case Surface.ROTATION_180: {
102180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                return 360f - 180f;
102280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            }
102380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            case Surface.ROTATION_270: {
102480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                return 360f - 270f;
102580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            } default: {
102680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                return 0;
102780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            }
102880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
102980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
103080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
103180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private boolean isConnectedLocked() {
103280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        return mConnectionId != CONNECTION_ID_UNDEFINED;
103380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
103480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
103580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private void throwIfConnectedLocked() {
103680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        if (mConnectionId != CONNECTION_ID_UNDEFINED) {
103780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throw new IllegalStateException("UiAutomation not connected!");
103880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
103980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
104080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
104180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private void throwIfNotConnectedLocked() {
104280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        if (!isConnectedLocked()) {
104380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            throw new IllegalStateException("UiAutomation not connected!");
104480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
104580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
104680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
104780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    private class IAccessibilityServiceClientImpl extends IAccessibilityServiceClientWrapper {
104880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
104980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        public IAccessibilityServiceClientImpl(Looper looper) {
105080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            super(null, looper, new Callbacks() {
105180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                @Override
10523a5c721072c60c7ed9c8a95d0a65d0e3cb4eb9bbSvetoslav                public void init(int connectionId, IBinder windowToken) {
105380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    synchronized (mLock) {
105480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                        mConnectionId = connectionId;
105580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                        mLock.notifyAll();
105680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    }
105780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                }
105880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
105980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                @Override
106080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                public void onServiceConnected() {
106180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    /* do nothing */
106280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                }
106380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
106480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                @Override
106580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                public void onInterrupt() {
106680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    /* do nothing */
106780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                }
106880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
106980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                @Override
107080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                public boolean onGesture(int gestureId) {
107180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    /* do nothing */
107280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    return false;
107380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                }
107480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov
107580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                @Override
107680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                public void onAccessibilityEvent(AccessibilityEvent event) {
107780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    synchronized (mLock) {
107880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                        mLastEventTimeMillis = event.getEventTime();
107980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                        if (mWaitingForEventDelivery) {
108080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                            mEventQueue.add(AccessibilityEvent.obtain(event));
108180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                        }
108280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                        mLock.notifyAll();
108380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    }
108480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    // Calling out only without a lock held.
108580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    final OnAccessibilityEventListener listener = mOnAccessibilityEventListener;
108680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    if (listener != null) {
108780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                        listener.onAccessibilityEvent(AccessibilityEvent.obtain(event));
108880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                    }
108980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov                }
1090c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav
1091c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav                @Override
1092c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav                public boolean onKeyEvent(KeyEvent event) {
1093c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav                    return false;
1094c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav                }
1095214fb68767502f5fede643a062c1dc5975d75b27Alan Viverette
1096214fb68767502f5fede643a062c1dc5975d75b27Alan Viverette                @Override
1097214fb68767502f5fede643a062c1dc5975d75b27Alan Viverette                public void onMagnificationChanged(@NonNull Region region,
1098214fb68767502f5fede643a062c1dc5975d75b27Alan Viverette                        float scale, float centerX, float centerY) {
1099214fb68767502f5fede643a062c1dc5975d75b27Alan Viverette                    /* do nothing */
1100214fb68767502f5fede643a062c1dc5975d75b27Alan Viverette                }
1101a6b64f5099b7be6e8384958d8bcddb97bb06ec93Phil Weaver
1102a6b64f5099b7be6e8384958d8bcddb97bb06ec93Phil Weaver                @Override
11039b278112467581e2b8d99f29cf48b9fbef9cc53fAnna Galusza                public void onSoftKeyboardShowModeChanged(int showMode) {
11049b278112467581e2b8d99f29cf48b9fbef9cc53fAnna Galusza                    /* do nothing */
11059b278112467581e2b8d99f29cf48b9fbef9cc53fAnna Galusza                }
11069b278112467581e2b8d99f29cf48b9fbef9cc53fAnna Galusza
11079b278112467581e2b8d99f29cf48b9fbef9cc53fAnna Galusza                @Override
1108a6b64f5099b7be6e8384958d8bcddb97bb06ec93Phil Weaver                public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
1109a6b64f5099b7be6e8384958d8bcddb97bb06ec93Phil Weaver                    /* do nothing */
1110a6b64f5099b7be6e8384958d8bcddb97bb06ec93Phil Weaver                }
111127fcd9c97a2ceb50bab026237390207e5ee9e290Phil Weaver
111227fcd9c97a2ceb50bab026237390207e5ee9e290Phil Weaver                @Override
111327fcd9c97a2ceb50bab026237390207e5ee9e290Phil Weaver                public void onFingerprintCapturingGesturesChanged(boolean active) {
111427fcd9c97a2ceb50bab026237390207e5ee9e290Phil Weaver                    /* do nothing */
111527fcd9c97a2ceb50bab026237390207e5ee9e290Phil Weaver                }
111627fcd9c97a2ceb50bab026237390207e5ee9e290Phil Weaver
111727fcd9c97a2ceb50bab026237390207e5ee9e290Phil Weaver                @Override
111827fcd9c97a2ceb50bab026237390207e5ee9e290Phil Weaver                public void onFingerprintGesture(int gesture) {
111927fcd9c97a2ceb50bab026237390207e5ee9e290Phil Weaver                    /* do nothing */
112027fcd9c97a2ceb50bab026237390207e5ee9e290Phil Weaver                }
1121048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt
1122048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt                @Override
1123048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt                public void onAccessibilityButtonClicked() {
1124048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt                    /* do nothing */
1125048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt                }
1126048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt
1127048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt                @Override
1128048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt                public void onAccessibilityButtonAvailabilityChanged(boolean available) {
1129048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt                    /* do nothing */
1130048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt                }
113180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov            });
113280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov        }
113380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov    }
113480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov}
1135