BasicBitmapDrawable.java revision 7be91f8fe3c6d9af037b36918ea5bd86a10bbb44
193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/*
293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Copyright (C) 2013 The Android Open Source Project
393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *
493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Licensed under the Apache License, Version 2.0 (the "License");
593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * you may not use this file except in compliance with the License.
693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * You may obtain a copy of the License at
793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *
893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *      http://www.apache.org/licenses/LICENSE-2.0
993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *
1093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Unless required by applicable law or agreed to in writing, software
1193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * distributed under the License is distributed on an "AS IS" BASIS,
1293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * See the License for the specific language governing permissions and
1493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * limitations under the License.
1593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */
1693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinpackage com.android.bitmap.drawable;
1793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
1893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.content.res.Resources;
1993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.Canvas;
2093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.ColorFilter;
2193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.Paint;
2293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.PixelFormat;
2393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.Rect;
2493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.drawable.Drawable;
2593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.util.DisplayMetrics;
2693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.util.Log;
2793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
2893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.BitmapCache;
2993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.DecodeTask;
309c6ac19d4a3d39b7c2992060957920118ff56a65Mark Weiimport com.android.bitmap.DecodeTask.DecodeCallback;
31cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Weiimport com.android.bitmap.DecodeTask.DecodeOptions;
32cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Weiimport com.android.bitmap.NamedThreadFactory;
3340662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzsteinimport com.android.bitmap.RequestKey;
349c6ac19d4a3d39b7c2992060957920118ff56a65Mark Weiimport com.android.bitmap.RequestKey.Cancelable;
359c6ac19d4a3d39b7c2992060957920118ff56a65Mark Weiimport com.android.bitmap.RequestKey.FileDescriptorFactory;
3693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.ReusableBitmap;
3793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.BitmapUtils;
3893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.RectUtils;
3993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.Trace;
4093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
4193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport java.util.concurrent.Executor;
4293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport java.util.concurrent.LinkedBlockingQueue;
4393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport java.util.concurrent.ThreadPoolExecutor;
4493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport java.util.concurrent.TimeUnit;
4593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
4693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/**
4793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * This class encapsulates the basic functionality needed to display a single image bitmap,
4893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * including request creation/cancelling, and data unbinding and re-binding.
4993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p>
5093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * The actual bitmap decode work is handled by {@link DecodeTask}.
51a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei * <p>
52a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei * If being used with a long-lived cache (static cache, attached to the Application instead of the
53a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei * Activity, etc) then make sure to call {@link BasicBitmapDrawable#unbind()} at the appropriate
549c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei * times so the cache has accurate unref counts. The
559c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei * {@link com.android.bitmap.view.BitmapDrawableImageView} class has been created to do the
569c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei * appropriate unbind operation when the view is detached from the window.
5793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */
589c6ac19d4a3d39b7c2992060957920118ff56a65Mark Weipublic class BasicBitmapDrawable extends Drawable implements DecodeCallback,
599c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei        Drawable.Callback, RequestKey.Callback {
602e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei
61e03daa1db89106c11d8885b94d7ac97c10bea3b3Mark Wei    protected static Rect sRect;
6293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
63528300fdc3caeb96a24873acf2b1cc0914b97593Mark Wei    protected RequestKey mCurrKey;
642e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    protected RequestKey mPrevKey;
6541af50eb1ac488572b066629c3954b23c21dfa76Mark Wei    protected int mDecodeWidth;
6641af50eb1ac488572b066629c3954b23c21dfa76Mark Wei    protected int mDecodeHeight;
67e03daa1db89106c11d8885b94d7ac97c10bea3b3Mark Wei
682e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    protected final Paint mPaint = new Paint();
6993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final BitmapCache mCache;
702e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei
71cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei    private final boolean mLimitDensity;
72e03daa1db89106c11d8885b94d7ac97c10bea3b3Mark Wei    private final float mDensity;
73a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei    private ReusableBitmap mBitmap;
7493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private DecodeTask mTask;
759c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei    private Cancelable mCreateFileDescriptorFactoryTask;
7693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
7793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    // based on framework CL:I015d77
7893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
7993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
8093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
81cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei
8293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private static final Executor SMALL_POOL_EXECUTOR = new ThreadPoolExecutor(
8393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, 1, TimeUnit.SECONDS,
84cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei            new LinkedBlockingQueue<Runnable>(128), new NamedThreadFactory("decode"));
8593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private static final Executor EXECUTOR = SMALL_POOL_EXECUTOR;
8693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
8793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private static final int MAX_BITMAP_DENSITY = DisplayMetrics.DENSITY_HIGH;
88cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei    private static final float VERTICAL_CENTER = 1f / 2;
892e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    private static final float NO_MULTIPLIER = 1f;
9093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
91e03daa1db89106c11d8885b94d7ac97c10bea3b3Mark Wei    private static final String TAG = BasicBitmapDrawable.class.getSimpleName();
92cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei    private static final boolean DEBUG = DecodeTask.DEBUG;
9393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
94cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei    public BasicBitmapDrawable(final Resources res, final BitmapCache cache,
95cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei            final boolean limitDensity) {
9693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mDensity = res.getDisplayMetrics().density;
9793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mCache = cache;
98cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei        mLimitDensity = limitDensity;
9993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mPaint.setFilterBitmap(true);
100e03daa1db89106c11d8885b94d7ac97c10bea3b3Mark Wei        mPaint.setAntiAlias(true);
101e03daa1db89106c11d8885b94d7ac97c10bea3b3Mark Wei        mPaint.setDither(true);
102e03daa1db89106c11d8885b94d7ac97c10bea3b3Mark Wei
103e03daa1db89106c11d8885b94d7ac97c10bea3b3Mark Wei        if (sRect == null) {
104e03daa1db89106c11d8885b94d7ac97c10bea3b3Mark Wei            sRect = new Rect();
105e03daa1db89106c11d8885b94d7ac97c10bea3b3Mark Wei        }
10693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
10793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
10810dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei    public final RequestKey getKey() {
10993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return mCurrKey;
11093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
11193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
11241af50eb1ac488572b066629c3954b23c21dfa76Mark Wei    protected ReusableBitmap getBitmap() {
1132e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        return mBitmap;
1142e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    }
1152e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei
11693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    /**
11710dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     * Set the dimensions to decode into. These dimensions should never change while the drawable is
11810dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     * attached to the same cache, because caches can only contain bitmaps of one size for re-use.
11910dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     *
12010dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     * All UI operations should be called from the UI thread.
12193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     */
12210dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei    public final void setDecodeDimensions(int w, int h) {
12393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mDecodeWidth = w;
12493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mDecodeHeight = h;
1259c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei        loadFileDescriptorFactory();
12693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
12793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
12810dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei    /**
12910dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     * Binds to the given key and start the decode process. This will first look in the cache, then
13010dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     * decode from the request key if not found.
13110dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     *
13210dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     * All UI operations should be called from the UI thread.
13310dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     */
13441af50eb1ac488572b066629c3954b23c21dfa76Mark Wei    public void bind(RequestKey key) {
13510dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei        setImage(key);
13693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
13793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
13810dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei    /**
13910dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     * Unbinds the current key and bitmap from the drawable. This will cause the bitmap to decrement
14010dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     * its ref count.
14110dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     *
14210dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     * All UI operations should be called from the UI thread.
14310dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     */
14441af50eb1ac488572b066629c3954b23c21dfa76Mark Wei    public void unbind() {
14510dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei        setImage(null);
14693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
14793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
14810dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei    /**
14910dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     * Should only be overriden, not called.
15010dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     */
1512e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    protected void setImage(final RequestKey key) {
15293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (mCurrKey != null && mCurrKey.equals(key)) {
15393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            return;
15493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
15593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
15693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        Trace.beginSection("set image");
15793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        Trace.beginSection("release reference");
15893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (mBitmap != null) {
15993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mBitmap.releaseReference();
16093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mBitmap = null;
16193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
16293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        Trace.endSection();
1632e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei
1642e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        mPrevKey = mCurrKey;
16593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mCurrKey = key;
16693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
16793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (mTask != null) {
16893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mTask.cancel();
16993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mTask = null;
17093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
1719c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei        if (mCreateFileDescriptorFactoryTask != null) {
1729c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei            mCreateFileDescriptorFactoryTask.cancel();
1739c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei            mCreateFileDescriptorFactoryTask = null;
1749c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei        }
17593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
17693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (key == null) {
17793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            invalidateSelf();
17893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            Trace.endSection();
17993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            return;
18093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
18193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
18293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        // find cached entry here and skip decode if found.
18393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        final ReusableBitmap cached = mCache.get(key, true /* incrementRefCount */);
18493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (cached != null) {
18593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            setBitmap(cached);
18693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (DEBUG) {
18793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                Log.d(TAG, String.format("CACHE HIT key=%s", mCurrKey));
18893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
18993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        } else {
1909c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei            loadFileDescriptorFactory();
19193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (DEBUG) {
19293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                Log.d(TAG, String.format(
19393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        "CACHE MISS key=%s\ncache=%s", mCurrKey, mCache.toDebugString()));
19493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
19593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
19693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        Trace.endSection();
19793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
19893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
19910dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei    /**
20010dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     * Should only be overriden, not called.
20110dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     */
2022e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    protected void setBitmap(ReusableBitmap bmp) {
2032e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        if (mBitmap != null && mBitmap != bmp) {
2042e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei            mBitmap.releaseReference();
2052e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        }
2062e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        mBitmap = bmp;
2072e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        invalidateSelf();
2082e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    }
2092e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei
21010dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei    /**
21110dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     * Should only be overriden, not called.
21210dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     */
2132e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    protected void loadFileDescriptorFactory() {
2142e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        if (mCurrKey == null || mDecodeWidth == 0 || mDecodeHeight == 0) {
2152e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei            return;
2162e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        }
2172e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei
2182e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        // Create file descriptor if request supports it.
2192e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        mCreateFileDescriptorFactoryTask = mCurrKey
2202e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei                .createFileDescriptorFactoryAsync(mCurrKey, this);
2212e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        if (mCreateFileDescriptorFactoryTask == null) {
2222e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei            // Use input stream if request does not.
2232e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei            decode(null);
2242e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        }
2252e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    }
2262e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei
2272e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    @Override
2282e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    public void fileDescriptorFactoryCreated(final RequestKey key,
2292e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei            final FileDescriptorFactory factory) {
2302e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        if (mCreateFileDescriptorFactoryTask == null) {
2312e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei            // Cancelled.
2322e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei            return;
2332e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        }
2342e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        mCreateFileDescriptorFactoryTask = null;
2352e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei
2362e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        if (key.equals(mCurrKey)) {
2372e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei            decode(factory);
2382e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        }
2392e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    }
2402e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei
24110dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei    /**
24210dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     * Should only be overriden, not called.
24310dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei     */
2442e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    protected void decode(final FileDescriptorFactory factory) {
2452e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        Trace.beginSection("decode");
2462e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        final int bufferW;
2472e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        final int bufferH;
2482e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        if (mLimitDensity) {
2492e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei            final float scale =
2502e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei                    Math.min(1f, (float) MAX_BITMAP_DENSITY / DisplayMetrics.DENSITY_DEFAULT
2512e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei                            / mDensity);
2522e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei            bufferW = (int) (mDecodeWidth * scale);
2532e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei            bufferH = (int) (mDecodeHeight * scale);
2542e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        } else {
2552e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei            bufferW = mDecodeWidth;
2562e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei            bufferH = mDecodeHeight;
2572e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        }
2582e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei
2592e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        if (mTask != null) {
2602e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei            mTask.cancel();
2612e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        }
2622e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        final DecodeOptions opts = new DecodeOptions(bufferW, bufferH, getDecodeVerticalCenter(),
2632e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei                DecodeOptions.STRATEGY_ROUND_NEAREST);
2642e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        mTask = new DecodeTask(mCurrKey, opts, factory, this, mCache);
265aab539ecd75ae365912200eb7f3318a53e9834f4Mark Wei        mTask.executeOnExecutor(getExecutor());
2662e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        Trace.endSection();
2672e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    }
2682e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei
269aab539ecd75ae365912200eb7f3318a53e9834f4Mark Wei    protected Executor getExecutor() {
270aab539ecd75ae365912200eb7f3318a53e9834f4Mark Wei        return EXECUTOR;
271aab539ecd75ae365912200eb7f3318a53e9834f4Mark Wei    }
272aab539ecd75ae365912200eb7f3318a53e9834f4Mark Wei
2732e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    protected float getDrawVerticalCenter() {
2742e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        return VERTICAL_CENTER;
2752e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    }
2762e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei
2772e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    protected float getDrawVerticalOffsetMultiplier() {
2782e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        return NO_MULTIPLIER;
2792e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    }
2802e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei
2812e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    protected float getDecodeVerticalCenter() {
2822e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei        return VERTICAL_CENTER;
2832e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei    }
2842e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei
28593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
28693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void draw(final Canvas canvas) {
28793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        final Rect bounds = getBounds();
28893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (bounds.isEmpty()) {
28993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            return;
29093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
29193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
29293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (mBitmap != null && mBitmap.bmp != null) {
29393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            BitmapUtils.calculateCroppedSrcRect(
29493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    mBitmap.getLogicalWidth(), mBitmap.getLogicalHeight(),
29593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    bounds.width(), bounds.height(),
29693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    bounds.height(), Integer.MAX_VALUE,
2972e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei                    getDrawVerticalCenter(), false /* absoluteFraction */,
2982e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei                    getDrawVerticalOffsetMultiplier(), sRect);
29993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
30093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            final int orientation = mBitmap.getOrientation();
30193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            // calculateCroppedSrcRect() gave us the source rectangle "as if" the orientation has
30293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            // been corrected. We need to decode the uncorrected source rectangle. Calculate true
30393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            // coordinates.
30493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            RectUtils.rotateRectForOrientation(orientation,
30593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    new Rect(0, 0, mBitmap.getLogicalWidth(), mBitmap.getLogicalHeight()),
306e03daa1db89106c11d8885b94d7ac97c10bea3b3Mark Wei                    sRect);
30793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
30893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            // We may need to rotate the canvas, so we also have to rotate the bounds.
30993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            final Rect rotatedBounds = new Rect(bounds);
31093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            RectUtils.rotateRect(orientation, bounds.centerX(), bounds.centerY(), rotatedBounds);
31193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
31293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            // Rotate the canvas.
31393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            canvas.save();
31493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            canvas.rotate(orientation, bounds.centerX(), bounds.centerY());
3157be91f8fe3c6d9af037b36918ea5bd86a10bbb44Mark Wei            onDrawBitmap(canvas, sRect, rotatedBounds);
31693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            canvas.restore();
31793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
31893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
31993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
3200c9aacac20202f4a41e98d8a34a6ee2c152ae2deMark Wei    /**
3210c9aacac20202f4a41e98d8a34a6ee2c152ae2deMark Wei     * Override this method to customize how to draw the bitmap to the canvas for the given bounds.
3220c9aacac20202f4a41e98d8a34a6ee2c152ae2deMark Wei     * The bitmap to be drawn can be found at {@link #getBitmap()}.
3230c9aacac20202f4a41e98d8a34a6ee2c152ae2deMark Wei     */
3247be91f8fe3c6d9af037b36918ea5bd86a10bbb44Mark Wei    protected void onDrawBitmap(final Canvas canvas, final Rect src, final Rect dst) {
3257be91f8fe3c6d9af037b36918ea5bd86a10bbb44Mark Wei        canvas.drawBitmap(mBitmap.bmp, src, dst, mPaint);
3260c9aacac20202f4a41e98d8a34a6ee2c152ae2deMark Wei    }
3270c9aacac20202f4a41e98d8a34a6ee2c152ae2deMark Wei
32893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
32993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void setAlpha(int alpha) {
33093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        final int old = mPaint.getAlpha();
33193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mPaint.setAlpha(alpha);
33293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (alpha != old) {
33393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            invalidateSelf();
33493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
33593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
33693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
33793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
33893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void setColorFilter(ColorFilter cf) {
33993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mPaint.setColorFilter(cf);
34093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        invalidateSelf();
34193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
34293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
34393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
34493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public int getOpacity() {
34593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return (mBitmap != null && (mBitmap.bmp.hasAlpha() || mPaint.getAlpha() < 255)) ?
34693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
34793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
34893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
34993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
35040662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein    public void onDecodeBegin(final RequestKey key) { }
35193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
35293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
35340662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein    public void onDecodeComplete(final RequestKey key, final ReusableBitmap result) {
35493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (key.equals(mCurrKey)) {
35593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            setBitmap(result);
35693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        } else {
35793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            // if the requests don't match (i.e. this request is stale), decrement the
35893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            // ref count to allow the bitmap to be pooled
35993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (result != null) {
36093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                result.releaseReference();
36193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
36293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
36393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
36493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
36593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
36640662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein    public void onDecodeCancel(final RequestKey key) { }
36793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
36893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
36993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void invalidateDrawable(Drawable who) {
37093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        invalidateSelf();
37193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
37293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
37393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
37493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void scheduleDrawable(Drawable who, Runnable what, long when) {
37593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        scheduleSelf(what, when);
37693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
37793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
37893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
37993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void unscheduleDrawable(Drawable who, Runnable what) {
38093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        unscheduleSelf(what);
38193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
38293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein}
383