Merge "Revert "Remove ViewTreeObserver allocations"" into jb-dev

This commit is contained in:
Chet Haase
2012-06-07 11:27:26 -07:00
committed by Android (Google) Code Review

View File

@ -20,6 +20,7 @@ import android.graphics.Rect;
import android.graphics.Region;
import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* A view tree observer is used to register listeners that can be notified of global
@ -31,12 +32,12 @@ import java.util.ArrayList;
* for more information.
*/
public final class ViewTreeObserver {
private CopyOnWriteArray<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
private CopyOnWriteArray<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
private CopyOnWriteArray<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
private CopyOnWriteArray<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
private CopyOnWriteArray<OnScrollChangedListener> mOnScrollChangedListeners;
private CopyOnWriteArray<OnPreDrawListener> mOnPreDrawListeners;
private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
private CopyOnWriteArrayList<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
private CopyOnWriteArrayList<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
private CopyOnWriteArrayList<OnScrollChangedListener> mOnScrollChangedListeners;
private ArrayList<OnPreDrawListener> mOnPreDrawListeners;
private ArrayList<OnDrawListener> mOnDrawListeners;
private boolean mAlive = true;
@ -146,7 +147,7 @@ public final class ViewTreeObserver {
* windows behind it should be placed.
*/
public final Rect contentInsets = new Rect();
/**
* Offsets from the frame of the window at which windows behind it
* are visible.
@ -165,13 +166,13 @@ public final class ViewTreeObserver {
* can be touched.
*/
public static final int TOUCHABLE_INSETS_FRAME = 0;
/**
* Option for {@link #setTouchableInsets(int)}: the area inside of
* the content insets can be touched.
*/
public static final int TOUCHABLE_INSETS_CONTENT = 1;
/**
* Option for {@link #setTouchableInsets(int)}: the area inside of
* the visible insets can be touched.
@ -194,7 +195,7 @@ public final class ViewTreeObserver {
}
int mTouchableInsets;
void reset() {
contentInsets.setEmpty();
visibleInsets.setEmpty();
@ -230,7 +231,7 @@ public final class ViewTreeObserver {
mTouchableInsets = other.mTouchableInsets;
}
}
/**
* Interface definition for a callback to be invoked when layout has
* completed and the client can compute its interior insets.
@ -327,7 +328,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnGlobalFocusListeners == null) {
mOnGlobalFocusListeners = new CopyOnWriteArray<OnGlobalFocusChangeListener>();
mOnGlobalFocusListeners = new CopyOnWriteArrayList<OnGlobalFocusChangeListener>();
}
mOnGlobalFocusListeners.add(listener);
@ -362,7 +363,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnGlobalLayoutListeners == null) {
mOnGlobalLayoutListeners = new CopyOnWriteArray<OnGlobalLayoutListener>();
mOnGlobalLayoutListeners = new CopyOnWriteArrayList<OnGlobalLayoutListener>();
}
mOnGlobalLayoutListeners.add(listener);
@ -412,7 +413,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnPreDrawListeners == null) {
mOnPreDrawListeners = new CopyOnWriteArray<OnPreDrawListener>();
mOnPreDrawListeners = new ArrayList<OnPreDrawListener>();
}
mOnPreDrawListeners.add(listener);
@ -484,7 +485,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnScrollChangedListeners == null) {
mOnScrollChangedListeners = new CopyOnWriteArray<OnScrollChangedListener>();
mOnScrollChangedListeners = new CopyOnWriteArrayList<OnScrollChangedListener>();
}
mOnScrollChangedListeners.add(listener);
@ -518,7 +519,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnTouchModeChangeListeners == null) {
mOnTouchModeChangeListeners = new CopyOnWriteArray<OnTouchModeChangeListener>();
mOnTouchModeChangeListeners = new CopyOnWriteArrayList<OnTouchModeChangeListener>();
}
mOnTouchModeChangeListeners.add(listener);
@ -557,7 +558,7 @@ public final class ViewTreeObserver {
if (mOnComputeInternalInsetsListeners == null) {
mOnComputeInternalInsetsListeners =
new CopyOnWriteArray<OnComputeInternalInsetsListener>();
new CopyOnWriteArrayList<OnComputeInternalInsetsListener>();
}
mOnComputeInternalInsetsListeners.add(listener);
@ -621,16 +622,10 @@ public final class ViewTreeObserver {
// perform the dispatching. The iterator is a safe guard against listeners that
// could mutate the list by calling the various add/remove methods. This prevents
// the array from being modified while we iterate it.
final CopyOnWriteArray<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
final CopyOnWriteArrayList<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
if (listeners != null && listeners.size() > 0) {
CopyOnWriteArray.Access<OnGlobalFocusChangeListener> access = listeners.start();
try {
int count = access.size();
for (int i = 0; i < count; i++) {
access.get(i).onGlobalFocusChanged(oldFocus, newFocus);
}
} finally {
listeners.end();
for (OnGlobalFocusChangeListener listener : listeners) {
listener.onGlobalFocusChanged(oldFocus, newFocus);
}
}
}
@ -645,16 +640,10 @@ public final class ViewTreeObserver {
// perform the dispatching. The iterator is a safe guard against listeners that
// could mutate the list by calling the various add/remove methods. This prevents
// the array from being modified while we iterate it.
final CopyOnWriteArray<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
final CopyOnWriteArrayList<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
if (listeners != null && listeners.size() > 0) {
CopyOnWriteArray.Access<OnGlobalLayoutListener> access = listeners.start();
try {
int count = access.size();
for (int i = 0; i < count; i++) {
access.get(i).onGlobalLayout();
}
} finally {
listeners.end();
for (OnGlobalLayoutListener listener : listeners) {
listener.onGlobalLayout();
}
}
}
@ -669,17 +658,17 @@ public final class ViewTreeObserver {
*/
@SuppressWarnings("unchecked")
public final boolean dispatchOnPreDraw() {
// NOTE: we *must* clone the listener list to perform the dispatching.
// The clone is a safe guard against listeners that
// could mutate the list by calling the various add/remove methods. This prevents
// the array from being modified while we process it.
boolean cancelDraw = false;
final CopyOnWriteArray<OnPreDrawListener> listeners = mOnPreDrawListeners;
if (listeners != null && listeners.size() > 0) {
CopyOnWriteArray.Access<OnPreDrawListener> access = listeners.start();
try {
int count = access.size();
for (int i = 0; i < count; i++) {
cancelDraw |= !(access.get(i).onPreDraw());
}
} finally {
listeners.end();
if (mOnPreDrawListeners != null && mOnPreDrawListeners.size() > 0) {
final ArrayList<OnPreDrawListener> listeners =
(ArrayList<OnPreDrawListener>) mOnPreDrawListeners.clone();
int numListeners = listeners.size();
for (int i = 0; i < numListeners; ++i) {
cancelDraw |= !(listeners.get(i).onPreDraw());
}
}
return cancelDraw;
@ -704,17 +693,11 @@ public final class ViewTreeObserver {
* @param inTouchMode True if the touch mode is now enabled, false otherwise.
*/
final void dispatchOnTouchModeChanged(boolean inTouchMode) {
final CopyOnWriteArray<OnTouchModeChangeListener> listeners =
final CopyOnWriteArrayList<OnTouchModeChangeListener> listeners =
mOnTouchModeChangeListeners;
if (listeners != null && listeners.size() > 0) {
CopyOnWriteArray.Access<OnTouchModeChangeListener> access = listeners.start();
try {
int count = access.size();
for (int i = 0; i < count; i++) {
access.get(i).onTouchModeChanged(inTouchMode);
}
} finally {
listeners.end();
for (OnTouchModeChangeListener listener : listeners) {
listener.onTouchModeChanged(inTouchMode);
}
}
}
@ -727,16 +710,10 @@ public final class ViewTreeObserver {
// perform the dispatching. The iterator is a safe guard against listeners that
// could mutate the list by calling the various add/remove methods. This prevents
// the array from being modified while we iterate it.
final CopyOnWriteArray<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
final CopyOnWriteArrayList<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
if (listeners != null && listeners.size() > 0) {
CopyOnWriteArray.Access<OnScrollChangedListener> access = listeners.start();
try {
int count = access.size();
for (int i = 0; i < count; i++) {
access.get(i).onScrollChanged();
}
} finally {
listeners.end();
for (OnScrollChangedListener listener : listeners) {
listener.onScrollChanged();
}
}
}
@ -745,11 +722,11 @@ public final class ViewTreeObserver {
* Returns whether there are listeners for computing internal insets.
*/
final boolean hasComputeInternalInsetsListeners() {
final CopyOnWriteArray<OnComputeInternalInsetsListener> listeners =
final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
mOnComputeInternalInsetsListeners;
return (listeners != null && listeners.size() > 0);
}
/**
* Calls all listeners to compute the current insets.
*/
@ -758,105 +735,12 @@ public final class ViewTreeObserver {
// perform the dispatching. The iterator is a safe guard against listeners that
// could mutate the list by calling the various add/remove methods. This prevents
// the array from being modified while we iterate it.
final CopyOnWriteArray<OnComputeInternalInsetsListener> listeners =
final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
mOnComputeInternalInsetsListeners;
if (listeners != null && listeners.size() > 0) {
CopyOnWriteArray.Access<OnComputeInternalInsetsListener> access = listeners.start();
try {
int count = access.size();
for (int i = 0; i < count; i++) {
access.get(i).onComputeInternalInsets(inoutInfo);
}
} finally {
listeners.end();
for (OnComputeInternalInsetsListener listener : listeners) {
listener.onComputeInternalInsets(inoutInfo);
}
}
}
/**
* Copy on write array. This array is not thread safe, and only one loop can
* iterate over this array at any given time. This class avoids allocations
* until a concurrent modification happens.
*
* Usage:
*
* CopyOnWriteArray.Access<MyData> access = array.start();
* try {
* for (int i = 0; i < access.size(); i++) {
* MyData d = access.get(i);
* }
* } finally {
* access.end();
* }
*/
static class CopyOnWriteArray<T> {
private ArrayList<T> mData = new ArrayList<T>();
private ArrayList<T> mDataCopy;
private final Access<T> mAccess = new Access<T>();
private boolean mStart;
static class Access<T> {
private ArrayList<T> mData;
private int mSize;
T get(int index) {
return mData.get(index);
}
int size() {
return mSize;
}
}
CopyOnWriteArray() {
}
private ArrayList<T> getArray() {
if (mStart) {
if (mDataCopy == null) mDataCopy = new ArrayList<T>(mData);
return mDataCopy;
}
return mData;
}
Access<T> start() {
if (mStart) throw new IllegalStateException("Iteration already started");
mStart = true;
mDataCopy = null;
mAccess.mData = mData;
mAccess.mSize = mData.size();
return mAccess;
}
void end() {
if (!mStart) throw new IllegalStateException("Iteration not started");
mStart = false;
if (mDataCopy != null) {
mData = mDataCopy;
}
mDataCopy = null;
}
int size() {
return getArray().size();
}
void add(T item) {
getArray().add(item);
}
void addAll(CopyOnWriteArray<T> array) {
getArray().addAll(array.mData);
}
void remove(T item) {
getArray().remove(item);
}
void clear() {
getArray().clear();
}
}
}