ThumbnailManager.java revision 7b6fe946f2e1020432e3600c8863f72449cd4e68
107ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor/* 207ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor * Copyright (C) 2012 The Android Open Source Project 307ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor * 407ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor * Licensed under the Apache License, Version 2.0 (the "License"); 507ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor * you may not use this file except in compliance with the License. 607ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor * You may obtain a copy of the License at 707ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor * 807ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor * http://www.apache.org/licenses/LICENSE-2.0 907ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor * 1007ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor * Unless required by applicable law or agreed to in writing, software 1107ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor * distributed under the License is distributed on an "AS IS" BASIS, 1207ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1307ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor * See the License for the specific language governing permissions and 1407ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor * limitations under the License. 1507ddb5c577a10e5aa3b4442426a055f3b95d5202Tom Taylor */ 1651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 1751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorpackage com.android.mms.util; 1851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 19721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylorimport java.io.ByteArrayOutputStream; 20721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylorimport java.io.Closeable; 21721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylorimport java.io.FileNotFoundException; 22721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylorimport java.io.InputStream; 2351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorimport java.util.Set; 2451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 2551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorimport android.content.Context; 2651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorimport android.graphics.Bitmap; 2751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorimport android.graphics.BitmapFactory; 28721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylorimport android.graphics.Canvas; 29721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylorimport android.graphics.Paint; 30721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylorimport android.graphics.Bitmap.Config; 31721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylorimport android.graphics.BitmapFactory.Options; 3279bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylorimport android.media.MediaMetadataRetriever; 3351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorimport android.net.Uri; 3451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorimport android.util.Log; 3551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 3651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorimport com.android.mms.LogTag; 37721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylorimport com.android.mms.R; 38b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylorimport com.android.mms.TempFileProvider; 397b6fe946f2e1020432e3600c8863f72449cd4e68Tom Taylorimport com.android.mms.ui.MessageItem; 4051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorimport com.android.mms.ui.UriImage; 41721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylorimport com.android.mms.util.ImageCacheService.ImageData; 4251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 4351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor/** 4451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * Primary {@link ThumbnailManager} implementation used by {@link MessagingApplication}. 4551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * <p> 4651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * Public methods should only be used from a single thread (typically the UI 4751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * thread). Callbacks will be invoked on the thread where the ThumbnailManager 4851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * was instantiated. 4951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * <p> 5051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * Uses a thread-pool ExecutorService instead of AsyncTasks since clients may 5151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * request lots of pdus around the same time, and AsyncTask may reject tasks 5251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * in that case and has no way of bounding the number of threads used by those 5351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * tasks. 5451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * <p> 5551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * ThumbnailManager is used to asynchronously load pictures and create thumbnails. The thumbnails 5651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * are stored in a local cache with SoftReferences. Once a thumbnail is loaded, it will call the 5751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * passed in callback with the result. If a thumbnail is immediately available in the cache, 5851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * the callback will be called immediately as well. 5951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * 6051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * Based on BooksImageManager by Virgil King. 6151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor */ 6251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorpublic class ThumbnailManager extends BackgroundLoaderManager { 6351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor private static final String TAG = "ThumbnailManager"; 6451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 65721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private static final boolean DEBUG_DISABLE_CACHE = false; 66721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private static final boolean DEBUG_DISABLE_CALLBACK = false; 6751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor private static final boolean DEBUG_DISABLE_LOAD = false; 6851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor private static final boolean DEBUG_LONG_WAIT = false; 6951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 70721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private static final int COMPRESS_JPEG_QUALITY = 90; 7151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 7251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor private final SimpleCache<Uri, Bitmap> mThumbnailCache; 7351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor private final Context mContext; 74721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private ImageCacheService mImageCacheService; 75721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private static Bitmap mEmptyImageBitmap; 76721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private static Bitmap mEmptyVideoBitmap; 77721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 78721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // NOTE: These type numbers are stored in the image cache, so it should not 79721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // not be changed without resetting the cache. 80721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor public static final int TYPE_THUMBNAIL = 1; 81721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor public static final int TYPE_MICROTHUMBNAIL = 2; 82721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 83721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor public static final int THUMBNAIL_TARGET_SIZE = 640; 8451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 8551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public ThumbnailManager(final Context context) { 8651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor super(context); 8751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 88721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor mThumbnailCache = new SimpleCache<Uri, Bitmap>(8, 16, 0.75f, true); 8951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mContext = context; 90721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 91721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor mEmptyImageBitmap = BitmapFactory.decodeResource(context.getResources(), 92721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor R.drawable.ic_missing_thumbnail_picture); 93721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 94721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor mEmptyVideoBitmap = BitmapFactory.decodeResource(context.getResources(), 95721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor R.drawable.ic_missing_thumbnail_video); 9651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 9751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 9851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor /** 9951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * getThumbnail must be called on the same thread that created ThumbnailManager. This is 10051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * normally the UI thread. 10151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * @param uri the uri of the image 10251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * @param width the original full width of the image 10351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * @param height the original full height of the image 10451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * @param callback the callback to call when the thumbnail is fully loaded 10551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * @return 10651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor */ 107721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor public ItemLoadedFuture getThumbnail(Uri uri, 10879bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor final ItemLoadedCallback<ImageLoaded> callback) { 109721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return getThumbnail(uri, false, callback); 11079bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor } 11179bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor 11279bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor /** 11379bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor * getVideoThumbnail must be called on the same thread that created ThumbnailManager. This is 11479bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor * normally the UI thread. 11579bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor * @param uri the uri of the image 11679bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor * @param callback the callback to call when the thumbnail is fully loaded 11779bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor * @return 11879bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor */ 11979bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor public ItemLoadedFuture getVideoThumbnail(Uri uri, 12079bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor final ItemLoadedCallback<ImageLoaded> callback) { 121721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return getThumbnail(uri, true, callback); 12279bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor } 12379bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor 124721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private ItemLoadedFuture getThumbnail(Uri uri, boolean isVideo, 12579bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor final ItemLoadedCallback<ImageLoaded> callback) { 12651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (uri == null) { 12751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor throw new NullPointerException(); 12851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 12951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 130721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor final Bitmap thumbnail = DEBUG_DISABLE_CACHE ? null : mThumbnailCache.get(uri); 13151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 13251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor final boolean thumbnailExists = (thumbnail != null); 13351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor final boolean taskExists = mPendingTaskUris.contains(uri); 13451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor final boolean newTaskRequired = !thumbnailExists && !taskExists; 13551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor final boolean callbackRequired = (callback != null); 13651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 13751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (Log.isLoggable(LogTag.THUMBNAIL_CACHE, Log.DEBUG)) { 13851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Log.v(TAG, "getThumbnail mThumbnailCache.get for uri: " + uri + " thumbnail: " + 13951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor thumbnail + " callback: " + callback + " thumbnailExists: " + 14051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor thumbnailExists + " taskExists: " + taskExists + 14151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor " newTaskRequired: " + newTaskRequired + 14251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor " callbackRequired: " + callbackRequired); 14351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 14451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 14551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (thumbnailExists) { 146721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (callbackRequired && !DEBUG_DISABLE_CALLBACK) { 14779bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor ImageLoaded imageLoaded = new ImageLoaded(thumbnail, isVideo); 14879bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor callback.onItemLoaded(imageLoaded, null); 14951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 15051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor return new NullItemLoadedFuture(); 15151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 15251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 15351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (callbackRequired) { 15451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor addCallback(uri, callback); 15551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 15651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 15751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (newTaskRequired) { 15851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mPendingTaskUris.add(uri); 159721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Runnable task = new ThumbnailTask(uri, isVideo); 16051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mExecutor.execute(task); 16151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 16251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor return new ItemLoadedFuture() { 163ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev @Override 16451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public void cancel() { 16551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor cancelCallback(callback); 16651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 167ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev @Override 16851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public boolean isDone() { 16951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor return false; 17051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 17151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor }; 17251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 17351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 17451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor @Override 1757b6fe946f2e1020432e3600c8863f72449cd4e68Tom Taylor public synchronized void clear() { 17651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor super.clear(); 17751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 1787b6fe946f2e1020432e3600c8863f72449cd4e68Tom Taylor mThumbnailCache.clear(); // clear in-memory cache 1797b6fe946f2e1020432e3600c8863f72449cd4e68Tom Taylor clearBackingStore(); // clear on-disk cache 1807b6fe946f2e1020432e3600c8863f72449cd4e68Tom Taylor } 1817b6fe946f2e1020432e3600c8863f72449cd4e68Tom Taylor 1827b6fe946f2e1020432e3600c8863f72449cd4e68Tom Taylor // Delete the on-disk cache, but leave the in-memory cache intact 1837b6fe946f2e1020432e3600c8863f72449cd4e68Tom Taylor public synchronized void clearBackingStore() { 1847b6fe946f2e1020432e3600c8863f72449cd4e68Tom Taylor getImageCacheService().clear(); 1857b6fe946f2e1020432e3600c8863f72449cd4e68Tom Taylor mImageCacheService = null; // force a re-init the next time getImageCacheService requested 18651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 18751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 188b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor public void removeThumbnail(Uri uri) { 189b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor mThumbnailCache.remove(uri); 190b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor } 191b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor 192ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev @Override 19351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public String getTag() { 19451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor return TAG; 19551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 19651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 197721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private synchronized ImageCacheService getImageCacheService() { 198721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (mImageCacheService == null) { 199721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor mImageCacheService = new ImageCacheService(mContext); 200721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 201721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return mImageCacheService; 202721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 203721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 20451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public class ThumbnailTask implements Runnable { 20551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor private final Uri mUri; 20679bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor private final boolean mIsVideo; 20751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 208721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor public ThumbnailTask(Uri uri, boolean isVideo) { 20951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (uri == null) { 21051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor throw new NullPointerException(); 21151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 21251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mUri = uri; 21379bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor mIsVideo = isVideo; 21451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 21551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 21651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor /** {@inheritDoc} */ 217ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev @Override 21851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public void run() { 21951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (DEBUG_DISABLE_LOAD) { 22051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor return; 22151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 22251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (DEBUG_LONG_WAIT) { 22351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor try { 22451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Thread.sleep(10000); 22551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } catch (InterruptedException e) { 22651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 22751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 22851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 2295d403c7cb873004bbc203536e818075a7223c0a5Tom Taylor Bitmap bitmap = null; 2305d403c7cb873004bbc203536e818075a7223c0a5Tom Taylor try { 2315d403c7cb873004bbc203536e818075a7223c0a5Tom Taylor bitmap = getBitmap(mIsVideo); 2325d403c7cb873004bbc203536e818075a7223c0a5Tom Taylor } catch (IllegalArgumentException e) { 2335d403c7cb873004bbc203536e818075a7223c0a5Tom Taylor Log.e(TAG, "Couldn't load bitmap for " + mUri, e); 2345d403c7cb873004bbc203536e818075a7223c0a5Tom Taylor } 2355d403c7cb873004bbc203536e818075a7223c0a5Tom Taylor final Bitmap resultBitmap = bitmap; 236721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 23751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mCallbackHandler.post(new Runnable() { 238ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev @Override 23951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public void run() { 24051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor final Set<ItemLoadedCallback> callbacks = mCallbacks.get(mUri); 24151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (callbacks != null) { 242721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap bitmap = resultBitmap == null ? 243721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor (mIsVideo ? mEmptyVideoBitmap : mEmptyImageBitmap) 244721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor : resultBitmap; 245721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 24651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor // Make a copy so that the callback can unregister itself 24779bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor for (final ItemLoadedCallback<ImageLoaded> callback : asList(callbacks)) { 248721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (Log.isLoggable(LogTag.THUMBNAIL_CACHE, Log.DEBUG)) { 24951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Log.d(TAG, "Invoking item loaded callback " + callback); 25051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 251721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (!DEBUG_DISABLE_CALLBACK) { 252721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor ImageLoaded imageLoaded = new ImageLoaded(bitmap, mIsVideo); 253721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor callback.onItemLoaded(imageLoaded, null); 254721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 25551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 25651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } else { 25751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (Log.isLoggable(TAG, Log.DEBUG)) { 25851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Log.d(TAG, "No image callback!"); 25951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 26051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 26151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 262721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // Add the bitmap to the soft cache if the load succeeded. Don't cache the 263721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // stand-ins for empty bitmaps. 26451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (resultBitmap != null) { 26551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mThumbnailCache.put(mUri, resultBitmap); 266721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (Log.isLoggable(LogTag.THUMBNAIL_CACHE, Log.DEBUG)) { 26751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Log.v(TAG, "in callback runnable: bitmap uri: " + mUri + 26851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor " width: " + resultBitmap.getWidth() + " height: " + 26951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor resultBitmap.getHeight() + " size: " + 27051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor resultBitmap.getByteCount()); 27151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 27251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 27351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 27451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mCallbacks.remove(mUri); 27551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mPendingTaskUris.remove(mUri); 27651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 27751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (Log.isLoggable(LogTag.THUMBNAIL_CACHE, Log.DEBUG)) { 27851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Log.d(TAG, "Image task for " + mUri + "exiting " + mPendingTaskUris.size() 27951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor + " remain"); 28051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 28151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 28251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor }); 28351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 284721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 285721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap getBitmap(boolean isVideo) { 286721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor ImageCacheService cacheService = getImageCacheService(); 287721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 288721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor UriImage uriImage = new UriImage(mContext, mUri); 289721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor String path = uriImage.getPath(); 290b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor 291b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor // We never want to store thumbnails of temp files in the thumbnail cache on disk 292b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor // because those temp filenames are recycled (and reused when capturing images 293b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor // or videos). 294b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor boolean isTempFile = TempFileProvider.isTempFile(path); 295b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor 296b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor ImageData data = null; 297b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor if (!isTempFile) { 298b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor data = cacheService.getImageData(path, TYPE_THUMBNAIL); 299b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor } 300721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 301721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (data != null) { 302721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor BitmapFactory.Options options = new BitmapFactory.Options(); 303721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor options.inPreferredConfig = Bitmap.Config.ARGB_8888; 304721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap bitmap = requestDecode(data.mData, 305721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor data.mOffset, data.mData.length - data.mOffset, options); 306721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (bitmap == null) { 307721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Log.w(TAG, "decode cached failed " + path); 308721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 309721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return bitmap; 310721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } else { 311721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap bitmap; 312721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (isVideo) { 313721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor bitmap = getVideoBitmap(); 314721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } else { 315721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor bitmap = onDecodeOriginal(mUri, TYPE_THUMBNAIL); 316721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 317721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (bitmap == null) { 318721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Log.w(TAG, "decode orig failed " + path); 319721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return null; 320721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 321721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 322721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor bitmap = resizeDownBySideLength(bitmap, THUMBNAIL_TARGET_SIZE, true); 323721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 324b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor if (!isTempFile) { 325b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor byte[] array = compressBitmap(bitmap); 326b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor cacheService.putImageData(path, TYPE_THUMBNAIL, array); 327b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor } 328721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return bitmap; 329721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 330721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 331721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 332721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap getVideoBitmap() { 333721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 334721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor try { 335721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor retriever.setDataSource(mContext, mUri); 336721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return retriever.getFrameAtTime(-1); 337721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } catch (RuntimeException ex) { 338721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // Assume this is a corrupt video file. 339721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } finally { 340721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor try { 341721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor retriever.release(); 342721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } catch (RuntimeException ex) { 343721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // Ignore failures while cleaning up. 344721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 345721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 346721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return null; 347721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 348721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 349721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private byte[] compressBitmap(Bitmap bitmap) { 350721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor ByteArrayOutputStream os = new ByteArrayOutputStream(); 351721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor bitmap.compress(Bitmap.CompressFormat.JPEG, 352721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor COMPRESS_JPEG_QUALITY, os); 353721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return os.toByteArray(); 354721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 355721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 356721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap requestDecode(byte[] bytes, int offset, 357721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int length, Options options) { 358721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (options == null) { 359721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor options = new Options(); 360721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 361721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return ensureGLCompatibleBitmap( 362721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor BitmapFactory.decodeByteArray(bytes, offset, length, options)); 363721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 364721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 365721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap resizeDownBySideLength( 366721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap bitmap, int maxLength, boolean recycle) { 367721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int srcWidth = bitmap.getWidth(); 368721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int srcHeight = bitmap.getHeight(); 369721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor float scale = Math.min( 370721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor (float) maxLength / srcWidth, (float) maxLength / srcHeight); 371721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (scale >= 1.0f) return bitmap; 372721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return resizeBitmapByScale(bitmap, scale, recycle); 373721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 374721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 375721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap resizeBitmapByScale( 376721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap bitmap, float scale, boolean recycle) { 377721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int width = Math.round(bitmap.getWidth() * scale); 378721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int height = Math.round(bitmap.getHeight() * scale); 379721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (width == bitmap.getWidth() 380721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor && height == bitmap.getHeight()) return bitmap; 381721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap)); 382721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Canvas canvas = new Canvas(target); 383721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor canvas.scale(scale, scale); 384721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); 385721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor canvas.drawBitmap(bitmap, 0, 0, paint); 386721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (recycle) bitmap.recycle(); 387721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return target; 388721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 389721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 390721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap.Config getConfig(Bitmap bitmap) { 391721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap.Config config = bitmap.getConfig(); 392721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (config == null) { 393721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor config = Bitmap.Config.ARGB_8888; 394721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 395721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return config; 396721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 397721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 398721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // TODO: This function should not be called directly from 399721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // DecodeUtils.requestDecode(...), since we don't have the knowledge 400721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // if the bitmap will be uploaded to GL. 401721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap ensureGLCompatibleBitmap(Bitmap bitmap) { 402721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (bitmap == null || bitmap.getConfig() != null) return bitmap; 403721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap newBitmap = bitmap.copy(Config.ARGB_8888, false); 404721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor bitmap.recycle(); 405721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return newBitmap; 406721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 407721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 408721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap onDecodeOriginal(Uri uri, int type) { 409721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor BitmapFactory.Options options = new BitmapFactory.Options(); 410721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor options.inPreferredConfig = Bitmap.Config.ARGB_8888; 411721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 412721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return requestDecode(uri, options, THUMBNAIL_TARGET_SIZE); 413721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 414721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 415721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private void closeSilently(Closeable c) { 416721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (c == null) return; 417721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor try { 418721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor c.close(); 419721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } catch (Throwable t) { 420721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Log.w(TAG, "close fail", t); 421721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 422721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 423721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 424721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap requestDecode(final Uri uri, Options options, int targetSize) { 425721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (options == null) options = new Options(); 426721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 427721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor InputStream inputStream; 428721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor try { 429721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor inputStream = mContext.getContentResolver().openInputStream(uri); 430721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } catch (FileNotFoundException e) { 431721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Log.e(TAG, "Can't open uri: " + uri, e); 432721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return null; 433721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 434721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 435721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor options.inJustDecodeBounds = true; 436721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor BitmapFactory.decodeStream(inputStream, null, options); 437721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor closeSilently(inputStream); 438721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 439721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // No way to reset the stream. Have to open it again :-( 440721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor try { 441721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor inputStream = mContext.getContentResolver().openInputStream(uri); 442721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } catch (FileNotFoundException e) { 443721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Log.e(TAG, "Can't open uri: " + uri, e); 444721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return null; 445721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 446721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 447721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor options.inSampleSize = computeSampleSizeLarger( 448721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor options.outWidth, options.outHeight, targetSize); 449721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor options.inJustDecodeBounds = false; 450721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 451721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap result = BitmapFactory.decodeStream(inputStream, null, options); 452721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor closeSilently(inputStream); 453721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 4545d403c7cb873004bbc203536e818075a7223c0a5Tom Taylor if (result == null) { 4555d403c7cb873004bbc203536e818075a7223c0a5Tom Taylor return null; 4565d403c7cb873004bbc203536e818075a7223c0a5Tom Taylor } 4575d403c7cb873004bbc203536e818075a7223c0a5Tom Taylor 458721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // We need to resize down if the decoder does not support inSampleSize. 459721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // (For example, GIF images.) 460721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor result = resizeDownIfTooBig(result, targetSize, true); 461721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return ensureGLCompatibleBitmap(result); 462721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 463721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 464721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // This computes a sample size which makes the longer side at least 465721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // minSideLength long. If that's not possible, return 1. 466721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private int computeSampleSizeLarger(int w, int h, 467721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int minSideLength) { 468721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int initialSize = Math.max(w / minSideLength, h / minSideLength); 469721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (initialSize <= 1) return 1; 470721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 471721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return initialSize <= 8 472721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor ? prevPowerOf2(initialSize) 473721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor : initialSize / 8 * 8; 474721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 475721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 476721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // Returns the previous power of two. 477721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // Returns the input if it is already power of 2. 478721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // Throws IllegalArgumentException if the input is <= 0 479721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private int prevPowerOf2(int n) { 480721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (n <= 0) throw new IllegalArgumentException(); 481721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return Integer.highestOneBit(n); 482721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 483721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 484721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // Resize the bitmap if each side is >= targetSize * 2 485721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap resizeDownIfTooBig( 486721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap bitmap, int targetSize, boolean recycle) { 487721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int srcWidth = bitmap.getWidth(); 488721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int srcHeight = bitmap.getHeight(); 489721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor float scale = Math.max( 490721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor (float) targetSize / srcWidth, (float) targetSize / srcHeight); 491721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (scale > 0.5f) return bitmap; 492721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return resizeBitmapByScale(bitmap, scale, recycle); 493721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 494721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 49551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 49679bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor 49779bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor public static class ImageLoaded { 49879bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor public final Bitmap mBitmap; 49979bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor public final boolean mIsVideo; 50079bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor 50179bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor public ImageLoaded(Bitmap bitmap, boolean isVideo) { 50279bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor mBitmap = bitmap; 50379bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor mIsVideo = isVideo; 50479bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor } 50579bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor } 50651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor} 507