AccessibilityInteractionClient.java revision c406be9036643ebe41bafcd94fe4aa861b4e4f4f
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; 22aa780c110922148a6a4ba06734bb2b0bb8c98f93Svetoslav Ganovimport android.os.Bundle; 238bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport android.os.Message; 244213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganovimport android.os.Process; 258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport android.os.RemoteException; 268bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport android.os.SystemClock; 27d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganovimport android.util.Log; 288b5a814f6a36045b06bee36f44703503c03714d4Svetoslav Ganovimport android.util.LongSparseArray; 29d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganovimport android.util.SparseArray; 308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 3179311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganovimport java.util.ArrayList; 328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport java.util.Collections; 338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport java.util.List; 348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovimport java.util.concurrent.atomic.AtomicInteger; 358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov/** 378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * This class is a singleton that performs accessibility interaction 388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * which is it queries remote view hierarchies about snapshots of their 398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * views as well requests from these hierarchies to perform certain 408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * actions on their views. 418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Rationale: The content retrieval APIs are synchronous from a client's 438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * perspective but internally they are asynchronous. The client thread 448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * calls into the system requesting an action and providing a callback 458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * to receive the result after which it waits up to a timeout for that 468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * result. The system enforces security and the delegates the request 478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * to a given view hierarchy where a message is posted (from a binder 488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * thread) describing what to be performed by the main UI thread the 498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * result of which it delivered via the mentioned callback. However, 508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * the blocked client thread and the main UI thread of the target view 518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * hierarchy can be the same thread, for example an accessibility service 528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * and an activity run in the same process, thus they are executed on the 538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * same main thread. In such a case the retrieval will fail since the UI 548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * thread that has to process the message describing the work to be done 558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * is blocked waiting for a result is has to compute! To avoid this scenario 568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * when making a call the client also passes its process and thread ids so 578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * the accessed view hierarchy can detect if the client making the request 588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * is running in its main UI thread. In such a case the view hierarchy, 598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * specifically the binder thread performing the IPC to it, does not post a 608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * message to be run on the UI thread but passes it to the singleton 618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * interaction client through which all interactions occur and the latter is 628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * responsible to execute the message before starting to wait for the 638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * asynchronous result delivered via the callback. In this case the expected 648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * result is already received so no waiting is performed. 658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @hide 678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganovpublic final class AccessibilityInteractionClient 698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov extends IAccessibilityInteractionConnectionCallback.Stub { 708bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 71d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public static final int NO_ID = -1; 72d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 73d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov private static final String LOG_TAG = "AccessibilityInteractionClient"; 74d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 75d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov private static final boolean DEBUG = false; 76d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private static final long TIMEOUT_INTERACTION_MILLIS = 5000; 788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private static final Object sStaticLock = new Object(); 808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 81021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov private static final LongSparseArray<AccessibilityInteractionClient> sClients = 82021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov new LongSparseArray<AccessibilityInteractionClient>(); 838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private final AtomicInteger mInteractionIdCounter = new AtomicInteger(); 858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private final Object mInstanceLock = new Object(); 878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 88fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov private volatile int mInteractionId = -1; 898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 908bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private AccessibilityNodeInfo mFindAccessibilityNodeInfoResult; 918bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 928bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private List<AccessibilityNodeInfo> mFindAccessibilityNodeInfosResult; 938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private boolean mPerformAccessibilityActionResult; 958bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private Message mSameThreadMessage; 978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private final Rect mTempBounds = new Rect(); 998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 10036bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov // The connection cache is shared between all interrogating threads. 10136bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache = 102d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov new SparseArray<IAccessibilityServiceConnection>(); 103d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 10479311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov // The connection cache is shared between all interrogating threads since 10579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov // at any given time there is only one window allowing querying. 10679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov private static final AccessibilityNodeInfoCache sAccessibilityNodeInfoCache = 10757c7fd5a43237afc5e8ef31a076e862c0c16c328Svetoslav Ganov new AccessibilityNodeInfoCache(); 10879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov 1098bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 110021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov * @return The client for the current thread. 1118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 1128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public static AccessibilityInteractionClient getInstance() { 113021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov final long threadId = Thread.currentThread().getId(); 114021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov return getInstanceForThread(threadId); 115021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov } 116021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov 117021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov /** 118021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov * <strong>Note:</strong> We keep one instance per interrogating thread since 119021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov * the instance contains state which can lead to undesired thread interleavings. 120021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov * We do not have a thread local variable since other threads should be able to 121021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov * look up the correct client knowing a thread id. See ViewRootImpl for details. 122021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov * 123021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov * @return The client for a given <code>threadId</code>. 124021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov */ 125021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov public static AccessibilityInteractionClient getInstanceForThread(long threadId) { 1268bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (sStaticLock) { 127021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov AccessibilityInteractionClient client = sClients.get(threadId); 128021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov if (client == null) { 129021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov client = new AccessibilityInteractionClient(); 130021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov sClients.put(threadId, client); 1318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 132021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov return client; 1338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 136021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov private AccessibilityInteractionClient() { 137021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov /* reducing constructor visibility */ 138021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov } 139021078554b902179442a345a9d080a165c3b5139Svetoslav Ganov 1408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 1418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Sets the message to be processed if the interacted view hierarchy 1428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * and the interacting client are running in the same thread. 1438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 1448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param message The message. 1458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 1468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setSameThreadMessage(Message message) { 1478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 1488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mSameThreadMessage = message; 1496bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov mInstanceLock.notifyAll(); 1508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 1528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 1538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 154fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov * Gets the root {@link AccessibilityNodeInfo} in the currently active window. 155fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov * 156fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 157fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov * @return The root {@link AccessibilityNodeInfo} if found, null otherwise. 158fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov */ 159fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov public AccessibilityNodeInfo getRootInActiveWindow(int connectionId) { 160fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov return findAccessibilityNodeInfoByAccessibilityId(connectionId, 161fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov AccessibilityNodeInfo.ACTIVE_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, 162fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS); 163fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov } 164fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov 165fefd20e927b7252d63acb7bb1852c5188e3c1b2eSvetoslav Ganov /** 1668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finds an {@link AccessibilityNodeInfo} by accessibility id. 1678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 168d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 16979311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 1700d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 17179311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to query the currently active window. 1720d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 1730d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * where to start the search. Use 1740d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 1750d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * to start from the root. 17657c7fd5a43237afc5e8ef31a076e862c0c16c328Svetoslav Ganov * @param prefetchFlags flags to guide prefetching. 1778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return An {@link AccessibilityNodeInfo} if found, null otherwise. 1788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 179d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(int connectionId, 18057c7fd5a43237afc5e8ef31a076e862c0c16c328Svetoslav Ganov int accessibilityWindowId, long accessibilityNodeId, int prefetchFlags) { 1818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 182d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 183d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 1840d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov AccessibilityNodeInfo cachedInfo = sAccessibilityNodeInfoCache.get( 1850d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov accessibilityNodeId); 18679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov if (cachedInfo != null) { 18779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov return cachedInfo; 18879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 189d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 190d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId( 191f3b4f3163b5b4c0a54a2643f07c97c47b14a1eb7Svetoslav Ganov accessibilityWindowId, accessibilityNodeId, interactionId, this, 1924213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov prefetchFlags, Thread.currentThread().getId()); 193d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov // If the scale is zero the call has failed. 194d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (windowScale > 0) { 19579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( 196d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId); 1970d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, windowScale); 19879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov if (infos != null && !infos.isEmpty()) { 19979311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov return infos.get(0); 20079311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 201d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 202d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 203d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 204d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 205d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 208d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 209d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote" 210d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov + " findAccessibilityNodeInfoByAccessibilityId", re); 211d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2138bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return null; 2148bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 2168bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 21779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in 21879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * the window whose id is specified and starts from the node whose accessibility 21979311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * id is specified. 2208bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 221d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 22279311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 2230d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 22479311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to query the currently active window. 2250d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 2260d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * where to start the search. Use 2270d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 22879311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to start from the root. 2296bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov * @param viewId The id of the view. 2308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return An {@link AccessibilityNodeInfo} if found, null otherwise. 2318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 23279311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int connectionId, 23379311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov int accessibilityWindowId, long accessibilityNodeId, int viewId) { 2348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 235d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 236d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 237d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 238d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final float windowScale = 23979311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov connection.findAccessibilityNodeInfoByViewId(accessibilityWindowId, 24079311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov accessibilityNodeId, viewId, interactionId, this, 24179311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov Thread.currentThread().getId()); 242d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov // If the scale is zero the call has failed. 243d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (windowScale > 0) { 244d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( 245d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId); 2460d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); 247d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov return info; 248d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 249d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 250d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 251d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 252d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 255d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 256d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote" 257d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov + " findAccessibilityNodeInfoByViewIdInActiveWindow", re); 258d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 2598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return null; 2618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 2628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 2638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 2648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finds {@link AccessibilityNodeInfo}s by View text. The match is case 2658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * insensitive containment. The search is performed in the window whose 26679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * id is specified and starts from the node whose accessibility id is 2678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * specified. 2688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 269d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 27079311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 2710d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 27279311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to query the currently active window. 2730d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 2740d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * where to start the search. Use 2750d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 2760d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * to start from the root. 2778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param text The searched text. 2788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return A list of found {@link AccessibilityNodeInfo}s. 2798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 28066922db828eab153c15bf3ca0b007313d9376e5eSvetoslav Ganov public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(int connectionId, 28179311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov int accessibilityWindowId, long accessibilityNodeId, String text) { 2828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 283d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 284d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 285d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 28679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov final float windowScale = connection.findAccessibilityNodeInfosByText( 28779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov accessibilityWindowId, accessibilityNodeId, text, interactionId, this, 288d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Thread.currentThread().getId()); 289d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov // If the scale is zero the call has failed. 290d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (windowScale > 0) { 291d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( 292d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov interactionId); 2930d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, windowScale); 294d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov return infos; 295d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 296d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 297d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 298d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 299d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 3008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 302d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 303d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote" 304d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov + " findAccessibilityNodeInfosByViewText", re); 305d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 3068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return Collections.emptyList(); 3088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 3098bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 3108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 3114213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * Finds the {@link android.view.accessibility.AccessibilityNodeInfo} that has the 3124213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * specified focus type. The search is performed in the window whose id is specified 3134213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * and starts from the node whose accessibility id is specified. 3144213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * 3154213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 3164213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 3174213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 3184213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * to query the currently active window. 3194213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 3204213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * where to start the search. Use 3214213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 3224213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * to start from the root. 3234213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param focusType The focus type. 3244213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @return The accessibility focused {@link AccessibilityNodeInfo}. 3254213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov */ 3264213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov public AccessibilityNodeInfo findFocus(int connectionId, int accessibilityWindowId, 3274213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov long accessibilityNodeId, int focusType) { 3284213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov try { 3294213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 3304213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (connection != null) { 3314213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 3324213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final float windowScale = connection.findFocus(accessibilityWindowId, 3334213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov accessibilityNodeId, focusType, interactionId, this, 3344213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Thread.currentThread().getId()); 3354213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // If the scale is zero the call has failed. 3364213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (windowScale > 0) { 3374213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( 3384213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov interactionId); 3394213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); 3404213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov return info; 3414213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3424213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } else { 3434213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (DEBUG) { 3444213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 3454213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3464213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3474213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } catch (RemoteException re) { 3484213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (DEBUG) { 3494213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote findAccessibilityFocus", re); 3504213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3514213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3524213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov return null; 3534213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3544213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov 3554213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov /** 3564213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * Finds the accessibility focused {@link android.view.accessibility.AccessibilityNodeInfo}. 3574213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * The search is performed in the window whose id is specified and starts from the 3584213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * node whose accessibility id is specified. 3594213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * 3604213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 3614213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 3624213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 3634213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * to query the currently active window. 3644213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 3654213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * where to start the search. Use 3664213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 3674213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * to start from the root. 3684213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @param direction The direction in which to search for focusable. 3694213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * @return The accessibility focused {@link AccessibilityNodeInfo}. 3704213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov */ 3714213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov public AccessibilityNodeInfo focusSearch(int connectionId, int accessibilityWindowId, 3724213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov long accessibilityNodeId, int direction) { 3734213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov try { 3744213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 3754213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (connection != null) { 3764213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 3774213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final float windowScale = connection.focusSearch(accessibilityWindowId, 3784213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov accessibilityNodeId, direction, interactionId, this, 3794213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Thread.currentThread().getId()); 3804213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // If the scale is zero the call has failed. 3814213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (windowScale > 0) { 3824213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( 3834213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov interactionId); 3844213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); 3854213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov return info; 3864213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3874213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } else { 3884213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (DEBUG) { 3894213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 3904213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3914213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3924213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } catch (RemoteException re) { 3934213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (DEBUG) { 3944213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote accessibilityFocusSearch", re); 3954213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3964213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3974213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov return null; 3984213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 3994213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov 4004213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov /** 4018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Performs an accessibility action on an {@link AccessibilityNodeInfo}. 4028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 403d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of a connection for interacting with the system. 40479311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * @param accessibilityWindowId A unique window id. Use 4050d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} 40679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov * to query the currently active window. 4070d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * @param accessibilityNodeId A unique view id or virtual descendant id from 4080d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * where to start the search. Use 4090d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} 4100d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov * to start from the root. 4118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param action The action to perform. 412aa780c110922148a6a4ba06734bb2b0bb8c98f93Svetoslav Ganov * @param arguments Optional action arguments. 4138bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return Whether the action was performed. 4148bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 415d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public boolean performAccessibilityAction(int connectionId, int accessibilityWindowId, 416aa780c110922148a6a4ba06734bb2b0bb8c98f93Svetoslav Ganov long accessibilityNodeId, int action, Bundle arguments) { 4178bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 418d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov IAccessibilityServiceConnection connection = getConnection(connectionId); 419d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (connection != null) { 420d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final int interactionId = mInteractionIdCounter.getAndIncrement(); 421d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov final boolean success = connection.performAccessibilityAction( 422aa780c110922148a6a4ba06734bb2b0bb8c98f93Svetoslav Ganov accessibilityWindowId, accessibilityNodeId, action, arguments, 423aa780c110922148a6a4ba06734bb2b0bb8c98f93Svetoslav Ganov interactionId, this, Thread.currentThread().getId()); 424d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (success) { 42579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov return getPerformAccessibilityActionResultAndClear(interactionId); 426d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 427d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } else { 428d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 429d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "No connection for connection id: " + connectionId); 430d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 4318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (RemoteException re) { 433d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov if (DEBUG) { 434d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov Log.w(LOG_TAG, "Error while calling remote performAccessibilityAction", re); 435d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 4368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return false; 4388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 44079311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov public void clearCache() { 44179311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov sAccessibilityNodeInfoCache.clear(); 44279311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 44379311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov 44479311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov public void onAccessibilityEvent(AccessibilityEvent event) { 44579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov sAccessibilityNodeInfoCache.onAccessibilityEvent(event); 44679311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 44779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov 4488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the the result of an async request that returns an {@link AccessibilityNodeInfo}. 4508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 4518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 4528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return The result {@link AccessibilityNodeInfo}. 4538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 4548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private AccessibilityNodeInfo getFindAccessibilityNodeInfoResultAndClear(int interactionId) { 4558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 4568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean success = waitForResultTimedLocked(interactionId); 4578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov AccessibilityNodeInfo result = success ? mFindAccessibilityNodeInfoResult : null; 4588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov clearResultLocked(); 4598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 4608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 4638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * {@inheritDoc} 4658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 4668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setFindAccessibilityNodeInfoResult(AccessibilityNodeInfo info, 4678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov int interactionId) { 4688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 4698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (interactionId > mInteractionId) { 4708bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mFindAccessibilityNodeInfoResult = info; 4718bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = interactionId; 4728bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4738bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.notifyAll(); 4748bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4758bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4768bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 4778bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the the result of an async request that returns {@link AccessibilityNodeInfo}s. 4798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 4808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 4818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return The result {@link AccessibilityNodeInfo}s. 4828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 4838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private List<AccessibilityNodeInfo> getFindAccessibilityNodeInfosResultAndClear( 4848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov int interactionId) { 4858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 4868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean success = waitForResultTimedLocked(interactionId); 4874213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov List<AccessibilityNodeInfo> result = null; 4884213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (success) { 4894213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov result = mFindAccessibilityNodeInfosResult; 4904213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } else { 4914213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov result = Collections.emptyList(); 4924213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 4938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov clearResultLocked(); 4948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 4958bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 4978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 4988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 4998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * {@inheritDoc} 5008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 5018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setFindAccessibilityNodeInfosResult(List<AccessibilityNodeInfo> infos, 5028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov int interactionId) { 5038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 5048bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (interactionId > mInteractionId) { 5054213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (infos != null) { 5064213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // If the call is not an IPC, i.e. it is made from the same process, we need to 5074213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // instantiate new result list to avoid passing internal instances to clients. 5084213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov final boolean isIpcCall = (Binder.getCallingPid() != Process.myPid()); 5094213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (!isIpcCall) { 5104213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov mFindAccessibilityNodeInfosResult = 5114213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov new ArrayList<AccessibilityNodeInfo>(infos); 5124213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } else { 5134213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov mFindAccessibilityNodeInfosResult = infos; 5144213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 51579311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } else { 5164213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov mFindAccessibilityNodeInfosResult = Collections.emptyList(); 51779311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov } 5188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = interactionId; 5198bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5208bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.notifyAll(); 5218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5238bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5248bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the result of a request to perform an accessibility action. 5268bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 5278bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 5288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return Whether the action was performed. 5298bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 53079311c4af8b54d3cd47ab37a120c648bfc990511Svetoslav Ganov private boolean getPerformAccessibilityActionResultAndClear(int interactionId) { 5318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 5328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean success = waitForResultTimedLocked(interactionId); 5338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final boolean result = success ? mPerformAccessibilityActionResult : false; 5348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov clearResultLocked(); 5358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 5368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5378bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5408bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * {@inheritDoc} 5418bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 5428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov public void setPerformAccessibilityActionResult(boolean succeeded, int interactionId) { 5438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 5448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (interactionId > mInteractionId) { 5458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mPerformAccessibilityActionResult = succeeded; 5468bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = interactionId; 5478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.notifyAll(); 5498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Clears the result state. 5548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 5558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private void clearResultLocked() { 5568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInteractionId = -1; 5578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mFindAccessibilityNodeInfoResult = null; 5588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mFindAccessibilityNodeInfosResult = null; 5598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mPerformAccessibilityActionResult = false; 5608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Waits up to a given bound for a result of a request and returns it. 5648bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 5658bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param interactionId The interaction id to match the result with the request. 5668bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return Whether the result was received. 5678bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 5688bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private boolean waitForResultTimedLocked(int interactionId) { 5698bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov long waitTimeMillis = TIMEOUT_INTERACTION_MILLIS; 5708bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final long startTimeMillis = SystemClock.uptimeMillis(); 5718bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov while (true) { 5728bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov try { 5736bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov Message sameProcessMessage = getSameProcessMessageAndClear(); 5746bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov if (sameProcessMessage != null) { 5756bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov sameProcessMessage.getTarget().handleMessage(sameProcessMessage); 5766bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov } 5776bc5e530016928027c7b390a8368ecdd5bff072fSvetoslav Ganov 5788bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (mInteractionId == interactionId) { 5798bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return true; 5808bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5818bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (mInteractionId > interactionId) { 5828bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return false; 5838bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5848bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; 5858bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov waitTimeMillis = TIMEOUT_INTERACTION_MILLIS - elapsedTimeMillis; 5868bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (waitTimeMillis <= 0) { 5878bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return false; 5888bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5898bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mInstanceLock.wait(waitTimeMillis); 5908bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } catch (InterruptedException ie) { 5918bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /* ignore */ 5928bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5938bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5948bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 5958bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 5968bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 5978bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Applies compatibility scale to the info bounds if it is not equal to one. 5988bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 5998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param info The info whose bounds to scale. 6008bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param scale The scale to apply. 6018bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 6028bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private void applyCompatibilityScaleIfNeeded(AccessibilityNodeInfo info, float scale) { 6038bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (scale == 1.0f) { 6048bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return; 6058bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6068bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov Rect bounds = mTempBounds; 6078bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.getBoundsInParent(bounds); 6088bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov bounds.scale(scale); 6098bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.setBoundsInParent(bounds); 6108bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 6118bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.getBoundsInScreen(bounds); 6128bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov bounds.scale(scale); 6138bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.setBoundsInScreen(bounds); 6148bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6158bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 6168bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 6178bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finalize an {@link AccessibilityNodeInfo} before passing it to the client. 6188bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 6198bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param info The info. 620d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of the connection to the system. 6218bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param windowScale The source window compatibility scale. 6228bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 6230d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov private void finalizeAndCacheAccessibilityNodeInfo(AccessibilityNodeInfo info, int connectionId, 624d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov float windowScale) { 6258bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (info != null) { 6268bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov applyCompatibilityScaleIfNeeded(info, windowScale); 627d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov info.setConnectionId(connectionId); 6288bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov info.setSealed(true); 629c406be9036643ebe41bafcd94fe4aa861b4e4f4fSvetoslav Ganov sAccessibilityNodeInfoCache.add(info); 6308bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6318bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6328bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 6338bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 6348bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Finalize {@link AccessibilityNodeInfo}s before passing them to the client. 6358bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 6368bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param infos The {@link AccessibilityNodeInfo}s. 637d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The id of the connection to the system. 6388bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @param windowScale The source window compatibility scale. 6398bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 6400d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov private void finalizeAndCacheAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos, 641d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov int connectionId, float windowScale) { 6428bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov if (infos != null) { 6438bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov final int infosCount = infos.size(); 6448bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov for (int i = 0; i < infosCount; i++) { 6458bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov AccessibilityNodeInfo info = infos.get(i); 6460d04e245534cf777dfaf16dce3c51553837c14ffSvetoslav Ganov finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); 6478bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6488bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6498bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6508bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov 6518bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov /** 6528bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * Gets the message stored if the interacted and interacting 6538bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * threads are the same. 6548bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * 6558bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov * @return The message. 6568bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov */ 6578bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov private Message getSameProcessMessageAndClear() { 6588bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov synchronized (mInstanceLock) { 6598bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov Message result = mSameThreadMessage; 6608bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov mSameThreadMessage = null; 6618bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov return result; 6628bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 6638bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov } 664d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 665d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov /** 666d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * Gets a cached accessibility service connection. 667d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * 668d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The connection id. 669d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @return The cached connection if such. 670d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov */ 671d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public IAccessibilityServiceConnection getConnection(int connectionId) { 67236bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov synchronized (sConnectionCache) { 67336bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov return sConnectionCache.get(connectionId); 674d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 675d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 676d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 677d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov /** 678d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * Adds a cached accessibility service connection. 679d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * 680d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The connection id. 681d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connection The connection. 682d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov */ 683d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public void addConnection(int connectionId, IAccessibilityServiceConnection connection) { 68436bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov synchronized (sConnectionCache) { 68536bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov sConnectionCache.put(connectionId, connection); 686d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 687d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 688d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov 689d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov /** 690d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * Removes a cached accessibility service connection. 691d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * 692d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov * @param connectionId The connection id. 693d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov */ 694d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov public void removeConnection(int connectionId) { 69536bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov synchronized (sConnectionCache) { 69636bcdb535e14a8a2e2c8643fb577569f7a2b6aedSvetoslav Ganov sConnectionCache.remove(connectionId); 697d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 698d116d7c78a9c53f30a73bf273bd7618312cf3847Svetoslav Ganov } 6998bd69610aafc6995126965d1d23b771fe02a9084Svetoslav Ganov} 700