Skip to content

Commit d9ee72f

Browse files
committed
Fixing errors in position information of scrollable views reported for accessibility.
1. ScrollView/HorizontalScroll view were reporting only the scroll X and Y but failed to convey the max scroll along X and Y so the position can be determined. 2. WebView was not reporting correctly its scroll position for accessibility. 3. Some descendants of AdapterView were reporting incorrect position information. 4. Updated the accessibility docs with some details about the scroll information. 5. Cleaned up duplicated code. bug:5412132 bug:5412265 Change-Id: I165e73ecde027dad811425b9f395a3f758c923ba
1 parent e921572 commit d9ee72f

File tree

10 files changed

+212
-125
lines changed

10 files changed

+212
-125
lines changed

core/java/android/view/View.java

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4001,23 +4001,13 @@ void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
40014001
event.setEnabled(isEnabled());
40024002
event.setContentDescription(mContentDescription);
40034003

4004-
final int eventType = event.getEventType();
4005-
switch (eventType) {
4006-
case AccessibilityEvent.TYPE_VIEW_FOCUSED: {
4007-
if (mAttachInfo != null) {
4008-
ArrayList<View> focusablesTempList = mAttachInfo.mFocusablesTempList;
4009-
getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD,
4010-
FOCUSABLES_ALL);
4011-
event.setItemCount(focusablesTempList.size());
4012-
event.setCurrentItemIndex(focusablesTempList.indexOf(this));
4013-
focusablesTempList.clear();
4014-
}
4015-
} break;
4016-
case AccessibilityEvent.TYPE_VIEW_SCROLLED: {
4017-
event.setScrollX(mScrollX);
4018-
event.setScrollY(mScrollY);
4019-
event.setItemCount(getHeight());
4020-
} break;
4004+
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED && mAttachInfo != null) {
4005+
ArrayList<View> focusablesTempList = mAttachInfo.mFocusablesTempList;
4006+
getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD,
4007+
FOCUSABLES_ALL);
4008+
event.setItemCount(focusablesTempList.size());
4009+
event.setCurrentItemIndex(focusablesTempList.indexOf(this));
4010+
focusablesTempList.clear();
40214011
}
40224012
}
40234013

core/java/android/view/accessibility/AccessibilityEvent.java

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@
7979
* <li>{@link #isPassword()} - Whether the source is password.</li>
8080
* <li>{@link #isChecked()} - Whether the source is checked.</li>
8181
* <li>{@link #getContentDescription()} - The content description of the source.</li>
82+
* <li>{@link #getScrollX()} - The offset of the source left edge in pixels
83+
* (without descendants of AdapterView).</li>
84+
* <li>{@link #getScrollY()} - The offset of the source top edge in pixels
85+
* (without descendants of AdapterView).</li>
86+
* <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
87+
* inclusive (for descendants of AdapterView).</li>
88+
* <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
89+
* inclusive (for descendants of AdapterView).</li>
90+
* <li>{@link #getItemCount()} - The total items of the source
91+
* (for descendants of AdapterView).</li>
8292
* </ul>
8393
* </p>
8494
* <p>
@@ -97,6 +107,16 @@
97107
* <li>{@link #isPassword()} - Whether the source is password.</li>
98108
* <li>{@link #isChecked()} - Whether the source is checked.</li>
99109
* <li>{@link #getContentDescription()} - The content description of the source.</li>
110+
* <li>{@link #getScrollX()} - The offset of the source left edge in pixels
111+
* (without descendants of AdapterView).</li>
112+
* <li>{@link #getScrollY()} - The offset of the source top edge in pixels
113+
* (without descendants of AdapterView).</li>
114+
* <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
115+
* inclusive (for descendants of AdapterView).</li>
116+
* <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
117+
* inclusive (for descendants of AdapterView).</li>
118+
* <li>{@link #getItemCount()} - The total items of the source
119+
* (for descendants of AdapterView).</li>
100120
* </ul>
101121
* </p>
102122
* <p>
@@ -117,6 +137,16 @@
117137
* <li>{@link #getItemCount()} - The number of selectable items of the source.</li>
118138
* <li>{@link #getCurrentItemIndex()} - The currently selected item index.</li>
119139
* <li>{@link #getContentDescription()} - The content description of the source.</li>
140+
* <li>{@link #getScrollX()} - The offset of the source left edge in pixels
141+
* (without descendants of AdapterView).</li>
142+
* <li>{@link #getScrollY()} - The offset of the source top edge in pixels
143+
* (without descendants of AdapterView).</li>
144+
* <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
145+
* inclusive (for descendants of AdapterView).</li>
146+
* <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
147+
* inclusive (for descendants of AdapterView).</li>
148+
* <li>{@link #getItemCount()} - The total items of the source
149+
* (for descendants of AdapterView).</li>
120150
* </ul>
121151
* </p>
122152
* <p>
@@ -137,6 +167,16 @@
137167
* <li>{@link #getItemCount()} - The number of focusable items on the screen.</li>
138168
* <li>{@link #getCurrentItemIndex()} - The currently focused item index.</li>
139169
* <li>{@link #getContentDescription()} - The content description of the source.</li>
170+
* <li>{@link #getScrollX()} - The offset of the source left edge in pixels
171+
* (without descendants of AdapterView).</li>
172+
* <li>{@link #getScrollY()} - The offset of the source top edge in pixels
173+
* (without descendants of AdapterView).</li>
174+
* <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
175+
* inclusive (for descendants of AdapterView).</li>
176+
* <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
177+
* inclusive (for descendants of AdapterView).</li>
178+
* <li>{@link #getItemCount()} - The total items of the source
179+
* (for descendants of AdapterView).</li>
140180
* </ul>
141181
* </p>
142182
* <p>
@@ -218,18 +258,17 @@
218258
* <li>{@link #getEventTime()} - The event time.</li>
219259
* <li>{@link #getText()} - The text of the source's sub-tree.</li>
220260
* <li>{@link #isEnabled()} - Whether the source is enabled.</li>
221-
* <li>{@link #getScrollX()} - The horizontal offset of the source
222-
* (without descendants of AdapterView)).</li>
223-
* <li>{@link #getScrollY()} - The vertical offset of the source
224-
* (without descendants of AdapterView)).</li>
225-
* <li>{@link #getFromIndex()} - The index of the first visible item of the source
226-
* (for descendants of AdapterView).</li>
227-
* <li>{@link #getToIndex()} - The index of the last visible item of the source
228-
* (for descendants of AdapterView).</li>
229-
* <li>{@link #getItemCount()} - The total items of the source (for descendants of AdapterView)
230-
* or the height of the source in pixels (all other cases).</li>
231-
* <li>{@link #getText()} - Text for providing more context.</li>
232261
* <li>{@link #getContentDescription()} - The content description of the source.</li>
262+
* <li>{@link #getScrollX()} - The offset of the source left edge in pixels
263+
* (without descendants of AdapterView).</li>
264+
* <li>{@link #getScrollY()} - The offset of the source top edge in pixels
265+
* (without descendants of AdapterView).</li>
266+
* <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
267+
* inclusive (for descendants of AdapterView).</li>
268+
* <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
269+
* inclusive (for descendants of AdapterView).</li>
270+
* <li>{@link #getItemCount()} - The total items of the source
271+
* (for descendants of AdapterView).</li>
233272
* </ul>
234273
* <em>Note:</em> This event type is not dispatched to descendants though
235274
* {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
@@ -334,6 +373,16 @@
334373
* <li>{@link #getText()} - The text of the source's sub-tree.</li>
335374
* <li>{@link #isEnabled()} - Whether the source is enabled.</li>
336375
* <li>{@link #getContentDescription()} - The content description of the source.</li>
376+
* <li>{@link #getScrollX()} - The offset of the source left edge in pixels
377+
* (without descendants of AdapterView).</li>
378+
* <li>{@link #getScrollY()} - The offset of the source top edge in pixels
379+
* (without descendants of AdapterView).</li>
380+
* <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
381+
* inclusive (for descendants of AdapterView).</li>
382+
* <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
383+
* inclusive (for descendants of AdapterView).</li>
384+
* <li>{@link #getItemCount()} - The total items of the source
385+
* (for descendants of AdapterView).</li>
337386
* </ul>
338387
* </p>
339388
* <b>View hover exit</b> - represents the event of stopping to hover
@@ -350,6 +399,16 @@
350399
* <li>{@link #getText()} - The text of the source's sub-tree.</li>
351400
* <li>{@link #isEnabled()} - Whether the source is enabled.</li>
352401
* <li>{@link #getContentDescription()} - The content description of the source.</li>
402+
* <li>{@link #getScrollX()} - The offset of the source left edge in pixels
403+
* (without descendants of AdapterView).</li>
404+
* <li>{@link #getScrollY()} - The offset of the source top edge in pixels
405+
* (without descendants of AdapterView).</li>
406+
* <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
407+
* inclusive (for descendants of AdapterView).</li>
408+
* <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
409+
* inclusive (for descendants of AdapterView).</li>
410+
* <li>{@link #getItemCount()} - The total items of the source
411+
* (for descendants of AdapterView).</li>
353412
* </ul>
354413
* </p>
355414
* <p>
@@ -816,6 +875,8 @@ private void readAccessibilityRecordFromParcel(AccessibilityRecord record,
816875
record.mToIndex = parcel.readInt();
817876
record.mScrollX = parcel.readInt();
818877
record.mScrollY = parcel.readInt();
878+
record.mMaxScrollX = parcel.readInt();
879+
record.mMaxScrollY = parcel.readInt();
819880
record.mAddedCount = parcel.readInt();
820881
record.mRemovedCount = parcel.readInt();
821882
record.mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
@@ -868,6 +929,8 @@ private void writeAccessibilityRecordToParcel(AccessibilityRecord record, Parcel
868929
parcel.writeInt(record.mToIndex);
869930
parcel.writeInt(record.mScrollX);
870931
parcel.writeInt(record.mScrollY);
932+
parcel.writeInt(record.mMaxScrollX);
933+
parcel.writeInt(record.mMaxScrollY);
871934
parcel.writeInt(record.mAddedCount);
872935
parcel.writeInt(record.mRemovedCount);
873936
TextUtils.writeToParcel(record.mClassName, parcel, flags);

core/java/android/view/accessibility/AccessibilityRecord.java

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ public class AccessibilityRecord {
7373
int mToIndex = UNDEFINED;
7474
int mScrollX = UNDEFINED;
7575
int mScrollY = UNDEFINED;
76+
int mMaxScrollX = UNDEFINED;
77+
int mMaxScrollY = UNDEFINED;
7678

7779
int mAddedCount= UNDEFINED;
7880
int mRemovedCount = UNDEFINED;
@@ -348,43 +350,88 @@ public void setToIndex(int toIndex) {
348350
}
349351

350352
/**
351-
* Gets the scroll position of the source along the X axis.
353+
* Gets the scroll offset of the source left edge in pixels.
352354
*
353-
* @return The scroll along the X axis.
355+
* @return The scroll.
354356
*/
355357
public int getScrollX() {
356358
return mScrollX;
357359
}
358360

359361
/**
360-
* Sets the scroll position of the source along the X axis.
362+
* Sets the scroll offset of the source left edge in pixels.
361363
*
362-
* @param scrollX The scroll along the X axis.
364+
* @param scrollX The scroll.
363365
*/
364366
public void setScrollX(int scrollX) {
365367
enforceNotSealed();
366368
mScrollX = scrollX;
367369
}
368370

369371
/**
370-
* Gets the scroll position of the source along the Y axis.
372+
* Gets the scroll offset of the source top edge in pixels.
371373
*
372-
* @return The scroll along the Y axis.
374+
* @return The scroll.
373375
*/
374376
public int getScrollY() {
375377
return mScrollY;
376378
}
377379

378380
/**
379-
* Sets the scroll position of the source along the Y axis.
381+
* Sets the scroll offset of the source top edge in pixels.
380382
*
381-
* @param scrollY The scroll along the Y axis.
383+
* @param scrollY The scroll.
382384
*/
383385
public void setScrollY(int scrollY) {
384386
enforceNotSealed();
385387
mScrollY = scrollY;
386388
}
387389

390+
/**
391+
* Gets the max scroll offset of the source left edge in pixels.
392+
*
393+
* @return The max scroll.
394+
*
395+
* @hide
396+
*/
397+
public int getMaxScrollX() {
398+
return mMaxScrollX;
399+
}
400+
/**
401+
* Sets the max scroll offset of the source left edge in pixels.
402+
*
403+
* @param maxScrollX The max scroll.
404+
*
405+
* @hide
406+
*/
407+
public void setMaxScrollX(int maxScrollX) {
408+
enforceNotSealed();
409+
mMaxScrollX = maxScrollX;
410+
}
411+
412+
/**
413+
* Gets the max scroll offset of the source top edge in pixels.
414+
*
415+
* @return The max scroll.
416+
*
417+
* @hide
418+
*/
419+
public int getMaxScrollY() {
420+
return mMaxScrollY;
421+
}
422+
423+
/**
424+
* Sets the max scroll offset of the source top edge in pixels.
425+
*
426+
* @param maxScrollY The max scroll.
427+
*
428+
* @hide
429+
*/
430+
public void setMaxScrollY(int maxScrollY) {
431+
enforceNotSealed();
432+
mMaxScrollY = maxScrollY;
433+
}
434+
388435
/**
389436
* Gets the number of added characters.
390437
*
@@ -658,6 +705,8 @@ void init(AccessibilityRecord record) {
658705
mToIndex = record.mToIndex;
659706
mScrollX = record.mScrollX;
660707
mScrollY = record.mScrollY;
708+
mMaxScrollX = record.mMaxScrollX;
709+
mMaxScrollY = record.mMaxScrollY;
661710
mAddedCount = record.mAddedCount;
662711
mRemovedCount = record.mRemovedCount;
663712
mClassName = record.mClassName;
@@ -682,6 +731,8 @@ void clear() {
682731
mToIndex = UNDEFINED;
683732
mScrollX = UNDEFINED;
684733
mScrollY = UNDEFINED;
734+
mMaxScrollX = UNDEFINED;
735+
mMaxScrollY = UNDEFINED;
685736
mAddedCount = UNDEFINED;
686737
mRemovedCount = UNDEFINED;
687738
mClassName = null;
@@ -711,6 +762,8 @@ public String toString() {
711762
builder.append("; ToIndex: " + mToIndex);
712763
builder.append("; ScrollX: " + mScrollX);
713764
builder.append("; ScrollY: " + mScrollY);
765+
builder.append("; MaxScrollX: " + mMaxScrollX);
766+
builder.append("; MaxScrollY: " + mMaxScrollY);
714767
builder.append("; AddedCount: " + mAddedCount);
715768
builder.append("; RemovedCount: " + mRemovedCount);
716769
builder.append("; ParcelableData: " + mParcelableData);

core/java/android/webkit/WebView.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@
7777
import android.view.ViewGroup;
7878
import android.view.ViewParent;
7979
import android.view.ViewTreeObserver;
80+
import android.view.accessibility.AccessibilityEvent;
8081
import android.view.accessibility.AccessibilityManager;
82+
import android.view.accessibility.AccessibilityNodeInfo;
8183
import android.view.inputmethod.EditorInfo;
8284
import android.view.inputmethod.InputConnection;
8385
import android.view.inputmethod.InputMethodManager;
@@ -1302,6 +1304,31 @@ private void removeAccessibilityApisFromJavaScript() {
13021304
}
13031305
}
13041306

1307+
@Override
1308+
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
1309+
super.onInitializeAccessibilityNodeInfo(info);
1310+
info.setScrollable(isScrollableForAccessibility());
1311+
}
1312+
1313+
@Override
1314+
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1315+
super.onInitializeAccessibilityEvent(event);
1316+
event.setScrollable(isScrollableForAccessibility());
1317+
event.setScrollX(mScrollX);
1318+
event.setScrollY(mScrollY);
1319+
final int convertedContentWidth = contentToViewX(getContentWidth());
1320+
final int adjustedViewWidth = getWidth() - mPaddingLeft - mPaddingRight;
1321+
event.setMaxScrollX(Math.max(convertedContentWidth - adjustedViewWidth, 0));
1322+
final int convertedContentHeight = contentToViewY(getContentHeight());
1323+
final int adjustedViewHeight = getHeight() - mPaddingTop - mPaddingBottom;
1324+
event.setMaxScrollY(Math.max(convertedContentHeight - adjustedViewHeight, 0));
1325+
}
1326+
1327+
private boolean isScrollableForAccessibility() {
1328+
return (contentToViewX(getContentWidth()) > getWidth() - mPaddingLeft - mPaddingRight
1329+
|| contentToViewY(getContentHeight()) > getHeight() - mPaddingTop - mPaddingBottom);
1330+
}
1331+
13051332
@Override
13061333
public void setOverScrollMode(int mode) {
13071334
super.setOverScrollMode(mode);

0 commit comments

Comments
 (0)