Merge "Optionally wait animations on syncInputTransactions/injectInputEvent"

This commit is contained in:
Bernardo Rufino
2020-11-19 14:07:13 +00:00
committed by Android (Google) Code Review
7 changed files with 75 additions and 23 deletions

View File

@@ -302,8 +302,10 @@ package android.app {
method public void destroy();
method @NonNull public android.os.ParcelFileDescriptor[] executeShellCommandRwe(@NonNull String);
method @Deprecated public boolean grantRuntimePermission(String, String, android.os.UserHandle);
method public boolean injectInputEvent(@NonNull android.view.InputEvent, boolean, boolean);
method @Deprecated public boolean revokeRuntimePermission(String, String, android.os.UserHandle);
method public void syncInputTransactions();
method public void syncInputTransactions(boolean);
}
public class UiModeManager {

View File

@@ -36,8 +36,8 @@ import android.os.ParcelFileDescriptor;
interface IUiAutomationConnection {
void connect(IAccessibilityServiceClient client, int flags);
void disconnect();
boolean injectInputEvent(in InputEvent event, boolean sync);
void syncInputTransactions();
boolean injectInputEvent(in InputEvent event, boolean sync, boolean waitForAnimations);
void syncInputTransactions(boolean waitForAnimations);
boolean setRotation(int rotation);
Bitmap takeScreenshot(in Rect crop);
boolean clearWindowContentFrameStats(int windowId);

View File

@@ -1119,7 +1119,8 @@ public class Instrumentation {
}
try {
WindowManagerGlobal.getWindowManagerService().injectInputAfterTransactionsApplied(event,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH,
true /* waitForAnimations */);
} catch (RemoteException e) {
}
}

View File

@@ -695,6 +695,9 @@ public final class UiAutomation {
/**
* A method for injecting an arbitrary input event.
*
* This method waits for all window container animations and surface operations to complete.
*
* <p>
* <strong>Note:</strong> It is caller's responsibility to recycle the event.
* </p>
@@ -704,12 +707,34 @@ public final class UiAutomation {
* @return Whether event injection succeeded.
*/
public boolean injectInputEvent(InputEvent event, boolean sync) {
return injectInputEvent(event, sync, true /* waitForAnimations */);
}
/**
* A method for injecting an arbitrary input event, optionally waiting for window animations to
* complete.
* <p>
* <strong>Note:</strong> It is caller's responsibility to recycle the event.
* </p>
*
* @param event The event to inject.
* @param sync Whether to inject the event synchronously.
* @param waitForAnimations Whether to wait for all window container animations and surface
* operations to complete.
* @return Whether event injection succeeded.
*
* @hide
*/
@TestApi
public boolean injectInputEvent(@NonNull InputEvent event, boolean sync,
boolean waitForAnimations) {
try {
if (DEBUG) {
Log.i(LOG_TAG, "Injecting: " + event + " sync: " + sync);
Log.i(LOG_TAG, "Injecting: " + event + " sync: " + sync + " waitForAnimations: "
+ waitForAnimations);
}
// Calling out without a lock held.
return mUiAutomationConnection.injectInputEvent(event, sync);
return mUiAutomationConnection.injectInputEvent(event, sync, waitForAnimations);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error while injecting input event!", re);
}
@@ -726,7 +751,26 @@ public final class UiAutomation {
public void syncInputTransactions() {
try {
// Calling out without a lock held.
mUiAutomationConnection.syncInputTransactions();
mUiAutomationConnection.syncInputTransactions(true /* waitForAnimations */);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error while syncing input transactions!", re);
}
}
/**
* A request for WindowManagerService to wait until all input information has been sent from
* WindowManager to native InputManager and optionally wait for animations to complete.
*
* @param waitForAnimations Whether to wait for all window container animations and surface
* operations to complete.
*
* @hide
*/
@TestApi
public void syncInputTransactions(boolean waitForAnimations) {
try {
// Calling out without a lock held.
mUiAutomationConnection.syncInputTransactions(waitForAnimations);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error while syncing input transactions!", re);
}

View File

@@ -124,7 +124,7 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
}
@Override
public boolean injectInputEvent(InputEvent event, boolean sync) {
public boolean injectInputEvent(InputEvent event, boolean sync, boolean waitForAnimations) {
synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked();
@@ -134,7 +134,8 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
: InputManager.INJECT_INPUT_EVENT_MODE_ASYNC;
final long identity = Binder.clearCallingIdentity();
try {
return mWindowManager.injectInputAfterTransactionsApplied(event, mode);
return mWindowManager.injectInputAfterTransactionsApplied(event, mode,
waitForAnimations);
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(identity);
@@ -143,7 +144,7 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
}
@Override
public void syncInputTransactions() {
public void syncInputTransactions(boolean waitForAnimations) {
synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked();
@@ -151,12 +152,11 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
}
try {
mWindowManager.syncInputTransactions();
mWindowManager.syncInputTransactions(waitForAnimations);
} catch (RemoteException e) {
}
}
@Override
public boolean setRotation(int rotation) {
synchronized (mLock) {

View File

@@ -668,22 +668,24 @@ interface IWindowManager
void setShouldShowIme(int displayId, boolean shouldShow);
/**
* Waits for transactions to get applied before injecting input.
* This includes waiting for the input windows to get sent to InputManager.
* Waits for transactions to get applied before injecting input, optionally waiting for
* animations to complete. This includes waiting for the input windows to get sent to
* InputManager.
*
* This is needed for testing since the system add windows and injects input
* quick enough that the windows don't have time to get sent to InputManager.
*/
boolean injectInputAfterTransactionsApplied(in InputEvent ev, int mode);
boolean injectInputAfterTransactionsApplied(in InputEvent ev, int mode,
boolean waitForAnimations);
/**
* Waits until all animations have completed and input information has been sent from
* WindowManager to native InputManager.
* Waits until input information has been sent from WindowManager to native InputManager,
* optionally waiting for animations to complete.
*
* This is needed for testing since we need to ensure input information has been propagated to
* native InputManager before proceeding with tests.
*/
void syncInputTransactions();
void syncInputTransactions(boolean waitForAnimations);
/**
* Returns whether SurfaceFlinger layer tracing is enabled.

View File

@@ -2978,7 +2978,7 @@ public class WindowManagerService extends IWindowManager.Stub
displayContent, true /* includingParents */);
}
}
syncInputTransactions();
syncInputTransactions(true /* waitForAnimations */);
}
/**
@@ -7979,7 +7979,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
public boolean injectInputAfterTransactionsApplied(InputEvent ev, int mode) {
public boolean injectInputAfterTransactionsApplied(InputEvent ev, int mode,
boolean waitForAnimations) {
boolean isDown;
boolean isUp;
@@ -7998,21 +7999,23 @@ public class WindowManagerService extends IWindowManager.Stub
// For all mouse events, also sync before injecting.
// For ACTION_UP, sync after injecting.
if (isDown || isMouseEvent) {
syncInputTransactions();
syncInputTransactions(waitForAnimations);
}
final boolean result =
LocalServices.getService(InputManagerInternal.class).injectInputEvent(ev, mode);
if (isUp) {
syncInputTransactions();
syncInputTransactions(waitForAnimations);
}
return result;
}
@Override
public void syncInputTransactions() {
public void syncInputTransactions(boolean waitForAnimations) {
final long token = Binder.clearCallingIdentity();
try {
waitForAnimationsToComplete();
if (waitForAnimations) {
waitForAnimationsToComplete();
}
// Collect all input transactions from all displays to make sure we could sync all input
// windows at same time.