Skip to content

Commit c1d7e77

Browse files
committed
Delegate list item focus and click actions to the parent list.
Change-Id: Ie05c79f049896bfb498d4b33f0611da38f381140
1 parent 14326fd commit c1d7e77

File tree

1 file changed

+78
-0
lines changed

1 file changed

+78
-0
lines changed

core/java/android/widget/AbsListView.java

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import android.graphics.Rect;
2626
import android.graphics.drawable.Drawable;
2727
import android.graphics.drawable.TransitionDrawable;
28+
import android.os.Bundle;
2829
import android.os.Debug;
2930
import android.os.Handler;
3031
import android.os.Parcel;
@@ -57,6 +58,7 @@
5758
import android.view.ViewParent;
5859
import android.view.ViewTreeObserver;
5960
import android.view.accessibility.AccessibilityEvent;
61+
import android.view.accessibility.AccessibilityManager;
6062
import android.view.accessibility.AccessibilityNodeInfo;
6163
import android.view.animation.Interpolator;
6264
import android.view.animation.LinearInterpolator;
@@ -648,6 +650,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
648650
private int mGlowPaddingLeft;
649651
private int mGlowPaddingRight;
650652

653+
/**
654+
* Used for interacting with list items from an accessibility service.
655+
*/
656+
private ListItemAccessibilityDelegate mAccessibilityDelegate;
657+
651658
private int mLastAccessibilityScrollEventFromIndex;
652659
private int mLastAccessibilityScrollEventToIndex;
653660

@@ -2121,9 +2128,77 @@ View obtainView(int position, boolean[] isScrap) {
21212128
child.setLayoutParams(lp);
21222129
}
21232130

2131+
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
2132+
if (mAccessibilityDelegate == null) {
2133+
mAccessibilityDelegate = new ListItemAccessibilityDelegate();
2134+
}
2135+
child.setAccessibilityDelegate(mAccessibilityDelegate);
2136+
}
2137+
21242138
return child;
21252139
}
21262140

2141+
class ListItemAccessibilityDelegate extends AccessibilityDelegate {
2142+
@Override
2143+
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
2144+
super.onInitializeAccessibilityNodeInfo(host, info);
2145+
2146+
final int position = getPositionForView(host);
2147+
2148+
if (position == INVALID_POSITION) {
2149+
return;
2150+
}
2151+
2152+
if (isClickable()) {
2153+
info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
2154+
info.setClickable(true);
2155+
}
2156+
2157+
if (isLongClickable()) {
2158+
info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
2159+
info.setLongClickable(true);
2160+
}
2161+
2162+
info.addAction(AccessibilityNodeInfo.ACTION_SELECT);
2163+
2164+
if (position == getSelectedItemPosition()) {
2165+
info.setSelected(true);
2166+
}
2167+
}
2168+
2169+
@Override
2170+
public boolean performAccessibilityAction(View host, int action, Bundle arguments) {
2171+
final int position = getPositionForView(host);
2172+
2173+
if (position == INVALID_POSITION) {
2174+
return false;
2175+
}
2176+
2177+
final long id = getItemIdAtPosition(position);
2178+
2179+
switch (action) {
2180+
case AccessibilityNodeInfo.ACTION_SELECT:
2181+
setSelection(position);
2182+
return true;
2183+
case AccessibilityNodeInfo.ACTION_CLICK:
2184+
if (!super.performAccessibilityAction(host, action, arguments)) {
2185+
return performItemClick(host, position, id);
2186+
}
2187+
return true;
2188+
case AccessibilityNodeInfo.ACTION_LONG_CLICK:
2189+
if (!super.performAccessibilityAction(host, action, arguments)) {
2190+
return performLongPress(host, position, id);
2191+
}
2192+
return true;
2193+
case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
2194+
smoothScrollToPosition(position);
2195+
break;
2196+
}
2197+
2198+
return super.performAccessibilityAction(host, action, arguments);
2199+
}
2200+
}
2201+
21272202
void positionSelector(int position, View sel) {
21282203
if (position != INVALID_POSITION) {
21292204
mSelectorPosition = position;
@@ -5651,6 +5726,7 @@ public void reclaimViews(List<View> views) {
56515726
// Don't reclaim header or footer views, or views that should be ignored
56525727
if (lp != null && mRecycler.shouldRecycleViewType(lp.viewType)) {
56535728
views.add(child);
5729+
child.setAccessibilityDelegate(null);
56545730
if (listener != null) {
56555731
// Pretend they went through the scrap heap
56565732
listener.onMovedToScrapHeap(child);
@@ -6206,6 +6282,7 @@ void addScrapView(View scrap, int position) {
62066282
mScrapViews[viewType].add(scrap);
62076283
}
62086284

6285+
scrap.setAccessibilityDelegate(null);
62096286
if (mRecyclerListener != null) {
62106287
mRecyclerListener.onMovedToScrapHeap(scrap);
62116288
}
@@ -6267,6 +6344,7 @@ void scrapActiveViews() {
62676344
lp.scrappedFromPosition = mFirstActivePosition + i;
62686345
scrapViews.add(victim);
62696346

6347+
victim.setAccessibilityDelegate(null);
62706348
if (hasListener) {
62716349
mRecyclerListener.onMovedToScrapHeap(victim);
62726350
}

0 commit comments

Comments
 (0)