Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 390a06b8 authored by Svetoslav Ganov's avatar Svetoslav Ganov Committed by Android (Google) Code Review
Browse files

Merge "Restore accessibility focus after ListView layout." into jb-mr1-dev

parents 6543c292 30ee76cf
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
@@ -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;
@@ -1490,6 +1491,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 +1589,25 @@ public class ListView extends AbsListView {
                requestFocus();
            }

            // Remember which child, if any, had accessibility focus.
            final View accessFocusedView = getViewRootImpl().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 = getViewRootImpl()
                                .getAccessibilityFocusedVirtualView();
                    } else {
                        // Otherwise, try to maintain focus at the same position.
                        accessibilityFocusPosition = getPositionForView(accessFocusedChild);
                    }
                }
            }

            // Clear out old views
            detachAllViewsFromParent();
            recycleBin.removeSkippedScrap();
@@ -1682,6 +1706,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
@@ -1712,6 +1752,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.