Home | History | Annotate | Download | only in camera
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.camera;
     18 
     19 import android.app.Activity;
     20 import android.app.AlertDialog;
     21 import android.app.admin.DevicePolicyManager;
     22 import android.content.ActivityNotFoundException;
     23 import android.content.ContentResolver;
     24 import android.content.Context;
     25 import android.content.DialogInterface;
     26 import android.content.Intent;
     27 import android.graphics.Bitmap;
     28 import android.graphics.BitmapFactory;
     29 import android.graphics.Matrix;
     30 import android.graphics.Rect;
     31 import android.graphics.RectF;
     32 import android.hardware.Camera;
     33 import android.hardware.Camera.CameraInfo;
     34 import android.hardware.Camera.Parameters;
     35 import android.hardware.Camera.Size;
     36 import android.location.Location;
     37 import android.net.Uri;
     38 import android.os.Build;
     39 import android.os.ParcelFileDescriptor;
     40 import android.provider.Settings;
     41 import android.telephony.TelephonyManager;
     42 import android.util.DisplayMetrics;
     43 import android.util.Log;
     44 import android.view.Display;
     45 import android.view.OrientationEventListener;
     46 import android.view.Surface;
     47 import android.view.View;
     48 import android.view.Window;
     49 import android.view.WindowManager;
     50 import android.view.animation.AlphaAnimation;
     51 import android.view.animation.Animation;
     52 
     53 import java.io.Closeable;
     54 import java.io.IOException;
     55 import java.lang.reflect.Method;
     56 import java.text.SimpleDateFormat;
     57 import java.util.Date;
     58 import java.util.List;
     59 import java.util.StringTokenizer;
     60 
     61 /**
     62  * Collection of utility functions used in this package.
     63  */
     64 public class Util {
     65     private static final String TAG = "Util";
     66     private static final int DIRECTION_LEFT = 0;
     67     private static final int DIRECTION_RIGHT = 1;
     68     private static final int DIRECTION_UP = 2;
     69     private static final int DIRECTION_DOWN = 3;
     70 
     71     // The brightness setting used when it is set to automatic in the system.
     72     // The reason why it is set to 0.7 is just because 1.0 is too bright.
     73     // Use the same setting among the Camera, VideoCamera and Panorama modes.
     74     private static final float DEFAULT_CAMERA_BRIGHTNESS = 0.7f;
     75 
     76     // Orientation hysteresis amount used in rounding, in degrees
     77     public static final int ORIENTATION_HYSTERESIS = 5;
     78 
     79     public static final String REVIEW_ACTION = "com.android.camera.action.REVIEW";
     80 
     81     // Private intent extras. Test only.
     82     private static final String EXTRAS_CAMERA_FACING =
     83             "android.intent.extras.CAMERA_FACING";
     84 
     85     private static boolean sIsTabletUI;
     86     private static float sPixelDensity = 1;
     87     private static ImageFileNamer sImageFileNamer;
     88 
     89     private Util() {
     90     }
     91 
     92     public static void initialize(Context context) {
     93         sIsTabletUI = (context.getResources().getConfiguration().screenWidthDp >= 1024);
     94 
     95         DisplayMetrics metrics = new DisplayMetrics();
     96         WindowManager wm = (WindowManager)
     97                 context.getSystemService(Context.WINDOW_SERVICE);
     98         wm.getDefaultDisplay().getMetrics(metrics);
     99         sPixelDensity = metrics.density;
    100         sImageFileNamer = new ImageFileNamer(
    101                 context.getString(R.string.image_file_name_format));
    102     }
    103 
    104     public static boolean isTabletUI() {
    105         return sIsTabletUI;
    106     }
    107 
    108     public static int dpToPixel(int dp) {
    109         return Math.round(sPixelDensity * dp);
    110     }
    111 
    112     // Rotates the bitmap by the specified degree.
    113     // If a new bitmap is created, the original bitmap is recycled.
    114     public static Bitmap rotate(Bitmap b, int degrees) {
    115         return rotateAndMirror(b, degrees, false);
    116     }
    117 
    118     // Rotates and/or mirrors the bitmap. If a new bitmap is created, the
    119     // original bitmap is recycled.
    120     public static Bitmap rotateAndMirror(Bitmap b, int degrees, boolean mirror) {
    121         if ((degrees != 0 || mirror) && b != null) {
    122             Matrix m = new Matrix();
    123             // Mirror first.
    124             // horizontal flip + rotation = -rotation + horizontal flip
    125             if (mirror) {
    126                 m.postScale(-1, 1);
    127                 degrees = (degrees + 360) % 360;
    128                 if (degrees == 0 || degrees == 180) {
    129                     m.postTranslate((float) b.getWidth(), 0);
    130                 } else if (degrees == 90 || degrees == 270) {
    131                     m.postTranslate((float) b.getHeight(), 0);
    132                 } else {
    133                     throw new IllegalArgumentException("Invalid degrees=" + degrees);
    134                 }
    135             }
    136             if (degrees != 0) {
    137                 // clockwise
    138                 m.postRotate(degrees,
    139                         (float) b.getWidth() / 2, (float) b.getHeight() / 2);
    140             }
    141 
    142             try {
    143                 Bitmap b2 = Bitmap.createBitmap(
    144                         b, 0, 0, b.getWidth(), b.getHeight(), m, true);
    145                 if (b != b2) {
    146                     b.recycle();
    147                     b = b2;
    148                 }
    149             } catch (OutOfMemoryError ex) {
    150                 // We have no memory to rotate. Return the original bitmap.
    151             }
    152         }
    153         return b;
    154     }
    155 
    156     /*
    157      * Compute the sample size as a function of minSideLength
    158      * and maxNumOfPixels.
    159      * minSideLength is used to specify that minimal width or height of a
    160      * bitmap.
    161      * maxNumOfPixels is used to specify the maximal size in pixels that is
    162      * tolerable in terms of memory usage.
    163      *
    164      * The function returns a sample size based on the constraints.
    165      * Both size and minSideLength can be passed in as -1
    166      * which indicates no care of the corresponding constraint.
    167      * The functions prefers returning a sample size that
    168      * generates a smaller bitmap, unless minSideLength = -1.
    169      *
    170      * Also, the function rounds up the sample size to a power of 2 or multiple
    171      * of 8 because BitmapFactory only honors sample size this way.
    172      * For example, BitmapFactory downsamples an image by 2 even though the
    173      * request is 3. So we round up the sample size to avoid OOM.
    174      */
    175     public static int computeSampleSize(BitmapFactory.Options options,
    176             int minSideLength, int maxNumOfPixels) {
    177         int initialSize = computeInitialSampleSize(options, minSideLength,
    178                 maxNumOfPixels);
    179 
    180         int roundedSize;
    181         if (initialSize <= 8) {
    182             roundedSize = 1;
    183             while (roundedSize < initialSize) {
    184                 roundedSize <<= 1;
    185             }
    186         } else {
    187             roundedSize = (initialSize + 7) / 8 * 8;
    188         }
    189 
    190         return roundedSize;
    191     }
    192 
    193     private static int computeInitialSampleSize(BitmapFactory.Options options,
    194             int minSideLength, int maxNumOfPixels) {
    195         double w = options.outWidth;
    196         double h = options.outHeight;
    197 
    198         int lowerBound = (maxNumOfPixels < 0) ? 1 :
    199                 (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
    200         int upperBound = (minSideLength < 0) ? 128 :
    201                 (int) Math.min(Math.floor(w / minSideLength),
    202                 Math.floor(h / minSideLength));
    203 
    204         if (upperBound < lowerBound) {
    205             // return the larger one when there is no overlapping zone.
    206             return lowerBound;
    207         }
    208 
    209         if (maxNumOfPixels < 0 && minSideLength < 0) {
    210             return 1;
    211         } else if (minSideLength < 0) {
    212             return lowerBound;
    213         } else {
    214             return upperBound;
    215         }
    216     }
    217 
    218     public static Bitmap makeBitmap(byte[] jpegData, int maxNumOfPixels) {
    219         try {
    220             BitmapFactory.Options options = new BitmapFactory.Options();
    221             options.inJustDecodeBounds = true;
    222             BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length,
    223                     options);
    224             if (options.mCancel || options.outWidth == -1
    225                     || options.outHeight == -1) {
    226                 return null;
    227             }
    228             options.inSampleSize = computeSampleSize(
    229                     options, -1, maxNumOfPixels);
    230             options.inJustDecodeBounds = false;
    231 
    232             options.inDither = false;
    233             options.inPreferredConfig = Bitmap.Config.ARGB_8888;
    234             return BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length,
    235                     options);
    236         } catch (OutOfMemoryError ex) {
    237             Log.e(TAG, "Got oom exception ", ex);
    238             return null;
    239         }
    240     }
    241 
    242     public static void closeSilently(Closeable c) {
    243         if (c == null) return;
    244         try {
    245             c.close();
    246         } catch (Throwable t) {
    247             // do nothing
    248         }
    249     }
    250 
    251     public static void Assert(boolean cond) {
    252         if (!cond) {
    253             throw new AssertionError();
    254         }
    255     }
    256 
    257     public static android.hardware.Camera openCamera(Activity activity, int cameraId)
    258             throws CameraHardwareException, CameraDisabledException {
    259         // Check if device policy has disabled the camera.
    260         DevicePolicyManager dpm = (DevicePolicyManager) activity.getSystemService(
    261                 Context.DEVICE_POLICY_SERVICE);
    262         if (dpm.getCameraDisabled(null)) {
    263             throw new CameraDisabledException();
    264         }
    265 
    266         try {
    267             return CameraHolder.instance().open(cameraId);
    268         } catch (CameraHardwareException e) {
    269             // In eng build, we throw the exception so that test tool
    270             // can detect it and report it
    271             if ("eng".equals(Build.TYPE)) {
    272                 throw new RuntimeException("openCamera failed", e);
    273             } else {
    274                 throw e;
    275             }
    276         }
    277     }
    278 
    279     public static void showErrorAndFinish(final Activity activity, int msgId) {
    280         DialogInterface.OnClickListener buttonListener =
    281                 new DialogInterface.OnClickListener() {
    282             public void onClick(DialogInterface dialog, int which) {
    283                 activity.finish();
    284             }
    285         };
    286         new AlertDialog.Builder(activity)
    287                 .setCancelable(false)
    288                 .setIconAttribute(android.R.attr.alertDialogIcon)
    289                 .setTitle(R.string.camera_error_title)
    290                 .setMessage(msgId)
    291                 .setNeutralButton(R.string.dialog_ok, buttonListener)
    292                 .show();
    293     }
    294 
    295     public static <T> T checkNotNull(T object) {
    296         if (object == null) throw new NullPointerException();
    297         return object;
    298     }
    299 
    300     public static boolean equals(Object a, Object b) {
    301         return (a == b) || (a == null ? false : a.equals(b));
    302     }
    303 
    304     public static int nextPowerOf2(int n) {
    305         n -= 1;
    306         n |= n >>> 16;
    307         n |= n >>> 8;
    308         n |= n >>> 4;
    309         n |= n >>> 2;
    310         n |= n >>> 1;
    311         return n + 1;
    312     }
    313 
    314     public static float distance(float x, float y, float sx, float sy) {
    315         float dx = x - sx;
    316         float dy = y - sy;
    317         return (float) Math.sqrt(dx * dx + dy * dy);
    318     }
    319 
    320     public static int clamp(int x, int min, int max) {
    321         if (x > max) return max;
    322         if (x < min) return min;
    323         return x;
    324     }
    325 
    326     public static int getDisplayRotation(Activity activity) {
    327         int rotation = activity.getWindowManager().getDefaultDisplay()
    328                 .getRotation();
    329         switch (rotation) {
    330             case Surface.ROTATION_0: return 0;
    331             case Surface.ROTATION_90: return 90;
    332             case Surface.ROTATION_180: return 180;
    333             case Surface.ROTATION_270: return 270;
    334         }
    335         return 0;
    336     }
    337 
    338     public static int getDisplayOrientation(int degrees, int cameraId) {
    339         // See android.hardware.Camera.setDisplayOrientation for
    340         // documentation.
    341         Camera.CameraInfo info = new Camera.CameraInfo();
    342         Camera.getCameraInfo(cameraId, info);
    343         int result;
    344         if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
    345             result = (info.orientation + degrees) % 360;
    346             result = (360 - result) % 360;  // compensate the mirror
    347         } else {  // back-facing
    348             result = (info.orientation - degrees + 360) % 360;
    349         }
    350         return result;
    351     }
    352 
    353     public static int roundOrientation(int orientation, int orientationHistory) {
    354         boolean changeOrientation = false;
    355         if (orientationHistory == OrientationEventListener.ORIENTATION_UNKNOWN) {
    356             changeOrientation = true;
    357         } else {
    358             int dist = Math.abs(orientation - orientationHistory);
    359             dist = Math.min( dist, 360 - dist );
    360             changeOrientation = ( dist >= 45 + ORIENTATION_HYSTERESIS );
    361         }
    362         if (changeOrientation) {
    363             return ((orientation + 45) / 90 * 90) % 360;
    364         }
    365         return orientationHistory;
    366     }
    367 
    368     public static Size getOptimalPreviewSize(Activity currentActivity,
    369             List<Size> sizes, double targetRatio) {
    370         // Use a very small tolerance because we want an exact match.
    371         final double ASPECT_TOLERANCE = 0.001;
    372         if (sizes == null) return null;
    373 
    374         Size optimalSize = null;
    375         double minDiff = Double.MAX_VALUE;
    376 
    377         // Because of bugs of overlay and layout, we sometimes will try to
    378         // layout the viewfinder in the portrait orientation and thus get the
    379         // wrong size of mSurfaceView. When we change the preview size, the
    380         // new overlay will be created before the old one closed, which causes
    381         // an exception. For now, just get the screen size
    382 
    383         Display display = currentActivity.getWindowManager().getDefaultDisplay();
    384         int targetHeight = Math.min(display.getHeight(), display.getWidth());
    385 
    386         if (targetHeight <= 0) {
    387             // We don't know the size of SurfaceView, use screen height
    388             targetHeight = display.getHeight();
    389         }
    390 
    391         // Try to find an size match aspect ratio and size
    392         for (Size size : sizes) {
    393             double ratio = (double) size.width / size.height;
    394             if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
    395             if (Math.abs(size.height - targetHeight) < minDiff) {
    396                 optimalSize = size;
    397                 minDiff = Math.abs(size.height - targetHeight);
    398             }
    399         }
    400 
    401         // Cannot find the one match the aspect ratio. This should not happen.
    402         // Ignore the requirement.
    403         if (optimalSize == null) {
    404             Log.w(TAG, "No preview size match the aspect ratio");
    405             minDiff = Double.MAX_VALUE;
    406             for (Size size : sizes) {
    407                 if (Math.abs(size.height - targetHeight) < minDiff) {
    408                     optimalSize = size;
    409                     minDiff = Math.abs(size.height - targetHeight);
    410                 }
    411             }
    412         }
    413         return optimalSize;
    414     }
    415 
    416     public static void dumpParameters(Parameters parameters) {
    417         String flattened = parameters.flatten();
    418         StringTokenizer tokenizer = new StringTokenizer(flattened, ";");
    419         Log.d(TAG, "Dump all camera parameters:");
    420         while (tokenizer.hasMoreElements()) {
    421             Log.d(TAG, tokenizer.nextToken());
    422         }
    423     }
    424 
    425     /**
    426      * Returns whether the device is voice-capable (meaning, it can do MMS).
    427      */
    428     public static boolean isMmsCapable(Context context) {
    429         TelephonyManager telephonyManager = (TelephonyManager)
    430                 context.getSystemService(Context.TELEPHONY_SERVICE);
    431         if (telephonyManager == null) {
    432             return false;
    433         }
    434 
    435         try {
    436             Class partypes[] = new Class[0];
    437             Method sIsVoiceCapable = TelephonyManager.class.getMethod(
    438                     "isVoiceCapable", partypes);
    439 
    440             Object arglist[] = new Object[0];
    441             Object retobj = sIsVoiceCapable.invoke(telephonyManager, arglist);
    442             return (Boolean) retobj;
    443         } catch (java.lang.reflect.InvocationTargetException ite) {
    444             // Failure, must be another device.
    445             // Assume that it is voice capable.
    446         } catch (IllegalAccessException iae) {
    447             // Failure, must be an other device.
    448             // Assume that it is voice capable.
    449         } catch (NoSuchMethodException nsme) {
    450         }
    451         return true;
    452     }
    453 
    454     // This is for test only. Allow the camera to launch the specific camera.
    455     public static int getCameraFacingIntentExtras(Activity currentActivity) {
    456         int cameraId = -1;
    457 
    458         int intentCameraId =
    459                 currentActivity.getIntent().getIntExtra(Util.EXTRAS_CAMERA_FACING, -1);
    460 
    461         if (isFrontCameraIntent(intentCameraId)) {
    462             // Check if the front camera exist
    463             int frontCameraId = CameraHolder.instance().getFrontCameraId();
    464             if (frontCameraId != -1) {
    465                 cameraId = frontCameraId;
    466             }
    467         } else if (isBackCameraIntent(intentCameraId)) {
    468             // Check if the back camera exist
    469             int backCameraId = CameraHolder.instance().getBackCameraId();
    470             if (backCameraId != -1) {
    471                 cameraId = backCameraId;
    472             }
    473         }
    474         return cameraId;
    475     }
    476 
    477     private static boolean isFrontCameraIntent(int intentCameraId) {
    478         return (intentCameraId == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT);
    479     }
    480 
    481     private static boolean isBackCameraIntent(int intentCameraId) {
    482         return (intentCameraId == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK);
    483     }
    484 
    485     private static int mLocation[] = new int[2];
    486 
    487     // This method is not thread-safe.
    488     public static boolean pointInView(float x, float y, View v) {
    489         v.getLocationInWindow(mLocation);
    490         return x >= mLocation[0] && x < (mLocation[0] + v.getWidth())
    491                 && y >= mLocation[1] && y < (mLocation[1] + v.getHeight());
    492     }
    493 
    494     public static boolean isUriValid(Uri uri, ContentResolver resolver) {
    495         if (uri == null) return false;
    496 
    497         try {
    498             ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r");
    499             if (pfd == null) {
    500                 Log.e(TAG, "Fail to open URI. URI=" + uri);
    501                 return false;
    502             }
    503             pfd.close();
    504         } catch (IOException ex) {
    505             return false;
    506         }
    507         return true;
    508     }
    509 
    510     public static void viewUri(Uri uri, Context context) {
    511         if (!isUriValid(uri, context.getContentResolver())) {
    512             Log.e(TAG, "Uri invalid. uri=" + uri);
    513             return;
    514         }
    515 
    516         try {
    517             context.startActivity(new Intent(Util.REVIEW_ACTION, uri));
    518         } catch (ActivityNotFoundException ex) {
    519             try {
    520                 context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
    521             } catch (ActivityNotFoundException e) {
    522                 Log.e(TAG, "review image fail. uri=" + uri, e);
    523             }
    524         }
    525     }
    526 
    527     public static void dumpRect(RectF rect, String msg) {
    528         Log.v(TAG, msg + "=(" + rect.left + "," + rect.top
    529                 + "," + rect.right + "," + rect.bottom + ")");
    530     }
    531 
    532     public static void rectFToRect(RectF rectF, Rect rect) {
    533         rect.left = Math.round(rectF.left);
    534         rect.top = Math.round(rectF.top);
    535         rect.right = Math.round(rectF.right);
    536         rect.bottom = Math.round(rectF.bottom);
    537     }
    538 
    539     public static void prepareMatrix(Matrix matrix, boolean mirror, int displayOrientation,
    540             int viewWidth, int viewHeight) {
    541         // Need mirror for front camera.
    542         matrix.setScale(mirror ? -1 : 1, 1);
    543         // This is the value for android.hardware.Camera.setDisplayOrientation.
    544         matrix.postRotate(displayOrientation);
    545         // Camera driver coordinates range from (-1000, -1000) to (1000, 1000).
    546         // UI coordinates range from (0, 0) to (width, height).
    547         matrix.postScale(viewWidth / 2000f, viewHeight / 2000f);
    548         matrix.postTranslate(viewWidth / 2f, viewHeight / 2f);
    549     }
    550 
    551     public static String createJpegName(long dateTaken) {
    552         synchronized (sImageFileNamer) {
    553             return sImageFileNamer.generateName(dateTaken);
    554         }
    555     }
    556 
    557     public static void broadcastNewPicture(Context context, Uri uri) {
    558         context.sendBroadcast(new Intent(android.hardware.Camera.ACTION_NEW_PICTURE, uri));
    559         // Keep compatibility
    560         context.sendBroadcast(new Intent("com.android.camera.NEW_PICTURE", uri));
    561     }
    562 
    563     public static void fadeIn(View view) {
    564         if (view.getVisibility() == View.VISIBLE) return;
    565 
    566         view.setVisibility(View.VISIBLE);
    567         Animation animation = new AlphaAnimation(0F, 1F);
    568         animation.setDuration(400);
    569         view.startAnimation(animation);
    570     }
    571 
    572     public static void fadeOut(View view) {
    573         if (view.getVisibility() != View.VISIBLE) return;
    574 
    575         Animation animation = new AlphaAnimation(1F, 0F);
    576         animation.setDuration(400);
    577         view.startAnimation(animation);
    578         view.setVisibility(View.GONE);
    579     }
    580 
    581     public static void setRotationParameter(Parameters parameters, int cameraId, int orientation) {
    582         // See android.hardware.Camera.Parameters.setRotation for
    583         // documentation.
    584         int rotation = 0;
    585         if (orientation != OrientationEventListener.ORIENTATION_UNKNOWN) {
    586             CameraInfo info = CameraHolder.instance().getCameraInfo()[cameraId];
    587             if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
    588                 rotation = (info.orientation - orientation + 360) % 360;
    589             } else {  // back-facing camera
    590                 rotation = (info.orientation + orientation) % 360;
    591             }
    592         }
    593         parameters.setRotation(rotation);
    594     }
    595 
    596     public static void setGpsParameters(Parameters parameters, Location loc) {
    597         // Clear previous GPS location from the parameters.
    598         parameters.removeGpsData();
    599 
    600         // We always encode GpsTimeStamp
    601         parameters.setGpsTimestamp(System.currentTimeMillis() / 1000);
    602 
    603         // Set GPS location.
    604         if (loc != null) {
    605             double lat = loc.getLatitude();
    606             double lon = loc.getLongitude();
    607             boolean hasLatLon = (lat != 0.0d) || (lon != 0.0d);
    608 
    609             if (hasLatLon) {
    610                 Log.d(TAG, "Set gps location");
    611                 parameters.setGpsLatitude(lat);
    612                 parameters.setGpsLongitude(lon);
    613                 parameters.setGpsProcessingMethod(loc.getProvider().toUpperCase());
    614                 if (loc.hasAltitude()) {
    615                     parameters.setGpsAltitude(loc.getAltitude());
    616                 } else {
    617                     // for NETWORK_PROVIDER location provider, we may have
    618                     // no altitude information, but the driver needs it, so
    619                     // we fake one.
    620                     parameters.setGpsAltitude(0);
    621                 }
    622                 if (loc.getTime() != 0) {
    623                     // Location.getTime() is UTC in milliseconds.
    624                     // gps-timestamp is UTC in seconds.
    625                     long utcTimeSeconds = loc.getTime() / 1000;
    626                     parameters.setGpsTimestamp(utcTimeSeconds);
    627                 }
    628             } else {
    629                 loc = null;
    630             }
    631         }
    632     }
    633 
    634     public static void enterLightsOutMode(Window window) {
    635         WindowManager.LayoutParams params = window.getAttributes();
    636         params.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE;
    637         window.setAttributes(params);
    638     }
    639 
    640     public static void initializeScreenBrightness(Window win, ContentResolver resolver) {
    641         // Overright the brightness settings if it is automatic
    642         int mode = Settings.System.getInt(resolver, Settings.System.SCREEN_BRIGHTNESS_MODE,
    643                 Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
    644         if (mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
    645             WindowManager.LayoutParams winParams = win.getAttributes();
    646             winParams.screenBrightness = DEFAULT_CAMERA_BRIGHTNESS;
    647             win.setAttributes(winParams);
    648         }
    649     }
    650 
    651     private static class ImageFileNamer {
    652         private SimpleDateFormat mFormat;
    653 
    654         // The date (in milliseconds) used to generate the last name.
    655         private long mLastDate;
    656 
    657         // Number of names generated for the same second.
    658         private int mSameSecondCount;
    659 
    660         public ImageFileNamer(String format) {
    661             mFormat = new SimpleDateFormat(format);
    662         }
    663 
    664         public String generateName(long dateTaken) {
    665             Date date = new Date(dateTaken);
    666             String result = mFormat.format(date);
    667 
    668             // If the last name was generated for the same second,
    669             // we append _1, _2, etc to the name.
    670             if (dateTaken / 1000 == mLastDate / 1000) {
    671                 mSameSecondCount++;
    672                 result += "_" + mSameSecondCount;
    673             } else {
    674                 mLastDate = dateTaken;
    675                 mSameSecondCount = 0;
    676             }
    677 
    678             return result;
    679         }
    680     }
    681 }
    682