Util.java revision cd972b0cd67d7a45084d9757ebd49b8f22989edd
1101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin/* 2101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Copyright (C) 2009 The Android Open Source Project 3101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * 4101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * you may not use this file except in compliance with the License. 6101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * You may obtain a copy of the License at 7101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * 8101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * http://www.apache.org/licenses/LICENSE-2.0 9101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * 10101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Unless required by applicable law or agreed to in writing, software 11101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * See the License for the specific language governing permissions and 14101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * limitations under the License. 15101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */ 16101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 17937fc48b37fafe3ffc8f4b52bd9a171bbb4d3a37Owen Linpackage com.android.camera; 18101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 193f3c857e3f34650c15d764810335024654b0fcc3Owen Linimport android.app.Activity; 203f3c857e3f34650c15d764810335024654b0fcc3Owen Linimport android.app.AlertDialog; 21601ce56b034f111b2875e7636776f2f359f6a156Owen Linimport android.app.ProgressDialog; 22c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Changimport android.content.ContentResolver; 233f3c857e3f34650c15d764810335024654b0fcc3Owen Linimport android.content.DialogInterface; 24bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Changimport android.content.Intent; 25101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.Bitmap; 26101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.BitmapFactory; 2796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Changimport android.graphics.Canvas; 28101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.Matrix; 2996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Changimport android.graphics.Rect; 30101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.media.MediaMetadataRetriever; 31c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Changimport android.net.Uri; 32482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Linimport android.os.Handler; 33101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.os.ParcelFileDescriptor; 34101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.util.Log; 35601ce56b034f111b2875e7636776f2f359f6a156Owen Linimport android.view.View; 36601ce56b034f111b2875e7636776f2f359f6a156Owen Linimport android.view.View.OnClickListener; 372c6c6174e2363fccb4e4f29b76290e99234fe140Owen Linimport android.view.animation.Animation; 382c6c6174e2363fccb4e4f29b76290e99234fe140Owen Linimport android.view.animation.TranslateAnimation; 39101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 403f3c857e3f34650c15d764810335024654b0fcc3Owen Linimport com.android.camera.gallery.IImage; 413f3c857e3f34650c15d764810335024654b0fcc3Owen Lin 42101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport java.io.ByteArrayOutputStream; 43101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport java.io.Closeable; 44c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Changimport java.io.FileDescriptor; 45d30b5877fbdedcebc0af5cccffddccfe9b11cb0bOwen Linimport java.io.IOException; 46101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 47101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin/** 48101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Collection of utility functions used in this package. 49101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */ 50101d528d59f447847d5c6b7578642132c2b76f4fOwen Linpublic class Util { 5134fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang private static final String TAG = "Util"; 522c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin public static final int DIRECTION_LEFT = 0; 532c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin public static final int DIRECTION_RIGHT = 1; 542c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin public static final int DIRECTION_UP = 2; 552c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin public static final int DIRECTION_DOWN = 3; 56101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 57601ce56b034f111b2875e7636776f2f359f6a156Owen Lin private static OnClickListener sNullOnClickListener; 58601ce56b034f111b2875e7636776f2f359f6a156Owen Lin 59101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin private Util() { 60101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 61101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 62101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin // Rotates the bitmap by the specified degree. 63101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin // If a new bitmap is created, the original bitmap is recycled. 64101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin public static Bitmap rotate(Bitmap b, int degrees) { 65101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin if (degrees != 0 && b != null) { 66101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin Matrix m = new Matrix(); 67101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin m.setRotate(degrees, 68101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin (float) b.getWidth() / 2, (float) b.getHeight() / 2); 69101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin try { 70101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin Bitmap b2 = Bitmap.createBitmap( 71101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin b, 0, 0, b.getWidth(), b.getHeight(), m, true); 72101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin if (b != b2) { 73101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin b.recycle(); 74101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin b = b2; 75101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 76101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } catch (OutOfMemoryError ex) { 77101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin // We have no memory to rotate. Return the original bitmap. 78101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 79101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 80101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin return b; 81101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 82101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 83101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin /* 84ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang * Compute the sample size as a function of minSideLength 85ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang * and maxNumOfPixels. 863c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * minSideLength is used to specify that minimal width or height of a 873c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * bitmap. 883c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * maxNumOfPixels is used to specify the maximal size in pixels that is 893c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * tolerable in terms of memory usage. 90ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang * 91ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang * The function returns a sample size based on the constraints. 92ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang * Both size and minSideLength can be passed in as IImage.UNCONSTRAINED, 93ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang * which indicates no care of the corresponding constraint. 94ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang * The functions prefers returning a sample size that 95ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang * generates a smaller bitmap, unless minSideLength = IImage.UNCONSTRAINED. 963c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * 973c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * Also, the function rounds up the sample size to a power of 2 or multiple 983c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * of 8 because BitmapFactory only honors sample size this way. 993c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * For example, BitmapFactory downsamples an image by 2 even though the 1003c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * request is 3. So we round up the sample size to avoid OOM. 101101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */ 102ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang public static int computeSampleSize(BitmapFactory.Options options, 103ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang int minSideLength, int maxNumOfPixels) { 1043c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen int initialSize = computeInitialSampleSize(options, minSideLength, 1053c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen maxNumOfPixels); 1063c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen 1073c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen int roundedSize; 108522e836abc90bcb2d4e7a4ac37e269154d06c715Chih-Chung Chang if (initialSize <= 8) { 1093c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen roundedSize = 1; 1103c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen while (roundedSize < initialSize) { 1113c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen roundedSize <<= 1; 1123c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen } 1133c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen } else { 1143c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen roundedSize = (initialSize + 7) / 8 * 8; 1153c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen } 1163c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen 1173c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen return roundedSize; 1183c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen } 1193c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen 1203c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen private static int computeInitialSampleSize(BitmapFactory.Options options, 1213c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen int minSideLength, int maxNumOfPixels) { 122ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang double w = options.outWidth; 123ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang double h = options.outHeight; 124ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang 125ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang int lowerBound = (maxNumOfPixels == IImage.UNCONSTRAINED) ? 1 : 126ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); 127ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang int upperBound = (minSideLength == IImage.UNCONSTRAINED) ? 128 : 128ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang (int) Math.min(Math.floor(w / minSideLength), 129ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang Math.floor(h / minSideLength)); 130ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang 131f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen if (upperBound < lowerBound) { 132f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen // return the larger one when there is no overlapping zone. 133f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen return lowerBound; 134f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen } 135f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen 136ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang if ((maxNumOfPixels == IImage.UNCONSTRAINED) && 137ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang (minSideLength == IImage.UNCONSTRAINED)) { 138ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang return 1; 139ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang } else if (minSideLength == IImage.UNCONSTRAINED) { 140ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang return lowerBound; 141ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang } else { 142ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang return upperBound; 143101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 144101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 145101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 14634fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang // Whether we should recycle the input (unless the output is the input). 147522e836abc90bcb2d4e7a4ac37e269154d06c715Chih-Chung Chang public static final boolean RECYCLE_INPUT = true; 148522e836abc90bcb2d4e7a4ac37e269154d06c715Chih-Chung Chang public static final boolean NO_RECYCLE_INPUT = false; 14934fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang 15096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang public static Bitmap transform(Matrix scaler, 15196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang Bitmap source, 15296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang int targetWidth, 15396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang int targetHeight, 15434fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang boolean scaleUp, 15534fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang boolean recycle) { 15696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang int deltaX = source.getWidth() - targetWidth; 15796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang int deltaY = source.getHeight() - targetHeight; 15896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang if (!scaleUp && (deltaX < 0 || deltaY < 0)) { 15996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang /* 16096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang * In this case the bitmap is smaller, at least in one dimension, 16196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang * than the target. Transform it by placing as much of the image 16296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang * as possible into the target and leaving the top/bottom or 16396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang * left/right (or both) black. 16496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang */ 16596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang Bitmap b2 = Bitmap.createBitmap(targetWidth, targetHeight, 16696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang Bitmap.Config.ARGB_8888); 16796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang Canvas c = new Canvas(b2); 16896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang 16996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang int deltaXHalf = Math.max(0, deltaX / 2); 17096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang int deltaYHalf = Math.max(0, deltaY / 2); 17196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang Rect src = new Rect( 17296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang deltaXHalf, 17396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang deltaYHalf, 17496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang deltaXHalf + Math.min(targetWidth, source.getWidth()), 17596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang deltaYHalf + Math.min(targetHeight, source.getHeight())); 17696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang int dstX = (targetWidth - src.width()) / 2; 17796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang int dstY = (targetHeight - src.height()) / 2; 17896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang Rect dst = new Rect( 17996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang dstX, 18096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang dstY, 18196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang targetWidth - dstX, 18296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang targetHeight - dstY); 18396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang c.drawBitmap(source, src, dst, null); 18434fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang if (recycle) { 18534fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang source.recycle(); 18634fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang } 18796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang return b2; 18896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang } 18996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang float bitmapWidthF = source.getWidth(); 19096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang float bitmapHeightF = source.getHeight(); 19196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang 19296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang float bitmapAspect = bitmapWidthF / bitmapHeightF; 19358e94eddd371a9bb7c04936dbeb99615fd1a0c2cChih-Chung Chang float viewAspect = (float) targetWidth / targetHeight; 19496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang 19596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang if (bitmapAspect > viewAspect) { 19696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang float scale = targetHeight / bitmapHeightF; 19796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang if (scale < .9F || scale > 1F) { 19896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang scaler.setScale(scale, scale); 19996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang } else { 20096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang scaler = null; 20196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang } 20296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang } else { 20396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang float scale = targetWidth / bitmapWidthF; 20496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang if (scale < .9F || scale > 1F) { 20596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang scaler.setScale(scale, scale); 20696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang } else { 20796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang scaler = null; 20896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang } 20996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang } 21096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang 21196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang Bitmap b1; 21296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang if (scaler != null) { 21396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang // this is used for minithumb and crop, so we want to filter here. 21496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang b1 = Bitmap.createBitmap(source, 0, 0, 21596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang source.getWidth(), source.getHeight(), scaler, true); 21696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang } else { 21796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang b1 = source; 21896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang } 21996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang 22034fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang if (recycle && b1 != source) { 22134fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang source.recycle(); 22234fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang } 22334fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang 22496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang int dx1 = Math.max(0, b1.getWidth() - targetWidth); 22596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang int dy1 = Math.max(0, b1.getHeight() - targetHeight); 22696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang 22796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang Bitmap b2 = Bitmap.createBitmap( 22896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang b1, 22996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang dx1 / 2, 23096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang dy1 / 2, 23196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang targetWidth, 23296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang targetHeight); 23396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang 23434fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang if (b2 != b1) { 23534fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang if (recycle || b1 != source) { 23634fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang b1.recycle(); 23734fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang } 23896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang } 23996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang 24096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang return b2; 24196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang } 24296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang 243101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin /** 24434fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang * Creates a centered bitmap of the desired size. 245101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * @param source 24634fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang * @param recycle whether we want to recycle the input 247101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */ 248101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin public static Bitmap extractMiniThumb( 249101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin Bitmap source, int width, int height, boolean recycle) { 250101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin if (source == null) { 251101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin return null; 252101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 253101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 254101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin float scale; 255101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin if (source.getWidth() < source.getHeight()) { 256101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin scale = width / (float) source.getWidth(); 257101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } else { 258101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin scale = height / (float) source.getHeight(); 259101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 260101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin Matrix matrix = new Matrix(); 261101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin matrix.setScale(scale, scale); 262522e836abc90bcb2d4e7a4ac37e269154d06c715Chih-Chung Chang Bitmap miniThumbnail = transform(matrix, source, width, height, 263697ea6ef1d84bc707881e736ff1148e3a30ed445Chih-Chung Chang true, recycle); 264101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin return miniThumbnail; 265101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 266101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 267101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin /** 268101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Creates a byte[] for a given bitmap of the desired size. Recycles the 269101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * input bitmap. 270101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */ 271101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin public static byte[] miniThumbData(Bitmap source) { 272101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin if (source == null) return null; 273101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 274101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin Bitmap miniThumbnail = extractMiniThumb( 2750a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang source, IImage.MINI_THUMB_TARGET_SIZE, 27634fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang IImage.MINI_THUMB_TARGET_SIZE, 27734fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang Util.RECYCLE_INPUT); 278101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 279101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin ByteArrayOutputStream miniOutStream = new ByteArrayOutputStream(); 280101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin miniThumbnail.compress(Bitmap.CompressFormat.JPEG, 75, miniOutStream); 281101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin miniThumbnail.recycle(); 282101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 283101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin try { 284101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin miniOutStream.close(); 285101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin byte [] data = miniOutStream.toByteArray(); 286101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin return data; 287101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } catch (java.io.IOException ex) { 288101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin Log.e(TAG, "got exception ex " + ex); 289101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 290101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin return null; 291101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 292101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 293101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin /** 294101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Create a video thumbnail for a video. May return null if the video is 295101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * corrupt. 296101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * 297101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * @param filePath 298101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */ 299101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin public static Bitmap createVideoThumbnail(String filePath) { 300101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin Bitmap bitmap = null; 301101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 302101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin try { 303101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY); 304101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin retriever.setDataSource(filePath); 305101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin bitmap = retriever.captureFrame(); 306101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } catch (IllegalArgumentException ex) { 307101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin // Assume this is a corrupt video file 308101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } catch (RuntimeException ex) { 309101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin // Assume this is a corrupt video file. 310101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } finally { 311101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin try { 312101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin retriever.release(); 313101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } catch (RuntimeException ex) { 314101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin // Ignore failures while cleaning up. 315101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 316101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 317101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin return bitmap; 318101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 319101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 320bbc2f2f15a865cf0330cd78a6ea67177c5863b3bOwen Lin public static <T> int indexOf(T [] array, T s) { 321101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin for (int i = 0; i < array.length; i++) { 322101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin if (array[i].equals(s)) { 323101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin return i; 324101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 325101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 326101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin return -1; 327101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 328101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 329724e9b3db93677b753c1267a716e30e6cf5ff3b6Chih-Chung Chang public static void closeSilently(Closeable c) { 330101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin if (c == null) return; 331101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin try { 332101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin c.close(); 333101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } catch (Throwable t) { 334101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin // do nothing 335101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 336101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 337101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 338724e9b3db93677b753c1267a716e30e6cf5ff3b6Chih-Chung Chang public static void closeSilently(ParcelFileDescriptor c) { 339101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin if (c == null) return; 340101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin try { 341101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin c.close(); 342101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } catch (Throwable t) { 343101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin // do nothing 344101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 345101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 346101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 347c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang /** 348c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang * Make a bitmap from a given Uri. 349c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang * 350c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang * @param uri 351c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang */ 352ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, 353ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang Uri uri, ContentResolver cr) { 354ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang return makeBitmap(minSideLength, maxNumOfPixels, uri, cr, 355ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang IImage.NO_NATIVE); 3564250e214f539a3caee1434889c5660d594b45dfdChih-Chung Chang } 357f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen 358ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, 359ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang Uri uri, ContentResolver cr, boolean useNative) { 360c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang ParcelFileDescriptor input = null; 361c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang try { 362c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang input = cr.openFileDescriptor(uri, "r"); 3634250e214f539a3caee1434889c5660d594b45dfdChih-Chung Chang BitmapFactory.Options options = null; 3644250e214f539a3caee1434889c5660d594b45dfdChih-Chung Chang if (useNative) { 3654250e214f539a3caee1434889c5660d594b45dfdChih-Chung Chang options = createNativeAllocOptions(); 3664250e214f539a3caee1434889c5660d594b45dfdChih-Chung Chang } 367ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang return makeBitmap(minSideLength, maxNumOfPixels, uri, cr, input, 368ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang options); 369c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang } catch (IOException ex) { 370c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang return null; 371c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang } finally { 372724e9b3db93677b753c1267a716e30e6cf5ff3b6Chih-Chung Chang closeSilently(input); 373c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang } 374c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang } 375c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang 376ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, 3774250e214f539a3caee1434889c5660d594b45dfdChih-Chung Chang ParcelFileDescriptor pfd, boolean useNative) { 3784250e214f539a3caee1434889c5660d594b45dfdChih-Chung Chang BitmapFactory.Options options = null; 3794250e214f539a3caee1434889c5660d594b45dfdChih-Chung Chang if (useNative) { 3804250e214f539a3caee1434889c5660d594b45dfdChih-Chung Chang options = createNativeAllocOptions(); 3814250e214f539a3caee1434889c5660d594b45dfdChih-Chung Chang } 382ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang return makeBitmap(minSideLength, maxNumOfPixels, null, null, pfd, 383ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang options); 3844250e214f539a3caee1434889c5660d594b45dfdChih-Chung Chang } 385f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen 386ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, 387ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang Uri uri, ContentResolver cr, ParcelFileDescriptor pfd, 388c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang BitmapFactory.Options options) { 389c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang try { 390c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang if (pfd == null) pfd = makeInputStream(uri, cr); 391c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang if (pfd == null) return null; 392c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang if (options == null) options = new BitmapFactory.Options(); 393c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang 394c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang FileDescriptor fd = pfd.getFileDescriptor(); 395ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang options.inJustDecodeBounds = true; 396ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang BitmapManager.instance().decodeFileDescriptor(fd, options); 397ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang if (options.mCancel || options.outWidth == -1 398ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang || options.outHeight == -1) { 399ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang return null; 400c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang } 401ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang options.inSampleSize = computeSampleSize( 402ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang options, minSideLength, maxNumOfPixels); 403ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang options.inJustDecodeBounds = false; 404c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang 405c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang options.inDither = false; 406c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang options.inPreferredConfig = Bitmap.Config.ARGB_8888; 407cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang return BitmapManager.instance().decodeFileDescriptor(fd, options); 408c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang } catch (OutOfMemoryError ex) { 409c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang Log.e(TAG, "Got oom exception ", ex); 410c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang return null; 411c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang } finally { 412724e9b3db93677b753c1267a716e30e6cf5ff3b6Chih-Chung Chang closeSilently(pfd); 413c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang } 414cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang } 415cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang 416cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang public static Bitmap makeBitmap(byte[] jpegData, int maxNumOfPixels) { 417cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang try { 418cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang BitmapFactory.Options options = new BitmapFactory.Options(); 419cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options.inJustDecodeBounds = true; 420cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length, 421cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options); 422cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang if (options.mCancel || options.outWidth == -1 423cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang || options.outHeight == -1) { 424cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang return null; 425cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang } 426cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options.inSampleSize = computeSampleSize( 427cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options, IImage.UNCONSTRAINED, maxNumOfPixels); 428cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options.inJustDecodeBounds = false; 429cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang 430cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options.inDither = false; 431cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options.inPreferredConfig = Bitmap.Config.ARGB_8888; 432cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang return BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length, 433cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options); 434cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang } catch (OutOfMemoryError ex) { 435cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang Log.e(TAG, "Got oom exception ", ex); 436cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang return null; 437cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang } 438c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang } 439c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang 440c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang private static ParcelFileDescriptor makeInputStream( 441c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang Uri uri, ContentResolver cr) { 442c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang try { 443c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang return cr.openFileDescriptor(uri, "r"); 444c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang } catch (IOException ex) { 445c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang return null; 446c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang } 447c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang } 448fa021af9397011cf180003139e80a88902c4b70aChih-Chung Chang 4494177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang public static synchronized OnClickListener getNullOnClickListener() { 450601ce56b034f111b2875e7636776f2f359f6a156Owen Lin if (sNullOnClickListener == null) { 451601ce56b034f111b2875e7636776f2f359f6a156Owen Lin sNullOnClickListener = new OnClickListener() { 452601ce56b034f111b2875e7636776f2f359f6a156Owen Lin public void onClick(View v) { 453601ce56b034f111b2875e7636776f2f359f6a156Owen Lin } 454601ce56b034f111b2875e7636776f2f359f6a156Owen Lin }; 455601ce56b034f111b2875e7636776f2f359f6a156Owen Lin } 456601ce56b034f111b2875e7636776f2f359f6a156Owen Lin return sNullOnClickListener; 457601ce56b034f111b2875e7636776f2f359f6a156Owen Lin } 458341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang 459341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang public static void Assert(boolean cond) { 460341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang if (!cond) { 461341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang throw new AssertionError(); 462341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang } 463341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang } 464059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin 465b0e1282810ec68fd7585beb9ab9afab9bcafe1bdOwen Lin public static boolean equals(String a, String b) { 466b0e1282810ec68fd7585beb9ab9afab9bcafe1bdOwen Lin // return true if both string are null or the content equals 467b0e1282810ec68fd7585beb9ab9afab9bcafe1bdOwen Lin return a == b || a.equals(b); 468b0e1282810ec68fd7585beb9ab9afab9bcafe1bdOwen Lin } 469482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin 470482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin private static class BackgroundJob 471482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin extends MonitoredActivity.LifeCycleAdapter implements Runnable { 472482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin 473482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin private final MonitoredActivity mActivity; 474482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin private final ProgressDialog mDialog; 475482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin private final Runnable mJob; 476482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin private final Handler mHandler; 4776fa5404fd6c34d401c56accd059a706d8a832812Owen Lin private final Runnable mCleanupRunner = new Runnable() { 4786fa5404fd6c34d401c56accd059a706d8a832812Owen Lin public void run() { 4796fa5404fd6c34d401c56accd059a706d8a832812Owen Lin mActivity.removeLifeCycleListener(BackgroundJob.this); 4806fa5404fd6c34d401c56accd059a706d8a832812Owen Lin if (mDialog.getWindow() != null) mDialog.dismiss(); 4816fa5404fd6c34d401c56accd059a706d8a832812Owen Lin } 4826fa5404fd6c34d401c56accd059a706d8a832812Owen Lin }; 483482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin 484482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin public BackgroundJob(MonitoredActivity activity, Runnable job, 485482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin ProgressDialog dialog, Handler handler) { 486482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin mActivity = activity; 487482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin mDialog = dialog; 488482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin mJob = job; 489482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin mActivity.addLifeCycleListener(this); 490482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin mHandler = handler; 491482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin } 492482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin 493482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin public void run() { 494482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin try { 495482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin mJob.run(); 496482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin } finally { 4976fa5404fd6c34d401c56accd059a706d8a832812Owen Lin mHandler.post(mCleanupRunner); 498482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin } 499482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin } 500482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin 5016fa5404fd6c34d401c56accd059a706d8a832812Owen Lin 5026fa5404fd6c34d401c56accd059a706d8a832812Owen Lin @Override 5036fa5404fd6c34d401c56accd059a706d8a832812Owen Lin public void onActivityDestroyed(MonitoredActivity activity) { 5046fa5404fd6c34d401c56accd059a706d8a832812Owen Lin // We get here only when the onDestroyed being called before 5056fa5404fd6c34d401c56accd059a706d8a832812Owen Lin // the mCleanupRunner. So, run it now and remove it from the queue 5066fa5404fd6c34d401c56accd059a706d8a832812Owen Lin mCleanupRunner.run(); 5076fa5404fd6c34d401c56accd059a706d8a832812Owen Lin mHandler.removeCallbacks(mCleanupRunner); 5086fa5404fd6c34d401c56accd059a706d8a832812Owen Lin } 5096fa5404fd6c34d401c56accd059a706d8a832812Owen Lin 510482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin @Override 511482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin public void onActivityStopped(MonitoredActivity activity) { 512482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin mDialog.hide(); 513482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin } 514482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin 515482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin @Override 516482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin public void onActivityStarted(MonitoredActivity activity) { 517482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin mDialog.show(); 518482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin } 519482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin } 520482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin 521482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin public static void startBackgroundJob(MonitoredActivity activity, 522482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin String title, String message, Runnable job, Handler handler) { 523482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin // Make the progress dialog uncancelable, so that we can gurantee 524482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin // the thread will be done before the activity getting destroyed. 525482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin ProgressDialog dialog = ProgressDialog.show( 526482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin activity, title, message, true, false); 527482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin new Thread(new BackgroundJob(activity, job, dialog, handler)).start(); 528482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin } 529bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang 530bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang // Returns an intent which is used for "set as" menu items. 531bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang public static Intent createSetAsIntent(IImage image) { 532bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang Uri u = image.fullSizeImageUri(); 533bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang Intent intent = new Intent(Intent.ACTION_ATTACH_DATA); 534bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang intent.setDataAndType(u, image.getMimeType()); 535bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang intent.putExtra("mimeType", image.getMimeType()); 536bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang return intent; 537bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang } 538d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen 539d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen // Returns Options that set the puregeable flag for Bitmap decode. 540026dff889c80763fc322ed03e2d3a76750320138Wei-Ta Chen public static BitmapFactory.Options createNativeAllocOptions() { 541d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen BitmapFactory.Options options = new BitmapFactory.Options(); 542026dff889c80763fc322ed03e2d3a76750320138Wei-Ta Chen options.inNativeAlloc = true; 543d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen return options; 544d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen } 5453f3c857e3f34650c15d764810335024654b0fcc3Owen Lin 5463f3c857e3f34650c15d764810335024654b0fcc3Owen Lin public static void showFatalErrorAndFinish( 5473f3c857e3f34650c15d764810335024654b0fcc3Owen Lin final Activity activity, String title, String message) { 5483f3c857e3f34650c15d764810335024654b0fcc3Owen Lin DialogInterface.OnClickListener buttonListener = 5493f3c857e3f34650c15d764810335024654b0fcc3Owen Lin new DialogInterface.OnClickListener() { 5503f3c857e3f34650c15d764810335024654b0fcc3Owen Lin public void onClick(DialogInterface dialog, int which) { 5513f3c857e3f34650c15d764810335024654b0fcc3Owen Lin activity.finish(); 5523f3c857e3f34650c15d764810335024654b0fcc3Owen Lin } 5533f3c857e3f34650c15d764810335024654b0fcc3Owen Lin }; 5543f3c857e3f34650c15d764810335024654b0fcc3Owen Lin new AlertDialog.Builder(activity) 5553f3c857e3f34650c15d764810335024654b0fcc3Owen Lin .setCancelable(false) 5563f3c857e3f34650c15d764810335024654b0fcc3Owen Lin .setIcon(android.R.drawable.ic_dialog_alert) 5573f3c857e3f34650c15d764810335024654b0fcc3Owen Lin .setTitle(title) 5583f3c857e3f34650c15d764810335024654b0fcc3Owen Lin .setMessage(message) 5593f3c857e3f34650c15d764810335024654b0fcc3Owen Lin .setNeutralButton(R.string.details_ok, buttonListener) 5603f3c857e3f34650c15d764810335024654b0fcc3Owen Lin .show(); 5613f3c857e3f34650c15d764810335024654b0fcc3Owen Lin } 5622c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin 563c1f2e3021bf7b12f2a33561e09bd0ab32530382eOwen Lin public static Animation slideOut(View view, int to) { 5642c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin view.setVisibility(View.INVISIBLE); 5652c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin Animation anim; 5662c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin switch (to) { 5672c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin case DIRECTION_LEFT: 5682c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin anim = new TranslateAnimation(0, -view.getWidth(), 0, 0); 5692c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin break; 5702c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin case DIRECTION_RIGHT: 5712c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin anim = new TranslateAnimation(0, view.getWidth(), 0, 0); 5722c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin break; 5732c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin case DIRECTION_UP: 5742c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin anim = new TranslateAnimation(0, 0, 0, -view.getHeight()); 5752c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin break; 5762c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin case DIRECTION_DOWN: 5772c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin anim = new TranslateAnimation(0, 0, 0, view.getHeight()); 5782c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin break; 5792c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin default: 5802c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin throw new IllegalArgumentException(Integer.toString(to)); 5812c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin } 5822c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin anim.setDuration(500); 5832c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin view.startAnimation(anim); 584c1f2e3021bf7b12f2a33561e09bd0ab32530382eOwen Lin return anim; 5852c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin } 5862c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin 587c1f2e3021bf7b12f2a33561e09bd0ab32530382eOwen Lin public static Animation slideIn(View view, int from) { 5882c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin view.setVisibility(View.VISIBLE); 5892c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin Animation anim; 5902c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin switch (from) { 5912c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin case DIRECTION_LEFT: 5922c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin anim = new TranslateAnimation(-view.getWidth(), 0, 0, 0); 5932c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin break; 5942c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin case DIRECTION_RIGHT: 5952c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin anim = new TranslateAnimation(view.getWidth(), 0, 0, 0); 5962c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin break; 5972c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin case DIRECTION_UP: 5982c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin anim = new TranslateAnimation(0, 0, -view.getHeight(), 0); 5992c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin break; 6002c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin case DIRECTION_DOWN: 6012c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin anim = new TranslateAnimation(0, 0, view.getHeight(), 0); 6022c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin break; 6032c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin default: 6042c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin throw new IllegalArgumentException(Integer.toString(from)); 6052c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin } 6062c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin anim.setDuration(500); 6072c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin view.startAnimation(anim); 608c1f2e3021bf7b12f2a33561e09bd0ab32530382eOwen Lin return anim; 6092c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin } 6102c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin 6112c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin public static <T> T checkNotNull(T object) { 6122c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin if (object == null) throw new NullPointerException(); 6132c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin return object; 6142c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin } 615101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin} 616