Add View reveal on focus hint

Provide a way for views to signal that they would prefer not
to have their parents scroll or otherwise rearrange when they
request focus to try to show the full focused view to the user.
In some cases this can be disruptive to the UX.

As of now, framework views do not respect this hint and custom
views such as those found in currently deployed support libs
don't either. The policy is left open to ViewParent subclasses
that implement requestChildFocus.

Bug 30256922

Change-Id: I55194de888fe2b8129be9a9aa21aa5e18cbb8296
diff --git a/api/current.txt b/api/current.txt
index 5263c26..8a5288f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -42475,6 +42475,7 @@
     method public float getPivotY();
     method public android.view.PointerIcon getPointerIcon();
     method public android.content.res.Resources getResources();
+    method public final boolean getRevealOnFocusHint();
     method public final int getRight();
     method protected float getRightFadingEdgeStrength();
     method protected int getRightPaddingOffset();
@@ -42762,6 +42763,7 @@
     method public void setPivotY(float);
     method public void setPointerIcon(android.view.PointerIcon);
     method public void setPressed(boolean);
+    method public final void setRevealOnFocusHint(boolean);
     method public final void setRight(int);
     method public void setRotation(float);
     method public void setRotationX(float);
diff --git a/api/system-current.txt b/api/system-current.txt
index 07a8825..b1d387e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -45641,6 +45641,7 @@
     method public float getPivotY();
     method public android.view.PointerIcon getPointerIcon();
     method public android.content.res.Resources getResources();
+    method public final boolean getRevealOnFocusHint();
     method public final int getRight();
     method protected float getRightFadingEdgeStrength();
     method protected int getRightPaddingOffset();
@@ -45928,6 +45929,7 @@
     method public void setPivotY(float);
     method public void setPointerIcon(android.view.PointerIcon);
     method public void setPressed(boolean);
+    method public final void setRevealOnFocusHint(boolean);
     method public final void setRight(int);
     method public void setRotation(float);
     method public void setRotationX(float);
diff --git a/api/test-current.txt b/api/test-current.txt
index 9256ba4..dcafcac 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -42555,6 +42555,7 @@
     method public float getPivotY();
     method public android.view.PointerIcon getPointerIcon();
     method public android.content.res.Resources getResources();
+    method public final boolean getRevealOnFocusHint();
     method public final int getRight();
     method protected float getRightFadingEdgeStrength();
     method protected int getRightPaddingOffset();
@@ -42842,6 +42843,7 @@
     method public void setPivotY(float);
     method public void setPointerIcon(android.view.PointerIcon);
     method public void setPressed(boolean);
+    method public final void setRevealOnFocusHint(boolean);
     method public final void setRight(int);
     method public void setRotation(float);
     method public void setRotationX(float);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e648114..7df582b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2435,6 +2435,7 @@
      *          1                        PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
      *         1                         PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
      *        1                          PFLAG3_TEMPORARY_DETACH
+     *       1                           PFLAG3_NO_REVEAL_ON_FOCUS
      * |-------|-------|-------|-------|
      */
 
@@ -2676,6 +2677,16 @@
      */
     static final int PFLAG3_TEMPORARY_DETACH = 0x2000000;
 
+    /**
+     * Flag indicating that the view does not wish to be revealed within its parent
+     * hierarchy when it gains focus. Expressed in the negative since the historical
+     * default behavior is to reveal on focus; this flag suppresses that behavior.
+     *
+     * @see #setRevealOnFocusHint(boolean)
+     * @see #getRevealOnFocusHint()
+     */
+    private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000;
+
     /* End of masks for mPrivateFlags3 */
 
     /**
@@ -5941,6 +5952,47 @@
     }
 
     /**
+     * Sets this view's preference for reveal behavior when it gains focus.
+     *
+     * <p>When set to true, this is a signal to ancestor views in the hierarchy that
+     * this view would prefer to be brought fully into view when it gains focus.
+     * For example, a text field that a user is meant to type into. Other views such
+     * as scrolling containers may prefer to opt-out of this behavior.</p>
+     *
+     * <p>The default value for views is true, though subclasses may change this
+     * based on their preferred behavior.</p>
+     *
+     * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise
+     *
+     * @see #getRevealOnFocusHint()
+     */
+    public final void setRevealOnFocusHint(boolean revealOnFocus) {
+        if (revealOnFocus) {
+            mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS;
+        } else {
+            mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS;
+        }
+    }
+
+    /**
+     * Returns this view's preference for reveal behavior when it gains focus.
+     *
+     * <p>When this method returns true for a child view requesting focus, ancestor
+     * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)}
+     * should make a best effort to make the newly focused child fully visible to the user.
+     * When it returns false, ancestor views should preferably not disrupt scroll positioning or
+     * other properties affecting visibility to the user as part of the focus change.</p>
+     *
+     * @return true if this view would prefer to become fully visible when it gains focus,
+     *         false if it would prefer not to disrupt scroll positioning
+     *
+     * @see #setRevealOnFocusHint(boolean)
+     */
+    public final boolean getRevealOnFocusHint() {
+        return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0;
+    }
+
+    /**
      * Populates <code>outRect</code> with the hotspot bounds. By default,
      * the hotspot bounds are identical to the screen bounds.
      *