Util.java revision 341ad98e59d92769e1cc8ba68fa86c72dce0543b
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
190a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Changimport com.android.camera.gallery.IImage;
200a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang
21601ce56b034f111b2875e7636776f2f359f6a156Owen Linimport android.app.ProgressDialog;
22c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Changimport android.content.ContentResolver;
23601ce56b034f111b2875e7636776f2f359f6a156Owen Linimport android.content.Context;
24101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.Bitmap;
25101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.BitmapFactory;
2696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Changimport android.graphics.Canvas;
27101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.Matrix;
2896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Changimport android.graphics.Rect;
29101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.media.MediaMetadataRetriever;
30c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Changimport android.net.Uri;
31101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.os.ParcelFileDescriptor;
32101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.util.Log;
33601ce56b034f111b2875e7636776f2f359f6a156Owen Linimport android.view.View;
34601ce56b034f111b2875e7636776f2f359f6a156Owen Linimport android.view.View.OnClickListener;
35101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
36101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport java.io.ByteArrayOutputStream;
37101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport java.io.Closeable;
38c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Changimport java.io.FileDescriptor;
39d30b5877fbdedcebc0af5cccffddccfe9b11cb0bOwen Linimport java.io.IOException;
40101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
41101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin/**
42101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Collection of utility functions used in this package.
43101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */
44101d528d59f447847d5c6b7578642132c2b76f4fOwen Linpublic class Util {
45101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    private static final String TAG = "db.Util";
46101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
47601ce56b034f111b2875e7636776f2f359f6a156Owen Lin    private static OnClickListener sNullOnClickListener;
48601ce56b034f111b2875e7636776f2f359f6a156Owen Lin
49101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    private Util() {
50101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
51101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
52101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    // Rotates the bitmap by the specified degree.
53101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    // If a new bitmap is created, the original bitmap is recycled.
54101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static Bitmap rotate(Bitmap b, int degrees) {
55101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (degrees != 0 && b != null) {
56101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Matrix m = new Matrix();
57101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            m.setRotate(degrees,
58101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    (float) b.getWidth() / 2, (float) b.getHeight() / 2);
59101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            try {
60101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                Bitmap b2 = Bitmap.createBitmap(
61101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                        b, 0, 0, b.getWidth(), b.getHeight(), m, true);
62101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                if (b != b2) {
63101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    b.recycle();
64101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    b = b2;
65101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                }
66101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            } catch (OutOfMemoryError ex) {
67101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                // We have no memory to rotate. Return the original bitmap.
68101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            }
69101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
70101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return b;
71101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
72101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
73101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /*
74101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * Compute the sample size as a function of the image size and the target.
75101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * Scale the image down so that both the width and height are just above the
76101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * target. If this means that one of the dimension goes from above the
77101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * target to below the target (e.g. given a width of 480 and an image width
78101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * of 600 but sample size of 2 -- i.e. new width 300 -- bump the sample size
79101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * down by 1.
80101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
81101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static int computeSampleSize(
82101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            BitmapFactory.Options options, int target) {
83101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int w = options.outWidth;
84101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int h = options.outHeight;
85101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
86101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int candidateW = w / target;
87101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int candidateH = h / target;
88101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int candidate = Math.max(candidateW, candidateH);
89101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
90101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (candidate == 0) return 1;
91101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
92101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (candidate > 1) {
93101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            if ((w > target) && (w / candidate) < target) candidate -= 1;
94101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
95101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
96101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (candidate > 1) {
97101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            if ((h > target) && (h / candidate) < target) candidate -= 1;
98101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
99101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
100101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return candidate;
101101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
102101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
10396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang    public static Bitmap transform(Matrix scaler,
10496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                                   Bitmap source,
10596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                                   int targetWidth,
10696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                                   int targetHeight,
10796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                                   boolean scaleUp) {
10896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        int deltaX = source.getWidth() - targetWidth;
10996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        int deltaY = source.getHeight() - targetHeight;
11096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        if (!scaleUp && (deltaX < 0 || deltaY < 0)) {
11196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            /*
11296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             * In this case the bitmap is smaller, at least in one dimension,
11396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             * than the target.  Transform it by placing as much of the image
11496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             * as possible into the target and leaving the top/bottom or
11596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             * left/right (or both) black.
11696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             */
11796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            Bitmap b2 = Bitmap.createBitmap(targetWidth, targetHeight,
11896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    Bitmap.Config.ARGB_8888);
11996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            Canvas c = new Canvas(b2);
12096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
12196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            int deltaXHalf = Math.max(0, deltaX / 2);
12296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            int deltaYHalf = Math.max(0, deltaY / 2);
12396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            Rect src = new Rect(
12496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    deltaXHalf,
12596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    deltaYHalf,
12696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    deltaXHalf + Math.min(targetWidth, source.getWidth()),
12796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    deltaYHalf + Math.min(targetHeight, source.getHeight()));
12896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            int dstX = (targetWidth  - src.width())  / 2;
12996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            int dstY = (targetHeight - src.height()) / 2;
13096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            Rect dst = new Rect(
13196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    dstX,
13296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    dstY,
13396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    targetWidth - dstX,
13496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    targetHeight - dstY);
13596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            c.drawBitmap(source, src, dst, null);
13696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            return b2;
13796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        }
13896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        float bitmapWidthF = source.getWidth();
13996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        float bitmapHeightF = source.getHeight();
14096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
14196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        float bitmapAspect = bitmapWidthF / bitmapHeightF;
14258e94eddd371a9bb7c04936dbeb99615fd1a0c2cChih-Chung Chang        float viewAspect   = (float) targetWidth / targetHeight;
14396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
14496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        if (bitmapAspect > viewAspect) {
14596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            float scale = targetHeight / bitmapHeightF;
14696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            if (scale < .9F || scale > 1F) {
14796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                scaler.setScale(scale, scale);
14896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            } else {
14996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                scaler = null;
15096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            }
15196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        } else {
15296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            float scale = targetWidth / bitmapWidthF;
15396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            if (scale < .9F || scale > 1F) {
15496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                scaler.setScale(scale, scale);
15596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            } else {
15696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                scaler = null;
15796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            }
15896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        }
15996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
16096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        Bitmap b1;
16196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        if (scaler != null) {
16296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            // this is used for minithumb and crop, so we want to filter here.
16396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            b1 = Bitmap.createBitmap(source, 0, 0,
16496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    source.getWidth(), source.getHeight(), scaler, true);
16596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        } else {
16696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            b1 = source;
16796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        }
16896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
16996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        int dx1 = Math.max(0, b1.getWidth() - targetWidth);
17096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        int dy1 = Math.max(0, b1.getHeight() - targetHeight);
17196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
17296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        Bitmap b2 = Bitmap.createBitmap(
17396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                b1,
17496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                dx1 / 2,
17596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                dy1 / 2,
17696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                targetWidth,
17796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                targetHeight);
17896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
17996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        if (b1 != source) {
18096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            b1.recycle();
18196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        }
18296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
18396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        return b2;
18496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang    }
18596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
186101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /**
187101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * Creates a centered bitmap of the desired size. Recycles the input.
188101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * @param source
189101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
190101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static Bitmap extractMiniThumb(
191101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Bitmap source, int width, int height) {
192101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return Util.extractMiniThumb(source, width, height, true);
193101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
194101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
195101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static Bitmap extractMiniThumb(
196101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Bitmap source, int width, int height, boolean recycle) {
197101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (source == null) {
198101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            return null;
199101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
200101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
201101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        float scale;
202101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (source.getWidth() < source.getHeight()) {
203101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            scale = width / (float) source.getWidth();
204101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } else {
205101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            scale = height / (float) source.getHeight();
206101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
207101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        Matrix matrix = new Matrix();
208101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        matrix.setScale(scale, scale);
20996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        Bitmap miniThumbnail = transform(matrix, source, width, height, false);
210101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
211101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (recycle && miniThumbnail != source) {
212101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            source.recycle();
213101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
214101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return miniThumbnail;
215101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
216101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
217101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /**
218101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * Creates a byte[] for a given bitmap of the desired size. Recycles the
219101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * input bitmap.
220101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
221101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static byte[] miniThumbData(Bitmap source) {
222101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (source == null) return null;
223101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
224101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        Bitmap miniThumbnail = extractMiniThumb(
2250a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang                source, IImage.MINI_THUMB_TARGET_SIZE,
2260a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang                IImage.MINI_THUMB_TARGET_SIZE);
227101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
228101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        ByteArrayOutputStream miniOutStream = new ByteArrayOutputStream();
229101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        miniThumbnail.compress(Bitmap.CompressFormat.JPEG, 75, miniOutStream);
230101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        miniThumbnail.recycle();
231101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
232101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        try {
233101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            miniOutStream.close();
234101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            byte [] data = miniOutStream.toByteArray();
235101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            return data;
236101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } catch (java.io.IOException ex) {
237101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Log.e(TAG, "got exception ex " + ex);
238101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
239101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return null;
240101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
241101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
242101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /**
243101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * @return true if the mimetype is a video mimetype.
244101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
245101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static boolean isVideoMimeType(String mimeType) {
246101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return mimeType.startsWith("video/");
247101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
248101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
249101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /**
250101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * Create a video thumbnail for a video. May return null if the video is
251101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * corrupt.
252101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     *
253101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * @param filePath
254101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
255101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static Bitmap createVideoThumbnail(String filePath) {
256101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        Bitmap bitmap = null;
257101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
258101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        try {
259101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
260101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            retriever.setDataSource(filePath);
261101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            bitmap = retriever.captureFrame();
262101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } catch (IllegalArgumentException ex) {
263101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            // Assume this is a corrupt video file
264101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } catch (RuntimeException ex) {
265101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            // Assume this is a corrupt video file.
266101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } finally {
267101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            try {
268101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                retriever.release();
269101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            } catch (RuntimeException ex) {
270101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                // Ignore failures while cleaning up.
271101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            }
272101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
273101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return bitmap;
274101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
275101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
276101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static int indexOf(String [] array, String s) {
277101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        for (int i = 0; i < array.length; i++) {
278101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            if (array[i].equals(s)) {
279101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                return i;
280101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            }
281101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
282101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return -1;
283101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
284101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
285101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static void closeSiliently(Closeable c) {
286101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (c == null) return;
287101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        try {
288101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            c.close();
289101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } catch (Throwable t) {
290101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            // do nothing
291101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
292101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
293101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
294101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static void closeSiliently(ParcelFileDescriptor c) {
295101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (c == null) return;
296101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        try {
297101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            c.close();
298101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } catch (Throwable t) {
299101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            // do nothing
300101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
301101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
302101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
303c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    /**
304c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang     * Make a bitmap from a given Uri.
305c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang     *
306c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang     * @param uri
307c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang     */
308c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    public static Bitmap makeBitmap(int targetWidthOrHeight, Uri uri,
309c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            ContentResolver cr) {
310c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        ParcelFileDescriptor input = null;
311c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        try {
312c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            input = cr.openFileDescriptor(uri, "r");
313c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return makeBitmap(targetWidthOrHeight, uri, cr, input, null);
314c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } catch (IOException ex) {
315c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return null;
316c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } finally {
317c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            closeSiliently(input);
318c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        }
319c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    }
320c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
321c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    public static Bitmap makeBitmap(int targetWidthHeight, Uri uri,
322c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            ContentResolver cr, ParcelFileDescriptor pfd,
323c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            BitmapFactory.Options options) {
324c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        Bitmap b = null;
325c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        try {
326c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            if (pfd == null) pfd = makeInputStream(uri, cr);
327c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            if (pfd == null) return null;
328c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            if (options == null) options = new BitmapFactory.Options();
329c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
330c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            FileDescriptor fd = pfd.getFileDescriptor();
331c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            options.inSampleSize = 1;
332c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            if (targetWidthHeight != -1) {
333c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                options.inJustDecodeBounds = true;
334d30b5877fbdedcebc0af5cccffddccfe9b11cb0bOwen Lin                BitmapManager.instance().decodeFileDescriptor(fd, options);
335c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                if (options.mCancel || options.outWidth == -1
336c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                        || options.outHeight == -1) {
337c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                    return null;
338c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                }
339c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                options.inSampleSize =
340c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                        computeSampleSize(options, targetWidthHeight);
341c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                options.inJustDecodeBounds = false;
342c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            }
343c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
344c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            options.inDither = false;
345c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
346d30b5877fbdedcebc0af5cccffddccfe9b11cb0bOwen Lin            b = BitmapManager.instance().decodeFileDescriptor(fd, options);
347c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } catch (OutOfMemoryError ex) {
348c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            Log.e(TAG, "Got oom exception ", ex);
349c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return null;
350c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } finally {
351c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            closeSiliently(pfd);
352c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        }
353c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        return b;
354c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    }
355c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
356c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    private static ParcelFileDescriptor makeInputStream(
357c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            Uri uri, ContentResolver cr) {
358c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        try {
359c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return cr.openFileDescriptor(uri, "r");
360c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } catch (IOException ex) {
361c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return null;
362c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        }
363c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    }
364fa021af9397011cf180003139e80a88902c4b70aChih-Chung Chang
365fa021af9397011cf180003139e80a88902c4b70aChih-Chung Chang    public static void debugWhere(String tag, String msg) {
36674c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin        Log.d(tag, msg + " --- stack trace begins: ");
36774c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin        StackTraceElement elements[] = Thread.currentThread().getStackTrace();
36874c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin        // skip first 3 element, they are not related to the caller
36974c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin        for (int i = 3, n = elements.length; i < n; ++i) {
37074c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin            StackTraceElement st = elements[i];
37174c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin            String message = String.format("    at %s.%s(%s:%s)",
37274c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin                    st.getClassName(), st.getMethodName(), st.getFileName(),
37374c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin                    st.getLineNumber());
37474c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin            Log.d(tag, message);
37574c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin        }
37674c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin        Log.d(tag, msg + " --- stack trace ends.");
377fa021af9397011cf180003139e80a88902c4b70aChih-Chung Chang    }
378601ce56b034f111b2875e7636776f2f359f6a156Owen Lin
379601ce56b034f111b2875e7636776f2f359f6a156Owen Lin    public static <T> void showProgressDialog(final Context context,
380601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            String title, String message, PriorityTask<T> task) {
381601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        final ProgressDialog dialog =
382601ce56b034f111b2875e7636776f2f359f6a156Owen Lin                ProgressDialog.show(context, title, message);
383601ce56b034f111b2875e7636776f2f359f6a156Owen Lin
384601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        task.addCallback(new PriorityTask.Callback<T>() {
385601ce56b034f111b2875e7636776f2f359f6a156Owen Lin
386601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            public void onCanceled(PriorityTask<T> t) {
387601ce56b034f111b2875e7636776f2f359f6a156Owen Lin                dialog.dismiss();
388601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            }
389601ce56b034f111b2875e7636776f2f359f6a156Owen Lin
390601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            public void onFail(PriorityTask<T> t, Throwable error) {
391601ce56b034f111b2875e7636776f2f359f6a156Owen Lin                dialog.dismiss();
392601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            }
393601ce56b034f111b2875e7636776f2f359f6a156Owen Lin
394601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            public void onResultAvailable(PriorityTask<T> t, T result) {
395601ce56b034f111b2875e7636776f2f359f6a156Owen Lin                dialog.dismiss();
396601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            }
397601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        });
398601ce56b034f111b2875e7636776f2f359f6a156Owen Lin    }
399601ce56b034f111b2875e7636776f2f359f6a156Owen Lin
400601ce56b034f111b2875e7636776f2f359f6a156Owen Lin    public synchronized static OnClickListener getNullOnClickListener() {
401601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        if (sNullOnClickListener == null) {
402601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            sNullOnClickListener = new OnClickListener() {
403601ce56b034f111b2875e7636776f2f359f6a156Owen Lin                public void onClick(View v) {
404601ce56b034f111b2875e7636776f2f359f6a156Owen Lin                }
405601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            };
406601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        }
407601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        return sNullOnClickListener;
408601ce56b034f111b2875e7636776f2f359f6a156Owen Lin    }
409341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang
410341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang    public static void Assert(boolean cond) {
411341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang        if (!cond) {
412341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang            throw new AssertionError();
413341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang        }
414341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang    }
415101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin}
416