ThumbnailLoadTask.java revision 4cb51dbce9635f4bf68a6de88f759e2f86d20325
1/* 2 * Copyright (C) 2012 Google Inc. 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package com.android.mail.ui; 19 20import android.content.res.AssetFileDescriptor; 21import android.graphics.Bitmap; 22import android.graphics.BitmapFactory; 23import android.net.Uri; 24import android.os.AsyncTask; 25 26import com.android.mail.providers.Attachment; 27import com.android.mail.utils.LogTag; 28import com.android.mail.utils.LogUtils; 29 30import java.io.IOException; 31 32/** 33 * Performs the load of a thumbnail bitmap in a background 34 * {@link AsyncTask}. Available for use with any view that implements 35 * the {@link AttachmentBitmapHolder} interface. 36 */ 37public class ThumbnailLoadTask extends AsyncTask<Uri, Void, Bitmap> { 38 private static final String LOG_TAG = LogTag.getLogTag(); 39 40 private final AttachmentBitmapHolder mHolder; 41 private final int mWidth; 42 private final int mHeight; 43 44 public static void setupThumbnailPreview( 45 ThumbnailLoadTask task, final AttachmentBitmapHolder holder, 46 final Attachment attachment, final Attachment prevAttachment) { 47 final int width = holder.getThumbnailWidth(); 48 final int height = holder.getThumbnailHeight(); 49 if (attachment == null || width == 0 || height == 0 || !attachment.isImage()) { 50 holder.setThumbnailToDefault(); 51 return; 52 } 53 54 final Uri thumbnailUri = attachment.thumbnailUri; 55 final Uri contentUri = attachment.contentUri; 56 final Uri uri = (prevAttachment == null) ? null : prevAttachment.uri; 57 final Uri prevUri = (prevAttachment == null) ? null : prevAttachment.uri; 58 // begin loading a thumbnail if this is an image and either the thumbnail or the original 59 // content is ready (and different from any existing image) 60 if ((thumbnailUri != null || contentUri != null) 61 && (holder.bitmapSetToDefault() || 62 prevUri == null || !uri.equals(prevUri))) { 63 // cancel/dispose any existing task and start a new one 64 if (task != null) { 65 task.cancel(true); 66 } 67 68 task = new ThumbnailLoadTask( 69 holder, width, height); 70 task.execute(thumbnailUri, contentUri); 71 } else if (thumbnailUri == null && contentUri == null) { 72 // not an image, or no thumbnail exists. fall back to default. 73 // async image load must separately ensure the default appears upon load failure. 74 holder.setThumbnailToDefault(); 75 } 76 } 77 78 public ThumbnailLoadTask(AttachmentBitmapHolder holder, int width, int height) { 79 mHolder = holder; 80 mWidth = width; 81 mHeight = height; 82 } 83 84 @Override 85 protected Bitmap doInBackground(Uri... params) { 86 Bitmap result = loadBitmap(params[0]); 87 if (result == null) { 88 result = loadBitmap(params[1]); 89 } 90 91 return result; 92 } 93 94 private Bitmap loadBitmap(final Uri thumbnailUri) { 95 AssetFileDescriptor fd = null; 96 Bitmap result = null; 97 98 try { 99 fd = mHolder.getResolver().openAssetFileDescriptor(thumbnailUri, "r"); 100 if (isCancelled() || fd == null) { 101 return null; 102 } 103 104 final BitmapFactory.Options opts = new BitmapFactory.Options(); 105 opts.inJustDecodeBounds = true; 106 107 BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor(), null, opts); 108 if (isCancelled() || opts.outWidth == -1 || opts.outHeight == -1) { 109 return null; 110 } 111 112 opts.inJustDecodeBounds = false; 113 // Shrink both X and Y (but do not over-shrink) 114 // and pick the least affected dimension to ensure the thumbnail is fillable 115 // (i.e. ScaleType.CENTER_CROP) 116 final int wDivider = Math.max(opts.outWidth / mWidth, 1); 117 final int hDivider = Math.max(opts.outHeight / mHeight, 1); 118 opts.inSampleSize = Math.min(wDivider, hDivider); 119 120 LogUtils.d(LOG_TAG, "in background, src w/h=%d/%d dst w/h=%d/%d, divider=%d", 121 opts.outWidth, opts.outHeight, mWidth, mHeight, opts.inSampleSize); 122 123 result = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor(), null, opts); 124 125 } catch (Throwable t) { 126 LogUtils.e(LOG_TAG, t, "Unable to decode thumbnail %s", thumbnailUri); 127 } finally { 128 if (fd != null) { 129 try { 130 fd.close(); 131 } catch (IOException e) { 132 LogUtils.e(LOG_TAG, e, ""); 133 } 134 } 135 } 136 137 return result; 138 } 139 140 @Override 141 protected void onPostExecute(Bitmap result) { 142 if (result == null) { 143 LogUtils.d(LOG_TAG, "back in UI thread, decode failed"); 144 mHolder.setThumbnailToDefault(); 145 return; 146 } 147 148 LogUtils.d(LOG_TAG, "back in UI thread, decode success, w/h=%d/%d", result.getWidth(), 149 result.getHeight()); 150 mHolder.setThumbnail(result); 151 } 152 153} 154