171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck/*
271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * Copyright (C) 2013 The Android Open Source Project
371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck *
471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * Licensed under the Apache License, Version 2.0 (the "License");
571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * you may not use this file except in compliance with the License.
671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * You may obtain a copy of the License at
771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck *
871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck *      http://www.apache.org/licenses/LICENSE-2.0
971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck *
1071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * Unless required by applicable law or agreed to in writing, software
1171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * distributed under the License is distributed on an "AS IS" BASIS,
1271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * See the License for the specific language governing permissions and
1471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * limitations under the License.
1571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck */
1671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
1771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckpackage com.android.photos.drawables;
1871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
1971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.graphics.Bitmap;
2071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.graphics.BitmapFactory;
2171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.graphics.Canvas;
2271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.graphics.ColorFilter;
2371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.graphics.Matrix;
2471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.graphics.Paint;
2571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.graphics.PixelFormat;
2671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.graphics.Rect;
2771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.graphics.drawable.Drawable;
2871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.util.Log;
2971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
30b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescuimport com.android.photos.data.GalleryBitmapPool;
31b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu
32b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescuimport java.io.InputStream;
3371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport java.util.concurrent.ExecutorService;
3471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport java.util.concurrent.Executors;
3571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
36b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescupublic abstract class AutoThumbnailDrawable<T> extends Drawable {
3771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
38b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu    private static final String TAG = "AutoThumbnailDrawable";
3971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
4071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private static ExecutorService sThreadPool = Executors.newSingleThreadExecutor();
41b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu    private static GalleryBitmapPool sBitmapPool = GalleryBitmapPool.getInstance();
4271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private static byte[] sTempStorage = new byte[64 * 1024];
4371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
44d26f1ad5a859da0847ab181df2eebd45e155118bJohn Reck    // UI thread only
4571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private Paint mPaint = new Paint();
46d26f1ad5a859da0847ab181df2eebd45e155118bJohn Reck    private Matrix mDrawMatrix = new Matrix();
47d26f1ad5a859da0847ab181df2eebd45e155118bJohn Reck
48d26f1ad5a859da0847ab181df2eebd45e155118bJohn Reck    // Decoder thread only
49d26f1ad5a859da0847ab181df2eebd45e155118bJohn Reck    private BitmapFactory.Options mOptions = new BitmapFactory.Options();
50d26f1ad5a859da0847ab181df2eebd45e155118bJohn Reck
51d26f1ad5a859da0847ab181df2eebd45e155118bJohn Reck    // Shared, guarded by mLock
52d26f1ad5a859da0847ab181df2eebd45e155118bJohn Reck    private Object mLock = new Object();
53d26f1ad5a859da0847ab181df2eebd45e155118bJohn Reck    private Bitmap mBitmap;
54b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu    protected T mData;
5571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private boolean mIsQueued;
5671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int mImageWidth, mImageHeight;
5771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private Rect mBounds = new Rect();
58b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu    private int mSampleSize = 1;
5971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
6071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public AutoThumbnailDrawable() {
6171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mPaint.setAntiAlias(true);
6271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mPaint.setFilterBitmap(true);
6371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mDrawMatrix.reset();
6471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mOptions.inTempStorage = sTempStorage;
6571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
6671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
67b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu    protected abstract byte[] getPreferredImageBytes(T data);
68b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu    protected abstract InputStream getFallbackImageStream(T data);
69b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu    protected abstract boolean dataChangedLocked(T data);
70b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu
71b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu    public void setImage(T data, int width, int height) {
72b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu        if (!dataChangedLocked(data)) return;
73d26f1ad5a859da0847ab181df2eebd45e155118bJohn Reck        synchronized (mLock) {
7471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mImageWidth = width;
7571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mImageHeight = height;
76b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            mData = data;
77b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            setBitmapLocked(null);
7871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            refreshSampleSizeLocked();
7971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
8071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        invalidateSelf();
8171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
8271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
83b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu    private void setBitmapLocked(Bitmap b) {
84b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu        if (b == mBitmap) {
85b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            return;
86b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu        }
87b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu        if (mBitmap != null) {
88b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            sBitmapPool.put(mBitmap);
89b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu        }
90b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu        mBitmap = b;
91b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu    }
92b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu
9371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
9471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    protected void onBoundsChange(Rect bounds) {
9571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        super.onBoundsChange(bounds);
96d26f1ad5a859da0847ab181df2eebd45e155118bJohn Reck        synchronized (mLock) {
9771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mBounds.set(bounds);
9871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (mBounds.isEmpty()) {
9971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mBitmap = null;
10071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            } else {
10171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                refreshSampleSizeLocked();
10271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                updateDrawMatrixLocked();
10371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
10471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
10571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        invalidateSelf();
10671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
10771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
10871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
10971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public void draw(Canvas canvas) {
11071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (mBitmap != null) {
11171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            canvas.save();
11271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            canvas.clipRect(mBounds);
11371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            canvas.concat(mDrawMatrix);
11471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            canvas.drawBitmap(mBitmap, 0, 0, mPaint);
11571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            canvas.restore();
11671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        } else {
11771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            // TODO: Draw placeholder...?
11871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
11971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
12071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
12171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private void updateDrawMatrixLocked() {
12271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (mBitmap == null || mBounds.isEmpty()) {
12371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mDrawMatrix.reset();
12471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            return;
12571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
12671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
12771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        float scale;
12871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        float dx = 0, dy = 0;
12971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
13071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int dwidth = mBitmap.getWidth();
13171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int dheight = mBitmap.getHeight();
13271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int vwidth = mBounds.width();
13371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int vheight = mBounds.height();
13471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
13571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        // Calculates a matrix similar to ScaleType.CENTER_CROP
13671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (dwidth * vheight > vwidth * dheight) {
13771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            scale = (float) vheight / (float) dheight;
13871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            dx = (vwidth - dwidth * scale) * 0.5f;
13971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        } else {
14071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            scale = (float) vwidth / (float) dwidth;
14171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            dy = (vheight - dheight * scale) * 0.5f;
14271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
14371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (scale < .8f) {
14471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            Log.w(TAG, "sample size was too small! Overdrawing! " + scale + ", " + mSampleSize);
14571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        } else if (scale > 1.5f) {
14671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            Log.w(TAG, "Potential quality loss! " + scale + ", " + mSampleSize);
14771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
14871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
14971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mDrawMatrix.setScale(scale, scale);
15071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
15171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
15271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
15371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int calculateSampleSizeLocked(int dwidth, int dheight) {
15471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        float scale;
15571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
15671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int vwidth = mBounds.width();
15771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int vheight = mBounds.height();
15871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
15971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        // Inverse of updateDrawMatrixLocked
16071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (dwidth * vheight > vwidth * dheight) {
16171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            scale = (float) dheight / (float) vheight;
16271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        } else {
16371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            scale = (float) dwidth / (float) vwidth;
16471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
165b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu        int result = Math.round(scale);
166b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu        return result > 0 ? result : 1;
16771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
16871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
16971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private void refreshSampleSizeLocked() {
170a73acc17eea200014edba9c9c6a40f1c632fa57dBobby Georgescu        if (mBounds.isEmpty() || mImageWidth == 0 || mImageHeight == 0) {
171a73acc17eea200014edba9c9c6a40f1c632fa57dBobby Georgescu            return;
172a73acc17eea200014edba9c9c6a40f1c632fa57dBobby Georgescu        }
17371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
17471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int sampleSize = calculateSampleSizeLocked(mImageWidth, mImageHeight);
17571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (sampleSize != mSampleSize || mBitmap == null) {
17671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mSampleSize = sampleSize;
17771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            loadBitmapLocked();
17871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
17971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
18071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
18171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private void loadBitmapLocked() {
18271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (!mIsQueued && !mBounds.isEmpty()) {
18371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            unscheduleSelf(mUpdateBitmap);
18471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            sThreadPool.execute(mLoadBitmap);
18571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mIsQueued = true;
18671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
18771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
18871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
18971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public float getAspectRatio() {
19071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return (float) mImageWidth / (float) mImageHeight;
19171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
19271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
19371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
19471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public int getIntrinsicWidth() {
19571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return -1;
19671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
19771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
19871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
19971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public int getIntrinsicHeight() {
20071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return -1;
20171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
20271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
20371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
20471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public int getOpacity() {
20571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        Bitmap bm = mBitmap;
20671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return (bm == null || bm.hasAlpha() || mPaint.getAlpha() < 255) ?
20771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
20871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
20971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
21071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
21171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public void setAlpha(int alpha) {
21271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int oldAlpha = mPaint.getAlpha();
21371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (alpha != oldAlpha) {
21471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mPaint.setAlpha(alpha);
21571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            invalidateSelf();
21671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
21771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
21871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
21971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
22071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public void setColorFilter(ColorFilter cf) {
22171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mPaint.setColorFilter(cf);
22271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        invalidateSelf();
22371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
22471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
22571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private final Runnable mLoadBitmap = new Runnable() {
22671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        @Override
22771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        public void run() {
228b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            T data;
229b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            synchronized (mLock) {
230b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                data = mData;
231b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            }
232b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            int preferredSampleSize = 1;
233b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            byte[] preferred = getPreferredImageBytes(data);
234b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            boolean hasPreferred = (preferred != null && preferred.length > 0);
235b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            if (hasPreferred) {
236b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                mOptions.inJustDecodeBounds = true;
237b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                BitmapFactory.decodeByteArray(preferred, 0, preferred.length, mOptions);
238b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                mOptions.inJustDecodeBounds = false;
239b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            }
240b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            int sampleSize, width, height;
241d26f1ad5a859da0847ab181df2eebd45e155118bJohn Reck            synchronized (mLock) {
242b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                if (dataChangedLocked(data)) {
243b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    return;
244b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                }
245b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                width = mImageWidth;
246b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                height = mImageHeight;
247b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                if (hasPreferred) {
248b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    preferredSampleSize = calculateSampleSizeLocked(
249b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                            mOptions.outWidth, mOptions.outHeight);
250b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                }
251b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                sampleSize = calculateSampleSizeLocked(width, height);
25271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mIsQueued = false;
25371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
254b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            Bitmap b = null;
255b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu            InputStream is = null;
25671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            try {
257b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                if (hasPreferred) {
258b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    mOptions.inSampleSize = preferredSampleSize;
259b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    mOptions.inBitmap = sBitmapPool.get(
260b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                            mOptions.outWidth / preferredSampleSize,
261b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                            mOptions.outHeight / preferredSampleSize);
262b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    b = BitmapFactory.decodeByteArray(preferred, 0, preferred.length, mOptions);
263b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    if (mOptions.inBitmap != null && b != mOptions.inBitmap) {
264b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                        sBitmapPool.put(mOptions.inBitmap);
265b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                        mOptions.inBitmap = null;
266b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    }
267b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                }
268b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                if (b == null) {
269b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    is = getFallbackImageStream(data);
270b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    mOptions.inSampleSize = sampleSize;
271b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    mOptions.inBitmap = sBitmapPool.get(width / sampleSize, height / sampleSize);
272b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    b = BitmapFactory.decodeStream(is, null, mOptions);
273b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    if (mOptions.inBitmap != null && b != mOptions.inBitmap) {
274b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                        sBitmapPool.put(mOptions.inBitmap);
275b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                        mOptions.inBitmap = null;
27671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    }
27771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                }
27871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            } catch (Exception e) {
279b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                Log.d(TAG, "Failed to fetch bitmap", e);
28071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                return;
28171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            } finally {
28271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                try {
283b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    if (is != null) {
284b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                        is.close();
285d26f1ad5a859da0847ab181df2eebd45e155118bJohn Reck                    }
28671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                } catch (Exception e) {}
287b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                if (b != null) {
288b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    synchronized (mLock) {
289b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                        if (!dataChangedLocked(data)) {
290b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                            setBitmapLocked(b);
291b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                            scheduleSelf(mUpdateBitmap, 0);
292b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                        }
293b4338b0fefea317bf18a3116c1bf231097535d35Bobby Georgescu                    }
29471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                }
29571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
29671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
29771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    };
29871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
29971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private final Runnable mUpdateBitmap = new Runnable() {
30071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        @Override
30171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        public void run() {
30271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            synchronized (AutoThumbnailDrawable.this) {
30371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                updateDrawMatrixLocked();
30471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                invalidateSelf();
30571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
30671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
30771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    };
30871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
30971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck}
310