diff --git a/api/current.txt b/api/current.txt index e83450136aa4a..661319f199889 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6532,6 +6532,7 @@ package android.app { method public android.graphics.Bitmap takeScreenshot(); method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException; field public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 1; // 0x1 + field public static final int FLAG_DONT_USE_ACCESSIBILITY = 2; // 0x2 field public static final int ROTATION_FREEZE_0 = 0; // 0x0 field public static final int ROTATION_FREEZE_180 = 2; // 0x2 field public static final int ROTATION_FREEZE_270 = 3; // 0x3 diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index 2ef147b3e903e..f2a9daafb4cef 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -97,7 +97,8 @@ public class Instrumentation { * @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef({0, UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES}) + @IntDef({0, UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES, + UiAutomation.FLAG_DONT_USE_ACCESSIBILITY}) public @interface UiAutomationFlags {}; @@ -2170,7 +2171,8 @@ public class Instrumentation { *

* * @param flags The flags to be passed to the UiAutomation, for example - * {@link UiAutomation#FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES}. + * {@link UiAutomation#FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES}, + * {@link UiAutomation#FLAG_DONT_USE_ACCESSIBILITY}. * * @return The UI automation instance. * diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 109205fadf187..ab997e9f78328 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -56,6 +56,7 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IAccessibilityInteractionConnection; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.function.pooled.PooledLambda; import libcore.io.IoUtils; @@ -142,13 +143,22 @@ public final class UiAutomation { } /** - * UiAutomation supresses accessibility services by default. This flag specifies that + * UiAutomation suppresses accessibility services by default. This flag specifies that * existing accessibility services should continue to run, and that new ones may start. * This flag is set when obtaining the UiAutomation from * {@link Instrumentation#getUiAutomation(int)}. */ public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 0x00000001; + /** + * UiAutomation uses the accessibility subsystem by default. This flag provides an option to + * eliminate the overhead of engaging the accessibility subsystem for tests that do not need to + * interact with the user interface. Setting this flag disables methods that rely on + * accessibility. This flag is set when obtaining the UiAutomation from + * {@link Instrumentation#getUiAutomation(int)}. + */ + public static final int FLAG_DONT_USE_ACCESSIBILITY = 0x00000002; + private final Object mLock = new Object(); private final ArrayList mEventQueue = new ArrayList(); @@ -267,11 +277,14 @@ public final class UiAutomation { /** * Connects this UiAutomation to the accessibility introspection APIs. * - * @param flags Any flags to apply to the automation as it gets connected + * @param flags Any flags to apply to the automation as it gets connected while + * {@link UiAutomation#FLAG_DONT_USE_ACCESSIBILITY} would keep the + * connection disconnected and not to register UiAutomation service. * @param timeoutMillis The wait timeout in milliseconds * + * @throws IllegalStateException If the connection to the accessibility subsystem is already + * established. * @throws TimeoutException If not connected within the timeout - * * @hide */ public void connectWithTimeout(int flags, long timeoutMillis) throws TimeoutException { @@ -292,6 +305,12 @@ public final class UiAutomation { // Calling out without a lock held. mUiAutomationConnection.connect(mClient, flags); mFlags = flags; + // If UiAutomation is not allowed to use the accessibility subsystem, the + // connection state should keep disconnected and not to start the client connection. + if (!useAccessibility()) { + mConnectionState = ConnectionState.DISCONNECTED; + return; + } } catch (RemoteException re) { throw new RuntimeException("Error while connecting " + this, re); } @@ -340,7 +359,7 @@ public final class UiAutomation { throw new IllegalStateException( "Cannot call disconnect() while connecting " + this); } - if (mConnectionState == ConnectionState.DISCONNECTED) { + if (useAccessibility() && mConnectionState == ConnectionState.DISCONNECTED) { return; } mConnectionState = ConnectionState.DISCONNECTED; @@ -354,8 +373,10 @@ public final class UiAutomation { } catch (RemoteException re) { throw new RuntimeException("Error while disconnecting " + this, re); } finally { - mRemoteCallbackThread.quit(); - mRemoteCallbackThread = null; + if (mRemoteCallbackThread != null) { + mRemoteCallbackThread.quit(); + mRemoteCallbackThread = null; + } } } @@ -389,9 +410,13 @@ public final class UiAutomation { * The callbacks are delivered on the main application thread. * * @param listener The callback. + * + * @throws IllegalStateException If the connection to the accessibility subsystem is not + * established. */ public void setOnAccessibilityEventListener(OnAccessibilityEventListener listener) { synchronized (mLock) { + throwIfNotConnectedLocked(); mOnAccessibilityEventListener = listener; } } @@ -423,9 +448,6 @@ public final class UiAutomation { * @see #dropShellPermissionIdentity() */ public void adoptShellPermissionIdentity() { - synchronized (mLock) { - throwIfNotConnectedLocked(); - } try { // Calling out without a lock held. mUiAutomationConnection.adoptShellPermissionIdentity(Process.myUid(), null); @@ -451,9 +473,6 @@ public final class UiAutomation { * @see #dropShellPermissionIdentity() */ public void adoptShellPermissionIdentity(@Nullable String... permissions) { - synchronized (mLock) { - throwIfNotConnectedLocked(); - } try { // Calling out without a lock held. mUiAutomationConnection.adoptShellPermissionIdentity(Process.myUid(), permissions); @@ -470,9 +489,6 @@ public final class UiAutomation { * @see #adoptShellPermissionIdentity() */ public void dropShellPermissionIdentity() { - synchronized (mLock) { - throwIfNotConnectedLocked(); - } try { // Calling out without a lock held. mUiAutomationConnection.dropShellPermissionIdentity(); @@ -489,6 +505,8 @@ public final class UiAutomation { * @param action The action to perform. * @return Whether the action was successfully performed. * + * @throws IllegalStateException If the connection to the accessibility subsystem is not + * established. * @see android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_BACK * @see android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_HOME * @see android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_NOTIFICATIONS @@ -523,13 +541,18 @@ public final class UiAutomation { *

* * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or - * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}. + * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}. * @return The node info of the focused view or null. * + * @throws IllegalStateException If the connection to the accessibility subsystem is not + * established. * @see AccessibilityNodeInfo#FOCUS_INPUT * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY */ public AccessibilityNodeInfo findFocus(int focus) { + synchronized (mLock) { + throwIfNotConnectedLocked(); + } return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, AccessibilityWindowInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus); } @@ -541,6 +564,8 @@ public final class UiAutomation { * * @return The accessibility service info. * + * @throws IllegalStateException If the connection to the accessibility subsystem is not + * established. * @see AccessibilityServiceInfo */ public final AccessibilityServiceInfo getServiceInfo() { @@ -567,6 +592,8 @@ public final class UiAutomation { * * @param info The info. * + * @throws IllegalStateException If the connection to the accessibility subsystem is not + * established. * @see AccessibilityServiceInfo */ public final void setServiceInfo(AccessibilityServiceInfo info) { @@ -602,6 +629,8 @@ public final class UiAutomation { *

* * @return The windows if there are windows such, otherwise an empty list. + * @throws IllegalStateException If the connection to the accessibility subsystem is not + * established. */ public List getWindows() { final int connectionId; @@ -630,6 +659,8 @@ public final class UiAutomation { * * @return The windows of all displays if there are windows and the service is can retrieve * them, otherwise an empty list. The key of SparseArray is display ID. + * @throws IllegalStateException If the connection to the accessibility subsystem is not + * established. */ @NonNull public SparseArray> getWindowsOnAllDisplays() { @@ -647,6 +678,8 @@ public final class UiAutomation { * Gets the root {@link AccessibilityNodeInfo} in the active window. * * @return The root info. + * @throws IllegalStateException If the connection to the accessibility subsystem is not + * established. */ public AccessibilityNodeInfo getRootInActiveWindow() { final int connectionId; @@ -664,14 +697,12 @@ public final class UiAutomation { *

* Note: It is caller's responsibility to recycle the event. *

+ * * @param event The event to inject. * @param sync Whether to inject the event synchronously. * @return Whether event injection succeeded. */ public boolean injectInputEvent(InputEvent event, boolean sync) { - synchronized (mLock) { - throwIfNotConnectedLocked(); - } try { if (DEBUG) { Log.i(LOG_TAG, "Injecting: " + event + " sync: " + sync); @@ -692,9 +723,6 @@ public final class UiAutomation { */ @TestApi public void syncInputTransactions() { - synchronized (mLock) { - throwIfNotConnectedLocked(); - } try { // Calling out without a lock held. mUiAutomationConnection.syncInputTransactions(); @@ -720,9 +748,6 @@ public final class UiAutomation { * @see #ROTATION_UNFREEZE */ public boolean setRotation(int rotation) { - synchronized (mLock) { - throwIfNotConnectedLocked(); - } switch (rotation) { case ROTATION_FREEZE_0: case ROTATION_FREEZE_90: @@ -752,11 +777,14 @@ public final class UiAutomation { *

* Note: It is caller's responsibility to recycle the returned event. *

+ * * @param command The command to execute. * @param filter Filter that recognizes the expected event. * @param timeoutMillis The wait timeout in milliseconds. * * @throws TimeoutException If the expected event is not received within the timeout. + * @throws IllegalStateException If the connection to the accessibility subsystem is not + * established. */ public AccessibilityEvent executeAndWaitForEvent(Runnable command, AccessibilityEventFilter filter, long timeoutMillis) throws TimeoutException { @@ -845,6 +873,8 @@ public final class UiAutomation { * * @throws TimeoutException If no idle state was detected within * globalTimeoutMillis. + * @throws IllegalStateException If the connection to the accessibility subsystem is not + * established. */ public void waitForIdle(long idleTimeoutMillis, long globalTimeoutMillis) throws TimeoutException { @@ -874,9 +904,9 @@ public final class UiAutomation { return; } try { - mLock.wait(remainingIdleTimeMillis); + mLock.wait(remainingIdleTimeMillis); } catch (InterruptedException ie) { - /* ignore */ + /* ignore */ } } } @@ -888,9 +918,6 @@ public final class UiAutomation { * @return The screenshot bitmap on success, null otherwise. */ public Bitmap takeScreenshot() { - synchronized (mLock) { - throwIfNotConnectedLocked(); - } Display display = DisplayManagerGlobal.getInstance() .getRealDisplay(Display.DEFAULT_DISPLAY); Point displaySize = new Point(); @@ -927,9 +954,6 @@ public final class UiAutomation { * @see ActivityManager#isUserAMonkey() */ public void setRunAsMonkey(boolean enable) { - synchronized (mLock) { - throwIfNotConnectedLocked(); - } try { ActivityManager.getService().setUserIsMonkey(enable); } catch (RemoteException re) { @@ -946,6 +970,8 @@ public final class UiAutomation { * @return Whether the window is present and its frame statistics * were cleared. * + * @throws IllegalStateException If the connection to the accessibility subsystem is not + * established. * @see android.view.WindowContentFrameStats * @see #getWindowContentFrameStats(int) * @see #getWindows() @@ -991,6 +1017,8 @@ public final class UiAutomation { * @param windowId The window id. * @return The window frame statistics, or null if the window is not present. * + * @throws IllegalStateException If the connection to the accessibility subsystem is not + * established. * @see android.view.WindowContentFrameStats * @see #clearWindowContentFrameStats(int) * @see #getWindows() @@ -1022,9 +1050,6 @@ public final class UiAutomation { * @see android.R.styleable#WindowAnimation */ public void clearWindowAnimationFrameStats() { - synchronized (mLock) { - throwIfNotConnectedLocked(); - } try { if (DEBUG) { Log.i(LOG_TAG, "Clearing window animation frame stats"); @@ -1064,9 +1089,6 @@ public final class UiAutomation { * @see android.R.styleable#WindowAnimation */ public WindowAnimationFrameStats getWindowAnimationFrameStats() { - synchronized (mLock) { - throwIfNotConnectedLocked(); - } try { if (DEBUG) { Log.i(LOG_TAG, "Getting window animation frame stats"); @@ -1081,6 +1103,7 @@ public final class UiAutomation { /** * Grants a runtime permission to a package. + * * @param packageName The package to which to grant. * @param permission The permission to grant. * @throws SecurityException if unable to grant the permission. @@ -1104,15 +1127,13 @@ public final class UiAutomation { /** * Grants a runtime permission to a package for a user. + * * @param packageName The package to which to grant. * @param permission The permission to grant. * @throws SecurityException if unable to grant the permission. */ public void grantRuntimePermissionAsUser(String packageName, String permission, UserHandle userHandle) { - synchronized (mLock) { - throwIfNotConnectedLocked(); - } try { if (DEBUG) { Log.i(LOG_TAG, "Granting runtime permission"); @@ -1127,6 +1148,7 @@ public final class UiAutomation { /** * Revokes a runtime permission from a package. + * * @param packageName The package to which to grant. * @param permission The permission to grant. * @throws SecurityException if unable to revoke the permission. @@ -1150,15 +1172,13 @@ public final class UiAutomation { /** * Revokes a runtime permission from a package. + * * @param packageName The package to which to grant. * @param permission The permission to grant. * @throws SecurityException if unable to revoke the permission. */ public void revokeRuntimePermissionAsUser(String packageName, String permission, UserHandle userHandle) { - synchronized (mLock) { - throwIfNotConnectedLocked(); - } try { if (DEBUG) { Log.i(LOG_TAG, "Revoking runtime permission"); @@ -1186,9 +1206,6 @@ public final class UiAutomation { * @see #adoptShellPermissionIdentity() */ public ParcelFileDescriptor executeShellCommand(String command) { - synchronized (mLock) { - throwIfNotConnectedLocked(); - } warnIfBetterCommand(command); ParcelFileDescriptor source = null; @@ -1229,9 +1246,6 @@ public final class UiAutomation { */ @TestApi public ParcelFileDescriptor[] executeShellCommandRw(String command) { - synchronized (mLock) { - throwIfNotConnectedLocked(); - } warnIfBetterCommand(command); ParcelFileDescriptor source_read = null; @@ -1276,15 +1290,21 @@ public final class UiAutomation { return stringBuilder.toString(); } + @GuardedBy("mLock") private void throwIfConnectedLocked() { if (mConnectionState == ConnectionState.CONNECTED) { throw new IllegalStateException("UiAutomation connected, " + this); } } + @GuardedBy("mLock") private void throwIfNotConnectedLocked() { if (mConnectionState != ConnectionState.CONNECTED) { - throw new IllegalStateException("UiAutomation not connected, " + this); + final String msg = useAccessibility() + ? "UiAutomation not connected, " + : "UiAutomation not connected: Accessibility-dependent method called with " + + "FLAG_DONT_USE_ACCESSIBILITY set, "; + throw new IllegalStateException(msg + this); } } @@ -1298,11 +1318,16 @@ public final class UiAutomation { } } + private boolean useAccessibility() { + return (mFlags & UiAutomation.FLAG_DONT_USE_ACCESSIBILITY) == 0; + } + private class IAccessibilityServiceClientImpl extends IAccessibilityServiceClientWrapper { public IAccessibilityServiceClientImpl(Looper looper, int generationId) { super(null, looper, new Callbacks() { private final int mGenerationId = generationId; + /** * True if UiAutomation doesn't interact with this client anymore. * Used by methods below to stop sending notifications or changing members diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt index bb40e24a68acc..a868c718447d3 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -6532,6 +6532,7 @@ package android.app { method public android.graphics.Bitmap takeScreenshot(); method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException; field public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 1; // 0x1 + field public static final int FLAG_DONT_USE_ACCESSIBILITY = 2; // 0x2 field public static final int ROTATION_FREEZE_0 = 0; // 0x0 field public static final int ROTATION_FREEZE_180 = 2; // 0x2 field public static final int ROTATION_FREEZE_270 = 3; // 0x3 diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java index 3d6a12884ec64..4473754e2b680 100644 --- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java +++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java @@ -72,7 +72,8 @@ class UiAutomationManager { }; /** - * Register a UiAutomation. Only one may be registered at a time. + * Register a UiAutomation if it uses the accessibility subsystem. Only one may be registered + * at a time. * * @param owner A binder object owned by the process that owns the UiAutomation to be * registered. @@ -80,6 +81,7 @@ class UiAutomationManager { * @param accessibilityServiceInfo The UiAutomation's service info * @param flags The UiAutomation's flags * @param id The id for the service connection + * @see UiAutomation#FLAG_DONT_USE_ACCESSIBILITY */ void registerUiTestAutomationServiceLocked(IBinder owner, IAccessibilityServiceClient serviceClient, @@ -88,14 +90,15 @@ class UiAutomationManager { AccessibilitySecurityPolicy securityPolicy, AbstractAccessibilityServiceConnection.SystemSupport systemSupport, WindowManagerInternal windowManagerInternal, - SystemActionPerformer systemActionPerfomer, + SystemActionPerformer systemActionPerformer, AccessibilityWindowManager awm, int flags) { synchronized (mLock) { accessibilityServiceInfo.setComponentName(COMPONENT_NAME); if (mUiAutomationService != null) { - throw new IllegalStateException("UiAutomationService " + serviceClient - + "already registered!"); + throw new IllegalStateException( + "UiAutomationService " + mUiAutomationService.mServiceInterface + + "already registered!"); } try { @@ -106,12 +109,17 @@ class UiAutomationManager { return; } + mUiAutomationFlags = flags; mSystemSupport = systemSupport; + // Ignore registering UiAutomation if it is not allowed to use the accessibility + // subsystem. + if (!useAccessibility()) { + return; + } mUiAutomationService = new UiAutomationService(context, accessibilityServiceInfo, id, mainHandler, mLock, securityPolicy, systemSupport, windowManagerInternal, - systemActionPerfomer, awm); + systemActionPerformer, awm); mUiAutomationServiceOwner = owner; - mUiAutomationFlags = flags; mUiAutomationServiceInfo = accessibilityServiceInfo; mUiAutomationService.mServiceInterface = serviceClient; mUiAutomationService.onAdded(); @@ -130,15 +138,15 @@ class UiAutomationManager { void unregisterUiTestAutomationServiceLocked(IAccessibilityServiceClient serviceClient) { synchronized (mLock) { - if ((mUiAutomationService == null) + if (useAccessibility() + && ((mUiAutomationService == null) || (serviceClient == null) || (mUiAutomationService.mServiceInterface == null) || (serviceClient.asBinder() - != mUiAutomationService.mServiceInterface.asBinder())) { + != mUiAutomationService.mServiceInterface.asBinder()))) { throw new IllegalStateException("UiAutomationService " + serviceClient + " not registered!"); } - destroyUiAutomationService(); } } @@ -150,14 +158,19 @@ class UiAutomationManager { } boolean isUiAutomationRunningLocked() { - return (mUiAutomationService != null); + return (mUiAutomationService != null || !useAccessibility()); } boolean suppressingAccessibilityServicesLocked() { - return (mUiAutomationService != null) && ((mUiAutomationFlags + return (mUiAutomationService != null || !useAccessibility()) + && ((mUiAutomationFlags & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0); } + boolean useAccessibility() { + return ((mUiAutomationFlags & UiAutomation.FLAG_DONT_USE_ACCESSIBILITY) == 0); + } + boolean isTouchExplorationEnabledLocked() { return (mUiAutomationService != null) && mUiAutomationService.mRequestTouchExplorationMode; @@ -209,14 +222,14 @@ class UiAutomationManager { mUiAutomationService.onRemoved(); mUiAutomationService.resetLocked(); mUiAutomationService = null; - mUiAutomationFlags = 0; if (mUiAutomationServiceOwner != null) { mUiAutomationServiceOwner.unlinkToDeath( mUiAutomationServiceOwnerDeathRecipient, 0); mUiAutomationServiceOwner = null; } - mSystemSupport.onClientChangeLocked(false); } + mUiAutomationFlags = 0; + mSystemSupport.onClientChangeLocked(false); } } @@ -227,9 +240,9 @@ class UiAutomationManager { int id, Handler mainHandler, Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport, WindowManagerInternal windowManagerInternal, - SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager awm) { + SystemActionPerformer systemActionPerformer, AccessibilityWindowManager awm) { super(context, COMPONENT_NAME, accessibilityServiceInfo, id, mainHandler, lock, - securityPolicy, systemSupport, windowManagerInternal, systemActionPerfomer, + securityPolicy, systemSupport, windowManagerInternal, systemActionPerformer, awm); mMainHandler = mainHandler; } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java index c8baca610bdc1..8062bfec3703a 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java @@ -170,6 +170,30 @@ public class UiAutomationManagerTest { verify(mMockSystemSupport).onClientChangeLocked(false); } + @Test + public void uiAutomationWithDontUseAccessibilityFlagAfterUnregistering_notifiesSystem() + throws Exception { + register(UiAutomation.FLAG_DONT_USE_ACCESSIBILITY); + unregister(); + verify(mMockSystemSupport).onClientChangeLocked(false); + } + + @Test + public void uiAutomationWithDontUseAccessibilityFlag_disableAccessibilityFunctions() + throws Exception { + register(0); + assertTrue(mUiAutomationManager.isUiAutomationRunningLocked()); + unregister(); + assertFalse(mUiAutomationManager.isUiAutomationRunningLocked()); + register(UiAutomation.FLAG_DONT_USE_ACCESSIBILITY); + assertTrue(mUiAutomationManager.isUiAutomationRunningLocked()); + assertFalse(mUiAutomationManager.useAccessibility()); + assertFalse(mUiAutomationManager.canRetrieveInteractiveWindowsLocked()); + assertFalse(mUiAutomationManager.isTouchExplorationEnabledLocked()); + assertEquals(0, mUiAutomationManager.getRelevantEventTypes()); + assertEquals(0, mUiAutomationManager.getRequestedEventMaskLocked()); + } + private void register(int flags) { mUiAutomationManager.registerUiTestAutomationServiceLocked(mMockOwner, mMockAccessibilityServiceClient, mMockContext, mMockServiceInfo, SERVICE_ID,