/*******************************************************************************
 * Copyright 2011, 2012 Chris Banes.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package uk.org.ngo.squeezer.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

public class CacheableImageView extends ImageView {

    private CacheableBitmapWrapper mDisplayedBitmapWrapper;

    public CacheableImageView(Context context) {
        super(context);
    }

    public CacheableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * onDraw() is occasionally called after the bitmap has been recycled. This should not happen.
     * If it does, just return.
     */
    @Override
    protected void onDraw(Canvas canvas) {
        final Drawable drawable = getDrawable();

        if (drawable != null) {
            if (Bitmap.class.isAssignableFrom(drawable.getClass())) {
                final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
                if (bitmap != null && bitmap.isRecycled()) {
                    return;
                }
            }
        }

        super.onDraw(canvas);
    }

    /**
     * Sets the current {@code CacheableBitmapWrapper}, and displays it Bitmap.
     *
     * @param wrapper - Wrapper to display.s
     */
    public void setImageCachedBitmap(final CacheableBitmapWrapper wrapper) {
        if (null != wrapper) {
            wrapper.setBeingUsed(true);
            setImageDrawable(new BitmapDrawable(getResources(), wrapper.getBitmap()));
        } else {
            setImageDrawable(null);
        }

        // Finally, set our new BitmapWrapper
        mDisplayedBitmapWrapper = wrapper;
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        setImageCachedBitmap(new CacheableBitmapWrapper(bm));
    }

    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        resetCachedDrawable();
    }

    @Override
    public void setImageResource(int resId) {
        super.setImageResource(resId);
        resetCachedDrawable();
    }

    public CacheableBitmapWrapper getCachedBitmapWrapper() {
        return mDisplayedBitmapWrapper;
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();

        // Will cause displayed bitmap wrapper to be 'free-able'
        setImageDrawable(null);
    }

    /**
     * Called when the current cached bitmap has been removed. This method will
     * remove the displayed flag and remove this objects reference to it.
     */
    private void resetCachedDrawable() {
        if (null != mDisplayedBitmapWrapper) {
            mDisplayedBitmapWrapper.setBeingUsed(false);
            mDisplayedBitmapWrapper = null;
        }
    }

}
@@ -991,25 +991,98 @@
 oid.
-util.AttributeSet
+graphics.drawable.LayerDrawable;%0Aimport android.util.AttributeSet;%0Aimport android.util.Log
 ;%0Aim
@@ -1692,229 +1692,584 @@
 able
- != null) %7B%0A            if (Bitmap.class.isAssignableFrom(drawable.getClass())) %7B%0A                final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();%0A                if (bitmap != null && bitmap.isRecycled()) %7B
+ContainsRecycledBitmap(drawable))%0A            return;%0A%0A        if (drawable instanceof LayerDrawable) %7B%0A            // Iterate over the layers in the drawable (should be only two since this%0A            // should be a TransitionDrawable, but just in case...). Perform the same%0A            // isRecycled() check to make sure it's safe to use the bitmap. If it's not,%0A            // return.%0A            for (int i = 0, l = ((LayerDrawable) drawable).getNumberOfLayers(); i %3C l; i++) %7B%0A                if (drawableContainsRecycledBitmap(((LayerDrawable) drawable).getDrawable(i)))
 %0A   
@@ -2297,26 +2297,8 @@
 rn;%0A
-                %7D%0A
     
@@ -2310,32 +2310,32 @@
    %7D%0A        %7D%0A%0A
-
         super.on
@@ -2347,32 +2347,747 @@
 canvas);%0A    %7D%0A%0A
+    /**%0A     * Check to see if a Drawable contains a recycled bitmap.%0A     * %0A     * @param drawable The Drawable to check%0A     * @return true if contains a recycled bitmap, false otherwise (either the bitmap is not%0A     *         recycled, or the drawable did not contain a bitmap).%0A     */%0A    private boolean drawableContainsRecycledBitmap(Drawable drawable) %7B%0A        if (drawable instanceof BitmapDrawable) %7B%0A            final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();%0A            if (bitmap != null && bitmap.isRecycled()) %7B%0A                Log.v(%22CacheableImageView%22, %22Trying to draw with a recycled bitmap%22);%0A                return true;%0A            %7D%0A        %7D%0A%0A        return false;%0A    %7D%0A%0A
     /**%0A     * S

Handle bitmaps in LayerDrawables that might be recycled.