Loading core/java/android/view/AccessibilityInteractionController.java +130 −221 Original line number Diff line number Diff line Loading @@ -86,19 +86,12 @@ public final class AccessibilityInteractionController { // accessibility from hanging private static final long REQUEST_PREPARER_TIMEOUT_MS = 500; // Callbacks should have the same configuration of the flags below to allow satisfying a pending // node request on prefetch private static final int FLAGS_AFFECTING_REPORTED_DATA = AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS | AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; private final ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList = new ArrayList<AccessibilityNodeInfo>(); private final Object mLock = new Object(); @VisibleForTesting public final PrivateHandler mHandler; private final PrivateHandler mHandler; private final ViewRootImpl mViewRootImpl; Loading @@ -120,9 +113,6 @@ public final class AccessibilityInteractionController { private AddNodeInfosForViewId mAddNodeInfosForViewId; @GuardedBy("mLock") private ArrayList<Message> mPendingFindNodeByIdMessages; @GuardedBy("mLock") private int mNumActiveRequestPreparers; @GuardedBy("mLock") Loading @@ -138,7 +128,6 @@ public final class AccessibilityInteractionController { mViewRootImpl = viewRootImpl; mPrefetcher = new AccessibilityNodePrefetcher(); mA11yManager = mViewRootImpl.mContext.getSystemService(AccessibilityManager.class); mPendingFindNodeByIdMessages = new ArrayList<>(); } private void scheduleMessage(Message message, int interrogatingPid, long interrogatingTid, Loading Loading @@ -188,9 +177,6 @@ public final class AccessibilityInteractionController { args.arg4 = arguments; message.obj = args; synchronized (mLock) { mPendingFindNodeByIdMessages.add(message); } scheduleMessage(message, interrogatingPid, interrogatingTid, CONSIDER_REQUEST_PREPARERS); } Loading Loading @@ -329,9 +315,6 @@ public final class AccessibilityInteractionController { } private void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) { synchronized (mLock) { mPendingFindNodeByIdMessages.remove(message); } final int flags = message.arg1; SomeArgs args = (SomeArgs) message.obj; Loading @@ -346,58 +329,22 @@ public final class AccessibilityInteractionController { args.recycle(); View rootView = null; AccessibilityNodeInfo rootNode = null; List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList; infos.clear(); try { if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) { return; } mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags; rootView = findViewByAccessibilityId(accessibilityViewId); if (rootView != null && isShown(rootView)) { rootNode = populateAccessibilityNodeInfoForView( rootView, arguments, virtualDescendantId); } } finally { updateInfoForViewportAndReturnFindNodeResult( rootNode == null ? null : AccessibilityNodeInfo.obtain(rootNode), callback, interactionId, spec, interactiveRegion); } ArrayList<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList; infos.clear(); final View root = findViewByAccessibilityId(accessibilityViewId); if (root != null && isShown(root)) { mPrefetcher.prefetchAccessibilityNodeInfos( rootView, rootNode == null ? null : AccessibilityNodeInfo.obtain(rootNode), virtualDescendantId, flags, infos); mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; updateInfosForViewPort(infos, spec, interactiveRegion); returnPrefetchResult(interactionId, infos, callback); returnPendingFindAccessibilityNodeInfosInPrefetch(rootNode, infos, flags); } private AccessibilityNodeInfo populateAccessibilityNodeInfoForView( View view, Bundle arguments, int virtualViewId) { AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider(); // Determine if we'll be populating extra data final String extraDataRequested = (arguments == null) ? null : arguments.getString(EXTRA_DATA_REQUESTED_KEY); AccessibilityNodeInfo root = null; if (provider == null) { root = view.createAccessibilityNodeInfo(); if (root != null) { if (extraDataRequested != null) { view.addExtraDataToAccessibilityNodeInfo(root, extraDataRequested, arguments); } } } else { root = provider.createAccessibilityNodeInfo(virtualViewId); if (root != null) { if (extraDataRequested != null) { provider.addExtraDataToAccessibilityNodeInfo( virtualViewId, root, extraDataRequested, arguments); } root, virtualDescendantId, flags, infos, arguments); } } finally { updateInfosForViewportAndReturnFindNodeResult( infos, callback, interactionId, spec, interactiveRegion); } return root; } public void findAccessibilityNodeInfosByViewIdClientThread(long accessibilityNodeId, Loading Loading @@ -456,7 +403,6 @@ public final class AccessibilityInteractionController { mAddNodeInfosForViewId.reset(); } } finally { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; updateInfosForViewportAndReturnFindNodeResult( infos, callback, interactionId, spec, interactiveRegion); } Loading Loading @@ -539,7 +485,6 @@ public final class AccessibilityInteractionController { } } } finally { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; updateInfosForViewportAndReturnFindNodeResult( infos, callback, interactionId, spec, interactiveRegion); } Loading Loading @@ -631,7 +576,6 @@ public final class AccessibilityInteractionController { } } } finally { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; updateInfoForViewportAndReturnFindNodeResult( focused, callback, interactionId, spec, interactiveRegion); } Loading Loading @@ -686,7 +630,6 @@ public final class AccessibilityInteractionController { } } } finally { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; updateInfoForViewportAndReturnFindNodeResult( next, callback, interactionId, spec, interactiveRegion); } Loading Loading @@ -843,6 +786,33 @@ public final class AccessibilityInteractionController { } } private void applyAppScaleAndMagnificationSpecIfNeeded(List<AccessibilityNodeInfo> infos, MagnificationSpec spec) { if (infos == null) { return; } final float applicationScale = mViewRootImpl.mAttachInfo.mApplicationScale; if (shouldApplyAppScaleAndMagnificationSpec(applicationScale, spec)) { final int infoCount = infos.size(); for (int i = 0; i < infoCount; i++) { AccessibilityNodeInfo info = infos.get(i); applyAppScaleAndMagnificationSpecIfNeeded(info, spec); } } } private void adjustIsVisibleToUserIfNeeded(List<AccessibilityNodeInfo> infos, Region interactiveRegion) { if (interactiveRegion == null || infos == null) { return; } final int infoCount = infos.size(); for (int i = 0; i < infoCount; i++) { AccessibilityNodeInfo info = infos.get(i); adjustIsVisibleToUserIfNeeded(info, interactiveRegion); } } private void adjustIsVisibleToUserIfNeeded(AccessibilityNodeInfo info, Region interactiveRegion) { if (interactiveRegion == null || info == null) { Loading @@ -863,6 +833,17 @@ public final class AccessibilityInteractionController { return false; } private void adjustBoundsInScreenIfNeeded(List<AccessibilityNodeInfo> infos) { if (infos == null || shouldBypassAdjustBoundsInScreen()) { return; } final int infoCount = infos.size(); for (int i = 0; i < infoCount; i++) { final AccessibilityNodeInfo info = infos.get(i); adjustBoundsInScreenIfNeeded(info); } } private void adjustBoundsInScreenIfNeeded(AccessibilityNodeInfo info) { if (info == null || shouldBypassAdjustBoundsInScreen()) { return; Loading Loading @@ -910,6 +891,17 @@ public final class AccessibilityInteractionController { return screenMatrix == null || screenMatrix.isIdentity(); } private void associateLeashedParentIfNeeded(List<AccessibilityNodeInfo> infos) { if (infos == null || shouldBypassAssociateLeashedParent()) { return; } final int infoCount = infos.size(); for (int i = 0; i < infoCount; i++) { final AccessibilityNodeInfo info = infos.get(i); associateLeashedParentIfNeeded(info); } } private void associateLeashedParentIfNeeded(AccessibilityNodeInfo info) { if (info == null || shouldBypassAssociateLeashedParent()) { return; Loading Loading @@ -983,46 +975,18 @@ public final class AccessibilityInteractionController { return (appScale != 1.0f || (spec != null && !spec.isNop())); } private void updateInfosForViewPort(List<AccessibilityNodeInfo> infos, MagnificationSpec spec, Region interactiveRegion) { for (int i = 0; i < infos.size(); i++) { updateInfoForViewPort(infos.get(i), spec, interactiveRegion); } } private void updateInfoForViewPort(AccessibilityNodeInfo info, MagnificationSpec spec, Region interactiveRegion) { associateLeashedParentIfNeeded(info); applyScreenMatrixIfNeeded(info); adjustBoundsInScreenIfNeeded(info); // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node, // then impact the visibility result, we need to adjust visibility before apply scale. adjustIsVisibleToUserIfNeeded(info, interactiveRegion); applyAppScaleAndMagnificationSpecIfNeeded(info, spec); } private void updateInfosForViewportAndReturnFindNodeResult(List<AccessibilityNodeInfo> infos, IAccessibilityInteractionConnectionCallback callback, int interactionId, MagnificationSpec spec, Region interactiveRegion) { if (infos != null) { updateInfosForViewPort(infos, spec, interactiveRegion); } returnFindNodesResult(infos, callback, interactionId); } private void returnFindNodeResult(AccessibilityNodeInfo info, IAccessibilityInteractionConnectionCallback callback, int interactionId) { try { callback.setFindAccessibilityNodeInfoResult(info, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ } } private void returnFindNodesResult(List<AccessibilityNodeInfo> infos, IAccessibilityInteractionConnectionCallback callback, int interactionId) { try { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; associateLeashedParentIfNeeded(infos); applyScreenMatrixIfNeeded(infos); adjustBoundsInScreenIfNeeded(infos); // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node, // then impact the visibility result, we need to adjust visibility before apply scale. adjustIsVisibleToUserIfNeeded(infos, interactiveRegion); applyAppScaleAndMagnificationSpecIfNeeded(infos, spec); callback.setFindAccessibilityNodeInfosResult(infos, interactionId); if (infos != null) { infos.clear(); Loading @@ -1032,80 +996,22 @@ public final class AccessibilityInteractionController { } } private void returnPendingFindAccessibilityNodeInfosInPrefetch(AccessibilityNodeInfo rootNode, List<AccessibilityNodeInfo> infos, int flags) { AccessibilityNodeInfo satisfiedPendingRequestPrefetchedNode = null; IAccessibilityInteractionConnectionCallback satisfiedPendingRequestCallback = null; int satisfiedPendingRequestInteractionId = AccessibilityInteractionClient.NO_ID; synchronized (mLock) { for (int i = 0; i < mPendingFindNodeByIdMessages.size(); i++) { final Message pendingMessage = mPendingFindNodeByIdMessages.get(i); final int pendingFlags = pendingMessage.arg1; if ((pendingFlags & FLAGS_AFFECTING_REPORTED_DATA) != (flags & FLAGS_AFFECTING_REPORTED_DATA)) { continue; } SomeArgs args = (SomeArgs) pendingMessage.obj; final int accessibilityViewId = args.argi1; final int virtualDescendantId = args.argi2; satisfiedPendingRequestPrefetchedNode = nodeWithIdFromList(rootNode, infos, AccessibilityNodeInfo.makeNodeId( accessibilityViewId, virtualDescendantId)); if (satisfiedPendingRequestPrefetchedNode != null) { satisfiedPendingRequestCallback = (IAccessibilityInteractionConnectionCallback) args.arg1; satisfiedPendingRequestInteractionId = args.argi3; mHandler.removeMessages( PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID, pendingMessage.obj); args.recycle(); break; } } mPendingFindNodeByIdMessages.clear(); } if (satisfiedPendingRequestPrefetchedNode != null) { returnFindNodeResult( AccessibilityNodeInfo.obtain(satisfiedPendingRequestPrefetchedNode), satisfiedPendingRequestCallback, satisfiedPendingRequestInteractionId); } } private AccessibilityNodeInfo nodeWithIdFromList(AccessibilityNodeInfo rootNode, List<AccessibilityNodeInfo> infos, long nodeId) { if (rootNode != null && rootNode.getSourceNodeId() == nodeId) { return rootNode; } for (int j = 0; j < infos.size(); j++) { AccessibilityNodeInfo info = infos.get(j); if (info.getSourceNodeId() == nodeId) { return info; } } return null; } private void returnPrefetchResult(int interactionId, List<AccessibilityNodeInfo> infos, IAccessibilityInteractionConnectionCallback callback) { if (infos.size() > 0) { try { callback.setPrefetchAccessibilityNodeInfoResult(infos, interactionId); } catch (RemoteException re) { /* ignore - other side isn't too bothered if this doesn't arrive */ } } } private void updateInfoForViewportAndReturnFindNodeResult(AccessibilityNodeInfo info, IAccessibilityInteractionConnectionCallback callback, int interactionId, MagnificationSpec spec, Region interactiveRegion) { updateInfoForViewPort(info, spec, interactiveRegion); returnFindNodeResult(info, callback, interactionId); try { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; associateLeashedParentIfNeeded(info); applyScreenMatrixIfNeeded(info); adjustBoundsInScreenIfNeeded(info); // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node, // then impact the visibility result, we need to adjust visibility before apply scale. adjustIsVisibleToUserIfNeeded(info, interactiveRegion); applyAppScaleAndMagnificationSpecIfNeeded(info, spec); callback.setFindAccessibilityNodeInfoResult(info, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ } } private boolean handleClickableSpanActionUiThread( Loading Loading @@ -1148,13 +1054,20 @@ public final class AccessibilityInteractionController { private final ArrayList<View> mTempViewList = new ArrayList<View>(); public void prefetchAccessibilityNodeInfos(View view, AccessibilityNodeInfo root, int virtualViewId, int fetchFlags, List<AccessibilityNodeInfo> outInfos) { if (root == null) { return; } public void prefetchAccessibilityNodeInfos(View view, int virtualViewId, int fetchFlags, List<AccessibilityNodeInfo> outInfos, Bundle arguments) { AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider(); // Determine if we'll be populating extra data final String extraDataRequested = (arguments == null) ? null : arguments.getString(EXTRA_DATA_REQUESTED_KEY); if (provider == null) { AccessibilityNodeInfo root = view.createAccessibilityNodeInfo(); if (root != null) { if (extraDataRequested != null) { view.addExtraDataToAccessibilityNodeInfo( root, extraDataRequested, arguments); } outInfos.add(root); if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) { prefetchPredecessorsOfRealNode(view, outInfos); } Loading @@ -1164,7 +1077,16 @@ public final class AccessibilityInteractionController { if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) { prefetchDescendantsOfRealNode(view, outInfos); } } } else { final AccessibilityNodeInfo root = provider.createAccessibilityNodeInfo(virtualViewId); if (root != null) { if (extraDataRequested != null) { provider.addExtraDataToAccessibilityNodeInfo( virtualViewId, root, extraDataRequested, arguments); } outInfos.add(root); if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) { prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos); } Loading @@ -1175,18 +1097,13 @@ public final class AccessibilityInteractionController { prefetchDescendantsOfVirtualNode(root, provider, outInfos); } } } if (ENFORCE_NODE_TREE_CONSISTENT) { enforceNodeTreeConsistent(root, outInfos); enforceNodeTreeConsistent(outInfos); } } private boolean shouldStopPrefetching(List prefetchededInfos) { return mHandler.hasUserInteractiveMessagesWaiting() || prefetchededInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE; } private void enforceNodeTreeConsistent( AccessibilityNodeInfo root, List<AccessibilityNodeInfo> nodes) { private void enforceNodeTreeConsistent(List<AccessibilityNodeInfo> nodes) { LongSparseArray<AccessibilityNodeInfo> nodeMap = new LongSparseArray<AccessibilityNodeInfo>(); final int nodeCount = nodes.size(); Loading @@ -1197,6 +1114,7 @@ public final class AccessibilityInteractionController { // If the nodes are a tree it does not matter from // which node we start to search for the root. AccessibilityNodeInfo root = nodeMap.valueAt(0); AccessibilityNodeInfo parent = root; while (parent != null) { root = parent; Loading Loading @@ -1263,11 +1181,9 @@ public final class AccessibilityInteractionController { private void prefetchPredecessorsOfRealNode(View view, List<AccessibilityNodeInfo> outInfos) { if (shouldStopPrefetching(outInfos)) { return; } ViewParent parent = view.getParentForAccessibility(); while (parent instanceof View && !shouldStopPrefetching(outInfos)) { while (parent instanceof View && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { View parentView = (View) parent; AccessibilityNodeInfo info = parentView.createAccessibilityNodeInfo(); if (info != null) { Loading @@ -1279,9 +1195,6 @@ public final class AccessibilityInteractionController { private void prefetchSiblingsOfRealNode(View current, List<AccessibilityNodeInfo> outInfos) { if (shouldStopPrefetching(outInfos)) { return; } ViewParent parent = current.getParentForAccessibility(); if (parent instanceof ViewGroup) { ViewGroup parentGroup = (ViewGroup) parent; Loading @@ -1291,7 +1204,7 @@ public final class AccessibilityInteractionController { parentGroup.addChildrenForAccessibility(children); final int childCount = children.size(); for (int i = 0; i < childCount; i++) { if (shouldStopPrefetching(outInfos)) { if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { return; } View child = children.get(i); Loading Loading @@ -1319,7 +1232,7 @@ public final class AccessibilityInteractionController { private void prefetchDescendantsOfRealNode(View root, List<AccessibilityNodeInfo> outInfos) { if (shouldStopPrefetching(outInfos) || !(root instanceof ViewGroup)) { if (!(root instanceof ViewGroup)) { return; } HashMap<View, AccessibilityNodeInfo> addedChildren = Loading @@ -1330,7 +1243,7 @@ public final class AccessibilityInteractionController { root.addChildrenForAccessibility(children); final int childCount = children.size(); for (int i = 0; i < childCount; i++) { if (shouldStopPrefetching(outInfos)) { if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { return; } View child = children.get(i); Loading @@ -1355,7 +1268,7 @@ public final class AccessibilityInteractionController { } finally { children.clear(); } if (!shouldStopPrefetching(outInfos)) { if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { for (Map.Entry<View, AccessibilityNodeInfo> entry : addedChildren.entrySet()) { View addedChild = entry.getKey(); AccessibilityNodeInfo virtualRoot = entry.getValue(); Loading @@ -1377,7 +1290,7 @@ public final class AccessibilityInteractionController { long parentNodeId = root.getParentNodeId(); int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId); while (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) { if (shouldStopPrefetching(outInfos)) { if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { return; } final int virtualDescendantId = Loading Loading @@ -1422,7 +1335,7 @@ public final class AccessibilityInteractionController { if (parent != null) { final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { if (shouldStopPrefetching(outInfos)) { if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { return; } final long childNodeId = parent.getChildId(i); Loading @@ -1447,7 +1360,7 @@ public final class AccessibilityInteractionController { final int initialOutInfosSize = outInfos.size(); final int childCount = root.getChildCount(); for (int i = 0; i < childCount; i++) { if (shouldStopPrefetching(outInfos)) { if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { return; } final long childNodeId = root.getChildId(i); Loading @@ -1457,7 +1370,7 @@ public final class AccessibilityInteractionController { outInfos.add(child); } } if (!shouldStopPrefetching(outInfos)) { if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { final int addedChildCount = outInfos.size() - initialOutInfosSize; for (int i = 0; i < addedChildCount; i++) { AccessibilityNodeInfo child = outInfos.get(initialOutInfosSize + i); Loading Loading @@ -1566,10 +1479,6 @@ public final class AccessibilityInteractionController { boolean hasAccessibilityCallback(Message message) { return message.what < FIRST_NO_ACCESSIBILITY_CALLBACK_MSG ? true : false; } boolean hasUserInteractiveMessagesWaiting() { return hasMessagesOrCallbacks(); } } private final class AddNodeInfosForViewId implements Predicate<View> { Loading Loading
core/java/android/view/AccessibilityInteractionController.java +130 −221 Original line number Diff line number Diff line Loading @@ -86,19 +86,12 @@ public final class AccessibilityInteractionController { // accessibility from hanging private static final long REQUEST_PREPARER_TIMEOUT_MS = 500; // Callbacks should have the same configuration of the flags below to allow satisfying a pending // node request on prefetch private static final int FLAGS_AFFECTING_REPORTED_DATA = AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS | AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; private final ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList = new ArrayList<AccessibilityNodeInfo>(); private final Object mLock = new Object(); @VisibleForTesting public final PrivateHandler mHandler; private final PrivateHandler mHandler; private final ViewRootImpl mViewRootImpl; Loading @@ -120,9 +113,6 @@ public final class AccessibilityInteractionController { private AddNodeInfosForViewId mAddNodeInfosForViewId; @GuardedBy("mLock") private ArrayList<Message> mPendingFindNodeByIdMessages; @GuardedBy("mLock") private int mNumActiveRequestPreparers; @GuardedBy("mLock") Loading @@ -138,7 +128,6 @@ public final class AccessibilityInteractionController { mViewRootImpl = viewRootImpl; mPrefetcher = new AccessibilityNodePrefetcher(); mA11yManager = mViewRootImpl.mContext.getSystemService(AccessibilityManager.class); mPendingFindNodeByIdMessages = new ArrayList<>(); } private void scheduleMessage(Message message, int interrogatingPid, long interrogatingTid, Loading Loading @@ -188,9 +177,6 @@ public final class AccessibilityInteractionController { args.arg4 = arguments; message.obj = args; synchronized (mLock) { mPendingFindNodeByIdMessages.add(message); } scheduleMessage(message, interrogatingPid, interrogatingTid, CONSIDER_REQUEST_PREPARERS); } Loading Loading @@ -329,9 +315,6 @@ public final class AccessibilityInteractionController { } private void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) { synchronized (mLock) { mPendingFindNodeByIdMessages.remove(message); } final int flags = message.arg1; SomeArgs args = (SomeArgs) message.obj; Loading @@ -346,58 +329,22 @@ public final class AccessibilityInteractionController { args.recycle(); View rootView = null; AccessibilityNodeInfo rootNode = null; List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList; infos.clear(); try { if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) { return; } mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags; rootView = findViewByAccessibilityId(accessibilityViewId); if (rootView != null && isShown(rootView)) { rootNode = populateAccessibilityNodeInfoForView( rootView, arguments, virtualDescendantId); } } finally { updateInfoForViewportAndReturnFindNodeResult( rootNode == null ? null : AccessibilityNodeInfo.obtain(rootNode), callback, interactionId, spec, interactiveRegion); } ArrayList<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList; infos.clear(); final View root = findViewByAccessibilityId(accessibilityViewId); if (root != null && isShown(root)) { mPrefetcher.prefetchAccessibilityNodeInfos( rootView, rootNode == null ? null : AccessibilityNodeInfo.obtain(rootNode), virtualDescendantId, flags, infos); mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; updateInfosForViewPort(infos, spec, interactiveRegion); returnPrefetchResult(interactionId, infos, callback); returnPendingFindAccessibilityNodeInfosInPrefetch(rootNode, infos, flags); } private AccessibilityNodeInfo populateAccessibilityNodeInfoForView( View view, Bundle arguments, int virtualViewId) { AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider(); // Determine if we'll be populating extra data final String extraDataRequested = (arguments == null) ? null : arguments.getString(EXTRA_DATA_REQUESTED_KEY); AccessibilityNodeInfo root = null; if (provider == null) { root = view.createAccessibilityNodeInfo(); if (root != null) { if (extraDataRequested != null) { view.addExtraDataToAccessibilityNodeInfo(root, extraDataRequested, arguments); } } } else { root = provider.createAccessibilityNodeInfo(virtualViewId); if (root != null) { if (extraDataRequested != null) { provider.addExtraDataToAccessibilityNodeInfo( virtualViewId, root, extraDataRequested, arguments); } root, virtualDescendantId, flags, infos, arguments); } } finally { updateInfosForViewportAndReturnFindNodeResult( infos, callback, interactionId, spec, interactiveRegion); } return root; } public void findAccessibilityNodeInfosByViewIdClientThread(long accessibilityNodeId, Loading Loading @@ -456,7 +403,6 @@ public final class AccessibilityInteractionController { mAddNodeInfosForViewId.reset(); } } finally { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; updateInfosForViewportAndReturnFindNodeResult( infos, callback, interactionId, spec, interactiveRegion); } Loading Loading @@ -539,7 +485,6 @@ public final class AccessibilityInteractionController { } } } finally { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; updateInfosForViewportAndReturnFindNodeResult( infos, callback, interactionId, spec, interactiveRegion); } Loading Loading @@ -631,7 +576,6 @@ public final class AccessibilityInteractionController { } } } finally { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; updateInfoForViewportAndReturnFindNodeResult( focused, callback, interactionId, spec, interactiveRegion); } Loading Loading @@ -686,7 +630,6 @@ public final class AccessibilityInteractionController { } } } finally { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; updateInfoForViewportAndReturnFindNodeResult( next, callback, interactionId, spec, interactiveRegion); } Loading Loading @@ -843,6 +786,33 @@ public final class AccessibilityInteractionController { } } private void applyAppScaleAndMagnificationSpecIfNeeded(List<AccessibilityNodeInfo> infos, MagnificationSpec spec) { if (infos == null) { return; } final float applicationScale = mViewRootImpl.mAttachInfo.mApplicationScale; if (shouldApplyAppScaleAndMagnificationSpec(applicationScale, spec)) { final int infoCount = infos.size(); for (int i = 0; i < infoCount; i++) { AccessibilityNodeInfo info = infos.get(i); applyAppScaleAndMagnificationSpecIfNeeded(info, spec); } } } private void adjustIsVisibleToUserIfNeeded(List<AccessibilityNodeInfo> infos, Region interactiveRegion) { if (interactiveRegion == null || infos == null) { return; } final int infoCount = infos.size(); for (int i = 0; i < infoCount; i++) { AccessibilityNodeInfo info = infos.get(i); adjustIsVisibleToUserIfNeeded(info, interactiveRegion); } } private void adjustIsVisibleToUserIfNeeded(AccessibilityNodeInfo info, Region interactiveRegion) { if (interactiveRegion == null || info == null) { Loading @@ -863,6 +833,17 @@ public final class AccessibilityInteractionController { return false; } private void adjustBoundsInScreenIfNeeded(List<AccessibilityNodeInfo> infos) { if (infos == null || shouldBypassAdjustBoundsInScreen()) { return; } final int infoCount = infos.size(); for (int i = 0; i < infoCount; i++) { final AccessibilityNodeInfo info = infos.get(i); adjustBoundsInScreenIfNeeded(info); } } private void adjustBoundsInScreenIfNeeded(AccessibilityNodeInfo info) { if (info == null || shouldBypassAdjustBoundsInScreen()) { return; Loading Loading @@ -910,6 +891,17 @@ public final class AccessibilityInteractionController { return screenMatrix == null || screenMatrix.isIdentity(); } private void associateLeashedParentIfNeeded(List<AccessibilityNodeInfo> infos) { if (infos == null || shouldBypassAssociateLeashedParent()) { return; } final int infoCount = infos.size(); for (int i = 0; i < infoCount; i++) { final AccessibilityNodeInfo info = infos.get(i); associateLeashedParentIfNeeded(info); } } private void associateLeashedParentIfNeeded(AccessibilityNodeInfo info) { if (info == null || shouldBypassAssociateLeashedParent()) { return; Loading Loading @@ -983,46 +975,18 @@ public final class AccessibilityInteractionController { return (appScale != 1.0f || (spec != null && !spec.isNop())); } private void updateInfosForViewPort(List<AccessibilityNodeInfo> infos, MagnificationSpec spec, Region interactiveRegion) { for (int i = 0; i < infos.size(); i++) { updateInfoForViewPort(infos.get(i), spec, interactiveRegion); } } private void updateInfoForViewPort(AccessibilityNodeInfo info, MagnificationSpec spec, Region interactiveRegion) { associateLeashedParentIfNeeded(info); applyScreenMatrixIfNeeded(info); adjustBoundsInScreenIfNeeded(info); // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node, // then impact the visibility result, we need to adjust visibility before apply scale. adjustIsVisibleToUserIfNeeded(info, interactiveRegion); applyAppScaleAndMagnificationSpecIfNeeded(info, spec); } private void updateInfosForViewportAndReturnFindNodeResult(List<AccessibilityNodeInfo> infos, IAccessibilityInteractionConnectionCallback callback, int interactionId, MagnificationSpec spec, Region interactiveRegion) { if (infos != null) { updateInfosForViewPort(infos, spec, interactiveRegion); } returnFindNodesResult(infos, callback, interactionId); } private void returnFindNodeResult(AccessibilityNodeInfo info, IAccessibilityInteractionConnectionCallback callback, int interactionId) { try { callback.setFindAccessibilityNodeInfoResult(info, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ } } private void returnFindNodesResult(List<AccessibilityNodeInfo> infos, IAccessibilityInteractionConnectionCallback callback, int interactionId) { try { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; associateLeashedParentIfNeeded(infos); applyScreenMatrixIfNeeded(infos); adjustBoundsInScreenIfNeeded(infos); // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node, // then impact the visibility result, we need to adjust visibility before apply scale. adjustIsVisibleToUserIfNeeded(infos, interactiveRegion); applyAppScaleAndMagnificationSpecIfNeeded(infos, spec); callback.setFindAccessibilityNodeInfosResult(infos, interactionId); if (infos != null) { infos.clear(); Loading @@ -1032,80 +996,22 @@ public final class AccessibilityInteractionController { } } private void returnPendingFindAccessibilityNodeInfosInPrefetch(AccessibilityNodeInfo rootNode, List<AccessibilityNodeInfo> infos, int flags) { AccessibilityNodeInfo satisfiedPendingRequestPrefetchedNode = null; IAccessibilityInteractionConnectionCallback satisfiedPendingRequestCallback = null; int satisfiedPendingRequestInteractionId = AccessibilityInteractionClient.NO_ID; synchronized (mLock) { for (int i = 0; i < mPendingFindNodeByIdMessages.size(); i++) { final Message pendingMessage = mPendingFindNodeByIdMessages.get(i); final int pendingFlags = pendingMessage.arg1; if ((pendingFlags & FLAGS_AFFECTING_REPORTED_DATA) != (flags & FLAGS_AFFECTING_REPORTED_DATA)) { continue; } SomeArgs args = (SomeArgs) pendingMessage.obj; final int accessibilityViewId = args.argi1; final int virtualDescendantId = args.argi2; satisfiedPendingRequestPrefetchedNode = nodeWithIdFromList(rootNode, infos, AccessibilityNodeInfo.makeNodeId( accessibilityViewId, virtualDescendantId)); if (satisfiedPendingRequestPrefetchedNode != null) { satisfiedPendingRequestCallback = (IAccessibilityInteractionConnectionCallback) args.arg1; satisfiedPendingRequestInteractionId = args.argi3; mHandler.removeMessages( PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID, pendingMessage.obj); args.recycle(); break; } } mPendingFindNodeByIdMessages.clear(); } if (satisfiedPendingRequestPrefetchedNode != null) { returnFindNodeResult( AccessibilityNodeInfo.obtain(satisfiedPendingRequestPrefetchedNode), satisfiedPendingRequestCallback, satisfiedPendingRequestInteractionId); } } private AccessibilityNodeInfo nodeWithIdFromList(AccessibilityNodeInfo rootNode, List<AccessibilityNodeInfo> infos, long nodeId) { if (rootNode != null && rootNode.getSourceNodeId() == nodeId) { return rootNode; } for (int j = 0; j < infos.size(); j++) { AccessibilityNodeInfo info = infos.get(j); if (info.getSourceNodeId() == nodeId) { return info; } } return null; } private void returnPrefetchResult(int interactionId, List<AccessibilityNodeInfo> infos, IAccessibilityInteractionConnectionCallback callback) { if (infos.size() > 0) { try { callback.setPrefetchAccessibilityNodeInfoResult(infos, interactionId); } catch (RemoteException re) { /* ignore - other side isn't too bothered if this doesn't arrive */ } } } private void updateInfoForViewportAndReturnFindNodeResult(AccessibilityNodeInfo info, IAccessibilityInteractionConnectionCallback callback, int interactionId, MagnificationSpec spec, Region interactiveRegion) { updateInfoForViewPort(info, spec, interactiveRegion); returnFindNodeResult(info, callback, interactionId); try { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; associateLeashedParentIfNeeded(info); applyScreenMatrixIfNeeded(info); adjustBoundsInScreenIfNeeded(info); // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node, // then impact the visibility result, we need to adjust visibility before apply scale. adjustIsVisibleToUserIfNeeded(info, interactiveRegion); applyAppScaleAndMagnificationSpecIfNeeded(info, spec); callback.setFindAccessibilityNodeInfoResult(info, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ } } private boolean handleClickableSpanActionUiThread( Loading Loading @@ -1148,13 +1054,20 @@ public final class AccessibilityInteractionController { private final ArrayList<View> mTempViewList = new ArrayList<View>(); public void prefetchAccessibilityNodeInfos(View view, AccessibilityNodeInfo root, int virtualViewId, int fetchFlags, List<AccessibilityNodeInfo> outInfos) { if (root == null) { return; } public void prefetchAccessibilityNodeInfos(View view, int virtualViewId, int fetchFlags, List<AccessibilityNodeInfo> outInfos, Bundle arguments) { AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider(); // Determine if we'll be populating extra data final String extraDataRequested = (arguments == null) ? null : arguments.getString(EXTRA_DATA_REQUESTED_KEY); if (provider == null) { AccessibilityNodeInfo root = view.createAccessibilityNodeInfo(); if (root != null) { if (extraDataRequested != null) { view.addExtraDataToAccessibilityNodeInfo( root, extraDataRequested, arguments); } outInfos.add(root); if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) { prefetchPredecessorsOfRealNode(view, outInfos); } Loading @@ -1164,7 +1077,16 @@ public final class AccessibilityInteractionController { if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) { prefetchDescendantsOfRealNode(view, outInfos); } } } else { final AccessibilityNodeInfo root = provider.createAccessibilityNodeInfo(virtualViewId); if (root != null) { if (extraDataRequested != null) { provider.addExtraDataToAccessibilityNodeInfo( virtualViewId, root, extraDataRequested, arguments); } outInfos.add(root); if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) { prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos); } Loading @@ -1175,18 +1097,13 @@ public final class AccessibilityInteractionController { prefetchDescendantsOfVirtualNode(root, provider, outInfos); } } } if (ENFORCE_NODE_TREE_CONSISTENT) { enforceNodeTreeConsistent(root, outInfos); enforceNodeTreeConsistent(outInfos); } } private boolean shouldStopPrefetching(List prefetchededInfos) { return mHandler.hasUserInteractiveMessagesWaiting() || prefetchededInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE; } private void enforceNodeTreeConsistent( AccessibilityNodeInfo root, List<AccessibilityNodeInfo> nodes) { private void enforceNodeTreeConsistent(List<AccessibilityNodeInfo> nodes) { LongSparseArray<AccessibilityNodeInfo> nodeMap = new LongSparseArray<AccessibilityNodeInfo>(); final int nodeCount = nodes.size(); Loading @@ -1197,6 +1114,7 @@ public final class AccessibilityInteractionController { // If the nodes are a tree it does not matter from // which node we start to search for the root. AccessibilityNodeInfo root = nodeMap.valueAt(0); AccessibilityNodeInfo parent = root; while (parent != null) { root = parent; Loading Loading @@ -1263,11 +1181,9 @@ public final class AccessibilityInteractionController { private void prefetchPredecessorsOfRealNode(View view, List<AccessibilityNodeInfo> outInfos) { if (shouldStopPrefetching(outInfos)) { return; } ViewParent parent = view.getParentForAccessibility(); while (parent instanceof View && !shouldStopPrefetching(outInfos)) { while (parent instanceof View && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { View parentView = (View) parent; AccessibilityNodeInfo info = parentView.createAccessibilityNodeInfo(); if (info != null) { Loading @@ -1279,9 +1195,6 @@ public final class AccessibilityInteractionController { private void prefetchSiblingsOfRealNode(View current, List<AccessibilityNodeInfo> outInfos) { if (shouldStopPrefetching(outInfos)) { return; } ViewParent parent = current.getParentForAccessibility(); if (parent instanceof ViewGroup) { ViewGroup parentGroup = (ViewGroup) parent; Loading @@ -1291,7 +1204,7 @@ public final class AccessibilityInteractionController { parentGroup.addChildrenForAccessibility(children); final int childCount = children.size(); for (int i = 0; i < childCount; i++) { if (shouldStopPrefetching(outInfos)) { if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { return; } View child = children.get(i); Loading Loading @@ -1319,7 +1232,7 @@ public final class AccessibilityInteractionController { private void prefetchDescendantsOfRealNode(View root, List<AccessibilityNodeInfo> outInfos) { if (shouldStopPrefetching(outInfos) || !(root instanceof ViewGroup)) { if (!(root instanceof ViewGroup)) { return; } HashMap<View, AccessibilityNodeInfo> addedChildren = Loading @@ -1330,7 +1243,7 @@ public final class AccessibilityInteractionController { root.addChildrenForAccessibility(children); final int childCount = children.size(); for (int i = 0; i < childCount; i++) { if (shouldStopPrefetching(outInfos)) { if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { return; } View child = children.get(i); Loading @@ -1355,7 +1268,7 @@ public final class AccessibilityInteractionController { } finally { children.clear(); } if (!shouldStopPrefetching(outInfos)) { if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { for (Map.Entry<View, AccessibilityNodeInfo> entry : addedChildren.entrySet()) { View addedChild = entry.getKey(); AccessibilityNodeInfo virtualRoot = entry.getValue(); Loading @@ -1377,7 +1290,7 @@ public final class AccessibilityInteractionController { long parentNodeId = root.getParentNodeId(); int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId); while (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) { if (shouldStopPrefetching(outInfos)) { if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { return; } final int virtualDescendantId = Loading Loading @@ -1422,7 +1335,7 @@ public final class AccessibilityInteractionController { if (parent != null) { final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { if (shouldStopPrefetching(outInfos)) { if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { return; } final long childNodeId = parent.getChildId(i); Loading @@ -1447,7 +1360,7 @@ public final class AccessibilityInteractionController { final int initialOutInfosSize = outInfos.size(); final int childCount = root.getChildCount(); for (int i = 0; i < childCount; i++) { if (shouldStopPrefetching(outInfos)) { if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { return; } final long childNodeId = root.getChildId(i); Loading @@ -1457,7 +1370,7 @@ public final class AccessibilityInteractionController { outInfos.add(child); } } if (!shouldStopPrefetching(outInfos)) { if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { final int addedChildCount = outInfos.size() - initialOutInfosSize; for (int i = 0; i < addedChildCount; i++) { AccessibilityNodeInfo child = outInfos.get(initialOutInfosSize + i); Loading Loading @@ -1566,10 +1479,6 @@ public final class AccessibilityInteractionController { boolean hasAccessibilityCallback(Message message) { return message.what < FIRST_NO_ACCESSIBILITY_CALLBACK_MSG ? true : false; } boolean hasUserInteractiveMessagesWaiting() { return hasMessagesOrCallbacks(); } } private final class AddNodeInfosForViewId implements Predicate<View> { Loading