GifDrawable.java revision 72e189cc27d62677a7e45dc5ddfcf4cc0d6466ab
1ea01ddd754126290fc18c3dc8f6095ce0216768aSam Juddpackage com.bumptech.glide.load.resource.gif; 2ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 3fcca8d79a3a04e71924d06799de2af46c923a84eSam Juddimport android.annotation.TargetApi; 4a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Juddimport android.content.Context; 5a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Juddimport android.content.res.Resources; 6ea01ddd754126290fc18c3dc8f6095ce0216768aSam Juddimport android.graphics.Bitmap; 7ea01ddd754126290fc18c3dc8f6095ce0216768aSam Juddimport android.graphics.Canvas; 8ea01ddd754126290fc18c3dc8f6095ce0216768aSam Juddimport android.graphics.ColorFilter; 9ea01ddd754126290fc18c3dc8f6095ce0216768aSam Juddimport android.graphics.Paint; 10ea01ddd754126290fc18c3dc8f6095ce0216768aSam Juddimport android.graphics.PixelFormat; 1138ced22f14acd14b69bb102605505d1feb04b46bSam Juddimport android.graphics.Rect; 12ea01ddd754126290fc18c3dc8f6095ce0216768aSam Juddimport android.graphics.drawable.Drawable; 13fcca8d79a3a04e71924d06799de2af46c923a84eSam Juddimport android.os.Build; 1438ced22f14acd14b69bb102605505d1feb04b46bSam Juddimport android.view.Gravity; 15f7a6d65cf7c1a41908dd48e0dab68ee5b881387eSam Judd 160f49c87b2f26f3e086f021461b7e5409a7d42be0Sam Juddimport com.bumptech.glide.gifdecoder.GifDecoder; 17a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Juddimport com.bumptech.glide.gifdecoder.GifHeader; 18a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Juddimport com.bumptech.glide.load.Transformation; 194185efc3779f8caf2dd8103aa84705e7a88f679cSam Juddimport com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; 20193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Juddimport com.bumptech.glide.load.resource.drawable.GlideDrawable; 21ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 225f4610b54d517be58105bcf73ce3291ba79f9f40Sam Judd/** 235f4610b54d517be58105bcf73ce3291ba79f9f40Sam Judd * An animated {@link android.graphics.drawable.Drawable} that plays the frames of an animated GIF. 245f4610b54d517be58105bcf73ce3291ba79f9f40Sam Judd */ 25193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Juddpublic class GifDrawable extends GlideDrawable implements GifFrameManager.FrameCallback { 26a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd private final Paint paint = new Paint(); 2738ced22f14acd14b69bb102605505d1feb04b46bSam Judd private final Rect destRect = new Rect(); 28da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd private final GifFrameManager frameManager; 29da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd private final GifState state; 30da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd private final GifDecoder decoder; 31da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd 32193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd /** True if the drawable is currently animating. */ 33da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd private boolean isRunning; 34193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd /** True if the drawable should animate while visible. */ 35da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd private boolean isStarted; 36193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd /** True if the drawable's resources have been recycled. */ 374f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd private boolean isRecycled; 38a9d87fb5e13a86c9ba52d400815566c020e1d3d5Sam Judd /** 39a9d87fb5e13a86c9ba52d400815566c020e1d3d5Sam Judd * True if the drawable is currently visible. Default to true because on certain platforms (at least 4.1.1), 40a9d87fb5e13a86c9ba52d400815566c020e1d3d5Sam Judd * setVisible is not called on {@link android.graphics.drawable.Drawable Drawables} during 41a9d87fb5e13a86c9ba52d400815566c020e1d3d5Sam Judd * {@link android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}. See issue #130. 42a9d87fb5e13a86c9ba52d400815566c020e1d3d5Sam Judd */ 43a9d87fb5e13a86c9ba52d400815566c020e1d3d5Sam Judd private boolean isVisible = true; 44193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd /** The number of times we've looped over all the frames in the gif. */ 45193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd private int loopCount; 46193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd /** The number of times to loop through the gif animation. */ 47193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd private int maxLoopCount = LOOP_FOREVER; 48ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 4938ced22f14acd14b69bb102605505d1feb04b46bSam Judd private boolean applyGravity; 5038ced22f14acd14b69bb102605505d1feb04b46bSam Judd 5121c2822985058df655ee4874798297f74c5e367eSam Judd /** 5221c2822985058df655ee4874798297f74c5e367eSam Judd * Constructor for GifDrawable. 5321c2822985058df655ee4874798297f74c5e367eSam Judd * 544185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd * @see #setFrameTransformation(com.bumptech.glide.load.Transformation, android.graphics.Bitmap) 5521c2822985058df655ee4874798297f74c5e367eSam Judd * 5621c2822985058df655ee4874798297f74c5e367eSam Judd * @param context A context. 5721c2822985058df655ee4874798297f74c5e367eSam Judd * @param bitmapProvider An {@link com.bumptech.glide.gifdecoder.GifDecoder.BitmapProvider} that can be used to 5821c2822985058df655ee4874798297f74c5e367eSam Judd * retrieve re-usable {@link android.graphics.Bitmap}s. 594185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd * @param bitmapPool A {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool} that can be used to return 604185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd * the first frame when this drawable is recycled. 6121c2822985058df655ee4874798297f74c5e367eSam Judd * @param frameTransformation An {@link com.bumptech.glide.load.Transformation} that can be applied to each frame. 6221c2822985058df655ee4874798297f74c5e367eSam Judd * @param targetFrameWidth The desired width of the frames displayed by this drawable (the width of the view or 6321c2822985058df655ee4874798297f74c5e367eSam Judd * {@link com.bumptech.glide.request.target.Target} this drawable is being loaded into). 6421c2822985058df655ee4874798297f74c5e367eSam Judd * @param targetFrameHeight The desired height of the frames displayed by this drawable (the height of the view or 6521c2822985058df655ee4874798297f74c5e367eSam Judd * {@link com.bumptech.glide.request.target.Target} this drawable is being loaded into). 6621c2822985058df655ee4874798297f74c5e367eSam Judd * @param gifHeader The header data for this gif. 6721c2822985058df655ee4874798297f74c5e367eSam Judd * @param data The full bytes of the gif. 684185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd * @param firstFrame The decoded and transformed first frame of this gif. 6921c2822985058df655ee4874798297f74c5e367eSam Judd */ 704185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd public GifDrawable(Context context, GifDecoder.BitmapProvider bitmapProvider, BitmapPool bitmapPool, 71b4cc7fa5f667e4a56514823cf2ad85d7435b498aSam Judd Transformation<Bitmap> frameTransformation, int targetFrameWidth, int targetFrameHeight, 724185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd GifHeader gifHeader, byte[] data, Bitmap firstFrame) { 73b4cc7fa5f667e4a56514823cf2ad85d7435b498aSam Judd this(new GifState(gifHeader, data, context, frameTransformation, targetFrameWidth, targetFrameHeight, 744185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd bitmapProvider, bitmapPool, firstFrame)); 75a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd } 76a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd 775ba19a0e69ad3a651b8f13ba45de48a56b56ce36Sam Judd GifDrawable(GifState state) { 7872e189cc27d62677a7e45dc5ddfcf4cc0d6466abSam Judd if (state == null) { 7972e189cc27d62677a7e45dc5ddfcf4cc0d6466abSam Judd throw new NullPointerException("GifState must not be null"); 8072e189cc27d62677a7e45dc5ddfcf4cc0d6466abSam Judd } 8172e189cc27d62677a7e45dc5ddfcf4cc0d6466abSam Judd 82a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd this.state = state; 83a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd this.decoder = new GifDecoder(state.bitmapProvider); 84b4cc7fa5f667e4a56514823cf2ad85d7435b498aSam Judd decoder.setData(state.gifHeader, state.data); 85b4762ebd63a4da3efd214b91cf45909a9471a3e7Sam Judd frameManager = new GifFrameManager(state.context, decoder, state.targetWidth, state.targetHeight); 86b4762ebd63a4da3efd214b91cf45909a9471a3e7Sam Judd frameManager.setFrameTransformation(state.frameTransformation); 87a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd } 88a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd 894185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd // Visible for testing. 904185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd GifDrawable(GifDecoder decoder, GifFrameManager frameManager, Bitmap firstFrame, BitmapPool bitmapPool) { 91ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd this.decoder = decoder; 92ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd this.frameManager = frameManager; 93a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd this.state = new GifState(null); 944185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd state.bitmapPool = bitmapPool; 954185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd state.firstFrame = firstFrame; 964185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd } 974185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd 984185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd public Bitmap getFirstFrame() { 994185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd return state.firstFrame; 100ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 101ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 1024185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd public void setFrameTransformation(Transformation<Bitmap> frameTransformation, Bitmap firstFrame) { 103a61f3e9b2f21355cf8a0d3cdb0da15f19369a5ebSam Judd if (firstFrame == null) { 104a61f3e9b2f21355cf8a0d3cdb0da15f19369a5ebSam Judd throw new NullPointerException("The first frame of the GIF must not be null"); 105a61f3e9b2f21355cf8a0d3cdb0da15f19369a5ebSam Judd } 106b4762ebd63a4da3efd214b91cf45909a9471a3e7Sam Judd if (frameTransformation == null) { 107b4762ebd63a4da3efd214b91cf45909a9471a3e7Sam Judd throw new NullPointerException("The frame transformation must not be null"); 108b4762ebd63a4da3efd214b91cf45909a9471a3e7Sam Judd } 10921c2822985058df655ee4874798297f74c5e367eSam Judd state.frameTransformation = frameTransformation; 1104185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd state.firstFrame = firstFrame; 111b4762ebd63a4da3efd214b91cf45909a9471a3e7Sam Judd frameManager.setFrameTransformation(frameTransformation); 11221c2822985058df655ee4874798297f74c5e367eSam Judd } 11321c2822985058df655ee4874798297f74c5e367eSam Judd 114f7b3e5d7a4893fd55b3fd36be56bb37319d8aa24Sam Judd public GifDecoder getDecoder() { 115f7b3e5d7a4893fd55b3fd36be56bb37319d8aa24Sam Judd return decoder; 116f7b3e5d7a4893fd55b3fd36be56bb37319d8aa24Sam Judd } 117f7b3e5d7a4893fd55b3fd36be56bb37319d8aa24Sam Judd 11821c2822985058df655ee4874798297f74c5e367eSam Judd public Transformation<Bitmap> getFrameTransformation() { 11921c2822985058df655ee4874798297f74c5e367eSam Judd return state.frameTransformation; 12021c2822985058df655ee4874798297f74c5e367eSam Judd } 12121c2822985058df655ee4874798297f74c5e367eSam Judd 12221c2822985058df655ee4874798297f74c5e367eSam Judd public byte[] getData() { 12321c2822985058df655ee4874798297f74c5e367eSam Judd return state.data; 12421c2822985058df655ee4874798297f74c5e367eSam Judd } 12521c2822985058df655ee4874798297f74c5e367eSam Judd 126b4ed2bbf3fbe3c5bccc57fa253ee8abd13b38549Sam Judd public int getFrameCount() { 127b4ed2bbf3fbe3c5bccc57fa253ee8abd13b38549Sam Judd return decoder.getFrameCount(); 128b4ed2bbf3fbe3c5bccc57fa253ee8abd13b38549Sam Judd } 129b4ed2bbf3fbe3c5bccc57fa253ee8abd13b38549Sam Judd 130193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd private void resetLoopCount() { 131193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd loopCount = 0; 132193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd } 133193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd 134ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd @Override 135ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd public void start() { 136da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd isStarted = true; 137193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd resetLoopCount(); 138da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd if (isVisible) { 139da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd startRunning(); 140da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd } 141da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd } 142da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd 143da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd @Override 144da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd public void stop() { 145da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd isStarted = false; 146da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd stopRunning(); 1476958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd 1486958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd // On APIs > honeycomb we know our drawable is not being displayed anymore when it's callback is cleared and so 1496958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd // we can use the absence of a callback as an indication that it's ok to clear our temporary data. Prior to 1506958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd // honeycomb we can't tell if our callback is null and instead eagerly reset to avoid holding on to resources we 1516958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd // no longer need. 1526958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { 1536958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd reset(); 1546958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd } 1556958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd } 1566958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd 1576958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd /** 1586958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd * Clears temporary data and resets the drawable back to the first frame. 1596958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd */ 1606958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd private void reset() { 1616958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd frameManager.clear(); 1626958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd invalidateSelf(); 163da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd } 164da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd 165da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd private void startRunning() { 166a128f6fbc301213074e0e3eaaf7c92f71c5da901Sam Judd // If we have only a single frame, we don't want to decode it endlessly. 167a128f6fbc301213074e0e3eaaf7c92f71c5da901Sam Judd if (decoder.getFrameCount() == 1) { 168a128f6fbc301213074e0e3eaaf7c92f71c5da901Sam Judd invalidateSelf(); 169a128f6fbc301213074e0e3eaaf7c92f71c5da901Sam Judd } else if (!isRunning) { 170ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd isRunning = true; 1718e9362526ca1e73364de269ae09c75c98d0e23f5Sam Judd frameManager.getNextFrame(this); 172ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd invalidateSelf(); 173ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 174ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 175ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 176da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd private void stopRunning() { 177da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd isRunning = false; 178da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd } 179da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd 180ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd @Override 181ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd public boolean setVisible(boolean visible, boolean restart) { 182da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd isVisible = visible; 183ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd if (!visible) { 184da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd stopRunning(); 185da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd } else if (isStarted) { 186da4b3dbb786c0f791496e8701bb2e4fc9dbe3536Sam Judd startRunning(); 187ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 188ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd return super.setVisible(visible, restart); 189ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 190ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 191ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd @Override 192ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd public int getIntrinsicWidth() { 1934185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd return state.firstFrame.getWidth(); 194ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 195ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 196ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd @Override 197ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd public int getIntrinsicHeight() { 1984185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd return state.firstFrame.getHeight(); 199ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 200ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 201ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd @Override 202ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd public boolean isRunning() { 203ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd return isRunning; 204ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 205ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 206ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd // For testing. 207ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd void setIsRunning(boolean isRunning) { 208ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd this.isRunning = isRunning; 209ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 210ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 211ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd @Override 21238ced22f14acd14b69bb102605505d1feb04b46bSam Judd protected void onBoundsChange(Rect bounds) { 21338ced22f14acd14b69bb102605505d1feb04b46bSam Judd super.onBoundsChange(bounds); 21438ced22f14acd14b69bb102605505d1feb04b46bSam Judd applyGravity = true; 21538ced22f14acd14b69bb102605505d1feb04b46bSam Judd } 21638ced22f14acd14b69bb102605505d1feb04b46bSam Judd 21738ced22f14acd14b69bb102605505d1feb04b46bSam Judd @Override 218ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd public void draw(Canvas canvas) { 2191579932986cc7438b103c811adeb0a14feab0adaSam Judd if (isRecycled) { 2201579932986cc7438b103c811adeb0a14feab0adaSam Judd return; 2211579932986cc7438b103c811adeb0a14feab0adaSam Judd } 22238ced22f14acd14b69bb102605505d1feb04b46bSam Judd 22338ced22f14acd14b69bb102605505d1feb04b46bSam Judd if (applyGravity) { 22438ced22f14acd14b69bb102605505d1feb04b46bSam Judd Gravity.apply(GifState.GRAVITY, getIntrinsicWidth(), getIntrinsicHeight(), getBounds(), destRect); 22538ced22f14acd14b69bb102605505d1feb04b46bSam Judd applyGravity = false; 22638ced22f14acd14b69bb102605505d1feb04b46bSam Judd } 22738ced22f14acd14b69bb102605505d1feb04b46bSam Judd 2281579932986cc7438b103c811adeb0a14feab0adaSam Judd Bitmap currentFrame = frameManager.getCurrentFrame(); 2294185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd Bitmap toDraw = currentFrame != null ? currentFrame : state.firstFrame; 23038ced22f14acd14b69bb102605505d1feb04b46bSam Judd canvas.drawBitmap(toDraw, null, destRect, paint); 231ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 232ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 233ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd @Override 234ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd public void setAlpha(int i) { 235ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd paint.setAlpha(i); 236ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 237ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 238ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd @Override 239ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd public void setColorFilter(ColorFilter colorFilter) { 240ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd paint.setColorFilter(colorFilter); 241ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 242ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 243ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd @Override 244ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd public int getOpacity() { 2452c259f532bee14a4f3f6be419bcfb58ef5e22ff5Sam Judd // We can't tell, so default to transparent to be safe. 2462c259f532bee14a4f3f6be419bcfb58ef5e22ff5Sam Judd return PixelFormat.TRANSPARENT; 247ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 248ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 249e7319b67364bd0ac6306bc7470a43d4a31600c1aRobert Papp @TargetApi(Build.VERSION_CODES.HONEYCOMB) 250ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd @Override 2511579932986cc7438b103c811adeb0a14feab0adaSam Judd public void onFrameRead(int frameIndex) { 2526958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && getCallback() == null) { 2530d8a954b91ef8a37c944c2fdee75966c6f94d7bbSam Judd stop(); 2546958330c93825bbfb70aea1aff9aeed76b59af4eSam Judd reset(); 2550d8a954b91ef8a37c944c2fdee75966c6f94d7bbSam Judd return; 256e7319b67364bd0ac6306bc7470a43d4a31600c1aRobert Papp } 257e7319b67364bd0ac6306bc7470a43d4a31600c1aRobert Papp if (!isRunning) { 258ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd return; 259ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 2600d8a954b91ef8a37c944c2fdee75966c6f94d7bbSam Judd 2611579932986cc7438b103c811adeb0a14feab0adaSam Judd invalidateSelf(); 262ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 263193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd if (frameIndex == decoder.getFrameCount() - 1) { 264193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd loopCount++; 265193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd } 266193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd 267193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd if (maxLoopCount != LOOP_FOREVER && loopCount >= maxLoopCount) { 268193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd stop(); 269193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd } else { 270193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd frameManager.getNextFrame(this); 271193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd } 272ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 273ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd 274a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd @Override 275a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd public ConstantState getConstantState() { 276a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd return state; 277a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd } 278a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd 2795f4610b54d517be58105bcf73ce3291ba79f9f40Sam Judd /** 2805f4610b54d517be58105bcf73ce3291ba79f9f40Sam Judd * Clears any resources for loading frames that are currently held on to by this object. 2815f4610b54d517be58105bcf73ce3291ba79f9f40Sam Judd */ 282ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd public void recycle() { 2834f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd isRecycled = true; 2844185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd state.bitmapPool.put(state.firstFrame); 285ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd frameManager.clear(); 286ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd } 2874f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd 2883e519104d688b295f6b1b46d1cc78695a36654a7Sam Judd // For testing. 2895f4610b54d517be58105bcf73ce3291ba79f9f40Sam Judd boolean isRecycled() { 2904f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd return isRecycled; 2914f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd } 292193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd 293193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd @Override 294193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd public boolean isAnimated() { 295193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd return true; 296193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd } 297193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd 298193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd @Override 299193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd public void setLoopCount(int loopCount) { 300193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd if (loopCount <= 0 && loopCount != LOOP_FOREVER && loopCount != LOOP_INTRINSIC) { 301193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd throw new IllegalArgumentException("Loop count must be greater than 0, or equal to " 302193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd + "GlideDrawable.LOOP_FOREVER, or equal to GlideDrawable.LOOP_INTRINSIC"); 303193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd } 304193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd 305193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd if (loopCount == LOOP_INTRINSIC) { 306193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd maxLoopCount = decoder.getLoopCount(); 307193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd } else { 308193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd maxLoopCount = loopCount; 309193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd } 310193e2f8f9d0c56ce4faa7cfe4e62ca6187be90b8Sam Judd } 311a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd 312a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd static class GifState extends ConstantState { 31338ced22f14acd14b69bb102605505d1feb04b46bSam Judd private static final int GRAVITY = Gravity.FILL; 314a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd GifHeader gifHeader; 315a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd byte[] data; 316a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd Context context; 317a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd Transformation<Bitmap> frameTransformation; 318a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd int targetWidth; 319a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd int targetHeight; 320a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd GifDecoder.BitmapProvider bitmapProvider; 3214185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd BitmapPool bitmapPool; 3224185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd Bitmap firstFrame; 323a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd 324b4cc7fa5f667e4a56514823cf2ad85d7435b498aSam Judd public GifState(GifHeader header, byte[] data, Context context, 325a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd Transformation<Bitmap> frameTransformation, int targetWidth, int targetHeight, 3264185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd GifDecoder.BitmapProvider provider, BitmapPool bitmapPool, Bitmap firstFrame) { 327a61f3e9b2f21355cf8a0d3cdb0da15f19369a5ebSam Judd if (firstFrame == null) { 328a61f3e9b2f21355cf8a0d3cdb0da15f19369a5ebSam Judd throw new NullPointerException("The first frame of the GIF must not be null"); 329a61f3e9b2f21355cf8a0d3cdb0da15f19369a5ebSam Judd } 330a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd gifHeader = header; 331a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd this.data = data; 3324185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd this.bitmapPool = bitmapPool; 3334185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd this.firstFrame = firstFrame; 334a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd this.context = context.getApplicationContext(); 335a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd this.frameTransformation = frameTransformation; 336a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd this.targetWidth = targetWidth; 337a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd this.targetHeight = targetHeight; 338a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd bitmapProvider = provider; 339a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd } 340a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd 341a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd public GifState(GifState original) { 342a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd if (original != null) { 343a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd gifHeader = original.gifHeader; 344a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd data = original.data; 345a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd context = original.context; 346a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd frameTransformation = original.frameTransformation; 347a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd targetWidth = original.targetWidth; 348a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd targetHeight = original.targetHeight; 349a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd bitmapProvider = original.bitmapProvider; 3504185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd bitmapPool = original.bitmapPool; 3514185efc3779f8caf2dd8103aa84705e7a88f679cSam Judd firstFrame = original.firstFrame; 352a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd } 353a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd } 354a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd 355a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd @Override 356a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd public Drawable newDrawable(Resources res) { 35721c2822985058df655ee4874798297f74c5e367eSam Judd return newDrawable(); 358a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd } 359a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd 360a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd @Override 361a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd public Drawable newDrawable() { 362a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd return new GifDrawable(this); 363a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd } 364a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd 365a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd @Override 366a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd public int getChangingConfigurations() { 367a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd return 0; 368a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd } 369a23b64f5872138b0a5fa4c95be5dcf3f6f0942d8Sam Judd } 370ea01ddd754126290fc18c3dc8f6095ce0216768aSam Judd} 371