DecodeTask.java revision 3a79e2002f9f6114b549c4bc2cc08bb10e75a4d2
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 Blitzstein 1793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinpackage com.android.bitmap; 1893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 1993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.Bitmap; 2093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.BitmapFactory; 2193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.BitmapRegionDecoder; 2293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.Rect; 2393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.os.AsyncTask; 24cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Weiimport android.os.ParcelFileDescriptor; 25cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Weiimport android.os.ParcelFileDescriptor.AutoCloseInputStream; 2693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.util.Log; 2793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 289c6ac19d4a3d39b7c2992060957920118ff56a65Mark Weiimport com.android.bitmap.RequestKey.FileDescriptorFactory; 2993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.BitmapUtils; 3093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.Exif; 3193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.RectUtils; 3293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.Trace; 3393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 3493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport java.io.IOException; 3593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport java.io.InputStream; 3693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 3793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/** 3893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Decodes an image from either a file descriptor or input stream on a worker thread. After the 3993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * decode is complete, even if the task is cancelled, the result is placed in the given cache. 4093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * A {@link DecodeCallback} client may be notified on decode begin and completion. 4193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p> 4293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * This class uses {@link BitmapRegionDecoder} when possible to minimize unnecessary decoding 4393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * and allow bitmap reuse on Jellybean 4.1 and later. 4493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p> 4593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * GIFs are supported, but their decode does not reuse bitmaps at all. The resulting 4693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * {@link ReusableBitmap} will be marked as not reusable 4793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * ({@link ReusableBitmap#isEligibleForPooling()} will return false). 4893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 4993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinpublic class DecodeTask extends AsyncTask<Void, Void, ReusableBitmap> { 5093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 5140662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein private final RequestKey mKey; 52cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei private final DecodeOptions mDecodeOpts; 539c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei private final FileDescriptorFactory mFactory; 5493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private final DecodeCallback mDecodeCallback; 5593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private final BitmapCache mCache; 5693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private final BitmapFactory.Options mOpts = new BitmapFactory.Options(); 5793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 5893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private ReusableBitmap mInBitmap = null; 5993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 6093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private static final boolean CROP_DURING_DECODE = true; 6193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 6293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private static final String TAG = DecodeTask.class.getSimpleName(); 63cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei public static final boolean DEBUG = false; 6493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 6593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 6693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Callback interface for clients to be notified of decode state changes and completion. 6793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 6893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public interface DecodeCallback { 6993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 7093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Notifies that the async task's work is about to begin. Up until this point, the task 7193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * may have been preempted by the scheduler or queued up by a bottlenecked executor. 7293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p> 7393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * N.B. this method runs on the UI thread. 7493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 7540662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein void onDecodeBegin(RequestKey key); 7693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 7793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * The task is now complete and the ReusableBitmap is available for use. Clients should 7893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * double check that the request matches what the client is expecting. 7993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 8040662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein void onDecodeComplete(RequestKey key, ReusableBitmap result); 8193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 8240662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein * The task has been canceled, and {@link #onDecodeComplete(RequestKey, ReusableBitmap)} 8340662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein * will not be called. 8493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 8540662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein void onDecodeCancel(RequestKey key); 8693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 8793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 88cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei /** 899c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei * Create new DecodeTask. 909c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei * 919c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei * @param requestKey The request to decode, also the key to use for the cache. 929c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei * @param decodeOpts The decode options. 939c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei * @param factory The factory to obtain file descriptors to decode from. If this factory is 949c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei * null, then we will decode from requestKey.createInputStream(). 959c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei * @param callback The callback to notify of decode state changes. 969c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei * @param cache The cache and pool. 979c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei */ 98cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei public DecodeTask(RequestKey requestKey, DecodeOptions decodeOpts, 999c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei FileDescriptorFactory factory, DecodeCallback callback, BitmapCache cache) { 100cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei mKey = requestKey; 101cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei mDecodeOpts = decodeOpts; 1029c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei mFactory = factory; 103cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei mDecodeCallback = callback; 10493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mCache = cache; 10593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 10693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 10793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 10893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein protected ReusableBitmap doInBackground(Void... params) { 10993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // enqueue the 'onDecodeBegin' signal on the main thread 11093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein publishProgress(); 11193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 11293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return decode(); 11393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 11493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 11593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public ReusableBitmap decode() { 11693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (isCancelled()) { 11793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return null; 11893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 11993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 12093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein ReusableBitmap result = null; 121cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei ParcelFileDescriptor fd = null; 12293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein InputStream in = null; 12393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 1241ef4c6b7fdbc6e36c030e4a6fab3a8ccf8ba524bMark Wei try { 1259c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei if (mFactory != null) { 1262e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei Trace.beginSection("create fd"); 1279c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei fd = mFactory.createFileDescriptor(); 1282e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei Trace.endSection(); 1299c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei } else { 13093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein in = reset(in); 13193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (in == null) { 13293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return null; 13393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 1341ef4c6b7fdbc6e36c030e4a6fab3a8ccf8ba524bMark Wei if (isCancelled()) { 1351ef4c6b7fdbc6e36c030e4a6fab3a8ccf8ba524bMark Wei return null; 1361ef4c6b7fdbc6e36c030e4a6fab3a8ccf8ba524bMark Wei } 1371ef4c6b7fdbc6e36c030e4a6fab3a8ccf8ba524bMark Wei } 1381ef4c6b7fdbc6e36c030e4a6fab3a8ccf8ba524bMark Wei 1391ef4c6b7fdbc6e36c030e4a6fab3a8ccf8ba524bMark Wei final boolean isJellyBeanOrAbove = android.os.Build.VERSION.SDK_INT 1401ef4c6b7fdbc6e36c030e4a6fab3a8ccf8ba524bMark Wei >= android.os.Build.VERSION_CODES.JELLY_BEAN; 1411ef4c6b7fdbc6e36c030e4a6fab3a8ccf8ba524bMark Wei // This blocks during fling when the pool is empty. We block early to avoid jank. 1421ef4c6b7fdbc6e36c030e4a6fab3a8ccf8ba524bMark Wei if (isJellyBeanOrAbove) { 1431ef4c6b7fdbc6e36c030e4a6fab3a8ccf8ba524bMark Wei Trace.beginSection("poll for reusable bitmap"); 1441ef4c6b7fdbc6e36c030e4a6fab3a8ccf8ba524bMark Wei mInBitmap = mCache.poll(); 1451ef4c6b7fdbc6e36c030e4a6fab3a8ccf8ba524bMark Wei Trace.endSection(); 14693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 1472e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei 1482e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei if (isCancelled()) { 1492e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei return null; 1502e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei } 15193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 15293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.beginSection("get bytesize"); 15393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final long byteSize; 15493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (fd != null) { 155cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei byteSize = fd.getStatSize(); 15693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 15793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein byteSize = -1; 15893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 15993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 16093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 16193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.beginSection("get orientation"); 16293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final int orientation; 16393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mKey.hasOrientationExif()) { 16493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (fd != null) { 16593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Creating an input stream from the file descriptor makes it useless 16693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // afterwards. 1679c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei Trace.beginSection("create orientation fd and stream"); 1689c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei final ParcelFileDescriptor orientationFd = mFactory.createFileDescriptor(); 169cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei in = new AutoCloseInputStream(orientationFd); 17093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 17193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 17293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein orientation = Exif.getOrientation(in, byteSize); 17393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (fd != null) { 17493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein try { 17593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Close the temporary file descriptor. 17693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein in.close(); 17793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } catch (IOException ignored) { 17893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 17993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 18093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 18193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein orientation = 0; 18293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 18393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final boolean isNotRotatedOr180 = orientation == 0 || orientation == 180; 18493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 18593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 18693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (orientation != 0) { 18793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // disable inBitmap-- bitmap reuse doesn't work with different decode regions due 18893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // to orientation 18993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mInBitmap != null) { 19093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mCache.offer(mInBitmap); 19193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mInBitmap = null; 19293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mOpts.inBitmap = null; 19393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 19493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 19593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 19693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (isCancelled()) { 19793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return null; 19893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 19993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 20093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (fd == null) { 20193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein in = reset(in); 20293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (in == null) { 20393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return null; 20493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 2052e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei if (isCancelled()) { 2062e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei return null; 2072e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei } 20893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 20993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 21093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.beginSection("decodeBounds"); 21193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mOpts.inJustDecodeBounds = true; 21293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (fd != null) { 21393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor(), null, mOpts); 21493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 21593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein BitmapFactory.decodeStream(in, null, mOpts); 21693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 21793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 21893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 21993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (isCancelled()) { 22093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return null; 22193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 22293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 22393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // We want to calculate the sample size "as if" the orientation has been corrected. 22493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final int srcW, srcH; // Orientation corrected. 22593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (isNotRotatedOr180) { 22693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein srcW = mOpts.outWidth; 22793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein srcH = mOpts.outHeight; 22893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 22993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein srcW = mOpts.outHeight; 23093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein srcH = mOpts.outWidth; 23193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 23222955165fab693684cc3614c84ee81883ae933c8Mark Wei 23322955165fab693684cc3614c84ee81883ae933c8Mark Wei // BEGIN MANUAL-INLINE calculateSampleSize() 23422955165fab693684cc3614c84ee81883ae933c8Mark Wei 23522955165fab693684cc3614c84ee81883ae933c8Mark Wei final float sz = Math 23622955165fab693684cc3614c84ee81883ae933c8Mark Wei .min((float) srcW / mDecodeOpts.destW, (float) srcH / mDecodeOpts.destH); 23722955165fab693684cc3614c84ee81883ae933c8Mark Wei 23822955165fab693684cc3614c84ee81883ae933c8Mark Wei final int sampleSize; 23922955165fab693684cc3614c84ee81883ae933c8Mark Wei switch (mDecodeOpts.sampleSizeStrategy) { 24022955165fab693684cc3614c84ee81883ae933c8Mark Wei case DecodeOptions.STRATEGY_TRUNCATE: 24122955165fab693684cc3614c84ee81883ae933c8Mark Wei sampleSize = (int) sz; 24222955165fab693684cc3614c84ee81883ae933c8Mark Wei break; 24322955165fab693684cc3614c84ee81883ae933c8Mark Wei case DecodeOptions.STRATEGY_ROUND_UP: 24422955165fab693684cc3614c84ee81883ae933c8Mark Wei sampleSize = (int) Math.ceil(sz); 24522955165fab693684cc3614c84ee81883ae933c8Mark Wei break; 24622955165fab693684cc3614c84ee81883ae933c8Mark Wei case DecodeOptions.STRATEGY_ROUND_NEAREST: 24722955165fab693684cc3614c84ee81883ae933c8Mark Wei default: 24822955165fab693684cc3614c84ee81883ae933c8Mark Wei sampleSize = (int) Math.pow(2, (int) (0.5 + (Math.log(sz) / Math.log(2)))); 24922955165fab693684cc3614c84ee81883ae933c8Mark Wei break; 25022955165fab693684cc3614c84ee81883ae933c8Mark Wei } 25122955165fab693684cc3614c84ee81883ae933c8Mark Wei mOpts.inSampleSize = Math.max(1, sampleSize); 25222955165fab693684cc3614c84ee81883ae933c8Mark Wei 25322955165fab693684cc3614c84ee81883ae933c8Mark Wei // END MANUAL-INLINE calculateSampleSize() 25422955165fab693684cc3614c84ee81883ae933c8Mark Wei 25593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mOpts.inJustDecodeBounds = false; 25693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mOpts.inMutable = true; 25793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (isJellyBeanOrAbove && orientation == 0) { 25893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mInBitmap == null) { 25993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (DEBUG) { 26093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.e(TAG, "decode thread wants a bitmap. cache dump:\n" 26193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein + mCache.toDebugString()); 26293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 26393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.beginSection("create reusable bitmap"); 264cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei mInBitmap = new ReusableBitmap( 265cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei Bitmap.createBitmap(mDecodeOpts.destW, mDecodeOpts.destH, 266cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei Bitmap.Config.ARGB_8888)); 26793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 26893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 26993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (isCancelled()) { 27093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return null; 27193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 27293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 27393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (DEBUG) { 27493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.e(TAG, "*** allocated new bitmap in decode thread: " 27593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein + mInBitmap + " key=" + mKey); 27693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 27793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 27893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (DEBUG) { 27993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.e(TAG, "*** reusing existing bitmap in decode thread: " 28093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein + mInBitmap + " key=" + mKey); 28193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 28293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 28393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 28493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mOpts.inBitmap = mInBitmap.bmp; 28593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 28693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 28793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (isCancelled()) { 28893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return null; 28993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 29093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 29193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (fd == null) { 29293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein in = reset(in); 29393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (in == null) { 29493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return null; 29593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 2962e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei if (isCancelled()) { 2972e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei return null; 2982e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei } 29993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 30093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 3012e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei 30293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Bitmap decodeResult = null; 30393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final Rect srcRect = new Rect(); // Not orientation corrected. True coordinates. 30493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (CROP_DURING_DECODE) { 30593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein try { 30693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.beginSection("decodeCropped" + mOpts.inSampleSize); 30722955165fab693684cc3614c84ee81883ae933c8Mark Wei 30822955165fab693684cc3614c84ee81883ae933c8Mark Wei // BEGIN MANUAL INLINE decodeCropped() 30922955165fab693684cc3614c84ee81883ae933c8Mark Wei 31022955165fab693684cc3614c84ee81883ae933c8Mark Wei final BitmapRegionDecoder brd; 31122955165fab693684cc3614c84ee81883ae933c8Mark Wei if (fd != null) { 31222955165fab693684cc3614c84ee81883ae933c8Mark Wei brd = BitmapRegionDecoder 31322955165fab693684cc3614c84ee81883ae933c8Mark Wei .newInstance(fd.getFileDescriptor(), true /* shareable */); 31422955165fab693684cc3614c84ee81883ae933c8Mark Wei } else { 31522955165fab693684cc3614c84ee81883ae933c8Mark Wei brd = BitmapRegionDecoder.newInstance(in, true /* shareable */); 31622955165fab693684cc3614c84ee81883ae933c8Mark Wei } 31722955165fab693684cc3614c84ee81883ae933c8Mark Wei 31822955165fab693684cc3614c84ee81883ae933c8Mark Wei final Bitmap bitmap; 31922955165fab693684cc3614c84ee81883ae933c8Mark Wei if (isCancelled()) { 32022955165fab693684cc3614c84ee81883ae933c8Mark Wei bitmap = null; 32122955165fab693684cc3614c84ee81883ae933c8Mark Wei } else { 32222955165fab693684cc3614c84ee81883ae933c8Mark Wei // We want to call calculateCroppedSrcRect() on the source rectangle "as 32322955165fab693684cc3614c84ee81883ae933c8Mark Wei // if" the orientation has been corrected. 32422955165fab693684cc3614c84ee81883ae933c8Mark Wei // Center the decode on the top 1/3. 32522955165fab693684cc3614c84ee81883ae933c8Mark Wei BitmapUtils.calculateCroppedSrcRect(srcW, srcH, mDecodeOpts.destW, 3263a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung mDecodeOpts.destH, mDecodeOpts.destH, mOpts.inSampleSize, 3273a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung mDecodeOpts.horizontalCenter, mDecodeOpts.verticalCenter, 32822955165fab693684cc3614c84ee81883ae933c8Mark Wei true /* absoluteFraction */, 32922955165fab693684cc3614c84ee81883ae933c8Mark Wei 1f, srcRect); 33022955165fab693684cc3614c84ee81883ae933c8Mark Wei if (DEBUG) { 33122955165fab693684cc3614c84ee81883ae933c8Mark Wei System.out.println("rect for this decode is: " + srcRect 33222955165fab693684cc3614c84ee81883ae933c8Mark Wei + " srcW/H=" + srcW + "/" + srcH 33322955165fab693684cc3614c84ee81883ae933c8Mark Wei + " dstW/H=" + mDecodeOpts.destW + "/" + mDecodeOpts.destH); 33422955165fab693684cc3614c84ee81883ae933c8Mark Wei } 33522955165fab693684cc3614c84ee81883ae933c8Mark Wei 33622955165fab693684cc3614c84ee81883ae933c8Mark Wei // calculateCroppedSrcRect() gave us the source rectangle "as if" the 33722955165fab693684cc3614c84ee81883ae933c8Mark Wei // orientation has been corrected. We need to decode the uncorrected 33822955165fab693684cc3614c84ee81883ae933c8Mark Wei // source rectangle. Calculate true coordinates. 33922955165fab693684cc3614c84ee81883ae933c8Mark Wei RectUtils.rotateRectForOrientation(orientation, new Rect(0, 0, srcW, srcH), 34022955165fab693684cc3614c84ee81883ae933c8Mark Wei srcRect); 34122955165fab693684cc3614c84ee81883ae933c8Mark Wei 34222955165fab693684cc3614c84ee81883ae933c8Mark Wei bitmap = brd.decodeRegion(srcRect, mOpts); 34322955165fab693684cc3614c84ee81883ae933c8Mark Wei } 34422955165fab693684cc3614c84ee81883ae933c8Mark Wei brd.recycle(); 34522955165fab693684cc3614c84ee81883ae933c8Mark Wei 34622955165fab693684cc3614c84ee81883ae933c8Mark Wei // END MANUAL INLINE decodeCropped() 34722955165fab693684cc3614c84ee81883ae933c8Mark Wei 34822955165fab693684cc3614c84ee81883ae933c8Mark Wei decodeResult = bitmap; 34993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } catch (IOException e) { 35093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // fall through to below and try again with the non-cropping decoder 351c7ad691a967e860a93d76bedb7c5d207dd083591Mark Wei if (fd == null) { 352c7ad691a967e860a93d76bedb7c5d207dd083591Mark Wei in = reset(in); 353c7ad691a967e860a93d76bedb7c5d207dd083591Mark Wei if (in == null) { 354c7ad691a967e860a93d76bedb7c5d207dd083591Mark Wei return null; 355c7ad691a967e860a93d76bedb7c5d207dd083591Mark Wei } 356c7ad691a967e860a93d76bedb7c5d207dd083591Mark Wei if (isCancelled()) { 357c7ad691a967e860a93d76bedb7c5d207dd083591Mark Wei return null; 358c7ad691a967e860a93d76bedb7c5d207dd083591Mark Wei } 359c7ad691a967e860a93d76bedb7c5d207dd083591Mark Wei } 360c7ad691a967e860a93d76bedb7c5d207dd083591Mark Wei 36193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein e.printStackTrace(); 36293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } finally { 36393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 36493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 36593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 36693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (isCancelled()) { 36793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return null; 36893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 36993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 37093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 37193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein //noinspection PointlessBooleanExpression 37293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (!CROP_DURING_DECODE || (decodeResult == null && !isCancelled())) { 37393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein try { 37493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.beginSection("decode" + mOpts.inSampleSize); 37593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // disable inBitmap-- bitmap reuse doesn't work well below K 37693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mInBitmap != null) { 37793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mCache.offer(mInBitmap); 37893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mInBitmap = null; 37993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mOpts.inBitmap = null; 38093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 38193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein decodeResult = decode(fd, in); 38293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } catch (IllegalArgumentException e) { 38393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.e(TAG, "decode failed: reason='" + e.getMessage() + "' ss=" 38493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein + mOpts.inSampleSize); 38593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 38693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mOpts.inSampleSize > 1) { 38793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // try again with ss=1 38893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mOpts.inSampleSize = 1; 38993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein decodeResult = decode(fd, in); 39093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 39193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } finally { 39293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 39393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 39493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 39593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (isCancelled()) { 39693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return null; 39793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 39893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 39993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 40093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (decodeResult == null) { 40193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return null; 40293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 40393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 40493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mInBitmap != null) { 40593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result = mInBitmap; 40693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // srcRect is non-empty when using the cropping BitmapRegionDecoder codepath 40793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (!srcRect.isEmpty()) { 40893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result.setLogicalWidth((srcRect.right - srcRect.left) / mOpts.inSampleSize); 40993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result.setLogicalHeight( 41093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein (srcRect.bottom - srcRect.top) / mOpts.inSampleSize); 41193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 41293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result.setLogicalWidth(mOpts.outWidth); 41393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result.setLogicalHeight(mOpts.outHeight); 41493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 41593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 41693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // no mInBitmap means no pooling 41793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result = new ReusableBitmap(decodeResult, false /* reusable */); 41893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (isNotRotatedOr180) { 41993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result.setLogicalWidth(decodeResult.getWidth()); 42093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result.setLogicalHeight(decodeResult.getHeight()); 42193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 42293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result.setLogicalWidth(decodeResult.getHeight()); 42393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result.setLogicalHeight(decodeResult.getWidth()); 42493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 42593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 42693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result.setOrientation(orientation); 42793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } catch (Exception e) { 42893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein e.printStackTrace(); 42993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } finally { 43093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (fd != null) { 43193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein try { 43293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein fd.close(); 43393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } catch (IOException ignored) { 43493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 43593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 43693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (in != null) { 43793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein try { 43893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein in.close(); 43993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } catch (IOException ignored) { 44093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 44193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 442a07e0af0f1997ce3d40df6a8a9f44cb0b2e4c07fJames Kung 443a07e0af0f1997ce3d40df6a8a9f44cb0b2e4c07fJames Kung // Put result in cache, regardless of null. The cache will handle null results. 444a07e0af0f1997ce3d40df6a8a9f44cb0b2e4c07fJames Kung mCache.put(mKey, result); 44593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (result != null) { 44693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result.acquireReference(); 44793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (DEBUG) { 44893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.d(TAG, "placed result in cache: key=" + mKey + " bmp=" 44993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein + result + " cancelled=" + isCancelled()); 45093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 45193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else if (mInBitmap != null) { 45293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (DEBUG) { 45393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.d(TAG, "placing failed/cancelled bitmap in pool: key=" 45493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein + mKey + " bmp=" + mInBitmap); 45593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 45693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mCache.offer(mInBitmap); 45793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 45893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 45993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return result; 46093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 46193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 46293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 46393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Return an input stream that can be read from the beginning using the most efficient way, 46493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * given an input stream that may or may not support reset(), or given null. 46593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 46693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * The returned input stream may or may not be the same stream. 46793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 46893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private InputStream reset(InputStream in) throws IOException { 46993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.beginSection("create stream"); 47093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (in == null) { 47193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein in = mKey.createInputStream(); 47293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else if (in.markSupported()) { 47393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein in.reset(); 47493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 47593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein try { 47693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein in.close(); 47793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } catch (IOException ignored) { 47893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 47993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein in = mKey.createInputStream(); 48093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 48193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 48293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return in; 48393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 48493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 485cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei private Bitmap decode(ParcelFileDescriptor fd, InputStream in) { 48693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final Bitmap result; 48793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (fd != null) { 48893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor(), null, mOpts); 48993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 49093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result = BitmapFactory.decodeStream(in, null, mOpts); 49193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 49293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return result; 49393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 49493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 49593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void cancel() { 49693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein cancel(true); 49793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mOpts.requestCancelDecode(); 49893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 49993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 50093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 50193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein protected void onProgressUpdate(Void... values) { 50293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mDecodeCallback.onDecodeBegin(mKey); 50393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 50493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 50593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 50693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void onPostExecute(ReusableBitmap result) { 50793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mDecodeCallback.onDecodeComplete(mKey, result); 50893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 50993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 51093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 51193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein protected void onCancelled(ReusableBitmap result) { 51293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mDecodeCallback.onDecodeCancel(mKey); 51393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (result == null) { 51493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return; 51593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 51693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 51793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result.releaseReference(); 51893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mInBitmap == null) { 51993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // not reusing bitmaps: can recycle immediately 52093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein result.bmp.recycle(); 52193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 52293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 52393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 5245030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 5255030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Parameters to pass to the DecodeTask. 5265030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 527cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei public static class DecodeOptions { 528cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei 529cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei /** 530cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * Round sample size to the nearest power of 2. Depending on the source and destination 531cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * dimensions, we will either truncate, in which case we decode from a bigger region and 532cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * crop down, or we will round up, in which case we decode from a smaller region and scale 533cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * up. 534cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei */ 535cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei public static final int STRATEGY_ROUND_NEAREST = 0; 536cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei /** 537cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * Always decode from a bigger region and crop down. 538cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei */ 539cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei public static final int STRATEGY_TRUNCATE = 1; 540cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei 541cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei /** 542cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * Always decode from a smaller region and scale up. 543cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei */ 544cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei public static final int STRATEGY_ROUND_UP = 2; 545cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei 546cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei /** 547cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * The destination width to decode to. 548cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei */ 549cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei public int destW; 550cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei /** 551cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * The destination height to decode to. 552cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei */ 553cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei public int destH; 554cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei /** 555cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * If the destination dimensions are smaller than the source image provided by the request 5563a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * key, this will determine where horizontally the destination rect will be cropped from. 5573a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * Value from 0f for left-most crop to 1f for right-most crop. 5583a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung */ 5593a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung public float horizontalCenter; 5603a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung /** 5613a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * If the destination dimensions are smaller than the source image provided by the request 562cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * key, this will determine where vertically the destination rect will be cropped from. 563cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * Value from 0f for top-most crop to 1f for bottom-most crop. 564cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei */ 565cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei public float verticalCenter; 566cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei /** 567cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * One of the STRATEGY constants. 568cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei */ 569cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei public int sampleSizeStrategy; 570cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei 571cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei public DecodeOptions(final int destW, final int destH) { 5723a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung this(destW, destH, 0.5f, 0.5f, STRATEGY_ROUND_NEAREST); 5733a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung } 5743a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung 5753a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung /** 5763a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * Create new DecodeOptions with horizontally-centered cropping if applicable. 5773a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * @param destW The destination width to decode to. 5783a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * @param destH The destination height to decode to. 5793a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * @param verticalCenter If the destination dimensions are smaller than the source image 5803a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * provided by the request key, this will determine where vertically 5813a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * the destination rect will be cropped from. 5823a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * @param sampleSizeStrategy One of the STRATEGY constants. 5833a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung */ 5843a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung public DecodeOptions(final int destW, final int destH, 5853a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung final float verticalCenter, final int sampleSizeStrategy) { 5863a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung this(destW, destH, 0.5f, verticalCenter, sampleSizeStrategy); 587cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei } 588cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei 589cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei /** 590cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * Create new DecodeOptions. 591cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * @param destW The destination width to decode to. 592cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * @param destH The destination height to decode to. 5933a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * @param horizontalCenter If the destination dimensions are smaller than the source image 5943a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * provided by the request key, this will determine where 5953a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * horizontally the destination rect will be cropped from. 596cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * @param verticalCenter If the destination dimensions are smaller than the source image 597cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * provided by the request key, this will determine where vertically 598cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * the destination rect will be cropped from. 599cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei * @param sampleSizeStrategy One of the STRATEGY constants. 600cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei */ 6013a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung public DecodeOptions(final int destW, final int destH, final float horizontalCenter, 6023a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung final float verticalCenter, final int sampleSizeStrategy) { 603cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei this.destW = destW; 604cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei this.destH = destH; 6053a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung this.horizontalCenter = horizontalCenter; 606cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei this.verticalCenter = verticalCenter; 607cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei this.sampleSizeStrategy = sampleSizeStrategy; 608cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei } 609cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei } 61093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein} 611