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

Commit c587433d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Introducing teleportation between sections."

parents 46708586 8957f2dd
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -41819,7 +41819,7 @@ package android.view {
    method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
    method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
    method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
    method public android.view.View findNextKeyboardNavigationCluster(android.view.ViewGroup, android.view.View, int);
    method public android.view.View findNextKeyboardNavigationCluster(int, android.view.View, android.view.View, int);
    method public static android.view.FocusFinder getInstance();
  }
@@ -43112,7 +43112,7 @@ package android.view {
    method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
    method public void addFocusables(java.util.ArrayList<android.view.View>, int);
    method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
    method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
    method public void addKeyboardNavigationClusters(int, java.util.Collection<android.view.View>, int);
    method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
    method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
    method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -43400,7 +43400,7 @@ package android.view {
    method public boolean isVerticalFadingEdgeEnabled();
    method public boolean isVerticalScrollBarEnabled();
    method public void jumpDrawablesToCurrentState();
    method public android.view.View keyboardNavigationClusterSearch(int);
    method public android.view.View keyboardNavigationClusterSearch(int, android.view.View, int);
    method public void layout(int, int, int, int);
    method public final void measure(int, int);
    method protected static int[] mergeDrawableStates(int[], int[]);
@@ -43682,6 +43682,8 @@ package android.view {
    field public static final int FOCUS_BACKWARD = 1; // 0x1
    field public static final int FOCUS_DOWN = 130; // 0x82
    field public static final int FOCUS_FORWARD = 2; // 0x2
    field public static final int FOCUS_GROUP_CLUSTER = 1; // 0x1
    field public static final int FOCUS_GROUP_SECTION = 2; // 0x2
    field public static final int FOCUS_LEFT = 17; // 0x11
    field public static final int FOCUS_RIGHT = 66; // 0x42
    field public static final int FOCUS_UP = 33; // 0x21
@@ -44049,7 +44051,6 @@ package android.view {
    method protected deprecated boolean isChildrenDrawnWithCacheEnabled();
    method public boolean isMotionEventSplittingEnabled();
    method public boolean isTransitionGroup();
    method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
    method public final void layout(int, int, int, int);
    method protected void measureChild(android.view.View, int, int);
    method protected void measureChildWithMargins(android.view.View, int, int, int, int);
@@ -44212,7 +44213,7 @@ package android.view {
    method public abstract boolean isLayoutRequested();
    method public abstract boolean isTextAlignmentResolved();
    method public abstract boolean isTextDirectionResolved();
    method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
    method public abstract android.view.View keyboardNavigationClusterSearch(int, android.view.View, int);
    method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
    method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
    method public abstract boolean onNestedPreFling(android.view.View, float, float);
+6 −5
Original line number Diff line number Diff line
@@ -45029,7 +45029,7 @@ package android.view {
    method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
    method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
    method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
    method public android.view.View findNextKeyboardNavigationCluster(android.view.ViewGroup, android.view.View, int);
    method public android.view.View findNextKeyboardNavigationCluster(int, android.view.View, android.view.View, int);
    method public static android.view.FocusFinder getInstance();
  }
@@ -46322,7 +46322,7 @@ package android.view {
    method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
    method public void addFocusables(java.util.ArrayList<android.view.View>, int);
    method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
    method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
    method public void addKeyboardNavigationClusters(int, java.util.Collection<android.view.View>, int);
    method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
    method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
    method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -46610,7 +46610,7 @@ package android.view {
    method public boolean isVerticalFadingEdgeEnabled();
    method public boolean isVerticalScrollBarEnabled();
    method public void jumpDrawablesToCurrentState();
    method public android.view.View keyboardNavigationClusterSearch(int);
    method public android.view.View keyboardNavigationClusterSearch(int, android.view.View, int);
    method public void layout(int, int, int, int);
    method public final void measure(int, int);
    method protected static int[] mergeDrawableStates(int[], int[]);
@@ -46892,6 +46892,8 @@ package android.view {
    field public static final int FOCUS_BACKWARD = 1; // 0x1
    field public static final int FOCUS_DOWN = 130; // 0x82
    field public static final int FOCUS_FORWARD = 2; // 0x2
    field public static final int FOCUS_GROUP_CLUSTER = 1; // 0x1
    field public static final int FOCUS_GROUP_SECTION = 2; // 0x2
    field public static final int FOCUS_LEFT = 17; // 0x11
    field public static final int FOCUS_RIGHT = 66; // 0x42
    field public static final int FOCUS_UP = 33; // 0x21
@@ -47259,7 +47261,6 @@ package android.view {
    method protected deprecated boolean isChildrenDrawnWithCacheEnabled();
    method public boolean isMotionEventSplittingEnabled();
    method public boolean isTransitionGroup();
    method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
    method public final void layout(int, int, int, int);
    method protected void measureChild(android.view.View, int, int);
    method protected void measureChildWithMargins(android.view.View, int, int, int, int);
@@ -47422,7 +47423,7 @@ package android.view {
    method public abstract boolean isLayoutRequested();
    method public abstract boolean isTextAlignmentResolved();
    method public abstract boolean isTextDirectionResolved();
    method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
    method public abstract android.view.View keyboardNavigationClusterSearch(int, android.view.View, int);
    method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
    method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
    method public abstract boolean onNestedPreFling(android.view.View, float, float);
+6 −5
Original line number Diff line number Diff line
@@ -42106,7 +42106,7 @@ package android.view {
    method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
    method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
    method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
    method public android.view.View findNextKeyboardNavigationCluster(android.view.ViewGroup, android.view.View, int);
    method public android.view.View findNextKeyboardNavigationCluster(int, android.view.View, android.view.View, int);
    method public static android.view.FocusFinder getInstance();
  }
@@ -43401,7 +43401,7 @@ package android.view {
    method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
    method public void addFocusables(java.util.ArrayList<android.view.View>, int);
    method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
    method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
    method public void addKeyboardNavigationClusters(int, java.util.Collection<android.view.View>, int);
    method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
    method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
    method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -43690,7 +43690,7 @@ package android.view {
    method public boolean isVerticalFadingEdgeEnabled();
    method public boolean isVerticalScrollBarEnabled();
    method public void jumpDrawablesToCurrentState();
    method public android.view.View keyboardNavigationClusterSearch(int);
    method public android.view.View keyboardNavigationClusterSearch(int, android.view.View, int);
    method public void layout(int, int, int, int);
    method public final void measure(int, int);
    method protected static int[] mergeDrawableStates(int[], int[]);
@@ -43972,6 +43972,8 @@ package android.view {
    field public static final int FOCUS_BACKWARD = 1; // 0x1
    field public static final int FOCUS_DOWN = 130; // 0x82
    field public static final int FOCUS_FORWARD = 2; // 0x2
    field public static final int FOCUS_GROUP_CLUSTER = 1; // 0x1
    field public static final int FOCUS_GROUP_SECTION = 2; // 0x2
    field public static final int FOCUS_LEFT = 17; // 0x11
    field public static final int FOCUS_RIGHT = 66; // 0x42
    field public static final int FOCUS_UP = 33; // 0x21
@@ -44343,7 +44345,6 @@ package android.view {
    method protected deprecated boolean isChildrenDrawnWithCacheEnabled();
    method public boolean isMotionEventSplittingEnabled();
    method public boolean isTransitionGroup();
    method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
    method public final void layout(int, int, int, int);
    method protected void measureChild(android.view.View, int, int);
    method protected void measureChildWithMargins(android.view.View, int, int, int, int);
@@ -44506,7 +44507,7 @@ package android.view {
    method public abstract boolean isLayoutRequested();
    method public abstract boolean isTextAlignmentResolved();
    method public abstract boolean isTextDirectionResolved();
    method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
    method public abstract android.view.View keyboardNavigationClusterSearch(int, android.view.View, int);
    method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
    method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
    method public abstract boolean onNestedPreFling(android.view.View, float, float);
+57 −17
Original line number Diff line number Diff line
@@ -16,12 +16,16 @@

package android.view;

import static android.view.View.FOCUS_GROUP_CLUSTER;
import static android.view.View.FOCUS_GROUP_SECTION;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.util.ArrayMap;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.View.FocusGroupType;

import java.util.ArrayList;
import java.util.Collections;
@@ -107,21 +111,26 @@ public class FocusFinder {

    /**
     * Find the root of the next keyboard navigation cluster after the current one.
     * @param root Thew view tree to look inside. Cannot be null
     * @param focusGroupType Type of the focus group
     * @param root The view tree to look inside. Cannot be null
     * @param currentCluster The starting point of the search. Null means the default cluster
     * @param direction Direction to look
     * @return The next cluster, or null if none exists
     */
    public View findNextKeyboardNavigationCluster(
            @NonNull ViewGroup root, @Nullable View currentCluster, int direction) {
            @FocusGroupType int focusGroupType,
            @NonNull View root,
            @Nullable View currentCluster,
            int direction) {
        View next = null;

        final ArrayList<View> clusters = mTempList;
        try {
            clusters.clear();
            root.addKeyboardNavigationClusters(clusters, direction);
            root.addKeyboardNavigationClusters(focusGroupType, clusters, direction);
            if (!clusters.isEmpty()) {
                next = findNextKeyboardNavigationCluster(root, currentCluster, clusters, direction);
                next = findNextKeyboardNavigationCluster(
                        focusGroupType, root, currentCluster, clusters, direction);
            }
        } finally {
            clusters.clear();
@@ -197,19 +206,25 @@ public class FocusFinder {
        }
    }

    private View findNextKeyboardNavigationCluster(ViewGroup root, View currentCluster,
            List<View> clusters, int direction) {
    private View findNextKeyboardNavigationCluster(
            @FocusGroupType int focusGroupType,
            View root,
            View currentCluster,
            List<View> clusters,
            int direction) {
        final int count = clusters.size();

        switch (direction) {
            case View.FOCUS_FORWARD:
            case View.FOCUS_DOWN:
            case View.FOCUS_RIGHT:
                return getNextKeyboardNavigationCluster(root, currentCluster, clusters, count);
                return getNextKeyboardNavigationCluster(
                        focusGroupType, root, currentCluster, clusters, count);
            case View.FOCUS_BACKWARD:
            case View.FOCUS_UP:
            case View.FOCUS_LEFT:
                return getPreviousKeyboardNavigationCluster(root, currentCluster, clusters, count);
                return getPreviousKeyboardNavigationCluster(
                        focusGroupType, root, currentCluster, clusters, count);
            default:
                throw new IllegalArgumentException("Unknown direction: " + direction);
        }
@@ -315,8 +330,12 @@ public class FocusFinder {
        return null;
    }

    private static View getNextKeyboardNavigationCluster(ViewGroup root, View currentCluster,
            List<View> clusters, int count) {
    private static View getNextKeyboardNavigationCluster(
            @FocusGroupType int focusGroupType,
            View root,
            View currentCluster,
            List<View> clusters,
            int count) {
        if (currentCluster == null) {
            // The current cluster is the default one.
            // The next cluster after the default one is the first one.
@@ -330,12 +349,25 @@ public class FocusFinder {
            return clusters.get(position + 1);
        }

        // The current cluster is the last one. The next one is the default one, i.e. the root.
        switch (focusGroupType) {
            case FOCUS_GROUP_CLUSTER:
                // The current cluster is the last one. The next one is the default one, i.e. the
                // root.
                return root;
            case FOCUS_GROUP_SECTION:
                // There is no "default section", hence returning the first one.
                return clusters.get(0);
            default:
                throw new IllegalArgumentException("Unknown focus group type: " + focusGroupType);
        }
    }

    private static View getPreviousKeyboardNavigationCluster(ViewGroup root, View currentCluster,
            List<View> clusters, int count) {
    private static View getPreviousKeyboardNavigationCluster(
            @FocusGroupType int focusGroupType,
            View root,
            View currentCluster,
            List<View> clusters,
            int count) {
        if (currentCluster == null) {
            // The current cluster is the default one.
            // The previous cluster before the default one is the last one.
@@ -349,9 +381,17 @@ public class FocusFinder {
            return clusters.get(position - 1);
        }

        // The current cluster is the first one. The previous one is the default one, i.e. the
        // root.
        switch (focusGroupType) {
            case FOCUS_GROUP_CLUSTER:
                // The current cluster is the first one. The previous one is the default one, i.e.
                // the root.
                return root;
            case FOCUS_GROUP_SECTION:
                // There is no "default section", hence returning the last one.
                return clusters.get(count - 1);
            default:
                throw new IllegalArgumentException("Unknown focus group type: " + focusGroupType);
        }
    }

    /**
+57 −8
Original line number Diff line number Diff line
@@ -1248,6 +1248,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    @Retention(RetentionPolicy.SOURCE)
    public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward
    /** @hide */
    @IntDef({
            FOCUS_GROUP_CLUSTER,
            FOCUS_GROUP_SECTION
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface FocusGroupType {}
    /**
     * Use with {@link #focusSearch(int)}. Move focus to the previous selectable
     * item.
@@ -1280,6 +1288,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     */
    public static final int FOCUS_DOWN = 0x00000082;
    /**
     * Use with {@link #keyboardNavigationClusterSearch(int, View, int)}. Search for a keyboard
     * navigation cluster.
     */
    public static final int FOCUS_GROUP_CLUSTER = 1;
    /**
     * Use with {@link #keyboardNavigationClusterSearch(int, View, int)}. Search for a keyboard
     * navigation section.
     */
    public static final int FOCUS_GROUP_SECTION = 2;
    /**
     * Bits of {@link #getMeasuredWidthAndState()} and
     * {@link #getMeasuredWidthAndState()} that provide the actual measured size.
@@ -9096,22 +9116,47 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        }
    }
    final boolean isFocusGroupOfType(@FocusGroupType int focusGroupType) {
        switch (focusGroupType) {
            case FOCUS_GROUP_CLUSTER:
                return isKeyboardNavigationCluster();
            case FOCUS_GROUP_SECTION:
                return isKeyboardNavigationSection();
            default:
                throw new IllegalArgumentException("Unknown focus group type: " + focusGroupType);
        }
    }
    /**
     * Find the nearest keyboard navigation cluster in the specified direction.
     * This does not actually give focus to that cluster.
     *
     * @param focusGroupType Type of the focus group
     * @param currentCluster The starting point of the search. Null means the current cluster is not
     *                       found yet
     * @param direction Direction to look
     *
     * @return The nearest keyboard navigation cluster in the specified direction, or null if none
     *         can be found
     */
    public View keyboardNavigationClusterSearch(int direction) {
        if (mParent != null) {
            final View currentCluster = isKeyboardNavigationCluster() ? this : null;
            return mParent.keyboardNavigationClusterSearch(currentCluster, direction);
        } else {
            return null;
    public View keyboardNavigationClusterSearch(
            @FocusGroupType int focusGroupType, View currentCluster, int direction) {
        if (isFocusGroupOfType(focusGroupType)) {
            currentCluster = this;
        }
        if (isRootNamespace()
                || focusGroupType == FOCUS_GROUP_SECTION && isKeyboardNavigationCluster()) {
            // Root namespace means we should consider ourselves the top of the
            // tree for cluster searching; otherwise we could be focus searching
            // into other tabs.  see LocalActivityManager and TabHost for more info.
            // In addition, a cluster node works as a root for section searches.
            return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
                    focusGroupType, this, currentCluster, direction);
        } else if (mParent != null) {
            return mParent.keyboardNavigationClusterSearch(
                    focusGroupType, currentCluster, direction);
        }
        return null;
    }
    /**
@@ -9240,11 +9285,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     * Adds any keyboard navigation cluster roots that are descendants of this view (possibly
     * including this view if it is a cluster root itself) to views.
     *
     * @param focusGroupType Type of the focus group
     * @param views Cluster roots found so far
     * @param direction Direction to look
     */
    public void addKeyboardNavigationClusters(@NonNull Collection<View> views, int direction) {
        if (!isKeyboardNavigationCluster()) {
    public void addKeyboardNavigationClusters(
            @FocusGroupType int focusGroupType,
            @NonNull Collection<View> views,
            int direction) {
        if (!(isFocusGroupOfType(focusGroupType))) {
            return;
        }
        views.add(this);
Loading