Util.java revision 96b3c6ee6d93c136bb8270521158a989584966b1
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
21c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Changimport android.content.ContentResolver;
22101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.Bitmap;
23101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.BitmapFactory;
2496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Changimport android.graphics.Canvas;
25101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.Matrix;
2696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Changimport android.graphics.Rect;
27101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.media.MediaMetadataRetriever;
28c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Changimport android.net.Uri;
29101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.os.ParcelFileDescriptor;
30101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.util.Log;
31101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
32101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport java.io.ByteArrayOutputStream;
33101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport java.io.Closeable;
34c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Changimport java.io.IOException;
35c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Changimport java.io.FileDescriptor;
36101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
37101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin/**
38101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Collection of utility functions used in this package.
39101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */
40101d528d59f447847d5c6b7578642132c2b76f4fOwen Linpublic class Util {
41101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    private static final boolean VERBOSE = false;
42101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    private static final String TAG = "db.Util";
43101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
44101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    private Util() {
45101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
46101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
47101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    // Rotates the bitmap by the specified degree.
48101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    // If a new bitmap is created, the original bitmap is recycled.
49101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static Bitmap rotate(Bitmap b, int degrees) {
50101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (degrees != 0 && b != null) {
51101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Matrix m = new Matrix();
52101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            m.setRotate(degrees,
53101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    (float) b.getWidth() / 2, (float) b.getHeight() / 2);
54101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            try {
55101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                Bitmap b2 = Bitmap.createBitmap(
56101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                        b, 0, 0, b.getWidth(), b.getHeight(), m, true);
57101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                if (b != b2) {
58101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    b.recycle();
59101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    b = b2;
60101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                }
61101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            } catch (OutOfMemoryError ex) {
62101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                // We have no memory to rotate. Return the original bitmap.
63101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            }
64101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
65101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return b;
66101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
67101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
68101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /*
69101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * Compute the sample size as a function of the image size and the target.
70101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * Scale the image down so that both the width and height are just above the
71101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * target. If this means that one of the dimension goes from above the
72101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * target to below the target (e.g. given a width of 480 and an image width
73101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * of 600 but sample size of 2 -- i.e. new width 300 -- bump the sample size
74101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * down by 1.
75101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
76101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static int computeSampleSize(
77101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            BitmapFactory.Options options, int target) {
78101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int w = options.outWidth;
79101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int h = options.outHeight;
80101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
81101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int candidateW = w / target;
82101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int candidateH = h / target;
83101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int candidate = Math.max(candidateW, candidateH);
84101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
85101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (candidate == 0) return 1;
86101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
87101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (candidate > 1) {
88101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            if ((w > target) && (w / candidate) < target) candidate -= 1;
89101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
90101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
91101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (candidate > 1) {
92101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            if ((h > target) && (h / candidate) < target) candidate -= 1;
93101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
94101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
95101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return candidate;
96101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
97101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
9896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang    public static Bitmap transform(Matrix scaler,
9996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                                   Bitmap source,
10096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                                   int targetWidth,
10196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                                   int targetHeight,
10296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                                   boolean scaleUp) {
10396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        int deltaX = source.getWidth() - targetWidth;
10496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        int deltaY = source.getHeight() - targetHeight;
10596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        if (!scaleUp && (deltaX < 0 || deltaY < 0)) {
10696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            /*
10796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             * In this case the bitmap is smaller, at least in one dimension,
10896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             * than the target.  Transform it by placing as much of the image
10996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             * as possible into the target and leaving the top/bottom or
11096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             * left/right (or both) black.
11196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             */
11296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            Bitmap b2 = Bitmap.createBitmap(targetWidth, targetHeight,
11396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    Bitmap.Config.ARGB_8888);
11496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            Canvas c = new Canvas(b2);
11596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
11696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            int deltaXHalf = Math.max(0, deltaX / 2);
11796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            int deltaYHalf = Math.max(0, deltaY / 2);
11896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            Rect src = new Rect(
11996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    deltaXHalf,
12096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    deltaYHalf,
12196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    deltaXHalf + Math.min(targetWidth, source.getWidth()),
12296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    deltaYHalf + Math.min(targetHeight, source.getHeight()));
12396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            int dstX = (targetWidth  - src.width())  / 2;
12496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            int dstY = (targetHeight - src.height()) / 2;
12596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            Rect dst = new Rect(
12696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    dstX,
12796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    dstY,
12896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    targetWidth - dstX,
12996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    targetHeight - dstY);
13096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            c.drawBitmap(source, src, dst, null);
13196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            return b2;
13296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        }
13396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        float bitmapWidthF = source.getWidth();
13496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        float bitmapHeightF = source.getHeight();
13596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
13696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        float bitmapAspect = bitmapWidthF / bitmapHeightF;
13796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        float viewAspect   = (float) targetWidth / (float) targetHeight;
13896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
13996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        if (bitmapAspect > viewAspect) {
14096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            float scale = targetHeight / bitmapHeightF;
14196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            if (scale < .9F || scale > 1F) {
14296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                scaler.setScale(scale, scale);
14396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            } else {
14496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                scaler = null;
14596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            }
14696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        } else {
14796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            float scale = targetWidth / bitmapWidthF;
14896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            if (scale < .9F || scale > 1F) {
14996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                scaler.setScale(scale, scale);
15096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            } else {
15196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                scaler = null;
15296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            }
15396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        }
15496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
15596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        Bitmap b1;
15696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        if (scaler != null) {
15796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            // this is used for minithumb and crop, so we want to filter here.
15896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            b1 = Bitmap.createBitmap(source, 0, 0,
15996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    source.getWidth(), source.getHeight(), scaler, true);
16096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        } else {
16196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            b1 = source;
16296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        }
16396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
16496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        int dx1 = Math.max(0, b1.getWidth() - targetWidth);
16596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        int dy1 = Math.max(0, b1.getHeight() - targetHeight);
16696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
16796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        Bitmap b2 = Bitmap.createBitmap(
16896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                b1,
16996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                dx1 / 2,
17096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                dy1 / 2,
17196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                targetWidth,
17296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                targetHeight);
17396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
17496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        if (b1 != source) {
17596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            b1.recycle();
17696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        }
17796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
17896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        return b2;
17996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang    }
18096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
181101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /**
182101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * Creates a centered bitmap of the desired size. Recycles the input.
183101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * @param source
184101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
185101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static Bitmap extractMiniThumb(
186101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Bitmap source, int width, int height) {
187101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return Util.extractMiniThumb(source, width, height, true);
188101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
189101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
190101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static Bitmap extractMiniThumb(
191101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Bitmap source, int width, int height, boolean recycle) {
192101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (source == null) {
193101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            return null;
194101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
195101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
196101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        float scale;
197101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (source.getWidth() < source.getHeight()) {
198101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            scale = width / (float) source.getWidth();
199101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } else {
200101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            scale = height / (float) source.getHeight();
201101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
202101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        Matrix matrix = new Matrix();
203101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        matrix.setScale(scale, scale);
20496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        Bitmap miniThumbnail = transform(matrix, source, width, height, false);
205101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
206101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (recycle && miniThumbnail != source) {
207101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            source.recycle();
208101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
209101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return miniThumbnail;
210101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
211101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
212101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /**
213101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * Creates a byte[] for a given bitmap of the desired size. Recycles the
214101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * input bitmap.
215101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
216101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static byte[] miniThumbData(Bitmap source) {
217101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (source == null) return null;
218101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
219101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        Bitmap miniThumbnail = extractMiniThumb(
2200a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang                source, IImage.MINI_THUMB_TARGET_SIZE,
2210a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang                IImage.MINI_THUMB_TARGET_SIZE);
222101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
223101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        ByteArrayOutputStream miniOutStream = new ByteArrayOutputStream();
224101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        miniThumbnail.compress(Bitmap.CompressFormat.JPEG, 75, miniOutStream);
225101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        miniThumbnail.recycle();
226101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
227101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        try {
228101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            miniOutStream.close();
229101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            byte [] data = miniOutStream.toByteArray();
230101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            return data;
231101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } catch (java.io.IOException ex) {
232101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Log.e(TAG, "got exception ex " + ex);
233101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
234101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return null;
235101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
236101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
237101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /**
238101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * @return true if the mimetype is a video mimetype.
239101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
240101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static boolean isVideoMimeType(String mimeType) {
241101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return mimeType.startsWith("video/");
242101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
243101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
244101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /**
245101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * Create a video thumbnail for a video. May return null if the video is
246101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * corrupt.
247101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     *
248101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * @param filePath
249101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
250101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static Bitmap createVideoThumbnail(String filePath) {
251101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        Bitmap bitmap = null;
252101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
253101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        try {
254101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
255101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            retriever.setDataSource(filePath);
256101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            bitmap = retriever.captureFrame();
257101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } catch (IllegalArgumentException ex) {
258101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            // Assume this is a corrupt video file
259101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } catch (RuntimeException ex) {
260101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            // Assume this is a corrupt video file.
261101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } finally {
262101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            try {
263101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                retriever.release();
264101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            } catch (RuntimeException ex) {
265101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                // Ignore failures while cleaning up.
266101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            }
267101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
268101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return bitmap;
269101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
270101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
271101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static int indexOf(String [] array, String s) {
272101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        for (int i = 0; i < array.length; i++) {
273101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            if (array[i].equals(s)) {
274101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                return i;
275101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            }
276101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
277101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return -1;
278101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
279101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
280101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static void closeSiliently(Closeable c) {
281101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (c == null) return;
282101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        try {
283101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            c.close();
284101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } catch (Throwable t) {
285101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            // do nothing
286101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
287101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
288101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
289101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static void closeSiliently(ParcelFileDescriptor c) {
290101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (c == null) return;
291101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        try {
292101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            c.close();
293101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } catch (Throwable t) {
294101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            // do nothing
295101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
296101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
297101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
298c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    /**
299c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang     * Make a bitmap from a given Uri.
300c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang     *
301c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang     * @param uri
302c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang     */
303c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    public static Bitmap makeBitmap(int targetWidthOrHeight, Uri uri,
304c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            ContentResolver cr) {
305c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        ParcelFileDescriptor input = null;
306c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        try {
307c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            input = cr.openFileDescriptor(uri, "r");
308c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return makeBitmap(targetWidthOrHeight, uri, cr, input, null);
309c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } catch (IOException ex) {
310c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return null;
311c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } finally {
312c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            closeSiliently(input);
313c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        }
314c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    }
315c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
316c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    public static Bitmap makeBitmap(int targetWidthHeight, Uri uri,
317c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            ContentResolver cr, ParcelFileDescriptor pfd,
318c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            BitmapFactory.Options options) {
319c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        Bitmap b = null;
320c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        try {
321c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            if (pfd == null) pfd = makeInputStream(uri, cr);
322c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            if (pfd == null) return null;
323c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            if (options == null) options = new BitmapFactory.Options();
324c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
325c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            FileDescriptor fd = pfd.getFileDescriptor();
326c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            options.inSampleSize = 1;
327c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            if (targetWidthHeight != -1) {
328c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                options.inJustDecodeBounds = true;
329c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                BitmapManager.instance().decodeFileDescriptor(
330c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                        fd, null, options);
331c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                if (options.mCancel || options.outWidth == -1
332c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                        || options.outHeight == -1) {
333c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                    return null;
334c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                }
335c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                options.inSampleSize =
336c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                        computeSampleSize(options, targetWidthHeight);
337c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                options.inJustDecodeBounds = false;
338c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            }
339c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
340c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            options.inDither = false;
341c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
342c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            b = BitmapManager.instance()
343c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                    .decodeFileDescriptor(fd, null, options);
344c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } catch (OutOfMemoryError ex) {
345c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            Log.e(TAG, "Got oom exception ", ex);
346c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return null;
347c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } finally {
348c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            closeSiliently(pfd);
349c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        }
350c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        return b;
351c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    }
352c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
353c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    private static ParcelFileDescriptor makeInputStream(
354c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            Uri uri, ContentResolver cr) {
355c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        try {
356c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return cr.openFileDescriptor(uri, "r");
357c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } catch (IOException ex) {
358c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return null;
359c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        }
360c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    }
361101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin}
362