Util.java revision 026dff889c80763fc322ed03e2d3a76750320138
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;
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;
37101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
38101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport java.io.ByteArrayOutputStream;
39101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport java.io.Closeable;
40c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Changimport java.io.FileDescriptor;
41d30b5877fbdedcebc0af5cccffddccfe9b11cb0bOwen Linimport java.io.IOException;
42101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
43101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin/**
44101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Collection of utility functions used in this package.
45101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */
46101d528d59f447847d5c6b7578642132c2b76f4fOwen Linpublic class Util {
47101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    private static final String TAG = "db.Util";
48101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
49601ce56b034f111b2875e7636776f2f359f6a156Owen Lin    private static OnClickListener sNullOnClickListener;
50601ce56b034f111b2875e7636776f2f359f6a156Owen Lin
51101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    private Util() {
52101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
53101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
54101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    // Rotates the bitmap by the specified degree.
55101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    // If a new bitmap is created, the original bitmap is recycled.
56101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static Bitmap rotate(Bitmap b, int degrees) {
57101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (degrees != 0 && b != null) {
58101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Matrix m = new Matrix();
59101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            m.setRotate(degrees,
60101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    (float) b.getWidth() / 2, (float) b.getHeight() / 2);
61101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            try {
62101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                Bitmap b2 = Bitmap.createBitmap(
63101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                        b, 0, 0, b.getWidth(), b.getHeight(), m, true);
64101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                if (b != b2) {
65101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    b.recycle();
66101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    b = b2;
67101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                }
68101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            } catch (OutOfMemoryError ex) {
69101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                // We have no memory to rotate. Return the original bitmap.
70101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            }
71101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
72101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return b;
73101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
74101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
75101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /*
76101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * Compute the sample size as a function of the image size and the target.
77101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * Scale the image down so that both the width and height are just above the
78101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * target. If this means that one of the dimension goes from above the
79101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * target to below the target (e.g. given a width of 480 and an image width
80101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * of 600 but sample size of 2 -- i.e. new width 300 -- bump the sample size
81101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * down by 1.
82101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
83101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static int computeSampleSize(
84101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            BitmapFactory.Options options, int target) {
85101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int w = options.outWidth;
86101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int h = options.outHeight;
87101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
88101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int candidateW = w / target;
89101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int candidateH = h / target;
90101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        int candidate = Math.max(candidateW, candidateH);
91101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
92101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (candidate == 0) return 1;
93101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
94101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (candidate > 1) {
95101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            if ((w > target) && (w / candidate) < target) candidate -= 1;
96101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
97101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
98101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (candidate > 1) {
99101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            if ((h > target) && (h / candidate) < target) candidate -= 1;
100101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
101101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
102101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return candidate;
103101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
104101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
10596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang    public static Bitmap transform(Matrix scaler,
10696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                                   Bitmap source,
10796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                                   int targetWidth,
10896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                                   int targetHeight,
10996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                                   boolean scaleUp) {
11096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        int deltaX = source.getWidth() - targetWidth;
11196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        int deltaY = source.getHeight() - targetHeight;
11296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        if (!scaleUp && (deltaX < 0 || deltaY < 0)) {
11396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            /*
11496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             * In this case the bitmap is smaller, at least in one dimension,
11596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             * than the target.  Transform it by placing as much of the image
11696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             * as possible into the target and leaving the top/bottom or
11796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             * left/right (or both) black.
11896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang             */
11996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            Bitmap b2 = Bitmap.createBitmap(targetWidth, targetHeight,
12096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    Bitmap.Config.ARGB_8888);
12196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            Canvas c = new Canvas(b2);
12296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
12396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            int deltaXHalf = Math.max(0, deltaX / 2);
12496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            int deltaYHalf = Math.max(0, deltaY / 2);
12596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            Rect src = new Rect(
12696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    deltaXHalf,
12796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    deltaYHalf,
12896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    deltaXHalf + Math.min(targetWidth, source.getWidth()),
12996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    deltaYHalf + Math.min(targetHeight, source.getHeight()));
13096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            int dstX = (targetWidth  - src.width())  / 2;
13196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            int dstY = (targetHeight - src.height()) / 2;
13296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            Rect dst = new Rect(
13396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    dstX,
13496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    dstY,
13596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    targetWidth - dstX,
13696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    targetHeight - dstY);
13796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            c.drawBitmap(source, src, dst, null);
13896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            return b2;
13996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        }
14096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        float bitmapWidthF = source.getWidth();
14196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        float bitmapHeightF = source.getHeight();
14296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
14396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        float bitmapAspect = bitmapWidthF / bitmapHeightF;
14458e94eddd371a9bb7c04936dbeb99615fd1a0c2cChih-Chung Chang        float viewAspect   = (float) targetWidth / targetHeight;
14596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
14696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        if (bitmapAspect > viewAspect) {
14796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            float scale = targetHeight / bitmapHeightF;
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        } else {
15496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            float scale = targetWidth / bitmapWidthF;
15596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            if (scale < .9F || scale > 1F) {
15696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                scaler.setScale(scale, scale);
15796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            } else {
15896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                scaler = null;
15996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            }
16096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        }
16196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
16296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        Bitmap b1;
16396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        if (scaler != null) {
16496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            // this is used for minithumb and crop, so we want to filter here.
16596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            b1 = Bitmap.createBitmap(source, 0, 0,
16696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                    source.getWidth(), source.getHeight(), scaler, true);
16796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        } else {
16896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            b1 = source;
16996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        }
17096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
17196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        int dx1 = Math.max(0, b1.getWidth() - targetWidth);
17296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        int dy1 = Math.max(0, b1.getHeight() - targetHeight);
17396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
17496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        Bitmap b2 = Bitmap.createBitmap(
17596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                b1,
17696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                dx1 / 2,
17796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                dy1 / 2,
17896b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                targetWidth,
17996b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang                targetHeight);
18096b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
18196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        if (b1 != source) {
18296b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang            b1.recycle();
18396b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        }
18496b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
18596b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        return b2;
18696b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang    }
18796b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang
188101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /**
189101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * Creates a centered bitmap of the desired size. Recycles the input.
190101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * @param source
191101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
192101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static Bitmap extractMiniThumb(
193101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Bitmap source, int width, int height) {
194101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return Util.extractMiniThumb(source, width, height, true);
195101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
196101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
197101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static Bitmap extractMiniThumb(
198101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Bitmap source, int width, int height, boolean recycle) {
199101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (source == null) {
200101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            return null;
201101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
202101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
203101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        float scale;
204101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (source.getWidth() < source.getHeight()) {
205101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            scale = width / (float) source.getWidth();
206101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } else {
207101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            scale = height / (float) source.getHeight();
208101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
209101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        Matrix matrix = new Matrix();
210101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        matrix.setScale(scale, scale);
21196b3c6ee6d93c136bb8270521158a989584966b1Chih-Chung Chang        Bitmap miniThumbnail = transform(matrix, source, width, height, false);
212101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
213101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (recycle && miniThumbnail != source) {
214101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            source.recycle();
215101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
216101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return miniThumbnail;
217101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
218101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
219101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /**
220101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * Creates a byte[] for a given bitmap of the desired size. Recycles the
221101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     * input bitmap.
222101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
223101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static byte[] miniThumbData(Bitmap source) {
224101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        if (source == null) return null;
225101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
226101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        Bitmap miniThumbnail = extractMiniThumb(
2270a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang                source, IImage.MINI_THUMB_TARGET_SIZE,
2280a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang                IImage.MINI_THUMB_TARGET_SIZE);
229101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
230101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        ByteArrayOutputStream miniOutStream = new ByteArrayOutputStream();
231101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        miniThumbnail.compress(Bitmap.CompressFormat.JPEG, 75, miniOutStream);
232101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        miniThumbnail.recycle();
233101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
234101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        try {
235101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            miniOutStream.close();
236101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            byte [] data = miniOutStream.toByteArray();
237101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            return data;
238101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        } catch (java.io.IOException ex) {
239101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Log.e(TAG, "got exception ex " + ex);
240101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
241101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return null;
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
271bbc2f2f15a865cf0330cd78a6ea67177c5863b3bOwen Lin    public static <T>  int indexOf(T [] array, T 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
280724e9b3db93677b753c1267a716e30e6cf5ff3b6Chih-Chung Chang    public static void closeSilently(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
289724e9b3db93677b753c1267a716e30e6cf5ff3b6Chih-Chung Chang    public static void closeSilently(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 {
312724e9b3db93677b753c1267a716e30e6cf5ff3b6Chih-Chung Chang            closeSilently(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;
329d30b5877fbdedcebc0af5cccffddccfe9b11cb0bOwen Lin                BitmapManager.instance().decodeFileDescriptor(fd, options);
330c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                if (options.mCancel || options.outWidth == -1
331c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                        || options.outHeight == -1) {
332c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                    return null;
333c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                }
334c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                options.inSampleSize =
335c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                        computeSampleSize(options, targetWidthHeight);
336c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang                options.inJustDecodeBounds = false;
337c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            }
338c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
339c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            options.inDither = false;
340c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
341d30b5877fbdedcebc0af5cccffddccfe9b11cb0bOwen Lin            b = BitmapManager.instance().decodeFileDescriptor(fd, options);
342c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } catch (OutOfMemoryError ex) {
343c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            Log.e(TAG, "Got oom exception ", ex);
344c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return null;
345c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } finally {
346724e9b3db93677b753c1267a716e30e6cf5ff3b6Chih-Chung Chang            closeSilently(pfd);
347c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        }
348c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        return b;
349c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    }
350c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
351c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    private static ParcelFileDescriptor makeInputStream(
352c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            Uri uri, ContentResolver cr) {
353c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        try {
354c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return cr.openFileDescriptor(uri, "r");
355c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        } catch (IOException ex) {
356c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang            return null;
357c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang        }
358c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    }
359fa021af9397011cf180003139e80a88902c4b70aChih-Chung Chang
360fa021af9397011cf180003139e80a88902c4b70aChih-Chung Chang    public static void debugWhere(String tag, String msg) {
36174c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin        Log.d(tag, msg + " --- stack trace begins: ");
36274c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin        StackTraceElement elements[] = Thread.currentThread().getStackTrace();
36374c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin        // skip first 3 element, they are not related to the caller
36474c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin        for (int i = 3, n = elements.length; i < n; ++i) {
36574c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin            StackTraceElement st = elements[i];
36674c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin            String message = String.format("    at %s.%s(%s:%s)",
36774c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin                    st.getClassName(), st.getMethodName(), st.getFileName(),
36874c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin                    st.getLineNumber());
36974c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin            Log.d(tag, message);
37074c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin        }
37174c3bd38d4155c694bbb575f389597ee60aec7d3Owen Lin        Log.d(tag, msg + " --- stack trace ends.");
372fa021af9397011cf180003139e80a88902c4b70aChih-Chung Chang    }
373601ce56b034f111b2875e7636776f2f359f6a156Owen Lin
374601ce56b034f111b2875e7636776f2f359f6a156Owen Lin    public static <T> void showProgressDialog(final Context context,
375601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            String title, String message, PriorityTask<T> task) {
376601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        final ProgressDialog dialog =
377601ce56b034f111b2875e7636776f2f359f6a156Owen Lin                ProgressDialog.show(context, title, message);
378601ce56b034f111b2875e7636776f2f359f6a156Owen Lin
379601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        task.addCallback(new PriorityTask.Callback<T>() {
380601ce56b034f111b2875e7636776f2f359f6a156Owen Lin
381601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            public void onCanceled(PriorityTask<T> t) {
382601ce56b034f111b2875e7636776f2f359f6a156Owen Lin                dialog.dismiss();
383601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            }
384601ce56b034f111b2875e7636776f2f359f6a156Owen Lin
385601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            public void onFail(PriorityTask<T> t, Throwable error) {
386601ce56b034f111b2875e7636776f2f359f6a156Owen Lin                dialog.dismiss();
387601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            }
388601ce56b034f111b2875e7636776f2f359f6a156Owen Lin
389601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            public void onResultAvailable(PriorityTask<T> t, T result) {
390601ce56b034f111b2875e7636776f2f359f6a156Owen Lin                dialog.dismiss();
391601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            }
392601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        });
393601ce56b034f111b2875e7636776f2f359f6a156Owen Lin    }
394601ce56b034f111b2875e7636776f2f359f6a156Owen Lin
3954177add422a041ea9f1007c05ff42361bf529d52Chih-Chung Chang    public static synchronized OnClickListener getNullOnClickListener() {
396601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        if (sNullOnClickListener == null) {
397601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            sNullOnClickListener = new OnClickListener() {
398601ce56b034f111b2875e7636776f2f359f6a156Owen Lin                public void onClick(View v) {
399601ce56b034f111b2875e7636776f2f359f6a156Owen Lin                }
400601ce56b034f111b2875e7636776f2f359f6a156Owen Lin            };
401601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        }
402601ce56b034f111b2875e7636776f2f359f6a156Owen Lin        return sNullOnClickListener;
403601ce56b034f111b2875e7636776f2f359f6a156Owen Lin    }
404341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang
405341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang    public static void Assert(boolean cond) {
406341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang        if (!cond) {
407341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang            throw new AssertionError();
408341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang        }
409341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang    }
410059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin
411b0e1282810ec68fd7585beb9ab9afab9bcafe1bdOwen Lin    public static boolean equals(String a, String b) {
412b0e1282810ec68fd7585beb9ab9afab9bcafe1bdOwen Lin        // return true if both string are null or the content equals
413b0e1282810ec68fd7585beb9ab9afab9bcafe1bdOwen Lin        return a == b || a.equals(b);
414b0e1282810ec68fd7585beb9ab9afab9bcafe1bdOwen Lin    }
415482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin
416482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin    private static class BackgroundJob
417482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            extends MonitoredActivity.LifeCycleAdapter implements Runnable {
418482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin
419482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        private final MonitoredActivity mActivity;
420482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        private final ProgressDialog mDialog;
421482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        private final Runnable mJob;
422482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        private final Handler mHandler;
4236fa5404fd6c34d401c56accd059a706d8a832812Owen Lin        private final Runnable mCleanupRunner = new Runnable() {
4246fa5404fd6c34d401c56accd059a706d8a832812Owen Lin            public void run() {
4256fa5404fd6c34d401c56accd059a706d8a832812Owen Lin                mActivity.removeLifeCycleListener(BackgroundJob.this);
4266fa5404fd6c34d401c56accd059a706d8a832812Owen Lin                if (mDialog.getWindow() != null) mDialog.dismiss();
4276fa5404fd6c34d401c56accd059a706d8a832812Owen Lin            }
4286fa5404fd6c34d401c56accd059a706d8a832812Owen Lin        };
429482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin
430482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        public BackgroundJob(MonitoredActivity activity, Runnable job,
431482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin                ProgressDialog dialog, Handler handler) {
432482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            mActivity = activity;
433482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            mDialog = dialog;
434482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            mJob = job;
435482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            mActivity.addLifeCycleListener(this);
436482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            mHandler = handler;
437482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        }
438482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin
439482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        public void run() {
440482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            try {
441482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin                mJob.run();
442482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            } finally {
4436fa5404fd6c34d401c56accd059a706d8a832812Owen Lin                mHandler.post(mCleanupRunner);
444482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            }
445482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        }
446482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin
4476fa5404fd6c34d401c56accd059a706d8a832812Owen Lin
4486fa5404fd6c34d401c56accd059a706d8a832812Owen Lin        @Override
4496fa5404fd6c34d401c56accd059a706d8a832812Owen Lin        public void onActivityDestroyed(MonitoredActivity activity) {
4506fa5404fd6c34d401c56accd059a706d8a832812Owen Lin            // We get here only when the onDestroyed being called before
4516fa5404fd6c34d401c56accd059a706d8a832812Owen Lin            // the mCleanupRunner. So, run it now and remove it from the queue
4526fa5404fd6c34d401c56accd059a706d8a832812Owen Lin            mCleanupRunner.run();
4536fa5404fd6c34d401c56accd059a706d8a832812Owen Lin            mHandler.removeCallbacks(mCleanupRunner);
4546fa5404fd6c34d401c56accd059a706d8a832812Owen Lin        }
4556fa5404fd6c34d401c56accd059a706d8a832812Owen Lin
456482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        @Override
457482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        public void onActivityStopped(MonitoredActivity activity) {
458482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            mDialog.hide();
459482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        }
460482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin
461482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        @Override
462482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        public void onActivityStarted(MonitoredActivity activity) {
463482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            mDialog.show();
464482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        }
465482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin    }
466482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin
467482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin    public static void startBackgroundJob(MonitoredActivity activity,
468482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin            String title, String message, Runnable job, Handler handler) {
469482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        // Make the progress dialog uncancelable, so that we can gurantee
470482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        // the thread will be done before the activity getting destroyed.
471482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        ProgressDialog dialog = ProgressDialog.show(
472482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin                activity, title, message, true, false);
473482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin        new Thread(new BackgroundJob(activity, job, dialog, handler)).start();
474482a3a54cfa8ec2cc913efc0e73a01d78453ee6dOwen Lin    }
475bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang
476bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang    // Returns an intent which is used for "set as" menu items.
477bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang    public static Intent createSetAsIntent(IImage image) {
478bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang        Uri u = image.fullSizeImageUri();
479bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang        Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
480bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang        intent.setDataAndType(u, image.getMimeType());
481bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang        intent.putExtra("mimeType", image.getMimeType());
482bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang        return intent;
483bb1877847ae050918fe591d9b7fa63deaf645746Chih-Chung Chang    }
484d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen
485d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen    // Returns Options that set the puregeable flag for Bitmap decode.
486026dff889c80763fc322ed03e2d3a76750320138Wei-Ta Chen    public static BitmapFactory.Options createNativeAllocOptions() {
487d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen        BitmapFactory.Options options = new BitmapFactory.Options();
488026dff889c80763fc322ed03e2d3a76750320138Wei-Ta Chen        options.inNativeAlloc = true;
489d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen        return options;
490d5d74642d7c0b43578b43cdd46b70671b64c88e2Wei-Ta Chen    }
491101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin}
492