Add transient state tracking to Views

Transient state is temporary bookkeeping that Views need to perform
that the app should not need to be aware of. Examples include text
selection regions and animation state.

Transient state is a problem for AdapterViews like ListView that do
view recycling. Unless the app takes responsibility for tracking and
restoring transient state as if it were a part of the adapter's data
set, it cannot correctly recycle views. Selections disappear when an
EditText is scrolled out of sight and animations seem to play on the
wrong views.

Views can now flag themselves as having transient state. (As the name
implies, this should be a temporary condition.) If a ViewGroup
contains a child with transient state, that ViewGroup also has
transient state.

AbsListView's recycler now tracks views with transient state
separately. Views with transient state will be retained, and until a
data set change occurs the same view will be reused for that position
instead of calling the adapter's getView() method.

The API to set and check transient state is currently hidden.

Change-Id: Idfd8eaac2c548337686d8d9f98fda4c64be5b8a0
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 32f5732..c16eb31 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1759,6 +1759,16 @@
     static final int LAYOUT_DIRECTION_RESOLVED = 0x00000008;
 
 
+    /**
+     * Indicates that the view is tracking some sort of transient state
+     * that the app should not need to be aware of, but that the framework
+     * should take special care to preserve.
+     *
+     * @hide
+     */
+    static final int HAS_TRANSIENT_STATE = 0x00000010;
+
+
     /* End of masks for mPrivateFlags2 */
 
     static final int DRAG_MASK = DRAG_CAN_ACCEPT | DRAG_HOVERED;
@@ -4889,6 +4899,43 @@
     }
 
     /**
+     * Indicates whether the view is currently tracking transient state that the
+     * app should not need to concern itself with saving and restoring, but that
+     * the framework should take special note to preserve when possible.
+     *
+     * @return true if the view has transient state
+     *
+     * @hide
+     */
+    @ViewDebug.ExportedProperty(category = "layout")
+    public boolean hasTransientState() {
+        return (mPrivateFlags2 & HAS_TRANSIENT_STATE) == HAS_TRANSIENT_STATE;
+    }
+
+    /**
+     * Set whether this view is currently tracking transient state that the
+     * framework should attempt to preserve when possible.
+     *
+     * @param hasTransientState true if this view has transient state
+     *
+     * @hide
+     */
+    public void setHasTransientState(boolean hasTransientState) {
+        if (hasTransientState() == hasTransientState) return;
+
+        mPrivateFlags2 = (mPrivateFlags2 & ~HAS_TRANSIENT_STATE) |
+                (hasTransientState ? HAS_TRANSIENT_STATE : 0);
+        if (mParent != null) {
+            try {
+                mParent.childHasTransientStateChanged(this, hasTransientState);
+            } catch (AbstractMethodError e) {
+                Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
+                        " does not fully implement ViewParent", e);
+            }
+        }
+    }
+
+    /**
      * If this view doesn't do any drawing on its own, set this flag to
      * allow further optimizations. By default, this flag is not set on
      * View, but could be set on some View subclasses such as ViewGroup.