Loading api/current.txt +6 −5 Original line number Diff line number Diff line Loading @@ -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(); } Loading Loading @@ -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>); Loading Loading @@ -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[]); Loading Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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); api/system-current.txt +6 −5 Original line number Diff line number Diff line Loading @@ -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(); } Loading Loading @@ -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>); Loading Loading @@ -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[]); Loading Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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); api/test-current.txt +6 −5 Original line number Diff line number Diff line Loading @@ -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(); } Loading Loading @@ -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>); Loading Loading @@ -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[]); Loading Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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); core/java/android/view/FocusFinder.java +57 −17 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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); } Loading Loading @@ -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. Loading @@ -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. Loading @@ -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); } } /** Loading core/java/android/view/View.java +57 −8 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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. Loading Loading @@ -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; } /** Loading Loading @@ -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 Loading
api/current.txt +6 −5 Original line number Diff line number Diff line Loading @@ -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(); } Loading Loading @@ -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>); Loading Loading @@ -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[]); Loading Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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);
api/system-current.txt +6 −5 Original line number Diff line number Diff line Loading @@ -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(); } Loading Loading @@ -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>); Loading Loading @@ -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[]); Loading Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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);
api/test-current.txt +6 −5 Original line number Diff line number Diff line Loading @@ -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(); } Loading Loading @@ -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>); Loading Loading @@ -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[]); Loading Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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);
core/java/android/view/FocusFinder.java +57 −17 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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); } Loading Loading @@ -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. Loading @@ -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. Loading @@ -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); } } /** Loading
core/java/android/view/View.java +57 −8 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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. Loading Loading @@ -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; } /** Loading Loading @@ -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