From 452dbebd0effb34520456e9d06f52d9d2dc4ff1b Mon Sep 17 00:00:00 2001 From: Svet Ganov Date: Sat, 19 May 2018 18:52:40 -0700 Subject: [PATCH] Allow UiAutomation being used off the main thread Test: cts-tradefed run cts -m CtsUiAutomationTestCases cts-tradefed run cts -m CtsAccessibilityServiceTestCases cts-tradefed run cts-instant -m CtsAccessibilityServiceTestCases bug:80024164 Change-Id: I72c565d28f4cbcf6775535fb846b268b785a6b34 --- core/java/android/app/UiAutomation.java | 28 ++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index c03340e84a85c..5662aeae81102 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -28,6 +28,8 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.hardware.display.DisplayManagerGlobal; +import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.ParcelFileDescriptor; @@ -47,6 +49,7 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IAccessibilityInteractionConnection; +import com.android.internal.util.function.pooled.PooledLambda; import libcore.io.IoUtils; import java.io.IOException; @@ -118,10 +121,14 @@ public final class UiAutomation { private final ArrayList mEventQueue = new ArrayList(); - private final IAccessibilityServiceClient mClient; + private final Handler mLocalCallbackHandler; private final IUiAutomationConnection mUiAutomationConnection; + private HandlerThread mRemoteCallbackThread; + + private IAccessibilityServiceClient mClient; + private int mConnectionId = CONNECTION_ID_UNDEFINED; private OnAccessibilityEventListener mOnAccessibilityEventListener; @@ -190,8 +197,8 @@ public final class UiAutomation { if (connection == null) { throw new IllegalArgumentException("Connection cannot be null!"); } + mLocalCallbackHandler = new Handler(looper); mUiAutomationConnection = connection; - mClient = new IAccessibilityServiceClientImpl(looper); } /** @@ -217,6 +224,9 @@ public final class UiAutomation { return; } mIsConnecting = true; + mRemoteCallbackThread = new HandlerThread("UiAutomation"); + mRemoteCallbackThread.start(); + mClient = new IAccessibilityServiceClientImpl(mRemoteCallbackThread.getLooper()); } try { @@ -281,6 +291,9 @@ public final class UiAutomation { mUiAutomationConnection.disconnect(); } catch (RemoteException re) { throw new RuntimeException("Error while disconnecting UiAutomation", re); + } finally { + mRemoteCallbackThread.quit(); + mRemoteCallbackThread = null; } } @@ -311,6 +324,7 @@ public final class UiAutomation { /** * Sets a callback for observing the stream of {@link AccessibilityEvent}s. + * The callbacks are delivered on the main application thread. * * @param listener The callback. */ @@ -1139,17 +1153,21 @@ public final class UiAutomation { @Override public void onAccessibilityEvent(AccessibilityEvent event) { + final OnAccessibilityEventListener listener; synchronized (mLock) { mLastEventTimeMillis = event.getEventTime(); if (mWaitingForEventDelivery) { mEventQueue.add(AccessibilityEvent.obtain(event)); } mLock.notifyAll(); + listener = mOnAccessibilityEventListener; } - // Calling out only without a lock held. - final OnAccessibilityEventListener listener = mOnAccessibilityEventListener; if (listener != null) { - listener.onAccessibilityEvent(AccessibilityEvent.obtain(event)); + // Calling out only without a lock held. + mLocalCallbackHandler.post(PooledLambda.obtainRunnable( + OnAccessibilityEventListener::onAccessibilityEvent, + listener, AccessibilityEvent.obtain(event)) + .recycleOnUse()); } }