BasicBitmapDrawable.java revision 10dddd8a24a80d1d539997d8eaa9763c62bd02ad
16bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines/* 26bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * Copyright (C) 2013 The Android Open Source Project 36bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * 46bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * Licensed under the Apache License, Version 2.0 (the "License"); 56bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * you may not use this file except in compliance with the License. 66bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * You may obtain a copy of the License at 76bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * 86bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * http://www.apache.org/licenses/LICENSE-2.0 96bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * 106bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * Unless required by applicable law or agreed to in writing, software 116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * distributed under the License is distributed on an "AS IS" BASIS, 126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * See the License for the specific language governing permissions and 146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * limitations under the License. 156bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines */ 166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinespackage com.android.bitmap.drawable; 176bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 186bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport android.content.res.Resources; 196bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport android.graphics.Canvas; 206bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport android.graphics.ColorFilter; 216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport android.graphics.Paint; 226bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport android.graphics.PixelFormat; 236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport android.graphics.Rect; 246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport android.graphics.drawable.Drawable; 256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport android.util.DisplayMetrics; 266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport android.util.Log; 276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 286bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport com.android.bitmap.BitmapCache; 296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport com.android.bitmap.DecodeTask; 306bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport com.android.bitmap.DecodeTask.DecodeCallback; 316bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport com.android.bitmap.DecodeTask.DecodeOptions; 326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport com.android.bitmap.NamedThreadFactory; 336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport com.android.bitmap.RequestKey; 346bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport com.android.bitmap.RequestKey.Cancelable; 356bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport com.android.bitmap.RequestKey.FileDescriptorFactory; 366bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport com.android.bitmap.ReusableBitmap; 376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport com.android.bitmap.util.BitmapUtils; 386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport com.android.bitmap.util.RectUtils; 396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport com.android.bitmap.util.Trace; 406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport java.util.concurrent.Executor; 426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport java.util.concurrent.LinkedBlockingQueue; 436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport java.util.concurrent.ThreadPoolExecutor; 446bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesimport java.util.concurrent.TimeUnit; 456bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines/** 476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * This class encapsulates the basic functionality needed to display a single image bitmap, 486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * including request creation/cancelling, and data unbinding and re-binding. 496bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * <p> 506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * The actual bitmap decode work is handled by {@link DecodeTask}. 516bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * <p> 526bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * If being used with a long-lived cache (static cache, attached to the Application instead of the 536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * Activity, etc) then make sure to call {@link BasicBitmapDrawable#unbind()} at the appropriate 546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * times so the cache has accurate unref counts. The 556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * {@link com.android.bitmap.view.BitmapDrawableImageView} class has been created to do the 566bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * appropriate unbind operation when the view is detached from the window. 576bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines */ 586bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinespublic class BasicBitmapDrawable extends Drawable implements DecodeCallback, 596bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Drawable.Callback, RequestKey.Callback { 606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 616bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines protected static Rect sRect; 626bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 636bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines protected RequestKey mCurrKey; 646bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines protected RequestKey mPrevKey; 656bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines protected final Paint mPaint = new Paint(); 676bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private final BitmapCache mCache; 686bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 696bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private final boolean mLimitDensity; 706bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private final float mDensity; 716bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private ReusableBitmap mBitmap; 726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private DecodeTask mTask; 736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private Cancelable mCreateFileDescriptorFactoryTask; 746bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private int mDecodeWidth; 756bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private int mDecodeHeight; 766bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 776bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines // based on framework CL:I015d77 786bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); 796bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private static final int CORE_POOL_SIZE = CPU_COUNT + 1; 806bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; 816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private static final Executor SMALL_POOL_EXECUTOR = new ThreadPoolExecutor( 836bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, 1, TimeUnit.SECONDS, 846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines new LinkedBlockingQueue<Runnable>(128), new NamedThreadFactory("decode")); 856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private static final Executor EXECUTOR = SMALL_POOL_EXECUTOR; 866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private static final int MAX_BITMAP_DENSITY = DisplayMetrics.DENSITY_HIGH; 886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private static final float VERTICAL_CENTER = 1f / 2; 896bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private static final float NO_MULTIPLIER = 1f; 906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private static final String TAG = BasicBitmapDrawable.class.getSimpleName(); 926bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines private static final boolean DEBUG = DecodeTask.DEBUG; 936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines public BasicBitmapDrawable(final Resources res, final BitmapCache cache, 956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines final boolean limitDensity) { 966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mDensity = res.getDisplayMetrics().density; 976bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mCache = cache; 986bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mLimitDensity = limitDensity; 996bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mPaint.setFilterBitmap(true); 1006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mPaint.setAntiAlias(true); 1016bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mPaint.setDither(true); 1026bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 1036bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (sRect == null) { 1046bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines sRect = new Rect(); 1056bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 1066bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 1076bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 1086bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines public final RequestKey getKey() { 1096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines return mCurrKey; 1106bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 1116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 112ef8225444452a1486bd721f3285301fe84643b00Stephen Hines protected final ReusableBitmap getBitmap() { 1136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines return mBitmap; 114ef8225444452a1486bd721f3285301fe84643b00Stephen Hines } 1156bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 1166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines /** 1176bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * Set the dimensions to decode into. These dimensions should never change while the drawable is 1186bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * attached to the same cache, because caches can only contain bitmaps of one size for re-use. 1196bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * 1206bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * All UI operations should be called from the UI thread. 1216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines */ 1226bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines public final void setDecodeDimensions(int w, int h) { 123ef8225444452a1486bd721f3285301fe84643b00Stephen Hines mDecodeWidth = w; 124ef8225444452a1486bd721f3285301fe84643b00Stephen Hines mDecodeHeight = h; 125ef8225444452a1486bd721f3285301fe84643b00Stephen Hines loadFileDescriptorFactory(); 126ef8225444452a1486bd721f3285301fe84643b00Stephen Hines } 127ef8225444452a1486bd721f3285301fe84643b00Stephen Hines 128ef8225444452a1486bd721f3285301fe84643b00Stephen Hines /** 129ef8225444452a1486bd721f3285301fe84643b00Stephen Hines * Binds to the given key and start the decode process. This will first look in the cache, then 130ef8225444452a1486bd721f3285301fe84643b00Stephen Hines * decode from the request key if not found. 1316bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * 1326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * All UI operations should be called from the UI thread. 1336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines */ 1346bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines public final void bind(RequestKey key) { 1356bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines setImage(key); 1366bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 1376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 1386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines /** 1396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * Unbinds the current key and bitmap from the drawable. This will cause the bitmap to decrement 1406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * its ref count. 1416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * 1426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * All UI operations should be called from the UI thread. 1436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines */ 1446bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines public final void unbind() { 1456bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines setImage(null); 1466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 1476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 1486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines /** 1496bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * Should only be overriden, not called. 1506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines */ 1516bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines protected void setImage(final RequestKey key) { 1526bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (mCurrKey != null && mCurrKey.equals(key)) { 1536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines return; 1546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 1556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 1566bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Trace.beginSection("set image"); 1576bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Trace.beginSection("release reference"); 1586bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (mBitmap != null) { 1596bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mBitmap.releaseReference(); 1606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mBitmap = null; 1616bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 1626bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Trace.endSection(); 1636bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 1646bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mPrevKey = mCurrKey; 1656bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mCurrKey = key; 1666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 1676bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (mTask != null) { 1686bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mTask.cancel(); 1696bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mTask = null; 1706bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 1716bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (mCreateFileDescriptorFactoryTask != null) { 1726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mCreateFileDescriptorFactoryTask.cancel(); 1736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mCreateFileDescriptorFactoryTask = null; 1746bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 175ef8225444452a1486bd721f3285301fe84643b00Stephen Hines 176ef8225444452a1486bd721f3285301fe84643b00Stephen Hines if (key == null) { 177ef8225444452a1486bd721f3285301fe84643b00Stephen Hines invalidateSelf(); 178ef8225444452a1486bd721f3285301fe84643b00Stephen Hines Trace.endSection(); 179ef8225444452a1486bd721f3285301fe84643b00Stephen Hines return; 180ef8225444452a1486bd721f3285301fe84643b00Stephen Hines } 1816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 1826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines // find cached entry here and skip decode if found. 1836bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines final ReusableBitmap cached = mCache.get(key, true /* incrementRefCount */); 1846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (cached != null) { 1856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines setBitmap(cached); 1866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (DEBUG) { 1876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Log.d(TAG, String.format("CACHE HIT key=%s", mCurrKey)); 1886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 1896bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } else { 1906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines loadFileDescriptorFactory(); 1916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (DEBUG) { 1926bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Log.d(TAG, String.format( 1936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines "CACHE MISS key=%s\ncache=%s", mCurrKey, mCache.toDebugString())); 1946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 1956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 1966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Trace.endSection(); 1976bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 1986bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 1996bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines /** 2006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * Should only be overriden, not called. 2016bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines */ 2026bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines protected void setBitmap(ReusableBitmap bmp) { 2036bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (mBitmap != null && mBitmap != bmp) { 2046bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mBitmap.releaseReference(); 2056bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2066bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mBitmap = bmp; 2076bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines invalidateSelf(); 2086bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 2106bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines /** 2116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * Should only be overriden, not called. 2126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines */ 2136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines protected void loadFileDescriptorFactory() { 2146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (mCurrKey == null || mDecodeWidth == 0 || mDecodeHeight == 0) { 2156bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines return; 2166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2176bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 2186bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines // Create file descriptor if request supports it. 2196bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mCreateFileDescriptorFactoryTask = mCurrKey 2206bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines .createFileDescriptorFactoryAsync(mCurrKey, this); 2216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (mCreateFileDescriptorFactoryTask == null) { 2226bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines // Use input stream if request does not. 2236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines decode(null); 2246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 2276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines @Override 2286bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines public void fileDescriptorFactoryCreated(final RequestKey key, 2296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines final FileDescriptorFactory factory) { 2306bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (mCreateFileDescriptorFactoryTask == null) { 2316bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines // Cancelled. 2326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines return; 2336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2346bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mCreateFileDescriptorFactoryTask = null; 2356bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 2366bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (key.equals(mCurrKey)) { 2376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines decode(factory); 2386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 2416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines /** 2426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines * Should only be overriden, not called. 2436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines */ 2446bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines protected void decode(final FileDescriptorFactory factory) { 2456bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Trace.beginSection("decode"); 2466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines final int bufferW; 2476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines final int bufferH; 2486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (mLimitDensity) { 2496bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines final float scale = 2506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Math.min(1f, (float) MAX_BITMAP_DENSITY / DisplayMetrics.DENSITY_DEFAULT 2516bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines / mDensity); 2526bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines bufferW = (int) (mDecodeWidth * scale); 2536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines bufferH = (int) (mDecodeHeight * scale); 2546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } else { 2556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines bufferW = mDecodeWidth; 2566bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines bufferH = mDecodeHeight; 2576bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2586bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 2596bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (mTask != null) { 2606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mTask.cancel(); 2616bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2626bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines final DecodeOptions opts = new DecodeOptions(bufferW, bufferH, getDecodeVerticalCenter(), 2636bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines DecodeOptions.STRATEGY_ROUND_NEAREST); 2646bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mTask = new DecodeTask(mCurrKey, opts, factory, this, mCache); 2656bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mTask.executeOnExecutor(getExecutor()); 2666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Trace.endSection(); 2676bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2686bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 2696bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines protected Executor getExecutor() { 2706bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines return EXECUTOR; 2716bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 2736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines protected float getDrawVerticalCenter() { 2746bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines return VERTICAL_CENTER; 2756bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2766bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 2776bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines protected float getDrawVerticalOffsetMultiplier() { 2786bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines return NO_MULTIPLIER; 2796bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2806bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 2816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines protected float getDecodeVerticalCenter() { 2826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines return VERTICAL_CENTER; 2836bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 2856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines @Override 2866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines public void draw(final Canvas canvas) { 2876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines final Rect bounds = getBounds(); 2886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (bounds.isEmpty()) { 2896bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines return; 2906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 2916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 2926bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (mBitmap != null && mBitmap.bmp != null) { 2936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines BitmapUtils.calculateCroppedSrcRect( 2946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines mBitmap.getLogicalWidth(), mBitmap.getLogicalHeight(), 2956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines bounds.width(), bounds.height(), 2966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines bounds.height(), Integer.MAX_VALUE, 2976bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines getDrawVerticalCenter(), false /* absoluteFraction */, 2986bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines getDrawVerticalOffsetMultiplier(), sRect); 2996bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 3006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines final int orientation = mBitmap.getOrientation(); 3016bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines // calculateCroppedSrcRect() gave us the source rectangle "as if" the orientation has 3026bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines // been corrected. We need to decode the uncorrected source rectangle. Calculate true 3036bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines // coordinates. 3046bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines RectUtils.rotateRectForOrientation(orientation, 3056bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines new Rect(0, 0, mBitmap.getLogicalWidth(), mBitmap.getLogicalHeight()), 3066bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines sRect); 3076bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 3086bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines // We may need to rotate the canvas, so we also have to rotate the bounds. 3096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines final Rect rotatedBounds = new Rect(bounds); 3106bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines RectUtils.rotateRect(orientation, bounds.centerX(), bounds.centerY(), rotatedBounds); 3116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 3126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines // Rotate the canvas. 3136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines canvas.save(); 3146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines canvas.rotate(orientation, bounds.centerX(), bounds.centerY()); 3156bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines onDrawBitmap(canvas, rotatedBounds); 3166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines canvas.restore(); 317 } 318 } 319 320 /** 321 * Override this method to customize how to draw the bitmap to the canvas for the given bounds. 322 * The bitmap to be drawn can be found at {@link #getBitmap()}. 323 */ 324 protected void onDrawBitmap(final Canvas canvas, final Rect bounds) { 325 canvas.drawBitmap(mBitmap.bmp, sRect, bounds, mPaint); 326 } 327 328 @Override 329 public void setAlpha(int alpha) { 330 final int old = mPaint.getAlpha(); 331 mPaint.setAlpha(alpha); 332 if (alpha != old) { 333 invalidateSelf(); 334 } 335 } 336 337 @Override 338 public void setColorFilter(ColorFilter cf) { 339 mPaint.setColorFilter(cf); 340 invalidateSelf(); 341 } 342 343 @Override 344 public int getOpacity() { 345 return (mBitmap != null && (mBitmap.bmp.hasAlpha() || mPaint.getAlpha() < 255)) ? 346 PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; 347 } 348 349 @Override 350 public void onDecodeBegin(final RequestKey key) { } 351 352 @Override 353 public void onDecodeComplete(final RequestKey key, final ReusableBitmap result) { 354 if (key.equals(mCurrKey)) { 355 setBitmap(result); 356 } else { 357 // if the requests don't match (i.e. this request is stale), decrement the 358 // ref count to allow the bitmap to be pooled 359 if (result != null) { 360 result.releaseReference(); 361 } 362 } 363 } 364 365 @Override 366 public void onDecodeCancel(final RequestKey key) { } 367 368 @Override 369 public void invalidateDrawable(Drawable who) { 370 invalidateSelf(); 371 } 372 373 @Override 374 public void scheduleDrawable(Drawable who, Runnable what, long when) { 375 scheduleSelf(what, when); 376 } 377 378 @Override 379 public void unscheduleDrawable(Drawable who, Runnable what) { 380 unscheduleSelf(what); 381 } 382} 383