Add initial support for TAB navigation.
Bug: 3286652
Change-Id: I813a0318b3b8d9c9bc791ea6a2427be11c08de00
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 75aebc9..71d07c6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -64,6 +64,7 @@
import android.view.inputmethod.InputMethodManager;
import android.widget.ScrollBarDrawable;
import com.android.internal.R;
+import com.android.internal.util.Predicate;
import com.android.internal.view.menu.MenuBuilder;
import java.lang.ref.WeakReference;
@@ -2066,6 +2067,12 @@
*/
private int mNextFocusDownId = View.NO_ID;
+ /**
+ * When this view has focus and the next focus is {@link #FOCUS_FORWARD},
+ * the user may specify which view to go to next.
+ */
+ int mNextFocusForwardId = View.NO_ID;
+
private CheckForLongPress mPendingCheckForLongPress;
private CheckForTap mPendingCheckForTap = null;
private PerformClick mPerformClick;
@@ -2424,6 +2431,9 @@
case R.styleable.View_nextFocusDown:
mNextFocusDownId = a.getResourceId(attr, View.NO_ID);
break;
+ case R.styleable.View_nextFocusForward:
+ mNextFocusForwardId = a.getResourceId(attr, View.NO_ID);
+ break;
case R.styleable.View_minWidth:
mMinWidth = a.getDimensionPixelSize(attr, 0);
break;
@@ -3112,9 +3122,9 @@
* @param gainFocus True if the View has focus; false otherwise.
* @param direction The direction focus has moved when requestFocus()
* is called to give this view focus. Values are
- * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT} or
- * {@link #FOCUS_RIGHT}. It may not always apply, in which
- * case use the default.
+ * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT},
+ * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}.
+ * It may not always apply, in which case use the default.
* @param previouslyFocusedRect The rectangle, in this view's coordinate
* system, of the previously focused view. If applicable, this will be
* passed in as finer grained information about where the focus is coming
@@ -3359,7 +3369,8 @@
}
/**
- * @return The user specified next focus ID.
+ * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}.
+ * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically.
*
* @attr ref android.R.styleable#View_nextFocusLeft
*/
@@ -3368,9 +3379,9 @@
}
/**
- * Set the id of the view to use for the next focus
- *
- * @param nextFocusLeftId
+ * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}.
+ * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should
+ * decide automatically.
*
* @attr ref android.R.styleable#View_nextFocusLeft
*/
@@ -3379,7 +3390,8 @@
}
/**
- * @return The user specified next focus ID.
+ * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}.
+ * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically.
*
* @attr ref android.R.styleable#View_nextFocusRight
*/
@@ -3388,9 +3400,9 @@
}
/**
- * Set the id of the view to use for the next focus
- *
- * @param nextFocusRightId
+ * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}.
+ * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should
+ * decide automatically.
*
* @attr ref android.R.styleable#View_nextFocusRight
*/
@@ -3399,7 +3411,8 @@
}
/**
- * @return The user specified next focus ID.
+ * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}.
+ * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically.
*
* @attr ref android.R.styleable#View_nextFocusUp
*/
@@ -3408,9 +3421,9 @@
}
/**
- * Set the id of the view to use for the next focus
- *
- * @param nextFocusUpId
+ * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}.
+ * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should
+ * decide automatically.
*
* @attr ref android.R.styleable#View_nextFocusUp
*/
@@ -3419,7 +3432,8 @@
}
/**
- * @return The user specified next focus ID.
+ * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}.
+ * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically.
*
* @attr ref android.R.styleable#View_nextFocusDown
*/
@@ -3428,9 +3442,9 @@
}
/**
- * Set the id of the view to use for the next focus
- *
- * @param nextFocusDownId
+ * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}.
+ * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should
+ * decide automatically.
*
* @attr ref android.R.styleable#View_nextFocusDown
*/
@@ -3439,6 +3453,27 @@
}
/**
+ * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}.
+ * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically.
+ *
+ * @attr ref android.R.styleable#View_nextFocusForward
+ */
+ public int getNextFocusForwardId() {
+ return mNextFocusForwardId;
+ }
+
+ /**
+ * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}.
+ * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should
+ * decide automatically.
+ *
+ * @attr ref android.R.styleable#View_nextFocusForward
+ */
+ public void setNextFocusForwardId(int nextFocusForwardId) {
+ mNextFocusForwardId = nextFocusForwardId;
+ }
+
+ /**
* Returns the visibility of this view and all of its ancestors
*
* @return True if this view and all of its ancestors are {@link #VISIBLE}
@@ -3949,10 +3984,10 @@
/**
* If a user manually specified the next view id for a particular direction,
- * use the root to look up the view. Once a view is found, it is cached
- * for future lookups.
+ * use the root to look up the view.
* @param root The root view of the hierarchy containing this view.
- * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
+ * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD,
+ * or FOCUS_BACKWARD.
* @return The user specified next view, or null if there is none.
*/
View findUserSetNextFocus(View root, int direction) {
@@ -3969,6 +4004,18 @@
case FOCUS_DOWN:
if (mNextFocusDownId == View.NO_ID) return null;
return findViewShouldExist(root, mNextFocusDownId);
+ case FOCUS_FORWARD:
+ if (mNextFocusForwardId == View.NO_ID) return null;
+ return findViewShouldExist(root, mNextFocusForwardId);
+ case FOCUS_BACKWARD: {
+ final int id = mID;
+ return root.findViewByPredicate(new Predicate<View>() {
+ @Override
+ public boolean apply(View t) {
+ return t.mNextFocusForwardId == id;
+ }
+ });
+ }
}
return null;
}
@@ -9359,6 +9406,18 @@
}
/**
+ * {@hide}
+ * @param predicate The predicate to evaluate.
+ * @return The first view that matches the predicate or null.
+ */
+ protected View findViewByPredicateTraversal(Predicate<View> predicate) {
+ if (predicate.apply(this)) {
+ return this;
+ }
+ return null;
+ }
+
+ /**
* Look for a child view with the given id. If this view has the given
* id, return this view.
*
@@ -9387,6 +9446,18 @@
}
/**
+ * {@hide}
+ * Look for a child view that matches the specified predicate.
+ * If this view matches the predicate, return this view.
+ *
+ * @param predicate The predicate to evaluate.
+ * @return The first view that matches the predicate or null.
+ */
+ public final View findViewByPredicate(Predicate<View> predicate) {
+ return findViewByPredicateTraversal(predicate);
+ }
+
+ /**
* Sets the identifier for this view. The identifier does not have to be
* unique in this view's hierarchy. The identifier should be a positive
* number.