summaryrefslogtreecommitdiffstats
path: root/core/java/android/view
diff options
context:
space:
mode:
authorAdam Powell <adamp@google.com>2012-02-03 19:00:49 -0800
committerAdam Powell <adamp@google.com>2012-02-17 16:40:24 -0800
commit539ee8716b4f81260bab2e9f3dc5d88d81c99985 (patch)
tree8019a11d8462118fd17bce538a22af5f2590f006 /core/java/android/view
parent6917e6550d2dc11ad3b794be08cc9caa53970d32 (diff)
downloadframeworks_base-539ee8716b4f81260bab2e9f3dc5d88d81c99985.zip
frameworks_base-539ee8716b4f81260bab2e9f3dc5d88d81c99985.tar.gz
frameworks_base-539ee8716b4f81260bab2e9f3dc5d88d81c99985.tar.bz2
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
Diffstat (limited to 'core/java/android/view')
-rw-r--r--core/java/android/view/View.java47
-rw-r--r--core/java/android/view/ViewGroup.java57
-rw-r--r--core/java/android/view/ViewParent.java10
-rw-r--r--core/java/android/view/ViewRootImpl.java4
4 files changed, 118 insertions, 0 deletions
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 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
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 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
/**
+ * 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.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index f2935e8..ac46d4e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -77,6 +77,7 @@ import java.util.HashSet;
* @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
*/
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
+ private static final String TAG = "ViewGroup";
private static final boolean DBG = false;
@@ -375,6 +376,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
@ViewDebug.ExportedProperty(category = "drawing")
boolean mDrawLayers = true;
+ // Indicates how many of this container's child subtrees contain transient state
+ @ViewDebug.ExportedProperty(category = "layout")
+ private int mChildCountWithTransientState = 0;
+
public ViewGroup(Context context) {
super(context);
initViewGroup();
@@ -653,6 +658,38 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
/**
+ * Called when a child view has changed whether or not it is tracking transient state.
+ *
+ * @hide
+ */
+ public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
+ final boolean oldHasTransientState = hasTransientState();
+ if (childHasTransientState) {
+ mChildCountWithTransientState++;
+ } else {
+ mChildCountWithTransientState--;
+ }
+
+ final boolean newHasTransientState = hasTransientState();
+ if (mParent != null && oldHasTransientState != newHasTransientState) {
+ try {
+ mParent.childHasTransientStateChanged(this, newHasTransientState);
+ } catch (AbstractMethodError e) {
+ Log.e(TAG, mParent.getClass().getSimpleName() +
+ " does not fully implement ViewParent", e);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean hasTransientState() {
+ return mChildCountWithTransientState > 0 || super.hasTransientState();
+ }
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -3099,6 +3136,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
}
+
+ if (child.hasTransientState()) {
+ childHasTransientStateChanged(child, true);
+ }
}
private void addInArray(View child, int index) {
@@ -3295,6 +3336,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
view.dispatchDetachedFromWindow();
}
+ if (view.hasTransientState()) {
+ childHasTransientStateChanged(view, false);
+ }
+
onViewRemoved(view);
needGlobalAttributesUpdate(false);
@@ -3366,6 +3411,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
view.dispatchDetachedFromWindow();
}
+ if (view.hasTransientState()) {
+ childHasTransientStateChanged(view, false);
+ }
+
needGlobalAttributesUpdate(false);
onViewRemoved(view);
@@ -3431,6 +3480,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
view.dispatchDetachedFromWindow();
}
+ if (view.hasTransientState()) {
+ childHasTransientStateChanged(view, false);
+ }
+
onViewRemoved(view);
view.mParent = null;
@@ -3471,6 +3524,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
child.dispatchDetachedFromWindow();
}
+ if (child.hasTransientState()) {
+ childHasTransientStateChanged(child, false);
+ }
+
onViewRemoved(child);
}
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 873d4bb..8395f1b 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -261,4 +261,14 @@ public interface ViewParent {
* @return True if the event was sent.
*/
public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event);
+
+ /**
+ * Called when a child view now has or no longer is tracking transient state.
+ *
+ * @param child Child view whose state has changed
+ * @param hasTransientState true if this child has transient state
+ *
+ * @hide
+ */
+ public void childHasTransientStateChanged(View child, boolean hasTransientState);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d41d168..84ce2a4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4144,6 +4144,10 @@ public final class ViewRootImpl implements ViewParent,
return scrollToRectOrFocus(rectangle, immediate);
}
+ public void childHasTransientStateChanged(View child, boolean hasTransientState) {
+ // Do nothing.
+ }
+
class TakenSurfaceHolder extends BaseSurfaceHolder {
@Override
public boolean onAllowLockCanvas() {