summaryrefslogtreecommitdiffstats
path: root/core/java/android/widget
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2012-03-14 16:41:42 -0700
committerRomain Guy <romainguy@google.com>2012-03-14 17:19:35 -0700
commit9d849a2f6351caed83105b90cab79223ec2bfbd3 (patch)
treed0569276780cb4cd8123d139deb7dbfa5cbd66b3 /core/java/android/widget
parent390f882f8905e8d1ac0d4b7f2e01aa04dccc3c16 (diff)
downloadframeworks_base-9d849a2f6351caed83105b90cab79223ec2bfbd3.zip
frameworks_base-9d849a2f6351caed83105b90cab79223ec2bfbd3.tar.gz
frameworks_base-9d849a2f6351caed83105b90cab79223ec2bfbd3.tar.bz2
Optimize invalidate calls in lists.
AbsListView was doing too many invalidates during scrolls/flings. Some of them were also covering too large an area of the screen. Change-Id: I68fe5dda3657bddd673996e7cf4f3c3672c66cfc
Diffstat (limited to 'core/java/android/widget')
-rw-r--r--core/java/android/widget/AbsListView.java92
-rw-r--r--core/java/android/widget/EdgeEffect.java49
2 files changed, 101 insertions, 40 deletions
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 5774440..9e07151 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -88,6 +88,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
ViewTreeObserver.OnTouchModeChangeListener,
RemoteViewsAdapter.RemoteAdapterConnectionCallback {
+ @SuppressWarnings("UnusedDeclaration")
private static final String TAG = "AbsListView";
/**
@@ -2429,7 +2430,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final ViewTreeObserver treeObserver = getViewTreeObserver();
treeObserver.removeOnTouchModeChangeListener(this);
if (mTextFilterEnabled && mPopup != null) {
- treeObserver.removeGlobalOnLayoutListener(this);
+ treeObserver.removeOnGlobalLayoutListener(this);
mGlobalLayoutListenerAddedFilter = false;
}
@@ -2943,11 +2944,23 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mDirection = 0; // Reset when entering overscroll.
mTouchMode = TOUCH_MODE_OVERSCROLL;
if (rawDeltaY > 0) {
+ if (!mEdgeGlowTop.isIdle()) {
+ invalidate(mEdgeGlowTop.getBounds());
+ } else {
+ invalidate();
+ }
+
mEdgeGlowTop.onPull((float) overscroll / getHeight());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
} else if (rawDeltaY < 0) {
+ if (!mEdgeGlowBottom.isIdle()) {
+ invalidate(mEdgeGlowBottom.getBounds());
+ } else {
+ invalidate();
+ }
+
mEdgeGlowBottom.onPull((float) overscroll / getHeight());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
@@ -2956,7 +2969,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
mMotionY = y;
- invalidate();
}
mLastY = y;
}
@@ -2990,26 +3002,26 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
+ invalidate(mEdgeGlowTop.getBounds());
} else if (rawDeltaY < 0) {
mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
}
+ invalidate(mEdgeGlowBottom.getBounds());
}
- invalidate();
}
}
if (incrementalDeltaY != 0) {
// Coming back to 'real' list scrolling
- mScrollY = 0;
- invalidateParentIfNeeded();
-
- // No need to do all this work if we're not going to move anyway
- if (incrementalDeltaY != 0) {
- trackMotionScroll(incrementalDeltaY, incrementalDeltaY);
+ if (mScrollY != 0) {
+ mScrollY = 0;
+ invalidateParentIfNeeded();
}
+ trackMotionScroll(incrementalDeltaY, incrementalDeltaY);
+
mTouchMode = TOUCH_MODE_SCROLL;
// We did not scroll the full amount. Treat this essentially like the
@@ -3468,11 +3480,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final int rightPadding = mListPadding.right + mGlowPaddingRight;
final int width = getWidth() - leftPadding - rightPadding;
- canvas.translate(leftPadding,
- Math.min(0, scrollY + mFirstPositionDistanceGuess));
+ int edgeY = Math.min(0, scrollY + mFirstPositionDistanceGuess);
+ canvas.translate(leftPadding, edgeY);
mEdgeGlowTop.setSize(width, getHeight());
if (mEdgeGlowTop.draw(canvas)) {
- invalidate();
+ mEdgeGlowTop.setPosition(leftPadding, edgeY);
+ invalidate(mEdgeGlowTop.getBounds());
}
canvas.restoreToCount(restoreCount);
}
@@ -3483,12 +3496,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final int width = getWidth() - leftPadding - rightPadding;
final int height = getHeight();
- canvas.translate(-width + leftPadding,
- Math.max(height, scrollY + mLastPositionDistanceGuess));
+ int edgeX = -width + leftPadding;
+ int edgeY = Math.max(height, scrollY + mLastPositionDistanceGuess);
+ canvas.translate(edgeX, edgeY);
canvas.rotate(180, width, 0);
mEdgeGlowBottom.setSize(width, height);
if (mEdgeGlowBottom.draw(canvas)) {
- invalidate();
+ // Account for the rotation
+ mEdgeGlowBottom.setPosition(edgeX + width, edgeY - mEdgeGlowBottom.getHeight());
+ invalidate(mEdgeGlowBottom.getBounds());
}
canvas.restoreToCount(restoreCount);
}
@@ -3874,7 +3890,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
// Don't stop just because delta is zero (it could have been rounded)
- final boolean atEnd = trackMotionScroll(delta, delta) && (delta != 0);
+ final boolean atEdge = trackMotionScroll(delta, delta);
+ final boolean atEnd = atEdge && (delta != 0);
if (atEnd) {
if (motionView != null) {
// Tweak the scroll for how far we overshot
@@ -3889,7 +3906,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
if (more && !atEnd) {
- invalidate();
+ if (atEdge) invalidate();
mLastFlingY = y;
post(this);
} else {
@@ -4431,7 +4448,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
private void createScrollingCache() {
- if (mScrollingCacheEnabled && !mCachingStarted) {
+ if (mScrollingCacheEnabled && !mCachingStarted && !isHardwareAccelerated()) {
setChildrenDrawnWithCacheEnabled(true);
setChildrenDrawingCacheEnabled(true);
mCachingStarted = mCachingActive = true;
@@ -4439,23 +4456,25 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
private void clearScrollingCache() {
- if (mClearScrollingCache == null) {
- mClearScrollingCache = new Runnable() {
- public void run() {
- if (mCachingStarted) {
- mCachingStarted = mCachingActive = false;
- setChildrenDrawnWithCacheEnabled(false);
- if ((mPersistentDrawingCache & PERSISTENT_SCROLLING_CACHE) == 0) {
- setChildrenDrawingCacheEnabled(false);
- }
- if (!isAlwaysDrawnWithCacheEnabled()) {
- invalidate();
+ if (!isHardwareAccelerated()) {
+ if (mClearScrollingCache == null) {
+ mClearScrollingCache = new Runnable() {
+ public void run() {
+ if (mCachingStarted) {
+ mCachingStarted = mCachingActive = false;
+ setChildrenDrawnWithCacheEnabled(false);
+ if ((mPersistentDrawingCache & PERSISTENT_SCROLLING_CACHE) == 0) {
+ setChildrenDrawingCacheEnabled(false);
+ }
+ if (!isAlwaysDrawnWithCacheEnabled()) {
+ invalidate();
+ }
}
}
- }
- };
+ };
+ }
+ post(mClearScrollingCache);
}
- post(mClearScrollingCache);
}
/**
@@ -4599,14 +4618,18 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mRecycler.removeSkippedScrap();
}
+ // invalidate before moving the children to avoid unnecessary invalidate
+ // calls to bubble up from the children all the way to the top
+ if (!awakenScrollBars()) {
+ invalidate();
+ }
+
offsetChildrenTopAndBottom(incrementalDeltaY);
if (down) {
mFirstPosition += count;
}
- invalidate();
-
final int absIncrementalDeltaY = Math.abs(incrementalDeltaY);
if (spaceAbove < absIncrementalDeltaY || spaceBelow < absIncrementalDeltaY) {
fillGap(down);
@@ -4629,7 +4652,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mBlockLayoutRequests = false;
invokeOnItemScrollListener();
- awakenScrollBars();
return false;
}
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 83aa8ba..c1f31bb 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.graphics.Rect;
import com.android.internal.R;
import android.content.Context;
@@ -45,6 +46,7 @@ import android.view.animation.Interpolator;
* {@link #draw(Canvas)} method.</p>
*/
public class EdgeEffect {
+ @SuppressWarnings("UnusedDeclaration")
private static final String TAG = "EdgeEffect";
// Time it will take the effect to fully recede in ms
@@ -57,10 +59,7 @@ public class EdgeEffect {
private static final int PULL_DECAY_TIME = 1000;
private static final float MAX_ALPHA = 1.f;
- private static final float HELD_EDGE_ALPHA = 0.7f;
private static final float HELD_EDGE_SCALE_Y = 0.5f;
- private static final float HELD_GLOW_ALPHA = 0.5f;
- private static final float HELD_GLOW_SCALE_Y = 0.5f;
private static final float MAX_GLOW_HEIGHT = 4.f;
@@ -76,7 +75,9 @@ public class EdgeEffect {
private final Drawable mGlow;
private int mWidth;
private int mHeight;
- private final int MIN_WIDTH = 300;
+ private int mX;
+ private int mY;
+ private static final int MIN_WIDTH = 300;
private final int mMinWidth;
private float mEdgeAlpha;
@@ -119,6 +120,8 @@ public class EdgeEffect {
private int mState = STATE_IDLE;
private float mPullDistance;
+
+ private final Rect mBounds = new Rect();
/**
* Construct a new EdgeEffect with a theme appropriate for the provided context.
@@ -145,6 +148,29 @@ public class EdgeEffect {
}
/**
+ * Set the position of this edge effect in pixels. This position is
+ * only used by {@link #getBounds()}.
+ *
+ * @param x The position of the edge effect on the X axis
+ * @param y The position of the edge effect on the Y axis
+ */
+ void setPosition(int x, int y) {
+ mX = x;
+ mY = y;
+ }
+
+ boolean isIdle() {
+ return mState == STATE_IDLE;
+ }
+
+ /**
+ * Returns the height of the effect itself.
+ */
+ int getHeight() {
+ return Math.max(mGlow.getBounds().height(), mEdge.getBounds().height());
+ }
+
+ /**
* Reports if this EdgeEffect's animation is finished. If this method returns false
* after a call to {@link #draw(Canvas)} the host widget should schedule another
* drawing pass to continue the animation.
@@ -301,7 +327,6 @@ public class EdgeEffect {
update();
final int edgeHeight = mEdge.getIntrinsicHeight();
- final int edgeWidth = mEdge.getIntrinsicWidth();
final int glowHeight = mGlow.getIntrinsicHeight();
final int glowWidth = mGlow.getIntrinsicWidth();
@@ -334,9 +359,23 @@ public class EdgeEffect {
}
mEdge.draw(canvas);
+ if (mState == STATE_RECEDE && glowBottom == 0 && edgeBottom == 0) {
+ mState = STATE_IDLE;
+ }
+
return mState != STATE_IDLE;
}
+ /**
+ * Returns the bounds of the edge effect.
+ */
+ public Rect getBounds() {
+ mBounds.set(mGlow.getBounds());
+ mBounds.union(mEdge.getBounds());
+ mBounds.offset(mX, mY);
+ return mBounds;
+ }
+
private void update() {
final long time = AnimationUtils.currentAnimationTimeMillis();
final float t = Math.min((time - mStartTime) / mDuration, 1.f);