From f390f770ee570f1f4def41b165cb9492e381be40 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Thu, 13 Jun 2013 15:11:16 -0700 Subject: [PATCH] Postpone creating new drawables for DrawableContainerState. When creating a DrawableContainerState from a constant state, calls to ConstantState.newDrawable() are postponed and made as they are needed. Bug: 9280861 Change-Id: I03c93a43ee00aca3ff618d66d7f507f1722538d1 --- .../graphics/drawable/DrawableContainer.java | 327 ++++++++++++------ .../graphics/drawable/StateListDrawable.java | 8 +- 2 files changed, 229 insertions(+), 106 deletions(-) diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index e75ec753062af..f9cd4e261170e 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -23,6 +23,7 @@ import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.SystemClock; +import android.util.SparseArray; /** * A helper class that contains several {@link Drawable}s and selects which one to use. @@ -76,7 +77,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { | mDrawableContainerState.mChangingConfigurations | mDrawableContainerState.mChildrenChangingConfigurations; } - + @Override public boolean getPadding(Rect padding) { final Rect r = mDrawableContainerState.getConstantPadding(); @@ -137,7 +138,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } } } - + /** * Change the global fade duration when a new drawable is entering * the scene. @@ -146,7 +147,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { public void setEnterFadeDuration(int ms) { mDrawableContainerState.mEnterFadeDuration = ms; } - + /** * Change the global fade duration when a new drawable is leaving * the scene. @@ -155,7 +156,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { public void setExitFadeDuration(int ms) { mDrawableContainerState.mExitFadeDuration = ms; } - + @Override protected void onBoundsChange(Rect bounds) { if (mLastDrawable != null) { @@ -165,12 +166,12 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mCurrDrawable.setBounds(bounds); } } - + @Override public boolean isStateful() { return mDrawableContainerState.isStateful(); } - + @Override public void jumpToCurrentState() { boolean changed = false; @@ -233,7 +234,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } return mCurrDrawable != null ? mCurrDrawable.getIntrinsicHeight() : -1; } - + @Override public int getMinimumWidth() { if (mDrawableContainerState.isConstantSize()) { @@ -316,7 +317,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) { - Drawable d = mDrawableContainerState.mDrawables[idx]; + final Drawable d = mDrawableContainerState.getChild(idx); mCurrDrawable = d; mCurIndex = idx; if (d != null) { @@ -358,7 +359,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return true; } - + void animate(boolean schedule) { final long now = SystemClock.uptimeMillis(); boolean animating = false; @@ -432,90 +433,105 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { */ public abstract static class DrawableContainerState extends ConstantState { final DrawableContainer mOwner; + final Resources mRes; - int mChangingConfigurations; - int mChildrenChangingConfigurations; - - Drawable[] mDrawables; - int mNumChildren; + SparseArray mDrawableFutures; - boolean mVariablePadding = false; - Rect mConstantPadding = null; + int mChangingConfigurations; + int mChildrenChangingConfigurations; - boolean mConstantSize = false; - boolean mComputedConstantSize = false; - int mConstantWidth; - int mConstantHeight; - int mConstantMinimumWidth; - int mConstantMinimumHeight; + Drawable[] mDrawables; + int mNumChildren; - int mOpacity; + boolean mVariablePadding; + boolean mPaddingChecked; + Rect mConstantPadding; - boolean mHaveStateful = false; - boolean mStateful; + boolean mConstantSize; + boolean mComputedConstantSize; + int mConstantWidth; + int mConstantHeight; + int mConstantMinimumWidth; + int mConstantMinimumHeight; - boolean mCheckedConstantState; - boolean mCanConstantState; + boolean mCheckedOpacity; + int mOpacity; - boolean mPaddingChecked = false; - - boolean mDither = DEFAULT_DITHER; + boolean mCheckedStateful; + boolean mStateful; - int mEnterFadeDuration; - int mExitFadeDuration; + boolean mCheckedConstantState; + boolean mCanConstantState; + + boolean mDither = DEFAULT_DITHER; + + boolean mMutated; + int mLayoutDirection; + + int mEnterFadeDuration; + int mExitFadeDuration; DrawableContainerState(DrawableContainerState orig, DrawableContainer owner, Resources res) { mOwner = owner; + mRes = res; if (orig != null) { mChangingConfigurations = orig.mChangingConfigurations; mChildrenChangingConfigurations = orig.mChildrenChangingConfigurations; - - final Drawable[] origDr = orig.mDrawables; - mDrawables = new Drawable[origDr.length]; - mNumChildren = orig.mNumChildren; + mCheckedConstantState = true; + mCanConstantState = true; - final int N = mNumChildren; - for (int i=0; i origDf = orig.mDrawableFutures; + if (origDf != null) { + mDrawableFutures = origDf.clone(); + } else { + mDrawableFutures = new SparseArray(mNumChildren); + } + + final int N = mNumChildren; + for (int i = 0; i < N; i++) { + if (origDr[i] != null) { + mDrawableFutures.put(i, new ConstantStateFuture(origDr[i])); + } + } } else { mDrawables = new Drawable[10]; mNumChildren = 0; - mCheckedConstantState = mCanConstantState = false; } } - + @Override public int getChangingConfigurations() { return mChangingConfigurations | mChildrenChangingConfigurations; @@ -534,7 +550,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mDrawables[pos] = dr; mNumChildren++; mChildrenChangingConfigurations |= dr.getChangingConfigurations(); - mHaveStateful = false; + mCheckedStateful = false; + mCheckedOpacity = false; mConstantPadding = null; mPaddingChecked = false; @@ -547,6 +564,18 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return mDrawables.length; } + private final void createAllFutures() { + if (mDrawableFutures != null) { + final int futureCount = mDrawableFutures.size(); + for (int keyIndex = 0; keyIndex < futureCount; keyIndex++) { + final int index = mDrawableFutures.keyAt(keyIndex); + mDrawables[index] = mDrawableFutures.valueAt(keyIndex).get(this); + } + + mDrawableFutures = null; + } + } + public final int getChildCount() { return mNumChildren; } @@ -555,25 +584,65 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { * @deprecated Use {@link #getChild} instead. */ public final Drawable[] getChildren() { + // Create all futures for backwards compatibility. + createAllFutures(); + return mDrawables; } public final Drawable getChild(int index) { - return mDrawables[index]; + final Drawable result = mDrawables[index]; + if (result != null) { + return result; + } + + // Prepare future drawable if necessary. + if (mDrawableFutures != null) { + final int keyIndex = mDrawableFutures.indexOfKey(index); + if (keyIndex >= 0) { + final Drawable prepared = mDrawableFutures.valueAt(keyIndex).get(this); + mDrawables[index] = prepared; + mDrawableFutures.removeAt(keyIndex); + return prepared; + } + } + + return null; + } + + final void setLayoutDirection(int layoutDirection) { + // No need to call createAllFutures, since future drawables will + // change layout direction when they are prepared. + final int N = mNumChildren; + final Drawable[] drawables = mDrawables; + for (int i = 0; i < N; i++) { + if (drawables[i] != null) { + drawables[i].setLayoutDirection(layoutDirection); + } + } + + mLayoutDirection = layoutDirection; } final void mutate() { - final int N = getChildCount(); + // No need to call createAllFutures, since future drawables will + // mutate when they are prepared. + final int N = mNumChildren; final Drawable[] drawables = mDrawables; for (int i = 0; i < N; i++) { - if (drawables[i] != null) drawables[i].mutate(); + if (drawables[i] != null) { + drawables[i].mutate(); + } } + + mMutated = true; } - /** A boolean value indicating whether to use the maximum padding value of - * all frames in the set (false), or to use the padding value of the frame - * being shown (true). Default value is false. - */ + /** + * A boolean value indicating whether to use the maximum padding value + * of all frames in the set (false), or to use the padding value of the + * frame being shown (true). Default value is false. + */ public final void setVariablePadding(boolean variable) { mVariablePadding = variable; } @@ -582,13 +651,16 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (mVariablePadding) { return null; } - if (mConstantPadding != null || mPaddingChecked) { + + if ((mConstantPadding != null) || mPaddingChecked) { return mConstantPadding; } + createAllFutures(); + Rect r = null; final Rect t = new Rect(); - final int N = getChildCount(); + final int N = mNumChildren; final Drawable[] drawables = mDrawables; for (int i = 0; i < N; i++) { if (drawables[i].getPadding(t)) { @@ -599,6 +671,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (t.bottom > r.bottom) r.bottom = t.bottom; } } + mPaddingChecked = true; return (mConstantPadding = r); } @@ -646,12 +719,14 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { protected void computeConstantSize() { mComputedConstantSize = true; - final int N = getChildCount(); + createAllFutures(); + + final int N = mNumChildren; final Drawable[] drawables = mDrawables; mConstantWidth = mConstantHeight = -1; mConstantMinimumWidth = mConstantMinimumHeight = 0; for (int i = 0; i < N; i++) { - Drawable dr = drawables[i]; + final Drawable dr = drawables[i]; int s = dr.getIntrinsicWidth(); if (s > mConstantWidth) mConstantWidth = s; s = dr.getIntrinsicHeight(); @@ -680,33 +755,45 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } public final int getOpacity() { - final int N = getChildCount(); + if (mCheckedOpacity) { + return mOpacity; + } + + createAllFutures(); + + mCheckedOpacity = true; + + final int N = mNumChildren; final Drawable[] drawables = mDrawables; - int op = N > 0 ? drawables[0].getOpacity() : PixelFormat.TRANSPARENT; + int op = (N > 0) ? drawables[0].getOpacity() : PixelFormat.TRANSPARENT; for (int i = 1; i < N; i++) { op = Drawable.resolveOpacity(op, drawables[i].getOpacity()); } + mOpacity = op; return op; } public final boolean isStateful() { - if (mHaveStateful) { + if (mCheckedStateful) { return mStateful; } - - boolean stateful = false; - final int N = getChildCount(); + + createAllFutures(); + + mCheckedStateful = true; + + final int N = mNumChildren; + final Drawable[] drawables = mDrawables; for (int i = 0; i < N; i++) { - if (mDrawables[i].isStateful()) { - stateful = true; - break; + if (drawables[i].isStateful()) { + mStateful = true; + return true; } } - - mStateful = stateful; - mHaveStateful = true; - return stateful; + + mStateful = false; + return false; } public void growArray(int oldSize, int newSize) { @@ -716,24 +803,60 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } public synchronized boolean canConstantState() { - if (!mCheckedConstantState) { - mCanConstantState = true; - final int N = mNumChildren; - for (int i=0; i