AccessibilityInteractionClient.java revision 6bc5e530016928027c7b390a8368ecdd5bff072f
18bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov/*
28bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov ** Copyright 2011, The Android Open Source Project
38bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov **
48bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov ** Licensed under the Apache License, Version 2.0 (the "License");
58bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov ** you may not use this file except in compliance with the License.
68bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov ** You may obtain a copy of the License at
78bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov **
88bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov **     http://www.apache.org/licenses/LICENSE-2.0
98bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov **
108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov ** Unless required by applicable law or agreed to in writing, software
118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov ** distributed under the License is distributed on an "AS IS" BASIS,
128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov ** See the License for the specific language governing permissions and
148bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov ** limitations under the License.
158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */
168bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
178bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovpackage android.view.accessibility;
188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
198bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport android.accessibilityservice.IAccessibilityServiceConnection;
208bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport android.graphics.Rect;
218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport android.os.Message;
228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport android.os.RemoteException;
238bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport android.os.SystemClock;
248bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport java.util.Collections;
268bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport java.util.List;
278bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport java.util.concurrent.atomic.AtomicInteger;
288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov/**
308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * This class is a singleton that performs accessibility interaction
318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * which is it queries remote view hierarchies about snapshots of their
328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * views as well requests from these hierarchies to perform certain
338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * actions on their views.
348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *
358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Rationale: The content retrieval APIs are synchronous from a client's
368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     perspective but internally they are asynchronous. The client thread
378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     calls into the system requesting an action and providing a callback
388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     to receive the result after which it waits up to a timeout for that
398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     result. The system enforces security and the delegates the request
408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     to a given view hierarchy where a message is posted (from a binder
418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     thread) describing what to be performed by the main UI thread the
428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     result of which it delivered via the mentioned callback. However,
438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     the blocked client thread and the main UI thread of the target view
448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     hierarchy can be the same thread, for example an accessibility service
458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     and an activity run in the same process, thus they are executed on the
468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     same main thread. In such a case the retrieval will fail since the UI
478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     thread that has to process the message describing the work to be done
488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     is blocked waiting for a result is has to compute! To avoid this scenario
498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     when making a call the client also passes its process and thread ids so
508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     the accessed view hierarchy can detect if the client making the request
518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     is running in its main UI thread. In such a case the view hierarchy,
528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     specifically the binder thread performing the IPC to it, does not post a
538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     message to be run on the UI thread but passes it to the singleton
548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     interaction client through which all interactions occur and the latter is
558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     responsible to execute the message before starting to wait for the
568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     asynchronous result delivered via the callback. In this case the expected
578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *     result is already received so no waiting is performed.
588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov *
598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @hide
608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */
618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovpublic final class AccessibilityInteractionClient
628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        extends IAccessibilityInteractionConnectionCallback.Stub {
638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private static final long TIMEOUT_INTERACTION_MILLIS = 5000;
658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private static final Object sStaticLock = new Object();
678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private static AccessibilityInteractionClient sInstance;
698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
708bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private final AtomicInteger mInteractionIdCounter = new AtomicInteger();
718bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
728bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private final Object mInstanceLock = new Object();
738bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
748bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private int mInteractionId = -1;
758bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
768bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private AccessibilityNodeInfo mFindAccessibilityNodeInfoResult;
778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private List<AccessibilityNodeInfo> mFindAccessibilityNodeInfosResult;
798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private boolean mPerformAccessibilityActionResult;
818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private Message mSameThreadMessage;
838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private final Rect mTempBounds = new Rect();
858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @return The singleton of this class.
888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    public static AccessibilityInteractionClient getInstance() {
908bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        synchronized (sStaticLock) {
918bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            if (sInstance == null) {
928bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                sInstance = new AccessibilityInteractionClient();
938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            }
948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            return sInstance;
958bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Sets the message to be processed if the interacted view hierarchy
1008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * and the interacting client are running in the same thread.
1018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *
1028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param message The message.
1038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
1048bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    public void setSameThreadMessage(Message message) {
1058bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        synchronized (mInstanceLock) {
1068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            mSameThreadMessage = message;
1076bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov            mInstanceLock.notifyAll();
1088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
1098bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
1108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
1118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
1128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Finds an {@link AccessibilityNodeInfo} by accessibility id.
1138bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *
1148bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param connection A connection for interacting with the system.
1158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param accessibilityWindowId A unique window id.
1168bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param accessibilityViewId A unique View accessibility id.
1178bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @return An {@link AccessibilityNodeInfo} if found, null otherwise.
1188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
1198bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(
1208bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            IAccessibilityServiceConnection connection, int accessibilityWindowId,
1218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            int accessibilityViewId) {
1228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        try {
1238bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final int interactionId = mInteractionIdCounter.getAndIncrement();
1248bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId(
1258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                    accessibilityWindowId, accessibilityViewId, interactionId, this,
1268bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                    Thread.currentThread().getId());
1278bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            // If the scale is zero the call has failed.
1288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            if (windowScale > 0) {
1298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
1308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                        interactionId);
1318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                finalizeAccessibilityNodeInfo(info, connection, windowScale);
1328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                return info;
1338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            }
1348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        } catch (RemoteException re) {
1358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            /* ignore */
1368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
1378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        return null;
1388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
1398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
1408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
1418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed
1428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * in the currently active window and starts from the root View in the window.
1438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *
1448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param connection A connection for interacting with the system.
1456bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov     * @param viewId The id of the view.
1468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @return An {@link AccessibilityNodeInfo} if found, null otherwise.
1478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
1488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(
1498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            IAccessibilityServiceConnection connection, int viewId) {
1508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        try {
1518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final int interactionId = mInteractionIdCounter.getAndIncrement();
1528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final float windowScale = connection.findAccessibilityNodeInfoByViewIdInActiveWindow(
1538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                    viewId, interactionId, this, Thread.currentThread().getId());
1548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            // If the scale is zero the call has failed.
1558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            if (windowScale > 0) {
1568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
1578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                        interactionId);
1588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                finalizeAccessibilityNodeInfo(info, connection, windowScale);
1598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                return info;
1608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            }
1618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        } catch (RemoteException re) {
1628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            /* ignore */
1638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
1648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        return null;
1658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
1668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
1678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
1688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
1698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * insensitive containment. The search is performed in the currently
1708bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * active window and starts from the root View in the window.
1718bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *
1728bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param connection A connection for interacting with the system.
1738bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param text The searched text.
1748bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @return A list of found {@link AccessibilityNodeInfo}s.
1758bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
1768bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewTextInActiveWindow(
1778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            IAccessibilityServiceConnection connection, String text) {
1788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        try {
1798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final int interactionId = mInteractionIdCounter.getAndIncrement();
1808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final float windowScale = connection.findAccessibilityNodeInfosByViewTextInActiveWindow(
1818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                    text, interactionId, this, Thread.currentThread().getId());
1828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            // If the scale is zero the call has failed.
1838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            if (windowScale > 0) {
1848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
1858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                        interactionId);
1868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                finalizeAccessibilityNodeInfos(infos, connection, windowScale);
1878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                return infos;
1888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            }
1898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        } catch (RemoteException re) {
1908bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            /* ignore */
1918bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
1928bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        return null;
1938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
1948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
1958bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
1968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
1978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * insensitive containment. The search is performed in the window whose
1988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * id is specified and starts from the View whose accessibility id is
1998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * specified.
2008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *
2018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param connection A connection for interacting with the system.
2028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param text The searched text.
2038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param accessibilityWindowId A unique window id.
2048bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param accessibilityViewId A unique View accessibility id from where to start the search.
2058bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *        Use {@link android.view.View#NO_ID} to start from the root.
2068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @return A list of found {@link AccessibilityNodeInfo}s.
2078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
2088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(
2098bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            IAccessibilityServiceConnection connection, String text, int accessibilityWindowId,
2108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            int accessibilityViewId) {
2118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        try {
2128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final int interactionId = mInteractionIdCounter.getAndIncrement();
2138bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final float windowScale = connection.findAccessibilityNodeInfosByViewText(text,
2148bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                    accessibilityWindowId, accessibilityViewId, interactionId, this,
2158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                    Thread.currentThread().getId());
2168bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            // If the scale is zero the call has failed.
2178bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            if (windowScale > 0) {
2188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
2198bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                        interactionId);
2208bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                finalizeAccessibilityNodeInfos(infos, connection, windowScale);
2218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                return infos;
2228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            }
2238bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        } catch (RemoteException re) {
2248bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            /* ignore */
2258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
2268bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        return Collections.emptyList();
2278bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
2288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
2298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
2308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
2318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *
2328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param connection A connection for interacting with the system.
2338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param accessibilityWindowId The id of the window.
2348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param accessibilityViewId A unique View accessibility id.
2358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param action The action to perform.
2368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @return Whether the action was performed.
2378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
2388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    public boolean performAccessibilityAction(IAccessibilityServiceConnection connection,
2398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            int accessibilityWindowId, int accessibilityViewId, int action) {
2408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        try {
2418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final int interactionId = mInteractionIdCounter.getAndIncrement();
2428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final boolean success = connection.performAccessibilityAction(
2438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                    accessibilityWindowId, accessibilityViewId, action, interactionId, this,
2448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                    Thread.currentThread().getId());
2458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            if (success) {
2468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                return getPerformAccessibilityActionResult(interactionId);
2478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            }
2488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        } catch (RemoteException re) {
2498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            /* ignore */
2508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
2518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        return false;
2528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
2538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
2548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
2558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Gets the the result of an async request that returns an {@link AccessibilityNodeInfo}.
2568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *
2578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param interactionId The interaction id to match the result with the request.
2588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @return The result {@link AccessibilityNodeInfo}.
2598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
2608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private AccessibilityNodeInfo getFindAccessibilityNodeInfoResultAndClear(int interactionId) {
2618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        synchronized (mInstanceLock) {
2628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final boolean success = waitForResultTimedLocked(interactionId);
2638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            AccessibilityNodeInfo result = success ? mFindAccessibilityNodeInfoResult : null;
2648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            clearResultLocked();
2658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            return result;
2668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
2678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
2688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
2698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
2708bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * {@inheritDoc}
2718bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
2728bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    public void setFindAccessibilityNodeInfoResult(AccessibilityNodeInfo info,
2738bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                int interactionId) {
2748bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        synchronized (mInstanceLock) {
2758bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            if (interactionId > mInteractionId) {
2768bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                mFindAccessibilityNodeInfoResult = info;
2778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                mInteractionId = interactionId;
2788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            }
2798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            mInstanceLock.notifyAll();
2808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
2818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
2828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
2838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
2848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Gets the the result of an async request that returns {@link AccessibilityNodeInfo}s.
2858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *
2868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param interactionId The interaction id to match the result with the request.
2878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @return The result {@link AccessibilityNodeInfo}s.
2888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
2898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private List<AccessibilityNodeInfo> getFindAccessibilityNodeInfosResultAndClear(
2908bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                int interactionId) {
2918bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        synchronized (mInstanceLock) {
2928bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final boolean success = waitForResultTimedLocked(interactionId);
2938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            List<AccessibilityNodeInfo> result = success ? mFindAccessibilityNodeInfosResult : null;
2948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            clearResultLocked();
2958bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            return result;
2968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
2978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
2988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
2998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
3008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * {@inheritDoc}
3018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
3028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    public void setFindAccessibilityNodeInfosResult(List<AccessibilityNodeInfo> infos,
3038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                int interactionId) {
3048bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        synchronized (mInstanceLock) {
3058bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            if (interactionId > mInteractionId) {
3068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                mFindAccessibilityNodeInfosResult = infos;
3078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                mInteractionId = interactionId;
3088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            }
3098bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            mInstanceLock.notifyAll();
3108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
3118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
3128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
3138bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
3148bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Gets the result of a request to perform an accessibility action.
3158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *
3168bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param interactionId The interaction id to match the result with the request.
3178bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @return Whether the action was performed.
3188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
3198bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private boolean getPerformAccessibilityActionResult(int interactionId) {
3208bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        synchronized (mInstanceLock) {
3218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final boolean success = waitForResultTimedLocked(interactionId);
3228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final boolean result = success ? mPerformAccessibilityActionResult : false;
3238bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            clearResultLocked();
3248bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            return result;
3258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
3268bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
3278bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
3288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
3298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * {@inheritDoc}
3308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
3318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    public void setPerformAccessibilityActionResult(boolean succeeded, int interactionId) {
3328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        synchronized (mInstanceLock) {
3338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            if (interactionId > mInteractionId) {
3348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                mPerformAccessibilityActionResult = succeeded;
3358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                mInteractionId = interactionId;
3368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            }
3378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            mInstanceLock.notifyAll();
3388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
3398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
3408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
3418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
3428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Clears the result state.
3438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
3448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private void clearResultLocked() {
3458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        mInteractionId = -1;
3468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        mFindAccessibilityNodeInfoResult = null;
3478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        mFindAccessibilityNodeInfosResult = null;
3488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        mPerformAccessibilityActionResult = false;
3498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
3508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
3518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
3528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Waits up to a given bound for a result of a request and returns it.
3538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *
3548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param interactionId The interaction id to match the result with the request.
3558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @return Whether the result was received.
3568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
3578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private boolean waitForResultTimedLocked(int interactionId) {
3588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        long waitTimeMillis = TIMEOUT_INTERACTION_MILLIS;
3598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        final long startTimeMillis = SystemClock.uptimeMillis();
3608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        while (true) {
3618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            try {
3626bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov                Message sameProcessMessage = getSameProcessMessageAndClear();
3636bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov                if (sameProcessMessage != null) {
3646bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov                    sameProcessMessage.getTarget().handleMessage(sameProcessMessage);
3656bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov                }
3666bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov
3678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                if (mInteractionId == interactionId) {
3688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                    return true;
3698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                }
3708bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                if (mInteractionId > interactionId) {
3718bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                    return false;
3728bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                }
3738bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
3748bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                waitTimeMillis = TIMEOUT_INTERACTION_MILLIS - elapsedTimeMillis;
3758bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                if (waitTimeMillis <= 0) {
3768bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                    return false;
3778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                }
3788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                mInstanceLock.wait(waitTimeMillis);
3798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            } catch (InterruptedException ie) {
3808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                /* ignore */
3818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            }
3828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
3838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
3848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
3858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
3868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Applies compatibility scale to the info bounds if it is not equal to one.
3878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *
3888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param info The info whose bounds to scale.
3898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param scale The scale to apply.
3908bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
3918bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private void applyCompatibilityScaleIfNeeded(AccessibilityNodeInfo info, float scale) {
3928bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        if (scale == 1.0f) {
3938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            return;
3948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
3958bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        Rect bounds = mTempBounds;
3968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        info.getBoundsInParent(bounds);
3978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        bounds.scale(scale);
3988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        info.setBoundsInParent(bounds);
3998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
4008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        info.getBoundsInScreen(bounds);
4018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        bounds.scale(scale);
4028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        info.setBoundsInScreen(bounds);
4038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
4048bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
4058bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
4068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Finalize an {@link AccessibilityNodeInfo} before passing it to the client.
4078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *
4088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param info The info.
4098bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param connection The current connection to the system.
4108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param windowScale The source window compatibility scale.
4118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
4128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private void finalizeAccessibilityNodeInfo(AccessibilityNodeInfo info,
4138bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            IAccessibilityServiceConnection connection, float windowScale) {
4148bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        if (info != null) {
4158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            applyCompatibilityScaleIfNeeded(info, windowScale);
4168bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            info.setConnection(connection);
4178bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            info.setSealed(true);
4188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
4198bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
4208bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
4218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
4228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Finalize {@link AccessibilityNodeInfo}s before passing them to the client.
4238bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *
4248bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param infos The {@link AccessibilityNodeInfo}s.
4258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param connection The current connection to the system.
4268bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @param windowScale The source window compatibility scale.
4278bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
4288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private void finalizeAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos,
4298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            IAccessibilityServiceConnection connection, float windowScale) {
4308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        if (infos != null) {
4318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            final int infosCount = infos.size();
4328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            for (int i = 0; i < infosCount; i++) {
4338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                AccessibilityNodeInfo info = infos.get(i);
4348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov                finalizeAccessibilityNodeInfo(info, connection, windowScale);
4358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            }
4368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
4378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
4388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov
4398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    /**
4408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * Gets the message stored if the interacted and interacting
4418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * threads are the same.
4428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     *
4438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     * @return The message.
4448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov     */
4458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    private Message getSameProcessMessageAndClear() {
4468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        synchronized (mInstanceLock) {
4478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            Message result = mSameThreadMessage;
4488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            mSameThreadMessage = null;
4498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov            return result;
4508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov        }
4518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov    }
4528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov}
453