Introducing teleportation between sections.

The key combos differ from the ones in the spec because key combos
including Meta key don’t get delivered to apps. To fix this, I’ll
implement necessary plumbing after the feature freeze. Meanwhile,
temporary combos are used.

Given that the section and cluster teleportation have a lot in common,
I’m not introducing new methods, but adding a param to the cluster
teleportation ones. I should have also changed the names to something
like findNextKeyboardNavigationCluster => findNextFocusGroup, where
“FocusGroup” is a generalized name for clusters and sections.
However, that name depends on b/33708251, so I’m not doing it now. I
don’t rename existing identifiers, and using “focusGroup” for new
ones. Admittedly, this creates mess that will be resolved based on
the outcome of the mentioned bug.

Bug: 32151632
Test: Manual checks; CTS are coming after feature freeze
Change-Id: I01b5d6e5a9689b8f643fa4af695d2ce61265f374
This commit is contained in:
Vadim Tryshev
2016-12-21 19:22:26 -08:00
parent 196bbe7a4b
commit 8957f2ddda
8 changed files with 174 additions and 71 deletions

View File

@@ -41816,7 +41816,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();
}
@@ -43109,7 +43109,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>);
@@ -43397,7 +43397,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[]);
@@ -43679,6 +43679,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
@@ -44046,7 +44048,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);
@@ -44209,7 +44210,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);

View File

@@ -45008,7 +45008,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();
}
@@ -46301,7 +46301,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>);
@@ -46589,7 +46589,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[]);
@@ -46871,6 +46871,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
@@ -47238,7 +47240,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);
@@ -47401,7 +47402,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);

View File

@@ -42103,7 +42103,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();
}
@@ -43398,7 +43398,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>);
@@ -43687,7 +43687,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[]);
@@ -43969,6 +43969,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
@@ -44340,7 +44342,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);
@@ -44503,7 +44504,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);

View File

@@ -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.
return 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.
return 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);
}
}
/**

View File

@@ -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);

View File

@@ -901,23 +901,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
return null;
}
@Override
public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
if (isKeyboardNavigationCluster()) {
currentCluster = this;
}
if (isRootNamespace()) {
// 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
return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
this, currentCluster, direction);
} else if (mParent != null) {
return mParent.keyboardNavigationClusterSearch(currentCluster, direction);
}
return null;
}
@Override
public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
return false;
@@ -1164,10 +1147,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
@Override
public void addKeyboardNavigationClusters(Collection<View> views, int direction) {
public void addKeyboardNavigationClusters(
@FocusGroupType int focusGroupType, Collection<View> views, int direction) {
final int focusableCount = views.size();
super.addKeyboardNavigationClusters(views, direction);
super.addKeyboardNavigationClusters(focusGroupType, views, direction);
if (focusableCount != views.size()) {
// No need to look for clusters inside a cluster.
@@ -1183,8 +1167,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
for (int i = 0; i < count; i++) {
final View child = children[i];
if (focusGroupType == FOCUS_GROUP_SECTION && child.isKeyboardNavigationCluster()) {
// When the current cluster is the default cluster, and we are searching for
// sections, ignore sections inside non-default clusters.
continue;
}
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
child.addKeyboardNavigationClusters(views, direction);
child.addKeyboardNavigationClusters(focusGroupType, views, direction);
}
}
}

View File

@@ -18,6 +18,7 @@ package android.view;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View.FocusGroupType;
import android.view.accessibility.AccessibilityEvent;
/**
@@ -150,6 +151,7 @@ public interface ViewParent {
* 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
@@ -157,7 +159,8 @@ public interface ViewParent {
* @return The nearest keyboard navigation cluster in the specified direction, or null if none
* can be found
*/
View keyboardNavigationClusterSearch(View currentCluster, int direction);
View keyboardNavigationClusterSearch(
@FocusGroupType int focusGroupType, View currentCluster, int direction);
/**
* Change the z order of the child so it's on top of all other children.

View File

@@ -16,6 +16,8 @@
package android.view;
import static android.view.View.FOCUS_GROUP_CLUSTER;
import static android.view.View.FOCUS_GROUP_SECTION;
import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
@@ -71,6 +73,7 @@ import android.util.TimeUtils;
import android.util.TypedValue;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;
import android.view.View.FocusGroupType;
import android.view.View.MeasureSpec;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -4392,11 +4395,12 @@ public final class ViewRootImpl implements ViewParent,
return false;
}
private boolean performClusterNavigation(int direction) {
private boolean performClusterNavigation(
@FocusGroupType int focusGroupType, int direction) {
final View focused = mView.findFocus();
final View cluster = focused != null
? focused.keyboardNavigationClusterSearch(direction)
: keyboardNavigationClusterSearch(null, direction);
? focused.keyboardNavigationClusterSearch(focusGroupType, null, direction)
: keyboardNavigationClusterSearch(focusGroupType, null, direction);
if (cluster != null && cluster.restoreLastFocus()) {
return true;
@@ -4418,15 +4422,32 @@ public final class ViewRootImpl implements ViewParent,
}
int clusterNavigationDirection = 0;
@FocusGroupType int focusGroupType = 0;
if (event.getAction() == KeyEvent.ACTION_DOWN && event.isCtrlPressed()) {
final int character =
event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK);
if (character == '+') {
focusGroupType = FOCUS_GROUP_CLUSTER;
clusterNavigationDirection = View.FOCUS_FORWARD;
}
if (character == '_') {
focusGroupType = FOCUS_GROUP_CLUSTER;
clusterNavigationDirection = View.FOCUS_BACKWARD;
}
}
if (event.getAction() == KeyEvent.ACTION_DOWN && event.isAltPressed()) {
final int character =
event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_ALT_MASK);
if (character == '+') {
focusGroupType = FOCUS_GROUP_SECTION;
clusterNavigationDirection = View.FOCUS_FORWARD;
}
if (character == '_') {
focusGroupType = FOCUS_GROUP_SECTION;
clusterNavigationDirection = View.FOCUS_BACKWARD;
}
}
@@ -4456,7 +4477,7 @@ public final class ViewRootImpl implements ViewParent,
// Handle automatic focus changes.
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (clusterNavigationDirection != 0) {
if (performClusterNavigation(clusterNavigationDirection)) {
if (performClusterNavigation(focusGroupType, clusterNavigationDirection)) {
return FINISH_HANDLED;
}
} else {
@@ -5887,13 +5908,11 @@ public final class ViewRootImpl implements ViewParent,
* {@inheritDoc}
*/
@Override
public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
public View keyboardNavigationClusterSearch(
@FocusGroupType int focusGroupType, View currentCluster, int direction) {
checkThread();
if (!(mView instanceof ViewGroup)) {
return null;
}
return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
(ViewGroup) mView, currentCluster, direction);
return FocusFinder.getInstance().findNextKeyboardNavigationCluster(focusGroupType,
mView, currentCluster, direction);
}
public void debug() {