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;
30048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huangimport android.graphics.Rect;
31048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huangimport android.graphics.RectF;
32c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Liimport android.hardware.Camera;
33a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Liimport android.hardware.Camera.CameraInfo;
3410fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Liimport android.hardware.Camera.Parameters;
356227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatraimport android.hardware.Camera.Size;
36a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Liimport android.location.Location;
378ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.net.Uri;
38dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Liimport android.os.Build;
398ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.os.ParcelFileDescriptor;
40a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chenimport android.provider.Settings;
4110208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Liimport android.telephony.TelephonyManager;
4216ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Liimport android.util.DisplayMetrics;
43101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.util.Log;
446227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatraimport android.view.Display;
45a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Liimport android.view.OrientationEventListener;
46ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Changimport android.view.Surface;
47601ce56b034f111b2875e7636776f2f359f6a156Owen Linimport android.view.View;
48e0861e7473d042bdd9c935f3bdf50ae220891b6cWu-cheng Liimport android.view.Window;
4916ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Liimport android.view.WindowManager;
50ea136afa2f4d38428ad486df5fb0a24db8314a3dChih-yu Huangimport android.view.animation.AlphaAnimation;
51ea136afa2f4d38428ad486df5fb0a24db8314a3dChih-yu Huangimport android.view.animation.Animation;
52101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
53101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport java.io.Closeable;
548ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport java.io.IOException;
5510208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Liimport java.lang.reflect.Method;
56757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Liimport java.text.SimpleDateFormat;
57757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Liimport java.util.Date;
581efb18228a45952d699af280482e1c51a4582690Owen Linimport java.util.List;
5910fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Liimport java.util.StringTokenizer;
60101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
61101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin/**
62101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Collection of utility functions used in this package.
63101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */
64101d528d59f447847d5c6b7578642132c2b76f4fOwen Linpublic class Util {
6534fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang    private static final String TAG = "Util";
669e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final int DIRECTION_LEFT = 0;
679e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final int DIRECTION_RIGHT = 1;
689e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final int DIRECTION_UP = 2;
699e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final int DIRECTION_DOWN = 3;
70101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
71a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen    // The brightness setting used when it is set to automatic in the system.
72a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen    // The reason why it is set to 0.7 is just because 1.0 is too bright.
73a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen    // Use the same setting among the Camera, VideoCamera and Panorama modes.
74a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen    private static final float DEFAULT_CAMERA_BRIGHTNESS = 0.7f;
75a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen
76131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala    // Orientation hysteresis amount used in rounding, in degrees
77131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala    public static final int ORIENTATION_HYSTERESIS = 5;
78131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala
791efb18228a45952d699af280482e1c51a4582690Owen Lin    public static final String REVIEW_ACTION = "com.android.camera.action.REVIEW";
8035688439f40f00a1376dcfab6e6495989d82e433Wei-Ta Chen
81bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    // Private intent extras. Test only.
829e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final String EXTRAS_CAMERA_FACING =
839e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li            "android.intent.extras.CAMERA_FACING";
84bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
85bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang    private static boolean sIsTabletUI;
8616ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li    private static float sPixelDensity = 1;
87ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang    private static ImageFileNamer sImageFileNamer;
88bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang
89101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    private Util() {
90101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
91101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
92bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang    public static void initialize(Context context) {
934c7b291018e08dbb4bc1712d95117a294fa1416cWu-cheng Li        sIsTabletUI = (context.getResources().getConfiguration().smallestScreenWidthDp >= 600);
9416ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li
9516ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li        DisplayMetrics metrics = new DisplayMetrics();
9616ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li        WindowManager wm = (WindowManager)
9716ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li                context.getSystemService(Context.WINDOW_SERVICE);
9816ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li        wm.getDefaultDisplay().getMetrics(metrics);
9916ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li        sPixelDensity = metrics.density;
100ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang        sImageFileNamer = new ImageFileNamer(
101ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang                context.getString(R.string.image_file_name_format));
102bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang    }
103bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang
104bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang    public static boolean isTabletUI() {
105bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang        return sIsTabletUI;
106bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang    }
107bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang
10816ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li    public static int dpToPixel(int dp) {
10916ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li        return Math.round(sPixelDensity * dp);
11016ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li    }
11116ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li
112101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    // Rotates the bitmap by the specified degree.
113101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    // If a new bitmap is created, the original bitmap is recycled.
114101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static Bitmap rotate(Bitmap b, int degrees) {
1159cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li        return rotateAndMirror(b, degrees, false);
1169cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li    }
1179cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li
1189cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li    // Rotates and/or mirrors the bitmap. If a new bitmap is created, the
1199cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li    // original bitmap is recycled.
1209cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li    public static Bitmap rotateAndMirror(Bitmap b, int degrees, boolean mirror) {
1219cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li        if ((degrees != 0 || mirror) && b != null) {
122101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Matrix m = new Matrix();
123b416f542580970aeac320219b80137b1e9f8d4cdMike Dodd            // Mirror first.
124b416f542580970aeac320219b80137b1e9f8d4cdMike Dodd            // horizontal flip + rotation = -rotation + horizontal flip
1259cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li            if (mirror) {
1269cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                m.postScale(-1, 1);
1279cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                degrees = (degrees + 360) % 360;
1289cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                if (degrees == 0 || degrees == 180) {
1299cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                    m.postTranslate((float) b.getWidth(), 0);
1309cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                } else if (degrees == 90 || degrees == 270) {
1319cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                    m.postTranslate((float) b.getHeight(), 0);
1329cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                } else {
1339cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                    throw new IllegalArgumentException("Invalid degrees=" + degrees);
1349cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                }
1359cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li            }
136b416f542580970aeac320219b80137b1e9f8d4cdMike Dodd            if (degrees != 0) {
137b416f542580970aeac320219b80137b1e9f8d4cdMike Dodd                // clockwise
138b416f542580970aeac320219b80137b1e9f8d4cdMike Dodd                m.postRotate(degrees,
139b416f542580970aeac320219b80137b1e9f8d4cdMike Dodd                        (float) b.getWidth() / 2, (float) b.getHeight() / 2);
140b416f542580970aeac320219b80137b1e9f8d4cdMike Dodd            }
1419cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li
142101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            try {
143101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                Bitmap b2 = Bitmap.createBitmap(
144101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                        b, 0, 0, b.getWidth(), b.getHeight(), m, true);
145101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                if (b != b2) {
146101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    b.recycle();
147101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    b = b2;
148101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                }
149101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            } catch (OutOfMemoryError ex) {
150101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                // We have no memory to rotate. Return the original bitmap.
151101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            }
152101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
153101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return b;
154101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
155101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
156101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /*
157ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * Compute the sample size as a function of minSideLength
158ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * and maxNumOfPixels.
1593c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * minSideLength is used to specify that minimal width or height of a
1603c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * bitmap.
1613c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * maxNumOfPixels is used to specify the maximal size in pixels that is
1623c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * tolerable in terms of memory usage.
163ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     *
164ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * The function returns a sample size based on the constraints.
1656bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh     * Both size and minSideLength can be passed in as -1
166ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * which indicates no care of the corresponding constraint.
167ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * The functions prefers returning a sample size that
1686bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh     * generates a smaller bitmap, unless minSideLength = -1.
1693c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     *
1703c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * Also, the function rounds up the sample size to a power of 2 or multiple
1713c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * of 8 because BitmapFactory only honors sample size this way.
1723c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * For example, BitmapFactory downsamples an image by 2 even though the
1733c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * request is 3. So we round up the sample size to avoid OOM.
174101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
175ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang    public static int computeSampleSize(BitmapFactory.Options options,
176ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            int minSideLength, int maxNumOfPixels) {
1773c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        int initialSize = computeInitialSampleSize(options, minSideLength,
1783c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen                maxNumOfPixels);
1793c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen
1803c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        int roundedSize;
181522e836abc90bcb2d4e7a4ac37e269154d06c715Chih-Chung Chang        if (initialSize <= 8) {
1823c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            roundedSize = 1;
1833c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            while (roundedSize < initialSize) {
1843c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen                roundedSize <<= 1;
1853c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            }
1863c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        } else {
1873c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            roundedSize = (initialSize + 7) / 8 * 8;
1883c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        }
1893c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen
1903c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        return roundedSize;
1913c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen    }
1923c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen
1933c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen    private static int computeInitialSampleSize(BitmapFactory.Options options,
1943c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            int minSideLength, int maxNumOfPixels) {
195ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang        double w = options.outWidth;
196ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang        double h = options.outHeight;
197ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang
1986bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        int lowerBound = (maxNumOfPixels < 0) ? 1 :
199ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang                (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
2006bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        int upperBound = (minSideLength < 0) ? 128 :
201ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang                (int) Math.min(Math.floor(w / minSideLength),
202ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang                Math.floor(h / minSideLength));
203ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang
204f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen        if (upperBound < lowerBound) {
205f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen            // return the larger one when there is no overlapping zone.
206f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen            return lowerBound;
207f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen        }
208f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen
2096bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        if (maxNumOfPixels < 0 && minSideLength < 0) {
210ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            return 1;
2116bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        } else if (minSideLength < 0) {
212ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            return lowerBound;
213ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang        } else {
214ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            return upperBound;
215101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
216101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
217101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
218cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang    public static Bitmap makeBitmap(byte[] jpegData, int maxNumOfPixels) {
219cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang        try {
220cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            BitmapFactory.Options options = new BitmapFactory.Options();
221cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inJustDecodeBounds = true;
222cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length,
223cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang                    options);
224cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            if (options.mCancel || options.outWidth == -1
225cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang                    || options.outHeight == -1) {
226cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang                return null;
227cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            }
228cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inSampleSize = computeSampleSize(
2296bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh                    options, -1, maxNumOfPixels);
230cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inJustDecodeBounds = false;
231cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang
232cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inDither = false;
233cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
234cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            return BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length,
235cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang                    options);
236cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang        } catch (OutOfMemoryError ex) {
237cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            Log.e(TAG, "Got oom exception ", ex);
238cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            return null;
239cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang        }
240c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    }
241c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
2426bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh    public static void closeSilently(Closeable c) {
2436bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        if (c == null) return;
2446bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        try {
2456bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh            c.close();
2466bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        } catch (Throwable t) {
2476bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh            // do nothing
2486bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        }
2496bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh    }
2506bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh
251341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang    public static void Assert(boolean cond) {
252341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang        if (!cond) {
253341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang            throw new AssertionError();
254341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang        }
255341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang    }
256059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin
257dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li    public static android.hardware.Camera openCamera(Activity activity, int cameraId)
258dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            throws CameraHardwareException, CameraDisabledException {
259dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li        // Check if device policy has disabled the camera.
260dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li        DevicePolicyManager dpm = (DevicePolicyManager) activity.getSystemService(
261dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li                Context.DEVICE_POLICY_SERVICE);
262dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li        if (dpm.getCameraDisabled(null)) {
263dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            throw new CameraDisabledException();
264dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li        }
265dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li
266dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li        try {
267dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            return CameraHolder.instance().open(cameraId);
268dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li        } catch (CameraHardwareException e) {
269dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            // In eng build, we throw the exception so that test tool
270dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            // can detect it and report it
271dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            if ("eng".equals(Build.TYPE)) {
272dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li                throw new RuntimeException("openCamera failed", e);
273dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            } else {
274dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li                throw e;
275dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li            }
276dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li        }
277dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li    }
278dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li
279dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li    public static void showErrorAndFinish(final Activity activity, int msgId) {
2803f3c857e3f34650c15d764810335024654b0fcc3Owen Lin        DialogInterface.OnClickListener buttonListener =
2813f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                new DialogInterface.OnClickListener() {
2823f3c857e3f34650c15d764810335024654b0fcc3Owen Lin            public void onClick(DialogInterface dialog, int which) {
2833f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                activity.finish();
2843f3c857e3f34650c15d764810335024654b0fcc3Owen Lin            }
2853f3c857e3f34650c15d764810335024654b0fcc3Owen Lin        };
2863f3c857e3f34650c15d764810335024654b0fcc3Owen Lin        new AlertDialog.Builder(activity)
2873f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .setCancelable(false)
288db0757dc9c627e7c5206104664028e386ade7d03Wu-cheng Li                .setIconAttribute(android.R.attr.alertDialogIcon)
289dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li                .setTitle(R.string.camera_error_title)
290dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li                .setMessage(msgId)
29122d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong                .setNeutralButton(R.string.dialog_ok, buttonListener)
2923f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .show();
2933f3c857e3f34650c15d764810335024654b0fcc3Owen Lin    }
2942c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin
29573e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin    public static <T> T checkNotNull(T object) {
29673e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin        if (object == null) throw new NullPointerException();
29773e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin        return object;
29873e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin    }
29973e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin
30073e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin    public static boolean equals(Object a, Object b) {
30173e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin        return (a == b) || (a == null ? false : a.equals(b));
30273e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin    }
3034de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
3044de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    public static int nextPowerOf2(int n) {
3054de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n -= 1;
3064de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 16;
3074de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 8;
3084de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 4;
3094de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 2;
3104de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 1;
3114de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        return n + 1;
3124de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
31333be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin
31433be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin    public static float distance(float x, float y, float sx, float sy) {
31533be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        float dx = x - sx;
31633be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        float dy = y - sy;
31733be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        return (float) Math.sqrt(dx * dx + dy * dy);
31833be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin    }
31933be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin
32033be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin    public static int clamp(int x, int min, int max) {
32133be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        if (x > max) return max;
32233be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        if (x < min) return min;
32333be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        return x;
32433be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin    }
325ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang
3264aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li    public static int getDisplayRotation(Activity activity) {
327ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang        int rotation = activity.getWindowManager().getDefaultDisplay()
328ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang                .getRotation();
329ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang        switch (rotation) {
3304aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li            case Surface.ROTATION_0: return 0;
3314aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li            case Surface.ROTATION_90: return 90;
3324aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li            case Surface.ROTATION_180: return 180;
3334aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li            case Surface.ROTATION_270: return 270;
334ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang        }
3354aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li        return 0;
3364aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li    }
337ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang
3384b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li    public static int getDisplayOrientation(int degrees, int cameraId) {
3394b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li        // See android.hardware.Camera.setDisplayOrientation for
340c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        // documentation.
341c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        Camera.CameraInfo info = new Camera.CameraInfo();
342c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        Camera.getCameraInfo(cameraId, info);
343c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        int result;
344c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
345c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li            result = (info.orientation + degrees) % 360;
346c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li            result = (360 - result) % 360;  // compensate the mirror
347c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        } else {  // back-facing
348c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li            result = (info.orientation - degrees + 360) % 360;
349c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        }
3504b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li        return result;
351ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang    }
3526227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
353e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen    public static int getCameraOrientation(int cameraId) {
354e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen        Camera.CameraInfo info = new Camera.CameraInfo();
355e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen        Camera.getCameraInfo(cameraId, info);
356e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen        return info.orientation;
357e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen    }
358e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen
359131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala    public static int roundOrientation(int orientation, int orientationHistory) {
360131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala        boolean changeOrientation = false;
361131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala        if (orientationHistory == OrientationEventListener.ORIENTATION_UNKNOWN) {
362131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala            changeOrientation = true;
363131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala        } else {
364131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala            int dist = Math.abs(orientation - orientationHistory);
365131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala            dist = Math.min( dist, 360 - dist );
366131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala            changeOrientation = ( dist >= 45 + ORIENTATION_HYSTERESIS );
367131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala        }
368131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala        if (changeOrientation) {
369131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala            return ((orientation + 45) / 90 * 90) % 360;
370131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala        }
371131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala        return orientationHistory;
372131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala    }
373131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala
3746227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra    public static Size getOptimalPreviewSize(Activity currentActivity,
3756227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            List<Size> sizes, double targetRatio) {
3760fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li        // Use a very small tolerance because we want an exact match.
3770fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li        final double ASPECT_TOLERANCE = 0.001;
3786227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        if (sizes == null) return null;
3796227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3806227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        Size optimalSize = null;
3816227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        double minDiff = Double.MAX_VALUE;
3826227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3836227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // Because of bugs of overlay and layout, we sometimes will try to
3846227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // layout the viewfinder in the portrait orientation and thus get the
3856227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // wrong size of mSurfaceView. When we change the preview size, the
3866227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // new overlay will be created before the old one closed, which causes
3876227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // an exception. For now, just get the screen size
3886227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3896227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        Display display = currentActivity.getWindowManager().getDefaultDisplay();
3906227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        int targetHeight = Math.min(display.getHeight(), display.getWidth());
3916227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3926227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        if (targetHeight <= 0) {
3936227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            // We don't know the size of SurfaceView, use screen height
3946227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            targetHeight = display.getHeight();
3956227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        }
3966227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3976227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // Try to find an size match aspect ratio and size
3986227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        for (Size size : sizes) {
3996227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            double ratio = (double) size.width / size.height;
4006227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
4016227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            if (Math.abs(size.height - targetHeight) < minDiff) {
4026227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                optimalSize = size;
4036227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                minDiff = Math.abs(size.height - targetHeight);
4046227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            }
4056227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        }
4066227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
4070fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li        // Cannot find the one match the aspect ratio. This should not happen.
4080fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li        // Ignore the requirement.
4096227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        if (optimalSize == null) {
4100fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li            Log.w(TAG, "No preview size match the aspect ratio");
4116227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            minDiff = Double.MAX_VALUE;
4126227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            for (Size size : sizes) {
4136227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                if (Math.abs(size.height - targetHeight) < minDiff) {
4146227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                    optimalSize = size;
4156227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                    minDiff = Math.abs(size.height - targetHeight);
4166227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                }
4176227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            }
4186227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        }
4196227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        return optimalSize;
4206227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra    }
42110fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li
4221d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang    // Returns the largest picture size which matches the given aspect ratio.
4231d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang    public static Size getOptimalVideoSnapshotPictureSize(
4241d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang            List<Size> sizes, double targetRatio) {
4251d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang        // Use a very small tolerance because we want an exact match.
4261d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang        final double ASPECT_TOLERANCE = 0.001;
4271d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang        if (sizes == null) return null;
4281d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang
4291d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang        Size optimalSize = null;
4301d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang
4311d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang        // Try to find a size matches aspect ratio and has the largest width
4321d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang        for (Size size : sizes) {
4331d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang            double ratio = (double) size.width / size.height;
4341d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
4351d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang            if (optimalSize == null || size.width > optimalSize.width) {
4361d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang                optimalSize = size;
4371d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang            }
4381d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang        }
4391d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang
4401d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang        // Cannot find one that matches the aspect ratio. This should not happen.
4411d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang        // Ignore the requirement.
4421d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang        if (optimalSize == null) {
4431d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang            Log.w(TAG, "No picture size match the aspect ratio");
4441d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang            for (Size size : sizes) {
4451d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang                if (optimalSize == null || size.width > optimalSize.width) {
4461d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang                    optimalSize = size;
4471d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang                }
4481d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang            }
4491d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang        }
4501d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang        return optimalSize;
4511d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang    }
4521d965984ecf6c6233967a1f5d5a24f21fd2e450dChih-Chung Chang
45310fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li    public static void dumpParameters(Parameters parameters) {
45410fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        String flattened = parameters.flatten();
45510fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        StringTokenizer tokenizer = new StringTokenizer(flattened, ";");
45610fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        Log.d(TAG, "Dump all camera parameters:");
45710fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        while (tokenizer.hasMoreElements()) {
45810fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li            Log.d(TAG, tokenizer.nextToken());
45910fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        }
46010fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li    }
46110208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li
462dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li    /**
46310208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li     * Returns whether the device is voice-capable (meaning, it can do MMS).
46410208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li     */
46510208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li    public static boolean isMmsCapable(Context context) {
46610208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        TelephonyManager telephonyManager = (TelephonyManager)
46710208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li                context.getSystemService(Context.TELEPHONY_SERVICE);
46810208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        if (telephonyManager == null) {
46910208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            return false;
47010208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        }
47110208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li
47210208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        try {
47310208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            Class partypes[] = new Class[0];
47410208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            Method sIsVoiceCapable = TelephonyManager.class.getMethod(
47510208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li                    "isVoiceCapable", partypes);
47610208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li
47710208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            Object arglist[] = new Object[0];
47810208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            Object retobj = sIsVoiceCapable.invoke(telephonyManager, arglist);
47910208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            return (Boolean) retobj;
48010208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        } catch (java.lang.reflect.InvocationTargetException ite) {
48110208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            // Failure, must be another device.
48210208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            // Assume that it is voice capable.
483feaf2ccff42c44b74be814b66296f9ddedcc9aa9Wu-cheng Li        } catch (IllegalAccessException iae) {
48410208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            // Failure, must be an other device.
48510208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            // Assume that it is voice capable.
48610208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        } catch (NoSuchMethodException nsme) {
48710208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        }
48810208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        return true;
48910208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li    }
490bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
491bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    // This is for test only. Allow the camera to launch the specific camera.
492bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    public static int getCameraFacingIntentExtras(Activity currentActivity) {
493bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        int cameraId = -1;
494bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
495bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        int intentCameraId =
496bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau                currentActivity.getIntent().getIntExtra(Util.EXTRAS_CAMERA_FACING, -1);
497bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
498bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        if (isFrontCameraIntent(intentCameraId)) {
499bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            // Check if the front camera exist
500bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            int frontCameraId = CameraHolder.instance().getFrontCameraId();
501bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            if (frontCameraId != -1) {
502bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau                cameraId = frontCameraId;
503bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            }
504bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        } else if (isBackCameraIntent(intentCameraId)) {
505bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            // Check if the back camera exist
506bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            int backCameraId = CameraHolder.instance().getBackCameraId();
507bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            if (backCameraId != -1) {
508bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau                cameraId = backCameraId;
509bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            }
510bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        }
511bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        return cameraId;
512bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    }
513bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
514bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    private static boolean isFrontCameraIntent(int intentCameraId) {
515bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        return (intentCameraId == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT);
516bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    }
517bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
518bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    private static boolean isBackCameraIntent(int intentCameraId) {
519bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        return (intentCameraId == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK);
520bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    }
521bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
52297d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li    private static int mLocation[] = new int[2];
52397d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li
52497d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li    // This method is not thread-safe.
52597d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li    public static boolean pointInView(float x, float y, View v) {
52697d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li        v.getLocationInWindow(mLocation);
52797d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li        return x >= mLocation[0] && x < (mLocation[0] + v.getWidth())
52897d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li                && y >= mLocation[1] && y < (mLocation[1] + v.getHeight());
52997d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li    }
5308ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li
5318ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li    public static boolean isUriValid(Uri uri, ContentResolver resolver) {
5328ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        if (uri == null) return false;
5338ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li
5348ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        try {
5358ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r");
5368ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            if (pfd == null) {
5378ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li                Log.e(TAG, "Fail to open URI. URI=" + uri);
5388ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li                return false;
5398ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            }
5408ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            pfd.close();
5418ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        } catch (IOException ex) {
5428ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            return false;
5438ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        }
5448ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        return true;
5458ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li    }
5468ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li
5478ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li    public static void viewUri(Uri uri, Context context) {
5488ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        if (!isUriValid(uri, context.getContentResolver())) {
5498ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            Log.e(TAG, "Uri invalid. uri=" + uri);
5508ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            return;
5518ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        }
5528ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li
5538ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        try {
5548ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            context.startActivity(new Intent(Util.REVIEW_ACTION, uri));
5558ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        } catch (ActivityNotFoundException ex) {
5568ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            try {
5578ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li                context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
5588ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            } catch (ActivityNotFoundException e) {
5598ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li                Log.e(TAG, "review image fail. uri=" + uri, e);
5608ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            }
5618ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        }
5628ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li    }
563d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li
564048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang    public static void dumpRect(RectF rect, String msg) {
565048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang        Log.v(TAG, msg + "=(" + rect.left + "," + rect.top
566048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang                + "," + rect.right + "," + rect.bottom + ")");
567048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang    }
568048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang
569048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang    public static void rectFToRect(RectF rectF, Rect rect) {
570048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang        rect.left = Math.round(rectF.left);
571048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang        rect.top = Math.round(rectF.top);
572048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang        rect.right = Math.round(rectF.right);
573048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang        rect.bottom = Math.round(rectF.bottom);
574048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang    }
575048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang
576d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li    public static void prepareMatrix(Matrix matrix, boolean mirror, int displayOrientation,
577d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li            int viewWidth, int viewHeight) {
578d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        // Need mirror for front camera.
579d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        matrix.setScale(mirror ? -1 : 1, 1);
580d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        // This is the value for android.hardware.Camera.setDisplayOrientation.
581d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        matrix.postRotate(displayOrientation);
582d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        // Camera driver coordinates range from (-1000, -1000) to (1000, 1000).
583d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        // UI coordinates range from (0, 0) to (width, height).
584d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        matrix.postScale(viewWidth / 2000f, viewHeight / 2000f);
585d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li        matrix.postTranslate(viewWidth / 2f, viewHeight / 2f);
586d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li    }
587757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li
588757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li    public static String createJpegName(long dateTaken) {
589ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang        synchronized (sImageFileNamer) {
590ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang            return sImageFileNamer.generateName(dateTaken);
591ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang        }
592757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li    }
593757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li
594757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li    public static void broadcastNewPicture(Context context, Uri uri) {
595757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li        context.sendBroadcast(new Intent(android.hardware.Camera.ACTION_NEW_PICTURE, uri));
596757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li        // Keep compatibility
597757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li        context.sendBroadcast(new Intent("com.android.camera.NEW_PICTURE", uri));
598757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li    }
599ea136afa2f4d38428ad486df5fb0a24db8314a3dChih-yu Huang
600ea136afa2f4d38428ad486df5fb0a24db8314a3dChih-yu Huang    public static void fadeIn(View view) {
60130f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang        if (view.getVisibility() == View.VISIBLE) return;
60230f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang
603ea136afa2f4d38428ad486df5fb0a24db8314a3dChih-yu Huang        view.setVisibility(View.VISIBLE);
604ea136afa2f4d38428ad486df5fb0a24db8314a3dChih-yu Huang        Animation animation = new AlphaAnimation(0F, 1F);
60530f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang        animation.setDuration(400);
60630f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang        view.startAnimation(animation);
60730f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang    }
60830f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang
60930f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang    public static void fadeOut(View view) {
61030f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang        if (view.getVisibility() != View.VISIBLE) return;
61130f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang
61230f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang        Animation animation = new AlphaAnimation(1F, 0F);
61330f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang        animation.setDuration(400);
614ea136afa2f4d38428ad486df5fb0a24db8314a3dChih-yu Huang        view.startAnimation(animation);
61530f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang        view.setVisibility(View.GONE);
616ea136afa2f4d38428ad486df5fb0a24db8314a3dChih-yu Huang    }
617a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li
618a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li    public static void setRotationParameter(Parameters parameters, int cameraId, int orientation) {
619a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li        // See android.hardware.Camera.Parameters.setRotation for
620a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li        // documentation.
621a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li        int rotation = 0;
622a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li        if (orientation != OrientationEventListener.ORIENTATION_UNKNOWN) {
623a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li            CameraInfo info = CameraHolder.instance().getCameraInfo()[cameraId];
624a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li            if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
625a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                rotation = (info.orientation - orientation + 360) % 360;
626a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li            } else {  // back-facing camera
627a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                rotation = (info.orientation + orientation) % 360;
628a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li            }
629a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li        }
630a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li        parameters.setRotation(rotation);
631a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li    }
632a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li
633a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li    public static void setGpsParameters(Parameters parameters, Location loc) {
634a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li        // Clear previous GPS location from the parameters.
635a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li        parameters.removeGpsData();
636a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li
637a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li        // We always encode GpsTimeStamp
638a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li        parameters.setGpsTimestamp(System.currentTimeMillis() / 1000);
639a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li
640a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li        // Set GPS location.
641a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li        if (loc != null) {
642a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li            double lat = loc.getLatitude();
643a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li            double lon = loc.getLongitude();
644a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li            boolean hasLatLon = (lat != 0.0d) || (lon != 0.0d);
645a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li
646a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li            if (hasLatLon) {
647a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                Log.d(TAG, "Set gps location");
648a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                parameters.setGpsLatitude(lat);
649a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                parameters.setGpsLongitude(lon);
650a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                parameters.setGpsProcessingMethod(loc.getProvider().toUpperCase());
651a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                if (loc.hasAltitude()) {
652a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                    parameters.setGpsAltitude(loc.getAltitude());
653a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                } else {
654a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                    // for NETWORK_PROVIDER location provider, we may have
655a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                    // no altitude information, but the driver needs it, so
656a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                    // we fake one.
657a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                    parameters.setGpsAltitude(0);
658a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                }
659a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                if (loc.getTime() != 0) {
660a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                    // Location.getTime() is UTC in milliseconds.
661a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                    // gps-timestamp is UTC in seconds.
662a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                    long utcTimeSeconds = loc.getTime() / 1000;
663a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                    parameters.setGpsTimestamp(utcTimeSeconds);
664a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                }
665a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li            } else {
666a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li                loc = null;
667a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li            }
668a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li        }
669a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li    }
670e0861e7473d042bdd9c935f3bdf50ae220891b6cWu-cheng Li
671e0861e7473d042bdd9c935f3bdf50ae220891b6cWu-cheng Li    public static void enterLightsOutMode(Window window) {
672e0861e7473d042bdd9c935f3bdf50ae220891b6cWu-cheng Li        WindowManager.LayoutParams params = window.getAttributes();
673e0861e7473d042bdd9c935f3bdf50ae220891b6cWu-cheng Li        params.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE;
674e0861e7473d042bdd9c935f3bdf50ae220891b6cWu-cheng Li        window.setAttributes(params);
675e0861e7473d042bdd9c935f3bdf50ae220891b6cWu-cheng Li    }
676a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen
677a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen    public static void initializeScreenBrightness(Window win, ContentResolver resolver) {
678a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen        // Overright the brightness settings if it is automatic
679a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen        int mode = Settings.System.getInt(resolver, Settings.System.SCREEN_BRIGHTNESS_MODE,
680a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen                Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
681a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen        if (mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
682a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen            WindowManager.LayoutParams winParams = win.getAttributes();
683a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen            winParams.screenBrightness = DEFAULT_CAMERA_BRIGHTNESS;
684a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen            win.setAttributes(winParams);
685a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen        }
686a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen    }
687ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang
688ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang    private static class ImageFileNamer {
689ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang        private SimpleDateFormat mFormat;
690ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang
691ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang        // The date (in milliseconds) used to generate the last name.
692ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang        private long mLastDate;
693ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang
694ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang        // Number of names generated for the same second.
695ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang        private int mSameSecondCount;
696ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang
697ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang        public ImageFileNamer(String format) {
698ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang            mFormat = new SimpleDateFormat(format);
699ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang        }
700ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang
701ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang        public String generateName(long dateTaken) {
702ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang            Date date = new Date(dateTaken);
703ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang            String result = mFormat.format(date);
704ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang
705ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang            // If the last name was generated for the same second,
706ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang            // we append _1, _2, etc to the name.
707ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang            if (dateTaken / 1000 == mLastDate / 1000) {
708ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang                mSameSecondCount++;
709ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang                result += "_" + mSameSecondCount;
710ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang            } else {
711ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang                mLastDate = dateTaken;
712ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang                mSameSecondCount = 0;
713ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang            }
714ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang
715ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang            return result;
716ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang        }
717ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang    }
718101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin}
719