DecodeTask.java revision 40662f4b39e795d9c64502b13036e7c37fa2d373
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.content.res.AssetFileDescriptor;
2093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.Bitmap;
2193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.BitmapFactory;
2293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.BitmapRegionDecoder;
2393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.Rect;
2493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.os.AsyncTask;
2593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.util.Log;
2693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
2793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.BitmapUtils;
2893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.Exif;
2993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.RectUtils;
3093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.Trace;
3193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
3293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport java.io.IOException;
3393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport java.io.InputStream;
3493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
3593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/**
3693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Decodes an image from either a file descriptor or input stream on a worker thread. After the
3793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * decode is complete, even if the task is cancelled, the result is placed in the given cache.
3893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * A {@link DecodeCallback} client may be notified on decode begin and completion.
3993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p>
4093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * This class uses {@link BitmapRegionDecoder} when possible to minimize unnecessary decoding
4193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * and allow bitmap reuse on Jellybean 4.1 and later.
4293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p>
4393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *  GIFs are supported, but their decode does not reuse bitmaps at all. The resulting
4493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *  {@link ReusableBitmap} will be marked as not reusable
4593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *  ({@link ReusableBitmap#isEligibleForPooling()} will return false).
4693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */
4793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinpublic class DecodeTask extends AsyncTask<Void, Void, ReusableBitmap> {
4893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
4940662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein    private final RequestKey mKey;
5093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final int mDestW;
5193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final int mDestH;
5293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final DecodeCallback mDecodeCallback;
5393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final BitmapCache mCache;
5493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final BitmapFactory.Options mOpts = new BitmapFactory.Options();
5593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
5693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private ReusableBitmap mInBitmap = null;
5793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
5893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private static final boolean CROP_DURING_DECODE = true;
5993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
6093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private static final String TAG = DecodeTask.class.getSimpleName();
6193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private static final boolean DEBUG = false;
6293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
6393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    /**
6493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * Callback interface for clients to be notified of decode state changes and completion.
6593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     */
6693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public interface DecodeCallback {
6793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        /**
6893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein         * Notifies that the async task's work is about to begin. Up until this point, the task
6993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein         * may have been preempted by the scheduler or queued up by a bottlenecked executor.
7093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein         * <p>
7193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein         * N.B. this method runs on the UI thread.
7293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein         */
7340662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein        void onDecodeBegin(RequestKey key);
7493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        /**
7593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein         * The task is now complete and the ReusableBitmap is available for use. Clients should
7693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein         * double check that the request matches what the client is expecting.
7793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein         */
7840662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein        void onDecodeComplete(RequestKey key, ReusableBitmap result);
7993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        /**
8040662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein         * The task has been canceled, and {@link #onDecodeComplete(RequestKey, ReusableBitmap)}
8140662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein         * will not be called.
8293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein         */
8340662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein        void onDecodeCancel(RequestKey key);
8493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
8593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
8640662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein    public DecodeTask(RequestKey key, int w, int h, DecodeCallback view,
8793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            BitmapCache cache) {
8893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mKey = key;
8993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mDestW = w;
9093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mDestH = h;
9193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mDecodeCallback = view;
9293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mCache = cache;
9393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
9493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
9593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
9693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    protected ReusableBitmap doInBackground(Void... params) {
9793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        // enqueue the 'onDecodeBegin' signal on the main thread
9893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        publishProgress();
9993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
10093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return decode();
10193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
10293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
10393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public ReusableBitmap decode() {
10493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (isCancelled()) {
10593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            return null;
10693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
10793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
10893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        ReusableBitmap result = null;
10993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        AssetFileDescriptor fd = null;
11093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        InputStream in = null;
11193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        try {
11293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            final boolean isJellyBeanOrAbove = android.os.Build.VERSION.SDK_INT
11393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    >= android.os.Build.VERSION_CODES.JELLY_BEAN;
11493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            // This blocks during fling when the pool is empty. We block early to avoid jank.
11593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (isJellyBeanOrAbove) {
11693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                Trace.beginSection("poll for reusable bitmap");
11793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                mInBitmap = mCache.poll();
11893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                Trace.endSection();
11993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
12093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (isCancelled()) {
12193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    return null;
12293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
12393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
12493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
12593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            Trace.beginSection("create fd and stream");
12693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            fd = mKey.createFd();
12793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            Trace.endSection();
12893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (fd == null) {
12993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                in = reset(in);
13093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (in == null) {
13193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    return null;
13293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
13393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
13493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
13593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            Trace.beginSection("get bytesize");
13693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            final long byteSize;
13793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (fd != null) {
13893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                byteSize = fd.getLength();
13993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            } else {
14093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                byteSize = -1;
14193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
14293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            Trace.endSection();
14393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
14493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            Trace.beginSection("get orientation");
14593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            final int orientation;
14693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (mKey.hasOrientationExif()) {
14793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (fd != null) {
14893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    // Creating an input stream from the file descriptor makes it useless
14993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    // afterwards.
15093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    Trace.beginSection("create fd and stream");
15193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    final AssetFileDescriptor orientationFd = mKey.createFd();
15293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    in = orientationFd.createInputStream();
15393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    Trace.endSection();
15493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
15593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                orientation = Exif.getOrientation(in, byteSize);
15693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (fd != null) {
15793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    try {
15893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        // Close the temporary file descriptor.
15993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        in.close();
16093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    } catch (IOException ignored) {
16193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    }
16293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
16393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            } else {
16493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                orientation = 0;
16593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
16693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            final boolean isNotRotatedOr180 = orientation == 0 || orientation == 180;
16793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            Trace.endSection();
16893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
16993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (orientation != 0) {
17093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                // disable inBitmap-- bitmap reuse doesn't work with different decode regions due
17193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                // to orientation
17293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (mInBitmap != null) {
17393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    mCache.offer(mInBitmap);
17493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    mInBitmap = null;
17593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    mOpts.inBitmap = null;
17693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
17793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
17893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
17993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (isCancelled()) {
18093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                return null;
18193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
18293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
18393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (fd == null) {
18493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                in = reset(in);
18593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (in == null) {
18693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    return null;
18793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
18893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
18993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
19093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            Trace.beginSection("decodeBounds");
19193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mOpts.inJustDecodeBounds = true;
19293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (fd != null) {
19393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor(), null, mOpts);
19493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            } else {
19593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                BitmapFactory.decodeStream(in, null, mOpts);
19693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
19793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            Trace.endSection();
19893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
19993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (isCancelled()) {
20093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                return null;
20193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
20293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
20393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            // We want to calculate the sample size "as if" the orientation has been corrected.
20493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            final int srcW, srcH; // Orientation corrected.
20593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (isNotRotatedOr180) {
20693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                srcW = mOpts.outWidth;
20793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                srcH = mOpts.outHeight;
20893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            } else {
20993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                srcW = mOpts.outHeight;
21093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                srcH = mOpts.outWidth;
21193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
21293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mOpts.inSampleSize = calculateSampleSize(srcW, srcH, mDestW, mDestH);
21393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mOpts.inJustDecodeBounds = false;
21493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mOpts.inMutable = true;
21593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (isJellyBeanOrAbove && orientation == 0) {
21693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (mInBitmap == null) {
21793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    if (DEBUG) {
21893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        Log.e(TAG, "decode thread wants a bitmap. cache dump:\n"
21993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                                + mCache.toDebugString());
22093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    }
22193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    Trace.beginSection("create reusable bitmap");
22293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    mInBitmap = new ReusableBitmap(Bitmap.createBitmap(mDestW, mDestH,
22393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                            Bitmap.Config.ARGB_8888));
22493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    Trace.endSection();
22593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
22693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    if (isCancelled()) {
22793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        return null;
22893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    }
22993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
23093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    if (DEBUG) {
23193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        Log.e(TAG, "*** allocated new bitmap in decode thread: "
23293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                                + mInBitmap + " key=" + mKey);
23393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    }
23493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                } else {
23593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    if (DEBUG) {
23693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        Log.e(TAG, "*** reusing existing bitmap in decode thread: "
23793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                                + mInBitmap + " key=" + mKey);
23893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    }
23993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
24093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
24193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                mOpts.inBitmap = mInBitmap.bmp;
24293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
24393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
24493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (isCancelled()) {
24593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                return null;
24693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
24793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
24893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (fd == null) {
24993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                in = reset(in);
25093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (in == null) {
25193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    return null;
25293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
25393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
25493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
25593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            Bitmap decodeResult = null;
25693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            final Rect srcRect = new Rect(); // Not orientation corrected. True coordinates.
25793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (CROP_DURING_DECODE) {
25893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                try {
25993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    Trace.beginSection("decodeCropped" + mOpts.inSampleSize);
26093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    decodeResult = decodeCropped(fd, in, orientation, srcRect);
26193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                } catch (IOException e) {
26293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    // fall through to below and try again with the non-cropping decoder
26393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    e.printStackTrace();
26493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                } finally {
26593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    Trace.endSection();
26693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
26793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
26893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (isCancelled()) {
26993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    return null;
27093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
27193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
27293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
27393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            //noinspection PointlessBooleanExpression
27493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (!CROP_DURING_DECODE || (decodeResult == null && !isCancelled())) {
27593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                try {
27693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    Trace.beginSection("decode" + mOpts.inSampleSize);
27793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    // disable inBitmap-- bitmap reuse doesn't work well below K
27893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    if (mInBitmap != null) {
27993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        mCache.offer(mInBitmap);
28093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        mInBitmap = null;
28193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        mOpts.inBitmap = null;
28293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    }
28393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    decodeResult = decode(fd, in);
28493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                } catch (IllegalArgumentException e) {
28593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    Log.e(TAG, "decode failed: reason='" + e.getMessage() + "' ss="
28693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                            + mOpts.inSampleSize);
28793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
28893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    if (mOpts.inSampleSize > 1) {
28993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        // try again with ss=1
29093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        mOpts.inSampleSize = 1;
29193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        decodeResult = decode(fd, in);
29293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    }
29393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                } finally {
29493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    Trace.endSection();
29593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
29693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
29793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (isCancelled()) {
29893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    return null;
29993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
30093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
30193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
30293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (decodeResult == null) {
30393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                return null;
30493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
30593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
30693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (mInBitmap != null) {
30793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                result = mInBitmap;
30893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                // srcRect is non-empty when using the cropping BitmapRegionDecoder codepath
30993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (!srcRect.isEmpty()) {
31093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    result.setLogicalWidth((srcRect.right - srcRect.left) / mOpts.inSampleSize);
31193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    result.setLogicalHeight(
31293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                            (srcRect.bottom - srcRect.top) / mOpts.inSampleSize);
31393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                } else {
31493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    result.setLogicalWidth(mOpts.outWidth);
31593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    result.setLogicalHeight(mOpts.outHeight);
31693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
31793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            } else {
31893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                // no mInBitmap means no pooling
31993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                result = new ReusableBitmap(decodeResult, false /* reusable */);
32093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (isNotRotatedOr180) {
32193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    result.setLogicalWidth(decodeResult.getWidth());
32293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    result.setLogicalHeight(decodeResult.getHeight());
32393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                } else {
32493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    result.setLogicalWidth(decodeResult.getHeight());
32593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    result.setLogicalHeight(decodeResult.getWidth());
32693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
32793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
32893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            result.setOrientation(orientation);
32993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        } catch (Exception e) {
33093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            e.printStackTrace();
33193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        } finally {
33293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (fd != null) {
33393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                try {
33493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    fd.close();
33593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                } catch (IOException ignored) {
33693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
33793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
33893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (in != null) {
33993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                try {
34093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    in.close();
34193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                } catch (IOException ignored) {
34293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
34393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
34493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (result != null) {
34593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                result.acquireReference();
34693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                mCache.put(mKey, result);
34793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (DEBUG) {
34893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    Log.d(TAG, "placed result in cache: key=" + mKey + " bmp="
34993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        + result + " cancelled=" + isCancelled());
35093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
35193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            } else if (mInBitmap != null) {
35293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (DEBUG) {
35393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    Log.d(TAG, "placing failed/cancelled bitmap in pool: key="
35493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        + mKey + " bmp=" + mInBitmap);
35593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
35693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                mCache.offer(mInBitmap);
35793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
35893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
35993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return result;
36093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
36193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
36293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private Bitmap decodeCropped(final AssetFileDescriptor fd, final InputStream in,
36393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            final int orientation, final Rect outSrcRect) throws IOException {
36493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        final BitmapRegionDecoder brd;
36593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (fd != null) {
36693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            brd = BitmapRegionDecoder.newInstance(fd.getFileDescriptor(), true /* shareable */);
36793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        } else {
36893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            brd = BitmapRegionDecoder.newInstance(in, true /* shareable */);
36993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
37093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (isCancelled()) {
37193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            brd.recycle();
37293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            return null;
37393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
37493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
37593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        // We want to call calculateCroppedSrcRect() on the source rectangle "as if" the
37693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        // orientation has been corrected.
37793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        final int srcW, srcH; //Orientation corrected.
37893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        final boolean isNotRotatedOr180 = orientation == 0 || orientation == 180;
37993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (isNotRotatedOr180) {
38093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            srcW = mOpts.outWidth;
38193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            srcH = mOpts.outHeight;
38293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        } else {
38393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            srcW = mOpts.outHeight;
38493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            srcH = mOpts.outWidth;
38593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
38693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
38793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        // Coordinates are orientation corrected.
38893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        // Center the decode on the top 1/3.
38993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        BitmapUtils.calculateCroppedSrcRect(srcW, srcH, mDestW, mDestH, mDestH, mOpts.inSampleSize,
39093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                1f / 3, true /* absoluteFraction */, 1f, outSrcRect);
39193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (DEBUG) System.out.println("rect for this decode is: " + outSrcRect
39293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                + " srcW/H=" + srcW + "/" + srcH
39393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                + " dstW/H=" + mDestW + "/" + mDestH);
39493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
39593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        // calculateCroppedSrcRect() gave us the source rectangle "as if" the orientation has
39693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        // been corrected. We need to decode the uncorrected source rectangle. Calculate true
39793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        // coordinates.
39893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        RectUtils.rotateRectForOrientation(orientation, new Rect(0, 0, srcW, srcH), outSrcRect);
39993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
40093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        final Bitmap result = brd.decodeRegion(outSrcRect, mOpts);
40193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        brd.recycle();
40293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return result;
40393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
40493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
40593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    /**
40693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * Return an input stream that can be read from the beginning using the most efficient way,
40793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * given an input stream that may or may not support reset(), or given null.
40893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     *
40993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * The returned input stream may or may not be the same stream.
41093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     */
41193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private InputStream reset(InputStream in) throws IOException {
41293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        Trace.beginSection("create stream");
41393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (in == null) {
41493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            in = mKey.createInputStream();
41593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        } else if (in.markSupported()) {
41693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            in.reset();
41793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        } else {
41893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            try {
41993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                in.close();
42093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            } catch (IOException ignored) {
42193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
42293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            in = mKey.createInputStream();
42393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
42493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        Trace.endSection();
42593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return in;
42693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
42793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
42893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private Bitmap decode(AssetFileDescriptor fd, InputStream in) {
42993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        final Bitmap result;
43093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (fd != null) {
43193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            result = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor(), null, mOpts);
43293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        } else {
43393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            result = BitmapFactory.decodeStream(in, null, mOpts);
43493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
43593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return result;
43693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
43793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
43893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private static int calculateSampleSize(int srcW, int srcH, int destW, int destH) {
43993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        int result;
44093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
44193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        final float sz = Math.min((float) srcW / destW, (float) srcH / destH);
44293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
44393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        // round to the nearest power of two, or just truncate
44493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        final boolean stricter = true;
44593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
44693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        //noinspection ConstantConditions
44793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (stricter) {
44893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            result = (int) Math.pow(2, (int) (0.5 + (Math.log(sz) / Math.log(2))));
44993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        } else {
45093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            result = (int) sz;
45193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
45293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return Math.max(1, result);
45393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
45493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
45593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void cancel() {
45693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        cancel(true);
45793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mOpts.requestCancelDecode();
45893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
45993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
46093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
46193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    protected void onProgressUpdate(Void... values) {
46293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mDecodeCallback.onDecodeBegin(mKey);
46393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
46493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
46593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
46693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void onPostExecute(ReusableBitmap result) {
46793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mDecodeCallback.onDecodeComplete(mKey, result);
46893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
46993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
47093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
47193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    protected void onCancelled(ReusableBitmap result) {
47293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mDecodeCallback.onDecodeCancel(mKey);
47393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (result == null) {
47493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            return;
47593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
47693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
47793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        result.releaseReference();
47893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (mInBitmap == null) {
47993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            // not reusing bitmaps: can recycle immediately
48093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            result.bmp.recycle();
48193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
48293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
48393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
48493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein}
485