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 194a12eec56ad1c5a7e89168b205363a3ced7e26b6Owen Linimport android.annotation.TargetApi; 203f3c857e3f34650c15d764810335024654b0fcc3Owen Linimport android.app.Activity; 213f3c857e3f34650c15d764810335024654b0fcc3Owen Linimport android.app.AlertDialog; 22dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Liimport android.app.admin.DevicePolicyManager; 238ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.content.ActivityNotFoundException; 248ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.content.ContentResolver; 25dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Liimport android.content.Context; 263f3c857e3f34650c15d764810335024654b0fcc3Owen Linimport android.content.DialogInterface; 278ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.content.Intent; 28101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.Bitmap; 29101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.BitmapFactory; 30101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.graphics.Matrix; 31043ad7e3404cdf74afc01076551c84d70a0a01d3Wu-cheng Liimport android.graphics.Point; 32048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huangimport android.graphics.Rect; 33048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huangimport android.graphics.RectF; 34c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Liimport android.hardware.Camera; 35a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Liimport android.hardware.Camera.CameraInfo; 3610fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Liimport android.hardware.Camera.Parameters; 376227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatraimport android.hardware.Camera.Size; 38a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Liimport android.location.Location; 398ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.net.Uri; 40dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Liimport android.os.Build; 418ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport android.os.ParcelFileDescriptor; 4210208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Liimport android.telephony.TelephonyManager; 4316ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Liimport android.util.DisplayMetrics; 444d226d16bb06861527e5ec162e39d9673e23df83akahuangimport android.util.FloatMath; 45101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport android.util.Log; 46c347dd2cccb6cbad8caa8404eae1c0ae17204156Ahbong Changimport android.util.TypedValue; 476227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatraimport android.view.Display; 48a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Liimport android.view.OrientationEventListener; 49ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Changimport android.view.Surface; 50601ce56b034f111b2875e7636776f2f359f6a156Owen Linimport android.view.View; 5116ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Liimport android.view.WindowManager; 52ea136afa2f4d38428ad486df5fb0a24db8314a3dChih-yu Huangimport android.view.animation.AlphaAnimation; 53ea136afa2f4d38428ad486df5fb0a24db8314a3dChih-yu Huangimport android.view.animation.Animation; 54101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 557f0753739e843926a240c001c80ef7fa2f6a8296Owen Linimport com.android.gallery3d.common.ApiHelper; 567f0753739e843926a240c001c80ef7fa2f6a8296Owen Lin 57101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport java.io.Closeable; 588ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Liimport java.io.IOException; 5910208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Liimport java.lang.reflect.Method; 60757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Liimport java.text.SimpleDateFormat; 61757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Liimport java.util.Date; 621efb18228a45952d699af280482e1c51a4582690Owen Linimport java.util.List; 6310fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Liimport java.util.StringTokenizer; 64101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 65101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin/** 66101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin * Collection of utility functions used in this package. 67101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */ 68101d528d59f447847d5c6b7578642132c2b76f4fOwen Linpublic class Util { 6934fe2a9d33a5b4ce49862ce4558a36c62ba6d540Chih-Chung Chang private static final String TAG = "Util"; 70101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 71131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala // Orientation hysteresis amount used in rounding, in degrees 72131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala public static final int ORIENTATION_HYSTERESIS = 5; 73131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala 7471bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li public static final String REVIEW_ACTION = "com.android.camera.action.REVIEW"; 75f75f0f05491560f3be90a1cee05c1ecc90227d42Wu-cheng Li // See android.hardware.Camera.ACTION_NEW_PICTURE. 76f75f0f05491560f3be90a1cee05c1ecc90227d42Wu-cheng Li public static final String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE"; 77f75f0f05491560f3be90a1cee05c1ecc90227d42Wu-cheng Li // See android.hardware.Camera.ACTION_NEW_VIDEO. 78f75f0f05491560f3be90a1cee05c1ecc90227d42Wu-cheng Li public static final String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO"; 7971bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li 80f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang // Fields from android.hardware.Camera.Parameters 81f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang public static final String FOCUS_MODE_CONTINUOUS_PICTURE = "continuous-picture"; 82f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang public static final String RECORDING_HINT = "recording-hint"; 83f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang private static final String AUTO_EXPOSURE_LOCK_SUPPORTED = "auto-exposure-lock-supported"; 84f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang private static final String AUTO_WHITE_BALANCE_LOCK_SUPPORTED = "auto-whitebalance-lock-supported"; 85f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang private static final String VIDEO_SNAPSHOT_SUPPORTED = "video-snapshot-supported"; 86ad30bda0d0103bd8a93eb834c234341b1ab1e77fWu-cheng Li public static final String SCENE_MODE_HDR = "hdr"; 87f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang public static final String TRUE = "true"; 88f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang public static final String FALSE = "false"; 89f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang 90df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang public static boolean isSupported(String value, List<String> supported) { 91df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang return supported == null ? false : supported.indexOf(value) >= 0; 92df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang } 93df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang 94f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang public static boolean isAutoExposureLockSupported(Parameters params) { 95f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang return TRUE.equals(params.get(AUTO_EXPOSURE_LOCK_SUPPORTED)); 96f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang } 97f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang 98f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang public static boolean isAutoWhiteBalanceLockSupported(Parameters params) { 99f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang return TRUE.equals(params.get(AUTO_WHITE_BALANCE_LOCK_SUPPORTED)); 100f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang } 101f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang 102f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang public static boolean isVideoSnapshotSupported(Parameters params) { 103f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang return TRUE.equals(params.get(VIDEO_SNAPSHOT_SUPPORTED)); 104f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang } 105f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang 106ad30bda0d0103bd8a93eb834c234341b1ab1e77fWu-cheng Li public static boolean isCameraHdrSupported(Parameters params) { 107ad30bda0d0103bd8a93eb834c234341b1ab1e77fWu-cheng Li List<String> supported = params.getSupportedSceneModes(); 108ad30bda0d0103bd8a93eb834c234341b1ab1e77fWu-cheng Li return (supported != null) && supported.contains(SCENE_MODE_HDR); 109ad30bda0d0103bd8a93eb834c234341b1ab1e77fWu-cheng Li } 110ad30bda0d0103bd8a93eb834c234341b1ab1e77fWu-cheng Li 111df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) 112df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang public static boolean isMeteringAreaSupported(Parameters params) { 113df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang if (ApiHelper.HAS_CAMERA_METERING_AREA) { 114df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang return params.getMaxNumMeteringAreas() > 0; 115df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang } 116df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang return false; 117df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang } 118df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang 119df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) 120df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang public static boolean isFocusAreaSupported(Parameters params) { 121df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang if (ApiHelper.HAS_CAMERA_FOCUS_AREA) { 122df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang return (params.getMaxNumFocusAreas() > 0 123df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang && isSupported(Parameters.FOCUS_MODE_AUTO, 124df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang params.getSupportedFocusModes())); 125df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang } 126df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang return false; 127df90c922da29c6c4fa2de721e3cff19461c51715Ahbong Chang } 128f2229614847f060be34593757ca402ae62c7cc7dAhbong Chang 129bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau // Private intent extras. Test only. 1309e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li private static final String EXTRAS_CAMERA_FACING = 1319e1fcfe35695fd1e71d6c86f28075ca356e5bad5Wu-cheng Li "android.intent.extras.CAMERA_FACING"; 132bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau 13316ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li private static float sPixelDensity = 1; 134ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang private static ImageFileNamer sImageFileNamer; 135bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang 136101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin private Util() { 137101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 138101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 139bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang public static void initialize(Context context) { 14016ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li DisplayMetrics metrics = new DisplayMetrics(); 14116ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li WindowManager wm = (WindowManager) 14216ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li context.getSystemService(Context.WINDOW_SERVICE); 14316ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li wm.getDefaultDisplay().getMetrics(metrics); 14416ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li sPixelDensity = metrics.density; 145ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang sImageFileNamer = new ImageFileNamer( 146ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang context.getString(R.string.image_file_name_format)); 147bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang } 148bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang 14916ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li public static int dpToPixel(int dp) { 15016ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li return Math.round(sPixelDensity * dp); 15116ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li } 15216ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li 153101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin // Rotates the bitmap by the specified degree. 154101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin // If a new bitmap is created, the original bitmap is recycled. 155101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin public static Bitmap rotate(Bitmap b, int degrees) { 1569cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li return rotateAndMirror(b, degrees, false); 1579cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li } 1589cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li 1599cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li // Rotates and/or mirrors the bitmap. If a new bitmap is created, the 1609cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li // original bitmap is recycled. 1619cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li public static Bitmap rotateAndMirror(Bitmap b, int degrees, boolean mirror) { 1629cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li if ((degrees != 0 || mirror) && b != null) { 163101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin Matrix m = new Matrix(); 164b416f542580970aeac320219b80137b1e9f8d4cdMike Dodd // Mirror first. 165b416f542580970aeac320219b80137b1e9f8d4cdMike Dodd // horizontal flip + rotation = -rotation + horizontal flip 1669cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li if (mirror) { 1679cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li m.postScale(-1, 1); 1689cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li degrees = (degrees + 360) % 360; 1699cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li if (degrees == 0 || degrees == 180) { 170913f3784d368a5e11fee5d5db2c355ef832685daWu-cheng Li m.postTranslate(b.getWidth(), 0); 1719cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li } else if (degrees == 90 || degrees == 270) { 172913f3784d368a5e11fee5d5db2c355ef832685daWu-cheng Li m.postTranslate(b.getHeight(), 0); 1739cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li } else { 1749cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li throw new IllegalArgumentException("Invalid degrees=" + degrees); 1759cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li } 1769cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li } 177b416f542580970aeac320219b80137b1e9f8d4cdMike Dodd if (degrees != 0) { 178b416f542580970aeac320219b80137b1e9f8d4cdMike Dodd // clockwise 179b416f542580970aeac320219b80137b1e9f8d4cdMike Dodd m.postRotate(degrees, 180b416f542580970aeac320219b80137b1e9f8d4cdMike Dodd (float) b.getWidth() / 2, (float) b.getHeight() / 2); 181b416f542580970aeac320219b80137b1e9f8d4cdMike Dodd } 1829cfab4bc18b8d9d905263c687e19c06df885dca7Wu-cheng Li 183101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin try { 184101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin Bitmap b2 = Bitmap.createBitmap( 185101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin b, 0, 0, b.getWidth(), b.getHeight(), m, true); 186101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin if (b != b2) { 187101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin b.recycle(); 188101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin b = b2; 189101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 190101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } catch (OutOfMemoryError ex) { 191101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin // We have no memory to rotate. Return the original bitmap. 192101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 193101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 194101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin return b; 195101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 196101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 197101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin /* 198ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang * Compute the sample size as a function of minSideLength 199ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang * and maxNumOfPixels. 2003c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * minSideLength is used to specify that minimal width or height of a 2013c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * bitmap. 2023c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * maxNumOfPixels is used to specify the maximal size in pixels that is 2033c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * tolerable in terms of memory usage. 204ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang * 205ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang * The function returns a sample size based on the constraints. 2066bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh * Both size and minSideLength can be passed in as -1 207ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang * which indicates no care of the corresponding constraint. 208ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang * The functions prefers returning a sample size that 2096bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh * generates a smaller bitmap, unless minSideLength = -1. 2103c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * 2113c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * Also, the function rounds up the sample size to a power of 2 or multiple 2123c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * of 8 because BitmapFactory only honors sample size this way. 2133c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * For example, BitmapFactory downsamples an image by 2 even though the 2143c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen * request is 3. So we round up the sample size to avoid OOM. 215101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin */ 216ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang public static int computeSampleSize(BitmapFactory.Options options, 217ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang int minSideLength, int maxNumOfPixels) { 2183c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen int initialSize = computeInitialSampleSize(options, minSideLength, 2193c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen maxNumOfPixels); 2203c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen 2213c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen int roundedSize; 222522e836abc90bcb2d4e7a4ac37e269154d06c715Chih-Chung Chang if (initialSize <= 8) { 2233c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen roundedSize = 1; 2243c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen while (roundedSize < initialSize) { 2253c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen roundedSize <<= 1; 2263c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen } 2273c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen } else { 2283c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen roundedSize = (initialSize + 7) / 8 * 8; 2293c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen } 2303c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen 2313c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen return roundedSize; 2323c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen } 2333c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen 2343c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen private static int computeInitialSampleSize(BitmapFactory.Options options, 2353c21008c953cf6177f7771c176fa81d336e74ed8Wei-Ta Chen int minSideLength, int maxNumOfPixels) { 236ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang double w = options.outWidth; 237ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang double h = options.outHeight; 238ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang 2396bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh int lowerBound = (maxNumOfPixels < 0) ? 1 : 240ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); 2416bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh int upperBound = (minSideLength < 0) ? 128 : 242ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang (int) Math.min(Math.floor(w / minSideLength), 243ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang Math.floor(h / minSideLength)); 244ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang 245f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen if (upperBound < lowerBound) { 246f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen // return the larger one when there is no overlapping zone. 247f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen return lowerBound; 248f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen } 249f2c7e983fafaf7639a6ad090a93d1892015777edWei-Ta Chen 2506bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh if (maxNumOfPixels < 0 && minSideLength < 0) { 251ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang return 1; 2526bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh } else if (minSideLength < 0) { 253ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang return lowerBound; 254ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang } else { 255ce033a5871a0b678521411f9a3acaee2ab279178Chih-Chung Chang return upperBound; 256101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 257101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin } 258101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin 259cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang public static Bitmap makeBitmap(byte[] jpegData, int maxNumOfPixels) { 260cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang try { 261cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang BitmapFactory.Options options = new BitmapFactory.Options(); 262cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options.inJustDecodeBounds = true; 263cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length, 264cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options); 265cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang if (options.mCancel || options.outWidth == -1 266cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang || options.outHeight == -1) { 267cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang return null; 268cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang } 269cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options.inSampleSize = computeSampleSize( 2706bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh options, -1, maxNumOfPixels); 271cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options.inJustDecodeBounds = false; 272cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang 273cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options.inDither = false; 274cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options.inPreferredConfig = Bitmap.Config.ARGB_8888; 275cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang return BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length, 276cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang options); 277cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang } catch (OutOfMemoryError ex) { 278cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang Log.e(TAG, "Got oom exception ", ex); 279cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang return null; 280cd972b0cd67d7a45084d9757ebd49b8f22989eddChih-Chung Chang } 281c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang } 282c1c20e9ce386c1f660059acaede591d2d718995aChih-Chung Chang 2836bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh public static void closeSilently(Closeable c) { 2846bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh if (c == null) return; 2856bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh try { 2866bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh c.close(); 2876bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh } catch (Throwable t) { 2886bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh // do nothing 2896bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh } 2906bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh } 2916bca5289166b1444f4b98538343a24d35f46dda5Chia-chi Yeh 292341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang public static void Assert(boolean cond) { 293341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang if (!cond) { 294341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang throw new AssertionError(); 295341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang } 296341ad98e59d92769e1cc8ba68fa86c72dce0543bChih-Chung Chang } 297059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin 2984c8e827c20e7c93f94880c42456715191c55d8d0Hung-ying Tyan @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) 2994c8e827c20e7c93f94880c42456715191c55d8d0Hung-ying Tyan private static void throwIfCameraDisabled(Activity activity) throws CameraDisabledException { 300dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li // Check if device policy has disabled the camera. 3014c8e827c20e7c93f94880c42456715191c55d8d0Hung-ying Tyan if (ApiHelper.HAS_GET_CAMERA_DISABLED) { 3024c8e827c20e7c93f94880c42456715191c55d8d0Hung-ying Tyan DevicePolicyManager dpm = (DevicePolicyManager) activity.getSystemService( 3034c8e827c20e7c93f94880c42456715191c55d8d0Hung-ying Tyan Context.DEVICE_POLICY_SERVICE); 3044c8e827c20e7c93f94880c42456715191c55d8d0Hung-ying Tyan if (dpm.getCameraDisabled(null)) { 3054c8e827c20e7c93f94880c42456715191c55d8d0Hung-ying Tyan throw new CameraDisabledException(); 3064c8e827c20e7c93f94880c42456715191c55d8d0Hung-ying Tyan } 307dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li } 3084c8e827c20e7c93f94880c42456715191c55d8d0Hung-ying Tyan } 3094c8e827c20e7c93f94880c42456715191c55d8d0Hung-ying Tyan 3104c8e827c20e7c93f94880c42456715191c55d8d0Hung-ying Tyan public static CameraManager.CameraProxy openCamera(Activity activity, int cameraId) 3114c8e827c20e7c93f94880c42456715191c55d8d0Hung-ying Tyan throws CameraHardwareException, CameraDisabledException { 3124c8e827c20e7c93f94880c42456715191c55d8d0Hung-ying Tyan throwIfCameraDisabled(activity); 313dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li 314dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li try { 315dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li return CameraHolder.instance().open(cameraId); 316dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li } catch (CameraHardwareException e) { 317dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li // In eng build, we throw the exception so that test tool 318dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li // can detect it and report it 319dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li if ("eng".equals(Build.TYPE)) { 320dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li throw new RuntimeException("openCamera failed", e); 321dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li } else { 322dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li throw e; 323dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li } 324dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li } 325dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li } 326dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li 327dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li public static void showErrorAndFinish(final Activity activity, int msgId) { 3283f3c857e3f34650c15d764810335024654b0fcc3Owen Lin DialogInterface.OnClickListener buttonListener = 3293f3c857e3f34650c15d764810335024654b0fcc3Owen Lin new DialogInterface.OnClickListener() { 330913f3784d368a5e11fee5d5db2c355ef832685daWu-cheng Li @Override 3313f3c857e3f34650c15d764810335024654b0fcc3Owen Lin public void onClick(DialogInterface dialog, int which) { 3323f3c857e3f34650c15d764810335024654b0fcc3Owen Lin activity.finish(); 3333f3c857e3f34650c15d764810335024654b0fcc3Owen Lin } 3343f3c857e3f34650c15d764810335024654b0fcc3Owen Lin }; 335c347dd2cccb6cbad8caa8404eae1c0ae17204156Ahbong Chang TypedValue out = new TypedValue(); 336c347dd2cccb6cbad8caa8404eae1c0ae17204156Ahbong Chang activity.getTheme().resolveAttribute(android.R.attr.alertDialogIcon, out, true); 3373f3c857e3f34650c15d764810335024654b0fcc3Owen Lin new AlertDialog.Builder(activity) 3383f3c857e3f34650c15d764810335024654b0fcc3Owen Lin .setCancelable(false) 339dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li .setTitle(R.string.camera_error_title) 340dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li .setMessage(msgId) 34122d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong .setNeutralButton(R.string.dialog_ok, buttonListener) 342c347dd2cccb6cbad8caa8404eae1c0ae17204156Ahbong Chang .setIcon(out.resourceId) 3433f3c857e3f34650c15d764810335024654b0fcc3Owen Lin .show(); 3443f3c857e3f34650c15d764810335024654b0fcc3Owen Lin } 3452c6c6174e2363fccb4e4f29b76290e99234fe140Owen Lin 34673e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin public static <T> T checkNotNull(T object) { 34773e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin if (object == null) throw new NullPointerException(); 34873e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin return object; 34973e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin } 35073e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin 35173e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin public static boolean equals(Object a, Object b) { 35273e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin return (a == b) || (a == null ? false : a.equals(b)); 35373e782de608cbe2ddffd75c055009ff2e208f78bOwen Lin } 3544de149ceb47f2c251f646419907424bfb67d2b64Owen Lin 3554de149ceb47f2c251f646419907424bfb67d2b64Owen Lin public static int nextPowerOf2(int n) { 3564de149ceb47f2c251f646419907424bfb67d2b64Owen Lin n -= 1; 3574de149ceb47f2c251f646419907424bfb67d2b64Owen Lin n |= n >>> 16; 3584de149ceb47f2c251f646419907424bfb67d2b64Owen Lin n |= n >>> 8; 3594de149ceb47f2c251f646419907424bfb67d2b64Owen Lin n |= n >>> 4; 3604de149ceb47f2c251f646419907424bfb67d2b64Owen Lin n |= n >>> 2; 3614de149ceb47f2c251f646419907424bfb67d2b64Owen Lin n |= n >>> 1; 3624de149ceb47f2c251f646419907424bfb67d2b64Owen Lin return n + 1; 3634de149ceb47f2c251f646419907424bfb67d2b64Owen Lin } 36433be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin 36533be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin public static float distance(float x, float y, float sx, float sy) { 36633be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin float dx = x - sx; 36733be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin float dy = y - sy; 3684d226d16bb06861527e5ec162e39d9673e23df83akahuang return FloatMath.sqrt(dx * dx + dy * dy); 36933be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin } 37033be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin 37133be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin public static int clamp(int x, int min, int max) { 37233be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin if (x > max) return max; 37333be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin if (x < min) return min; 37433be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin return x; 37533be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin } 376ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang 3774aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li public static int getDisplayRotation(Activity activity) { 378ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang int rotation = activity.getWindowManager().getDefaultDisplay() 379ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang .getRotation(); 380ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang switch (rotation) { 3814aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li case Surface.ROTATION_0: return 0; 3824aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li case Surface.ROTATION_90: return 90; 3834aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li case Surface.ROTATION_180: return 180; 3844aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li case Surface.ROTATION_270: return 270; 385ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang } 3864aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li return 0; 3874aaa2130af7241f128ee561cafd17a4fb560b92cWu-cheng Li } 388ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang 3894b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li public static int getDisplayOrientation(int degrees, int cameraId) { 3904b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li // See android.hardware.Camera.setDisplayOrientation for 391c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li // documentation. 392c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li Camera.CameraInfo info = new Camera.CameraInfo(); 393c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li Camera.getCameraInfo(cameraId, info); 394c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li int result; 395c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { 396c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li result = (info.orientation + degrees) % 360; 397c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li result = (360 - result) % 360; // compensate the mirror 398c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li } else { // back-facing 399c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li result = (info.orientation - degrees + 360) % 360; 400c1dd72054122befb49aa1ca11ffa589b00186f80Wu-cheng Li } 4014b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li return result; 402ac9d0a1ce538eb4bd50cba3b257737a05b9ac4e5Chih-Chung Chang } 4036227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra 404e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen public static int getCameraOrientation(int cameraId) { 405e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen Camera.CameraInfo info = new Camera.CameraInfo(); 406e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen Camera.getCameraInfo(cameraId, info); 407e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen return info.orientation; 408e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen } 409e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen 410131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala public static int roundOrientation(int orientation, int orientationHistory) { 411131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala boolean changeOrientation = false; 412131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala if (orientationHistory == OrientationEventListener.ORIENTATION_UNKNOWN) { 413131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala changeOrientation = true; 414131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala } else { 415131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala int dist = Math.abs(orientation - orientationHistory); 416131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala dist = Math.min( dist, 360 - dist ); 417131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala changeOrientation = ( dist >= 45 + ORIENTATION_HYSTERESIS ); 418131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala } 419131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala if (changeOrientation) { 420131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala return ((orientation + 45) / 90 * 90) % 360; 421131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala } 422131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala return orientationHistory; 423131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala } 424131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala 4254a12eec56ad1c5a7e89168b205363a3ced7e26b6Owen Lin @SuppressWarnings("deprecation") 4264a12eec56ad1c5a7e89168b205363a3ced7e26b6Owen Lin @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) 4274a12eec56ad1c5a7e89168b205363a3ced7e26b6Owen Lin private static Point getDefaultDisplaySize(Activity activity, Point size) { 4284a12eec56ad1c5a7e89168b205363a3ced7e26b6Owen Lin Display d = activity.getWindowManager().getDefaultDisplay(); 4297f0753739e843926a240c001c80ef7fa2f6a8296Owen Lin if (Build.VERSION.SDK_INT >= ApiHelper.VERSION_CODES.HONEYCOMB_MR2) { 4304a12eec56ad1c5a7e89168b205363a3ced7e26b6Owen Lin d.getSize(size); 4314a12eec56ad1c5a7e89168b205363a3ced7e26b6Owen Lin } else { 4324a12eec56ad1c5a7e89168b205363a3ced7e26b6Owen Lin size.set(d.getWidth(), d.getHeight()); 4334a12eec56ad1c5a7e89168b205363a3ced7e26b6Owen Lin } 4344a12eec56ad1c5a7e89168b205363a3ced7e26b6Owen Lin return size; 4354a12eec56ad1c5a7e89168b205363a3ced7e26b6Owen Lin } 4364a12eec56ad1c5a7e89168b205363a3ced7e26b6Owen Lin 4376227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra public static Size getOptimalPreviewSize(Activity currentActivity, 4388a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li List<Size> sizes, double targetRatio) { 4390fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li // Use a very small tolerance because we want an exact match. 4408a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li final double ASPECT_TOLERANCE = 0.001; 4416227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra if (sizes == null) return null; 4426227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra 4436227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra Size optimalSize = null; 4446227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra double minDiff = Double.MAX_VALUE; 4456227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra 4466227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra // Because of bugs of overlay and layout, we sometimes will try to 4476227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra // layout the viewfinder in the portrait orientation and thus get the 448b59f282910deca258ca4381c6f4b6970a2838bedAngus Kong // wrong size of preview surface. When we change the preview size, the 4496227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra // new overlay will be created before the old one closed, which causes 450043ad7e3404cdf74afc01076551c84d70a0a01d3Wu-cheng Li // an exception. For now, just get the screen size. 4514a12eec56ad1c5a7e89168b205363a3ced7e26b6Owen Lin Point point = getDefaultDisplaySize(currentActivity, new Point()); 452043ad7e3404cdf74afc01076551c84d70a0a01d3Wu-cheng Li int targetHeight = Math.min(point.x, point.y); 4536227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra // Try to find an size match aspect ratio and size 4546227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra for (Size size : sizes) { 4556227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra double ratio = (double) size.width / size.height; 4566227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; 4576227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra if (Math.abs(size.height - targetHeight) < minDiff) { 4586227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra optimalSize = size; 4596227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra minDiff = Math.abs(size.height - targetHeight); 4606227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra } 4616227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra } 4620fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li // Cannot find the one match the aspect ratio. This should not happen. 4630fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li // Ignore the requirement. 4646227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra if (optimalSize == null) { 4650fad45d0d64569098f4daf34ff7e5ae785601304Wu-cheng Li Log.w(TAG, "No preview size match the aspect ratio"); 4666227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra minDiff = Double.MAX_VALUE; 4676227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra for (Size size : sizes) { 4686227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra if (Math.abs(size.height - targetHeight) < minDiff) { 4696227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra optimalSize = size; 4706227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra minDiff = Math.abs(size.height - targetHeight); 4716227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra } 4726227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra } 4736227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra } 4746227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra return optimalSize; 4756227fa641518492a6b660c78463da18d9ec8fcd8Nipun Kwatra } 47610fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li 477cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev // Returns the largest picture size which matches the given aspect ratio. 478cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev public static Size getOptimalVideoSnapshotPictureSize( 479cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev List<Size> sizes, double targetRatio) { 480cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev // Use a very small tolerance because we want an exact match. 481cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev final double ASPECT_TOLERANCE = 0.001; 482cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev if (sizes == null) return null; 483cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev 484cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev Size optimalSize = null; 485cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev 486cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev // Try to find a size matches aspect ratio and has the largest width 487cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev for (Size size : sizes) { 488cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev double ratio = (double) size.width / size.height; 489cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; 490cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev if (optimalSize == null || size.width > optimalSize.width) { 491cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev optimalSize = size; 492cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev } 493cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev } 494cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev 495cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev // Cannot find one that matches the aspect ratio. This should not happen. 496cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev // Ignore the requirement. 497cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev if (optimalSize == null) { 498cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev Log.w(TAG, "No picture size match the aspect ratio"); 499cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev for (Size size : sizes) { 500cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev if (optimalSize == null || size.width > optimalSize.width) { 501cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev optimalSize = size; 502cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev } 503cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev } 504cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev } 505cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev return optimalSize; 506cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev } 507cd4b5bd53fe9cbf3cdccfbba94f2bc12250eb187Iliyan Malchev 50810fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li public static void dumpParameters(Parameters parameters) { 50910fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li String flattened = parameters.flatten(); 51010fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li StringTokenizer tokenizer = new StringTokenizer(flattened, ";"); 51110fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li Log.d(TAG, "Dump all camera parameters:"); 51210fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li while (tokenizer.hasMoreElements()) { 51310fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li Log.d(TAG, tokenizer.nextToken()); 51410fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li } 51510fb15e4b1a8cd4acae1a745ada98cf9fac5a809Wu-cheng Li } 51610208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li 517dfb6f208e3f5dd7d68bcaade644aa1d1f1f0a98fWu-cheng Li /** 51810208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li * Returns whether the device is voice-capable (meaning, it can do MMS). 51910208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li */ 52010208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li public static boolean isMmsCapable(Context context) { 52110208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li TelephonyManager telephonyManager = (TelephonyManager) 52210208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li context.getSystemService(Context.TELEPHONY_SERVICE); 52310208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li if (telephonyManager == null) { 52410208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li return false; 52510208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li } 52610208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li 52710208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li try { 528043ad7e3404cdf74afc01076551c84d70a0a01d3Wu-cheng Li Class<?> partypes[] = new Class[0]; 52910208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li Method sIsVoiceCapable = TelephonyManager.class.getMethod( 53010208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li "isVoiceCapable", partypes); 53110208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li 53210208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li Object arglist[] = new Object[0]; 53310208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li Object retobj = sIsVoiceCapable.invoke(telephonyManager, arglist); 53410208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li return (Boolean) retobj; 53510208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li } catch (java.lang.reflect.InvocationTargetException ite) { 53610208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li // Failure, must be another device. 53710208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li // Assume that it is voice capable. 538feaf2ccff42c44b74be814b66296f9ddedcc9aa9Wu-cheng Li } catch (IllegalAccessException iae) { 53910208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li // Failure, must be an other device. 54010208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li // Assume that it is voice capable. 54110208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li } catch (NoSuchMethodException nsme) { 54210208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li } 54310208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li return true; 54410208b3b4e2e9ca5af27be49356288531e3cd45bWu-cheng Li } 545bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau 546bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau // This is for test only. Allow the camera to launch the specific camera. 547bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau public static int getCameraFacingIntentExtras(Activity currentActivity) { 548bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau int cameraId = -1; 549bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau 550bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau int intentCameraId = 551bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau currentActivity.getIntent().getIntExtra(Util.EXTRAS_CAMERA_FACING, -1); 552bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau 553bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau if (isFrontCameraIntent(intentCameraId)) { 554bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau // Check if the front camera exist 555bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau int frontCameraId = CameraHolder.instance().getFrontCameraId(); 556bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau if (frontCameraId != -1) { 557bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau cameraId = frontCameraId; 558bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau } 559bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau } else if (isBackCameraIntent(intentCameraId)) { 560bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau // Check if the back camera exist 561bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau int backCameraId = CameraHolder.instance().getBackCameraId(); 562bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau if (backCameraId != -1) { 563bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau cameraId = backCameraId; 564bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau } 565bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau } 566bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau return cameraId; 567bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau } 568bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau 569bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau private static boolean isFrontCameraIntent(int intentCameraId) { 570bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau return (intentCameraId == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT); 571bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau } 572bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau 573bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau private static boolean isBackCameraIntent(int intentCameraId) { 574bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau return (intentCameraId == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK); 575bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau } 576bbe9db4d12978f220aeb0379731b548420bbd6dbYu Shan Emily Lau 5777a54ffad3be4bd94365a1c70b719e41b573cc7fdPin Ting private static int sLocation[] = new int[2]; 57897d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li 57997d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li // This method is not thread-safe. 58097d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li public static boolean pointInView(float x, float y, View v) { 5817a54ffad3be4bd94365a1c70b719e41b573cc7fdPin Ting v.getLocationInWindow(sLocation); 5827a54ffad3be4bd94365a1c70b719e41b573cc7fdPin Ting return x >= sLocation[0] && x < (sLocation[0] + v.getWidth()) 5837a54ffad3be4bd94365a1c70b719e41b573cc7fdPin Ting && y >= sLocation[1] && y < (sLocation[1] + v.getHeight()); 58497d089d718dc92c0e9ccc3c923066cf4f0101c35Wu-cheng Li } 5858ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li 586bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li public static int[] getRelativeLocation(View reference, View view) { 5877a54ffad3be4bd94365a1c70b719e41b573cc7fdPin Ting reference.getLocationInWindow(sLocation); 5887a54ffad3be4bd94365a1c70b719e41b573cc7fdPin Ting int referenceX = sLocation[0]; 5897a54ffad3be4bd94365a1c70b719e41b573cc7fdPin Ting int referenceY = sLocation[1]; 5907a54ffad3be4bd94365a1c70b719e41b573cc7fdPin Ting view.getLocationInWindow(sLocation); 5917a54ffad3be4bd94365a1c70b719e41b573cc7fdPin Ting sLocation[0] -= referenceX; 5927a54ffad3be4bd94365a1c70b719e41b573cc7fdPin Ting sLocation[1] -= referenceY; 5937a54ffad3be4bd94365a1c70b719e41b573cc7fdPin Ting return sLocation; 594bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li } 595bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li 5968ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li public static boolean isUriValid(Uri uri, ContentResolver resolver) { 5978ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li if (uri == null) return false; 5988ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li 5998ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li try { 6008ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r"); 6018ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li if (pfd == null) { 6028ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li Log.e(TAG, "Fail to open URI. URI=" + uri); 6038ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li return false; 6048ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li } 6058ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li pfd.close(); 6068ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li } catch (IOException ex) { 6078ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li return false; 6088ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li } 6098ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li return true; 6108ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li } 6118ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li 61271bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li public static void viewUri(Uri uri, Context context) { 61371bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li if (!isUriValid(uri, context.getContentResolver())) { 61471bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li Log.e(TAG, "Uri invalid. uri=" + uri); 61571bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li return; 61671bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li } 61771bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li 61871bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li try { 61971bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li context.startActivity(new Intent(Util.REVIEW_ACTION, uri)); 62071bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li } catch (ActivityNotFoundException ex) { 62171bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li try { 62271bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li context.startActivity(new Intent(Intent.ACTION_VIEW, uri)); 62371bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li } catch (ActivityNotFoundException e) { 62471bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li Log.e(TAG, "review image fail. uri=" + uri, e); 62571bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li } 62671bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li } 62771bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li } 62871bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li 629048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang public static void dumpRect(RectF rect, String msg) { 630048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang Log.v(TAG, msg + "=(" + rect.left + "," + rect.top 631048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang + "," + rect.right + "," + rect.bottom + ")"); 632048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang } 633048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang 634048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang public static void rectFToRect(RectF rectF, Rect rect) { 635048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang rect.left = Math.round(rectF.left); 636048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang rect.top = Math.round(rectF.top); 637048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang rect.right = Math.round(rectF.right); 638048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang rect.bottom = Math.round(rectF.bottom); 639048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang } 640048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang 641d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li public static void prepareMatrix(Matrix matrix, boolean mirror, int displayOrientation, 642d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li int viewWidth, int viewHeight) { 643d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li // Need mirror for front camera. 644d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li matrix.setScale(mirror ? -1 : 1, 1); 645d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li // This is the value for android.hardware.Camera.setDisplayOrientation. 646d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li matrix.postRotate(displayOrientation); 647d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li // Camera driver coordinates range from (-1000, -1000) to (1000, 1000). 648d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li // UI coordinates range from (0, 0) to (width, height). 649d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li matrix.postScale(viewWidth / 2000f, viewHeight / 2000f); 650d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li matrix.postTranslate(viewWidth / 2f, viewHeight / 2f); 651d2db70880e6159413932f747eb82df3e925852c1Wu-cheng Li } 652757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li 653757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li public static String createJpegName(long dateTaken) { 654ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang synchronized (sImageFileNamer) { 655ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang return sImageFileNamer.generateName(dateTaken); 656ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang } 657757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li } 658757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li 659757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li public static void broadcastNewPicture(Context context, Uri uri) { 660f75f0f05491560f3be90a1cee05c1ecc90227d42Wu-cheng Li context.sendBroadcast(new Intent(ACTION_NEW_PICTURE, uri)); 661757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li // Keep compatibility 662757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li context.sendBroadcast(new Intent("com.android.camera.NEW_PICTURE", uri)); 663757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li } 664ea136afa2f4d38428ad486df5fb0a24db8314a3dChih-yu Huang 665a1f6eec7b587064b5677160668345f5610073b51akahuang public static void fadeIn(View view, float startAlpha, float endAlpha, long duration) { 66630f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang if (view.getVisibility() == View.VISIBLE) return; 66730f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang 668ea136afa2f4d38428ad486df5fb0a24db8314a3dChih-yu Huang view.setVisibility(View.VISIBLE); 669a1f6eec7b587064b5677160668345f5610073b51akahuang Animation animation = new AlphaAnimation(startAlpha, endAlpha); 670a1f6eec7b587064b5677160668345f5610073b51akahuang animation.setDuration(duration); 67130f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang view.startAnimation(animation); 67230f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang } 67330f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang 674a1f6eec7b587064b5677160668345f5610073b51akahuang public static void fadeIn(View view) { 675a1f6eec7b587064b5677160668345f5610073b51akahuang fadeIn(view, 0F, 1F, 400); 676aaf129e4b755e4eef9eaa0fd736a9bbd20904fc8Pin Ting 677aaf129e4b755e4eef9eaa0fd736a9bbd20904fc8Pin Ting // We disabled the button in fadeOut(), so enable it here. 678aaf129e4b755e4eef9eaa0fd736a9bbd20904fc8Pin Ting view.setEnabled(true); 679a1f6eec7b587064b5677160668345f5610073b51akahuang } 680a1f6eec7b587064b5677160668345f5610073b51akahuang 68130f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang public static void fadeOut(View view) { 68230f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang if (view.getVisibility() != View.VISIBLE) return; 68330f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang 684aaf129e4b755e4eef9eaa0fd736a9bbd20904fc8Pin Ting // Since the button is still clickable before fade-out animation 685aaf129e4b755e4eef9eaa0fd736a9bbd20904fc8Pin Ting // ends, we disable the button first to block click. 686aaf129e4b755e4eef9eaa0fd736a9bbd20904fc8Pin Ting view.setEnabled(false); 68730f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang Animation animation = new AlphaAnimation(1F, 0F); 68830f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang animation.setDuration(400); 689ea136afa2f4d38428ad486df5fb0a24db8314a3dChih-yu Huang view.startAnimation(animation); 69030f0481931beed547656f2c7bc6290ecc9b01ac3Chih-yu Huang view.setVisibility(View.GONE); 691ea136afa2f4d38428ad486df5fb0a24db8314a3dChih-yu Huang } 692a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li 693b130b9af898f597eb7506dd2f29f0961b858176dWu-cheng Li public static int getJpegRotation(int cameraId, int orientation) { 694a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li // See android.hardware.Camera.Parameters.setRotation for 695a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li // documentation. 696a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li int rotation = 0; 697a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li if (orientation != OrientationEventListener.ORIENTATION_UNKNOWN) { 698a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li CameraInfo info = CameraHolder.instance().getCameraInfo()[cameraId]; 699a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li if (info.facing == CameraInfo.CAMERA_FACING_FRONT) { 700a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li rotation = (info.orientation - orientation + 360) % 360; 701a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li } else { // back-facing camera 702a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li rotation = (info.orientation + orientation) % 360; 703a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li } 704a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li } 705b130b9af898f597eb7506dd2f29f0961b858176dWu-cheng Li return rotation; 706a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li } 707a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li 708a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li public static void setGpsParameters(Parameters parameters, Location loc) { 709a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li // Clear previous GPS location from the parameters. 710a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li parameters.removeGpsData(); 711a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li 712a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li // We always encode GpsTimeStamp 713a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li parameters.setGpsTimestamp(System.currentTimeMillis() / 1000); 714a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li 715a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li // Set GPS location. 716a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li if (loc != null) { 717a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li double lat = loc.getLatitude(); 718a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li double lon = loc.getLongitude(); 719a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li boolean hasLatLon = (lat != 0.0d) || (lon != 0.0d); 720a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li 721a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li if (hasLatLon) { 722a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li Log.d(TAG, "Set gps location"); 723a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li parameters.setGpsLatitude(lat); 724a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li parameters.setGpsLongitude(lon); 725a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li parameters.setGpsProcessingMethod(loc.getProvider().toUpperCase()); 726a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li if (loc.hasAltitude()) { 727a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li parameters.setGpsAltitude(loc.getAltitude()); 728a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li } else { 729a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li // for NETWORK_PROVIDER location provider, we may have 730a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li // no altitude information, but the driver needs it, so 731a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li // we fake one. 732a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li parameters.setGpsAltitude(0); 733a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li } 734a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li if (loc.getTime() != 0) { 735a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li // Location.getTime() is UTC in milliseconds. 736a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li // gps-timestamp is UTC in seconds. 737a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li long utcTimeSeconds = loc.getTime() / 1000; 738a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li parameters.setGpsTimestamp(utcTimeSeconds); 739a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li } 740a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li } else { 741a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li loc = null; 742a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li } 743a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li } 744a93a4d60eacee4e12471b45f8691c14114e113a4Wu-cheng Li } 745e0861e7473d042bdd9c935f3bdf50ae220891b6cWu-cheng Li 746ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang private static class ImageFileNamer { 747ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang private SimpleDateFormat mFormat; 748ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang 749ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang // The date (in milliseconds) used to generate the last name. 750ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang private long mLastDate; 751ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang 752ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang // Number of names generated for the same second. 753ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang private int mSameSecondCount; 754ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang 755ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang public ImageFileNamer(String format) { 756ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang mFormat = new SimpleDateFormat(format); 757ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang } 758ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang 759ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang public String generateName(long dateTaken) { 760ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang Date date = new Date(dateTaken); 761ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang String result = mFormat.format(date); 762ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang 763ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang // If the last name was generated for the same second, 764ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang // we append _1, _2, etc to the name. 765ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang if (dateTaken / 1000 == mLastDate / 1000) { 766ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang mSameSecondCount++; 767ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang result += "_" + mSameSecondCount; 768ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang } else { 769ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang mLastDate = dateTaken; 770ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang mSameSecondCount = 0; 771ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang } 772ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang 773ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang return result; 774ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang } 775ee740f1254232cbe5b8dd34c0c957866c03e7787Chih-Chung Chang } 776101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin} 777