• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.annotation.TargetApi;
20 import android.app.Activity;
21 import android.app.AlertDialog;
22 import android.content.ContentProviderClient;
23 import android.content.ContentResolver;
24 import android.content.Context;
25 import android.content.DialogInterface;
26 import android.content.Intent;
27 import android.content.SharedPreferences.Editor;
28 import android.content.res.Configuration;
29 import android.graphics.Bitmap;
30 import android.graphics.SurfaceTexture;
31 import android.hardware.Camera.CameraInfo;
32 import android.hardware.Camera.Parameters;
33 import android.hardware.Camera.PictureCallback;
34 import android.hardware.Camera.Size;
35 import android.hardware.Sensor;
36 import android.hardware.SensorEvent;
37 import android.hardware.SensorEventListener;
38 import android.hardware.SensorManager;
39 import android.location.Location;
40 import android.media.CameraProfile;
41 import android.net.Uri;
42 import android.os.Bundle;
43 import android.os.ConditionVariable;
44 import android.os.Handler;
45 import android.os.Looper;
46 import android.os.Message;
47 import android.os.MessageQueue;
48 import android.os.SystemClock;
49 import android.provider.MediaStore;
50 import android.util.Log;
51 import android.view.KeyEvent;
52 import android.view.MotionEvent;
53 import android.view.OrientationEventListener;
54 import android.view.SurfaceHolder;
55 import android.view.View;
56 import android.view.WindowManager;
57 
58 import com.android.camera.CameraManager.CameraProxy;
59 import com.android.camera.ui.CountDownView.OnCountDownFinishedListener;
60 import com.android.camera.ui.PopupManager;
61 import com.android.camera.ui.RotateTextToast;
62 import com.android.gallery3d.R;
63 import com.android.gallery3d.common.ApiHelper;
64 import com.android.gallery3d.exif.ExifInterface;
65 import com.android.gallery3d.exif.ExifTag;
66 import com.android.gallery3d.exif.Rational;
67 import com.android.gallery3d.filtershow.FilterShowActivity;
68 import com.android.gallery3d.filtershow.crop.CropExtras;
69 import com.android.gallery3d.util.UsageStatistics;
70 
71 import java.io.File;
72 import java.io.FileNotFoundException;
73 import java.io.FileOutputStream;
74 import java.io.IOException;
75 import java.io.OutputStream;
76 import java.util.ArrayList;
77 import java.util.Collections;
78 import java.util.Formatter;
79 import java.util.List;
80 
81 public class PhotoModule
82     implements CameraModule,
83     PhotoController,
84     FocusOverlayManager.Listener,
85     CameraPreference.OnPreferenceChangedListener,
86     ShutterButton.OnShutterButtonListener,
87     MediaSaveService.Listener,
88     OnCountDownFinishedListener,
89     SensorEventListener {
90 
91     private static final String TAG = "CAM_PhotoModule";
92 
93     // We number the request code from 1000 to avoid collision with Gallery.
94     private static final int REQUEST_CROP = 1000;
95 
96     private static final int SETUP_PREVIEW = 1;
97     private static final int FIRST_TIME_INIT = 2;
98     private static final int CLEAR_SCREEN_DELAY = 3;
99     private static final int SET_CAMERA_PARAMETERS_WHEN_IDLE = 4;
100     private static final int CHECK_DISPLAY_ROTATION = 5;
101     private static final int SHOW_TAP_TO_FOCUS_TOAST = 6;
102     private static final int SWITCH_CAMERA = 7;
103     private static final int SWITCH_CAMERA_START_ANIMATION = 8;
104     private static final int CAMERA_OPEN_DONE = 9;
105     private static final int START_PREVIEW_DONE = 10;
106     private static final int OPEN_CAMERA_FAIL = 11;
107     private static final int CAMERA_DISABLED = 12;
108     private static final int CAPTURE_ANIMATION_DONE = 13;
109 
110     // The subset of parameters we need to update in setCameraParameters().
111     private static final int UPDATE_PARAM_INITIALIZE = 1;
112     private static final int UPDATE_PARAM_ZOOM = 2;
113     private static final int UPDATE_PARAM_PREFERENCE = 4;
114     private static final int UPDATE_PARAM_ALL = -1;
115 
116     // This is the timeout to keep the camera in onPause for the first time
117     // after screen on if the activity is started from secure lock screen.
118     private static final int KEEP_CAMERA_TIMEOUT = 1000; // ms
119 
120     // copied from Camera hierarchy
121     private CameraActivity mActivity;
122     private CameraProxy mCameraDevice;
123     private int mCameraId;
124     private Parameters mParameters;
125     private boolean mPaused;
126 
127     private PhotoUI mUI;
128 
129     // these are only used by Camera
130 
131     // The activity is going to switch to the specified camera id. This is
132     // needed because texture copy is done in GL thread. -1 means camera is not
133     // switching.
134     protected int mPendingSwitchCameraId = -1;
135     private boolean mOpenCameraFail;
136     private boolean mCameraDisabled;
137 
138     // When setCameraParametersWhenIdle() is called, we accumulate the subsets
139     // needed to be updated in mUpdateSet.
140     private int mUpdateSet;
141 
142     private static final int SCREEN_DELAY = 2 * 60 * 1000;
143 
144     private int mZoomValue;  // The current zoom value.
145 
146     private Parameters mInitialParams;
147     private boolean mFocusAreaSupported;
148     private boolean mMeteringAreaSupported;
149     private boolean mAeLockSupported;
150     private boolean mAwbLockSupported;
151     private boolean mContinousFocusSupported;
152 
153     // The degrees of the device rotated clockwise from its natural orientation.
154     private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
155     private ComboPreferences mPreferences;
156 
157     private static final String sTempCropFilename = "crop-temp";
158 
159     private ContentProviderClient mMediaProviderClient;
160     private boolean mFaceDetectionStarted = false;
161 
162     // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
163     private String mCropValue;
164     private Uri mSaveUri;
165 
166     // We use a queue to generated names of the images to be used later
167     // when the image is ready to be saved.
168     private NamedImages mNamedImages;
169 
170     private Runnable mDoSnapRunnable = new Runnable() {
171         @Override
172         public void run() {
173             onShutterButtonClick();
174         }
175     };
176 
177     private Runnable mFlashRunnable = new Runnable() {
178         @Override
179         public void run() {
180             animateFlash();
181         }
182     };
183 
184     private final StringBuilder mBuilder = new StringBuilder();
185     private final Formatter mFormatter = new Formatter(mBuilder);
186     private final Object[] mFormatterArgs = new Object[1];
187 
188     /**
189      * An unpublished intent flag requesting to return as soon as capturing
190      * is completed.
191      *
192      * TODO: consider publishing by moving into MediaStore.
193      */
194     private static final String EXTRA_QUICK_CAPTURE =
195             "android.intent.extra.quickCapture";
196 
197     // The display rotation in degrees. This is only valid when mCameraState is
198     // not PREVIEW_STOPPED.
199     private int mDisplayRotation;
200     // The value for android.hardware.Camera.setDisplayOrientation.
201     private int mCameraDisplayOrientation;
202     // The value for UI components like indicators.
203     private int mDisplayOrientation;
204     // The value for android.hardware.Camera.Parameters.setRotation.
205     private int mJpegRotation;
206     private boolean mFirstTimeInitialized;
207     private boolean mIsImageCaptureIntent;
208 
209     private int mCameraState = PREVIEW_STOPPED;
210     private boolean mSnapshotOnIdle = false;
211 
212     private ContentResolver mContentResolver;
213 
214     private LocationManager mLocationManager;
215 
216     private final PostViewPictureCallback mPostViewPictureCallback =
217             new PostViewPictureCallback();
218     private final RawPictureCallback mRawPictureCallback =
219             new RawPictureCallback();
220     private final AutoFocusCallback mAutoFocusCallback =
221             new AutoFocusCallback();
222     private final Object mAutoFocusMoveCallback =
223             ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK
224             ? new AutoFocusMoveCallback()
225             : null;
226 
227     private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
228 
229     private long mFocusStartTime;
230     private long mShutterCallbackTime;
231     private long mPostViewPictureCallbackTime;
232     private long mRawPictureCallbackTime;
233     private long mJpegPictureCallbackTime;
234     private long mOnResumeTime;
235     private byte[] mJpegImageData;
236 
237     // These latency time are for the CameraLatency test.
238     public long mAutoFocusTime;
239     public long mShutterLag;
240     public long mShutterToPictureDisplayedTime;
241     public long mPictureDisplayedToJpegCallbackTime;
242     public long mJpegCallbackFinishTime;
243     public long mCaptureStartTime;
244 
245     // This handles everything about focus.
246     private FocusOverlayManager mFocusManager;
247 
248     private String mSceneMode;
249 
250     private final Handler mHandler = new MainHandler();
251     private PreferenceGroup mPreferenceGroup;
252 
253     private boolean mQuickCapture;
254 
255     CameraStartUpThread mCameraStartUpThread;
256     ConditionVariable mStartPreviewPrerequisiteReady = new ConditionVariable();
257 
258     private SensorManager mSensorManager;
259     private float[] mGData = new float[3];
260     private float[] mMData = new float[3];
261     private float[] mR = new float[16];
262     private int mHeading = -1;
263 
264     private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener =
265             new MediaSaveService.OnMediaSavedListener() {
266                 @Override
267                 public void onMediaSaved(Uri uri) {
268                     if (uri != null) {
269                         mActivity.addSecureAlbumItemIfNeeded(false, uri);
270                         Util.broadcastNewPicture(mActivity, uri);
271                     }
272                 }
273             };
274 
275     // The purpose is not to block the main thread in onCreate and onResume.
276     private class CameraStartUpThread extends Thread {
277         private volatile boolean mCancelled;
278 
cancel()279         public void cancel() {
280             mCancelled = true;
281             interrupt();
282         }
283 
isCanceled()284         public boolean isCanceled() {
285             return mCancelled;
286         }
287 
288         @Override
run()289         public void run() {
290             try {
291                 // We need to check whether the activity is paused before long
292                 // operations to ensure that onPause() can be done ASAP.
293                 if (mCancelled) return;
294                 mCameraDevice = Util.openCamera(mActivity, mCameraId);
295                 mParameters = mCameraDevice.getParameters();
296                 // Wait until all the initialization needed by startPreview are
297                 // done.
298                 mStartPreviewPrerequisiteReady.block();
299 
300                 initializeCapabilities();
301                 if (mFocusManager == null) initializeFocusManager();
302                 if (mCancelled) return;
303                 setCameraParameters(UPDATE_PARAM_ALL);
304                 mHandler.sendEmptyMessage(CAMERA_OPEN_DONE);
305                 if (mCancelled) return;
306                 startPreview();
307                 mHandler.sendEmptyMessage(START_PREVIEW_DONE);
308                 mOnResumeTime = SystemClock.uptimeMillis();
309                 mHandler.sendEmptyMessage(CHECK_DISPLAY_ROTATION);
310             } catch (CameraHardwareException e) {
311                 mHandler.sendEmptyMessage(OPEN_CAMERA_FAIL);
312             } catch (CameraDisabledException e) {
313                 mHandler.sendEmptyMessage(CAMERA_DISABLED);
314             }
315         }
316     }
317 
318     /**
319      * This Handler is used to post message back onto the main thread of the
320      * application
321      */
322     private class MainHandler extends Handler {
323         @Override
handleMessage(Message msg)324         public void handleMessage(Message msg) {
325             switch (msg.what) {
326                 case SETUP_PREVIEW: {
327                     setupPreview();
328                     break;
329                 }
330 
331                 case CLEAR_SCREEN_DELAY: {
332                     mActivity.getWindow().clearFlags(
333                             WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
334                     break;
335                 }
336 
337                 case FIRST_TIME_INIT: {
338                     initializeFirstTime();
339                     break;
340                 }
341 
342                 case SET_CAMERA_PARAMETERS_WHEN_IDLE: {
343                     setCameraParametersWhenIdle(0);
344                     break;
345                 }
346 
347                 case CHECK_DISPLAY_ROTATION: {
348                     // Set the display orientation if display rotation has changed.
349                     // Sometimes this happens when the device is held upside
350                     // down and camera app is opened. Rotation animation will
351                     // take some time and the rotation value we have got may be
352                     // wrong. Framework does not have a callback for this now.
353                     if (Util.getDisplayRotation(mActivity) != mDisplayRotation) {
354                         setDisplayOrientation();
355                     }
356                     if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
357                         mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100);
358                     }
359                     break;
360                 }
361 
362                 case SHOW_TAP_TO_FOCUS_TOAST: {
363                     showTapToFocusToast();
364                     break;
365                 }
366 
367                 case SWITCH_CAMERA: {
368                     switchCamera();
369                     break;
370                 }
371 
372                 case SWITCH_CAMERA_START_ANIMATION: {
373                     ((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera();
374                     break;
375                 }
376 
377                 case CAMERA_OPEN_DONE: {
378                     onCameraOpened();
379                     break;
380                 }
381 
382                 case START_PREVIEW_DONE: {
383                     onPreviewStarted();
384                     break;
385                 }
386 
387                 case OPEN_CAMERA_FAIL: {
388                     mCameraStartUpThread = null;
389                     mOpenCameraFail = true;
390                     Util.showErrorAndFinish(mActivity,
391                             R.string.cannot_connect_camera);
392                     break;
393                 }
394 
395                 case CAMERA_DISABLED: {
396                     mCameraStartUpThread = null;
397                     mCameraDisabled = true;
398                     Util.showErrorAndFinish(mActivity,
399                             R.string.camera_disabled);
400                     break;
401                 }
402                 case CAPTURE_ANIMATION_DONE: {
403                     mUI.enablePreviewThumb(false);
404                     break;
405                 }
406             }
407         }
408     }
409 
410     @Override
init(CameraActivity activity, View parent, boolean reuseNail)411     public void init(CameraActivity activity, View parent, boolean reuseNail) {
412         mActivity = activity;
413         mUI = new PhotoUI(activity, this, parent);
414         mPreferences = new ComboPreferences(mActivity);
415         CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal());
416         mCameraId = getPreferredCameraId(mPreferences);
417 
418         mContentResolver = mActivity.getContentResolver();
419 
420         // To reduce startup time, open the camera and start the preview in
421         // another thread.
422         mCameraStartUpThread = new CameraStartUpThread();
423         mCameraStartUpThread.start();
424 
425 
426         // Surface texture is from camera screen nail and startPreview needs it.
427         // This must be done before startPreview.
428         mIsImageCaptureIntent = isImageCaptureIntent();
429         if (reuseNail) {
430             mActivity.reuseCameraScreenNail(!mIsImageCaptureIntent);
431         } else {
432             mActivity.createCameraScreenNail(!mIsImageCaptureIntent);
433         }
434 
435         mPreferences.setLocalId(mActivity, mCameraId);
436         CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
437         // we need to reset exposure for the preview
438         resetExposureCompensation();
439         // Starting the preview needs preferences, camera screen nail, and
440         // focus area indicator.
441         mStartPreviewPrerequisiteReady.open();
442 
443         initializeControlByIntent();
444         mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
445         mLocationManager = new LocationManager(mActivity, mUI);
446         mSensorManager = (SensorManager)(mActivity.getSystemService(Context.SENSOR_SERVICE));
447 
448     }
449 
initializeControlByIntent()450     private void initializeControlByIntent() {
451         mUI.initializeControlByIntent();
452         if (mIsImageCaptureIntent) {
453             setupCaptureParams();
454         }
455     }
456 
onPreviewStarted()457     private void onPreviewStarted() {
458         mCameraStartUpThread = null;
459         setCameraState(IDLE);
460         if (!ApiHelper.HAS_SURFACE_TEXTURE) {
461             // This may happen if surfaceCreated has arrived.
462             mCameraDevice.setPreviewDisplayAsync(mUI.getSurfaceHolder());
463         }
464         startFaceDetection();
465         locationFirstRun();
466     }
467 
468     // Prompt the user to pick to record location for the very first run of
469     // camera only
locationFirstRun()470     private void locationFirstRun() {
471         if (RecordLocationPreference.isSet(mPreferences)) {
472             return;
473         }
474         if (mActivity.isSecureCamera()) return;
475         // Check if the back camera exists
476         int backCameraId = CameraHolder.instance().getBackCameraId();
477         if (backCameraId == -1) {
478             // If there is no back camera, do not show the prompt.
479             return;
480         }
481 
482         new AlertDialog.Builder(mActivity)
483             .setTitle(R.string.remember_location_title)
484             .setMessage(R.string.remember_location_prompt)
485             .setPositiveButton(R.string.remember_location_yes, new DialogInterface.OnClickListener() {
486                 @Override
487                 public void onClick(DialogInterface dialog, int arg1) {
488                     setLocationPreference(RecordLocationPreference.VALUE_ON);
489                 }
490             })
491             .setNegativeButton(R.string.remember_location_no, new DialogInterface.OnClickListener() {
492                 @Override
493                 public void onClick(DialogInterface dialog, int arg1) {
494                     dialog.cancel();
495                 }
496             })
497             .setOnCancelListener(new DialogInterface.OnCancelListener() {
498                 @Override
499                 public void onCancel(DialogInterface dialog) {
500                     setLocationPreference(RecordLocationPreference.VALUE_OFF);
501                 }
502             })
503             .show();
504     }
505 
setLocationPreference(String value)506     private void setLocationPreference(String value) {
507         mPreferences.edit()
508             .putString(CameraSettings.KEY_RECORD_LOCATION, value)
509             .apply();
510         // TODO: Fix this to use the actual onSharedPreferencesChanged listener
511         // instead of invoking manually
512         onSharedPreferenceChanged();
513     }
514 
onCameraOpened()515     private void onCameraOpened() {
516         View root = mUI.getRootView();
517         // These depend on camera parameters.
518 
519         int width = root.getWidth();
520         int height = root.getHeight();
521         mFocusManager.setPreviewSize(width, height);
522         // Full-screen screennail
523         if (Util.getDisplayRotation(mActivity) % 180 == 0) {
524             ((CameraScreenNail) mActivity.mCameraScreenNail).setPreviewFrameLayoutSize(width, height);
525         } else {
526             ((CameraScreenNail) mActivity.mCameraScreenNail).setPreviewFrameLayoutSize(height, width);
527         }
528         // Set touch focus listener.
529         mActivity.setSingleTapUpListener(root);
530         openCameraCommon();
531         onFullScreenChanged(mActivity.isInCameraApp());
532     }
533 
switchCamera()534     private void switchCamera() {
535         if (mPaused) return;
536 
537         Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
538         mCameraId = mPendingSwitchCameraId;
539         mPendingSwitchCameraId = -1;
540         setCameraId(mCameraId);
541 
542         // from onPause
543         closeCamera();
544         mUI.collapseCameraControls();
545         mUI.clearFaces();
546         if (mFocusManager != null) mFocusManager.removeMessages();
547 
548         // Restart the camera and initialize the UI. From onCreate.
549         mPreferences.setLocalId(mActivity, mCameraId);
550         CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
551         try {
552             mCameraDevice = Util.openCamera(mActivity, mCameraId);
553             mParameters = mCameraDevice.getParameters();
554         } catch (CameraHardwareException e) {
555             Util.showErrorAndFinish(mActivity, R.string.cannot_connect_camera);
556             return;
557         } catch (CameraDisabledException e) {
558             Util.showErrorAndFinish(mActivity, R.string.camera_disabled);
559             return;
560         }
561         initializeCapabilities();
562         CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
563         boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
564         mFocusManager.setMirror(mirror);
565         mFocusManager.setParameters(mInitialParams);
566         setupPreview();
567 
568         openCameraCommon();
569 
570         if (ApiHelper.HAS_SURFACE_TEXTURE) {
571             // Start switch camera animation. Post a message because
572             // onFrameAvailable from the old camera may already exist.
573             mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION);
574         }
575     }
576 
setCameraId(int cameraId)577     protected void setCameraId(int cameraId) {
578         ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID);
579         pref.setValue("" + cameraId);
580     }
581 
582     // either open a new camera or switch cameras
openCameraCommon()583     private void openCameraCommon() {
584         loadCameraPreferences();
585 
586         mUI.onCameraOpened(mPreferenceGroup, mPreferences, mParameters, this);
587         updateSceneMode();
588         showTapToFocusToastIfNeeded();
589 
590 
591     }
592 
onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight)593     public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) {
594         Log.d(TAG, "Preview size changed.");
595         if (mFocusManager != null) mFocusManager.setPreviewSize(width, height);
596         ((CameraScreenNail) mActivity.mCameraScreenNail).setPreviewFrameLayoutSize(
597                 previewWidth, previewHeight);
598         mActivity.notifyScreenNailChanged();
599     }
600 
resetExposureCompensation()601     private void resetExposureCompensation() {
602         String value = mPreferences.getString(CameraSettings.KEY_EXPOSURE,
603                 CameraSettings.EXPOSURE_DEFAULT_VALUE);
604         if (!CameraSettings.EXPOSURE_DEFAULT_VALUE.equals(value)) {
605             Editor editor = mPreferences.edit();
606             editor.putString(CameraSettings.KEY_EXPOSURE, "0");
607             editor.apply();
608         }
609     }
610 
keepMediaProviderInstance()611     private void keepMediaProviderInstance() {
612         // We want to keep a reference to MediaProvider in camera's lifecycle.
613         // TODO: Utilize mMediaProviderClient instance to replace
614         // ContentResolver calls.
615         if (mMediaProviderClient == null) {
616             mMediaProviderClient = mContentResolver
617                     .acquireContentProviderClient(MediaStore.AUTHORITY);
618         }
619     }
620 
621     // Snapshots can only be taken after this is called. It should be called
622     // once only. We could have done these things in onCreate() but we want to
623     // make preview screen appear as soon as possible.
initializeFirstTime()624     private void initializeFirstTime() {
625         if (mFirstTimeInitialized) return;
626 
627         // Initialize location service.
628         boolean recordLocation = RecordLocationPreference.get(
629                 mPreferences, mContentResolver);
630         mLocationManager.recordLocation(recordLocation);
631 
632         keepMediaProviderInstance();
633 
634         mUI.initializeFirstTime();
635         MediaSaveService s = mActivity.getMediaSaveService();
636         // We set the listener only when both service and shutterbutton
637         // are initialized.
638         if (s != null) {
639             s.setListener(this);
640         }
641 
642         mNamedImages = new NamedImages();
643 
644         mFirstTimeInitialized = true;
645         addIdleHandler();
646 
647         mActivity.updateStorageSpaceAndHint();
648     }
649 
650     // If the activity is paused and resumed, this method will be called in
651     // onResume.
initializeSecondTime()652     private void initializeSecondTime() {
653         // Start location update if needed.
654         boolean recordLocation = RecordLocationPreference.get(
655                 mPreferences, mContentResolver);
656         mLocationManager.recordLocation(recordLocation);
657         MediaSaveService s = mActivity.getMediaSaveService();
658         if (s != null) {
659             s.setListener(this);
660         }
661         mNamedImages = new NamedImages();
662         mUI.initializeSecondTime(mParameters);
663         keepMediaProviderInstance();
664     }
665 
666     @Override
onSurfaceCreated(SurfaceHolder holder)667     public void onSurfaceCreated(SurfaceHolder holder) {
668         // Do not access the camera if camera start up thread is not finished.
669         if (mCameraDevice == null || mCameraStartUpThread != null)
670             return;
671 
672         mCameraDevice.setPreviewDisplayAsync(holder);
673         // This happens when onConfigurationChanged arrives, surface has been
674         // destroyed, and there is no onFullScreenChanged.
675         if (mCameraState == PREVIEW_STOPPED) {
676             setupPreview();
677         }
678     }
679 
showTapToFocusToastIfNeeded()680     private void showTapToFocusToastIfNeeded() {
681         // Show the tap to focus toast if this is the first start.
682         if (mFocusAreaSupported &&
683                 mPreferences.getBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, true)) {
684             // Delay the toast for one second to wait for orientation.
685             mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_FOCUS_TOAST, 1000);
686         }
687     }
688 
addIdleHandler()689     private void addIdleHandler() {
690         MessageQueue queue = Looper.myQueue();
691         queue.addIdleHandler(new MessageQueue.IdleHandler() {
692             @Override
693             public boolean queueIdle() {
694                 Storage.ensureOSXCompatible();
695                 return false;
696             }
697         });
698     }
699 
700     @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
701     @Override
startFaceDetection()702     public void startFaceDetection() {
703         if (!ApiHelper.HAS_FACE_DETECTION) return;
704         if (mFaceDetectionStarted) return;
705         if (mParameters.getMaxNumDetectedFaces() > 0) {
706             mFaceDetectionStarted = true;
707             CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
708             mUI.onStartFaceDetection(mDisplayOrientation,
709                     (info.facing == CameraInfo.CAMERA_FACING_FRONT));
710             mCameraDevice.setFaceDetectionListener(mUI);
711             mCameraDevice.startFaceDetection();
712         }
713     }
714 
715     @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
716     @Override
stopFaceDetection()717     public void stopFaceDetection() {
718         if (!ApiHelper.HAS_FACE_DETECTION) return;
719         if (!mFaceDetectionStarted) return;
720         if (mParameters.getMaxNumDetectedFaces() > 0) {
721             mFaceDetectionStarted = false;
722             mCameraDevice.setFaceDetectionListener(null);
723             mCameraDevice.stopFaceDetection();
724             mUI.clearFaces();
725         }
726     }
727 
728     @Override
dispatchTouchEvent(MotionEvent m)729     public boolean dispatchTouchEvent(MotionEvent m) {
730         if (mCameraState == SWITCHING_CAMERA) return true;
731         return mUI.dispatchTouchEvent(m);
732     }
733 
734     private final class ShutterCallback
735             implements android.hardware.Camera.ShutterCallback {
736 
737         private boolean mAnimateFlash;
738 
ShutterCallback(boolean animateFlash)739         public ShutterCallback(boolean animateFlash) {
740             mAnimateFlash = animateFlash;
741         }
742 
743         @Override
onShutter()744         public void onShutter() {
745             mShutterCallbackTime = System.currentTimeMillis();
746             mShutterLag = mShutterCallbackTime - mCaptureStartTime;
747             Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
748             if (mAnimateFlash) {
749                 mActivity.runOnUiThread(mFlashRunnable);
750             }
751         }
752     }
753 
754     private final class PostViewPictureCallback implements PictureCallback {
755         @Override
onPictureTaken( byte [] data, android.hardware.Camera camera)756         public void onPictureTaken(
757                 byte [] data, android.hardware.Camera camera) {
758             mPostViewPictureCallbackTime = System.currentTimeMillis();
759             Log.v(TAG, "mShutterToPostViewCallbackTime = "
760                     + (mPostViewPictureCallbackTime - mShutterCallbackTime)
761                     + "ms");
762         }
763     }
764 
765     private final class RawPictureCallback implements PictureCallback {
766         @Override
onPictureTaken( byte [] rawData, android.hardware.Camera camera)767         public void onPictureTaken(
768                 byte [] rawData, android.hardware.Camera camera) {
769             mRawPictureCallbackTime = System.currentTimeMillis();
770             Log.v(TAG, "mShutterToRawCallbackTime = "
771                     + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
772         }
773     }
774 
775     private final class JpegPictureCallback implements PictureCallback {
776         Location mLocation;
777 
JpegPictureCallback(Location loc)778         public JpegPictureCallback(Location loc) {
779             mLocation = loc;
780         }
781 
782         @Override
onPictureTaken( final byte [] jpegData, final android.hardware.Camera camera)783         public void onPictureTaken(
784                 final byte [] jpegData, final android.hardware.Camera camera) {
785             if (mPaused) {
786                 return;
787             }
788             if (mSceneMode == Util.SCENE_MODE_HDR) {
789                 mActivity.showSwitcher();
790                 mActivity.setSwipingEnabled(true);
791             }
792 
793             mJpegPictureCallbackTime = System.currentTimeMillis();
794             // If postview callback has arrived, the captured image is displayed
795             // in postview callback. If not, the captured image is displayed in
796             // raw picture callback.
797             if (mPostViewPictureCallbackTime != 0) {
798                 mShutterToPictureDisplayedTime =
799                         mPostViewPictureCallbackTime - mShutterCallbackTime;
800                 mPictureDisplayedToJpegCallbackTime =
801                         mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
802             } else {
803                 mShutterToPictureDisplayedTime =
804                         mRawPictureCallbackTime - mShutterCallbackTime;
805                 mPictureDisplayedToJpegCallbackTime =
806                         mJpegPictureCallbackTime - mRawPictureCallbackTime;
807             }
808             Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
809                     + mPictureDisplayedToJpegCallbackTime + "ms");
810 
811             // Only animate when in full screen capture mode
812             // i.e. If monkey/a user swipes to the gallery during picture taking,
813             // don't show animation
814             if (ApiHelper.HAS_SURFACE_TEXTURE && !mIsImageCaptureIntent
815                     && mActivity.mShowCameraAppView) {
816                 // Finish capture animation
817                 mHandler.removeMessages(CAPTURE_ANIMATION_DONE);
818                 ((CameraScreenNail) mActivity.mCameraScreenNail).animateSlide();
819                 mHandler.sendEmptyMessageDelayed(CAPTURE_ANIMATION_DONE,
820                         CaptureAnimManager.getAnimationDuration());
821             }
822             mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
823             if (!mIsImageCaptureIntent) {
824                 if (ApiHelper.CAN_START_PREVIEW_IN_JPEG_CALLBACK) {
825                     setupPreview();
826                 } else {
827                     // Camera HAL of some devices have a bug. Starting preview
828                     // immediately after taking a picture will fail. Wait some
829                     // time before starting the preview.
830                     mHandler.sendEmptyMessageDelayed(SETUP_PREVIEW, 300);
831                 }
832             }
833 
834             if (!mIsImageCaptureIntent) {
835                 // Calculate the width and the height of the jpeg.
836                 Size s = mParameters.getPictureSize();
837                 ExifInterface exif = Exif.getExif(jpegData);
838                 int orientation = Exif.getOrientation(exif);
839                 int width, height;
840                 if ((mJpegRotation + orientation) % 180 == 0) {
841                     width = s.width;
842                     height = s.height;
843                 } else {
844                     width = s.height;
845                     height = s.width;
846                 }
847                 String title = mNamedImages.getTitle();
848                 long date = mNamedImages.getDate();
849                 if (title == null) {
850                     Log.e(TAG, "Unbalanced name/data pair");
851                 } else {
852                     if (date == -1) date = mCaptureStartTime;
853                     if (mHeading >= 0) {
854                         // heading direction has been updated by the sensor.
855                         ExifTag directionRefTag = exif.buildTag(
856                                 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
857                                 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
858                         ExifTag directionTag = exif.buildTag(
859                                 ExifInterface.TAG_GPS_IMG_DIRECTION,
860                                 new Rational(mHeading, 1));
861                         exif.setTag(directionRefTag);
862                         exif.setTag(directionTag);
863                     }
864                     mActivity.getMediaSaveService().addImage(
865                             jpegData, title, date, mLocation, width, height,
866                             orientation, exif, mOnMediaSavedListener, mContentResolver);
867                 }
868             } else {
869                 mJpegImageData = jpegData;
870                 if (!mQuickCapture) {
871                     mUI.showPostCaptureAlert();
872                 } else {
873                     onCaptureDone();
874                 }
875             }
876 
877             // Check this in advance of each shot so we don't add to shutter
878             // latency. It's true that someone else could write to the SD card in
879             // the mean time and fill it, but that could have happened between the
880             // shutter press and saving the JPEG too.
881             mActivity.updateStorageSpaceAndHint();
882 
883             long now = System.currentTimeMillis();
884             mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
885             Log.v(TAG, "mJpegCallbackFinishTime = "
886                     + mJpegCallbackFinishTime + "ms");
887             mJpegPictureCallbackTime = 0;
888         }
889     }
890 
891     private final class AutoFocusCallback
892             implements android.hardware.Camera.AutoFocusCallback {
893         @Override
onAutoFocus( boolean focused, android.hardware.Camera camera)894         public void onAutoFocus(
895                 boolean focused, android.hardware.Camera camera) {
896             if (mPaused) return;
897 
898             mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
899             Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
900             setCameraState(IDLE);
901             mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
902         }
903     }
904 
905     @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
906     private final class AutoFocusMoveCallback
907             implements android.hardware.Camera.AutoFocusMoveCallback {
908         @Override
onAutoFocusMoving( boolean moving, android.hardware.Camera camera)909         public void onAutoFocusMoving(
910             boolean moving, android.hardware.Camera camera) {
911                 mFocusManager.onAutoFocusMoving(moving);
912         }
913     }
914 
915     private static class NamedImages {
916         private ArrayList<NamedEntity> mQueue;
917         private boolean mStop;
918         private NamedEntity mNamedEntity;
919 
NamedImages()920         public NamedImages() {
921             mQueue = new ArrayList<NamedEntity>();
922         }
923 
nameNewImage(ContentResolver resolver, long date)924         public void nameNewImage(ContentResolver resolver, long date) {
925             NamedEntity r = new NamedEntity();
926             r.title = Util.createJpegName(date);
927             r.date = date;
928             mQueue.add(r);
929         }
930 
getTitle()931         public String getTitle() {
932             if (mQueue.isEmpty()) {
933                 mNamedEntity = null;
934                 return null;
935             }
936             mNamedEntity = mQueue.get(0);
937             mQueue.remove(0);
938 
939             return mNamedEntity.title;
940         }
941 
942         // Must be called after getTitle().
getDate()943         public long getDate() {
944             if (mNamedEntity == null) return -1;
945             return mNamedEntity.date;
946         }
947 
948         private static class NamedEntity {
949             String title;
950             long date;
951         }
952     }
953 
setCameraState(int state)954     private void setCameraState(int state) {
955         mCameraState = state;
956         switch (state) {
957         case PhotoController.PREVIEW_STOPPED:
958         case PhotoController.SNAPSHOT_IN_PROGRESS:
959         case PhotoController.FOCUSING:
960         case PhotoController.SWITCHING_CAMERA:
961             mUI.enableGestures(false);
962             break;
963         case PhotoController.IDLE:
964             if (mActivity.isInCameraApp()) {
965                 mUI.enableGestures(true);
966             }
967             break;
968         }
969     }
970 
animateFlash()971     private void animateFlash() {
972         // Only animate when in full screen capture mode
973         // i.e. If monkey/a user swipes to the gallery during picture taking,
974         // don't show animation
975         if (ApiHelper.HAS_SURFACE_TEXTURE && !mIsImageCaptureIntent
976                 && mActivity.mShowCameraAppView) {
977             // Start capture animation.
978             ((CameraScreenNail) mActivity.mCameraScreenNail).animateFlash(mDisplayRotation);
979             mUI.enablePreviewThumb(true);
980             mHandler.sendEmptyMessageDelayed(CAPTURE_ANIMATION_DONE,
981                     CaptureAnimManager.getAnimationDuration());
982         }
983     }
984 
985     @Override
capture()986     public boolean capture() {
987         // If we are already in the middle of taking a snapshot or the image save request
988         // is full then ignore.
989         if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
990                 || mCameraState == SWITCHING_CAMERA
991                 || mActivity.getMediaSaveService().isQueueFull()) {
992             return false;
993         }
994         mCaptureStartTime = System.currentTimeMillis();
995         mPostViewPictureCallbackTime = 0;
996         mJpegImageData = null;
997 
998         final boolean animateBefore = (mSceneMode == Util.SCENE_MODE_HDR);
999 
1000         if (animateBefore) {
1001             animateFlash();
1002         }
1003 
1004         // Set rotation and gps data.
1005         int orientation;
1006         // We need to be consistent with the framework orientation (i.e. the
1007         // orientation of the UI.) when the auto-rotate screen setting is on.
1008         if (mActivity.isAutoRotateScreen()) {
1009             orientation = (360 - mDisplayRotation) % 360;
1010         } else {
1011             orientation = mOrientation;
1012         }
1013         mJpegRotation = Util.getJpegRotation(mCameraId, orientation);
1014         mParameters.setRotation(mJpegRotation);
1015         Location loc = mLocationManager.getCurrentLocation();
1016         Util.setGpsParameters(mParameters, loc);
1017         mCameraDevice.setParameters(mParameters);
1018 
1019         mCameraDevice.takePicture2(new ShutterCallback(!animateBefore),
1020                 mRawPictureCallback, mPostViewPictureCallback,
1021                 new JpegPictureCallback(loc), mCameraState,
1022                 mFocusManager.getFocusState());
1023 
1024         mNamedImages.nameNewImage(mContentResolver, mCaptureStartTime);
1025 
1026         mFaceDetectionStarted = false;
1027         setCameraState(SNAPSHOT_IN_PROGRESS);
1028         UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1029                 UsageStatistics.ACTION_CAPTURE_DONE, "Photo");
1030         return true;
1031     }
1032 
1033     @Override
setFocusParameters()1034     public void setFocusParameters() {
1035         setCameraParameters(UPDATE_PARAM_PREFERENCE);
1036     }
1037 
getPreferredCameraId(ComboPreferences preferences)1038     private int getPreferredCameraId(ComboPreferences preferences) {
1039         int intentCameraId = Util.getCameraFacingIntentExtras(mActivity);
1040         if (intentCameraId != -1) {
1041             // Testing purpose. Launch a specific camera through the intent
1042             // extras.
1043             return intentCameraId;
1044         } else {
1045             return CameraSettings.readPreferredCameraId(preferences);
1046         }
1047     }
1048 
1049     @Override
onFullScreenChanged(boolean full)1050     public void onFullScreenChanged(boolean full) {
1051         mUI.onFullScreenChanged(full);
1052         if (ApiHelper.HAS_SURFACE_TEXTURE) {
1053             if (mActivity.mCameraScreenNail != null) {
1054                 ((CameraScreenNail) mActivity.mCameraScreenNail).setFullScreen(full);
1055             }
1056             return;
1057         }
1058     }
1059 
updateSceneMode()1060     private void updateSceneMode() {
1061         // If scene mode is set, we cannot set flash mode, white balance, and
1062         // focus mode, instead, we read it from driver
1063         if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1064             overrideCameraSettings(mParameters.getFlashMode(),
1065                     mParameters.getWhiteBalance(), mParameters.getFocusMode());
1066         } else {
1067             overrideCameraSettings(null, null, null);
1068         }
1069     }
1070 
overrideCameraSettings(final String flashMode, final String whiteBalance, final String focusMode)1071     private void overrideCameraSettings(final String flashMode,
1072             final String whiteBalance, final String focusMode) {
1073         mUI.overrideSettings(
1074                 CameraSettings.KEY_FLASH_MODE, flashMode,
1075                 CameraSettings.KEY_WHITE_BALANCE, whiteBalance,
1076                 CameraSettings.KEY_FOCUS_MODE, focusMode);
1077     }
1078 
loadCameraPreferences()1079     private void loadCameraPreferences() {
1080         CameraSettings settings = new CameraSettings(mActivity, mInitialParams,
1081                 mCameraId, CameraHolder.instance().getCameraInfo());
1082         mPreferenceGroup = settings.getPreferenceGroup(R.xml.camera_preferences);
1083     }
1084 
1085     @Override
onOrientationChanged(int orientation)1086     public void onOrientationChanged(int orientation) {
1087         // We keep the last known orientation. So if the user first orient
1088         // the camera then point the camera to floor or sky, we still have
1089         // the correct orientation.
1090         if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return;
1091         mOrientation = Util.roundOrientation(orientation, mOrientation);
1092 
1093         // Show the toast after getting the first orientation changed.
1094         if (mHandler.hasMessages(SHOW_TAP_TO_FOCUS_TOAST)) {
1095             mHandler.removeMessages(SHOW_TAP_TO_FOCUS_TOAST);
1096             showTapToFocusToast();
1097         }
1098     }
1099 
1100     @Override
onStop()1101     public void onStop() {
1102         if (mMediaProviderClient != null) {
1103             mMediaProviderClient.release();
1104             mMediaProviderClient = null;
1105         }
1106     }
1107 
1108     @Override
onCaptureCancelled()1109     public void onCaptureCancelled() {
1110         mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
1111         mActivity.finish();
1112     }
1113 
1114     @Override
onCaptureRetake()1115     public void onCaptureRetake() {
1116         if (mPaused)
1117             return;
1118         mUI.hidePostCaptureAlert();
1119         setupPreview();
1120     }
1121 
1122     @Override
onCaptureDone()1123     public void onCaptureDone() {
1124         if (mPaused) {
1125             return;
1126         }
1127 
1128         byte[] data = mJpegImageData;
1129 
1130         if (mCropValue == null) {
1131             // First handle the no crop case -- just return the value.  If the
1132             // caller specifies a "save uri" then write the data to its
1133             // stream. Otherwise, pass back a scaled down version of the bitmap
1134             // directly in the extras.
1135             if (mSaveUri != null) {
1136                 OutputStream outputStream = null;
1137                 try {
1138                     outputStream = mContentResolver.openOutputStream(mSaveUri);
1139                     outputStream.write(data);
1140                     outputStream.close();
1141 
1142                     mActivity.setResultEx(Activity.RESULT_OK);
1143                     mActivity.finish();
1144                 } catch (IOException ex) {
1145                     // ignore exception
1146                 } finally {
1147                     Util.closeSilently(outputStream);
1148                 }
1149             } else {
1150                 ExifInterface exif = Exif.getExif(data);
1151                 int orientation = Exif.getOrientation(exif);
1152                 Bitmap bitmap = Util.makeBitmap(data, 50 * 1024);
1153                 bitmap = Util.rotate(bitmap, orientation);
1154                 mActivity.setResultEx(Activity.RESULT_OK,
1155                         new Intent("inline-data").putExtra("data", bitmap));
1156                 mActivity.finish();
1157             }
1158         } else {
1159             // Save the image to a temp file and invoke the cropper
1160             Uri tempUri = null;
1161             FileOutputStream tempStream = null;
1162             try {
1163                 File path = mActivity.getFileStreamPath(sTempCropFilename);
1164                 path.delete();
1165                 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1166                 tempStream.write(data);
1167                 tempStream.close();
1168                 tempUri = Uri.fromFile(path);
1169             } catch (FileNotFoundException ex) {
1170                 mActivity.setResultEx(Activity.RESULT_CANCELED);
1171                 mActivity.finish();
1172                 return;
1173             } catch (IOException ex) {
1174                 mActivity.setResultEx(Activity.RESULT_CANCELED);
1175                 mActivity.finish();
1176                 return;
1177             } finally {
1178                 Util.closeSilently(tempStream);
1179             }
1180 
1181             Bundle newExtras = new Bundle();
1182             if (mCropValue.equals("circle")) {
1183                 newExtras.putString("circleCrop", "true");
1184             }
1185             if (mSaveUri != null) {
1186                 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1187             } else {
1188                 newExtras.putBoolean(CropExtras.KEY_RETURN_DATA, true);
1189             }
1190             if (mActivity.isSecureCamera()) {
1191                 newExtras.putBoolean(CropExtras.KEY_SHOW_WHEN_LOCKED, true);
1192             }
1193 
1194             Intent cropIntent = new Intent(FilterShowActivity.CROP_ACTION);
1195 
1196             cropIntent.setData(tempUri);
1197             cropIntent.putExtras(newExtras);
1198 
1199             mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1200         }
1201     }
1202 
1203     @Override
onShutterButtonFocus(boolean pressed)1204     public void onShutterButtonFocus(boolean pressed) {
1205         if (mPaused || mUI.collapseCameraControls()
1206                 || (mCameraState == SNAPSHOT_IN_PROGRESS)
1207                 || (mCameraState == PREVIEW_STOPPED)) return;
1208 
1209         // Do not do focus if there is not enough storage.
1210         if (pressed && !canTakePicture()) return;
1211 
1212         if (pressed) {
1213             mFocusManager.onShutterDown();
1214         } else {
1215             // for countdown mode, we need to postpone the shutter release
1216             // i.e. lock the focus during countdown.
1217             if (!mUI.isCountingDown()) {
1218                 mFocusManager.onShutterUp();
1219             }
1220         }
1221     }
1222 
1223     @Override
onShutterButtonClick()1224     public void onShutterButtonClick() {
1225         if (mPaused || mUI.collapseCameraControls()
1226                 || (mCameraState == SWITCHING_CAMERA)
1227                 || (mCameraState == PREVIEW_STOPPED)) return;
1228 
1229         // Do not take the picture if there is not enough storage.
1230         if (mActivity.getStorageSpace() <= Storage.LOW_STORAGE_THRESHOLD) {
1231             Log.i(TAG, "Not enough space or storage not ready. remaining="
1232                     + mActivity.getStorageSpace());
1233             return;
1234         }
1235         Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1236 
1237         if (mSceneMode == Util.SCENE_MODE_HDR) {
1238             mActivity.hideSwitcher();
1239             mActivity.setSwipingEnabled(false);
1240         }
1241         // If the user wants to do a snapshot while the previous one is still
1242         // in progress, remember the fact and do it after we finish the previous
1243         // one and re-start the preview. Snapshot in progress also includes the
1244         // state that autofocus is focusing and a picture will be taken when
1245         // focus callback arrives.
1246         if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1247                 && !mIsImageCaptureIntent) {
1248             mSnapshotOnIdle = true;
1249             return;
1250         }
1251 
1252         String timer = mPreferences.getString(
1253                 CameraSettings.KEY_TIMER,
1254                 mActivity.getString(R.string.pref_camera_timer_default));
1255         boolean playSound = mPreferences.getString(CameraSettings.KEY_TIMER_SOUND_EFFECTS,
1256                 mActivity.getString(R.string.pref_camera_timer_sound_default))
1257                 .equals(mActivity.getString(R.string.setting_on_value));
1258 
1259         int seconds = Integer.parseInt(timer);
1260         // When shutter button is pressed, check whether the previous countdown is
1261         // finished. If not, cancel the previous countdown and start a new one.
1262         if (mUI.isCountingDown()) {
1263             mUI.cancelCountDown();
1264         }
1265         if (seconds > 0) {
1266             mUI.startCountDown(seconds, playSound);
1267         } else {
1268            mSnapshotOnIdle = false;
1269            mFocusManager.doSnap();
1270         }
1271     }
1272 
1273     @Override
installIntentFilter()1274     public void installIntentFilter() {
1275     }
1276 
1277     @Override
updateStorageHintOnResume()1278     public boolean updateStorageHintOnResume() {
1279         return mFirstTimeInitialized;
1280     }
1281 
1282     @Override
updateCameraAppView()1283     public void updateCameraAppView() {
1284     }
1285 
1286     @Override
onResumeBeforeSuper()1287     public void onResumeBeforeSuper() {
1288         mPaused = false;
1289     }
1290 
1291     @Override
onResumeAfterSuper()1292     public void onResumeAfterSuper() {
1293         if (mOpenCameraFail || mCameraDisabled) return;
1294 
1295         mJpegPictureCallbackTime = 0;
1296         mZoomValue = 0;
1297 
1298         // Start the preview if it is not started.
1299         if (mCameraState == PREVIEW_STOPPED && mCameraStartUpThread == null) {
1300             resetExposureCompensation();
1301             mCameraStartUpThread = new CameraStartUpThread();
1302             mCameraStartUpThread.start();
1303         }
1304 
1305         // If first time initialization is not finished, put it in the
1306         // message queue.
1307         if (!mFirstTimeInitialized) {
1308             mHandler.sendEmptyMessage(FIRST_TIME_INIT);
1309         } else {
1310             initializeSecondTime();
1311         }
1312         keepScreenOnAwhile();
1313 
1314         // Dismiss open menu if exists.
1315         PopupManager.getInstance(mActivity).notifyShowPopup(null);
1316         UsageStatistics.onContentViewChanged(
1317                 UsageStatistics.COMPONENT_CAMERA, "PhotoModule");
1318 
1319         Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1320         if (gsensor != null) {
1321             mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1322         }
1323 
1324         Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1325         if (msensor != null) {
1326             mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1327         }
1328     }
1329 
waitCameraStartUpThread()1330     void waitCameraStartUpThread() {
1331         try {
1332             if (mCameraStartUpThread != null) {
1333                 mCameraStartUpThread.cancel();
1334                 mCameraStartUpThread.join();
1335                 mCameraStartUpThread = null;
1336                 setCameraState(IDLE);
1337             }
1338         } catch (InterruptedException e) {
1339             // ignore
1340         }
1341     }
1342 
1343     @Override
onPauseBeforeSuper()1344     public void onPauseBeforeSuper() {
1345         mPaused = true;
1346         Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1347         if (gsensor != null) {
1348             mSensorManager.unregisterListener(this, gsensor);
1349         }
1350 
1351         Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1352         if (msensor != null) {
1353             mSensorManager.unregisterListener(this, msensor);
1354         }
1355     }
1356 
1357     @Override
onPauseAfterSuper()1358     public void onPauseAfterSuper() {
1359         // Wait the camera start up thread to finish.
1360         waitCameraStartUpThread();
1361 
1362         // When camera is started from secure lock screen for the first time
1363         // after screen on, the activity gets onCreate->onResume->onPause->onResume.
1364         // To reduce the latency, keep the camera for a short time so it does
1365         // not need to be opened again.
1366         if (mCameraDevice != null && mActivity.isSecureCamera()
1367                 && ActivityBase.isFirstStartAfterScreenOn()) {
1368             ActivityBase.resetFirstStartAfterScreenOn();
1369             CameraHolder.instance().keep(KEEP_CAMERA_TIMEOUT);
1370         }
1371         // Reset the focus first. Camera CTS does not guarantee that
1372         // cancelAutoFocus is allowed after preview stops.
1373         if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1374             mCameraDevice.cancelAutoFocus();
1375         }
1376         stopPreview();
1377         // Release surface texture.
1378         ((CameraScreenNail) mActivity.mCameraScreenNail).releaseSurfaceTexture();
1379 
1380         mNamedImages = null;
1381 
1382         if (mLocationManager != null) mLocationManager.recordLocation(false);
1383 
1384         // If we are in an image capture intent and has taken
1385         // a picture, we just clear it in onPause.
1386         mJpegImageData = null;
1387 
1388         // Remove the messages in the event queue.
1389         mHandler.removeMessages(SETUP_PREVIEW);
1390         mHandler.removeMessages(FIRST_TIME_INIT);
1391         mHandler.removeMessages(CHECK_DISPLAY_ROTATION);
1392         mHandler.removeMessages(SWITCH_CAMERA);
1393         mHandler.removeMessages(SWITCH_CAMERA_START_ANIMATION);
1394         mHandler.removeMessages(CAMERA_OPEN_DONE);
1395         mHandler.removeMessages(START_PREVIEW_DONE);
1396         mHandler.removeMessages(OPEN_CAMERA_FAIL);
1397         mHandler.removeMessages(CAMERA_DISABLED);
1398 
1399         closeCamera();
1400 
1401         resetScreenOn();
1402         mUI.onPause();
1403 
1404         mPendingSwitchCameraId = -1;
1405         if (mFocusManager != null) mFocusManager.removeMessages();
1406         MediaSaveService s = mActivity.getMediaSaveService();
1407         if (s != null) {
1408             s.setListener(null);
1409         }
1410     }
1411 
1412     /**
1413      * The focus manager is the first UI related element to get initialized,
1414      * and it requires the RenderOverlay, so initialize it here
1415      */
initializeFocusManager()1416     private void initializeFocusManager() {
1417         // Create FocusManager object. startPreview needs it.
1418         // if mFocusManager not null, reuse it
1419         // otherwise create a new instance
1420         if (mFocusManager != null) {
1421             mFocusManager.removeMessages();
1422         } else {
1423             CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
1424             boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
1425             String[] defaultFocusModes = mActivity.getResources().getStringArray(
1426                     R.array.pref_camera_focusmode_default_array);
1427             mFocusManager = new FocusOverlayManager(mPreferences, defaultFocusModes,
1428                     mInitialParams, this, mirror,
1429                     mActivity.getMainLooper(), mUI);
1430         }
1431     }
1432 
1433     @Override
onConfigurationChanged(Configuration newConfig)1434     public void onConfigurationChanged(Configuration newConfig) {
1435         Log.v(TAG, "onConfigurationChanged");
1436         setDisplayOrientation();
1437     }
1438 
1439     @Override
onActivityResult( int requestCode, int resultCode, Intent data)1440     public void onActivityResult(
1441             int requestCode, int resultCode, Intent data) {
1442         switch (requestCode) {
1443             case REQUEST_CROP: {
1444                 Intent intent = new Intent();
1445                 if (data != null) {
1446                     Bundle extras = data.getExtras();
1447                     if (extras != null) {
1448                         intent.putExtras(extras);
1449                     }
1450                 }
1451                 mActivity.setResultEx(resultCode, intent);
1452                 mActivity.finish();
1453 
1454                 File path = mActivity.getFileStreamPath(sTempCropFilename);
1455                 path.delete();
1456 
1457                 break;
1458             }
1459         }
1460     }
1461 
canTakePicture()1462     private boolean canTakePicture() {
1463         return isCameraIdle() && (mActivity.getStorageSpace() > Storage.LOW_STORAGE_THRESHOLD);
1464     }
1465 
1466     @Override
autoFocus()1467     public void autoFocus() {
1468         mFocusStartTime = System.currentTimeMillis();
1469         mCameraDevice.autoFocus(mAutoFocusCallback);
1470         setCameraState(FOCUSING);
1471     }
1472 
1473     @Override
cancelAutoFocus()1474     public void cancelAutoFocus() {
1475         mCameraDevice.cancelAutoFocus();
1476         setCameraState(IDLE);
1477         setCameraParameters(UPDATE_PARAM_PREFERENCE);
1478     }
1479 
1480     // Preview area is touched. Handle touch focus.
1481     @Override
onSingleTapUp(View view, int x, int y)1482     public void onSingleTapUp(View view, int x, int y) {
1483         if (mPaused || mCameraDevice == null || !mFirstTimeInitialized
1484                 || mCameraState == SNAPSHOT_IN_PROGRESS
1485                 || mCameraState == SWITCHING_CAMERA
1486                 || mCameraState == PREVIEW_STOPPED) {
1487             return;
1488         }
1489 
1490         // Do not trigger touch focus if popup window is opened.
1491         if (mUI.removeTopLevelPopup()) return;
1492 
1493         // Check if metering area or focus area is supported.
1494         if (!mFocusAreaSupported && !mMeteringAreaSupported) return;
1495         mFocusManager.onSingleTapUp(x, y);
1496     }
1497 
1498     @Override
onBackPressed()1499     public boolean onBackPressed() {
1500         return mUI.onBackPressed();
1501     }
1502 
1503     @Override
onKeyDown(int keyCode, KeyEvent event)1504     public boolean onKeyDown(int keyCode, KeyEvent event) {
1505         switch (keyCode) {
1506         case KeyEvent.KEYCODE_VOLUME_UP:
1507         case KeyEvent.KEYCODE_VOLUME_DOWN:
1508         case KeyEvent.KEYCODE_FOCUS:
1509             if (mActivity.isInCameraApp() && mFirstTimeInitialized) {
1510                 if (event.getRepeatCount() == 0) {
1511                     onShutterButtonFocus(true);
1512                 }
1513                 return true;
1514             }
1515             return false;
1516         case KeyEvent.KEYCODE_CAMERA:
1517             if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1518                 onShutterButtonClick();
1519             }
1520             return true;
1521         case KeyEvent.KEYCODE_DPAD_CENTER:
1522             // If we get a dpad center event without any focused view, move
1523             // the focus to the shutter button and press it.
1524             if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1525                 // Start auto-focus immediately to reduce shutter lag. After
1526                 // the shutter button gets the focus, onShutterButtonFocus()
1527                 // will be called again but it is fine.
1528                 if (mUI.removeTopLevelPopup()) return true;
1529                 onShutterButtonFocus(true);
1530                 mUI.pressShutterButton();
1531             }
1532             return true;
1533         }
1534         return false;
1535     }
1536 
1537     @Override
onKeyUp(int keyCode, KeyEvent event)1538     public boolean onKeyUp(int keyCode, KeyEvent event) {
1539         switch (keyCode) {
1540         case KeyEvent.KEYCODE_VOLUME_UP:
1541         case KeyEvent.KEYCODE_VOLUME_DOWN:
1542             if (mActivity.isInCameraApp() && mFirstTimeInitialized) {
1543                 onShutterButtonClick();
1544                 return true;
1545             }
1546             return false;
1547         case KeyEvent.KEYCODE_FOCUS:
1548             if (mFirstTimeInitialized) {
1549                 onShutterButtonFocus(false);
1550             }
1551             return true;
1552         }
1553         return false;
1554     }
1555 
1556     @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
closeCamera()1557     private void closeCamera() {
1558         if (mCameraDevice != null) {
1559             mCameraDevice.setZoomChangeListener(null);
1560             if(ApiHelper.HAS_FACE_DETECTION) {
1561                 mCameraDevice.setFaceDetectionListener(null);
1562             }
1563             mCameraDevice.setErrorCallback(null);
1564             CameraHolder.instance().release();
1565             mFaceDetectionStarted = false;
1566             mCameraDevice = null;
1567             setCameraState(PREVIEW_STOPPED);
1568             mFocusManager.onCameraReleased();
1569         }
1570     }
1571 
setDisplayOrientation()1572     private void setDisplayOrientation() {
1573         mDisplayRotation = Util.getDisplayRotation(mActivity);
1574         mDisplayOrientation = Util.getDisplayOrientation(mDisplayRotation, mCameraId);
1575         mCameraDisplayOrientation = Util.getDisplayOrientation(0, mCameraId);
1576         mUI.setDisplayOrientation(mDisplayOrientation);
1577         if (mFocusManager != null) {
1578             mFocusManager.setDisplayOrientation(mDisplayOrientation);
1579         }
1580         // GLRoot also uses the DisplayRotation, and needs to be told to layout to update
1581         mActivity.getGLRoot().requestLayoutContentPane();
1582     }
1583 
1584     // Only called by UI thread.
setupPreview()1585     private void setupPreview() {
1586         mFocusManager.resetTouchFocus();
1587         startPreview();
1588         setCameraState(IDLE);
1589         startFaceDetection();
1590     }
1591 
1592     // This can be called by UI Thread or CameraStartUpThread. So this should
1593     // not modify the views.
startPreview()1594     private void startPreview() {
1595         mCameraDevice.setErrorCallback(mErrorCallback);
1596 
1597         // ICS camera frameworks has a bug. Face detection state is not cleared
1598         // after taking a picture. Stop the preview to work around it. The bug
1599         // was fixed in JB.
1600         if (mCameraState != PREVIEW_STOPPED) stopPreview();
1601 
1602         setDisplayOrientation();
1603 
1604         if (!mSnapshotOnIdle) {
1605             // If the focus mode is continuous autofocus, call cancelAutoFocus to
1606             // resume it because it may have been paused by autoFocus call.
1607             if (Util.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) {
1608                 mCameraDevice.cancelAutoFocus();
1609             }
1610             mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1611         }
1612         setCameraParameters(UPDATE_PARAM_ALL);
1613 
1614         if (ApiHelper.HAS_SURFACE_TEXTURE) {
1615             CameraScreenNail screenNail = (CameraScreenNail) mActivity.mCameraScreenNail;
1616             if (mUI.getSurfaceTexture() == null) {
1617                 Size size = mParameters.getPreviewSize();
1618                 if (mCameraDisplayOrientation % 180 == 0) {
1619                     screenNail.setSize(size.width, size.height);
1620                 } else {
1621                     screenNail.setSize(size.height, size.width);
1622                 }
1623                 screenNail.enableAspectRatioClamping();
1624                 mActivity.notifyScreenNailChanged();
1625                 screenNail.acquireSurfaceTexture();
1626                 CameraStartUpThread t = mCameraStartUpThread;
1627                 if (t != null && t.isCanceled()) {
1628                     return; // Exiting, so no need to get the surface texture.
1629                 }
1630                 mUI.setSurfaceTexture(screenNail.getSurfaceTexture());
1631             } else {
1632                 updatePreviewSize(screenNail);
1633             }
1634             mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1635             Object st = mUI.getSurfaceTexture();
1636             if (st != null) {
1637                 mCameraDevice.setPreviewTextureAsync((SurfaceTexture) st);
1638             }
1639         } else {
1640             mCameraDevice.setDisplayOrientation(mDisplayOrientation);
1641             mCameraDevice.setPreviewDisplayAsync(mUI.getSurfaceHolder());
1642         }
1643 
1644         Log.v(TAG, "startPreview");
1645         mCameraDevice.startPreviewAsync();
1646 
1647         mFocusManager.onPreviewStarted();
1648 
1649         if (mSnapshotOnIdle) {
1650             mHandler.post(mDoSnapRunnable);
1651         }
1652     }
1653 
updatePreviewSize(CameraScreenNail snail)1654     private void updatePreviewSize(CameraScreenNail snail) {
1655         Size size = mParameters.getPreviewSize();
1656         int w = size.width;
1657         int h = size.height;
1658         if (mCameraDisplayOrientation % 180 != 0) {
1659             w = size.height;
1660             h = size.width;
1661         }
1662         if (snail.getWidth() != w || snail.getHeight() != h) {
1663             snail.setSize(w, h);
1664         }
1665         snail.enableAspectRatioClamping();
1666         mActivity.notifyScreenNailChanged();
1667     }
1668 
1669     @Override
stopPreview()1670     public void stopPreview() {
1671         if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1672             Log.v(TAG, "stopPreview");
1673             mCameraDevice.stopPreview();
1674             mFaceDetectionStarted = false;
1675         }
1676         setCameraState(PREVIEW_STOPPED);
1677         if (mFocusManager != null) mFocusManager.onPreviewStopped();
1678     }
1679 
1680     @SuppressWarnings("deprecation")
updateCameraParametersInitialize()1681     private void updateCameraParametersInitialize() {
1682         // Reset preview frame rate to the maximum because it may be lowered by
1683         // video camera application.
1684         List<Integer> frameRates = mParameters.getSupportedPreviewFrameRates();
1685         if (frameRates != null) {
1686             Integer max = Collections.max(frameRates);
1687             mParameters.setPreviewFrameRate(max);
1688         }
1689 
1690         mParameters.set(Util.RECORDING_HINT, Util.FALSE);
1691 
1692         // Disable video stabilization. Convenience methods not available in API
1693         // level <= 14
1694         String vstabSupported = mParameters.get("video-stabilization-supported");
1695         if ("true".equals(vstabSupported)) {
1696             mParameters.set("video-stabilization", "false");
1697         }
1698     }
1699 
updateCameraParametersZoom()1700     private void updateCameraParametersZoom() {
1701         // Set zoom.
1702         if (mParameters.isZoomSupported()) {
1703             mParameters.setZoom(mZoomValue);
1704         }
1705     }
1706 
1707     @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
setAutoExposureLockIfSupported()1708     private void setAutoExposureLockIfSupported() {
1709         if (mAeLockSupported) {
1710             mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1711         }
1712     }
1713 
1714     @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
setAutoWhiteBalanceLockIfSupported()1715     private void setAutoWhiteBalanceLockIfSupported() {
1716         if (mAwbLockSupported) {
1717             mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1718         }
1719     }
1720 
1721     @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
setFocusAreasIfSupported()1722     private void setFocusAreasIfSupported() {
1723         if (mFocusAreaSupported) {
1724             mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1725         }
1726     }
1727 
1728     @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
setMeteringAreasIfSupported()1729     private void setMeteringAreasIfSupported() {
1730         if (mMeteringAreaSupported) {
1731             // Use the same area for focus and metering.
1732             mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1733         }
1734     }
1735 
updateCameraParametersPreference()1736     private void updateCameraParametersPreference() {
1737         setAutoExposureLockIfSupported();
1738         setAutoWhiteBalanceLockIfSupported();
1739         setFocusAreasIfSupported();
1740         setMeteringAreasIfSupported();
1741 
1742         // Set picture size.
1743         String pictureSize = mPreferences.getString(
1744                 CameraSettings.KEY_PICTURE_SIZE, null);
1745         if (pictureSize == null) {
1746             CameraSettings.initialCameraPictureSize(mActivity, mParameters);
1747         } else {
1748             List<Size> supported = mParameters.getSupportedPictureSizes();
1749             CameraSettings.setCameraPictureSize(
1750                     pictureSize, supported, mParameters);
1751         }
1752         Size size = mParameters.getPictureSize();
1753 
1754         // Set a preview size that is closest to the viewfinder height and has
1755         // the right aspect ratio.
1756         List<Size> sizes = mParameters.getSupportedPreviewSizes();
1757         Size optimalSize = Util.getOptimalPreviewSize(mActivity, sizes,
1758                 (double) size.width / size.height);
1759         Size original = mParameters.getPreviewSize();
1760         if (!original.equals(optimalSize)) {
1761             mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
1762             // Zoom related settings will be changed for different preview
1763             // sizes, so set and read the parameters to get latest values
1764             if (mHandler.getLooper() == Looper.myLooper()) {
1765                 // On UI thread only, not when camera starts up
1766                 setupPreview();
1767             } else {
1768                 mCameraDevice.setParameters(mParameters);
1769             }
1770             mParameters = mCameraDevice.getParameters();
1771         }
1772         Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
1773 
1774         // Since changing scene mode may change supported values, set scene mode
1775         // first. HDR is a scene mode. To promote it in UI, it is stored in a
1776         // separate preference.
1777         String hdr = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR,
1778                 mActivity.getString(R.string.pref_camera_hdr_default));
1779         if (mActivity.getString(R.string.setting_on_value).equals(hdr)) {
1780             mSceneMode = Util.SCENE_MODE_HDR;
1781         } else {
1782             mSceneMode = mPreferences.getString(
1783                 CameraSettings.KEY_SCENE_MODE,
1784                 mActivity.getString(R.string.pref_camera_scenemode_default));
1785         }
1786         if (Util.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
1787             if (!mParameters.getSceneMode().equals(mSceneMode)) {
1788                 mParameters.setSceneMode(mSceneMode);
1789 
1790                 // Setting scene mode will change the settings of flash mode,
1791                 // white balance, and focus mode. Here we read back the
1792                 // parameters, so we can know those settings.
1793                 mCameraDevice.setParameters(mParameters);
1794                 mParameters = mCameraDevice.getParameters();
1795             }
1796         } else {
1797             mSceneMode = mParameters.getSceneMode();
1798             if (mSceneMode == null) {
1799                 mSceneMode = Parameters.SCENE_MODE_AUTO;
1800             }
1801         }
1802 
1803         // Set JPEG quality.
1804         int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1805                 CameraProfile.QUALITY_HIGH);
1806         mParameters.setJpegQuality(jpegQuality);
1807 
1808         // For the following settings, we need to check if the settings are
1809         // still supported by latest driver, if not, ignore the settings.
1810 
1811         // Set exposure compensation
1812         int value = CameraSettings.readExposure(mPreferences);
1813         int max = mParameters.getMaxExposureCompensation();
1814         int min = mParameters.getMinExposureCompensation();
1815         if (value >= min && value <= max) {
1816             mParameters.setExposureCompensation(value);
1817         } else {
1818             Log.w(TAG, "invalid exposure range: " + value);
1819         }
1820 
1821         if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1822             // Set flash mode.
1823             String flashMode = mPreferences.getString(
1824                     CameraSettings.KEY_FLASH_MODE,
1825                     mActivity.getString(R.string.pref_camera_flashmode_default));
1826             List<String> supportedFlash = mParameters.getSupportedFlashModes();
1827             if (Util.isSupported(flashMode, supportedFlash)) {
1828                 mParameters.setFlashMode(flashMode);
1829             } else {
1830                 flashMode = mParameters.getFlashMode();
1831                 if (flashMode == null) {
1832                     flashMode = mActivity.getString(
1833                             R.string.pref_camera_flashmode_no_flash);
1834                 }
1835             }
1836 
1837             // Set white balance parameter.
1838             String whiteBalance = mPreferences.getString(
1839                     CameraSettings.KEY_WHITE_BALANCE,
1840                     mActivity.getString(R.string.pref_camera_whitebalance_default));
1841             if (Util.isSupported(whiteBalance,
1842                     mParameters.getSupportedWhiteBalance())) {
1843                 mParameters.setWhiteBalance(whiteBalance);
1844             } else {
1845                 whiteBalance = mParameters.getWhiteBalance();
1846                 if (whiteBalance == null) {
1847                     whiteBalance = Parameters.WHITE_BALANCE_AUTO;
1848                 }
1849             }
1850 
1851             // Set focus mode.
1852             mFocusManager.overrideFocusMode(null);
1853             mParameters.setFocusMode(mFocusManager.getFocusMode());
1854         } else {
1855             mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1856         }
1857 
1858         if (mContinousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
1859             updateAutoFocusMoveCallback();
1860         }
1861     }
1862 
1863     @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
updateAutoFocusMoveCallback()1864     private void updateAutoFocusMoveCallback() {
1865         if (mParameters.getFocusMode().equals(Util.FOCUS_MODE_CONTINUOUS_PICTURE)) {
1866             mCameraDevice.setAutoFocusMoveCallback(
1867                 (AutoFocusMoveCallback) mAutoFocusMoveCallback);
1868         } else {
1869             mCameraDevice.setAutoFocusMoveCallback(null);
1870         }
1871     }
1872 
1873     // We separate the parameters into several subsets, so we can update only
1874     // the subsets actually need updating. The PREFERENCE set needs extra
1875     // locking because the preference can be changed from GLThread as well.
setCameraParameters(int updateSet)1876     private void setCameraParameters(int updateSet) {
1877         if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1878             updateCameraParametersInitialize();
1879         }
1880 
1881         if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1882             updateCameraParametersZoom();
1883         }
1884 
1885         if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
1886             updateCameraParametersPreference();
1887         }
1888 
1889         mCameraDevice.setParameters(mParameters);
1890     }
1891 
1892     // If the Camera is idle, update the parameters immediately, otherwise
1893     // accumulate them in mUpdateSet and update later.
setCameraParametersWhenIdle(int additionalUpdateSet)1894     private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1895         mUpdateSet |= additionalUpdateSet;
1896         if (mCameraDevice == null) {
1897             // We will update all the parameters when we open the device, so
1898             // we don't need to do anything now.
1899             mUpdateSet = 0;
1900             return;
1901         } else if (isCameraIdle()) {
1902             setCameraParameters(mUpdateSet);
1903             updateSceneMode();
1904             mUpdateSet = 0;
1905         } else {
1906             if (!mHandler.hasMessages(SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1907                 mHandler.sendEmptyMessageDelayed(
1908                         SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
1909             }
1910         }
1911     }
1912 
isCameraIdle()1913     public boolean isCameraIdle() {
1914         return (mCameraState == IDLE) ||
1915                 (mCameraState == PREVIEW_STOPPED) ||
1916                 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
1917                         && (mCameraState != SWITCHING_CAMERA));
1918     }
1919 
isImageCaptureIntent()1920     public boolean isImageCaptureIntent() {
1921         String action = mActivity.getIntent().getAction();
1922         return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
1923                 || ActivityBase.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
1924     }
1925 
setupCaptureParams()1926     private void setupCaptureParams() {
1927         Bundle myExtras = mActivity.getIntent().getExtras();
1928         if (myExtras != null) {
1929             mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1930             mCropValue = myExtras.getString("crop");
1931         }
1932     }
1933 
1934     @Override
onSharedPreferenceChanged()1935     public void onSharedPreferenceChanged() {
1936         // ignore the events after "onPause()"
1937         if (mPaused) return;
1938 
1939         boolean recordLocation = RecordLocationPreference.get(
1940                 mPreferences, mContentResolver);
1941         mLocationManager.recordLocation(recordLocation);
1942 
1943         setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
1944         mUI.updateOnScreenIndicators(mParameters, mPreferenceGroup, mPreferences);
1945     }
1946 
1947     @Override
onCameraPickerClicked(int cameraId)1948     public void onCameraPickerClicked(int cameraId) {
1949         if (mPaused || mPendingSwitchCameraId != -1) return;
1950 
1951         mPendingSwitchCameraId = cameraId;
1952         if (ApiHelper.HAS_SURFACE_TEXTURE) {
1953             Log.v(TAG, "Start to copy texture. cameraId=" + cameraId);
1954             // We need to keep a preview frame for the animation before
1955             // releasing the camera. This will trigger onPreviewTextureCopied.
1956             ((CameraScreenNail) mActivity.mCameraScreenNail).copyTexture();
1957             // Disable all camera controls.
1958             setCameraState(SWITCHING_CAMERA);
1959         } else {
1960             switchCamera();
1961         }
1962     }
1963 
1964     // Preview texture has been copied. Now camera can be released and the
1965     // animation can be started.
1966     @Override
onPreviewTextureCopied()1967     public void onPreviewTextureCopied() {
1968         mHandler.sendEmptyMessage(SWITCH_CAMERA);
1969     }
1970 
1971     @Override
onCaptureTextureCopied()1972     public void onCaptureTextureCopied() {
1973     }
1974 
1975     @Override
onUserInteraction()1976     public void onUserInteraction() {
1977         if (!mActivity.isFinishing()) keepScreenOnAwhile();
1978     }
1979 
resetScreenOn()1980     private void resetScreenOn() {
1981         mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1982         mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1983     }
1984 
keepScreenOnAwhile()1985     private void keepScreenOnAwhile() {
1986         mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1987         mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1988         mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
1989     }
1990 
1991     // TODO: Delete this function after old camera code is removed
1992     @Override
onRestorePreferencesClicked()1993     public void onRestorePreferencesClicked() {
1994     }
1995 
1996     @Override
onOverriddenPreferencesClicked()1997     public void onOverriddenPreferencesClicked() {
1998         if (mPaused) return;
1999         mUI.showPreferencesToast();
2000     }
2001 
showTapToFocusToast()2002     private void showTapToFocusToast() {
2003         // TODO: Use a toast?
2004         new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
2005         // Clear the preference.
2006         Editor editor = mPreferences.edit();
2007         editor.putBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, false);
2008         editor.apply();
2009     }
2010 
initializeCapabilities()2011     private void initializeCapabilities() {
2012         mInitialParams = mCameraDevice.getParameters();
2013         mFocusAreaSupported = Util.isFocusAreaSupported(mInitialParams);
2014         mMeteringAreaSupported = Util.isMeteringAreaSupported(mInitialParams);
2015         mAeLockSupported = Util.isAutoExposureLockSupported(mInitialParams);
2016         mAwbLockSupported = Util.isAutoWhiteBalanceLockSupported(mInitialParams);
2017         mContinousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
2018                 Util.FOCUS_MODE_CONTINUOUS_PICTURE);
2019     }
2020 
2021     @Override
onCountDownFinished()2022     public void onCountDownFinished() {
2023         mSnapshotOnIdle = false;
2024         mFocusManager.doSnap();
2025         mFocusManager.onShutterUp();
2026     }
2027 
2028     @Override
needsSwitcher()2029     public boolean needsSwitcher() {
2030         return !mIsImageCaptureIntent;
2031     }
2032 
2033     @Override
needsPieMenu()2034     public boolean needsPieMenu() {
2035         return true;
2036     }
2037 
2038     @Override
onShowSwitcherPopup()2039     public void onShowSwitcherPopup() {
2040         mUI.onShowSwitcherPopup();
2041     }
2042 
2043     @Override
onZoomChanged(int index)2044     public int onZoomChanged(int index) {
2045         // Not useful to change zoom value when the activity is paused.
2046         if (mPaused) return index;
2047         mZoomValue = index;
2048         if (mParameters == null || mCameraDevice == null) return index;
2049         // Set zoom parameters asynchronously
2050         mParameters.setZoom(mZoomValue);
2051         mCameraDevice.setParameters(mParameters);
2052         Parameters p = mCameraDevice.getParameters();
2053         if (p != null) return p.getZoom();
2054         return index;
2055     }
2056 
2057     @Override
getCameraState()2058     public int getCameraState() {
2059         return mCameraState;
2060     }
2061 
2062     @Override
onQueueStatus(boolean full)2063     public void onQueueStatus(boolean full) {
2064         mUI.enableShutter(!full);
2065     }
2066 
2067     @Override
onMediaSaveServiceConnected(MediaSaveService s)2068     public void onMediaSaveServiceConnected(MediaSaveService s) {
2069         // We set the listener only when both service and shutterbutton
2070         // are initialized.
2071         if (mFirstTimeInitialized) {
2072             s.setListener(this);
2073         }
2074     }
2075 
2076     @Override
onAccuracyChanged(Sensor sensor, int accuracy)2077     public void onAccuracyChanged(Sensor sensor, int accuracy) {
2078     }
2079 
2080     @Override
onSensorChanged(SensorEvent event)2081     public void onSensorChanged(SensorEvent event) {
2082         int type = event.sensor.getType();
2083         float[] data;
2084         if (type == Sensor.TYPE_ACCELEROMETER) {
2085             data = mGData;
2086         } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
2087             data = mMData;
2088         } else {
2089             // we should not be here.
2090             return;
2091         }
2092         for (int i = 0; i < 3 ; i++) {
2093             data[i] = event.values[i];
2094         }
2095         float[] orientation = new float[3];
2096         SensorManager.getRotationMatrix(mR, null, mGData, mMData);
2097         SensorManager.getOrientation(mR, orientation);
2098         mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
2099         if (mHeading < 0) {
2100             mHeading += 360;
2101         }
2102     }
2103 }
2104