Util.java revision 697ea6ef1d84bc707881e736ff1148e3a30ed445
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        Bitmap b = null;
390c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        try {
391c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            if (pfd == null) pfd = makeInputStream(uri, cr);
392c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            if (pfd == null) return null;
393c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            if (options == null) options = new BitmapFactory.Options();
394c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
395c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            FileDescriptor fd = pfd.getFileDescriptor();
396c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            options.inSampleSize = 1;
397ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            options.inJustDecodeBounds = true;
398ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            BitmapManager.instance().decodeFileDescriptor(fd, options);
399ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            if (options.mCancel || options.outWidth == -1
400ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang                    || options.outHeight == -1) {
401ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang                return null;
402c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            }
403ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            options.inSampleSize = computeSampleSize(
404ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang                    options, minSideLength, maxNumOfPixels);
405ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            options.inJustDecodeBounds = false;
406c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
407c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            options.inDither = false;
408c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
409d30b5877fbdedcebc0af5cccffddccfe9b11cb0bOwen Lin            b = BitmapManager.instance().decodeFileDescriptor(fd, options);
410c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } catch (OutOfMemoryError ex) {
411c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            Log.e(TAG, "Got oom exception ", ex);
412c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return null;
413c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } finally {
414724e9b3db93677b753c1267a716e30e6cf5ff3b6Chih-Chung Chang            closeSilently(pfd);
415c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        }
416c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        return b;
417c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    }
418c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
419c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    private static ParcelFileDescriptor makeInputStream(
420c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            Uri uri, ContentResolver cr) {
421c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        try {
422c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return cr.openFileDescriptor(uri, "r");
423c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } catch (IOException ex) {
424c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return null;
425c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        }
426c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    }
427fa021af9397011cf180003139e80a88902c4b70aChih-Chung Chang
4284177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang    public static synchronized OnClickListener getNullOnClickListener() {
429601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        if (sNullOnClickListener == null) {
430601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            sNullOnClickListener = new OnClickListener() {
431601ce56b034f111b2875e7636776f2f359f6a156Owen Lin                public void onClick(View v) {
432601ce56b034f111b2875e7636776f2f359f6a156Owen Lin                }
433601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            };
434601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        }
435601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        return sNullOnClickListener;
436601ce56b034f111b2875e7636776f2f359f6a156Owen Lin    }
437341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang
438341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang    public static void Assert(boolean cond) {
439341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang        if (!cond) {
440341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang            throw new AssertionError();
441341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang        }
442341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang    }
443059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin
444b0e1282810ec68fd7585beb9ab9afab9bcafe1bdOwen Lin    public static boolean equals(String a, String b) {
445b0e1282810ec68fd7585beb9ab9afab9bcafe1bdOwen Lin        // return true if both string are null or the content equals
446b0e1282810ec68fd7585beb9ab9afab9bcafe1bdOwen Lin        return a == b || a.equals(b);
447b0e1282810ec68fd7585beb9ab9afab9bcafe1bdOwen Lin    }
448482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin
449482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin    private static class BackgroundJob
450482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            extends MonitoredActivity.LifeCycleAdapter implements Runnable {
451482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin
452482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        private final MonitoredActivity mActivity;
453482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        private final ProgressDialog mDialog;
454482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        private final Runnable mJob;
455482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        private final Handler mHandler;
4566fa5404fd6c34d401c56accd059a706d8a832812Owen Lin        private final Runnable mCleanupRunner = new Runnable() {
4576fa5404fd6c34d401c56accd059a706d8a832812Owen Lin            public void run() {
4586fa5404fd6c34d401c56accd059a706d8a832812Owen Lin                mActivity.removeLifeCycleListener(BackgroundJob.this);
4596fa5404fd6c34d401c56accd059a706d8a832812Owen Lin                if (mDialog.getWindow() != null) mDialog.dismiss();
4606fa5404fd6c34d401c56accd059a706d8a832812Owen Lin            }
4616fa5404fd6c34d401c56accd059a706d8a832812Owen Lin        };
462482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin
463482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        public BackgroundJob(MonitoredActivity activity, Runnable job,
464482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin                ProgressDialog dialog, Handler handler) {
465482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            mActivity = activity;
466482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            mDialog = dialog;
467482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            mJob = job;
468482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            mActivity.addLifeCycleListener(this);
469482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            mHandler = handler;
470482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        }
471482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin
472482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        public void run() {
473482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            try {
474482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin                mJob.run();
475482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            } finally {
4766fa5404fd6c34d401c56accd059a706d8a832812Owen Lin                mHandler.post(mCleanupRunner);
477482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            }
478482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        }
479482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin
4806fa5404fd6c34d401c56accd059a706d8a832812Owen Lin
4816fa5404fd6c34d401c56accd059a706d8a832812Owen Lin        @Override
4826fa5404fd6c34d401c56accd059a706d8a832812Owen Lin        public void onActivityDestroyed(MonitoredActivity activity) {
4836fa5404fd6c34d401c56accd059a706d8a832812Owen Lin            // We get here only when the onDestroyed being called before
4846fa5404fd6c34d401c56accd059a706d8a832812Owen Lin            // the mCleanupRunner. So, run it now and remove it from the queue
4856fa5404fd6c34d401c56accd059a706d8a832812Owen Lin            mCleanupRunner.run();
4866fa5404fd6c34d401c56accd059a706d8a832812Owen Lin            mHandler.removeCallbacks(mCleanupRunner);
4876fa5404fd6c34d401c56accd059a706d8a832812Owen Lin        }
4886fa5404fd6c34d401c56accd059a706d8a832812Owen Lin
489482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        @Override
490482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        public void onActivityStopped(MonitoredActivity activity) {
491482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            mDialog.hide();
492482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        }
493482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin
494482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        @Override
495482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        public void onActivityStarted(MonitoredActivity activity) {
496482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            mDialog.show();
497482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        }
498482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin    }
499482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin
500482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin    public static void startBackgroundJob(MonitoredActivity activity,
501482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            String title, String message, Runnable job, Handler handler) {
502482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        // Make the progress dialog uncancelable, so that we can gurantee
503482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        // the thread will be done before the activity getting destroyed.
504482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        ProgressDialog dialog = ProgressDialog.show(
505482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin                activity, title, message, true, false);
506482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        new Thread(new BackgroundJob(activity, job, dialog, handler)).start();
507482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin    }
508bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang
509bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang    // Returns an intent which is used for "set as" menu items.
510bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang    public static Intent createSetAsIntent(IImage image) {
511bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang        Uri u = image.fullSizeImageUri();
512bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang        Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
513bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang        intent.setDataAndType(u, image.getMimeType());
514bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang        intent.putExtra("mimeType", image.getMimeType());
515bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang        return intent;
516bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang    }
517d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen
518d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen    // Returns Options that set the puregeable flag for Bitmap decode.
519026dff889c80763fc322ed03e2d3a76750320138Wei-Ta Chen    public static BitmapFactory.Options createNativeAllocOptions() {
520d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen        BitmapFactory.Options options = new BitmapFactory.Options();
521026dff889c80763fc322ed03e2d3a76750320138Wei-Ta Chen        options.inNativeAlloc = true;
522d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen        return options;
523d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen    }
5243f3c857e3f34650c15d764810335024654b0fcc3Owen Lin
5253f3c857e3f34650c15d764810335024654b0fcc3Owen Lin    public static void showFatalErrorAndFinish(
5263f3c857e3f34650c15d764810335024654b0fcc3Owen Lin            final Activity activity, String title, String message) {
5273f3c857e3f34650c15d764810335024654b0fcc3Owen Lin        DialogInterface.OnClickListener buttonListener =
5283f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                new DialogInterface.OnClickListener() {
5293f3c857e3f34650c15d764810335024654b0fcc3Owen Lin            public void onClick(DialogInterface dialog, int which) {
5303f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                activity.finish();
5313f3c857e3f34650c15d764810335024654b0fcc3Owen Lin            }
5323f3c857e3f34650c15d764810335024654b0fcc3Owen Lin        };
5333f3c857e3f34650c15d764810335024654b0fcc3Owen Lin        new AlertDialog.Builder(activity)
5343f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .setCancelable(false)
5353f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .setIcon(android.R.drawable.ic_dialog_alert)
5363f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .setTitle(title)
5373f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .setMessage(message)
5383f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .setNeutralButton(R.string.details_ok, buttonListener)
5393f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .show();
5403f3c857e3f34650c15d764810335024654b0fcc3Owen Lin    }
5412c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin
542c1f2e3021bf7b12f2a33561e09bd0ab32530382eOwen Lin    public static Animation slideOut(View view, int to) {
5432c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin        view.setVisibility(View.INVISIBLE);
5442c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin        Animation anim;
5452c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin        switch (to) {
5462c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin            case DIRECTION_LEFT:
5472c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                anim = new TranslateAnimation(0, -view.getWidth(), 0, 0);
5482c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                break;
5492c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin            case DIRECTION_RIGHT:
5502c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                anim = new TranslateAnimation(0, view.getWidth(), 0, 0);
5512c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                break;
5522c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin            case DIRECTION_UP:
5532c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                anim = new TranslateAnimation(0, 0, 0, -view.getHeight());
5542c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                break;
5552c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin            case DIRECTION_DOWN:
5562c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                anim = new TranslateAnimation(0, 0, 0, view.getHeight());
5572c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                break;
5582c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin            default:
5592c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                throw new IllegalArgumentException(Integer.toString(to));
5602c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin        }
5612c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin        anim.setDuration(500);
5622c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin        view.startAnimation(anim);
563c1f2e3021bf7b12f2a33561e09bd0ab32530382eOwen Lin        return anim;
5642c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin    }
5652c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin
566c1f2e3021bf7b12f2a33561e09bd0ab32530382eOwen Lin    public static Animation slideIn(View view, int from) {
5672c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin        view.setVisibility(View.VISIBLE);
5682c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin        Animation anim;
5692c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin        switch (from) {
5702c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin            case DIRECTION_LEFT:
5712c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                anim = new TranslateAnimation(-view.getWidth(), 0, 0, 0);
5722c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                break;
5732c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin            case DIRECTION_RIGHT:
5742c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                anim = new TranslateAnimation(view.getWidth(), 0, 0, 0);
5752c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                break;
5762c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin            case DIRECTION_UP:
5772c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                anim = new TranslateAnimation(0, 0, -view.getHeight(), 0);
5782c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                break;
5792c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin            case DIRECTION_DOWN:
5802c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                anim = new TranslateAnimation(0, 0, view.getHeight(), 0);
5812c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                break;
5822c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin            default:
5832c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin                throw new IllegalArgumentException(Integer.toString(from));
5842c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin        }
5852c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin        anim.setDuration(500);
5862c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin        view.startAnimation(anim);
587c1f2e3021bf7b12f2a33561e09bd0ab32530382eOwen Lin        return anim;
5882c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin    }
5892c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin
5902c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin    public static <T> T checkNotNull(T object) {
5912c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin        if (object == null) throw new NullPointerException();
5922c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin        return object;
5932c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin    }
594101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin}
595