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

Commit 7906d47f authored by Evan Rosky's avatar Evan Rosky Committed by Android (Google) Code Review
Browse files

Merge "Ignore nested keyboard navigation clusters" into oc-dev

parents 7fa4198a 0e8a6832
Loading
Loading
Loading
Loading
+10 −7
Original line number Diff line number Diff line
@@ -127,20 +127,23 @@ public class FocusFinder {
        if (focused == null || focused == root) {
            return root;
        }
        ViewParent effective = focused.getParent();
        ViewGroup effective = null;
        ViewParent nextParent = focused.getParent();
        do {
            if (effective == root) {
                return root;
            if (nextParent == root) {
                return effective != null ? effective : root;
            }
            ViewGroup vg = (ViewGroup) effective;
            ViewGroup vg = (ViewGroup) nextParent;
            if (vg.getTouchscreenBlocksFocus()
                    && focused.getContext().getPackageManager().hasSystemFeature(
                            PackageManager.FEATURE_TOUCHSCREEN)
                    && vg.isKeyboardNavigationCluster()) {
                return vg;
                // Don't stop and return here because the cluster could be nested and we only
                // care about the top-most one.
                effective = vg;
            }
            effective = effective.getParent();
        } while (effective != null);
            nextParent = nextParent.getParent();
        } while (nextParent instanceof ViewGroup);
        return root;
    }

+33 −3
Original line number Diff line number Diff line
@@ -9767,6 +9767,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0;
    }
    /**
     * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters
     * will be ignored.
     *
     * @return the keyboard navigation cluster that this view is in (can be this view)
     *         or {@code null} if not in one
     */
    View findKeyboardNavigationCluster() {
        if (mParent instanceof View) {
            View cluster = ((View) mParent).findKeyboardNavigationCluster();
            if (cluster != null) {
                return cluster;
            } else if (isKeyboardNavigationCluster()) {
                return this;
            }
        }
        return null;
    }
    /**
     * Set whether this view is a root of a keyboard navigation cluster.
     *
@@ -9789,9 +9808,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     *
     * @hide
     */
    public void setFocusedInCluster() {
        if (mParent instanceof ViewGroup) {
            ((ViewGroup) mParent).setFocusInCluster(this);
    public final void setFocusedInCluster() {
        View top = findKeyboardNavigationCluster();
        if (top == this) {
            return;
        }
        ViewParent parent = mParent;
        View child = this;
        while (parent instanceof ViewGroup) {
            ((ViewGroup) parent).setFocusedInCluster(child);
            if (parent == top) {
                return;
            }
            child = (View) parent;
            parent = parent.getParent();
        }
    }
+22 −28
Original line number Diff line number Diff line
@@ -807,33 +807,27 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        return mDefaultFocus != null || super.hasDefaultFocus();
    }

    void setFocusInCluster(View child) {
        // Stop at the root of the cluster
        if (child.isKeyboardNavigationCluster()) {
            return;
        }

    void setFocusedInCluster(View child) {
        mFocusedInCluster = child;

        if (mParent instanceof ViewGroup) {
            ((ViewGroup) mParent).setFocusInCluster(this);
        }
    }

    void clearFocusInCluster(View child) {
    /**
     * Removes {@code child} (and associated focusedInCluster chain) from the cluster containing
     * it.
     * <br>
     * This is intended to be run on {@code child}'s immediate parent. This is necessary because
     * the chain is sometimes cleared after {@code child} has been detached.
     */
    void clearFocusedInCluster(View child) {
        if (mFocusedInCluster != child) {
            return;
        }

        if (child.isKeyboardNavigationCluster()) {
            return;
        }

        mFocusedInCluster = null;

        if (mParent instanceof ViewGroup) {
            ((ViewGroup) mParent).clearFocusInCluster(this);
        }
        View top = findKeyboardNavigationCluster();
        ViewParent parent = this;
        do {
            ((ViewGroup) parent).mFocusedInCluster = null;
            parent = parent.getParent();
        } while (parent != top && parent instanceof ViewGroup);
    }

    @Override
@@ -1281,7 +1275,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    public void setTouchscreenBlocksFocus(boolean touchscreenBlocksFocus) {
        if (touchscreenBlocksFocus) {
            mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
            if (hasFocus()) {
            if (hasFocus() && !isKeyboardNavigationCluster()) {
                final View focusedChild = getDeepestFocusedChild();
                if (!focusedChild.isFocusableInTouchMode()) {
                    final View newFocus = focusSearch(FOCUS_FORWARD);
@@ -1316,7 +1310,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        // cluster, focus is free to move around within it.
        return getTouchscreenBlocksFocus() &&
                mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
                && (!hasFocus() || !isKeyboardNavigationCluster());
                && !(isKeyboardNavigationCluster()
                        && (hasFocus() || (findKeyboardNavigationCluster() != this)));
    }

    @Override
@@ -3217,8 +3212,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    }

    private boolean restoreFocusInClusterInternal(@FocusRealDirection int direction) {
        if (mFocusedInCluster != null && !mFocusedInCluster.isKeyboardNavigationCluster()
                && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
        if (mFocusedInCluster != null && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
                && (mFocusedInCluster.mViewFlags & VISIBILITY_MASK) == VISIBLE
                && mFocusedInCluster.restoreFocusInCluster(direction)) {
            return true;
@@ -5182,7 +5176,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            clearChildFocus = true;
        }
        if (view == mFocusedInCluster) {
            clearFocusInCluster(view);
            clearFocusedInCluster(view);
        }

        view.clearAccessibilityFocus();
@@ -5302,7 +5296,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                clearDefaultFocus = view;
            }
            if (view == mFocusedInCluster) {
                clearFocusInCluster(view);
                clearFocusedInCluster(view);
            }

            view.clearAccessibilityFocus();
@@ -5458,7 +5452,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            clearDefaultFocus(child);
        }
        if (child == mFocusedInCluster) {
            clearFocusInCluster(child);
            clearFocusedInCluster(child);
        }

        child.clearAccessibilityFocus();