1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.camera; 18 19 20 import android.content.ContentResolver; 21 import android.content.res.Resources; 22 import android.graphics.Bitmap; 23 import android.graphics.BitmapFactory; 24 import android.graphics.drawable.BitmapDrawable; 25 import android.graphics.drawable.Drawable; 26 import android.graphics.drawable.TransitionDrawable; 27 import android.media.ThumbnailUtils; 28 import android.net.Uri; 29 import android.os.ParcelFileDescriptor; 30 import android.util.Log; 31 import android.view.ViewGroup.LayoutParams; 32 import android.widget.ImageView; 33 34 import java.io.BufferedInputStream; 35 import java.io.BufferedOutputStream; 36 import java.io.DataInputStream; 37 import java.io.DataOutputStream; 38 import java.io.FileInputStream; 39 import java.io.FileOutputStream; 40 import java.io.IOException; 41 42 /** 43 * A controller shows thumbnail picture on a button. The thumbnail picture 44 * corresponds to a URI of the original picture/video. The thumbnail bitmap 45 * and the URI can be saved to a file (and later loaded from it). 46 */ 47 public class ThumbnailController { 48 49 @SuppressWarnings("unused") 50 private static final String TAG = "ThumbnailController"; 51 private final ContentResolver mContentResolver; 52 private Uri mUri; 53 private Bitmap mThumb; 54 private final ImageView mButton; 55 private Drawable[] mThumbs; 56 private TransitionDrawable mThumbTransition; 57 private boolean mShouldAnimateThumb; 58 private final Resources mResources; 59 60 // The "frame" is a drawable we want to put on top of the thumbnail. ThumbnailController(Resources resources, ImageView button, ContentResolver contentResolver)61 public ThumbnailController(Resources resources, 62 ImageView button, ContentResolver contentResolver) { 63 mResources = resources; 64 mButton = button; 65 mContentResolver = contentResolver; 66 } 67 setData(Uri uri, Bitmap original)68 public void setData(Uri uri, Bitmap original) { 69 // Make sure uri and original are consistently both null or both 70 // non-null. 71 if (uri == null || original == null) { 72 uri = null; 73 original = null; 74 } 75 mUri = uri; 76 updateThumb(original); 77 } 78 getUri()79 public Uri getUri() { 80 return mUri; 81 } 82 83 private static final int BUFSIZE = 4096; 84 85 // Stores the data from the specified file. 86 // Returns true for success. storeData(String filePath)87 public boolean storeData(String filePath) { 88 if (mUri == null) { 89 return false; 90 } 91 92 FileOutputStream f = null; 93 BufferedOutputStream b = null; 94 DataOutputStream d = null; 95 try { 96 f = new FileOutputStream(filePath); 97 b = new BufferedOutputStream(f, BUFSIZE); 98 d = new DataOutputStream(b); 99 d.writeUTF(mUri.toString()); 100 mThumb.compress(Bitmap.CompressFormat.PNG, 100, d); 101 d.close(); 102 } catch (IOException e) { 103 return false; 104 } finally { 105 MenuHelper.closeSilently(f); 106 MenuHelper.closeSilently(b); 107 MenuHelper.closeSilently(d); 108 } 109 return true; 110 } 111 112 // Loads the data from the specified file. 113 // Returns true for success. loadData(String filePath)114 public boolean loadData(String filePath) { 115 FileInputStream f = null; 116 BufferedInputStream b = null; 117 DataInputStream d = null; 118 try { 119 f = new FileInputStream(filePath); 120 b = new BufferedInputStream(f, BUFSIZE); 121 d = new DataInputStream(b); 122 Uri uri = Uri.parse(d.readUTF()); 123 Bitmap thumb = BitmapFactory.decodeStream(d); 124 setData(uri, thumb); 125 d.close(); 126 } catch (IOException e) { 127 return false; 128 } finally { 129 MenuHelper.closeSilently(f); 130 MenuHelper.closeSilently(b); 131 MenuHelper.closeSilently(d); 132 } 133 return true; 134 } 135 updateDisplayIfNeeded()136 public void updateDisplayIfNeeded() { 137 if (mUri == null) { 138 mButton.setImageDrawable(null); 139 return; 140 } 141 142 if (mShouldAnimateThumb) { 143 mThumbTransition.startTransition(500); 144 mShouldAnimateThumb = false; 145 } 146 } 147 updateThumb(Bitmap original)148 private void updateThumb(Bitmap original) { 149 if (original == null) { 150 mThumb = null; 151 mThumbs = null; 152 return; 153 } 154 155 LayoutParams param = mButton.getLayoutParams(); 156 final int miniThumbWidth = param.width 157 - mButton.getPaddingLeft() - mButton.getPaddingRight(); 158 final int miniThumbHeight = param.height 159 - mButton.getPaddingTop() - mButton.getPaddingBottom(); 160 mThumb = ThumbnailUtils.extractThumbnail( 161 original, miniThumbWidth, miniThumbHeight); 162 Drawable drawable; 163 if (mThumbs == null) { 164 mThumbs = new Drawable[2]; 165 mThumbs[1] = new BitmapDrawable(mResources, mThumb); 166 drawable = mThumbs[1]; 167 mShouldAnimateThumb = false; 168 } else { 169 mThumbs[0] = mThumbs[1]; 170 mThumbs[1] = new BitmapDrawable(mResources, mThumb); 171 mThumbTransition = new TransitionDrawable(mThumbs); 172 drawable = mThumbTransition; 173 mShouldAnimateThumb = true; 174 } 175 mButton.setImageDrawable(drawable); 176 } 177 isUriValid()178 public boolean isUriValid() { 179 if (mUri == null) { 180 return false; 181 } 182 try { 183 ParcelFileDescriptor pfd = 184 mContentResolver.openFileDescriptor(mUri, "r"); 185 if (pfd == null) { 186 Log.e(TAG, "Fail to open URI."); 187 return false; 188 } 189 pfd.close(); 190 } catch (IOException ex) { 191 return false; 192 } 193 return true; 194 } 195 } 196