Merge "Cache display lists for Drawables"
diff --git a/api/current.txt b/api/current.txt
index 241c540..2c22472 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10338,7 +10338,6 @@
ctor public BitmapDrawable(android.content.res.Resources, java.lang.String);
ctor public deprecated BitmapDrawable(java.io.InputStream);
ctor public BitmapDrawable(android.content.res.Resources, java.io.InputStream);
- method public void draw(android.graphics.Canvas);
method public final android.graphics.Bitmap getBitmap();
method public final android.graphics.drawable.Drawable.ConstantState getConstantState();
method public int getGravity();
@@ -10364,7 +10363,6 @@
public class ClipDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
ctor public ClipDrawable(android.graphics.drawable.Drawable, int, int);
- method public void draw(android.graphics.Canvas);
method public int getOpacity();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -10378,7 +10376,6 @@
public class ColorDrawable extends android.graphics.drawable.Drawable {
ctor public ColorDrawable();
ctor public ColorDrawable(int);
- method public void draw(android.graphics.Canvas);
method public int getColor();
method public int getOpacity();
method public void setAlpha(int);
@@ -10397,7 +10394,7 @@
method public static android.graphics.drawable.Drawable createFromStream(java.io.InputStream, java.lang.String);
method public static android.graphics.drawable.Drawable createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static android.graphics.drawable.Drawable createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public abstract void draw(android.graphics.Canvas);
+ method public void draw(android.graphics.Canvas);
method public int getAlpha();
method public final android.graphics.Rect getBounds();
method public android.graphics.drawable.Drawable.Callback getCallback();
@@ -10421,6 +10418,7 @@
method public void jumpToCurrentState();
method public android.graphics.drawable.Drawable mutate();
method protected void onBoundsChange(android.graphics.Rect);
+ method protected void onDraw(android.graphics.Canvas);
method protected boolean onLevelChange(int);
method protected boolean onStateChange(int[]);
method public static int resolveOpacity(int, int);
@@ -10456,7 +10454,6 @@
public class DrawableContainer extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
ctor public DrawableContainer();
- method public void draw(android.graphics.Canvas);
method public int getOpacity();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -10497,7 +10494,6 @@
public class GradientDrawable extends android.graphics.drawable.Drawable {
ctor public GradientDrawable();
ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, int[]);
- method public void draw(android.graphics.Canvas);
method public int getOpacity();
method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
method public boolean onStateChange(int[]);
@@ -10544,7 +10540,6 @@
public class InsetDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
ctor public InsetDrawable(android.graphics.drawable.Drawable, int);
ctor public InsetDrawable(android.graphics.drawable.Drawable, int, int, int, int);
- method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable getDrawable();
method public int getOpacity();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
@@ -10556,7 +10551,6 @@
public class LayerDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
ctor public LayerDrawable(android.graphics.drawable.Drawable[]);
- method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
method public android.graphics.drawable.Drawable getDrawable(int);
method public int getId(int);
@@ -10587,7 +10581,6 @@
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.Bitmap, byte[], android.graphics.Rect, java.lang.String);
ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
- method public void draw(android.graphics.Canvas);
method public int getOpacity();
method public android.graphics.Paint getPaint();
method public void setAlpha(int);
@@ -10606,7 +10599,6 @@
public class PictureDrawable extends android.graphics.drawable.Drawable {
ctor public PictureDrawable(android.graphics.Picture);
- method public void draw(android.graphics.Canvas);
method public int getOpacity();
method public android.graphics.Picture getPicture();
method public void setAlpha(int);
@@ -10620,7 +10612,6 @@
public class RotateDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
ctor public RotateDrawable();
- method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable getDrawable();
method public int getOpacity();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
@@ -10632,7 +10623,6 @@
public class ScaleDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
ctor public ScaleDrawable(android.graphics.drawable.Drawable, int, float, float);
- method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable getDrawable();
method public int getOpacity();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
@@ -10645,7 +10635,6 @@
public class ShapeDrawable extends android.graphics.drawable.Drawable {
ctor public ShapeDrawable();
ctor public ShapeDrawable(android.graphics.drawable.shapes.Shape);
- method public void draw(android.graphics.Canvas);
method public int getOpacity();
method public android.graphics.Paint getPaint();
method public android.graphics.drawable.ShapeDrawable.ShaderFactory getShaderFactory();
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 9360558..52e5b5b 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -456,7 +456,7 @@
}
@Override
- public void draw(Canvas canvas) {
+ protected void onDraw(Canvas canvas) {
Bitmap bitmap = mBitmap;
if (bitmap != null) {
final BitmapState state = mBitmapState;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index b8365aa..cfb1983 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -39,6 +39,9 @@
import android.util.StateSet;
import android.util.TypedValue;
import android.util.Xml;
+import android.view.DisplayList;
+import android.view.HardwareCanvas;
+import android.view.HardwareRenderer;
import android.view.View;
import java.io.IOException;
@@ -139,16 +142,96 @@
private Rect mBounds = ZERO_BOUNDS_RECT; // lazily becomes a new Rect()
private WeakReference<Callback> mCallback = null;
private boolean mVisible = true;
+ private DisplayList mDisplayList;
private int mLayoutDirection;
/**
* Draw in its bounds (set via setBounds) respecting optional effects such
* as alpha (set via setAlpha) and color filter (set via setColorFilter).
+ * <p>
+ * Overriding this method will prevent caching optimizations. To enable
+ * optimizations, override {@link #onDraw} instead.
*
* @param canvas The canvas to draw into
*/
- public abstract void draw(Canvas canvas);
+ public void draw(Canvas canvas) {
+ if (canvas != null && canvas.isHardwareAccelerated()) {
+ final HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas;
+ final DisplayList displayList = getDisplayList(hardwareCanvas);
+ if (displayList != null) {
+ final int restoreCount = hardwareCanvas.save(Canvas.MATRIX_SAVE_FLAG);
+ hardwareCanvas.translate(mBounds.left, mBounds.top);
+ hardwareCanvas.drawDisplayList(displayList);
+ hardwareCanvas.restoreToCount(restoreCount);
+ return;
+ }
+ }
+
+ onDraw(canvas);
+ }
+
+ /**
+ * Draw in its bounds (set via setBounds) respecting optional effects such
+ * as alpha (set via setAlpha) and color filter (set via setColorFilter).
+ * <p>
+ * Overriding this method, rather than {@link #draw}, enables caching
+ * optimizations that avoid re-drawing when unnecessary.
+ *
+ * @param canvas The canvas to draw into
+ */
+ protected void onDraw(Canvas canvas) {
+ throw new UnsupportedOperationException(
+ "Drawable subclasses must implement either draw or onDraw");
+ }
+
+ /**
+ * Gets a display list that can be used to draw this drawable again without
+ * invoking its draw method.
+ *
+ * @param hardwareCanvas The hardware canvas.
+ * @return A DisplayList ready to replay, or null if caching is not enabled.
+ * @hide
+ */
+ private DisplayList getDisplayList(HardwareCanvas hardwareCanvas) {
+ DisplayList displayList = mDisplayList;
+ if (displayList != null && displayList.isValid()) {
+ // Note: This code assumes that the display list previously generated
+ // is compatible with the given hardware canvas. That might not be true
+ // if we start using multiple different types of hardware canvas
+ // in the system someday.
+ return displayList;
+ }
+
+ displayList = DisplayList.create(getClass().getName());
+ mDisplayList = displayList;
+
+ final Rect bounds = mBounds;
+ final int width = bounds.width();
+ final int height = bounds.height();
+ final HardwareCanvas canvas = displayList.start(width, height);
+ canvas.onPreDraw(null);
+
+ // Draw the display list with origin (0,0) so that if the position
+ // changes then we can translate without recreating the display list.
+ final int restoreCount = canvas.save();
+ try {
+ canvas.translate(-bounds.left, -bounds.top);
+ onDraw(canvas);
+ } finally {
+ canvas.restoreToCount(restoreCount);
+ canvas.onPostDraw();
+ displayList.end();
+ }
+
+ displayList.setLeftTopRightBottom(0, 0, width, height);
+ displayList.setClipToBounds(false);
+ return displayList;
+ }
+
+ private void invalidateDisplayList() {
+ mDisplayList = null;
+ }
/**
* Specify a bounding rectangle for the Drawable. This is where the drawable
@@ -163,10 +246,11 @@
if (oldBounds.left != left || oldBounds.top != top ||
oldBounds.right != right || oldBounds.bottom != bottom) {
- if (!oldBounds.isEmpty()) {
- // first invalidate the previous bounds
- invalidateSelf();
+ if (oldBounds.right - oldBounds.left != right - left
+ || oldBounds.bottom - oldBounds.top != bottom - top) {
+ invalidateDisplayList();
}
+
mBounds.set(left, top, right, bottom);
onBoundsChange(mBounds);
}
@@ -354,6 +438,8 @@
* @see #setCallback(android.graphics.drawable.Drawable.Callback)
*/
public void invalidateSelf() {
+ invalidateDisplayList();
+
final Callback callback = getCallback();
if (callback != null) {
callback.invalidateDrawable(this);
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 75184e0..6a9454c 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -472,7 +472,7 @@
}
@Override
- public void draw(Canvas canvas) {
+ protected void onDraw(Canvas canvas) {
if (!ensureValidRect()) {
// nothing to draw
return;
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 515d3c1..ee64d7a 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -223,7 +223,7 @@
}
@Override
- public void draw(Canvas canvas) {
+ protected void onDraw(Canvas canvas) {
final Rect bounds = getBounds();
final boolean needsMirroring = needsMirroring();
if (needsMirroring) {
diff --git a/graphics/java/android/graphics/drawable/PictureDrawable.java b/graphics/java/android/graphics/drawable/PictureDrawable.java
index cb2d8f6..2118b23 100644
--- a/graphics/java/android/graphics/drawable/PictureDrawable.java
+++ b/graphics/java/android/graphics/drawable/PictureDrawable.java
@@ -60,7 +60,7 @@
}
@Override
- public void draw(Canvas canvas) {
+ protected void onDraw(Canvas canvas) {
if (mPicture != null) {
Rect bounds = getBounds();
canvas.save();
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 93f2dc60..9ca3bbf 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -210,7 +210,7 @@
}
@Override
- public void draw(Canvas canvas) {
+ protected void onDraw(Canvas canvas) {
Rect r = getBounds();
Paint paint = mShapeState.mPaint;