diff options
Diffstat (limited to 'core/java/android/widget/ListView.java')
-rw-r--r-- | core/java/android/widget/ListView.java | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index e011c13..03507b5 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -29,6 +29,7 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.util.MathUtils; import android.util.SparseBooleanArray; import android.view.FocusFinder; import android.view.KeyEvent; @@ -37,6 +38,7 @@ import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup; import android.view.ViewParent; +import android.view.ViewRootImpl; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.RemoteViews.RemoteView; @@ -1490,6 +1492,10 @@ public class ListView extends AbsListView { View focusLayoutRestoreView = null; + AccessibilityNodeInfo accessibilityFocusLayoutRestoreNode = null; + View accessibilityFocusLayoutRestoreView = null; + int accessibilityFocusPosition = INVALID_POSITION; + // Remember stuff we will need down below switch (mLayoutMode) { case LAYOUT_SET_SELECTION: @@ -1584,6 +1590,30 @@ public class ListView extends AbsListView { requestFocus(); } + // Remember which child, if any, had accessibility focus. + final ViewRootImpl viewRootImpl = getViewRootImpl(); + if (viewRootImpl != null) { + final View accessFocusedView = viewRootImpl.getAccessibilityFocusedHost(); + if (accessFocusedView != null) { + final View accessFocusedChild = findAccessibilityFocusedChild( + accessFocusedView); + if (accessFocusedChild != null) { + if (!dataChanged || isDirectChildHeaderOrFooter(accessFocusedChild)) { + // If the views won't be changing, try to maintain + // focus on the current view host and (if + // applicable) its virtual view. + accessibilityFocusLayoutRestoreView = accessFocusedView; + accessibilityFocusLayoutRestoreNode = viewRootImpl + .getAccessibilityFocusedVirtualView(); + } else { + // Otherwise, try to maintain focus at the same + // position. + accessibilityFocusPosition = getPositionForView(accessFocusedChild); + } + } + } + } + // Clear out old views detachAllViewsFromParent(); recycleBin.removeSkippedScrap(); @@ -1682,6 +1712,22 @@ public class ListView extends AbsListView { } } + // Attempt to restore accessibility focus. + if (accessibilityFocusLayoutRestoreNode != null) { + accessibilityFocusLayoutRestoreNode.performAction( + AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); + } else if (accessibilityFocusLayoutRestoreView != null) { + accessibilityFocusLayoutRestoreView.requestAccessibilityFocus(); + } else if (accessibilityFocusPosition != INVALID_POSITION) { + // Bound the position within the visible children. + final int position = MathUtils.constrain( + (accessibilityFocusPosition - mFirstPosition), 0, (getChildCount() - 1)); + final View restoreView = getChildAt(position); + if (restoreView != null) { + restoreView.requestAccessibilityFocus(); + } + } + // tell focus view we are done mucking with it, if it is still in // our view hierarchy. if (focusLayoutRestoreView != null @@ -1713,6 +1759,22 @@ public class ListView extends AbsListView { } /** + * @param focusedView the view that has accessibility focus. + * @return the direct child that contains accessibility focus. + */ + private View findAccessibilityFocusedChild(View focusedView) { + ViewParent viewParent = focusedView.getParent(); + while ((viewParent instanceof View) && (viewParent != this)) { + focusedView = (View) viewParent; + viewParent = viewParent.getParent(); + } + if (!(viewParent instanceof View)) { + return null; + } + return focusedView; + } + + /** * @param child a direct child of this list. * @return Whether child is a header or footer view. */ |