Util.java revision 8ab2b624d51b3b8254ece98c46a7e22a6fb5d4aa
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;
218ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.content.ActivityNotFoundException;
2210208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Liimport android.content.Context;
238ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.content.ContentResolver;
243f3c857e3f34650c15d764810335024654b0fcc3Owen Linimport android.content.DialogInterface;
258ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.content.Intent;
26101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.Bitmap;
27101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.BitmapFactory;
28101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.Matrix;
29c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Liimport android.hardware.Camera;
3010fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Liimport android.hardware.Camera.Parameters;
316227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatraimport android.hardware.Camera.Size;
328ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.net.Uri;
338ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.os.ParcelFileDescriptor;
3410208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Liimport android.telephony.TelephonyManager;
35101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.util.Log;
366227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatraimport android.view.Display;
37ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Changimport android.view.Surface;
38601ce56b034f111b2875e7636776f2f359f6a156Owen Linimport android.view.View;
392c6c6174e2363fccb4e4f29b76290e99234fe140Owen Linimport android.view.animation.Animation;
402c6c6174e2363fccb4e4f29b76290e99234fe140Owen Linimport android.view.animation.TranslateAnimation;
41101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
42101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport java.io.Closeable;
438ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport java.io.IOException;
4410208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Liimport java.lang.reflect.Method;
451efb18228a45952d699af280482e1c51a4582690Owen Linimport java.util.List;
4610fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Liimport java.util.StringTokenizer;
47101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
48101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin/**
49101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Collection of utility functions used in this package.
50101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */
51101d528d59f447847d5c6b7578642132c2b76f4fOwen Linpublic class Util {
5234fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang    private static final String TAG = "Util";
539e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final int DIRECTION_LEFT = 0;
549e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final int DIRECTION_RIGHT = 1;
559e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final int DIRECTION_UP = 2;
569e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final int DIRECTION_DOWN = 3;
57101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
581efb18228a45952d699af280482e1c51a4582690Owen Lin    public static final String REVIEW_ACTION = "com.android.camera.action.REVIEW";
5935688439f40f00a1376dcfab6e6495989d82e433Wei-Ta Chen
60bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    // Private intent extras. Test only.
619e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li    private static final String EXTRAS_CAMERA_FACING =
629e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li            "android.intent.extras.CAMERA_FACING";
63bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
64101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    private Util() {
65101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
66101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
67101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    // Rotates the bitmap by the specified degree.
68101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    // If a new bitmap is created, the original bitmap is recycled.
69101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    public static Bitmap rotate(Bitmap b, int degrees) {
709cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li        return rotateAndMirror(b, degrees, false);
719cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li    }
729cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li
739cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li    // Rotates and/or mirrors the bitmap. If a new bitmap is created, the
749cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li    // original bitmap is recycled.
759cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li    public static Bitmap rotateAndMirror(Bitmap b, int degrees, boolean mirror) {
769cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li        if ((degrees != 0 || mirror) && b != null) {
77101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            Matrix m = new Matrix();
78101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            m.setRotate(degrees,
79101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    (float) b.getWidth() / 2, (float) b.getHeight() / 2);
809cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li            if (mirror) {
819cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                m.postScale(-1, 1);
829cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                degrees = (degrees + 360) % 360;
839cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                if (degrees == 0 || degrees == 180) {
849cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                    m.postTranslate((float) b.getWidth(), 0);
859cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                } else if (degrees == 90 || degrees == 270) {
869cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                    m.postTranslate((float) b.getHeight(), 0);
879cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                } else {
889cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                    throw new IllegalArgumentException("Invalid degrees=" + degrees);
899cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li                }
909cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li            }
919cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li
92101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            try {
93101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                Bitmap b2 = Bitmap.createBitmap(
94101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                        b, 0, 0, b.getWidth(), b.getHeight(), m, true);
95101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                if (b != b2) {
96101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    b.recycle();
97101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                    b = b2;
98101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                }
99101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            } catch (OutOfMemoryError ex) {
100101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin                // We have no memory to rotate. Return the original bitmap.
101101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin            }
102101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
103101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        return b;
104101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
105101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
106101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    /*
107ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * Compute the sample size as a function of minSideLength
108ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * and maxNumOfPixels.
1093c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * minSideLength is used to specify that minimal width or height of a
1103c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * bitmap.
1113c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * maxNumOfPixels is used to specify the maximal size in pixels that is
1123c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * tolerable in terms of memory usage.
113ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     *
114ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * The function returns a sample size based on the constraints.
1156bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh     * Both size and minSideLength can be passed in as -1
116ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * which indicates no care of the corresponding constraint.
117ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang     * The functions prefers returning a sample size that
1186bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh     * generates a smaller bitmap, unless minSideLength = -1.
1193c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     *
1203c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * Also, the function rounds up the sample size to a power of 2 or multiple
1213c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * of 8 because BitmapFactory only honors sample size this way.
1223c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * For example, BitmapFactory downsamples an image by 2 even though the
1233c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen     * request is 3. So we round up the sample size to avoid OOM.
124101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin     */
125ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang    public static int computeSampleSize(BitmapFactory.Options options,
126ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            int minSideLength, int maxNumOfPixels) {
1273c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        int initialSize = computeInitialSampleSize(options, minSideLength,
1283c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen                maxNumOfPixels);
1293c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen
1303c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        int roundedSize;
131522e836abc90bcb2d4e7a4ac37e269154d06c715Chih-Chung Chang        if (initialSize <= 8) {
1323c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            roundedSize = 1;
1333c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            while (roundedSize < initialSize) {
1343c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen                roundedSize <<= 1;
1353c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            }
1363c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        } else {
1373c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            roundedSize = (initialSize + 7) / 8 * 8;
1383c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        }
1393c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen
1403c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen        return roundedSize;
1413c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen    }
1423c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen
1433c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen    private static int computeInitialSampleSize(BitmapFactory.Options options,
1443c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen            int minSideLength, int maxNumOfPixels) {
145ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang        double w = options.outWidth;
146ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang        double h = options.outHeight;
147ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang
1486bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        int lowerBound = (maxNumOfPixels < 0) ? 1 :
149ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang                (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
1506bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        int upperBound = (minSideLength < 0) ? 128 :
151ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang                (int) Math.min(Math.floor(w / minSideLength),
152ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang                Math.floor(h / minSideLength));
153ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang
154f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen        if (upperBound < lowerBound) {
155f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen            // return the larger one when there is no overlapping zone.
156f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen            return lowerBound;
157f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen        }
158f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen
1596bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        if (maxNumOfPixels < 0 && minSideLength < 0) {
160ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            return 1;
1616bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        } else if (minSideLength < 0) {
162ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            return lowerBound;
163ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang        } else {
164ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang            return upperBound;
165101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        }
166101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin    }
167101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
168cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang    public static Bitmap makeBitmap(byte[] jpegData, int maxNumOfPixels) {
169cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang        try {
170cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            BitmapFactory.Options options = new BitmapFactory.Options();
171cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inJustDecodeBounds = true;
172cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length,
173cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang                    options);
174cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            if (options.mCancel || options.outWidth == -1
175cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang                    || options.outHeight == -1) {
176cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang                return null;
177cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            }
178cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inSampleSize = computeSampleSize(
1796bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh                    options, -1, maxNumOfPixels);
180cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inJustDecodeBounds = false;
181cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang
182cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inDither = false;
183cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
184cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            return BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length,
185cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang                    options);
186cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang        } catch (OutOfMemoryError ex) {
187cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            Log.e(TAG, "Got oom exception ", ex);
188cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang            return null;
189cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang        }
190c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang    }
191c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang
1926bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh    public static void closeSilently(Closeable c) {
1936bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        if (c == null) return;
1946bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        try {
1956bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh            c.close();
1966bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        } catch (Throwable t) {
1976bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh            // do nothing
1986bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh        }
1996bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh    }
2006bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh
201341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang    public static void Assert(boolean cond) {
202341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang        if (!cond) {
203341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang            throw new AssertionError();
204341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang        }
205341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang    }
206059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin
2073f3c857e3f34650c15d764810335024654b0fcc3Owen Lin    public static void showFatalErrorAndFinish(
2083f3c857e3f34650c15d764810335024654b0fcc3Owen Lin            final Activity activity, String title, String message) {
2093f3c857e3f34650c15d764810335024654b0fcc3Owen Lin        DialogInterface.OnClickListener buttonListener =
2103f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                new DialogInterface.OnClickListener() {
2113f3c857e3f34650c15d764810335024654b0fcc3Owen Lin            public void onClick(DialogInterface dialog, int which) {
2123f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                activity.finish();
2133f3c857e3f34650c15d764810335024654b0fcc3Owen Lin            }
2143f3c857e3f34650c15d764810335024654b0fcc3Owen Lin        };
2153f3c857e3f34650c15d764810335024654b0fcc3Owen Lin        new AlertDialog.Builder(activity)
2163f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .setCancelable(false)
217db0757dc9c627e7c5206104664028e386ade7d03Wu-cheng Li                .setIconAttribute(android.R.attr.alertDialogIcon)
2183f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .setTitle(title)
2193f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .setMessage(message)
2203f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .setNeutralButton(R.string.details_ok, buttonListener)
2213f3c857e3f34650c15d764810335024654b0fcc3Owen Lin                .show();
2223f3c857e3f34650c15d764810335024654b0fcc3Owen Lin    }
2232c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin
22473e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin    public static <T> T checkNotNull(T object) {
22573e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin        if (object == null) throw new NullPointerException();
22673e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin        return object;
22773e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin    }
22873e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin
22973e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin    public static boolean equals(Object a, Object b) {
23073e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin        return (a == b) || (a == null ? false : a.equals(b));
23173e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin    }
2324de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
2334de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    public static int nextPowerOf2(int n) {
2344de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n -= 1;
2354de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 16;
2364de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 8;
2374de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 4;
2384de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 2;
2394de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        n |= n >>> 1;
2404de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        return n + 1;
2414de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
24233be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin
24333be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin    public static float distance(float x, float y, float sx, float sy) {
24433be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        float dx = x - sx;
24533be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        float dy = y - sy;
24633be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        return (float) Math.sqrt(dx * dx + dy * dy);
24733be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin    }
24833be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin
24933be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin    public static int clamp(int x, int min, int max) {
25033be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        if (x > max) return max;
25133be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        if (x < min) return min;
25233be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        return x;
25333be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin    }
254ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang
2554aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li    public static int getDisplayRotation(Activity activity) {
256ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang        int rotation = activity.getWindowManager().getDefaultDisplay()
257ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang                .getRotation();
258ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang        switch (rotation) {
2594aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li            case Surface.ROTATION_0: return 0;
2604aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li            case Surface.ROTATION_90: return 90;
2614aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li            case Surface.ROTATION_180: return 180;
2624aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li            case Surface.ROTATION_270: return 270;
263ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang        }
2644aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li        return 0;
2654aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li    }
266ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang
267855b4ca04f982c7110acd81b509c955df976926fWu-cheng Li    public static void setCameraDisplayOrientation(int degrees,
268c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li            int cameraId, Camera camera) {
269c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        // See android.hardware.Camera.setCameraDisplayOrientation for
270c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        // documentation.
271c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        Camera.CameraInfo info = new Camera.CameraInfo();
272c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        Camera.getCameraInfo(cameraId, info);
273c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        int result;
274c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
275c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li            result = (info.orientation + degrees) % 360;
276c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li            result = (360 - result) % 360;  // compensate the mirror
277c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        } else {  // back-facing
278c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li            result = (info.orientation - degrees + 360) % 360;
279c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li        }
280ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang        camera.setDisplayOrientation(result);
281ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang    }
2826227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
2836227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra    public static Size getOptimalPreviewSize(Activity currentActivity,
2846227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            List<Size> sizes, double targetRatio) {
2850fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li        // Use a very small tolerance because we want an exact match.
2860fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li        final double ASPECT_TOLERANCE = 0.001;
2876227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        if (sizes == null) return null;
2886227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
2896227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        Size optimalSize = null;
2906227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        double minDiff = Double.MAX_VALUE;
2916227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
2926227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // Because of bugs of overlay and layout, we sometimes will try to
2936227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // layout the viewfinder in the portrait orientation and thus get the
2946227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // wrong size of mSurfaceView. When we change the preview size, the
2956227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // new overlay will be created before the old one closed, which causes
2966227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // an exception. For now, just get the screen size
2976227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
2986227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        Display display = currentActivity.getWindowManager().getDefaultDisplay();
2996227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        int targetHeight = Math.min(display.getHeight(), display.getWidth());
3006227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3016227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        if (targetHeight <= 0) {
3026227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            // We don't know the size of SurfaceView, use screen height
3036227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            targetHeight = display.getHeight();
3046227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        }
3056227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3066227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        // Try to find an size match aspect ratio and size
3076227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        for (Size size : sizes) {
3086227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            double ratio = (double) size.width / size.height;
3096227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
3106227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            if (Math.abs(size.height - targetHeight) < minDiff) {
3116227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                optimalSize = size;
3126227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                minDiff = Math.abs(size.height - targetHeight);
3136227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            }
3146227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        }
3156227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra
3160fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li        // Cannot find the one match the aspect ratio. This should not happen.
3170fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li        // Ignore the requirement.
3186227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        if (optimalSize == null) {
3190fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li            Log.w(TAG, "No preview size match the aspect ratio");
3206227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            minDiff = Double.MAX_VALUE;
3216227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            for (Size size : sizes) {
3226227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                if (Math.abs(size.height - targetHeight) < minDiff) {
3236227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                    optimalSize = size;
3246227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                    minDiff = Math.abs(size.height - targetHeight);
3256227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra                }
3266227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra            }
3276227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        }
3286227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra        return optimalSize;
3296227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra    }
33010fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li
33110fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li    public static void dumpParameters(Parameters parameters) {
33210fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        String flattened = parameters.flatten();
33310fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        StringTokenizer tokenizer = new StringTokenizer(flattened, ";");
33410fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        Log.d(TAG, "Dump all camera parameters:");
33510fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        while (tokenizer.hasMoreElements()) {
33610fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li            Log.d(TAG, tokenizer.nextToken());
33710fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li        }
33810fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li    }
33910208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li
34010208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li   /**
34110208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li     * Returns whether the device is voice-capable (meaning, it can do MMS).
34210208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li     */
34310208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li    public static boolean isMmsCapable(Context context) {
34410208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        TelephonyManager telephonyManager = (TelephonyManager)
34510208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li                context.getSystemService(Context.TELEPHONY_SERVICE);
34610208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        if (telephonyManager == null) {
34710208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            return false;
34810208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        }
34910208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li
35010208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        try {
35110208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            Class partypes[] = new Class[0];
35210208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            Method sIsVoiceCapable = TelephonyManager.class.getMethod(
35310208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li                    "isVoiceCapable", partypes);
35410208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li
35510208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            Object arglist[] = new Object[0];
35610208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            Object retobj = sIsVoiceCapable.invoke(telephonyManager, arglist);
35710208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            return (Boolean) retobj;
35810208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        } catch (java.lang.reflect.InvocationTargetException ite) {
35910208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            // Failure, must be another device.
36010208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            // Assume that it is voice capable.
361feaf2ccff42c44b74be814b66296f9ddedcc9aa9Wu-cheng Li        } catch (IllegalAccessException iae) {
36210208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            // Failure, must be an other device.
36310208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li            // Assume that it is voice capable.
36410208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        } catch (NoSuchMethodException nsme) {
36510208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        }
36610208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li        return true;
36710208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li    }
368bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
369bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    // This is for test only. Allow the camera to launch the specific camera.
370bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    public static int getCameraFacingIntentExtras(Activity currentActivity) {
371bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        int cameraId = -1;
372bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
373bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        int intentCameraId =
374bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau                currentActivity.getIntent().getIntExtra(Util.EXTRAS_CAMERA_FACING, -1);
375bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
376bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        if (isFrontCameraIntent(intentCameraId)) {
377bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            // Check if the front camera exist
378bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            int frontCameraId = CameraHolder.instance().getFrontCameraId();
379bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            if (frontCameraId != -1) {
380bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau                cameraId = frontCameraId;
381bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            }
382bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        } else if (isBackCameraIntent(intentCameraId)) {
383bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            // Check if the back camera exist
384bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            int backCameraId = CameraHolder.instance().getBackCameraId();
385bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            if (backCameraId != -1) {
386bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau                cameraId = backCameraId;
387bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau            }
388bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        }
389bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        return cameraId;
390bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    }
391bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
392bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    private static boolean isFrontCameraIntent(int intentCameraId) {
393bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        return (intentCameraId == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT);
394bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    }
395bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
396bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    private static boolean isBackCameraIntent(int intentCameraId) {
397bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau        return (intentCameraId == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK);
398bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau    }
399bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau
40097d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li    private static int mLocation[] = new int[2];
40197d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li
40297d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li    // This method is not thread-safe.
40397d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li    public static boolean pointInView(float x, float y, View v) {
40497d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li        v.getLocationInWindow(mLocation);
40597d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li        return x >= mLocation[0] && x < (mLocation[0] + v.getWidth())
40697d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li                && y >= mLocation[1] && y < (mLocation[1] + v.getHeight());
40797d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li    }
4088ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li
4098ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li    public static boolean isUriValid(Uri uri, ContentResolver resolver) {
4108ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        if (uri == null) return false;
4118ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li
4128ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        try {
4138ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r");
4148ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            if (pfd == null) {
4158ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li                Log.e(TAG, "Fail to open URI. URI=" + uri);
4168ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li                return false;
4178ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            }
4188ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            pfd.close();
4198ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        } catch (IOException ex) {
4208ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            return false;
4218ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        }
4228ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        return true;
4238ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li    }
4248ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li
4258ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li    public static void viewUri(Uri uri, Context context) {
4268ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        if (!isUriValid(uri, context.getContentResolver())) {
4278ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            Log.e(TAG, "Uri invalid. uri=" + uri);
4288ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            return;
4298ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        }
4308ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li
4318ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        try {
4328ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            context.startActivity(new Intent(Util.REVIEW_ACTION, uri));
4338ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        } catch (ActivityNotFoundException ex) {
4348ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            try {
4358ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li                context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
4368ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            } catch (ActivityNotFoundException e) {
4378ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li                Log.e(TAG, "review image fail. uri=" + uri, e);
4388ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li            }
4398ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li        }
4408ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li    }
441101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin}
442