AccessibilityInteractionClient.java revision 36bcdb535e14a8a2e2c8643fb577569f7a2b6aed
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; 24d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganovimport android.util.Log; 25d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganovimport android.util.SparseArray; 268bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 278bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport java.util.Collections; 288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport java.util.List; 298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport java.util.concurrent.atomic.AtomicInteger; 308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov/** 328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * This class is a singleton that performs accessibility interaction 338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * which is it queries remote view hierarchies about snapshots of their 348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * views as well requests from these hierarchies to perform certain 358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * actions on their views. 368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Rationale: The content retrieval APIs are synchronous from a client's 388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * perspective but internally they are asynchronous. The client thread 398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * calls into the system requesting an action and providing a callback 408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * to receive the result after which it waits up to a timeout for that 418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * result. The system enforces security and the delegates the request 428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * to a given view hierarchy where a message is posted (from a binder 438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * thread) describing what to be performed by the main UI thread the 448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * result of which it delivered via the mentioned callback. However, 458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * the blocked client thread and the main UI thread of the target view 468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * hierarchy can be the same thread, for example an accessibility service 478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * and an activity run in the same process, thus they are executed on the 488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * same main thread. In such a case the retrieval will fail since the UI 498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * thread that has to process the message describing the work to be done 508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * is blocked waiting for a result is has to compute! To avoid this scenario 518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * when making a call the client also passes its process and thread ids so 528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * the accessed view hierarchy can detect if the client making the request 538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * is running in its main UI thread. In such a case the view hierarchy, 548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * specifically the binder thread performing the IPC to it, does not post a 558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * message to be run on the UI thread but passes it to the singleton 568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * interaction client through which all interactions occur and the latter is 578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * responsible to execute the message before starting to wait for the 588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * asynchronous result delivered via the callback. In this case the expected 598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * result is already received so no waiting is performed. 608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @hide 628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovpublic final class AccessibilityInteractionClient 648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov extends IAccessibilityInteractionConnectionCallback.Stub { 658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 66d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public static final int NO_ID = -1; 67d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 68d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov private static final String LOG_TAG = "AccessibilityInteractionClient"; 69d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 70d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov private static final boolean DEBUG = false; 71d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 728bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private static final long TIMEOUT_INTERACTION_MILLIS = 5000; 738bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 748bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private static final Object sStaticLock = new Object(); 758bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 768bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private static AccessibilityInteractionClient sInstance; 778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private final AtomicInteger mInteractionIdCounter = new AtomicInteger(); 798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private final Object mInstanceLock = new Object(); 818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private int mInteractionId = -1; 838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private AccessibilityNodeInfo mFindAccessibilityNodeInfoResult; 858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private List<AccessibilityNodeInfo> mFindAccessibilityNodeInfosResult; 878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private boolean mPerformAccessibilityActionResult; 898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 908bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private Message mSameThreadMessage; 918bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 928bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private final Rect mTempBounds = new Rect(); 938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 9436bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov // The connection cache is shared between all interrogating threads. 9536bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache = 96d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov new SparseArray<IAccessibilityServiceConnection>(); 97d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return The singleton of this class. 1008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 1018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public static AccessibilityInteractionClient getInstance() { 1028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (sStaticLock) { 1038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (sInstance == null) { 1048bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov sInstance = new AccessibilityInteractionClient(); 1058bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return sInstance; 1078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1098bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 1108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 1118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Sets the message to be processed if the interacted view hierarchy 1128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * and the interacting client are running in the same thread. 1138bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 1148bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param message The message. 1158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 1168bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setSameThreadMessage(Message message) { 1178bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 1188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mSameThreadMessage = message; 1196bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov mInstanceLock.notifyAll(); 1208bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 1238bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 1248bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finds an {@link AccessibilityNodeInfo} by accessibility id. 1258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 126d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 1278bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param accessibilityWindowId A unique window id. 1288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param accessibilityViewId A unique View accessibility id. 1298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return An {@link AccessibilityNodeInfo} if found, null otherwise. 1308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 131d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(int connectionId, 132d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov int accessibilityWindowId, int accessibilityViewId) { 1338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 134d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 135d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 136d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 137d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId( 138d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov accessibilityWindowId, accessibilityViewId, interactionId, this, 139d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Thread.currentThread().getId()); 140d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov // If the scale is zero the call has failed. 141d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (windowScale > 0) { 142d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( 143d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId); 144d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov finalizeAccessibilityNodeInfo(info, connectionId, windowScale); 145d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov return info; 146d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 147d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 148d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 149d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 150d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 1518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 153d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 154d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote" 155d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov + " findAccessibilityNodeInfoByAccessibilityId", re); 156d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 1578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return null; 1598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 1618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 1628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed 1638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * in the currently active window and starts from the root View in the window. 1648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 165d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 1666bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov * @param viewId The id of the view. 1678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return An {@link AccessibilityNodeInfo} if found, null otherwise. 1688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 169d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int connectionId, 170d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov int viewId) { 1718bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 172d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 173d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 174d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 175d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final float windowScale = 176d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov connection.findAccessibilityNodeInfoByViewIdInActiveWindow(viewId, 177d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId, this, Thread.currentThread().getId()); 178d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov // If the scale is zero the call has failed. 179d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (windowScale > 0) { 180d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( 181d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId); 182d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov finalizeAccessibilityNodeInfo(info, connectionId, windowScale); 183d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov return info; 184d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 185d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 186d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 187d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 188d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 1898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1908bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 191d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 192d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote" 193d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov + " findAccessibilityNodeInfoByViewIdInActiveWindow", re); 194d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 1958bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return null; 1978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 1998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 2008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finds {@link AccessibilityNodeInfo}s by View text. The match is case 2018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * insensitive containment. The search is performed in the currently 2028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * active window and starts from the root View in the window. 2038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 204d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 2058bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param text The searched text. 2068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return A list of found {@link AccessibilityNodeInfo}s. 2078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 2088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewTextInActiveWindow( 209d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov int connectionId, String text) { 2108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 211d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 212d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 213d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 214d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final float windowScale = 215d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov connection.findAccessibilityNodeInfosByViewTextInActiveWindow(text, 216d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId, this, Thread.currentThread().getId()); 217d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov // If the scale is zero the call has failed. 218d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (windowScale > 0) { 219d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( 220d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId); 221d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov finalizeAccessibilityNodeInfos(infos, connectionId, windowScale); 222d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov return infos; 223d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 224d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 225d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 226d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 227d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 230d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 231d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote" 232d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov + " findAccessibilityNodeInfosByViewTextInActiveWindow", re); 233d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return null; 2368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 2388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 2398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finds {@link AccessibilityNodeInfo}s by View text. The match is case 2408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * insensitive containment. The search is performed in the window whose 2418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * id is specified and starts from the View whose accessibility id is 2428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * specified. 2438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 244d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 2458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param text The searched text. 2468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param accessibilityWindowId A unique window id. 2478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param accessibilityViewId A unique View accessibility id from where to start the search. 2488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Use {@link android.view.View#NO_ID} to start from the root. 2498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return A list of found {@link AccessibilityNodeInfo}s. 2508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 251d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(int connectionId, 252d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov String text, int accessibilityWindowId, int accessibilityViewId) { 2538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 254d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 255d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 256d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 257d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final float windowScale = connection.findAccessibilityNodeInfosByViewText(text, 258d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov accessibilityWindowId, accessibilityViewId, interactionId, this, 259d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Thread.currentThread().getId()); 260d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov // If the scale is zero the call has failed. 261d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (windowScale > 0) { 262d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( 263d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId); 264d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov finalizeAccessibilityNodeInfos(infos, connectionId, windowScale); 265d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov return infos; 266d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 267d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 268d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 269d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 270d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2718bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2728bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 273d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 274d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote" 275d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov + " findAccessibilityNodeInfosByViewText", re); 276d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return Collections.emptyList(); 2798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 2818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 2828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Performs an accessibility action on an {@link AccessibilityNodeInfo}. 2838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 284d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 2858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param accessibilityWindowId The id of the window. 2868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param accessibilityViewId A unique View accessibility id. 2878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param action The action to perform. 2888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return Whether the action was performed. 2898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 290d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public boolean performAccessibilityAction(int connectionId, int accessibilityWindowId, 291d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov int accessibilityViewId, int action) { 2928bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 293d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 294d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 295d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 296d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final boolean success = connection.performAccessibilityAction( 297d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov accessibilityWindowId, accessibilityViewId, action, interactionId, this, 298d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Thread.currentThread().getId()); 299d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (success) { 300d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov return getPerformAccessibilityActionResult(interactionId); 301d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 302d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 303d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 304d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 305d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 3068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 308d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 309d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote performAccessibilityAction", re); 310d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 3118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return false; 3138bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3148bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 3158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 3168bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the the result of an async request that returns an {@link AccessibilityNodeInfo}. 3178bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 3188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 3198bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return The result {@link AccessibilityNodeInfo}. 3208bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 3218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private AccessibilityNodeInfo getFindAccessibilityNodeInfoResultAndClear(int interactionId) { 3228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 3238bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean success = waitForResultTimedLocked(interactionId); 3248bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov AccessibilityNodeInfo result = success ? mFindAccessibilityNodeInfoResult : null; 3258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov clearResultLocked(); 3268bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 3278bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 3308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 3318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * {@inheritDoc} 3328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 3338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setFindAccessibilityNodeInfoResult(AccessibilityNodeInfo info, 3348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov int interactionId) { 3358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 3368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (interactionId > mInteractionId) { 3378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mFindAccessibilityNodeInfoResult = info; 3388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = interactionId; 3398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.notifyAll(); 3418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 3448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 3458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the the result of an async request that returns {@link AccessibilityNodeInfo}s. 3468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 3478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 3488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return The result {@link AccessibilityNodeInfo}s. 3498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 3508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private List<AccessibilityNodeInfo> getFindAccessibilityNodeInfosResultAndClear( 3518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov int interactionId) { 3528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 3538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean success = waitForResultTimedLocked(interactionId); 3548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov List<AccessibilityNodeInfo> result = success ? mFindAccessibilityNodeInfosResult : null; 3558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov clearResultLocked(); 3568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 3578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 3608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 3618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * {@inheritDoc} 3628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 3638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setFindAccessibilityNodeInfosResult(List<AccessibilityNodeInfo> infos, 3648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov int interactionId) { 3658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 3668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (interactionId > mInteractionId) { 3678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mFindAccessibilityNodeInfosResult = infos; 3688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = interactionId; 3698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3708bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.notifyAll(); 3718bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3728bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3738bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 3748bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 3758bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the result of a request to perform an accessibility action. 3768bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 3778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 3788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return Whether the action was performed. 3798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 3808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private boolean getPerformAccessibilityActionResult(int interactionId) { 3818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 3828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean success = waitForResultTimedLocked(interactionId); 3838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean result = success ? mPerformAccessibilityActionResult : false; 3848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov clearResultLocked(); 3858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 3868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 3898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 3908bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * {@inheritDoc} 3918bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 3928bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setPerformAccessibilityActionResult(boolean succeeded, int interactionId) { 3938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 3948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (interactionId > mInteractionId) { 3958bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mPerformAccessibilityActionResult = succeeded; 3968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = interactionId; 3978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.notifyAll(); 3998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 4028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Clears the result state. 4048bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 4058bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private void clearResultLocked() { 4068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = -1; 4078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mFindAccessibilityNodeInfoResult = null; 4088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mFindAccessibilityNodeInfosResult = null; 4098bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mPerformAccessibilityActionResult = false; 4108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 4128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4138bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Waits up to a given bound for a result of a request and returns it. 4148bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 4158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 4168bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return Whether the result was received. 4178bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 4188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private boolean waitForResultTimedLocked(int interactionId) { 4198bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov long waitTimeMillis = TIMEOUT_INTERACTION_MILLIS; 4208bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final long startTimeMillis = SystemClock.uptimeMillis(); 4218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov while (true) { 4228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 4236bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov Message sameProcessMessage = getSameProcessMessageAndClear(); 4246bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov if (sameProcessMessage != null) { 4256bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov sameProcessMessage.getTarget().handleMessage(sameProcessMessage); 4266bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov } 4276bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov 4288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (mInteractionId == interactionId) { 4298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return true; 4308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (mInteractionId > interactionId) { 4328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return false; 4338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; 4358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov waitTimeMillis = TIMEOUT_INTERACTION_MILLIS - elapsedTimeMillis; 4368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (waitTimeMillis <= 0) { 4378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return false; 4388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.wait(waitTimeMillis); 4408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (InterruptedException ie) { 4418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /* ignore */ 4428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 4468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Applies compatibility scale to the info bounds if it is not equal to one. 4488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 4498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param info The info whose bounds to scale. 4508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param scale The scale to apply. 4518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 4528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private void applyCompatibilityScaleIfNeeded(AccessibilityNodeInfo info, float scale) { 4538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (scale == 1.0f) { 4548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return; 4558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov Rect bounds = mTempBounds; 4578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.getBoundsInParent(bounds); 4588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov bounds.scale(scale); 4598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.setBoundsInParent(bounds); 4608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 4618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.getBoundsInScreen(bounds); 4628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov bounds.scale(scale); 4638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.setBoundsInScreen(bounds); 4648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 4668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finalize an {@link AccessibilityNodeInfo} before passing it to the client. 4688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 4698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param info The info. 470d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of the connection to the system. 4718bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param windowScale The source window compatibility scale. 4728bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 473d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov private void finalizeAccessibilityNodeInfo(AccessibilityNodeInfo info, int connectionId, 474d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov float windowScale) { 4758bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (info != null) { 4768bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov applyCompatibilityScaleIfNeeded(info, windowScale); 477d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov info.setConnectionId(connectionId); 4788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.setSealed(true); 4798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 4828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finalize {@link AccessibilityNodeInfo}s before passing them to the client. 4848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 4858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param infos The {@link AccessibilityNodeInfo}s. 486d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of the connection to the system. 4878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param windowScale The source window compatibility scale. 4888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 4898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private void finalizeAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos, 490d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov int connectionId, float windowScale) { 4918bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (infos != null) { 4928bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final int infosCount = infos.size(); 4938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov for (int i = 0; i < infosCount; i++) { 4948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov AccessibilityNodeInfo info = infos.get(i); 495d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov finalizeAccessibilityNodeInfo(info, connectionId, windowScale); 4968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the message stored if the interacted and interacting 5028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * threads are the same. 5038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 5048bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return The message. 5058bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 5068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private Message getSameProcessMessageAndClear() { 5078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 5088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov Message result = mSameThreadMessage; 5098bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mSameThreadMessage = null; 5108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 5118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 513d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 514d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov /** 515d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * Gets a cached accessibility service connection. 516d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * 517d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The connection id. 518d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @return The cached connection if such. 519d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov */ 520d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public IAccessibilityServiceConnection getConnection(int connectionId) { 52136bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov synchronized (sConnectionCache) { 52236bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov return sConnectionCache.get(connectionId); 523d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 524d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 525d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 526d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov /** 527d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * Adds a cached accessibility service connection. 528d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * 529d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The connection id. 530d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connection The connection. 531d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov */ 532d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public void addConnection(int connectionId, IAccessibilityServiceConnection connection) { 53336bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov synchronized (sConnectionCache) { 53436bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov sConnectionCache.put(connectionId, connection); 535d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 536d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 537d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 538d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov /** 539d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * Removes a cached accessibility service connection. 540d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * 541d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The connection id. 542d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov */ 543d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public void removeConnection(int connectionId) { 54436bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov synchronized (sConnectionCache) { 54536bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov sConnectionCache.remove(connectionId); 546d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 547d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 5488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov} 549