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

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

Merge "Allow cluster navigation to jump into touchscreenBlocksFocus"

parents 995353cd aee802f3
Loading
Loading
Loading
Loading
+34 −3
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.view;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.util.ArrayMap;
import android.util.SparseArray;
@@ -88,8 +89,9 @@ public class FocusFinder {

    private View findNextFocus(ViewGroup root, View focused, Rect focusedRect, int direction) {
        View next = null;
        ViewGroup effectiveRoot = getEffectiveRoot(root, focused);
        if (focused != null) {
            next = findNextUserSpecifiedFocus(root, focused, direction);
            next = findNextUserSpecifiedFocus(effectiveRoot, focused, direction);
        }
        if (next != null) {
            return next;
@@ -97,9 +99,9 @@ public class FocusFinder {
        ArrayList<View> focusables = mTempList;
        try {
            focusables.clear();
            root.addFocusables(focusables, direction);
            effectiveRoot.addFocusables(focusables, direction);
            if (!focusables.isEmpty()) {
                next = findNextFocus(root, focused, focusedRect, direction, focusables);
                next = findNextFocus(effectiveRoot, focused, focusedRect, direction, focusables);
            }
        } finally {
            focusables.clear();
@@ -107,6 +109,35 @@ public class FocusFinder {
        return next;
    }

    /**
     * Returns the "effective" root of a view. The "effective" root is the closest ancestor
     * within-which focus should cycle.
     * <p>
     * For example: normal focus navigation would stay within a ViewGroup marked as
     * touchscreenBlocksFocus and keyboardNavigationCluster until a cluster-jump out.
     * @return the "effective" root of {@param focused}
     */
    private ViewGroup getEffectiveRoot(ViewGroup root, View focused) {
        if (focused == null) {
            return root;
        }
        ViewParent effective = focused.getParent();
        do {
            if (effective == root) {
                return root;
            }
            ViewGroup vg = (ViewGroup) effective;
            if (vg.getTouchscreenBlocksFocus()
                    && focused.getContext().getPackageManager().hasSystemFeature(
                            PackageManager.FEATURE_TOUCHSCREEN)
                    && vg.isKeyboardNavigationCluster()) {
                return vg;
            }
            effective = effective.getParent();
        } while (effective != null);
        return root;
    }

    /**
     * Find the root of the next keyboard navigation cluster after the current one.
     * @param root The view tree to look inside. Cannot be null
+44 −4
Original line number Diff line number Diff line
@@ -1190,7 +1190,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        final int focusableCount = views.size();

        final int descendantFocusability = getDescendantFocusability();
        final boolean focusSelf = (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen());
        final boolean blockFocusForTouchscreen = shouldBlockFocusForTouchscreen();
        final boolean focusSelf = (isFocusableInTouchMode() || !blockFocusForTouchscreen);

        if (descendantFocusability == FOCUS_BLOCK_DESCENDANTS) {
            if (focusSelf) {
@@ -1199,7 +1200,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            return;
        }

        if (shouldBlockFocusForTouchscreen()) {
        if (blockFocusForTouchscreen) {
            focusableMode |= FOCUSABLES_TOUCH_MODE;
        }

@@ -1234,7 +1235,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    public void addKeyboardNavigationClusters(Collection<View> views, int direction) {
        final int focusableCount = views.size();

        if (isKeyboardNavigationCluster()) {
            // Cluster-navigation can enter a touchscreenBlocksFocus cluster, so temporarily
            // disable touchscreenBlocksFocus to evaluate whether it contains focusables.
            final boolean blockedFocus = getTouchscreenBlocksFocus();
            try {
                setTouchscreenBlocksFocusNoRefocus(false);
                super.addKeyboardNavigationClusters(views, direction);
            } finally {
                setTouchscreenBlocksFocusNoRefocus(blockedFocus);
            }
        } else {
            super.addKeyboardNavigationClusters(views, direction);
        }

        if (focusableCount != views.size()) {
            // No need to look for groups inside a group.
@@ -1280,6 +1293,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        }
    }

    private void setTouchscreenBlocksFocusNoRefocus(boolean touchscreenBlocksFocus) {
        if (touchscreenBlocksFocus) {
            mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
        } else {
            mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
        }
    }

    /**
     * Check whether this ViewGroup should ignore focus requests for itself and its children.
     */
@@ -1288,8 +1309,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    }

    boolean shouldBlockFocusForTouchscreen() {
        // There is a special case for keyboard-navigation clusters. We allow cluster navigation
        // to jump into blockFocusForTouchscreen ViewGroups which are clusters. Once in the
        // cluster, focus is free to move around within it.
        return getTouchscreenBlocksFocus() &&
                mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
                mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
                && (!hasFocus() || !isKeyboardNavigationCluster());
    }

    @Override
@@ -3175,6 +3200,21 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    @TestApi
    @Override
    public boolean restoreFocusInCluster(@FocusRealDirection int direction) {
        // Allow cluster-navigation to enter touchscreenBlocksFocus ViewGroups.
        if (isKeyboardNavigationCluster()) {
            final boolean blockedFocus = getTouchscreenBlocksFocus();
            try {
                setTouchscreenBlocksFocusNoRefocus(false);
                return restoreFocusInClusterInternal(direction);
            } finally {
                setTouchscreenBlocksFocusNoRefocus(blockedFocus);
            }
        } else {
            return restoreFocusInClusterInternal(direction);
        }
    }

    private boolean restoreFocusInClusterInternal(@FocusRealDirection int direction) {
        if (mFocusedInCluster != null && !mFocusedInCluster.isKeyboardNavigationCluster()
                && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
                && (mFocusedInCluster.mViewFlags & VISIBILITY_MASK) == VISIBLE
+3 −0
Original line number Diff line number Diff line
@@ -343,6 +343,9 @@ public class Toolbar extends ViewGroup {
            final ViewGroup vgParent = (ViewGroup) parent;
            if (vgParent.isKeyboardNavigationCluster()) {
                setKeyboardNavigationCluster(false);
                if (vgParent.getTouchscreenBlocksFocus()) {
                    setTouchscreenBlocksFocus(false);
                }
                break;
            }
            parent = vgParent.getParent();
+2 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ This is an optimized layout for a screen with the Action Bar enabled.
        android:layout_alignParentTop="true"
        style="?attr/actionBarStyle"
        android:transitionName="android:action_bar"
        android:touchscreenBlocksFocus="true"
        android:keyboardNavigationCluster="true"
        android:gravity="top">
        <com.android.internal.widget.ActionBarView
@@ -54,6 +55,7 @@ This is an optimized layout for a screen with the Action Bar enabled.
                  android:layout_height="wrap_content"
                  style="?attr/actionBarSplitStyle"
                  android:visibility="gone"
                  android:touchscreenBlocksFocus="true"
                  android:keyboardNavigationCluster="true"
                  android:gravity="center"/>
</com.android.internal.widget.ActionBarOverlayLayout>
+1 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ This is an optimized layout for a screen with a toolbar enabled.
        android:layout_alignParentTop="true"
        style="?attr/actionBarStyle"
        android:transitionName="android:action_bar"
        android:touchscreenBlocksFocus="true"
        android:keyboardNavigationCluster="true"
        android:gravity="top">
        <Toolbar
Loading