AccessibilityInteractionClient.java revision fefd20e927b7252d63acb7bb1852c5188e3c1b2e
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 87fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov private volatile 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 /** 153fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov * Gets the root {@link AccessibilityNodeInfo} in the currently active window. 154fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov * 155fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 156fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov * @return The root {@link AccessibilityNodeInfo} if found, null otherwise. 157fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov */ 158fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov public AccessibilityNodeInfo getRootInActiveWindow(int connectionId) { 159fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov return findAccessibilityNodeInfoByAccessibilityId(connectionId, 160fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov AccessibilityNodeInfo.ACTIVE_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, 161fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS); 162fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov } 163fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov 164fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov /** 1658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finds an {@link AccessibilityNodeInfo} by accessibility id. 1668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 167d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 16879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 1690d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 17079311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to query the currently active window. 1710d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 1720d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * where to start the search. Use 1730d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 1740d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * to start from the root. 17557c7fd5a43237afc5e8ef31a076e862c0c16c328Svetoslav Ganov * @param prefetchFlags flags to guide prefetching. 1768bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return An {@link AccessibilityNodeInfo} if found, null otherwise. 1778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 178d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(int connectionId, 17957c7fd5a43237afc5e8ef31a076e862c0c16c328Svetoslav Ganov int accessibilityWindowId, long accessibilityNodeId, int prefetchFlags) { 1808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 181d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 182d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 1830d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov AccessibilityNodeInfo cachedInfo = sAccessibilityNodeInfoCache.get( 1840d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov accessibilityNodeId); 18579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov if (cachedInfo != null) { 18679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov return cachedInfo; 18779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 188d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 189d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId( 190f3b4f3163b5b4c0a54a2643f07c97c47b14a1eb7Svetoslav Ganov accessibilityWindowId, accessibilityNodeId, interactionId, this, 1914213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov prefetchFlags, Thread.currentThread().getId()); 192d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov // If the scale is zero the call has failed. 193d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (windowScale > 0) { 19479311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( 195d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId); 1960d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, windowScale); 19779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov if (infos != null && !infos.isEmpty()) { 19879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov return infos.get(0); 19979311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 200d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 201d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 202d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 203d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 204d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2058bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 207d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 208d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote" 209d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov + " findAccessibilityNodeInfoByAccessibilityId", re); 210d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return null; 2138bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2148bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 2158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 21679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in 21779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * the window whose id is specified and starts from the node whose accessibility 21879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * id is specified. 2198bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 220d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 22179311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 2220d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 22379311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to query the currently active window. 2240d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 2250d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * where to start the search. Use 2260d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 22779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to start from the root. 2286bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov * @param viewId The id of the view. 2298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return An {@link AccessibilityNodeInfo} if found, null otherwise. 2308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 23179311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int connectionId, 23279311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov int accessibilityWindowId, long accessibilityNodeId, int viewId) { 2338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 234d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 235d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 236d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 237d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final float windowScale = 23879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov connection.findAccessibilityNodeInfoByViewId(accessibilityWindowId, 23979311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov accessibilityNodeId, viewId, interactionId, this, 24079311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov Thread.currentThread().getId()); 241d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov // If the scale is zero the call has failed. 242d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (windowScale > 0) { 243d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( 244d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId); 2450d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); 246d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov return info; 247d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 248d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 249d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 250d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 251d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 254d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 255d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote" 256d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov + " findAccessibilityNodeInfoByViewIdInActiveWindow", re); 257d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return null; 2608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 2628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 2638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finds {@link AccessibilityNodeInfo}s by View text. The match is case 2648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * insensitive containment. The search is performed in the window whose 26579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * id is specified and starts from the node whose accessibility id is 2668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * specified. 2678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 268d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 26979311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 2700d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 27179311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to query the currently active window. 2720d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 2730d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * where to start the search. Use 2740d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 2750d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * to start from the root. 2768bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param text The searched text. 2778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return A list of found {@link AccessibilityNodeInfo}s. 2788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 27966922db828eab153c15bf3ca0b007313d9376e5eSvetoslav Ganov public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(int connectionId, 28079311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov int accessibilityWindowId, long accessibilityNodeId, String text) { 2818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 282d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 283d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 284d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 28579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov final float windowScale = connection.findAccessibilityNodeInfosByText( 28679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov accessibilityWindowId, accessibilityNodeId, text, interactionId, this, 287d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Thread.currentThread().getId()); 288d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov // If the scale is zero the call has failed. 289d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (windowScale > 0) { 290d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( 291d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId); 2920d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, windowScale); 293d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov return infos; 294d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 295d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 296d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 297d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 298d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 301d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 302d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote" 303d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov + " findAccessibilityNodeInfosByViewText", re); 304d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 3058bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return Collections.emptyList(); 3078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 3098bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 3104213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * Finds the {@link android.view.accessibility.AccessibilityNodeInfo} that has the 3114213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * specified focus type. The search is performed in the window whose id is specified 3124213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * and starts from the node whose accessibility id is specified. 3134213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * 3144213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 3154213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 3164213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 3174213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * to query the currently active window. 3184213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 3194213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * where to start the search. Use 3204213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 3214213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * to start from the root. 3224213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param focusType The focus type. 3234213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @return The accessibility focused {@link AccessibilityNodeInfo}. 3244213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov */ 3254213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov public AccessibilityNodeInfo findFocus(int connectionId, int accessibilityWindowId, 3264213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov long accessibilityNodeId, int focusType) { 3274213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov try { 3284213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 3294213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (connection != null) { 3304213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 3314213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final float windowScale = connection.findFocus(accessibilityWindowId, 3324213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov accessibilityNodeId, focusType, interactionId, this, 3334213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Thread.currentThread().getId()); 3344213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // If the scale is zero the call has failed. 3354213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (windowScale > 0) { 3364213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( 3374213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov interactionId); 3384213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); 3394213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov return info; 3404213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3414213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } else { 3424213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (DEBUG) { 3434213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 3444213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3454213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3464213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } catch (RemoteException re) { 3474213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (DEBUG) { 3484213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote findAccessibilityFocus", re); 3494213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3504213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3514213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov return null; 3524213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3534213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov 3544213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov /** 3554213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * Finds the accessibility focused {@link android.view.accessibility.AccessibilityNodeInfo}. 3564213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * The search is performed in the window whose id is specified and starts from the 3574213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * node whose accessibility id is specified. 3584213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * 3594213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 3604213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 3614213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 3624213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * to query the currently active window. 3634213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 3644213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * where to start the search. Use 3654213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 3664213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * to start from the root. 3674213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param direction The direction in which to search for focusable. 3684213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @return The accessibility focused {@link AccessibilityNodeInfo}. 3694213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov */ 3704213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov public AccessibilityNodeInfo focusSearch(int connectionId, int accessibilityWindowId, 3714213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov long accessibilityNodeId, int direction) { 3724213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov try { 3734213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 3744213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (connection != null) { 3754213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 3764213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final float windowScale = connection.focusSearch(accessibilityWindowId, 3774213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov accessibilityNodeId, direction, interactionId, this, 3784213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Thread.currentThread().getId()); 3794213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // If the scale is zero the call has failed. 3804213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (windowScale > 0) { 3814213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( 3824213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov interactionId); 3834213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); 3844213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov return info; 3854213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3864213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } else { 3874213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (DEBUG) { 3884213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 3894213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3904213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3914213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } catch (RemoteException re) { 3924213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (DEBUG) { 3934213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote accessibilityFocusSearch", re); 3944213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3954213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3964213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov return null; 3974213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3984213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov 3994213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov /** 4008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Performs an accessibility action on an {@link AccessibilityNodeInfo}. 4018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 402d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 40379311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 4040d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 40579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to query the currently active window. 4060d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 4070d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * where to start the search. Use 4080d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 4090d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * to start from the root. 4108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param action The action to perform. 4118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return Whether the action was performed. 4128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 413d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public boolean performAccessibilityAction(int connectionId, int accessibilityWindowId, 41466922db828eab153c15bf3ca0b007313d9376e5eSvetoslav Ganov long accessibilityNodeId, int action) { 4158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 416d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 417d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 418d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 419d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final boolean success = connection.performAccessibilityAction( 420f3b4f3163b5b4c0a54a2643f07c97c47b14a1eb7Svetoslav Ganov accessibilityWindowId, accessibilityNodeId, action, interactionId, this, 421d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Thread.currentThread().getId()); 422d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (success) { 42379311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov return getPerformAccessibilityActionResultAndClear(interactionId); 424d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 425d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 426d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 427d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 428d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 4298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 431d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 432d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote performAccessibilityAction", re); 433d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 4348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return false; 4368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 43879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov public void clearCache() { 43979311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov sAccessibilityNodeInfoCache.clear(); 44079311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 44179311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov 44279311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov public void removeCachedNode(long accessibilityNodeId) { 44379311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov sAccessibilityNodeInfoCache.remove(accessibilityNodeId); 44479311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 44579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov 44679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov public void onAccessibilityEvent(AccessibilityEvent event) { 44779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov sAccessibilityNodeInfoCache.onAccessibilityEvent(event); 44879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 44979311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov 4508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the the result of an async request that returns an {@link AccessibilityNodeInfo}. 4528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 4538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 4548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return The result {@link AccessibilityNodeInfo}. 4558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 4568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private AccessibilityNodeInfo getFindAccessibilityNodeInfoResultAndClear(int interactionId) { 4578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 4588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean success = waitForResultTimedLocked(interactionId); 4598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov AccessibilityNodeInfo result = success ? mFindAccessibilityNodeInfoResult : null; 4608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov clearResultLocked(); 4618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 4628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 4658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * {@inheritDoc} 4678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 4688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setFindAccessibilityNodeInfoResult(AccessibilityNodeInfo info, 4698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov int interactionId) { 4708bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 4718bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (interactionId > mInteractionId) { 4728bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mFindAccessibilityNodeInfoResult = info; 4738bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = interactionId; 4748bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4758bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.notifyAll(); 4768bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 4798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the the result of an async request that returns {@link AccessibilityNodeInfo}s. 4818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 4828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 4838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return The result {@link AccessibilityNodeInfo}s. 4848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 4858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private List<AccessibilityNodeInfo> getFindAccessibilityNodeInfosResultAndClear( 4868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov int interactionId) { 4878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 4888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean success = waitForResultTimedLocked(interactionId); 4894213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov List<AccessibilityNodeInfo> result = null; 4904213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (success) { 4914213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov result = mFindAccessibilityNodeInfosResult; 4924213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } else { 4934213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov result = Collections.emptyList(); 4944213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 4958bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov clearResultLocked(); 4968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 4978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * {@inheritDoc} 5028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 5038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setFindAccessibilityNodeInfosResult(List<AccessibilityNodeInfo> infos, 5048bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov int interactionId) { 5058bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 5068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (interactionId > mInteractionId) { 5074213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (infos != null) { 5084213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // If the call is not an IPC, i.e. it is made from the same process, we need to 5094213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // instantiate new result list to avoid passing internal instances to clients. 5104213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final boolean isIpcCall = (Binder.getCallingPid() != Process.myPid()); 5114213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (!isIpcCall) { 5124213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov mFindAccessibilityNodeInfosResult = 5134213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov new ArrayList<AccessibilityNodeInfo>(infos); 5144213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } else { 5154213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov mFindAccessibilityNodeInfosResult = infos; 5164213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 51779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } else { 5184213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov mFindAccessibilityNodeInfosResult = Collections.emptyList(); 51979311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 5208bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = interactionId; 5218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.notifyAll(); 5238bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5248bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5268bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5278bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the result of a request to perform an accessibility action. 5288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 5298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 5308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return Whether the action was performed. 5318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 53279311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov private boolean getPerformAccessibilityActionResultAndClear(int interactionId) { 5338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 5348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean success = waitForResultTimedLocked(interactionId); 5358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean result = success ? mPerformAccessibilityActionResult : false; 5368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov clearResultLocked(); 5378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 5388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * {@inheritDoc} 5438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 5448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setPerformAccessibilityActionResult(boolean succeeded, int interactionId) { 5458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 5468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (interactionId > mInteractionId) { 5478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mPerformAccessibilityActionResult = succeeded; 5488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = interactionId; 5498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.notifyAll(); 5518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Clears the result state. 5568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 5578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private void clearResultLocked() { 5588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = -1; 5598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mFindAccessibilityNodeInfoResult = null; 5608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mFindAccessibilityNodeInfosResult = null; 5618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mPerformAccessibilityActionResult = false; 5628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Waits up to a given bound for a result of a request and returns it. 5668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 5678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 5688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return Whether the result was received. 5698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 5708bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private boolean waitForResultTimedLocked(int interactionId) { 5718bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov long waitTimeMillis = TIMEOUT_INTERACTION_MILLIS; 5728bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final long startTimeMillis = SystemClock.uptimeMillis(); 5738bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov while (true) { 5748bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 5756bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov Message sameProcessMessage = getSameProcessMessageAndClear(); 5766bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov if (sameProcessMessage != null) { 5776bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov sameProcessMessage.getTarget().handleMessage(sameProcessMessage); 5786bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov } 5796bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov 5808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (mInteractionId == interactionId) { 5818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return true; 5828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (mInteractionId > interactionId) { 5848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return false; 5858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; 5878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov waitTimeMillis = TIMEOUT_INTERACTION_MILLIS - elapsedTimeMillis; 5888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (waitTimeMillis <= 0) { 5898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return false; 5908bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5918bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.wait(waitTimeMillis); 5928bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (InterruptedException ie) { 5938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /* ignore */ 5948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5958bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Applies compatibility scale to the info bounds if it is not equal to one. 6008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 6018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param info The info whose bounds to scale. 6028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param scale The scale to apply. 6038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 6048bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private void applyCompatibilityScaleIfNeeded(AccessibilityNodeInfo info, float scale) { 6058bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (scale == 1.0f) { 6068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return; 6078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov Rect bounds = mTempBounds; 6098bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.getBoundsInParent(bounds); 6108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov bounds.scale(scale); 6118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.setBoundsInParent(bounds); 6128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 6138bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.getBoundsInScreen(bounds); 6148bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov bounds.scale(scale); 6158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.setBoundsInScreen(bounds); 6168bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6178bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 6188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 6198bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finalize an {@link AccessibilityNodeInfo} before passing it to the client. 6208bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 6218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param info The info. 622d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of the connection to the system. 6238bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param windowScale The source window compatibility scale. 6248bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 6250d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov private void finalizeAndCacheAccessibilityNodeInfo(AccessibilityNodeInfo info, int connectionId, 626d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov float windowScale) { 6278bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (info != null) { 6288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov applyCompatibilityScaleIfNeeded(info, windowScale); 629d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov info.setConnectionId(connectionId); 6308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.setSealed(true); 6310d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov sAccessibilityNodeInfoCache.put(info.getSourceNodeId(), info); 6328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 6358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 6368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finalize {@link AccessibilityNodeInfo}s before passing them to the client. 6378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 6388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param infos The {@link AccessibilityNodeInfo}s. 639d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of the connection to the system. 6408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param windowScale The source window compatibility scale. 6418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 6420d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov private void finalizeAndCacheAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos, 643d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov int connectionId, float windowScale) { 6448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (infos != null) { 6458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final int infosCount = infos.size(); 6468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov for (int i = 0; i < infosCount; i++) { 6478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov AccessibilityNodeInfo info = infos.get(i); 6480d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); 6498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 6538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 6548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the message stored if the interacted and interacting 6558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * threads are the same. 6568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 6578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return The message. 6588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 6598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private Message getSameProcessMessageAndClear() { 6608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 6618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov Message result = mSameThreadMessage; 6628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mSameThreadMessage = null; 6638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 6648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 666d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 667d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov /** 668d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * Gets a cached accessibility service connection. 669d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * 670d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The connection id. 671d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @return The cached connection if such. 672d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov */ 673d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public IAccessibilityServiceConnection getConnection(int connectionId) { 67436bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov synchronized (sConnectionCache) { 67536bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov return sConnectionCache.get(connectionId); 676d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 677d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 678d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 679d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov /** 680d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * Adds a cached accessibility service connection. 681d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * 682d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The connection id. 683d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connection The connection. 684d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov */ 685d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public void addConnection(int connectionId, IAccessibilityServiceConnection connection) { 68636bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov synchronized (sConnectionCache) { 68736bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov sConnectionCache.put(connectionId, connection); 688d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 689d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 690d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 691d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov /** 692d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * Removes a cached accessibility service connection. 693d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * 694d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The connection id. 695d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov */ 696d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public void removeConnection(int connectionId) { 69736bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov synchronized (sConnectionCache) { 69836bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov sConnectionCache.remove(connectionId); 699d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 700d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 7018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov} 702