Util.java revision d2db70880e6159413932f747eb82df3e925852c1
1101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin/*
2101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Copyright (C) 2009 The Android Open Source Project
3101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin *
4101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * you may not use this file except in compliance with the License.
6101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * You may obtain a copy of the License at
7101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin *
8101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin *
10101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Unless required by applicable law or agreed to in writing, software
11101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * See the License for the specific language governing permissions and
14101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * limitations under the License.
15101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */
16101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
17937fc48b37fafe3ffc8f4b52bd9a171bbb4d3a37Owen Linpackage com.android.camera;
18101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
193f3c857e3f34650c15d764810335024654b0fcc3Owen Linimport android.app.Activity;
203f3c857e3f34650c15d764810335024654b0fcc3Owen Linimport android.app.AlertDialog;
21dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Liimport android.app.admin.DevicePolicyManager;
228ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.content.ActivityNotFoundException;
238ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.content.ContentResolver;
24dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Liimport android.content.Context;
253f3c857e3f34650c15d764810335024654b0fcc3Owen Linimport android.content.DialogInterface;
268ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.content.Intent;
27101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.Bitmap;
28101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.BitmapFactory;
29101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.Matrix;
30c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Liimport android.hardware.Camera;
3110fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Liimport android.hardware.Camera.Parameters;
326227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatraimport android.hardware.Camera.Size;
338ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.net.Uri;
34dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Liimport android.os.Build;
358ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.os.ParcelFileDescriptor;
3610208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Liimport android.telephony.TelephonyManager;
3716ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Liimport android.util.DisplayMetrics;
38101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.util.Log;
396227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatraimport android.view.Display;
40ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Changimport android.view.Surface;
41601ce56b034f111b2875e7636776f2f359f6a156Owen Linimport android.view.View;
4216ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Liimport android.view.WindowManager;
43101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
44101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport java.io.Closeable;
458ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport java.io.IOException;
4610208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Liimport java.lang.reflect.Method;
471efb18228a45952d699af280482e1c51a4582690Owen Linimport java.util.List;
4810fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Liimport java.util.StringTokenizer;
49101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
50101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin/**
51101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Collection of utility functions used in this package.
52101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */
53101d528d59f447847d5c6b7578642132c2b76f4fOwen Linpublic class Util {
5434fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang    private static final String TAG = "Util";
559e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final int DIRECTION_LEFT = 0;
569e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final int DIRECTION_RIGHT = 1;
579e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final int DIRECTION_UP = 2;
589e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final int DIRECTION_DOWN = 3;
59101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
601efb18228a45952d699af280482e1c51a4582690Owen Lin    public static final String REVIEW_ACTION = "com.android.camera.action.REVIEW";
6135688439f40f00a1376dcfab6e6495989d82e433Wei-Ta Chen
62bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    // Private intent extras. Test only.
639e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final String EXTRAS_CAMERA_FACING =
649e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li            "android.intent.extras.CAMERA_FACING";
65bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
66bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang    private static boolean sIsTabletUI;
6716ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li    private static float sPixelDensity = 1;
68bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang
69101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    private Util() {
70101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
71101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
72bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang    public static void initialize(Context context) {
73bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang        sIsTabletUI = (context.getResources().getConfiguration().screenWidthDp >= 1024);
7416ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li
7516ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li        DisplayMetrics metrics = new DisplayMetrics();
7616ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li        WindowManager wm = (WindowManager)
7716ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li                context.getSystemService(Context.WINDOW_SERVICE);
7816ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li        wm.getDefaultDisplay().getMetrics(metrics);
7916ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li        sPixelDensity = metrics.density;
80bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang    }
81bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang
82bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang    public static boolean isTabletUI() {
83bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang        return sIsTabletUI;
84bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang    }
85bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang
8616ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li    public static int dpToPixel(int dp) {
8716ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li        return Math.round(sPixelDensity * dp);
8816ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li    }
8916ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li
90101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    // Rotates the bitmap by the specified degree.
91101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    // If a new bitmap is created, the original bitmap is recycled.
92101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static Bitmap rotate(Bitmap b, int degrees) {
939cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li        return rotateAndMirror(b, degrees, false);
949cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li    }
959cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li
969cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li    // Rotates and/or mirrors the bitmap. If a new bitmap is created, the
979cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li    // original bitmap is recycled.
989cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li    public static Bitmap rotateAndMirror(Bitmap b, int degrees, boolean mirror) {
999cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li        if ((degrees != 0 || mirror) && b != null) {
100101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Matrix m = new Matrix();
101101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            m.setRotate(degrees,
102101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    (float) b.getWidth() / 2, (float) b.getHeight() / 2);
1039cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li            if (mirror) {
1049cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                m.postScale(-1, 1);
1059cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                degrees = (degrees + 360) % 360;
1069cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                if (degrees == 0 || degrees == 180) {
1079cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                    m.postTranslate((float) b.getWidth(), 0);
1089cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                } else if (degrees == 90 || degrees == 270) {
1099cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                    m.postTranslate((float) b.getHeight(), 0);
1109cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                } else {
1119cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                    throw new IllegalArgumentException("Invalid degrees=" + degrees);
1129cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                }
1139cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li            }
1149cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li
115101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            try {
116101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                Bitmap b2 = Bitmap.createBitmap(
117101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                        b, 0, 0, b.getWidth(), b.getHeight(), m, true);
118101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                if (b != b2) {
119101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    b.recycle();
120101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    b = b2;
121101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                }
122101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            } catch (OutOfMemoryError ex) {
123101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                // We have no memory to rotate. Return the original bitmap.
124101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            }
125101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
126101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return b;
127101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
128101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
129101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /*
130ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * Compute the sample size as a function of minSideLength
131ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * and maxNumOfPixels.
1323c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * minSideLength is used to specify that minimal width or height of a
1333c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * bitmap.
1343c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * maxNumOfPixels is used to specify the maximal size in pixels that is
1353c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * tolerable in terms of memory usage.
136ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     *
137ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * The function returns a sample size based on the constraints.
1386bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh     * Both size and minSideLength can be passed in as -1
139ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * which indicates no care of the corresponding constraint.
140ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * The functions prefers returning a sample size that
1416bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh     * generates a smaller bitmap, unless minSideLength = -1.
1423c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     *
1433c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * Also, the function rounds up the sample size to a power of 2 or multiple
1443c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * of 8 because BitmapFactory only honors sample size this way.
1453c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * For example, BitmapFactory downsamples an image by 2 even though the
1463c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * request is 3. So we round up the sample size to avoid OOM.
147101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
148ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang    public static int computeSampleSize(BitmapFactory.Options options,
149ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            int minSideLength, int maxNumOfPixels) {
1503c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        int initialSize = computeInitialSampleSize(options, minSideLength,
1513c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen                maxNumOfPixels);
1523c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen
1533c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        int roundedSize;
154522e836abc90bcb2d4e7a4ac37e269154d06c715Chih-Chung Chang        if (initialSize <= 8) {
1553c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            roundedSize = 1;
1563c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            while (roundedSize < initialSize) {
1573c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen                roundedSize <<= 1;
1583c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            }
1593c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        } else {
1603c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            roundedSize = (initialSize + 7) / 8 * 8;
1613c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        }
1623c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen
1633c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        return roundedSize;
1643c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen    }
1653c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen
1663c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen    private static int computeInitialSampleSize(BitmapFactory.Options options,
1673c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            int minSideLength, int maxNumOfPixels) {
168ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang        double w = options.outWidth;
169ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang        double h = options.outHeight;
170ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang
1716bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        int lowerBound = (maxNumOfPixels < 0) ? 1 :
172ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang                (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
1736bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        int upperBound = (minSideLength < 0) ? 128 :
174ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang                (int) Math.min(Math.floor(w / minSideLength),
175ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang                Math.floor(h / minSideLength));
176ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang
177f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen        if (upperBound < lowerBound) {
178f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen            // return the larger one when there is no overlapping zone.
179f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen            return lowerBound;
180f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen        }
181f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen
1826bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        if (maxNumOfPixels < 0 && minSideLength < 0) {
183ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            return 1;
1846bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        } else if (minSideLength < 0) {
185ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            return lowerBound;
186ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang        } else {
187ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            return upperBound;
188101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
189101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
190101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
191cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang    public static Bitmap makeBitmap(byte[] jpegData, int maxNumOfPixels) {
192cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang        try {
193cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            BitmapFactory.Options options = new BitmapFactory.Options();
194cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inJustDecodeBounds = true;
195cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length,
196cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang                    options);
197cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            if (options.mCancel || options.outWidth == -1
198cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang                    || options.outHeight == -1) {
199cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang                return null;
200cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            }
201cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inSampleSize = computeSampleSize(
2026bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh                    options, -1, maxNumOfPixels);
203cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inJustDecodeBounds = false;
204cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang
205cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inDither = false;
206cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
207cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            return BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length,
208cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang                    options);
209cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang        } catch (OutOfMemoryError ex) {
210cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            Log.e(TAG, "Got oom exception ", ex);
211cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            return null;
212cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang        }
213c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    }
214c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
2156bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh    public static void closeSilently(Closeable c) {
2166bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        if (c == null) return;
2176bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        try {
2186bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh            c.close();
2196bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        } catch (Throwable t) {
2206bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh            // do nothing
2216bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        }
2226bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh    }
2236bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh
224341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang    public static void Assert(boolean cond) {
225341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang        if (!cond) {
226341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang            throw new AssertionError();
227341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang        }
228341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang    }
229059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin
230dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li    public static android.hardware.Camera openCamera(Activity activity, int cameraId)
231dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            throws CameraHardwareException, CameraDisabledException {
232dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li        // Check if device policy has disabled the camera.
233dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li        DevicePolicyManager dpm = (DevicePolicyManager) activity.getSystemService(
234dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li                Context.DEVICE_POLICY_SERVICE);
235dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li        if (dpm.getCameraDisabled(null)) {
236dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            throw new CameraDisabledException();
237dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li        }
238dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li
239dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li        try {
240dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            return CameraHolder.instance().open(cameraId);
241dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li        } catch (CameraHardwareException e) {
242dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            // In eng build, we throw the exception so that test tool
243dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            // can detect it and report it
244dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            if ("eng".equals(Build.TYPE)) {
245dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li                throw new RuntimeException("openCamera failed", e);
246dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            } else {
247dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li                throw e;
248dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            }
249dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li        }
250dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li    }
251dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li
252dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li    public static void showErrorAndFinish(final Activity activity, int msgId) {
2533f3c857e3f34650c15d764810335024654b0fcc3Owen Lin        DialogInterface.OnClickListener buttonListener =
2543f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                new DialogInterface.OnClickListener() {
2553f3c857e3f34650c15d764810335024654b0fcc3Owen Lin            public void onClick(DialogInterface dialog, int which) {
2563f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                activity.finish();
2573f3c857e3f34650c15d764810335024654b0fcc3Owen Lin            }
2583f3c857e3f34650c15d764810335024654b0fcc3Owen Lin        };
2593f3c857e3f34650c15d764810335024654b0fcc3Owen Lin        new AlertDialog.Builder(activity)
2603f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .setCancelable(false)
261db0757dc9c627e7c5206104664028e386ade7d03Wu-cheng Li                .setIconAttribute(android.R.attr.alertDialogIcon)
262dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li                .setTitle(R.string.camera_error_title)
263dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li                .setMessage(msgId)
2643f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .setNeutralButton(R.string.details_ok, buttonListener)
2653f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .show();
2663f3c857e3f34650c15d764810335024654b0fcc3Owen Lin    }
2672c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin
26873e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin    public static <T> T checkNotNull(T object) {
26973e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin        if (object == null) throw new NullPointerException();
27073e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin        return object;
27173e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin    }
27273e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin
27373e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin    public static boolean equals(Object a, Object b) {
27473e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin        return (a == b) || (a == null ? false : a.equals(b));
27573e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin    }
2764de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
2774de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    public static int nextPowerOf2(int n) {
2784de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n -= 1;
2794de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 16;
2804de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 8;
2814de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 4;
2824de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 2;
2834de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 1;
2844de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        return n + 1;
2854de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
28633be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin
28733be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin    public static float distance(float x, float y, float sx, float sy) {
28833be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        float dx = x - sx;
28933be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        float dy = y - sy;
29033be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        return (float) Math.sqrt(dx * dx + dy * dy);
29133be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin    }
29233be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin
29333be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin    public static int clamp(int x, int min, int max) {
29433be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        if (x > max) return max;
29533be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        if (x < min) return min;
29633be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        return x;
29733be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin    }
298ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang
2994aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li    public static int getDisplayRotation(Activity activity) {
300ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang        int rotation = activity.getWindowManager().getDefaultDisplay()
301ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang                .getRotation();
302ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang        switch (rotation) {
3034aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li            case Surface.ROTATION_0: return 0;
3044aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li            case Surface.ROTATION_90: return 90;
3054aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li            case Surface.ROTATION_180: return 180;
3064aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li            case Surface.ROTATION_270: return 270;
307ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang        }
3084aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li        return 0;
3094aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li    }
310ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang
3114b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li    public static int getDisplayOrientation(int degrees, int cameraId) {
3124b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li        // See android.hardware.Camera.setDisplayOrientation for
313c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        // documentation.
314c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        Camera.CameraInfo info = new Camera.CameraInfo();
315c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        Camera.getCameraInfo(cameraId, info);
316c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        int result;
317c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
318c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li            result = (info.orientation + degrees) % 360;
319c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li            result = (360 - result) % 360;  // compensate the mirror
320c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        } else {  // back-facing
321c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li            result = (info.orientation - degrees + 360) % 360;
322c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        }
3234b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li        return result;
324ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang    }
3256227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3266227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra    public static Size getOptimalPreviewSize(Activity currentActivity,
3276227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            List<Size> sizes, double targetRatio) {
3280fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li        // Use a very small tolerance because we want an exact match.
3290fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li        final double ASPECT_TOLERANCE = 0.001;
3306227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        if (sizes == null) return null;
3316227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3326227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        Size optimalSize = null;
3336227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        double minDiff = Double.MAX_VALUE;
3346227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3356227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // Because of bugs of overlay and layout, we sometimes will try to
3366227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // layout the viewfinder in the portrait orientation and thus get the
3376227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // wrong size of mSurfaceView. When we change the preview size, the
3386227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // new overlay will be created before the old one closed, which causes
3396227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // an exception. For now, just get the screen size
3406227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3416227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        Display display = currentActivity.getWindowManager().getDefaultDisplay();
3426227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        int targetHeight = Math.min(display.getHeight(), display.getWidth());
3436227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3446227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        if (targetHeight <= 0) {
3456227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            // We don't know the size of SurfaceView, use screen height
3466227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            targetHeight = display.getHeight();
3476227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        }
3486227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3496227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // Try to find an size match aspect ratio and size
3506227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        for (Size size : sizes) {
3516227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            double ratio = (double) size.width / size.height;
3526227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
3536227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            if (Math.abs(size.height - targetHeight) < minDiff) {
3546227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                optimalSize = size;
3556227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                minDiff = Math.abs(size.height - targetHeight);
3566227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            }
3576227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        }
3586227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3590fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li        // Cannot find the one match the aspect ratio. This should not happen.
3600fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li        // Ignore the requirement.
3616227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        if (optimalSize == null) {
3620fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li            Log.w(TAG, "No preview size match the aspect ratio");
3636227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            minDiff = Double.MAX_VALUE;
3646227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            for (Size size : sizes) {
3656227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                if (Math.abs(size.height - targetHeight) < minDiff) {
3666227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                    optimalSize = size;
3676227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                    minDiff = Math.abs(size.height - targetHeight);
3686227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                }
3696227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            }
3706227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        }
3716227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        return optimalSize;
3726227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra    }
37310fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li
37410fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li    public static void dumpParameters(Parameters parameters) {
37510fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        String flattened = parameters.flatten();
37610fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        StringTokenizer tokenizer = new StringTokenizer(flattened, ";");
37710fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        Log.d(TAG, "Dump all camera parameters:");
37810fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        while (tokenizer.hasMoreElements()) {
37910fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li            Log.d(TAG, tokenizer.nextToken());
38010fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        }
38110fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li    }
38210208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li
3834a045a8e858706f56a6ffb5187960768f861f007Wu-cheng Li    public static float[] convertZoomRatios(List<Integer> zoomRatios) {
3844a045a8e858706f56a6ffb5187960768f861f007Wu-cheng Li        float result[] = new float[zoomRatios.size()];
3854a045a8e858706f56a6ffb5187960768f861f007Wu-cheng Li        for (int i = 0, n = result.length; i < n; ++i) {
3864a045a8e858706f56a6ffb5187960768f861f007Wu-cheng Li            result[i] = (float) zoomRatios.get(i) / 100f;
3874a045a8e858706f56a6ffb5187960768f861f007Wu-cheng Li        }
3884a045a8e858706f56a6ffb5187960768f861f007Wu-cheng Li        return result;
3894a045a8e858706f56a6ffb5187960768f861f007Wu-cheng Li    }
3904a045a8e858706f56a6ffb5187960768f861f007Wu-cheng Li
391dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li    /**
39210208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li     * Returns whether the device is voice-capable (meaning, it can do MMS).
39310208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li     */
39410208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li    public static boolean isMmsCapable(Context context) {
39510208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        TelephonyManager telephonyManager = (TelephonyManager)
39610208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li                context.getSystemService(Context.TELEPHONY_SERVICE);
39710208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        if (telephonyManager == null) {
39810208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            return false;
39910208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        }
40010208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li
40110208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        try {
40210208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            Class partypes[] = new Class[0];
40310208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            Method sIsVoiceCapable = TelephonyManager.class.getMethod(
40410208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li                    "isVoiceCapable", partypes);
40510208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li
40610208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            Object arglist[] = new Object[0];
40710208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            Object retobj = sIsVoiceCapable.invoke(telephonyManager, arglist);
40810208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            return (Boolean) retobj;
40910208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        } catch (java.lang.reflect.InvocationTargetException ite) {
41010208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            // Failure, must be another device.
41110208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            // Assume that it is voice capable.
412feaf2ccff42c44b74be814b66296f9ddedcc9aa9Wu-cheng Li        } catch (IllegalAccessException iae) {
41310208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            // Failure, must be an other device.
41410208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            // Assume that it is voice capable.
41510208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        } catch (NoSuchMethodException nsme) {
41610208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        }
41710208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        return true;
41810208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li    }
419bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
420bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    // This is for test only. Allow the camera to launch the specific camera.
421bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    public static int getCameraFacingIntentExtras(Activity currentActivity) {
422bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        int cameraId = -1;
423bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
424bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        int intentCameraId =
425bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau                currentActivity.getIntent().getIntExtra(Util.EXTRAS_CAMERA_FACING, -1);
426bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
427bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        if (isFrontCameraIntent(intentCameraId)) {
428bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            // Check if the front camera exist
429bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            int frontCameraId = CameraHolder.instance().getFrontCameraId();
430bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            if (frontCameraId != -1) {
431bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau                cameraId = frontCameraId;
432bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            }
433bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        } else if (isBackCameraIntent(intentCameraId)) {
434bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            // Check if the back camera exist
435bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            int backCameraId = CameraHolder.instance().getBackCameraId();
436bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            if (backCameraId != -1) {
437bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau                cameraId = backCameraId;
438bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            }
439bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        }
440bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        return cameraId;
441bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    }
442bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
443bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    private static boolean isFrontCameraIntent(int intentCameraId) {
444bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        return (intentCameraId == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT);
445bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    }
446bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
447bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    private static boolean isBackCameraIntent(int intentCameraId) {
448bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        return (intentCameraId == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK);
449bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    }
450bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
45197d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li    private static int mLocation[] = new int[2];
45297d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li
45397d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li    // This method is not thread-safe.
45497d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li    public static boolean pointInView(float x, float y, View v) {
45597d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li        v.getLocationInWindow(mLocation);
45697d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li        return x >= mLocation[0] && x < (mLocation[0] + v.getWidth())
45797d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li                && y >= mLocation[1] && y < (mLocation[1] + v.getHeight());
45897d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li    }
4598ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li
4608ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li    public static boolean isUriValid(Uri uri, ContentResolver resolver) {
4618ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        if (uri == null) return false;
4628ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li
4638ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        try {
4648ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r");
4658ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            if (pfd == null) {
4668ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li                Log.e(TAG, "Fail to open URI. URI=" + uri);
4678ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li                return false;
4688ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            }
4698ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            pfd.close();
4708ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        } catch (IOException ex) {
4718ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            return false;
4728ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        }
4738ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        return true;
4748ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li    }
4758ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li
4768ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li    public static void viewUri(Uri uri, Context context) {
4778ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        if (!isUriValid(uri, context.getContentResolver())) {
4788ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            Log.e(TAG, "Uri invalid. uri=" + uri);
4798ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            return;
4808ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        }
4818ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li
4828ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        try {
4838ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            context.startActivity(new Intent(Util.REVIEW_ACTION, uri));
4848ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        } catch (ActivityNotFoundException ex) {
4858ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            try {
4868ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li                context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
4878ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            } catch (ActivityNotFoundException e) {
4888ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li                Log.e(TAG, "review image fail. uri=" + uri, e);
4898ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            }
4908ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        }
4918ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li    }
492d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li
493d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li    public static void prepareMatrix(Matrix matrix, boolean mirror, int displayOrientation,
494d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li            int viewWidth, int viewHeight) {
495d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        // Need mirror for front camera.
496d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        matrix.setScale(mirror ? -1 : 1, 1);
497d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        // This is the value for android.hardware.Camera.setDisplayOrientation.
498d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        matrix.postRotate(displayOrientation);
499d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        // Camera driver coordinates range from (-1000, -1000) to (1000, 1000).
500d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        // UI coordinates range from (0, 0) to (width, height).
501d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        matrix.postScale(viewWidth / 2000f, viewHeight / 2000f);
502d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        matrix.postTranslate(viewWidth / 2f, viewHeight / 2f);
503d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li    }
504101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin}
505