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, 3841e0d4af9986c8c2a658769a63bf8b385d25e0435Svetoslav AccessibilityNodeInfo.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. 583db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav synchronized (mLock) { 58480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov try { 58580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Wait for the event. 58680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long startTimeMillis = SystemClock.uptimeMillis(); 58780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov while (true) { 58880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Drain the event queue 58980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov while (!mEventQueue.isEmpty()) { 59080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov AccessibilityEvent event = mEventQueue.remove(0); 59180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Ignore events from previous interactions. 592db7da0eb8b7d515c168d5b410764e24c9a0f9431Svetoslav if (event.getEventTime() < executionStartTimeMillis) { 59380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov continue; 59480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 595550b48fa18f8b392be1aab46c5bb4ec92ac3328bSvetoslav if (filter.accept(event)) { 59680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return event; 59780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 59880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov event.recycle(); 59980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 60080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Check if timed out and if not wait. 60180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; 60280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis; 60380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (remainingTimeMillis <= 0) { 60480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new TimeoutException("Expected event not received within: " 60580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov + timeoutMillis + " ms."); 60680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 60780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov try { 60880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLock.wait(remainingTimeMillis); 60980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } catch (InterruptedException ie) { 61080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /* ignore */ 61180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 61280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 61380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } finally { 61480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mWaitingForEventDelivery = false; 61580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mEventQueue.clear(); 61680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLock.notifyAll(); 61780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 61880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 61980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 62080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 62180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 62280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Waits for the accessibility event stream to become idle, which is not to 62380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * have received an accessibility event within <code>idleTimeoutMillis</code>. 62480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * The total time spent to wait for an idle accessibility event stream is bounded 62580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * by the <code>globalTimeoutMillis</code>. 62680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 62780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @param idleTimeoutMillis The timeout in milliseconds between two events 62880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * to consider the device idle. 62980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @param globalTimeoutMillis The maximal global timeout in milliseconds in 63080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * which to wait for an idle state. 63180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 63280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @throws TimeoutException If no idle state was detected within 63380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * <code>globalTimeoutMillis.</code> 63480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 63580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public void waitForIdle(long idleTimeoutMillis, long globalTimeoutMillis) 63680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throws TimeoutException { 63780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 63880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throwIfNotConnectedLocked(); 63980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 64080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long startTimeMillis = SystemClock.uptimeMillis(); 64180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (mLastEventTimeMillis <= 0) { 64280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLastEventTimeMillis = startTimeMillis; 64380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 64480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 64580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov while (true) { 64680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long currentTimeMillis = SystemClock.uptimeMillis(); 64780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Did we get idle state within the global timeout? 64880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long elapsedGlobalTimeMillis = currentTimeMillis - startTimeMillis; 64980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long remainingGlobalTimeMillis = 65080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov globalTimeoutMillis - elapsedGlobalTimeMillis; 65180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (remainingGlobalTimeMillis <= 0) { 65280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new TimeoutException("No idle state with idle timeout: " 65380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov + idleTimeoutMillis + " within global timeout: " 65480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov + globalTimeoutMillis); 65580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 65680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Did we get an idle state within the idle timeout? 65780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long elapsedIdleTimeMillis = currentTimeMillis - mLastEventTimeMillis; 65880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final long remainingIdleTimeMillis = idleTimeoutMillis - elapsedIdleTimeMillis; 65980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (remainingIdleTimeMillis <= 0) { 66080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return; 66180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 66280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov try { 66380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLock.wait(remainingIdleTimeMillis); 66480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } catch (InterruptedException ie) { 66580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /* ignore */ 66680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 66780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 66880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 66980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 67080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 67180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /** 67280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * Takes a screenshot. 67380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * 67480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov * @return The screenshot bitmap on success, null otherwise. 67580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov */ 67680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public Bitmap takeScreenshot() { 67780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 67880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throwIfNotConnectedLocked(); 67980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 68080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Display display = DisplayManagerGlobal.getInstance() 68180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov .getRealDisplay(Display.DEFAULT_DISPLAY); 68280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Point displaySize = new Point(); 68380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov display.getRealSize(displaySize); 68480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final int displayWidth = displaySize.x; 68580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final int displayHeight = displaySize.y; 68680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 68780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final float screenshotWidth; 68880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final float screenshotHeight; 68980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 69080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final int rotation = display.getRotation(); 69180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov switch (rotation) { 69280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case ROTATION_FREEZE_0: { 69380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotWidth = displayWidth; 69480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotHeight = displayHeight; 69580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } break; 69680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case ROTATION_FREEZE_90: { 69780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotWidth = displayHeight; 69880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotHeight = displayWidth; 69980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } break; 70080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case ROTATION_FREEZE_180: { 70180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotWidth = displayWidth; 70280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotHeight = displayHeight; 70380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } break; 70480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case ROTATION_FREEZE_270: { 70580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotWidth = displayHeight; 70680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenshotHeight = displayWidth; 70780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } break; 70880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov default: { 70980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new IllegalArgumentException("Invalid rotation: " 71080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov + rotation); 71180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 71280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 71380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 71480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Take the screenshot 71580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Bitmap screenShot = null; 71680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov try { 71780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Calling out without a lock held. 71880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenShot = mUiAutomationConnection.takeScreenshot((int) screenshotWidth, 71980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov (int) screenshotHeight); 72080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (screenShot == null) { 72180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return null; 72280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 72380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } catch (RemoteException re) { 72480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Log.e(LOG_TAG, "Error while taking screnshot!", re); 72580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return null; 72680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 72780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 72880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Rotate the screenshot to the current orientation 72980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (rotation != ROTATION_FREEZE_0) { 73080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Bitmap unrotatedScreenShot = Bitmap.createBitmap(displayWidth, displayHeight, 73180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Bitmap.Config.ARGB_8888); 73280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov Canvas canvas = new Canvas(unrotatedScreenShot); 73380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov canvas.translate(unrotatedScreenShot.getWidth() / 2, 73480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov unrotatedScreenShot.getHeight() / 2); 73580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov canvas.rotate(getDegreesForRotation(rotation)); 73680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov canvas.translate(- screenshotWidth / 2, - screenshotHeight / 2); 73780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov canvas.drawBitmap(screenShot, 0, 0, null); 73880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov canvas.setBitmap(null); 739b101ebe8a63ee1b6fc90135d661f4fe19c2e5f07Leon Scroggins III screenShot.recycle(); 74080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenShot = unrotatedScreenShot; 74180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 74280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 74380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Optimization 74480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov screenShot.setHasAlpha(false); 74580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 74680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return screenShot; 74780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 74880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 7498f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz /** 7508f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz * Sets whether this UiAutomation to run in a "monkey" mode. Applications can query whether 7518f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz * they are executed in a "monkey" mode, i.e. run by a test framework, and avoid doing 7528f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz * potentially undesirable actions such as calling 911 or posting on public forums etc. 7538f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz * 7548f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz * @param enable whether to run in a "monkey" mode or not. Default is not. 755a9f6a9b769b71d89382b9b8c158b168cd7b4c692Quddus Chong * @see ActivityManager#isUserAMonkey() 7568f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz */ 7578f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz public void setRunAsMonkey(boolean enable) { 7588f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz synchronized (mLock) { 7598f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz throwIfNotConnectedLocked(); 7608f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz } 7618f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz try { 7628f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz ActivityManagerNative.getDefault().setUserIsMonkey(enable); 7638f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz } catch (RemoteException re) { 7648f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz Log.e(LOG_TAG, "Error while setting run as monkey!", re); 7658f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz } 7668f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz } 7678f6f1f43eeb0d7263b626978ee2c21d4053bf610Adam Momtaz 7681376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav /** 7691376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * Clears the frame statistics for the content of a given window. These 7701376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * statistics contain information about the most recently rendered content 7711376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * frames. 7721376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * 7731376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @param windowId The window id. 7741376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @return Whether the window is present and its frame statistics 7751376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * were cleared. 7761376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * 7771376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @see android.view.WindowContentFrameStats 7781376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @see #getWindowContentFrameStats(int) 7791376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @see #getWindows() 7801376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @see AccessibilityWindowInfo#getId() AccessibilityWindowInfo.getId() 7811376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav */ 7821376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav public boolean clearWindowContentFrameStats(int windowId) { 7831376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav synchronized (mLock) { 7841376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav throwIfNotConnectedLocked(); 7851376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 7861376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav try { 7871376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav if (DEBUG) { 7881376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav Log.i(LOG_TAG, "Clearing content frame stats for window: " + windowId); 7891376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 7901376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav // Calling out without a lock held. 7911376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav return mUiAutomationConnection.clearWindowContentFrameStats(windowId); 7921376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } catch (RemoteException re) { 7931376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav Log.e(LOG_TAG, "Error clearing window content frame stats!", re); 7941376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 7951376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav return false; 7961376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 7971376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav 7981376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav /** 7991376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * Gets the frame statistics for a given window. These statistics contain 8001376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * information about the most recently rendered content frames. 8011376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * <p> 8021376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * A typical usage requires clearing the window frame statistics via {@link 8031376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * #clearWindowContentFrameStats(int)} followed by an interaction with the UI and 8041376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * finally getting the window frame statistics via calling this method. 8051376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * </p> 8061376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * <pre> 8071376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * // Assume we have at least one window. 8081376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * final int windowId = getWindows().get(0).getId(); 8091376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * 8101376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * // Start with a clean slate. 8111376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * uiAutimation.clearWindowContentFrameStats(windowId); 8121376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * 8131376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * // Do stuff with the UI. 8141376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * 8151376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * // Get the frame statistics. 8161376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * WindowContentFrameStats stats = uiAutomation.getWindowContentFrameStats(windowId); 8171376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * </pre> 8181376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * 8191376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @param windowId The window id. 8201376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @return The window frame statistics, or null if the window is not present. 8211376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * 8221376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @see android.view.WindowContentFrameStats 8231376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @see #clearWindowContentFrameStats(int) 8241376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @see #getWindows() 8251376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @see AccessibilityWindowInfo#getId() AccessibilityWindowInfo.getId() 8261376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav */ 8271376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav public WindowContentFrameStats getWindowContentFrameStats(int windowId) { 8281376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav synchronized (mLock) { 8291376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav throwIfNotConnectedLocked(); 8301376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 8311376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav try { 8321376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav if (DEBUG) { 8331376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav Log.i(LOG_TAG, "Getting content frame stats for window: " + windowId); 8341376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 8351376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav // Calling out without a lock held. 8361376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav return mUiAutomationConnection.getWindowContentFrameStats(windowId); 8371376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } catch (RemoteException re) { 8381376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav Log.e(LOG_TAG, "Error getting window content frame stats!", re); 8391376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 8401376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav return null; 8411376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 8421376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav 8431376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav /** 8441376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * Clears the window animation rendering statistics. These statistics contain 8451376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * information about the most recently rendered window animation frames, i.e. 8461376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * for window transition animations. 8471376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * 8481376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @see android.view.WindowAnimationFrameStats 8491376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @see #getWindowAnimationFrameStats() 8501376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @see android.R.styleable#WindowAnimation 8511376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav */ 8521376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav public void clearWindowAnimationFrameStats() { 8531376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav synchronized (mLock) { 8541376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav throwIfNotConnectedLocked(); 8551376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 8561376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav try { 8571376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav if (DEBUG) { 8581376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav Log.i(LOG_TAG, "Clearing window animation frame stats"); 8591376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 8601376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav // Calling out without a lock held. 8611376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav mUiAutomationConnection.clearWindowAnimationFrameStats(); 8621376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } catch (RemoteException re) { 8631376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav Log.e(LOG_TAG, "Error clearing window animation frame stats!", re); 8641376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 8651376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 8661376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav 8671376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav /** 8681376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * Gets the window animation frame statistics. These statistics contain 8691376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * information about the most recently rendered window animation frames, i.e. 8701376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * for window transition animations. 8711376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * 8721376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * <p> 8731376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * A typical usage requires clearing the window animation frame statistics via 8741376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * {@link #clearWindowAnimationFrameStats()} followed by an interaction that causes 8751376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * a window transition which uses a window animation and finally getting the window 8761376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * animation frame statistics by calling this method. 8771376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * </p> 8781376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * <pre> 8791376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * // Start with a clean slate. 8801376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * uiAutimation.clearWindowAnimationFrameStats(); 8811376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * 8821376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * // Do stuff to trigger a window transition. 8831376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * 8841376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * // Get the frame statistics. 8851376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * WindowAnimationFrameStats stats = uiAutomation.getWindowAnimationFrameStats(); 8861376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * </pre> 8871376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * 8881376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @return The window animation frame statistics. 8891376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * 8901376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @see android.view.WindowAnimationFrameStats 8911376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @see #clearWindowAnimationFrameStats() 8921376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav * @see android.R.styleable#WindowAnimation 8931376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav */ 8941376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav public WindowAnimationFrameStats getWindowAnimationFrameStats() { 8951376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav synchronized (mLock) { 8961376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav throwIfNotConnectedLocked(); 8971376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 8981376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav try { 8991376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav if (DEBUG) { 9001376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav Log.i(LOG_TAG, "Getting window animation frame stats"); 9011376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 9021376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav // Calling out without a lock held. 9031376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav return mUiAutomationConnection.getWindowAnimationFrameStats(); 9041376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } catch (RemoteException re) { 9051376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav Log.e(LOG_TAG, "Error getting window animation frame stats!", re); 9061376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 9071376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav return null; 9081376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav } 9091376d600d8e0eefdbc0aa11d398cf7517fc77129Svetoslav 910121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav /** 91152153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov * Grants a runtime permission to a package for a user. 91252153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov * @param packageName The package to which to grant. 91352153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov * @param permission The permission to grant. 91452153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov * @return Whether granting succeeded. 91552153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov * 91652153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov * @hide 91752153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov */ 918a73b8fd1f4faaad00d8a49d6e496aaf249fa7003Jeff Sharkey @TestApi 91952153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov public boolean grantRuntimePermission(String packageName, String permission, 92052153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov UserHandle userHandle) { 92152153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov synchronized (mLock) { 92252153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov throwIfNotConnectedLocked(); 92352153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov } 92452153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov try { 92552153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov if (DEBUG) { 92652153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov Log.i(LOG_TAG, "Granting runtime permission"); 92752153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov } 92852153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov // Calling out without a lock held. 92952153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov mUiAutomationConnection.grantRuntimePermission(packageName, 93052153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov permission, userHandle.getIdentifier()); 93152153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov // TODO: The package manager API should return boolean. 93252153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov return true; 93352153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov } catch (RemoteException re) { 93452153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov Log.e(LOG_TAG, "Error granting runtime permission", re); 93552153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov } 93652153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov return false; 93752153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov } 93852153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov 93952153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov /** 94052153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov * Revokes a runtime permission from a package for a user. 94152153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov * @param packageName The package from which to revoke. 94252153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov * @param permission The permission to revoke. 94352153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov * @return Whether revoking succeeded. 94452153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov * 94552153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov * @hide 94652153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov */ 947a73b8fd1f4faaad00d8a49d6e496aaf249fa7003Jeff Sharkey @TestApi 94852153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov public boolean revokeRuntimePermission(String packageName, String permission, 94952153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov UserHandle userHandle) { 95052153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov synchronized (mLock) { 95152153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov throwIfNotConnectedLocked(); 95252153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov } 95352153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov try { 95452153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov if (DEBUG) { 95552153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov Log.i(LOG_TAG, "Revoking runtime permission"); 95652153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov } 95752153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov // Calling out without a lock held. 95852153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov mUiAutomationConnection.revokeRuntimePermission(packageName, 95952153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov permission, userHandle.getIdentifier()); 96052153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov // TODO: The package manager API should return boolean. 96152153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov return true; 96252153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov } catch (RemoteException re) { 96352153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov Log.e(LOG_TAG, "Error revoking runtime permission", re); 96452153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov } 96552153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov return false; 96652153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov } 96752153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov 96852153f4c0540a991b5b7214f4f14b5a891479a3cSvet Ganov /** 969121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav * Executes a shell command. This method returs a file descriptor that points 970121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav * to the standard output stream. The command execution is similar to running 971121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav * "adb shell <command>" from a host connected to the device. 972121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav * <p> 973121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav * <strong>Note:</strong> It is your responsibility to close the retunred file 974121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav * descriptor once you are done reading. 975121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav * </p> 976121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav * 977121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav * @param command The command to execute. 978121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav * @return A file descriptor to the standard output stream. 979121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav */ 980121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav public ParcelFileDescriptor executeShellCommand(String command) { 981121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav synchronized (mLock) { 982121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav throwIfNotConnectedLocked(); 983121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav } 984121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav 985121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav ParcelFileDescriptor source = null; 986121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav ParcelFileDescriptor sink = null; 987121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav 988121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav try { 989121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); 990121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav source = pipe[0]; 991121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav sink = pipe[1]; 992121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav 993121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav // Calling out without a lock held. 994121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav mUiAutomationConnection.executeShellCommand(command, sink); 995121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav } catch (IOException ioe) { 996121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav Log.e(LOG_TAG, "Error executing shell command!", ioe); 997121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav } catch (RemoteException re) { 998121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav Log.e(LOG_TAG, "Error executing shell command!", re); 999121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav } finally { 1000121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav IoUtils.closeQuietly(sink); 1001121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav } 1002121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav 1003121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav return source; 1004121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav } 1005121e0c073992658ca0ba055f40bf3b130caa819aSvetoslav 100680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private static float getDegreesForRotation(int value) { 100780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov switch (value) { 100880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case Surface.ROTATION_90: { 100980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return 360f - 90f; 101080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 101180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case Surface.ROTATION_180: { 101280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return 360f - 180f; 101380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 101480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov case Surface.ROTATION_270: { 101580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return 360f - 270f; 101680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } default: { 101780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return 0; 101880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 101980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 102080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 102180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 102280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private boolean isConnectedLocked() { 102380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return mConnectionId != CONNECTION_ID_UNDEFINED; 102480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 102580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 102680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private void throwIfConnectedLocked() { 102780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (mConnectionId != CONNECTION_ID_UNDEFINED) { 102880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new IllegalStateException("UiAutomation not connected!"); 102980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 103080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 103180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 103280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private void throwIfNotConnectedLocked() { 103380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (!isConnectedLocked()) { 103480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov throw new IllegalStateException("UiAutomation not connected!"); 103580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 103680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 103780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 103880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov private class IAccessibilityServiceClientImpl extends IAccessibilityServiceClientWrapper { 103980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 104080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public IAccessibilityServiceClientImpl(Looper looper) { 104180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov super(null, looper, new Callbacks() { 104280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov @Override 10433a5c721072c60c7ed9c8a95d0a65d0e3cb4eb9bbSvetoslav public void init(int connectionId, IBinder windowToken) { 104480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 104580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mConnectionId = connectionId; 104680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLock.notifyAll(); 104780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 104880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 104980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 105080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov @Override 105180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public void onServiceConnected() { 105280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /* do nothing */ 105380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 105480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 105580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov @Override 105680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public void onInterrupt() { 105780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /* do nothing */ 105880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 105980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 106080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov @Override 106180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public boolean onGesture(int gestureId) { 106280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov /* do nothing */ 106380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov return false; 106480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 106580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov 106680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov @Override 106780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov public void onAccessibilityEvent(AccessibilityEvent event) { 106880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov synchronized (mLock) { 106980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLastEventTimeMillis = event.getEventTime(); 107080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (mWaitingForEventDelivery) { 107180943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mEventQueue.add(AccessibilityEvent.obtain(event)); 107280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 107380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov mLock.notifyAll(); 107480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 107580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov // Calling out only without a lock held. 107680943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov final OnAccessibilityEventListener listener = mOnAccessibilityEventListener; 107780943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov if (listener != null) { 107880943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov listener.onAccessibilityEvent(AccessibilityEvent.obtain(event)); 107980943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 108080943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 1081c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav 1082c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav @Override 1083c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav public boolean onKeyEvent(KeyEvent event) { 1084c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav return false; 1085c4fccd183f1bb47a027bb303af5e65bec2f68b1bSvetoslav } 1086214fb68767502f5fede643a062c1dc5975d75b27Alan Viverette 1087214fb68767502f5fede643a062c1dc5975d75b27Alan Viverette @Override 1088214fb68767502f5fede643a062c1dc5975d75b27Alan Viverette public void onMagnificationChanged(@NonNull Region region, 1089214fb68767502f5fede643a062c1dc5975d75b27Alan Viverette float scale, float centerX, float centerY) { 1090214fb68767502f5fede643a062c1dc5975d75b27Alan Viverette /* do nothing */ 1091214fb68767502f5fede643a062c1dc5975d75b27Alan Viverette } 1092a6b64f5099b7be6e8384958d8bcddb97bb06ec93Phil Weaver 1093a6b64f5099b7be6e8384958d8bcddb97bb06ec93Phil Weaver @Override 10949b278112467581e2b8d99f29cf48b9fbef9cc53fAnna Galusza public void onSoftKeyboardShowModeChanged(int showMode) { 10959b278112467581e2b8d99f29cf48b9fbef9cc53fAnna Galusza /* do nothing */ 10969b278112467581e2b8d99f29cf48b9fbef9cc53fAnna Galusza } 10979b278112467581e2b8d99f29cf48b9fbef9cc53fAnna Galusza 10989b278112467581e2b8d99f29cf48b9fbef9cc53fAnna Galusza @Override 1099a6b64f5099b7be6e8384958d8bcddb97bb06ec93Phil Weaver public void onPerformGestureResult(int sequence, boolean completedSuccessfully) { 1100a6b64f5099b7be6e8384958d8bcddb97bb06ec93Phil Weaver /* do nothing */ 1101a6b64f5099b7be6e8384958d8bcddb97bb06ec93Phil Weaver } 110280943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov }); 110380943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 110480943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov } 110580943d8daa6ab31ab5c486d57aea406aa0730d58Svetoslav Ganov} 1106