AccessibilityInteractionClient.java revision 4213804541a8b05cd0587b138a2fd9a3b7fd9350
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 198b5a814f6a36045b06bee36f44703503c03714d4Svetoslav Ganovimport android.accessibilityservice.IAccessibilityServiceConnection; 208bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport android.graphics.Rect; 214213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganovimport android.os.Binder; 228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport android.os.Message; 234213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganovimport android.os.Process; 248bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport android.os.RemoteException; 258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport android.os.SystemClock; 26d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganovimport android.util.Log; 278b5a814f6a36045b06bee36f44703503c03714d4Svetoslav Ganovimport android.util.LongSparseArray; 28d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganovimport android.util.SparseArray; 298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 3079311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganovimport java.util.ArrayList; 318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport java.util.Collections; 328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport java.util.List; 338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport java.util.concurrent.atomic.AtomicInteger; 348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov/** 368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * This class is a singleton that performs accessibility interaction 378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * which is it queries remote view hierarchies about snapshots of their 388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * views as well requests from these hierarchies to perform certain 398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * actions on their views. 408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Rationale: The content retrieval APIs are synchronous from a client's 428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * perspective but internally they are asynchronous. The client thread 438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * calls into the system requesting an action and providing a callback 448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * to receive the result after which it waits up to a timeout for that 458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * result. The system enforces security and the delegates the request 468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * to a given view hierarchy where a message is posted (from a binder 478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * thread) describing what to be performed by the main UI thread the 488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * result of which it delivered via the mentioned callback. However, 498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * the blocked client thread and the main UI thread of the target view 508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * hierarchy can be the same thread, for example an accessibility service 518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * and an activity run in the same process, thus they are executed on the 528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * same main thread. In such a case the retrieval will fail since the UI 538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * thread that has to process the message describing the work to be done 548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * is blocked waiting for a result is has to compute! To avoid this scenario 558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * when making a call the client also passes its process and thread ids so 568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * the accessed view hierarchy can detect if the client making the request 578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * is running in its main UI thread. In such a case the view hierarchy, 588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * specifically the binder thread performing the IPC to it, does not post a 598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * message to be run on the UI thread but passes it to the singleton 608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * interaction client through which all interactions occur and the latter is 618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * responsible to execute the message before starting to wait for the 628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * asynchronous result delivered via the callback. In this case the expected 638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * result is already received so no waiting is performed. 648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @hide 668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovpublic final class AccessibilityInteractionClient 688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov extends IAccessibilityInteractionConnectionCallback.Stub { 698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 70d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public static final int NO_ID = -1; 71d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 72d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov private static final String LOG_TAG = "AccessibilityInteractionClient"; 73d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 74d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov private static final boolean DEBUG = false; 75d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 768bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private static final long TIMEOUT_INTERACTION_MILLIS = 5000; 778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private static final Object sStaticLock = new Object(); 798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 80021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov private static final LongSparseArray<AccessibilityInteractionClient> sClients = 81021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov new LongSparseArray<AccessibilityInteractionClient>(); 828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private final AtomicInteger mInteractionIdCounter = new AtomicInteger(); 848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private final Object mInstanceLock = new Object(); 868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private int mInteractionId = -1; 888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private AccessibilityNodeInfo mFindAccessibilityNodeInfoResult; 908bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 918bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private List<AccessibilityNodeInfo> mFindAccessibilityNodeInfosResult; 928bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private boolean mPerformAccessibilityActionResult; 948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 958bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private Message mSameThreadMessage; 968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private final Rect mTempBounds = new Rect(); 988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 9936bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov // The connection cache is shared between all interrogating threads. 10036bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache = 101d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov new SparseArray<IAccessibilityServiceConnection>(); 102d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 10379311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov // The connection cache is shared between all interrogating threads since 10479311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov // at any given time there is only one window allowing querying. 10579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov private static final AccessibilityNodeInfoCache sAccessibilityNodeInfoCache = 10657c7fd5a43237afc5e8ef31a076e862c0c16c328Svetoslav Ganov new AccessibilityNodeInfoCache(); 10779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov 1088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 109021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov * @return The client for the current thread. 1108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 1118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public static AccessibilityInteractionClient getInstance() { 112021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov final long threadId = Thread.currentThread().getId(); 113021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov return getInstanceForThread(threadId); 114021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov } 115021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov 116021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov /** 117021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov * <strong>Note:</strong> We keep one instance per interrogating thread since 118021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov * the instance contains state which can lead to undesired thread interleavings. 119021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov * We do not have a thread local variable since other threads should be able to 120021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov * look up the correct client knowing a thread id. See ViewRootImpl for details. 121021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov * 122021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov * @return The client for a given <code>threadId</code>. 123021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov */ 124021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov public static AccessibilityInteractionClient getInstanceForThread(long threadId) { 1258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (sStaticLock) { 126021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov AccessibilityInteractionClient client = sClients.get(threadId); 127021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov if (client == null) { 128021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov client = new AccessibilityInteractionClient(); 129021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov sClients.put(threadId, client); 1308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 131021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov return client; 1328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 135021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov private AccessibilityInteractionClient() { 136021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov /* reducing constructor visibility */ 137021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov } 138021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov 1398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 1408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Sets the message to be processed if the interacted view hierarchy 1418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * and the interacting client are running in the same thread. 1428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 1438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param message The message. 1448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 1458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setSameThreadMessage(Message message) { 1468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 1478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mSameThreadMessage = message; 1486bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov mInstanceLock.notifyAll(); 1498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 1528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 1538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finds an {@link AccessibilityNodeInfo} by accessibility id. 1548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 155d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 15679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 1570d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 15879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to query the currently active window. 1590d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 1600d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * where to start the search. Use 1610d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 1620d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * to start from the root. 16357c7fd5a43237afc5e8ef31a076e862c0c16c328Svetoslav Ganov * @param prefetchFlags flags to guide prefetching. 1648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return An {@link AccessibilityNodeInfo} if found, null otherwise. 1658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 166d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(int connectionId, 16757c7fd5a43237afc5e8ef31a076e862c0c16c328Svetoslav Ganov int accessibilityWindowId, long accessibilityNodeId, int prefetchFlags) { 1688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 169d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 170d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 1710d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov AccessibilityNodeInfo cachedInfo = sAccessibilityNodeInfoCache.get( 1720d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov accessibilityNodeId); 17379311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov if (cachedInfo != null) { 17479311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov return cachedInfo; 17579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 176d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 177d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId( 178f3b4f3163b5b4c0a54a2643f07c97c47b14a1eb7Svetoslav Ganov accessibilityWindowId, accessibilityNodeId, interactionId, this, 1794213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov prefetchFlags, Thread.currentThread().getId()); 180d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov // If the scale is zero the call has failed. 181d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (windowScale > 0) { 18279311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( 183d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId); 1840d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, windowScale); 18579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov if (infos != null && !infos.isEmpty()) { 18679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov return infos.get(0); 18779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 188d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 189d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 190d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 191d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 192d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 1938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 195d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 196d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote" 197d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov + " findAccessibilityNodeInfoByAccessibilityId", re); 198d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 1998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return null; 2018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 2038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 20479311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in 20579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * the window whose id is specified and starts from the node whose accessibility 20679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * id is specified. 2078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 208d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 20979311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 2100d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 21179311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to query the currently active window. 2120d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 2130d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * where to start the search. Use 2140d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 21579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to start from the root. 2166bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov * @param viewId The id of the view. 2178bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return An {@link AccessibilityNodeInfo} if found, null otherwise. 2188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 21979311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int connectionId, 22079311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov int accessibilityWindowId, long accessibilityNodeId, int viewId) { 2218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 222d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 223d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 224d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 225d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final float windowScale = 22679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov connection.findAccessibilityNodeInfoByViewId(accessibilityWindowId, 22779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov accessibilityNodeId, viewId, interactionId, this, 22879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov Thread.currentThread().getId()); 229d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov // If the scale is zero the call has failed. 230d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (windowScale > 0) { 231d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( 232d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId); 2330d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); 234d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov return info; 235d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 236d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 237d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 238d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 239d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 242d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 243d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote" 244d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov + " findAccessibilityNodeInfoByViewIdInActiveWindow", re); 245d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return null; 2488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 2508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 2518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finds {@link AccessibilityNodeInfo}s by View text. The match is case 2528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * insensitive containment. The search is performed in the window whose 25379311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * id is specified and starts from the node whose accessibility id is 2548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * specified. 2558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 256d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 25779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 2580d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 25979311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to query the currently active window. 2600d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 2610d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * where to start the search. Use 2620d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 2630d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * to start from the root. 2648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param text The searched text. 2658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return A list of found {@link AccessibilityNodeInfo}s. 2668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 26766922db828eab153c15bf3ca0b007313d9376e5eSvetoslav Ganov public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(int connectionId, 26879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov int accessibilityWindowId, long accessibilityNodeId, String text) { 2698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 270d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 271d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 272d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 27379311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov final float windowScale = connection.findAccessibilityNodeInfosByText( 27479311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov accessibilityWindowId, accessibilityNodeId, text, interactionId, this, 275d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Thread.currentThread().getId()); 276d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov // If the scale is zero the call has failed. 277d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (windowScale > 0) { 278d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( 279d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId); 2800d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, windowScale); 281d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov return infos; 282d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 283d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 284d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 285d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 286d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 289d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 290d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote" 291d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov + " findAccessibilityNodeInfosByViewText", re); 292d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return Collections.emptyList(); 2958bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 2978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 2984213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * Finds the {@link android.view.accessibility.AccessibilityNodeInfo} that has the 2994213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * specified focus type. The search is performed in the window whose id is specified 3004213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * and starts from the node whose accessibility id is specified. 3014213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * 3024213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 3034213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 3044213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 3054213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * to query the currently active window. 3064213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 3074213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * where to start the search. Use 3084213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 3094213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * to start from the root. 3104213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param focusType The focus type. 3114213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @return The accessibility focused {@link AccessibilityNodeInfo}. 3124213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov */ 3134213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov public AccessibilityNodeInfo findFocus(int connectionId, int accessibilityWindowId, 3144213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov long accessibilityNodeId, int focusType) { 3154213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov try { 3164213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 3174213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (connection != null) { 3184213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 3194213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final float windowScale = connection.findFocus(accessibilityWindowId, 3204213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov accessibilityNodeId, focusType, interactionId, this, 3214213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Thread.currentThread().getId()); 3224213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // If the scale is zero the call has failed. 3234213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (windowScale > 0) { 3244213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( 3254213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov interactionId); 3264213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); 3274213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov return info; 3284213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3294213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } else { 3304213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (DEBUG) { 3314213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 3324213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3334213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3344213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } catch (RemoteException re) { 3354213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (DEBUG) { 3364213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote findAccessibilityFocus", re); 3374213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3384213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3394213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov return null; 3404213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3414213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov 3424213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov /** 3434213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * Finds the accessibility focused {@link android.view.accessibility.AccessibilityNodeInfo}. 3444213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * The search is performed in the window whose id is specified and starts from the 3454213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * node whose accessibility id is specified. 3464213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * 3474213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 3484213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 3494213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 3504213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * to query the currently active window. 3514213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 3524213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * where to start the search. Use 3534213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 3544213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * to start from the root. 3554213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param direction The direction in which to search for focusable. 3564213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @return The accessibility focused {@link AccessibilityNodeInfo}. 3574213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov */ 3584213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov public AccessibilityNodeInfo focusSearch(int connectionId, int accessibilityWindowId, 3594213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov long accessibilityNodeId, int direction) { 3604213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov try { 3614213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 3624213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (connection != null) { 3634213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 3644213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final float windowScale = connection.focusSearch(accessibilityWindowId, 3654213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov accessibilityNodeId, direction, interactionId, this, 3664213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Thread.currentThread().getId()); 3674213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // If the scale is zero the call has failed. 3684213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (windowScale > 0) { 3694213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( 3704213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov interactionId); 3714213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); 3724213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov return info; 3734213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3744213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } else { 3754213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (DEBUG) { 3764213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 3774213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3784213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3794213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } catch (RemoteException re) { 3804213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (DEBUG) { 3814213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote accessibilityFocusSearch", re); 3824213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3834213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3844213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov return null; 3854213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3864213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov 3874213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov /** 3888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Performs an accessibility action on an {@link AccessibilityNodeInfo}. 3898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 390d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 39179311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 3920d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 39379311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to query the currently active window. 3940d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 3950d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * where to start the search. Use 3960d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 3970d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * to start from the root. 3988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param action The action to perform. 3998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return Whether the action was performed. 4008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 401d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public boolean performAccessibilityAction(int connectionId, int accessibilityWindowId, 40266922db828eab153c15bf3ca0b007313d9376e5eSvetoslav Ganov long accessibilityNodeId, int action) { 4038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 404d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 405d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 406d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 407d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final boolean success = connection.performAccessibilityAction( 408f3b4f3163b5b4c0a54a2643f07c97c47b14a1eb7Svetoslav Ganov accessibilityWindowId, accessibilityNodeId, action, interactionId, this, 409d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Thread.currentThread().getId()); 410d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (success) { 41179311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov return getPerformAccessibilityActionResultAndClear(interactionId); 412d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 413d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 414d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 415d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 416d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 4178bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 419d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 420d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote performAccessibilityAction", re); 421d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 4228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4238bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return false; 4248bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 42679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov public void clearCache() { 42779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov sAccessibilityNodeInfoCache.clear(); 42879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 42979311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov 43079311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov public void removeCachedNode(long accessibilityNodeId) { 43179311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov sAccessibilityNodeInfoCache.remove(accessibilityNodeId); 43279311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 43379311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov 43479311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov public void onAccessibilityEvent(AccessibilityEvent event) { 43579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov sAccessibilityNodeInfoCache.onAccessibilityEvent(event); 43679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 43779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov 4388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the the result of an async request that returns an {@link AccessibilityNodeInfo}. 4408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 4418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 4428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return The result {@link AccessibilityNodeInfo}. 4438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 4448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private AccessibilityNodeInfo getFindAccessibilityNodeInfoResultAndClear(int interactionId) { 4458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 4468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean success = waitForResultTimedLocked(interactionId); 4478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov AccessibilityNodeInfo result = success ? mFindAccessibilityNodeInfoResult : null; 4488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov clearResultLocked(); 4498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 4508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 4538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * {@inheritDoc} 4558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 4568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setFindAccessibilityNodeInfoResult(AccessibilityNodeInfo info, 4578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov int interactionId) { 4588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 4598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (interactionId > mInteractionId) { 4608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mFindAccessibilityNodeInfoResult = info; 4618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = interactionId; 4628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.notifyAll(); 4648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 4678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the the result of an async request that returns {@link AccessibilityNodeInfo}s. 4698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 4708bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 4718bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return The result {@link AccessibilityNodeInfo}s. 4728bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 4738bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private List<AccessibilityNodeInfo> getFindAccessibilityNodeInfosResultAndClear( 4748bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov int interactionId) { 4758bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 4768bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean success = waitForResultTimedLocked(interactionId); 4774213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov List<AccessibilityNodeInfo> result = null; 4784213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (success) { 4794213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov result = mFindAccessibilityNodeInfosResult; 4804213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } else { 4814213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov result = Collections.emptyList(); 4824213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 4838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov clearResultLocked(); 4848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 4858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 4888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * {@inheritDoc} 4908bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 4918bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setFindAccessibilityNodeInfosResult(List<AccessibilityNodeInfo> infos, 4928bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov int interactionId) { 4938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 4948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (interactionId > mInteractionId) { 4954213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (infos != null) { 4964213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // If the call is not an IPC, i.e. it is made from the same process, we need to 4974213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // instantiate new result list to avoid passing internal instances to clients. 4984213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final boolean isIpcCall = (Binder.getCallingPid() != Process.myPid()); 4994213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (!isIpcCall) { 5004213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov mFindAccessibilityNodeInfosResult = 5014213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov new ArrayList<AccessibilityNodeInfo>(infos); 5024213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } else { 5034213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov mFindAccessibilityNodeInfosResult = infos; 5044213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 50579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } else { 5064213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov mFindAccessibilityNodeInfosResult = Collections.emptyList(); 50779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 5088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = interactionId; 5098bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.notifyAll(); 5118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5138bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5148bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the result of a request to perform an accessibility action. 5168bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 5178bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 5188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return Whether the action was performed. 5198bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 52079311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov private boolean getPerformAccessibilityActionResultAndClear(int interactionId) { 5218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 5228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean success = waitForResultTimedLocked(interactionId); 5238bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean result = success ? mPerformAccessibilityActionResult : false; 5248bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov clearResultLocked(); 5258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 5268bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5278bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * {@inheritDoc} 5318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 5328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setPerformAccessibilityActionResult(boolean succeeded, int interactionId) { 5338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 5348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (interactionId > mInteractionId) { 5358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mPerformAccessibilityActionResult = succeeded; 5368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = interactionId; 5378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.notifyAll(); 5398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Clears the result state. 5448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 5458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private void clearResultLocked() { 5468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = -1; 5478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mFindAccessibilityNodeInfoResult = null; 5488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mFindAccessibilityNodeInfosResult = null; 5498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mPerformAccessibilityActionResult = false; 5508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Waits up to a given bound for a result of a request and returns it. 5548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 5558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 5568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return Whether the result was received. 5578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 5588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private boolean waitForResultTimedLocked(int interactionId) { 5598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov long waitTimeMillis = TIMEOUT_INTERACTION_MILLIS; 5608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final long startTimeMillis = SystemClock.uptimeMillis(); 5618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov while (true) { 5628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 5636bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov Message sameProcessMessage = getSameProcessMessageAndClear(); 5646bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov if (sameProcessMessage != null) { 5656bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov sameProcessMessage.getTarget().handleMessage(sameProcessMessage); 5666bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov } 5676bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov 5688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (mInteractionId == interactionId) { 5698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return true; 5708bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5718bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (mInteractionId > interactionId) { 5728bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return false; 5738bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5748bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; 5758bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov waitTimeMillis = TIMEOUT_INTERACTION_MILLIS - elapsedTimeMillis; 5768bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (waitTimeMillis <= 0) { 5778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return false; 5788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.wait(waitTimeMillis); 5808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (InterruptedException ie) { 5818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /* ignore */ 5828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Applies compatibility scale to the info bounds if it is not equal to one. 5888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 5898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param info The info whose bounds to scale. 5908bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param scale The scale to apply. 5918bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 5928bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private void applyCompatibilityScaleIfNeeded(AccessibilityNodeInfo info, float scale) { 5938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (scale == 1.0f) { 5948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return; 5958bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov Rect bounds = mTempBounds; 5978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.getBoundsInParent(bounds); 5988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov bounds.scale(scale); 5998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.setBoundsInParent(bounds); 6008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 6018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.getBoundsInScreen(bounds); 6028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov bounds.scale(scale); 6038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.setBoundsInScreen(bounds); 6048bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6058bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 6068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 6078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finalize an {@link AccessibilityNodeInfo} before passing it to the client. 6088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 6098bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param info The info. 610d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of the connection to the system. 6118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param windowScale The source window compatibility scale. 6128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 6130d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov private void finalizeAndCacheAccessibilityNodeInfo(AccessibilityNodeInfo info, int connectionId, 614d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov float windowScale) { 6158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (info != null) { 6168bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov applyCompatibilityScaleIfNeeded(info, windowScale); 617d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov info.setConnectionId(connectionId); 6188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.setSealed(true); 6190d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov sAccessibilityNodeInfoCache.put(info.getSourceNodeId(), info); 6208bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 6238bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 6248bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finalize {@link AccessibilityNodeInfo}s before passing them to the client. 6258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 6268bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param infos The {@link AccessibilityNodeInfo}s. 627d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of the connection to the system. 6288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param windowScale The source window compatibility scale. 6298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 6300d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov private void finalizeAndCacheAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos, 631d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov int connectionId, float windowScale) { 6328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (infos != null) { 6338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final int infosCount = infos.size(); 6348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov for (int i = 0; i < infosCount; i++) { 6358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov AccessibilityNodeInfo info = infos.get(i); 6360d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); 6378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 6418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 6428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the message stored if the interacted and interacting 6438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * threads are the same. 6448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 6458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return The message. 6468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 6478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private Message getSameProcessMessageAndClear() { 6488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 6498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov Message result = mSameThreadMessage; 6508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mSameThreadMessage = null; 6518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 6528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 654d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 655d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov /** 656d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * Gets a cached accessibility service connection. 657d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * 658d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The connection id. 659d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @return The cached connection if such. 660d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov */ 661d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public IAccessibilityServiceConnection getConnection(int connectionId) { 66236bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov synchronized (sConnectionCache) { 66336bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov return sConnectionCache.get(connectionId); 664d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 665d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 666d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 667d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov /** 668d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * Adds a cached accessibility service connection. 669d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * 670d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The connection id. 671d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connection The connection. 672d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov */ 673d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public void addConnection(int connectionId, IAccessibilityServiceConnection connection) { 67436bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov synchronized (sConnectionCache) { 67536bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov sConnectionCache.put(connectionId, connection); 676d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 677d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 678d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 679d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov /** 680d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * Removes a cached accessibility service connection. 681d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * 682d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The connection id. 683d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov */ 684d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public void removeConnection(int connectionId) { 68536bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov synchronized (sConnectionCache) { 68636bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov sConnectionCache.remove(connectionId); 687d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 688d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 6898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov} 690