Methods Summary |
---|
public void | clearWindowAnimationFrameStats()Clears the window animation rendering statistics. These statistics contain
information about the most recently rendered window animation frames, i.e.
for window transition animations.
synchronized (mLock) {
throwIfNotConnectedLocked();
}
try {
if (DEBUG) {
Log.i(LOG_TAG, "Clearing window animation frame stats");
}
// Calling out without a lock held.
mUiAutomationConnection.clearWindowAnimationFrameStats();
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error clearing window animation frame stats!", re);
}
|
public boolean | clearWindowContentFrameStats(int windowId)Clears the frame statistics for the content of a given window. These
statistics contain information about the most recently rendered content
frames.
synchronized (mLock) {
throwIfNotConnectedLocked();
}
try {
if (DEBUG) {
Log.i(LOG_TAG, "Clearing content frame stats for window: " + windowId);
}
// Calling out without a lock held.
return mUiAutomationConnection.clearWindowContentFrameStats(windowId);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error clearing window content frame stats!", re);
}
return false;
|
public void | connect()Connects this UiAutomation to the accessibility introspection APIs.
synchronized (mLock) {
throwIfConnectedLocked();
if (mIsConnecting) {
return;
}
mIsConnecting = true;
}
try {
// Calling out without a lock held.
mUiAutomationConnection.connect(mClient);
} catch (RemoteException re) {
throw new RuntimeException("Error while connecting UiAutomation", re);
}
synchronized (mLock) {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
while (true) {
if (isConnectedLocked()) {
break;
}
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
final long remainingTimeMillis = CONNECT_TIMEOUT_MILLIS - elapsedTimeMillis;
if (remainingTimeMillis <= 0) {
throw new RuntimeException("Error while connecting UiAutomation");
}
try {
mLock.wait(remainingTimeMillis);
} catch (InterruptedException ie) {
/* ignore */
}
}
} finally {
mIsConnecting = false;
}
}
|
public void | disconnect()Disconnects this UiAutomation from the accessibility introspection APIs.
synchronized (mLock) {
if (mIsConnecting) {
throw new IllegalStateException(
"Cannot call disconnect() while connecting!");
}
throwIfNotConnectedLocked();
mConnectionId = CONNECTION_ID_UNDEFINED;
}
try {
// Calling out without a lock held.
mUiAutomationConnection.disconnect();
} catch (RemoteException re) {
throw new RuntimeException("Error while disconnecting UiAutomation", re);
}
|
public android.view.accessibility.AccessibilityEvent | executeAndWaitForEvent(java.lang.Runnable command, android.app.UiAutomation$AccessibilityEventFilter filter, long timeoutMillis)Executes a command and waits for a specific accessibility event up to a
given wait timeout. To detect a sequence of events one can implement a
filter that keeps track of seen events of the expected sequence and
returns true after the last event of that sequence is received.
Note: It is caller's responsibility to recycle the returned event.
// Acquire the lock and prepare for receiving events.
synchronized (mLock) {
throwIfNotConnectedLocked();
mEventQueue.clear();
// Prepare to wait for an event.
mWaitingForEventDelivery = true;
}
// Note: We have to release the lock since calling out with this lock held
// can bite. We will correctly filter out events from other interactions,
// so starting to collect events before running the action is just fine.
// We will ignore events from previous interactions.
final long executionStartTimeMillis = SystemClock.uptimeMillis();
// Execute the command *without* the lock being held.
command.run();
// Acquire the lock and wait for the event.
synchronized (mLock) {
try {
// Wait for the event.
final long startTimeMillis = SystemClock.uptimeMillis();
while (true) {
// Drain the event queue
while (!mEventQueue.isEmpty()) {
AccessibilityEvent event = mEventQueue.remove(0);
// Ignore events from previous interactions.
if (event.getEventTime() < executionStartTimeMillis) {
continue;
}
if (filter.accept(event)) {
return event;
}
event.recycle();
}
// Check if timed out and if not wait.
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis;
if (remainingTimeMillis <= 0) {
throw new TimeoutException("Expected event not received within: "
+ timeoutMillis + " ms.");
}
try {
mLock.wait(remainingTimeMillis);
} catch (InterruptedException ie) {
/* ignore */
}
}
} finally {
mWaitingForEventDelivery = false;
mEventQueue.clear();
mLock.notifyAll();
}
}
|
public android.os.ParcelFileDescriptor | executeShellCommand(java.lang.String command)Executes a shell command. This method returs a file descriptor that points
to the standard output stream. The command execution is similar to running
"adb shell " from a host connected to the device.
Note: It is your responsibility to close the retunred file
descriptor once you are done reading.
synchronized (mLock) {
throwIfNotConnectedLocked();
}
ParcelFileDescriptor source = null;
ParcelFileDescriptor sink = null;
try {
ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
source = pipe[0];
sink = pipe[1];
// Calling out without a lock held.
mUiAutomationConnection.executeShellCommand(command, sink);
} catch (IOException ioe) {
Log.e(LOG_TAG, "Error executing shell command!", ioe);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error executing shell command!", re);
} finally {
IoUtils.closeQuietly(sink);
}
return source;
|
public android.view.accessibility.AccessibilityNodeInfo | findFocus(int focus)Find the view that has the specified focus type. The search is performed
across all windows.
Note: In order to access the windows you have to opt-in
to retrieve the interactive windows by setting the
{@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} flag.
Otherwise, the search will be performed only in the active window.
return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
AccessibilityNodeInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
|
public int | getConnectionId()The id of the {@link IAccessibilityInteractionConnection} for querying
the screen content. This is here for legacy purposes since some tools use
hidden APIs to introspect the screen.
synchronized (mLock) {
throwIfNotConnectedLocked();
return mConnectionId;
}
|
private static float | getDegreesForRotation(int value)
switch (value) {
case Surface.ROTATION_90: {
return 360f - 90f;
}
case Surface.ROTATION_180: {
return 360f - 180f;
}
case Surface.ROTATION_270: {
return 360f - 270f;
} default: {
return 0;
}
}
|
public android.view.accessibility.AccessibilityNodeInfo | getRootInActiveWindow()Gets the root {@link AccessibilityNodeInfo} in the active window.
final int connectionId;
synchronized (mLock) {
throwIfNotConnectedLocked();
connectionId = mConnectionId;
}
// Calling out without a lock held.
return AccessibilityInteractionClient.getInstance()
.getRootInActiveWindow(connectionId);
|
public final android.accessibilityservice.AccessibilityServiceInfo | getServiceInfo()Gets the an {@link AccessibilityServiceInfo} describing this UiAutomation.
This method is useful if one wants to change some of the dynamically
configurable properties at runtime.
final IAccessibilityServiceConnection connection;
synchronized (mLock) {
throwIfNotConnectedLocked();
connection = AccessibilityInteractionClient.getInstance()
.getConnection(mConnectionId);
}
// Calling out without a lock held.
if (connection != null) {
try {
return connection.getServiceInfo();
} catch (RemoteException re) {
Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
}
}
return null;
|
public android.view.WindowAnimationFrameStats | getWindowAnimationFrameStats()Gets the window animation frame statistics. These statistics contain
information about the most recently rendered window animation frames, i.e.
for window transition animations.
A typical usage requires clearing the window animation frame statistics via
{@link #clearWindowAnimationFrameStats()} followed by an interaction that causes
a window transition which uses a window animation and finally getting the window
animation frame statistics by calling this method.
// Start with a clean slate.
uiAutimation.clearWindowAnimationFrameStats();
// Do stuff to trigger a window transition.
// Get the frame statistics.
WindowAnimationFrameStats stats = uiAutomation.getWindowAnimationFrameStats();
synchronized (mLock) {
throwIfNotConnectedLocked();
}
try {
if (DEBUG) {
Log.i(LOG_TAG, "Getting window animation frame stats");
}
// Calling out without a lock held.
return mUiAutomationConnection.getWindowAnimationFrameStats();
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error getting window animation frame stats!", re);
}
return null;
|
public android.view.WindowContentFrameStats | getWindowContentFrameStats(int windowId)Gets the frame statistics for a given window. These statistics contain
information about the most recently rendered content frames.
A typical usage requires clearing the window frame statistics via {@link
#clearWindowContentFrameStats(int)} followed by an interaction with the UI and
finally getting the window frame statistics via calling this method.
// Assume we have at least one window.
final int windowId = getWindows().get(0).getId();
// Start with a clean slate.
uiAutimation.clearWindowContentFrameStats(windowId);
// Do stuff with the UI.
// Get the frame statistics.
WindowContentFrameStats stats = uiAutomation.getWindowContentFrameStats(windowId);
synchronized (mLock) {
throwIfNotConnectedLocked();
}
try {
if (DEBUG) {
Log.i(LOG_TAG, "Getting content frame stats for window: " + windowId);
}
// Calling out without a lock held.
return mUiAutomationConnection.getWindowContentFrameStats(windowId);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error getting window content frame stats!", re);
}
return null;
|
public java.util.List | getWindows()Gets the windows on the screen. This method returns only the windows
that a sighted user can interact with, as opposed to all windows.
For example, if there is a modal dialog shown and the user cannot touch
anything behind it, then only the modal window will be reported
(assuming it is the top one). For convenience the returned windows
are ordered in a descending layer order, which is the windows that
are higher in the Z-order are reported first.
Note: In order to access the windows you have to opt-in
to retrieve the interactive windows by setting the
{@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} flag.
final int connectionId;
synchronized (mLock) {
throwIfNotConnectedLocked();
connectionId = mConnectionId;
}
// Calling out without a lock held.
return AccessibilityInteractionClient.getInstance()
.getWindows(connectionId);
|
public boolean | injectInputEvent(android.view.InputEvent event, boolean sync)A method for injecting an arbitrary input event.
Note: It is caller's responsibility to recycle the event.
synchronized (mLock) {
throwIfNotConnectedLocked();
}
try {
if (DEBUG) {
Log.i(LOG_TAG, "Injecting: " + event + " sync: " + sync);
}
// Calling out without a lock held.
return mUiAutomationConnection.injectInputEvent(event, sync);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error while injecting input event!", re);
}
return false;
|
private boolean | isConnectedLocked()
return mConnectionId != CONNECTION_ID_UNDEFINED;
|
public final boolean | performGlobalAction(int action)Performs a global action. Such an action can be performed at any moment
regardless of the current application or user location in that application.
For example going back, going home, opening recents, etc.
final IAccessibilityServiceConnection connection;
synchronized (mLock) {
throwIfNotConnectedLocked();
connection = AccessibilityInteractionClient.getInstance()
.getConnection(mConnectionId);
}
// Calling out without a lock held.
if (connection != null) {
try {
return connection.performGlobalAction(action);
} catch (RemoteException re) {
Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
}
}
return false;
|
public void | setOnAccessibilityEventListener(android.app.UiAutomation$OnAccessibilityEventListener listener)Sets a callback for observing the stream of {@link AccessibilityEvent}s.
synchronized (mLock) {
mOnAccessibilityEventListener = listener;
}
|
public boolean | setRotation(int rotation)Sets the device rotation. A client can freeze the rotation in
desired state or freeze the rotation to its current state or
unfreeze the rotation (rotating the device changes its rotation
state).
synchronized (mLock) {
throwIfNotConnectedLocked();
}
switch (rotation) {
case ROTATION_FREEZE_0:
case ROTATION_FREEZE_90:
case ROTATION_FREEZE_180:
case ROTATION_FREEZE_270:
case ROTATION_UNFREEZE:
case ROTATION_FREEZE_CURRENT: {
try {
// Calling out without a lock held.
mUiAutomationConnection.setRotation(rotation);
return true;
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error while setting rotation!", re);
}
} return false;
default: {
throw new IllegalArgumentException("Invalid rotation.");
}
}
|
public void | setRunAsMonkey(boolean enable)Sets whether this UiAutomation to run in a "monkey" mode. Applications can query whether
they are executed in a "monkey" mode, i.e. run by a test framework, and avoid doing
potentially undesirable actions such as calling 911 or posting on public forums etc.
synchronized (mLock) {
throwIfNotConnectedLocked();
}
try {
ActivityManagerNative.getDefault().setUserIsMonkey(enable);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error while setting run as monkey!", re);
}
|
public final void | setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo info)Sets the {@link AccessibilityServiceInfo} that describes how this
UiAutomation will be handled by the platform accessibility layer.
final IAccessibilityServiceConnection connection;
synchronized (mLock) {
throwIfNotConnectedLocked();
AccessibilityInteractionClient.getInstance().clearCache();
connection = AccessibilityInteractionClient.getInstance()
.getConnection(mConnectionId);
}
// Calling out without a lock held.
if (connection != null) {
try {
connection.setServiceInfo(info);
} catch (RemoteException re) {
Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
}
}
|
public android.graphics.Bitmap | takeScreenshot()Takes a screenshot.
synchronized (mLock) {
throwIfNotConnectedLocked();
}
Display display = DisplayManagerGlobal.getInstance()
.getRealDisplay(Display.DEFAULT_DISPLAY);
Point displaySize = new Point();
display.getRealSize(displaySize);
final int displayWidth = displaySize.x;
final int displayHeight = displaySize.y;
final float screenshotWidth;
final float screenshotHeight;
final int rotation = display.getRotation();
switch (rotation) {
case ROTATION_FREEZE_0: {
screenshotWidth = displayWidth;
screenshotHeight = displayHeight;
} break;
case ROTATION_FREEZE_90: {
screenshotWidth = displayHeight;
screenshotHeight = displayWidth;
} break;
case ROTATION_FREEZE_180: {
screenshotWidth = displayWidth;
screenshotHeight = displayHeight;
} break;
case ROTATION_FREEZE_270: {
screenshotWidth = displayHeight;
screenshotHeight = displayWidth;
} break;
default: {
throw new IllegalArgumentException("Invalid rotation: "
+ rotation);
}
}
// Take the screenshot
Bitmap screenShot = null;
try {
// Calling out without a lock held.
screenShot = mUiAutomationConnection.takeScreenshot((int) screenshotWidth,
(int) screenshotHeight);
if (screenShot == null) {
return null;
}
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error while taking screnshot!", re);
return null;
}
// Rotate the screenshot to the current orientation
if (rotation != ROTATION_FREEZE_0) {
Bitmap unrotatedScreenShot = Bitmap.createBitmap(displayWidth, displayHeight,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(unrotatedScreenShot);
canvas.translate(unrotatedScreenShot.getWidth() / 2,
unrotatedScreenShot.getHeight() / 2);
canvas.rotate(getDegreesForRotation(rotation));
canvas.translate(- screenshotWidth / 2, - screenshotHeight / 2);
canvas.drawBitmap(screenShot, 0, 0, null);
canvas.setBitmap(null);
screenShot.recycle();
screenShot = unrotatedScreenShot;
}
// Optimization
screenShot.setHasAlpha(false);
return screenShot;
|
private void | throwIfConnectedLocked()
if (mConnectionId != CONNECTION_ID_UNDEFINED) {
throw new IllegalStateException("UiAutomation not connected!");
}
|
private void | throwIfNotConnectedLocked()
if (!isConnectedLocked()) {
throw new IllegalStateException("UiAutomation not connected!");
}
|
public void | waitForIdle(long idleTimeoutMillis, long globalTimeoutMillis)Waits for the accessibility event stream to become idle, which is not to
have received an accessibility event within idleTimeoutMillis .
The total time spent to wait for an idle accessibility event stream is bounded
by the globalTimeoutMillis .
synchronized (mLock) {
throwIfNotConnectedLocked();
final long startTimeMillis = SystemClock.uptimeMillis();
if (mLastEventTimeMillis <= 0) {
mLastEventTimeMillis = startTimeMillis;
}
while (true) {
final long currentTimeMillis = SystemClock.uptimeMillis();
// Did we get idle state within the global timeout?
final long elapsedGlobalTimeMillis = currentTimeMillis - startTimeMillis;
final long remainingGlobalTimeMillis =
globalTimeoutMillis - elapsedGlobalTimeMillis;
if (remainingGlobalTimeMillis <= 0) {
throw new TimeoutException("No idle state with idle timeout: "
+ idleTimeoutMillis + " within global timeout: "
+ globalTimeoutMillis);
}
// Did we get an idle state within the idle timeout?
final long elapsedIdleTimeMillis = currentTimeMillis - mLastEventTimeMillis;
final long remainingIdleTimeMillis = idleTimeoutMillis - elapsedIdleTimeMillis;
if (remainingIdleTimeMillis <= 0) {
return;
}
try {
mLock.wait(remainingIdleTimeMillis);
} catch (InterruptedException ie) {
/* ignore */
}
}
}
|