1666ea1b28a76aeba74744148b15099254d918671Owen Lin/* 2666ea1b28a76aeba74744148b15099254d918671Owen Lin * Copyright (C) 2009 The Android Open Source Project 3666ea1b28a76aeba74744148b15099254d918671Owen Lin * 4666ea1b28a76aeba74744148b15099254d918671Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5666ea1b28a76aeba74744148b15099254d918671Owen Lin * you may not use this file except in compliance with the License. 6666ea1b28a76aeba74744148b15099254d918671Owen Lin * You may obtain a copy of the License at 7666ea1b28a76aeba74744148b15099254d918671Owen Lin * 8666ea1b28a76aeba74744148b15099254d918671Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9666ea1b28a76aeba74744148b15099254d918671Owen Lin * 10666ea1b28a76aeba74744148b15099254d918671Owen Lin * Unless required by applicable law or agreed to in writing, software 11666ea1b28a76aeba74744148b15099254d918671Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12666ea1b28a76aeba74744148b15099254d918671Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13666ea1b28a76aeba74744148b15099254d918671Owen Lin * See the License for the specific language governing permissions and 14666ea1b28a76aeba74744148b15099254d918671Owen Lin * limitations under the License. 15666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 16666ea1b28a76aeba74744148b15099254d918671Owen Lin 17666ea1b28a76aeba74744148b15099254d918671Owen Linpackage com.android.camera; 18666ea1b28a76aeba74744148b15099254d918671Owen Lin 19d6c2fb7a38fcdb58742fcfffd67a4594487ec71cOwen Linimport com.android.gallery.R; 20d6c2fb7a38fcdb58742fcfffd67a4594487ec71cOwen Lin 21666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.app.Activity; 22666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.app.AlertDialog; 23666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.app.ProgressDialog; 24666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.ContentResolver; 25666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.DialogInterface; 26666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.Intent; 27666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Bitmap; 28666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.BitmapFactory; 29666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Canvas; 30666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Matrix; 31666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Rect; 32666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.net.Uri; 33666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Handler; 34666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.ParcelFileDescriptor; 35666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.util.Log; 36666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.View; 37666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.View.OnClickListener; 38666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.animation.Animation; 39666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.animation.TranslateAnimation; 40666ea1b28a76aeba74744148b15099254d918671Owen Lin 41666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.IImage; 42666ea1b28a76aeba74744148b15099254d918671Owen Lin 43666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.Closeable; 44666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.FileDescriptor; 45666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.IOException; 46666ea1b28a76aeba74744148b15099254d918671Owen Lin 47666ea1b28a76aeba74744148b15099254d918671Owen Lin/** 48666ea1b28a76aeba74744148b15099254d918671Owen Lin * Collection of utility functions used in this package. 49666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 50666ea1b28a76aeba74744148b15099254d918671Owen Linpublic class Util { 51666ea1b28a76aeba74744148b15099254d918671Owen Lin private static final String TAG = "Util"; 52666ea1b28a76aeba74744148b15099254d918671Owen Lin public static final int DIRECTION_LEFT = 0; 53666ea1b28a76aeba74744148b15099254d918671Owen Lin public static final int DIRECTION_RIGHT = 1; 54666ea1b28a76aeba74744148b15099254d918671Owen Lin public static final int DIRECTION_UP = 2; 55666ea1b28a76aeba74744148b15099254d918671Owen Lin public static final int DIRECTION_DOWN = 3; 56666ea1b28a76aeba74744148b15099254d918671Owen Lin 57666ea1b28a76aeba74744148b15099254d918671Owen Lin private static OnClickListener sNullOnClickListener; 58666ea1b28a76aeba74744148b15099254d918671Owen Lin 59666ea1b28a76aeba74744148b15099254d918671Owen Lin private Util() { 60666ea1b28a76aeba74744148b15099254d918671Owen Lin } 61666ea1b28a76aeba74744148b15099254d918671Owen Lin 62666ea1b28a76aeba74744148b15099254d918671Owen Lin // Rotates the bitmap by the specified degree. 63666ea1b28a76aeba74744148b15099254d918671Owen Lin // If a new bitmap is created, the original bitmap is recycled. 64666ea1b28a76aeba74744148b15099254d918671Owen Lin public static Bitmap rotate(Bitmap b, int degrees) { 65666ea1b28a76aeba74744148b15099254d918671Owen Lin if (degrees != 0 && b != null) { 66666ea1b28a76aeba74744148b15099254d918671Owen Lin Matrix m = new Matrix(); 67666ea1b28a76aeba74744148b15099254d918671Owen Lin m.setRotate(degrees, 68666ea1b28a76aeba74744148b15099254d918671Owen Lin (float) b.getWidth() / 2, (float) b.getHeight() / 2); 69666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 70666ea1b28a76aeba74744148b15099254d918671Owen Lin Bitmap b2 = Bitmap.createBitmap( 71666ea1b28a76aeba74744148b15099254d918671Owen Lin b, 0, 0, b.getWidth(), b.getHeight(), m, true); 72666ea1b28a76aeba74744148b15099254d918671Owen Lin if (b != b2) { 73666ea1b28a76aeba74744148b15099254d918671Owen Lin b.recycle(); 74666ea1b28a76aeba74744148b15099254d918671Owen Lin b = b2; 75666ea1b28a76aeba74744148b15099254d918671Owen Lin } 76666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (OutOfMemoryError ex) { 77666ea1b28a76aeba74744148b15099254d918671Owen Lin // We have no memory to rotate. Return the original bitmap. 78666ea1b28a76aeba74744148b15099254d918671Owen Lin } 79666ea1b28a76aeba74744148b15099254d918671Owen Lin } 80666ea1b28a76aeba74744148b15099254d918671Owen Lin return b; 81666ea1b28a76aeba74744148b15099254d918671Owen Lin } 82666ea1b28a76aeba74744148b15099254d918671Owen Lin 83666ea1b28a76aeba74744148b15099254d918671Owen Lin /* 84666ea1b28a76aeba74744148b15099254d918671Owen Lin * Compute the sample size as a function of minSideLength 85666ea1b28a76aeba74744148b15099254d918671Owen Lin * and maxNumOfPixels. 86666ea1b28a76aeba74744148b15099254d918671Owen Lin * minSideLength is used to specify that minimal width or height of a 87666ea1b28a76aeba74744148b15099254d918671Owen Lin * bitmap. 88666ea1b28a76aeba74744148b15099254d918671Owen Lin * maxNumOfPixels is used to specify the maximal size in pixels that is 89666ea1b28a76aeba74744148b15099254d918671Owen Lin * tolerable in terms of memory usage. 90666ea1b28a76aeba74744148b15099254d918671Owen Lin * 91666ea1b28a76aeba74744148b15099254d918671Owen Lin * The function returns a sample size based on the constraints. 92666ea1b28a76aeba74744148b15099254d918671Owen Lin * Both size and minSideLength can be passed in as IImage.UNCONSTRAINED, 93666ea1b28a76aeba74744148b15099254d918671Owen Lin * which indicates no care of the corresponding constraint. 94666ea1b28a76aeba74744148b15099254d918671Owen Lin * The functions prefers returning a sample size that 95666ea1b28a76aeba74744148b15099254d918671Owen Lin * generates a smaller bitmap, unless minSideLength = IImage.UNCONSTRAINED. 96666ea1b28a76aeba74744148b15099254d918671Owen Lin * 97666ea1b28a76aeba74744148b15099254d918671Owen Lin * Also, the function rounds up the sample size to a power of 2 or multiple 98666ea1b28a76aeba74744148b15099254d918671Owen Lin * of 8 because BitmapFactory only honors sample size this way. 99666ea1b28a76aeba74744148b15099254d918671Owen Lin * For example, BitmapFactory downsamples an image by 2 even though the 100666ea1b28a76aeba74744148b15099254d918671Owen Lin * request is 3. So we round up the sample size to avoid OOM. 101666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 102666ea1b28a76aeba74744148b15099254d918671Owen Lin public static int computeSampleSize(BitmapFactory.Options options, 103666ea1b28a76aeba74744148b15099254d918671Owen Lin int minSideLength, int maxNumOfPixels) { 104666ea1b28a76aeba74744148b15099254d918671Owen Lin int initialSize = computeInitialSampleSize(options, minSideLength, 105666ea1b28a76aeba74744148b15099254d918671Owen Lin maxNumOfPixels); 106666ea1b28a76aeba74744148b15099254d918671Owen Lin 107666ea1b28a76aeba74744148b15099254d918671Owen Lin int roundedSize; 108666ea1b28a76aeba74744148b15099254d918671Owen Lin if (initialSize <= 8) { 109666ea1b28a76aeba74744148b15099254d918671Owen Lin roundedSize = 1; 110666ea1b28a76aeba74744148b15099254d918671Owen Lin while (roundedSize < initialSize) { 111666ea1b28a76aeba74744148b15099254d918671Owen Lin roundedSize <<= 1; 112666ea1b28a76aeba74744148b15099254d918671Owen Lin } 113666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 114666ea1b28a76aeba74744148b15099254d918671Owen Lin roundedSize = (initialSize + 7) / 8 * 8; 115666ea1b28a76aeba74744148b15099254d918671Owen Lin } 116666ea1b28a76aeba74744148b15099254d918671Owen Lin 117666ea1b28a76aeba74744148b15099254d918671Owen Lin return roundedSize; 118666ea1b28a76aeba74744148b15099254d918671Owen Lin } 119666ea1b28a76aeba74744148b15099254d918671Owen Lin 120666ea1b28a76aeba74744148b15099254d918671Owen Lin private static int computeInitialSampleSize(BitmapFactory.Options options, 121666ea1b28a76aeba74744148b15099254d918671Owen Lin int minSideLength, int maxNumOfPixels) { 122666ea1b28a76aeba74744148b15099254d918671Owen Lin double w = options.outWidth; 123666ea1b28a76aeba74744148b15099254d918671Owen Lin double h = options.outHeight; 124666ea1b28a76aeba74744148b15099254d918671Owen Lin 125666ea1b28a76aeba74744148b15099254d918671Owen Lin int lowerBound = (maxNumOfPixels == IImage.UNCONSTRAINED) ? 1 : 126666ea1b28a76aeba74744148b15099254d918671Owen Lin (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); 127666ea1b28a76aeba74744148b15099254d918671Owen Lin int upperBound = (minSideLength == IImage.UNCONSTRAINED) ? 128 : 128666ea1b28a76aeba74744148b15099254d918671Owen Lin (int) Math.min(Math.floor(w / minSideLength), 129666ea1b28a76aeba74744148b15099254d918671Owen Lin Math.floor(h / minSideLength)); 130666ea1b28a76aeba74744148b15099254d918671Owen Lin 131666ea1b28a76aeba74744148b15099254d918671Owen Lin if (upperBound < lowerBound) { 132666ea1b28a76aeba74744148b15099254d918671Owen Lin // return the larger one when there is no overlapping zone. 133666ea1b28a76aeba74744148b15099254d918671Owen Lin return lowerBound; 134666ea1b28a76aeba74744148b15099254d918671Owen Lin } 135666ea1b28a76aeba74744148b15099254d918671Owen Lin 136666ea1b28a76aeba74744148b15099254d918671Owen Lin if ((maxNumOfPixels == IImage.UNCONSTRAINED) && 137666ea1b28a76aeba74744148b15099254d918671Owen Lin (minSideLength == IImage.UNCONSTRAINED)) { 138666ea1b28a76aeba74744148b15099254d918671Owen Lin return 1; 139666ea1b28a76aeba74744148b15099254d918671Owen Lin } else if (minSideLength == IImage.UNCONSTRAINED) { 140666ea1b28a76aeba74744148b15099254d918671Owen Lin return lowerBound; 141666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 142666ea1b28a76aeba74744148b15099254d918671Owen Lin return upperBound; 143666ea1b28a76aeba74744148b15099254d918671Owen Lin } 144666ea1b28a76aeba74744148b15099254d918671Owen Lin } 145666ea1b28a76aeba74744148b15099254d918671Owen Lin 146666ea1b28a76aeba74744148b15099254d918671Owen Lin // Whether we should recycle the input (unless the output is the input). 147666ea1b28a76aeba74744148b15099254d918671Owen Lin public static final boolean RECYCLE_INPUT = true; 148666ea1b28a76aeba74744148b15099254d918671Owen Lin public static final boolean NO_RECYCLE_INPUT = false; 149666ea1b28a76aeba74744148b15099254d918671Owen Lin 150666ea1b28a76aeba74744148b15099254d918671Owen Lin public static Bitmap transform(Matrix scaler, 151666ea1b28a76aeba74744148b15099254d918671Owen Lin Bitmap source, 152666ea1b28a76aeba74744148b15099254d918671Owen Lin int targetWidth, 153666ea1b28a76aeba74744148b15099254d918671Owen Lin int targetHeight, 154666ea1b28a76aeba74744148b15099254d918671Owen Lin boolean scaleUp, 155666ea1b28a76aeba74744148b15099254d918671Owen Lin boolean recycle) { 156666ea1b28a76aeba74744148b15099254d918671Owen Lin int deltaX = source.getWidth() - targetWidth; 157666ea1b28a76aeba74744148b15099254d918671Owen Lin int deltaY = source.getHeight() - targetHeight; 158666ea1b28a76aeba74744148b15099254d918671Owen Lin if (!scaleUp && (deltaX < 0 || deltaY < 0)) { 159666ea1b28a76aeba74744148b15099254d918671Owen Lin /* 160666ea1b28a76aeba74744148b15099254d918671Owen Lin * In this case the bitmap is smaller, at least in one dimension, 161666ea1b28a76aeba74744148b15099254d918671Owen Lin * than the target. Transform it by placing as much of the image 162666ea1b28a76aeba74744148b15099254d918671Owen Lin * as possible into the target and leaving the top/bottom or 163666ea1b28a76aeba74744148b15099254d918671Owen Lin * left/right (or both) black. 164666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 165666ea1b28a76aeba74744148b15099254d918671Owen Lin Bitmap b2 = Bitmap.createBitmap(targetWidth, targetHeight, 166666ea1b28a76aeba74744148b15099254d918671Owen Lin Bitmap.Config.ARGB_8888); 167666ea1b28a76aeba74744148b15099254d918671Owen Lin Canvas c = new Canvas(b2); 168666ea1b28a76aeba74744148b15099254d918671Owen Lin 169666ea1b28a76aeba74744148b15099254d918671Owen Lin int deltaXHalf = Math.max(0, deltaX / 2); 170666ea1b28a76aeba74744148b15099254d918671Owen Lin int deltaYHalf = Math.max(0, deltaY / 2); 171666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect src = new Rect( 172666ea1b28a76aeba74744148b15099254d918671Owen Lin deltaXHalf, 173666ea1b28a76aeba74744148b15099254d918671Owen Lin deltaYHalf, 174666ea1b28a76aeba74744148b15099254d918671Owen Lin deltaXHalf + Math.min(targetWidth, source.getWidth()), 175666ea1b28a76aeba74744148b15099254d918671Owen Lin deltaYHalf + Math.min(targetHeight, source.getHeight())); 176666ea1b28a76aeba74744148b15099254d918671Owen Lin int dstX = (targetWidth - src.width()) / 2; 177666ea1b28a76aeba74744148b15099254d918671Owen Lin int dstY = (targetHeight - src.height()) / 2; 178666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect dst = new Rect( 179666ea1b28a76aeba74744148b15099254d918671Owen Lin dstX, 180666ea1b28a76aeba74744148b15099254d918671Owen Lin dstY, 181666ea1b28a76aeba74744148b15099254d918671Owen Lin targetWidth - dstX, 182666ea1b28a76aeba74744148b15099254d918671Owen Lin targetHeight - dstY); 183666ea1b28a76aeba74744148b15099254d918671Owen Lin c.drawBitmap(source, src, dst, null); 184666ea1b28a76aeba74744148b15099254d918671Owen Lin if (recycle) { 185666ea1b28a76aeba74744148b15099254d918671Owen Lin source.recycle(); 186666ea1b28a76aeba74744148b15099254d918671Owen Lin } 187666ea1b28a76aeba74744148b15099254d918671Owen Lin return b2; 188666ea1b28a76aeba74744148b15099254d918671Owen Lin } 189666ea1b28a76aeba74744148b15099254d918671Owen Lin float bitmapWidthF = source.getWidth(); 190666ea1b28a76aeba74744148b15099254d918671Owen Lin float bitmapHeightF = source.getHeight(); 191666ea1b28a76aeba74744148b15099254d918671Owen Lin 192666ea1b28a76aeba74744148b15099254d918671Owen Lin float bitmapAspect = bitmapWidthF / bitmapHeightF; 193666ea1b28a76aeba74744148b15099254d918671Owen Lin float viewAspect = (float) targetWidth / targetHeight; 194666ea1b28a76aeba74744148b15099254d918671Owen Lin 195666ea1b28a76aeba74744148b15099254d918671Owen Lin if (bitmapAspect > viewAspect) { 196666ea1b28a76aeba74744148b15099254d918671Owen Lin float scale = targetHeight / bitmapHeightF; 197666ea1b28a76aeba74744148b15099254d918671Owen Lin if (scale < .9F || scale > 1F) { 198666ea1b28a76aeba74744148b15099254d918671Owen Lin scaler.setScale(scale, scale); 199666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 200666ea1b28a76aeba74744148b15099254d918671Owen Lin scaler = null; 201666ea1b28a76aeba74744148b15099254d918671Owen Lin } 202666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 203666ea1b28a76aeba74744148b15099254d918671Owen Lin float scale = targetWidth / bitmapWidthF; 204666ea1b28a76aeba74744148b15099254d918671Owen Lin if (scale < .9F || scale > 1F) { 205666ea1b28a76aeba74744148b15099254d918671Owen Lin scaler.setScale(scale, scale); 206666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 207666ea1b28a76aeba74744148b15099254d918671Owen Lin scaler = null; 208666ea1b28a76aeba74744148b15099254d918671Owen Lin } 209666ea1b28a76aeba74744148b15099254d918671Owen Lin } 210666ea1b28a76aeba74744148b15099254d918671Owen Lin 211666ea1b28a76aeba74744148b15099254d918671Owen Lin Bitmap b1; 212666ea1b28a76aeba74744148b15099254d918671Owen Lin if (scaler != null) { 213666ea1b28a76aeba74744148b15099254d918671Owen Lin // this is used for minithumb and crop, so we want to filter here. 214666ea1b28a76aeba74744148b15099254d918671Owen Lin b1 = Bitmap.createBitmap(source, 0, 0, 215666ea1b28a76aeba74744148b15099254d918671Owen Lin source.getWidth(), source.getHeight(), scaler, true); 216666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 217666ea1b28a76aeba74744148b15099254d918671Owen Lin b1 = source; 218666ea1b28a76aeba74744148b15099254d918671Owen Lin } 219666ea1b28a76aeba74744148b15099254d918671Owen Lin 220666ea1b28a76aeba74744148b15099254d918671Owen Lin if (recycle && b1 != source) { 221666ea1b28a76aeba74744148b15099254d918671Owen Lin source.recycle(); 222666ea1b28a76aeba74744148b15099254d918671Owen Lin } 223666ea1b28a76aeba74744148b15099254d918671Owen Lin 224666ea1b28a76aeba74744148b15099254d918671Owen Lin int dx1 = Math.max(0, b1.getWidth() - targetWidth); 225666ea1b28a76aeba74744148b15099254d918671Owen Lin int dy1 = Math.max(0, b1.getHeight() - targetHeight); 226666ea1b28a76aeba74744148b15099254d918671Owen Lin 227666ea1b28a76aeba74744148b15099254d918671Owen Lin Bitmap b2 = Bitmap.createBitmap( 228666ea1b28a76aeba74744148b15099254d918671Owen Lin b1, 229666ea1b28a76aeba74744148b15099254d918671Owen Lin dx1 / 2, 230666ea1b28a76aeba74744148b15099254d918671Owen Lin dy1 / 2, 231666ea1b28a76aeba74744148b15099254d918671Owen Lin targetWidth, 232666ea1b28a76aeba74744148b15099254d918671Owen Lin targetHeight); 233666ea1b28a76aeba74744148b15099254d918671Owen Lin 234666ea1b28a76aeba74744148b15099254d918671Owen Lin if (b2 != b1) { 235666ea1b28a76aeba74744148b15099254d918671Owen Lin if (recycle || b1 != source) { 236666ea1b28a76aeba74744148b15099254d918671Owen Lin b1.recycle(); 237666ea1b28a76aeba74744148b15099254d918671Owen Lin } 238666ea1b28a76aeba74744148b15099254d918671Owen Lin } 239666ea1b28a76aeba74744148b15099254d918671Owen Lin 240666ea1b28a76aeba74744148b15099254d918671Owen Lin return b2; 241666ea1b28a76aeba74744148b15099254d918671Owen Lin } 242666ea1b28a76aeba74744148b15099254d918671Owen Lin 243666ea1b28a76aeba74744148b15099254d918671Owen Lin public static <T> int indexOf(T [] array, T s) { 244666ea1b28a76aeba74744148b15099254d918671Owen Lin for (int i = 0; i < array.length; i++) { 245666ea1b28a76aeba74744148b15099254d918671Owen Lin if (array[i].equals(s)) { 246666ea1b28a76aeba74744148b15099254d918671Owen Lin return i; 247666ea1b28a76aeba74744148b15099254d918671Owen Lin } 248666ea1b28a76aeba74744148b15099254d918671Owen Lin } 249666ea1b28a76aeba74744148b15099254d918671Owen Lin return -1; 250666ea1b28a76aeba74744148b15099254d918671Owen Lin } 251666ea1b28a76aeba74744148b15099254d918671Owen Lin 252666ea1b28a76aeba74744148b15099254d918671Owen Lin public static void closeSilently(Closeable c) { 253666ea1b28a76aeba74744148b15099254d918671Owen Lin if (c == null) return; 254666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 255666ea1b28a76aeba74744148b15099254d918671Owen Lin c.close(); 256666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (Throwable t) { 257666ea1b28a76aeba74744148b15099254d918671Owen Lin // do nothing 258666ea1b28a76aeba74744148b15099254d918671Owen Lin } 259666ea1b28a76aeba74744148b15099254d918671Owen Lin } 260666ea1b28a76aeba74744148b15099254d918671Owen Lin 261666ea1b28a76aeba74744148b15099254d918671Owen Lin public static void closeSilently(ParcelFileDescriptor c) { 262666ea1b28a76aeba74744148b15099254d918671Owen Lin if (c == null) return; 263666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 264666ea1b28a76aeba74744148b15099254d918671Owen Lin c.close(); 265666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (Throwable t) { 266666ea1b28a76aeba74744148b15099254d918671Owen Lin // do nothing 267666ea1b28a76aeba74744148b15099254d918671Owen Lin } 268666ea1b28a76aeba74744148b15099254d918671Owen Lin } 269666ea1b28a76aeba74744148b15099254d918671Owen Lin 270666ea1b28a76aeba74744148b15099254d918671Owen Lin /** 271666ea1b28a76aeba74744148b15099254d918671Owen Lin * Make a bitmap from a given Uri. 272666ea1b28a76aeba74744148b15099254d918671Owen Lin * 273666ea1b28a76aeba74744148b15099254d918671Owen Lin * @param uri 274666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 275666ea1b28a76aeba74744148b15099254d918671Owen Lin public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, 276666ea1b28a76aeba74744148b15099254d918671Owen Lin Uri uri, ContentResolver cr, boolean useNative) { 277666ea1b28a76aeba74744148b15099254d918671Owen Lin ParcelFileDescriptor input = null; 278666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 279666ea1b28a76aeba74744148b15099254d918671Owen Lin input = cr.openFileDescriptor(uri, "r"); 280666ea1b28a76aeba74744148b15099254d918671Owen Lin BitmapFactory.Options options = null; 281666ea1b28a76aeba74744148b15099254d918671Owen Lin if (useNative) { 282666ea1b28a76aeba74744148b15099254d918671Owen Lin options = createNativeAllocOptions(); 283666ea1b28a76aeba74744148b15099254d918671Owen Lin } 284666ea1b28a76aeba74744148b15099254d918671Owen Lin return makeBitmap(minSideLength, maxNumOfPixels, uri, cr, input, 285666ea1b28a76aeba74744148b15099254d918671Owen Lin options); 286666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (IOException ex) { 287666ea1b28a76aeba74744148b15099254d918671Owen Lin return null; 288666ea1b28a76aeba74744148b15099254d918671Owen Lin } finally { 289666ea1b28a76aeba74744148b15099254d918671Owen Lin closeSilently(input); 290666ea1b28a76aeba74744148b15099254d918671Owen Lin } 291666ea1b28a76aeba74744148b15099254d918671Owen Lin } 292666ea1b28a76aeba74744148b15099254d918671Owen Lin 293666ea1b28a76aeba74744148b15099254d918671Owen Lin public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, 294666ea1b28a76aeba74744148b15099254d918671Owen Lin ParcelFileDescriptor pfd, boolean useNative) { 295666ea1b28a76aeba74744148b15099254d918671Owen Lin BitmapFactory.Options options = null; 296666ea1b28a76aeba74744148b15099254d918671Owen Lin if (useNative) { 297666ea1b28a76aeba74744148b15099254d918671Owen Lin options = createNativeAllocOptions(); 298666ea1b28a76aeba74744148b15099254d918671Owen Lin } 299666ea1b28a76aeba74744148b15099254d918671Owen Lin return makeBitmap(minSideLength, maxNumOfPixels, null, null, pfd, 300666ea1b28a76aeba74744148b15099254d918671Owen Lin options); 301666ea1b28a76aeba74744148b15099254d918671Owen Lin } 302666ea1b28a76aeba74744148b15099254d918671Owen Lin 303666ea1b28a76aeba74744148b15099254d918671Owen Lin public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, 304666ea1b28a76aeba74744148b15099254d918671Owen Lin Uri uri, ContentResolver cr, ParcelFileDescriptor pfd, 305666ea1b28a76aeba74744148b15099254d918671Owen Lin BitmapFactory.Options options) { 306666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 307666ea1b28a76aeba74744148b15099254d918671Owen Lin if (pfd == null) pfd = makeInputStream(uri, cr); 308666ea1b28a76aeba74744148b15099254d918671Owen Lin if (pfd == null) return null; 309666ea1b28a76aeba74744148b15099254d918671Owen Lin if (options == null) options = new BitmapFactory.Options(); 310666ea1b28a76aeba74744148b15099254d918671Owen Lin 311666ea1b28a76aeba74744148b15099254d918671Owen Lin FileDescriptor fd = pfd.getFileDescriptor(); 312666ea1b28a76aeba74744148b15099254d918671Owen Lin options.inJustDecodeBounds = true; 313666ea1b28a76aeba74744148b15099254d918671Owen Lin BitmapManager.instance().decodeFileDescriptor(fd, options); 314666ea1b28a76aeba74744148b15099254d918671Owen Lin if (options.mCancel || options.outWidth == -1 315666ea1b28a76aeba74744148b15099254d918671Owen Lin || options.outHeight == -1) { 316666ea1b28a76aeba74744148b15099254d918671Owen Lin return null; 317666ea1b28a76aeba74744148b15099254d918671Owen Lin } 318666ea1b28a76aeba74744148b15099254d918671Owen Lin options.inSampleSize = computeSampleSize( 319666ea1b28a76aeba74744148b15099254d918671Owen Lin options, minSideLength, maxNumOfPixels); 320666ea1b28a76aeba74744148b15099254d918671Owen Lin options.inJustDecodeBounds = false; 321666ea1b28a76aeba74744148b15099254d918671Owen Lin 322666ea1b28a76aeba74744148b15099254d918671Owen Lin options.inDither = false; 323666ea1b28a76aeba74744148b15099254d918671Owen Lin options.inPreferredConfig = Bitmap.Config.ARGB_8888; 324666ea1b28a76aeba74744148b15099254d918671Owen Lin return BitmapManager.instance().decodeFileDescriptor(fd, options); 325666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (OutOfMemoryError ex) { 326666ea1b28a76aeba74744148b15099254d918671Owen Lin Log.e(TAG, "Got oom exception ", ex); 327666ea1b28a76aeba74744148b15099254d918671Owen Lin return null; 328666ea1b28a76aeba74744148b15099254d918671Owen Lin } finally { 329666ea1b28a76aeba74744148b15099254d918671Owen Lin closeSilently(pfd); 330666ea1b28a76aeba74744148b15099254d918671Owen Lin } 331666ea1b28a76aeba74744148b15099254d918671Owen Lin } 332666ea1b28a76aeba74744148b15099254d918671Owen Lin 333666ea1b28a76aeba74744148b15099254d918671Owen Lin private static ParcelFileDescriptor makeInputStream( 334666ea1b28a76aeba74744148b15099254d918671Owen Lin Uri uri, ContentResolver cr) { 335666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 336666ea1b28a76aeba74744148b15099254d918671Owen Lin return cr.openFileDescriptor(uri, "r"); 337666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (IOException ex) { 338666ea1b28a76aeba74744148b15099254d918671Owen Lin return null; 339666ea1b28a76aeba74744148b15099254d918671Owen Lin } 340666ea1b28a76aeba74744148b15099254d918671Owen Lin } 341666ea1b28a76aeba74744148b15099254d918671Owen Lin 342666ea1b28a76aeba74744148b15099254d918671Owen Lin public static synchronized OnClickListener getNullOnClickListener() { 343666ea1b28a76aeba74744148b15099254d918671Owen Lin if (sNullOnClickListener == null) { 344666ea1b28a76aeba74744148b15099254d918671Owen Lin sNullOnClickListener = new OnClickListener() { 345666ea1b28a76aeba74744148b15099254d918671Owen Lin public void onClick(View v) { 346666ea1b28a76aeba74744148b15099254d918671Owen Lin } 347666ea1b28a76aeba74744148b15099254d918671Owen Lin }; 348666ea1b28a76aeba74744148b15099254d918671Owen Lin } 349666ea1b28a76aeba74744148b15099254d918671Owen Lin return sNullOnClickListener; 350666ea1b28a76aeba74744148b15099254d918671Owen Lin } 351666ea1b28a76aeba74744148b15099254d918671Owen Lin 352666ea1b28a76aeba74744148b15099254d918671Owen Lin public static void Assert(boolean cond) { 353666ea1b28a76aeba74744148b15099254d918671Owen Lin if (!cond) { 354666ea1b28a76aeba74744148b15099254d918671Owen Lin throw new AssertionError(); 355666ea1b28a76aeba74744148b15099254d918671Owen Lin } 356666ea1b28a76aeba74744148b15099254d918671Owen Lin } 357666ea1b28a76aeba74744148b15099254d918671Owen Lin 358666ea1b28a76aeba74744148b15099254d918671Owen Lin public static boolean equals(String a, String b) { 359666ea1b28a76aeba74744148b15099254d918671Owen Lin // return true if both string are null or the content equals 360666ea1b28a76aeba74744148b15099254d918671Owen Lin return a == b || a.equals(b); 361666ea1b28a76aeba74744148b15099254d918671Owen Lin } 362666ea1b28a76aeba74744148b15099254d918671Owen Lin 363666ea1b28a76aeba74744148b15099254d918671Owen Lin private static class BackgroundJob 364666ea1b28a76aeba74744148b15099254d918671Owen Lin extends MonitoredActivity.LifeCycleAdapter implements Runnable { 365666ea1b28a76aeba74744148b15099254d918671Owen Lin 366666ea1b28a76aeba74744148b15099254d918671Owen Lin private final MonitoredActivity mActivity; 367666ea1b28a76aeba74744148b15099254d918671Owen Lin private final ProgressDialog mDialog; 368666ea1b28a76aeba74744148b15099254d918671Owen Lin private final Runnable mJob; 369666ea1b28a76aeba74744148b15099254d918671Owen Lin private final Handler mHandler; 370666ea1b28a76aeba74744148b15099254d918671Owen Lin private final Runnable mCleanupRunner = new Runnable() { 371666ea1b28a76aeba74744148b15099254d918671Owen Lin public void run() { 372666ea1b28a76aeba74744148b15099254d918671Owen Lin mActivity.removeLifeCycleListener(BackgroundJob.this); 373666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mDialog.getWindow() != null) mDialog.dismiss(); 374666ea1b28a76aeba74744148b15099254d918671Owen Lin } 375666ea1b28a76aeba74744148b15099254d918671Owen Lin }; 376666ea1b28a76aeba74744148b15099254d918671Owen Lin 377666ea1b28a76aeba74744148b15099254d918671Owen Lin public BackgroundJob(MonitoredActivity activity, Runnable job, 378666ea1b28a76aeba74744148b15099254d918671Owen Lin ProgressDialog dialog, Handler handler) { 379666ea1b28a76aeba74744148b15099254d918671Owen Lin mActivity = activity; 380666ea1b28a76aeba74744148b15099254d918671Owen Lin mDialog = dialog; 381666ea1b28a76aeba74744148b15099254d918671Owen Lin mJob = job; 382666ea1b28a76aeba74744148b15099254d918671Owen Lin mActivity.addLifeCycleListener(this); 383666ea1b28a76aeba74744148b15099254d918671Owen Lin mHandler = handler; 384666ea1b28a76aeba74744148b15099254d918671Owen Lin } 385666ea1b28a76aeba74744148b15099254d918671Owen Lin 386666ea1b28a76aeba74744148b15099254d918671Owen Lin public void run() { 387666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 388666ea1b28a76aeba74744148b15099254d918671Owen Lin mJob.run(); 389666ea1b28a76aeba74744148b15099254d918671Owen Lin } finally { 390666ea1b28a76aeba74744148b15099254d918671Owen Lin mHandler.post(mCleanupRunner); 391666ea1b28a76aeba74744148b15099254d918671Owen Lin } 392666ea1b28a76aeba74744148b15099254d918671Owen Lin } 393666ea1b28a76aeba74744148b15099254d918671Owen Lin 394666ea1b28a76aeba74744148b15099254d918671Owen Lin 395666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 396666ea1b28a76aeba74744148b15099254d918671Owen Lin public void onActivityDestroyed(MonitoredActivity activity) { 397666ea1b28a76aeba74744148b15099254d918671Owen Lin // We get here only when the onDestroyed being called before 398666ea1b28a76aeba74744148b15099254d918671Owen Lin // the mCleanupRunner. So, run it now and remove it from the queue 399666ea1b28a76aeba74744148b15099254d918671Owen Lin mCleanupRunner.run(); 400666ea1b28a76aeba74744148b15099254d918671Owen Lin mHandler.removeCallbacks(mCleanupRunner); 401666ea1b28a76aeba74744148b15099254d918671Owen Lin } 402666ea1b28a76aeba74744148b15099254d918671Owen Lin 403666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 404666ea1b28a76aeba74744148b15099254d918671Owen Lin public void onActivityStopped(MonitoredActivity activity) { 405666ea1b28a76aeba74744148b15099254d918671Owen Lin mDialog.hide(); 406666ea1b28a76aeba74744148b15099254d918671Owen Lin } 407666ea1b28a76aeba74744148b15099254d918671Owen Lin 408666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 409666ea1b28a76aeba74744148b15099254d918671Owen Lin public void onActivityStarted(MonitoredActivity activity) { 410666ea1b28a76aeba74744148b15099254d918671Owen Lin mDialog.show(); 411666ea1b28a76aeba74744148b15099254d918671Owen Lin } 412666ea1b28a76aeba74744148b15099254d918671Owen Lin } 413666ea1b28a76aeba74744148b15099254d918671Owen Lin 414666ea1b28a76aeba74744148b15099254d918671Owen Lin public static void startBackgroundJob(MonitoredActivity activity, 415666ea1b28a76aeba74744148b15099254d918671Owen Lin String title, String message, Runnable job, Handler handler) { 416666ea1b28a76aeba74744148b15099254d918671Owen Lin // Make the progress dialog uncancelable, so that we can gurantee 417666ea1b28a76aeba74744148b15099254d918671Owen Lin // the thread will be done before the activity getting destroyed. 418666ea1b28a76aeba74744148b15099254d918671Owen Lin ProgressDialog dialog = ProgressDialog.show( 419666ea1b28a76aeba74744148b15099254d918671Owen Lin activity, title, message, true, false); 420666ea1b28a76aeba74744148b15099254d918671Owen Lin new Thread(new BackgroundJob(activity, job, dialog, handler)).start(); 421666ea1b28a76aeba74744148b15099254d918671Owen Lin } 422666ea1b28a76aeba74744148b15099254d918671Owen Lin 423666ea1b28a76aeba74744148b15099254d918671Owen Lin // Returns an intent which is used for "set as" menu items. 424666ea1b28a76aeba74744148b15099254d918671Owen Lin public static Intent createSetAsIntent(IImage image) { 425666ea1b28a76aeba74744148b15099254d918671Owen Lin Uri u = image.fullSizeImageUri(); 426666ea1b28a76aeba74744148b15099254d918671Owen Lin Intent intent = new Intent(Intent.ACTION_ATTACH_DATA); 427666ea1b28a76aeba74744148b15099254d918671Owen Lin intent.setDataAndType(u, image.getMimeType()); 428666ea1b28a76aeba74744148b15099254d918671Owen Lin intent.putExtra("mimeType", image.getMimeType()); 429666ea1b28a76aeba74744148b15099254d918671Owen Lin return intent; 430666ea1b28a76aeba74744148b15099254d918671Owen Lin } 431666ea1b28a76aeba74744148b15099254d918671Owen Lin 432666ea1b28a76aeba74744148b15099254d918671Owen Lin // Returns Options that set the puregeable flag for Bitmap decode. 433666ea1b28a76aeba74744148b15099254d918671Owen Lin public static BitmapFactory.Options createNativeAllocOptions() { 434ab2a61a77d1b309c19e76e4370a8dae6910d74d0Carl Shapiro return new BitmapFactory.Options(); 435666ea1b28a76aeba74744148b15099254d918671Owen Lin } 436666ea1b28a76aeba74744148b15099254d918671Owen Lin} 437