Skip to content

Commit 0a1bb6d

Browse files
committed
AccessibilityNodeInfo for visible views should reported.
1. AccessibilityNodeInfos for visible views should always be reported and the clients should be able to check whether that node info is shown to the user. For example, focus search may return a node that is not on the screen and the accessibility layer may decide to give it focus which scroll the source view in the screen. bug:6421991 Change-Id: Idc1fd8512dda767abe802aacedb0c69582e6fc2a
1 parent 2551e5a commit 0a1bb6d

File tree

4 files changed

+104
-17
lines changed

4 files changed

+104
-17
lines changed

api/current.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25181,6 +25181,7 @@ package android.view.accessibility {
2518125181
method public boolean isPassword();
2518225182
method public boolean isScrollable();
2518325183
method public boolean isSelected();
25184+
method public boolean isVisibleToUser();
2518425185
method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
2518525186
method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int);
2518625187
method public static android.view.accessibility.AccessibilityNodeInfo obtain();
@@ -25210,6 +25211,7 @@ package android.view.accessibility {
2521025211
method public void setSource(android.view.View);
2521125212
method public void setSource(android.view.View, int);
2521225213
method public void setText(java.lang.CharSequence);
25214+
method public void setVisibleToUser(boolean);
2521325215
method public void writeToParcel(android.os.Parcel, int);
2521425216
field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
2521525217
field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";

core/java/android/view/AccessibilityInteractionController.java

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ private void clear() {
126126
}
127127
}
128128

129+
private boolean isShown(View view) {
130+
// The first two checks are made also made by isShown() which
131+
// however traverses the tree up to the parent to catch that.
132+
// Therefore, we do some fail fast check to minimize the up
133+
// tree traversal.
134+
return (view.mAttachInfo != null
135+
&& view.mAttachInfo.mWindowVisibility == View.VISIBLE
136+
&& view.isShown());
137+
}
138+
129139
public void findAccessibilityNodeInfoByAccessibilityIdClientThread(
130140
long accessibilityNodeId, int interactionId,
131141
IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
@@ -174,7 +184,7 @@ private void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message)
174184
} else {
175185
root = findViewByAccessibilityId(accessibilityViewId);
176186
}
177-
if (root != null && root.isDisplayedOnScreen()) {
187+
if (root != null && isShown(root)) {
178188
mPrefetcher.prefetchAccessibilityNodeInfos(root, virtualDescendantId, flags, infos);
179189
}
180190
} finally {
@@ -236,7 +246,7 @@ private void findAccessibilityNodeInfoByViewIdUiThread(Message message) {
236246
}
237247
if (root != null) {
238248
View target = root.findViewById(viewId);
239-
if (target != null && target.isDisplayedOnScreen()) {
249+
if (target != null && isShown(target)) {
240250
info = target.createAccessibilityNodeInfo();
241251
}
242252
}
@@ -298,7 +308,7 @@ private void findAccessibilityNodeInfosByTextUiThread(Message message) {
298308
} else {
299309
root = mViewRootImpl.mView;
300310
}
301-
if (root != null && root.isDisplayedOnScreen()) {
311+
if (root != null && isShown(root)) {
302312
AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider();
303313
if (provider != null) {
304314
infos = provider.findAccessibilityNodeInfosByText(text,
@@ -315,7 +325,7 @@ private void findAccessibilityNodeInfosByTextUiThread(Message message) {
315325
final int viewCount = foundViews.size();
316326
for (int i = 0; i < viewCount; i++) {
317327
View foundView = foundViews.get(i);
318-
if (foundView.isDisplayedOnScreen()) {
328+
if (isShown(foundView)) {
319329
provider = foundView.getAccessibilityNodeProvider();
320330
if (provider != null) {
321331
List<AccessibilityNodeInfo> infosFromProvider =
@@ -390,7 +400,7 @@ private void findFocusUiThread(Message message) {
390400
} else {
391401
root = mViewRootImpl.mView;
392402
}
393-
if (root != null && root.isDisplayedOnScreen()) {
403+
if (root != null && isShown(root)) {
394404
switch (focusType) {
395405
case AccessibilityNodeInfo.FOCUS_ACCESSIBILITY: {
396406
View host = mViewRootImpl.mAccessibilityFocusedHost;
@@ -411,7 +421,7 @@ private void findFocusUiThread(Message message) {
411421
case AccessibilityNodeInfo.FOCUS_INPUT: {
412422
// Input focus cannot go to virtual views.
413423
View target = root.findFocus();
414-
if (target != null && target.isDisplayedOnScreen()) {
424+
if (target != null && isShown(target)) {
415425
focused = target.createAccessibilityNodeInfo();
416426
}
417427
} break;
@@ -477,7 +487,7 @@ private void focusSearchUiThread(Message message) {
477487
} else {
478488
root = mViewRootImpl.mView;
479489
}
480-
if (root != null && root.isDisplayedOnScreen()) {
490+
if (root != null && isShown(root)) {
481491
if ((direction & View.FOCUS_ACCESSIBILITY) == View.FOCUS_ACCESSIBILITY) {
482492
AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider();
483493
if (provider != null) {
@@ -565,7 +575,7 @@ private void perfromAccessibilityActionUiThread(Message message) {
565575
} else {
566576
target = mViewRootImpl.mView;
567577
}
568-
if (target != null && target.isDisplayedOnScreen()) {
578+
if (target != null && isShown(target)) {
569579
AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
570580
if (provider != null) {
571581
succeeded = provider.performAction(virtualDescendantId, action,
@@ -590,7 +600,7 @@ private View findViewByAccessibilityId(int accessibilityId) {
590600
return null;
591601
}
592602
View foundView = root.findViewByAccessibilityId(accessibilityId);
593-
if (foundView != null && !foundView.isDisplayedOnScreen()) {
603+
if (foundView != null && !isShown(foundView)) {
594604
return null;
595605
}
596606
return foundView;
@@ -670,7 +680,7 @@ private void prefetchSiblingsOfRealNode(View current,
670680
}
671681
View child = children.getChildAt(i);
672682
if (child.getAccessibilityViewId() != current.getAccessibilityViewId()
673-
&& child.isDisplayedOnScreen()) {
683+
&& isShown(child)) {
674684
AccessibilityNodeInfo info = null;
675685
AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
676686
if (provider == null) {
@@ -706,7 +716,7 @@ private void prefetchDescendantsOfRealNode(View root,
706716
return;
707717
}
708718
View child = children.getChildAt(i);
709-
if (child.isDisplayedOnScreen()) {
719+
if (isShown(child)) {
710720
AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
711721
if (provider == null) {
712722
AccessibilityNodeInfo info = child.createAccessibilityNodeInfo();

core/java/android/view/View.java

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4656,6 +4656,51 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
46564656
}
46574657
}
46584658

4659+
/**
4660+
* Gets the location of this view in screen coordintates.
4661+
*
4662+
* @param outRect The output location
4663+
*/
4664+
private void getBoundsOnScreen(Rect outRect) {
4665+
if (mAttachInfo == null) {
4666+
return;
4667+
}
4668+
4669+
RectF position = mAttachInfo.mTmpTransformRect;
4670+
position.setEmpty();
4671+
4672+
if (!hasIdentityMatrix()) {
4673+
getMatrix().mapRect(position);
4674+
}
4675+
4676+
position.offset(mLeft, mRight);
4677+
4678+
ViewParent parent = mParent;
4679+
while (parent instanceof View) {
4680+
View parentView = (View) parent;
4681+
4682+
position.offset(-parentView.mScrollX, -parentView.mScrollY);
4683+
4684+
if (!parentView.hasIdentityMatrix()) {
4685+
parentView.getMatrix().mapRect(position);
4686+
}
4687+
4688+
position.offset(parentView.mLeft, parentView.mTop);
4689+
4690+
parent = parentView.mParent;
4691+
}
4692+
4693+
if (parent instanceof ViewRootImpl) {
4694+
ViewRootImpl viewRootImpl = (ViewRootImpl) parent;
4695+
position.offset(0, -viewRootImpl.mCurScrollY);
4696+
}
4697+
4698+
position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
4699+
4700+
outRect.set((int) (position.left + 0.5f), (int) (position.top + 0.5f),
4701+
(int) (position.right + 0.5f), (int) (position.bottom + 0.5f));
4702+
}
4703+
46594704
/**
46604705
* @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
46614706
*
@@ -4666,8 +4711,7 @@ void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
46664711
getDrawingRect(bounds);
46674712
info.setBoundsInParent(bounds);
46684713

4669-
getGlobalVisibleRect(bounds);
4670-
bounds.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
4714+
getBoundsOnScreen(bounds);
46714715
info.setBoundsInScreen(bounds);
46724716

46734717
if ((mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
@@ -4677,6 +4721,8 @@ void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
46774721
}
46784722
}
46794723

4724+
info.setVisibleToUser(isVisibleToUser());
4725+
46804726
info.setPackageName(mContext.getPackageName());
46814727
info.setClassName(View.class.getName());
46824728
info.setContentDescription(getContentDescription());
@@ -4723,11 +4769,13 @@ void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
47234769
}
47244770

47254771
/**
4726-
* Computes whether this view is visible on the screen.
4772+
* Computes whether this view is visible to the user. Such a view is
4773+
* attached, visible, all its predecessors are visible, it is not clipped
4774+
* entirely by its predecessors, and has an alpha greater than zero.
47274775
*
47284776
* @return Whether the view is visible on the screen.
47294777
*/
4730-
boolean isDisplayedOnScreen() {
4778+
private boolean isVisibleToUser() {
47314779
// The first two checks are made also made by isShown() which
47324780
// however traverses the tree up to the parent to catch that.
47334781
// Therefore, we do some fail fast check to minimize the up
@@ -6377,9 +6425,9 @@ public void addChildrenForAccessibility(ArrayList<View> children) {
63776425
boolean includeForAccessibility() {
63786426
if (mAttachInfo != null) {
63796427
if (!mAttachInfo.mIncludeNotImportantViews) {
6380-
return isImportantForAccessibility() && isDisplayedOnScreen();
6428+
return isImportantForAccessibility();
63816429
} else {
6382-
return isDisplayedOnScreen();
6430+
return true;
63836431
}
63846432
}
63856433
return false;

core/java/android/view/accessibility/AccessibilityNodeInfo.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,8 @@ public class AccessibilityNodeInfo implements Parcelable {
287287

288288
private static final int PROPERTY_ACCESSIBILITY_FOCUSED = 0x00000400;
289289

290+
private static final int PROPERTY_VISIBLE_TO_USER = 0x00000800;
291+
290292
/**
291293
* Bits that provide the id of a virtual descendant of a view.
292294
*/
@@ -909,6 +911,31 @@ public void setFocused(boolean focused) {
909911
setBooleanProperty(PROPERTY_FOCUSED, focused);
910912
}
911913

914+
/**
915+
* Sets whether this node is visible to the user.
916+
*
917+
* @return Whether the node is visible to the user.
918+
*/
919+
public boolean isVisibleToUser() {
920+
return getBooleanProperty(PROPERTY_VISIBLE_TO_USER);
921+
}
922+
923+
/**
924+
* Sets whether this node is visible to the user.
925+
* <p>
926+
* <strong>Note:</strong> Cannot be called from an
927+
* {@link android.accessibilityservice.AccessibilityService}.
928+
* This class is made immutable before being delivered to an AccessibilityService.
929+
* </p>
930+
*
931+
* @param visibleToUser Whether the node is visible to the user.
932+
*
933+
* @throws IllegalStateException If called from an AccessibilityService.
934+
*/
935+
public void setVisibleToUser(boolean visibleToUser) {
936+
setBooleanProperty(PROPERTY_VISIBLE_TO_USER, visibleToUser);
937+
}
938+
912939
/**
913940
* Gets whether this node is accessibility focused.
914941
*

0 commit comments

Comments
 (0)