FileDocCategorySizeDatePackage
BasicBitmapDrawable.javaAPI DocAndroid 5.1 API13943Thu Mar 12 22:22:50 GMT 2015com.android.bitmap.drawable

BasicBitmapDrawable

public class BasicBitmapDrawable extends android.graphics.drawable.Drawable implements RequestKey.Callback, Drawable.Callback, com.android.bitmap.DecodeTask.DecodeCallback
This class encapsulates the basic functionality needed to display a single image bitmap, including request creation/cancelling, and data unbinding and re-binding.

The actual bitmap decode work is handled by {@link DecodeTask}.

If being used with a long-lived cache (static cache, attached to the Application instead of the Activity, etc) then make sure to call {@link BasicBitmapDrawable#unbind()} at the appropriate times so the cache has accurate unref counts. The {@link com.android.bitmap.view.BitmapDrawableImageView} class has been created to do the appropriate unbind operation when the view is detached from the window.

Fields Summary
protected static android.graphics.Rect
sRect
protected com.android.bitmap.RequestKey
mCurrKey
protected com.android.bitmap.RequestKey
mPrevKey
protected int
mDecodeWidth
protected int
mDecodeHeight
protected final android.graphics.Paint
mPaint
private final com.android.bitmap.BitmapCache
mCache
private final boolean
mLimitDensity
private final float
mDensity
private com.android.bitmap.ReusableBitmap
mBitmap
private com.android.bitmap.DecodeTask
mTask
private com.android.bitmap.RequestKey.Cancelable
mCreateFileDescriptorFactoryTask
private static final int
CPU_COUNT
private static final int
CORE_POOL_SIZE
private static final int
MAXIMUM_POOL_SIZE
private static final Executor
SMALL_POOL_EXECUTOR
private static final Executor
EXECUTOR
private static final int
MAX_BITMAP_DENSITY
private static final float
VERTICAL_CENTER
private static final float
NO_MULTIPLIER
private static final String
TAG
private static final boolean
DEBUG
Constructors Summary
public BasicBitmapDrawable(android.content.res.Resources res, com.android.bitmap.BitmapCache cache, boolean limitDensity)


          
               
        mDensity = res.getDisplayMetrics().density;
        mCache = cache;
        mLimitDensity = limitDensity;
        mPaint.setFilterBitmap(true);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);

        if (sRect == null) {
            sRect = new Rect();
        }
    
Methods Summary
public voidbind(com.android.bitmap.RequestKey key)
Binds to the given key and start the decode process. This will first look in the cache, then decode from the request key if not found. The key being replaced will be kept in {@link #mPrevKey}. All UI operations should be called from the UI thread.

        Trace.beginSection("bind");
        if (mCurrKey != null && mCurrKey.equals(key)) {
            Trace.endSection();
            return;
        }
        setImage(key);
        Trace.endSection();
    
protected voiddecode(com.android.bitmap.RequestKey.FileDescriptorFactory factory)
Should only be overriden, not called.

        Trace.beginSection("decode");
        final int bufferW;
        final int bufferH;
        if (mLimitDensity) {
            final float scale =
                    Math.min(1f, (float) MAX_BITMAP_DENSITY / DisplayMetrics.DENSITY_DEFAULT
                            / mDensity);
            bufferW = (int) (mDecodeWidth * scale);
            bufferH = (int) (mDecodeHeight * scale);
        } else {
            bufferW = mDecodeWidth;
            bufferH = mDecodeHeight;
        }

        if (mTask != null) {
            mTask.cancel();
        }
        final DecodeOptions opts = new DecodeOptions(bufferW, bufferH, getDecodeVerticalCenter(),
                DecodeOptions.STRATEGY_ROUND_NEAREST);
        mTask = new DecodeTask(mCurrKey, opts, factory, this, mCache);
        mTask.executeOnExecutor(getExecutor());
        Trace.endSection();
    
public voiddraw(android.graphics.Canvas canvas)

        final Rect bounds = getBounds();
        if (bounds.isEmpty()) {
            return;
        }

        if (hasBitmap()) {
            BitmapUtils.calculateCroppedSrcRect(
                    mBitmap.getLogicalWidth(), mBitmap.getLogicalHeight(),
                    bounds.width(), bounds.height(),
                    bounds.height(), Integer.MAX_VALUE,
                    getDrawVerticalCenter(), false /* absoluteFraction */,
                    getDrawVerticalOffsetMultiplier(), sRect);

            final int orientation = mBitmap.getOrientation();
            // calculateCroppedSrcRect() gave us the source rectangle "as if" the orientation has
            // been corrected. We need to decode the uncorrected source rectangle. Calculate true
            // coordinates.
            RectUtils.rotateRectForOrientation(orientation,
                    new Rect(0, 0, mBitmap.getLogicalWidth(), mBitmap.getLogicalHeight()),
                    sRect);

            // We may need to rotate the canvas, so we also have to rotate the bounds.
            final Rect rotatedBounds = new Rect(bounds);
            RectUtils.rotateRect(orientation, bounds.centerX(), bounds.centerY(), rotatedBounds);

            // Rotate the canvas.
            canvas.save();
            canvas.rotate(orientation, bounds.centerX(), bounds.centerY());
            onDrawBitmap(canvas, sRect, rotatedBounds);
            canvas.restore();
        }
    
public voidfileDescriptorFactoryCreated(com.android.bitmap.RequestKey key, com.android.bitmap.RequestKey.FileDescriptorFactory factory)

        if (mCreateFileDescriptorFactoryTask == null) {
            // Cancelled.
            return;
        }
        mCreateFileDescriptorFactoryTask = null;

        if (key.equals(mCurrKey)) {
            decode(factory);
        }
    
protected com.android.bitmap.ReusableBitmapgetBitmap()

        return mBitmap;
    
protected floatgetDecodeVerticalCenter()
Clients can override this to specify which section of the source image to decode from. Possible applications include using face detection to always decode around facial features.

        return VERTICAL_CENTER;
    
protected floatgetDrawVerticalCenter()

        return VERTICAL_CENTER;
    
protected floatgetDrawVerticalOffsetMultiplier()

        return NO_MULTIPLIER;
    
protected java.util.concurrent.ExecutorgetExecutor()

        return EXECUTOR;
    
public final com.android.bitmap.RequestKeygetKey()

        return mCurrKey;
    
public intgetOpacity()

        return (hasBitmap() && (mBitmap.bmp.hasAlpha() || mPaint.getAlpha() < 255)) ?
                PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
    
public final com.android.bitmap.RequestKeygetPreviousKey()

        return mPrevKey;
    
protected booleanhasBitmap()

        return mBitmap != null && mBitmap.bmp != null;
    
public voidinvalidateDrawable(android.graphics.drawable.Drawable who)

        invalidateSelf();
    
protected voidloadFileDescriptorFactory()
Should only be overriden, not called.

        if (mCurrKey == null || mDecodeWidth == 0 || mDecodeHeight == 0) {
            return;
        }

        // Create file descriptor if request supports it.
        mCreateFileDescriptorFactoryTask = mCurrKey
                .createFileDescriptorFactoryAsync(mCurrKey, this);
        if (mCreateFileDescriptorFactoryTask == null) {
            // Use input stream if request does not.
            decode(null);
        }
    
public voidonDecodeBegin(com.android.bitmap.RequestKey key)

 
public voidonDecodeCancel(com.android.bitmap.RequestKey key)

 
public voidonDecodeComplete(com.android.bitmap.RequestKey key, com.android.bitmap.ReusableBitmap result)

        if (key.equals(mCurrKey)) {
            setBitmap(result);
        } else {
            // if the requests don't match (i.e. this request is stale), decrement the
            // ref count to allow the bitmap to be pooled
            if (result != null) {
                result.releaseReference();
            }
        }
    
protected voidonDrawBitmap(android.graphics.Canvas canvas, android.graphics.Rect src, android.graphics.Rect dst)
Override this method to customize how to draw the bitmap to the canvas for the given bounds. The bitmap to be drawn can be found at {@link #getBitmap()}.

        if (hasBitmap()) {
            canvas.drawBitmap(mBitmap.bmp, src, dst, mPaint);
        }
    
public voidscheduleDrawable(android.graphics.drawable.Drawable who, java.lang.Runnable what, long when)

        scheduleSelf(what, when);
    
public voidsetAlpha(int alpha)

        final int old = mPaint.getAlpha();
        mPaint.setAlpha(alpha);
        if (alpha != old) {
            invalidateSelf();
        }
    
protected voidsetBitmap(com.android.bitmap.ReusableBitmap bmp)
Should only be overriden, not called.

        if (hasBitmap()) {
            mBitmap.releaseReference();
        }
        mBitmap = bmp;
        invalidateSelf();
    
public voidsetColorFilter(android.graphics.ColorFilter cf)

        mPaint.setColorFilter(cf);
        invalidateSelf();
    
public voidsetDecodeDimensions(int width, int height)
Set the dimensions to decode into. These dimensions should never change while the drawable is attached to the same cache, because caches can only contain bitmaps of one size for re-use. All UI operations should be called from the UI thread.

        if (mDecodeWidth == 0 || mDecodeHeight == 0) {
            mDecodeWidth = width;
            mDecodeHeight = height;
            setImage(mCurrKey);
        }
    
protected voidsetImage(com.android.bitmap.RequestKey key)
Should only be overriden, not called.

        Trace.beginSection("set image");
        Trace.beginSection("release reference");
        if (mBitmap != null) {
            mBitmap.releaseReference();
            mBitmap = null;
        }
        Trace.endSection();

        mPrevKey = mCurrKey;
        mCurrKey = key;

        if (mTask != null) {
            mTask.cancel();
            mTask = null;
        }
        if (mCreateFileDescriptorFactoryTask != null) {
            mCreateFileDescriptorFactoryTask.cancel();
            mCreateFileDescriptorFactoryTask = null;
        }

        if (key == null) {
            invalidateSelf();
            Trace.endSection();
            return;
        }

        // find cached entry here and skip decode if found.
        final ReusableBitmap cached = mCache.get(key, true /* incrementRefCount */);
        if (cached != null) {
            setBitmap(cached);
            if (DEBUG) {
                Log.d(TAG, String.format("CACHE HIT key=%s", mCurrKey));
            }
        } else {
            loadFileDescriptorFactory();
            if (DEBUG) {
                Log.d(TAG, String.format(
                        "CACHE MISS key=%s\ncache=%s", mCurrKey, mCache.toDebugString()));
            }
        }
        Trace.endSection();
    
public voidunbind()
Unbinds the current key and bitmap from the drawable. This will cause the bitmap to decrement its ref count. This will assume that you do not want to keep the unbound key in {@link #mPrevKey}. All UI operations should be called from the UI thread.

        unbind(false);
    
public voidunbind(boolean temporary)
Unbinds the current key and bitmap from the drawable. This will cause the bitmap to decrement its ref count. If the temporary parameter is true, we will keep the unbound key in {@link #mPrevKey}. All UI operations should be called from the UI thread.

        Trace.beginSection("unbind");
        setImage(null);
        if (!temporary) {
            mPrevKey = null;
        }
        Trace.endSection();
    
public voidunscheduleDrawable(android.graphics.drawable.Drawable who, java.lang.Runnable what)

        unscheduleSelf(what);