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

Commit 85aa3e82 authored by Evan Rosky's avatar Evan Rosky Committed by android-build-merger
Browse files

Merge "Allow cluster navigation to jump into touchscreenBlocksFocus" into oc-dev

am: 37af93ad

Change-Id: I92254792b7681d1be53849ad3847dbb4e5318139
parents 70b93740 37af93ad
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