ThumbnailManager.java revision ddd31c4011b4191035bdfbba05a8edb1785f71af
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; 3851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorimport com.android.mms.ui.UriImage; 39721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylorimport com.android.mms.util.ImageCacheService.ImageData; 4051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 4151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor/** 4251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * Primary {@link ThumbnailManager} implementation used by {@link MessagingApplication}. 4351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * <p> 4451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * Public methods should only be used from a single thread (typically the UI 4551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * thread). Callbacks will be invoked on the thread where the ThumbnailManager 4651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * was instantiated. 4751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * <p> 4851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * Uses a thread-pool ExecutorService instead of AsyncTasks since clients may 4951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * request lots of pdus around the same time, and AsyncTask may reject tasks 5051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * in that case and has no way of bounding the number of threads used by those 5151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * tasks. 5251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * <p> 5351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * ThumbnailManager is used to asynchronously load pictures and create thumbnails. The thumbnails 5451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * are stored in a local cache with SoftReferences. Once a thumbnail is loaded, it will call the 5551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * passed in callback with the result. If a thumbnail is immediately available in the cache, 5651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * the callback will be called immediately as well. 5751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * 5851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * Based on BooksImageManager by Virgil King. 5951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor */ 6051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorpublic class ThumbnailManager extends BackgroundLoaderManager { 6151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor private static final String TAG = "ThumbnailManager"; 6251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 63721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private static final boolean DEBUG_DISABLE_CACHE = false; 64721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private static final boolean DEBUG_DISABLE_CALLBACK = false; 6551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor private static final boolean DEBUG_DISABLE_LOAD = false; 6651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor private static final boolean DEBUG_LONG_WAIT = false; 6751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 68721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private static final int COMPRESS_JPEG_QUALITY = 90; 6951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 7051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor private final SimpleCache<Uri, Bitmap> mThumbnailCache; 7151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor private final Context mContext; 72721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private ImageCacheService mImageCacheService; 73721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private static Bitmap mEmptyImageBitmap; 74721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private static Bitmap mEmptyVideoBitmap; 75721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 76721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // NOTE: These type numbers are stored in the image cache, so it should not 77721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // not be changed without resetting the cache. 78721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor public static final int TYPE_THUMBNAIL = 1; 79721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor public static final int TYPE_MICROTHUMBNAIL = 2; 80721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 81721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor public static final int THUMBNAIL_TARGET_SIZE = 640; 8251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 8351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public ThumbnailManager(final Context context) { 8451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor super(context); 8551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 86721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor mThumbnailCache = new SimpleCache<Uri, Bitmap>(8, 16, 0.75f, true); 8751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mContext = context; 88721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 89721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor mEmptyImageBitmap = BitmapFactory.decodeResource(context.getResources(), 90721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor R.drawable.ic_missing_thumbnail_picture); 91721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 92721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor mEmptyVideoBitmap = BitmapFactory.decodeResource(context.getResources(), 93721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor R.drawable.ic_missing_thumbnail_video); 9451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 9551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 9651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor /** 9751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * getThumbnail must be called on the same thread that created ThumbnailManager. This is 9851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * normally the UI thread. 9951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * @param uri the uri of the image 10051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * @param width the original full width of the image 10151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * @param height the original full height of the image 10251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * @param callback the callback to call when the thumbnail is fully loaded 10351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * @return 10451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor */ 105721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor public ItemLoadedFuture getThumbnail(Uri uri, 10679bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor final ItemLoadedCallback<ImageLoaded> callback) { 107721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return getThumbnail(uri, false, callback); 10879bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor } 10979bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor 11079bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor /** 11179bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor * getVideoThumbnail must be called on the same thread that created ThumbnailManager. This is 11279bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor * normally the UI thread. 11379bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor * @param uri the uri of the image 11479bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor * @param callback the callback to call when the thumbnail is fully loaded 11579bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor * @return 11679bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor */ 11779bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor public ItemLoadedFuture getVideoThumbnail(Uri uri, 11879bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor final ItemLoadedCallback<ImageLoaded> callback) { 119721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return getThumbnail(uri, true, callback); 12079bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor } 12179bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor 122721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private ItemLoadedFuture getThumbnail(Uri uri, boolean isVideo, 12379bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor final ItemLoadedCallback<ImageLoaded> callback) { 12451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (uri == null) { 12551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor throw new NullPointerException(); 12651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 12751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 128721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor final Bitmap thumbnail = DEBUG_DISABLE_CACHE ? null : mThumbnailCache.get(uri); 12951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 13051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor final boolean thumbnailExists = (thumbnail != null); 13151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor final boolean taskExists = mPendingTaskUris.contains(uri); 13251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor final boolean newTaskRequired = !thumbnailExists && !taskExists; 13351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor final boolean callbackRequired = (callback != null); 13451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 13551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (Log.isLoggable(LogTag.THUMBNAIL_CACHE, Log.DEBUG)) { 13651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Log.v(TAG, "getThumbnail mThumbnailCache.get for uri: " + uri + " thumbnail: " + 13751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor thumbnail + " callback: " + callback + " thumbnailExists: " + 13851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor thumbnailExists + " taskExists: " + taskExists + 13951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor " newTaskRequired: " + newTaskRequired + 14051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor " callbackRequired: " + callbackRequired); 14151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 14251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 14351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (thumbnailExists) { 144721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (callbackRequired && !DEBUG_DISABLE_CALLBACK) { 14579bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor ImageLoaded imageLoaded = new ImageLoaded(thumbnail, isVideo); 14679bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor callback.onItemLoaded(imageLoaded, null); 14751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 14851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor return new NullItemLoadedFuture(); 14951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 15051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 15151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (callbackRequired) { 15251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor addCallback(uri, callback); 15351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 15451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 15551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (newTaskRequired) { 15651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mPendingTaskUris.add(uri); 157721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Runnable task = new ThumbnailTask(uri, isVideo); 15851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mExecutor.execute(task); 15951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 16051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor return new ItemLoadedFuture() { 161ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev @Override 16251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public void cancel() { 16351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor cancelCallback(callback); 16451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 165ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev @Override 16651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public boolean isDone() { 16751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor return false; 16851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 16951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor }; 17051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 17151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 17251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor @Override 17351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public void clear() { 17451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor super.clear(); 17551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 17651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mThumbnailCache.clear(); 17751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 17851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 179ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev @Override 18051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public String getTag() { 18151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor return TAG; 18251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 18351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 184721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private synchronized ImageCacheService getImageCacheService() { 185721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (mImageCacheService == null) { 186721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor mImageCacheService = new ImageCacheService(mContext); 187721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 188721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return mImageCacheService; 189721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 190721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 19151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public class ThumbnailTask implements Runnable { 19251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor private final Uri mUri; 19379bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor private final boolean mIsVideo; 19451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 195721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor public ThumbnailTask(Uri uri, boolean isVideo) { 19651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (uri == null) { 19751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor throw new NullPointerException(); 19851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 19951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mUri = uri; 20079bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor mIsVideo = isVideo; 20151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 20251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 20351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor /** {@inheritDoc} */ 204ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev @Override 20551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public void run() { 20651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (DEBUG_DISABLE_LOAD) { 20751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor return; 20851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 20951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (DEBUG_LONG_WAIT) { 21051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor try { 21151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Thread.sleep(10000); 21251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } catch (InterruptedException e) { 21351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 21451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 21551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 216721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor final Bitmap resultBitmap = getBitmap(mIsVideo); 217721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 21851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mCallbackHandler.post(new Runnable() { 219ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev @Override 22051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor public void run() { 22151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor final Set<ItemLoadedCallback> callbacks = mCallbacks.get(mUri); 22251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (callbacks != null) { 223721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap bitmap = resultBitmap == null ? 224721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor (mIsVideo ? mEmptyVideoBitmap : mEmptyImageBitmap) 225721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor : resultBitmap; 226721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 22751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor // Make a copy so that the callback can unregister itself 22879bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor for (final ItemLoadedCallback<ImageLoaded> callback : asList(callbacks)) { 229721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (Log.isLoggable(LogTag.THUMBNAIL_CACHE, Log.DEBUG)) { 23051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Log.d(TAG, "Invoking item loaded callback " + callback); 23151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 232721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (!DEBUG_DISABLE_CALLBACK) { 233721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor ImageLoaded imageLoaded = new ImageLoaded(bitmap, mIsVideo); 234721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor callback.onItemLoaded(imageLoaded, null); 235721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 23651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 23751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } else { 23851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (Log.isLoggable(TAG, Log.DEBUG)) { 23951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Log.d(TAG, "No image callback!"); 24051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 24151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 24251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 243721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // Add the bitmap to the soft cache if the load succeeded. Don't cache the 244721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // stand-ins for empty bitmaps. 24551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (resultBitmap != null) { 24651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mThumbnailCache.put(mUri, resultBitmap); 247721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (Log.isLoggable(LogTag.THUMBNAIL_CACHE, Log.DEBUG)) { 24851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Log.v(TAG, "in callback runnable: bitmap uri: " + mUri + 24951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor " width: " + resultBitmap.getWidth() + " height: " + 25051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor resultBitmap.getHeight() + " size: " + 25151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor resultBitmap.getByteCount()); 25251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 25351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 25451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 25551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mCallbacks.remove(mUri); 25651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor mPendingTaskUris.remove(mUri); 25751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 25851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (Log.isLoggable(LogTag.THUMBNAIL_CACHE, Log.DEBUG)) { 25951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Log.d(TAG, "Image task for " + mUri + "exiting " + mPendingTaskUris.size() 26051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor + " remain"); 26151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 26251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 26351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor }); 26451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 265721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 266721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap getBitmap(boolean isVideo) { 267721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor ImageCacheService cacheService = getImageCacheService(); 268721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 269721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor UriImage uriImage = new UriImage(mContext, mUri); 270721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor String path = uriImage.getPath(); 271721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor ImageData data = cacheService.getImageData(path, TYPE_THUMBNAIL); 272721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 273721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (data != null) { 274721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor BitmapFactory.Options options = new BitmapFactory.Options(); 275721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor options.inPreferredConfig = Bitmap.Config.ARGB_8888; 276721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap bitmap = requestDecode(data.mData, 277721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor data.mOffset, data.mData.length - data.mOffset, options); 278721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (bitmap == null) { 279721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Log.w(TAG, "decode cached failed " + path); 280721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 281721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return bitmap; 282721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } else { 283721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap bitmap; 284721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (isVideo) { 285721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor bitmap = getVideoBitmap(); 286721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } else { 287721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor bitmap = onDecodeOriginal(mUri, TYPE_THUMBNAIL); 288721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 289721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (bitmap == null) { 290721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Log.w(TAG, "decode orig failed " + path); 291721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return null; 292721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 293721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 294721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor bitmap = resizeDownBySideLength(bitmap, THUMBNAIL_TARGET_SIZE, true); 295721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 296721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor byte[] array = compressBitmap(bitmap); 297721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 298721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor cacheService.putImageData(path, TYPE_THUMBNAIL, array); 299721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return bitmap; 300721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 301721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 302721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 303721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap getVideoBitmap() { 304721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 305721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor try { 306721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor retriever.setDataSource(mContext, mUri); 307721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return retriever.getFrameAtTime(-1); 308721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } catch (RuntimeException ex) { 309721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // Assume this is a corrupt video file. 310721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } finally { 311721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor try { 312721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor retriever.release(); 313721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } catch (RuntimeException ex) { 314721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // Ignore failures while cleaning up. 315721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 316721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 317721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return null; 318721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 319721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 320721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private byte[] compressBitmap(Bitmap bitmap) { 321721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor ByteArrayOutputStream os = new ByteArrayOutputStream(); 322721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor bitmap.compress(Bitmap.CompressFormat.JPEG, 323721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor COMPRESS_JPEG_QUALITY, os); 324721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return os.toByteArray(); 325721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 326721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 327721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap requestDecode(byte[] bytes, int offset, 328721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int length, Options options) { 329721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (options == null) { 330721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor options = new Options(); 331721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 332721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return ensureGLCompatibleBitmap( 333721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor BitmapFactory.decodeByteArray(bytes, offset, length, options)); 334721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 335721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 336721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap resizeDownBySideLength( 337721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap bitmap, int maxLength, boolean recycle) { 338721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int srcWidth = bitmap.getWidth(); 339721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int srcHeight = bitmap.getHeight(); 340721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor float scale = Math.min( 341721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor (float) maxLength / srcWidth, (float) maxLength / srcHeight); 342721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (scale >= 1.0f) return bitmap; 343721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return resizeBitmapByScale(bitmap, scale, recycle); 344721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 345721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 346721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap resizeBitmapByScale( 347721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap bitmap, float scale, boolean recycle) { 348721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int width = Math.round(bitmap.getWidth() * scale); 349721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int height = Math.round(bitmap.getHeight() * scale); 350721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (width == bitmap.getWidth() 351721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor && height == bitmap.getHeight()) return bitmap; 352721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap)); 353721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Canvas canvas = new Canvas(target); 354721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor canvas.scale(scale, scale); 355721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); 356721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor canvas.drawBitmap(bitmap, 0, 0, paint); 357721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (recycle) bitmap.recycle(); 358721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return target; 359721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 360721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 361721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap.Config getConfig(Bitmap bitmap) { 362721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap.Config config = bitmap.getConfig(); 363721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (config == null) { 364721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor config = Bitmap.Config.ARGB_8888; 365721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 366721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return config; 367721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 368721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 369721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // TODO: This function should not be called directly from 370721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // DecodeUtils.requestDecode(...), since we don't have the knowledge 371721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // if the bitmap will be uploaded to GL. 372721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap ensureGLCompatibleBitmap(Bitmap bitmap) { 373721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (bitmap == null || bitmap.getConfig() != null) return bitmap; 374721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap newBitmap = bitmap.copy(Config.ARGB_8888, false); 375721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor bitmap.recycle(); 376721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return newBitmap; 377721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 378721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 379721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap onDecodeOriginal(Uri uri, int type) { 380721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor BitmapFactory.Options options = new BitmapFactory.Options(); 381721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor options.inPreferredConfig = Bitmap.Config.ARGB_8888; 382721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 383721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return requestDecode(uri, options, THUMBNAIL_TARGET_SIZE); 384721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 385721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 386721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private void closeSilently(Closeable c) { 387721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (c == null) return; 388721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor try { 389721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor c.close(); 390721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } catch (Throwable t) { 391721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Log.w(TAG, "close fail", t); 392721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 393721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 394721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 395721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap requestDecode(final Uri uri, Options options, int targetSize) { 396721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (options == null) options = new Options(); 397721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 398721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor InputStream inputStream; 399721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor try { 400721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor inputStream = mContext.getContentResolver().openInputStream(uri); 401721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } catch (FileNotFoundException e) { 402721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Log.e(TAG, "Can't open uri: " + uri, e); 403721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return null; 404721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 405721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 406721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor options.inJustDecodeBounds = true; 407721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor BitmapFactory.decodeStream(inputStream, null, options); 408721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor closeSilently(inputStream); 409721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 410721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // No way to reset the stream. Have to open it again :-( 411721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor try { 412721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor inputStream = mContext.getContentResolver().openInputStream(uri); 413721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } catch (FileNotFoundException e) { 414721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Log.e(TAG, "Can't open uri: " + uri, e); 415721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return null; 416721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 417721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 418721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor options.inSampleSize = computeSampleSizeLarger( 419721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor options.outWidth, options.outHeight, targetSize); 420721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor options.inJustDecodeBounds = false; 421721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 422721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap result = BitmapFactory.decodeStream(inputStream, null, options); 423721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor closeSilently(inputStream); 424721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 425721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // We need to resize down if the decoder does not support inSampleSize. 426721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // (For example, GIF images.) 427721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor result = resizeDownIfTooBig(result, targetSize, true); 428721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return ensureGLCompatibleBitmap(result); 429721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 430721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 431721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // This computes a sample size which makes the longer side at least 432721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // minSideLength long. If that's not possible, return 1. 433721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private int computeSampleSizeLarger(int w, int h, 434721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int minSideLength) { 435721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int initialSize = Math.max(w / minSideLength, h / minSideLength); 436721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (initialSize <= 1) return 1; 437721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 438721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return initialSize <= 8 439721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor ? prevPowerOf2(initialSize) 440721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor : initialSize / 8 * 8; 441721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 442721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 443721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // Returns the previous power of two. 444721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // Returns the input if it is already power of 2. 445721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // Throws IllegalArgumentException if the input is <= 0 446721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private int prevPowerOf2(int n) { 447721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (n <= 0) throw new IllegalArgumentException(); 448721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return Integer.highestOneBit(n); 449721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 450721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 451721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor // Resize the bitmap if each side is >= targetSize * 2 452721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor private Bitmap resizeDownIfTooBig( 453721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor Bitmap bitmap, int targetSize, boolean recycle) { 454721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int srcWidth = bitmap.getWidth(); 455721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor int srcHeight = bitmap.getHeight(); 456721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor float scale = Math.max( 457721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor (float) targetSize / srcWidth, (float) targetSize / srcHeight); 458721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor if (scale > 0.5f) return bitmap; 459721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return resizeBitmapByScale(bitmap, scale, recycle); 460721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 461721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 46251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 46379bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor 46479bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor public static class ImageLoaded { 46579bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor public final Bitmap mBitmap; 46679bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor public final boolean mIsVideo; 46779bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor 46879bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor public ImageLoaded(Bitmap bitmap, boolean isVideo) { 46979bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor mBitmap = bitmap; 47079bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor mIsVideo = isVideo; 47179bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor } 47279bf6f70c54d08dc9c3481b8461a3a46a3cefb83Tom Taylor } 47351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor} 474