Adding public API for marking nodes as clusters and sections.
Clusters:
We need clusters to limit the size of the “tab loop” by
widgets related to the current context: working in the
app’s client area, choosing a command in the action bar
etc.
Clusters are a generalization of the current action bar’s
behavior.
An activity can have several clusters.
A cluster is a view or a view group group marked as such.
Pressing Tab loops inside the cluster, but you can exit it via
arrows.
You can teleport between clusters via special key combos.
Sections:
Sections live inside clusters.
They are needed for simplifying navigation in complex
hierarchies: instead of tabbing or arrowing, you can simply
teleport to the the next/previous section by pressing a
special key combo.
Example: think about panes in GMail app or dir/files
panels in a file manager.
Otherwise, sections are normal view groups: for example,
they don’t limit keyboard navigation in any way.
Bug: 32151632
Test: Checking for syntax errors and that Android starts.
Change-Id: Ic78495d0749db65d5177017553d37f870354c6bc
diff --git a/api/current.txt b/api/current.txt
index 460b99c..052924f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -750,6 +750,8 @@
field public static final int keyWidth = 16843325; // 0x101023d
field public static final int keyboardLayout = 16843691; // 0x10103ab
field public static final int keyboardMode = 16843341; // 0x101024d
+ field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
+ field public static final int keyboardNavigationSection = 16844097; // 0x1010541
field public static final int keycode = 16842949; // 0x10100c5
field public static final int killAfterRestore = 16843420; // 0x101029c
field public static final int label = 16842753; // 0x1010001
@@ -893,11 +895,13 @@
field public static final int negativeButtonText = 16843254; // 0x10101f6
field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
field public static final int networkSecurityConfig = 16844071; // 0x1010527
+ field public static final int nextClusterForward = 16844098; // 0x1010542
field public static final int nextFocusDown = 16842980; // 0x10100e4
field public static final int nextFocusForward = 16843580; // 0x101033c
field public static final int nextFocusLeft = 16842977; // 0x10100e1
field public static final int nextFocusRight = 16842978; // 0x10100e2
field public static final int nextFocusUp = 16842979; // 0x10100e3
+ field public static final int nextSectionForward = 16844099; // 0x1010543
field public static final int noHistory = 16843309; // 0x101022d
field public static final int normalScreens = 16843397; // 0x1010285
field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -43076,11 +43080,13 @@
method public final int getMeasuredWidthAndState();
method public int getMinimumHeight();
method public int getMinimumWidth();
+ method public int getNextClusterForwardId();
method public int getNextFocusDownId();
method public int getNextFocusForwardId();
method public int getNextFocusLeftId();
method public int getNextFocusRightId();
method public int getNextFocusUpId();
+ method public int getNextSectionForwardId();
method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
method public android.view.ViewOutlineProvider getOutlineProvider();
method public int getOverScrollMode();
@@ -43183,6 +43189,8 @@
method public boolean isInEditMode();
method public boolean isInLayout();
method public boolean isInTouchMode();
+ method public final boolean isKeyboardNavigationCluster();
+ method public final boolean isKeyboardNavigationSection();
method public boolean isLaidOut();
method public boolean isLayoutDirectionResolved();
method public boolean isLayoutRequested();
@@ -43351,6 +43359,8 @@
method public void setId(int);
method public void setImportantForAccessibility(int);
method public void setKeepScreenOn(boolean);
+ method public void setKeyboardNavigationCluster(boolean);
+ method public void setKeyboardNavigationSection(boolean);
method public void setLabelFor(int);
method public void setLayerPaint(android.graphics.Paint);
method public void setLayerType(int, android.graphics.Paint);
@@ -43362,11 +43372,13 @@
method public void setMinimumHeight(int);
method public void setMinimumWidth(int);
method public void setNestedScrollingEnabled(boolean);
+ method public void setNextClusterForwardId(int);
method public void setNextFocusDownId(int);
method public void setNextFocusForwardId(int);
method public void setNextFocusLeftId(int);
method public void setNextFocusRightId(int);
method public void setNextFocusUpId(int);
+ method public void setNextSectionForwardId(int);
method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
method public void setOnClickListener(android.view.View.OnClickListener);
method public void setOnContextClickListener(android.view.View.OnContextClickListener);
diff --git a/api/system-current.txt b/api/system-current.txt
index 1ced79c..f29e5fa 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -857,6 +857,8 @@
field public static final int keyWidth = 16843325; // 0x101023d
field public static final int keyboardLayout = 16843691; // 0x10103ab
field public static final int keyboardMode = 16843341; // 0x101024d
+ field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
+ field public static final int keyboardNavigationSection = 16844097; // 0x1010541
field public static final int keycode = 16842949; // 0x10100c5
field public static final int killAfterRestore = 16843420; // 0x101029c
field public static final int label = 16842753; // 0x1010001
@@ -1000,11 +1002,13 @@
field public static final int negativeButtonText = 16843254; // 0x10101f6
field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
field public static final int networkSecurityConfig = 16844071; // 0x1010527
+ field public static final int nextClusterForward = 16844098; // 0x1010542
field public static final int nextFocusDown = 16842980; // 0x10100e4
field public static final int nextFocusForward = 16843580; // 0x101033c
field public static final int nextFocusLeft = 16842977; // 0x10100e1
field public static final int nextFocusRight = 16842978; // 0x10100e2
field public static final int nextFocusUp = 16842979; // 0x10100e3
+ field public static final int nextSectionForward = 16844099; // 0x1010543
field public static final int noHistory = 16843309; // 0x101022d
field public static final int normalScreens = 16843397; // 0x1010285
field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -46269,11 +46273,13 @@
method public final int getMeasuredWidthAndState();
method public int getMinimumHeight();
method public int getMinimumWidth();
+ method public int getNextClusterForwardId();
method public int getNextFocusDownId();
method public int getNextFocusForwardId();
method public int getNextFocusLeftId();
method public int getNextFocusRightId();
method public int getNextFocusUpId();
+ method public int getNextSectionForwardId();
method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
method public android.view.ViewOutlineProvider getOutlineProvider();
method public int getOverScrollMode();
@@ -46376,6 +46382,8 @@
method public boolean isInEditMode();
method public boolean isInLayout();
method public boolean isInTouchMode();
+ method public final boolean isKeyboardNavigationCluster();
+ method public final boolean isKeyboardNavigationSection();
method public boolean isLaidOut();
method public boolean isLayoutDirectionResolved();
method public boolean isLayoutRequested();
@@ -46544,6 +46552,8 @@
method public void setId(int);
method public void setImportantForAccessibility(int);
method public void setKeepScreenOn(boolean);
+ method public void setKeyboardNavigationCluster(boolean);
+ method public void setKeyboardNavigationSection(boolean);
method public void setLabelFor(int);
method public void setLayerPaint(android.graphics.Paint);
method public void setLayerType(int, android.graphics.Paint);
@@ -46555,11 +46565,13 @@
method public void setMinimumHeight(int);
method public void setMinimumWidth(int);
method public void setNestedScrollingEnabled(boolean);
+ method public void setNextClusterForwardId(int);
method public void setNextFocusDownId(int);
method public void setNextFocusForwardId(int);
method public void setNextFocusLeftId(int);
method public void setNextFocusRightId(int);
method public void setNextFocusUpId(int);
+ method public void setNextSectionForwardId(int);
method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
method public void setOnClickListener(android.view.View.OnClickListener);
method public void setOnContextClickListener(android.view.View.OnContextClickListener);
diff --git a/api/test-current.txt b/api/test-current.txt
index 49f48d8..69beee5 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -750,6 +750,8 @@
field public static final int keyWidth = 16843325; // 0x101023d
field public static final int keyboardLayout = 16843691; // 0x10103ab
field public static final int keyboardMode = 16843341; // 0x101024d
+ field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
+ field public static final int keyboardNavigationSection = 16844097; // 0x1010541
field public static final int keycode = 16842949; // 0x10100c5
field public static final int killAfterRestore = 16843420; // 0x101029c
field public static final int label = 16842753; // 0x1010001
@@ -893,11 +895,13 @@
field public static final int negativeButtonText = 16843254; // 0x10101f6
field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
field public static final int networkSecurityConfig = 16844071; // 0x1010527
+ field public static final int nextClusterForward = 16844098; // 0x1010542
field public static final int nextFocusDown = 16842980; // 0x10100e4
field public static final int nextFocusForward = 16843580; // 0x101033c
field public static final int nextFocusLeft = 16842977; // 0x10100e1
field public static final int nextFocusRight = 16842978; // 0x10100e2
field public static final int nextFocusUp = 16842979; // 0x10100e3
+ field public static final int nextSectionForward = 16844099; // 0x1010543
field public static final int noHistory = 16843309; // 0x101022d
field public static final int normalScreens = 16843397; // 0x1010285
field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -43344,11 +43348,13 @@
method public final int getMeasuredWidthAndState();
method public int getMinimumHeight();
method public int getMinimumWidth();
+ method public int getNextClusterForwardId();
method public int getNextFocusDownId();
method public int getNextFocusForwardId();
method public int getNextFocusLeftId();
method public int getNextFocusRightId();
method public int getNextFocusUpId();
+ method public int getNextSectionForwardId();
method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
method public android.view.ViewOutlineProvider getOutlineProvider();
method public int getOverScrollMode();
@@ -43452,6 +43458,8 @@
method public boolean isInEditMode();
method public boolean isInLayout();
method public boolean isInTouchMode();
+ method public final boolean isKeyboardNavigationCluster();
+ method public final boolean isKeyboardNavigationSection();
method public boolean isLaidOut();
method public boolean isLayoutDirectionResolved();
method public boolean isLayoutRequested();
@@ -43620,6 +43628,8 @@
method public void setId(int);
method public void setImportantForAccessibility(int);
method public void setKeepScreenOn(boolean);
+ method public void setKeyboardNavigationCluster(boolean);
+ method public void setKeyboardNavigationSection(boolean);
method public void setLabelFor(int);
method public void setLayerPaint(android.graphics.Paint);
method public void setLayerType(int, android.graphics.Paint);
@@ -43631,11 +43641,13 @@
method public void setMinimumHeight(int);
method public void setMinimumWidth(int);
method public void setNestedScrollingEnabled(boolean);
+ method public void setNextClusterForwardId(int);
method public void setNextFocusDownId(int);
method public void setNextFocusForwardId(int);
method public void setNextFocusLeftId(int);
method public void setNextFocusRightId(int);
method public void setNextFocusUpId(int);
+ method public void setNextSectionForwardId(int);
method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
method public void setOnClickListener(android.view.View.OnClickListener);
method public void setOnContextClickListener(android.view.View.OnContextClickListener);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3f4c49b..9e4bb4c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2474,7 +2474,9 @@
* 1 PFLAG3_SCROLL_INDICATOR_START
* 1 PFLAG3_SCROLL_INDICATOR_END
* 1 PFLAG3_ASSIST_BLOCKED
- * xxxxxxxx * NO LONGER NEEDED, SHOULD BE REUSED *
+ * 1 PFLAG3_CLUSTER
+ * 1 PFLAG3_SECTION
+ * xxxxxx * NO LONGER NEEDED, SHOULD BE REUSED *
* 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
* 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
* 1 PFLAG3_TEMPORARY_DETACH
@@ -2673,6 +2675,22 @@
static final int PFLAG3_ASSIST_BLOCKED = 0x4000;
/**
+ * Flag indicating that the view is a root of a keyboard navigation cluster.
+ *
+ * @see #isKeyboardNavigationCluster()
+ * @see #setKeyboardNavigationCluster(boolean)
+ */
+ private static final int PFLAG3_CLUSTER = 0x8000;
+
+ /**
+ * Flag indicating that the view is a root of a keyboard navigation section.
+ *
+ * @see #isKeyboardNavigationSection()
+ * @see #setKeyboardNavigationSection(boolean)
+ */
+ private static final int PFLAG3_SECTION = 0x10000;
+
+ /**
* Whether this view has rendered elements that overlap (see {@link
* #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and
* {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when
@@ -3740,6 +3758,16 @@
*/
int mNextFocusForwardId = View.NO_ID;
+ /**
+ * User-specified next keyboard navigation cluster.
+ */
+ int mNextClusterForwardId = View.NO_ID;
+
+ /**
+ * User-specified next keyboard navigation section.
+ */
+ int mNextSectionForwardId = View.NO_ID;
+
private CheckForLongPress mPendingCheckForLongPress;
private CheckForTap mPendingCheckForTap = null;
private PerformClick mPerformClick;
@@ -4531,6 +4559,12 @@
case R.styleable.View_nextFocusForward:
mNextFocusForwardId = a.getResourceId(attr, View.NO_ID);
break;
+ case R.styleable.View_nextClusterForward:
+ mNextClusterForwardId = a.getResourceId(attr, View.NO_ID);
+ break;
+ case R.styleable.View_nextSectionForward:
+ mNextSectionForwardId = a.getResourceId(attr, View.NO_ID);
+ break;
case R.styleable.View_minWidth:
mMinWidth = a.getDimensionPixelSize(attr, 0);
break;
@@ -4667,10 +4701,19 @@
forceHasOverlappingRendering(a.getBoolean(attr, true));
}
break;
-
case R.styleable.View_tooltip:
setTooltip(a.getText(attr));
break;
+ case R.styleable.View_keyboardNavigationCluster:
+ if (a.peekValue(attr) != null) {
+ setKeyboardNavigationCluster(a.getBoolean(attr, true));
+ }
+ break;
+ case R.styleable.View_keyboardNavigationSection:
+ if (a.peekValue(attr) != null) {
+ setKeyboardNavigationSection(a.getBoolean(attr, true));
+ }
+ break;
}
}
@@ -7852,6 +7895,50 @@
}
/**
+ * Gets the id of the root of the next keyboard navigation cluster.
+ * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should
+ * decide automatically.
+ *
+ * @attr ref android.R.styleable#View_nextClusterForward
+ */
+ public int getNextClusterForwardId() {
+ return mNextClusterForwardId;
+ }
+
+ /**
+ * Sets the id of the view to use as the root of the next keyboard navigation cluster.
+ * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should
+ * decide automatically.
+ *
+ * @attr ref android.R.styleable#View_nextClusterForward
+ */
+ public void setNextClusterForwardId(int nextClusterForwardId) {
+ mNextClusterForwardId = nextClusterForwardId;
+ }
+
+ /**
+ * Gets the id of the root of the next keyboard navigation section.
+ * @return The next keyboard navigation section ID, or {@link #NO_ID} if the framework should
+ * decide automatically.
+ *
+ * @attr ref android.R.styleable#View_nextSectionForward
+ */
+ public int getNextSectionForwardId() {
+ return mNextSectionForwardId;
+ }
+
+ /**
+ * Sets the id of the view to use as the root of the next keyboard navigation section.
+ * @param nextSectionForwardId The next section ID, or {@link #NO_ID} if the framework should
+ * decide automatically.
+ *
+ * @attr ref android.R.styleable#View_nextSectionForward
+ */
+ public void setNextSectionForwardId(int nextSectionForwardId) {
+ mNextSectionForwardId = nextSectionForwardId;
+ }
+
+ /**
* Returns the visibility of this view and all of its ancestors
*
* @return True if this view and all of its ancestors are {@link #VISIBLE}
@@ -8947,6 +9034,58 @@
}
/**
+ * Returns whether this View is a root of a keyboard navigation cluster.
+ *
+ * @return True if this view is a root of a cluster, or false otherwise.
+ * @attr ref android.R.styleable#View_keyboardNavigationCluster
+ */
+ @ViewDebug.ExportedProperty(category = "keyboardNavigationCluster")
+ public final boolean isKeyboardNavigationCluster() {
+ return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0;
+ }
+
+ /**
+ * Set whether this view is a root of a keyboard navigation cluster.
+ *
+ * @param isCluster If true, this view is a root of a cluster.
+ *
+ * @attr ref android.R.styleable#View_keyboardNavigationCluster
+ */
+ public void setKeyboardNavigationCluster(boolean isCluster) {
+ if (isCluster) {
+ mPrivateFlags3 |= PFLAG3_CLUSTER;
+ } else {
+ mPrivateFlags3 &= ~PFLAG3_CLUSTER;
+ }
+ }
+
+ /**
+ * Returns whether this View is a root of a keyboard navigation section.
+ *
+ * @return True if this view is a root of a section, or false otherwise.
+ * @attr ref android.R.styleable#View_keyboardNavigationSection
+ */
+ @ViewDebug.ExportedProperty(category = "keyboardNavigationSection")
+ public final boolean isKeyboardNavigationSection() {
+ return (mPrivateFlags3 & PFLAG3_SECTION) != 0;
+ }
+
+ /**
+ * Set whether this view is a root of a keyboard navigation section.
+ *
+ * @param isSection If true, this view is a root of a section.
+ *
+ * @attr ref android.R.styleable#View_keyboardNavigationSection
+ */
+ public void setKeyboardNavigationSection(boolean isSection) {
+ if (isSection) {
+ mPrivateFlags3 |= PFLAG3_SECTION;
+ } else {
+ mPrivateFlags3 &= ~PFLAG3_SECTION;
+ }
+ }
+
+ /**
* This method is the last chance for the focused view and its ancestors to
* respond to an arrow key. This is called when the focused view did not
* consume the key internally, nor could the view system find a new view in
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8c64484..aa050de 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2887,6 +2887,28 @@
<!-- Defines text displayed in a small popup window on hover or long press. -->
<attr name="tooltip" format="string" localization="suggested" />
+ <!-- Whether this view is a root of a keyboard navigation cluster.
+ See {@link android.view.View#setKeyboardNavigationCluster(boolean)}. -->
+ <attr name="keyboardNavigationCluster" format="boolean" />
+
+ <!-- Whether this view is a root of a keyboard navigation section.
+ See {@link android.view.View#setKeyboardNavigationSection(boolean)}. -->
+ <attr name="keyboardNavigationSection" format="boolean" />
+
+ <!-- Defines the next keyboard navigation cluster.
+
+ If the reference refers to a view that does not exist or is part
+ of a hierarchy that is invisible, a {@link java.lang.RuntimeException}
+ will result when the reference is accessed.-->
+ <attr name="nextClusterForward" format="reference"/>
+
+ <!-- Defines the next keyboard navigation section.
+
+ If the reference refers to a view that does not exist or is part
+ of a hierarchy that is invisible, a {@link java.lang.RuntimeException}
+ will result when the reference is accessed.-->
+ <attr name="nextSectionForward" format="reference"/>
+
</declare-styleable>
<!-- Attributes that can be assigned to a tag for a particular View. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 37c4fd1..4604f3f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2776,6 +2776,10 @@
<public name="paddingHorizontal" />
<public name="paddingVertical" />
<public name="visibleToEphemeral" />
+ <public name="keyboardNavigationCluster" />
+ <public name="keyboardNavigationSection" />
+ <public name="nextClusterForward" />
+ <public name="nextSectionForward" />
</public-group>
<public-group type="style" first-id="0x010302e0">