blob: 891b814c2394df3747db93d306c586024a75bab4 [file] [log] [blame]
Michael Kolb8872c232013-01-29 10:33:22 -08001/*
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
17package com.android.camera;
18
19import android.annotation.TargetApi;
20import android.app.Activity;
Michael Kolb8872c232013-01-29 10:33:22 -080021import android.content.ContentResolver;
Angus Kong0d00a892013-03-26 11:40:40 -070022import android.content.Context;
Michael Kolb8872c232013-01-29 10:33:22 -080023import android.content.Intent;
Michael Kolb8872c232013-01-29 10:33:22 -080024import android.graphics.Bitmap;
Doris Liu36ebcb12013-10-28 14:44:24 -070025import android.graphics.Rect;
Michael Kolb8872c232013-01-29 10:33:22 -080026import android.graphics.SurfaceTexture;
27import android.hardware.Camera.CameraInfo;
Michael Kolb8872c232013-01-29 10:33:22 -080028import android.hardware.Camera.Parameters;
Michael Kolb8872c232013-01-29 10:33:22 -080029import android.hardware.Camera.Size;
Angus Kong0d00a892013-03-26 11:40:40 -070030import android.hardware.Sensor;
31import android.hardware.SensorEvent;
32import android.hardware.SensorEventListener;
33import android.hardware.SensorManager;
Michael Kolb8872c232013-01-29 10:33:22 -080034import android.location.Location;
35import android.media.CameraProfile;
36import android.net.Uri;
Sascha Haeberling638e6f02013-09-18 14:28:51 -070037import android.os.Build;
Michael Kolb8872c232013-01-29 10:33:22 -080038import android.os.Bundle;
Michael Kolb8872c232013-01-29 10:33:22 -080039import android.os.Handler;
40import android.os.Looper;
41import android.os.Message;
42import android.os.MessageQueue;
43import android.os.SystemClock;
44import android.provider.MediaStore;
45import android.util.Log;
Michael Kolb8872c232013-01-29 10:33:22 -080046import android.view.KeyEvent;
Michael Kolb8872c232013-01-29 10:33:22 -080047import android.view.OrientationEventListener;
Michael Kolb8872c232013-01-29 10:33:22 -080048import android.view.View;
Doris Liu773e1c92013-12-02 17:35:03 -080049import android.view.ViewGroup;
Michael Kolb8872c232013-01-29 10:33:22 -080050
Sameer Padala2c8cc452013-11-05 18:49:12 -080051import com.android.camera.PhotoModule.NamedImages.NamedEntity;
52import com.android.camera.app.AppController;
Angus Kong20fad242013-11-11 18:23:46 -080053import com.android.camera.app.CameraManager.CameraAFCallback;
54import com.android.camera.app.CameraManager.CameraAFMoveCallback;
55import com.android.camera.app.CameraManager.CameraPictureCallback;
56import com.android.camera.app.CameraManager.CameraProxy;
57import com.android.camera.app.CameraManager.CameraShutterCallback;
Angus Kongfd4fc0e2013-11-07 15:38:09 -080058import com.android.camera.app.MediaSaver;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080059import com.android.camera.app.MemoryManager;
60import com.android.camera.app.MemoryManager.MemoryListener;
ztenghuia16e7b52013-08-23 11:47:56 -070061import com.android.camera.exif.ExifInterface;
62import com.android.camera.exif.ExifTag;
63import com.android.camera.exif.Rational;
Angus Kong20fad242013-11-11 18:23:46 -080064import com.android.camera.module.ModuleController;
Erin Dahlgren357b7672013-11-20 17:38:14 -080065import com.android.camera.settings.SettingsManager;
Doris Liu1c94b7d2013-11-09 19:13:44 -080066import com.android.camera.ui.ModeListView;
Michael Kolb8872c232013-01-29 10:33:22 -080067import com.android.camera.ui.RotateTextToast;
Angus Kongdcccc512013-08-08 17:06:03 -070068import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -070069import com.android.camera.util.CameraUtil;
Ruben Brunk4601f5d2013-09-24 18:35:22 -070070import com.android.camera.util.GcamHelper;
Sameer Padala2c8cc452013-11-05 18:49:12 -080071import com.android.camera.util.SmartCameraHelper;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070072import com.android.camera.util.UsageStatistics;
73import com.android.camera2.R;
Michael Kolb8872c232013-01-29 10:33:22 -080074
Angus Kongdcccc512013-08-08 17:06:03 -070075import java.io.File;
76import java.io.FileNotFoundException;
77import java.io.FileOutputStream;
78import java.io.IOException;
79import java.io.OutputStream;
Angus Kongdcccc512013-08-08 17:06:03 -070080import java.util.List;
Ruben Brunka9d66bd2013-09-06 11:56:32 -070081import java.util.Vector;
Angus Kongdcccc512013-08-08 17:06:03 -070082
Michael Kolb8872c232013-01-29 10:33:22 -080083public class PhotoModule
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080084 extends CameraModule
85 implements PhotoController,
86 ModuleController,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080087 MemoryListener,
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080088 FocusOverlayManager.Listener,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080089 ShutterButton.OnShutterButtonListener,
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080090 SensorEventListener {
Michael Kolb8872c232013-01-29 10:33:22 -080091
92 private static final String TAG = "CAM_PhotoModule";
93
94 // We number the request code from 1000 to avoid collision with Gallery.
95 private static final int REQUEST_CROP = 1000;
96
Angus Kong13e87c42013-11-25 10:02:47 -080097 // Messages defined for the UI thread handler.
98 private static final int MSG_SETUP_PREVIEW = 1;
99 private static final int MSG_FIRST_TIME_INIT = 2;
100 private static final int MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE = 3;
101 private static final int MSG_SHOW_TAP_TO_FOCUS_TOAST = 4;
102 private static final int MSG_SWITCH_CAMERA = 5;
103 private static final int MSG_SWITCH_CAMERA_START_ANIMATION = 6;
104 private static final int MSG_CAMERA_OPEN_DONE = 7;
105 private static final int MSG_OPEN_CAMERA_FAIL = 8;
106 private static final int MSG_CAMERA_DISABLED = 9;
107 private static final int MSG_SWITCH_TO_GCAM_MODULE = 10;
Michael Kolb8872c232013-01-29 10:33:22 -0800108
109 // The subset of parameters we need to update in setCameraParameters().
110 private static final int UPDATE_PARAM_INITIALIZE = 1;
111 private static final int UPDATE_PARAM_ZOOM = 2;
112 private static final int UPDATE_PARAM_PREFERENCE = 4;
113 private static final int UPDATE_PARAM_ALL = -1;
114
Andy Huibersdef975d2013-11-22 09:13:39 -0800115 // This is the delay before we execute onResume tasks when coming
116 // from the lock screen, to allow time for onPause to execute.
117 private static final int ON_RESUME_TASKS_DELAY_MSEC = 20;
Michael Kolb8872c232013-01-29 10:33:22 -0800118
Ruben Brunkd7488272013-10-10 18:45:53 -0700119 private static final String DEBUG_IMAGE_PREFIX = "DEBUG_";
120
Michael Kolb8872c232013-01-29 10:33:22 -0800121 // copied from Camera hierarchy
122 private CameraActivity mActivity;
Michael Kolb8872c232013-01-29 10:33:22 -0800123 private CameraProxy mCameraDevice;
124 private int mCameraId;
125 private Parameters mParameters;
126 private boolean mPaused;
Michael Kolbd6954f32013-03-08 20:43:01 -0800127
128 private PhotoUI mUI;
Michael Kolb8872c232013-01-29 10:33:22 -0800129
Michael Kolb8872c232013-01-29 10:33:22 -0800130 // The activity is going to switch to the specified camera id. This is
131 // needed because texture copy is done in GL thread. -1 means camera is not
132 // switching.
133 protected int mPendingSwitchCameraId = -1;
134 private boolean mOpenCameraFail;
135 private boolean mCameraDisabled;
136
137 // When setCameraParametersWhenIdle() is called, we accumulate the subsets
138 // needed to be updated in mUpdateSet.
139 private int mUpdateSet;
140
141 private static final int SCREEN_DELAY = 2 * 60 * 1000;
142
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800143 private int mZoomValue; // The current zoom value.
Michael Kolb8872c232013-01-29 10:33:22 -0800144
145 private Parameters mInitialParams;
146 private boolean mFocusAreaSupported;
147 private boolean mMeteringAreaSupported;
148 private boolean mAeLockSupported;
149 private boolean mAwbLockSupported;
Angus Kongdcccc512013-08-08 17:06:03 -0700150 private boolean mContinuousFocusSupported;
Michael Kolb8872c232013-01-29 10:33:22 -0800151
152 // The degrees of the device rotated clockwise from its natural orientation.
153 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
Michael Kolb8872c232013-01-29 10:33:22 -0800154
155 private static final String sTempCropFilename = "crop-temp";
156
Michael Kolb8872c232013-01-29 10:33:22 -0800157 private boolean mFaceDetectionStarted = false;
158
Michael Kolb8872c232013-01-29 10:33:22 -0800159 // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
160 private String mCropValue;
161 private Uri mSaveUri;
162
Ruben Brunkd217ed02013-10-08 23:31:13 -0700163 private Uri mDebugUri;
164
Angus Kongce5480e2013-01-29 17:43:48 -0800165 // We use a queue to generated names of the images to be used later
166 // when the image is ready to be saved.
Michael Kolb8872c232013-01-29 10:33:22 -0800167 private NamedImages mNamedImages;
168
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800169 private final Runnable mDoSnapRunnable = new Runnable() {
Michael Kolb8872c232013-01-29 10:33:22 -0800170 @Override
171 public void run() {
172 onShutterButtonClick();
173 }
174 };
175
Michael Kolb8872c232013-01-29 10:33:22 -0800176 /**
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800177 * An unpublished intent flag requesting to return as soon as capturing is
178 * completed. TODO: consider publishing by moving into MediaStore.
Michael Kolb8872c232013-01-29 10:33:22 -0800179 */
180 private static final String EXTRA_QUICK_CAPTURE =
181 "android.intent.extra.quickCapture";
182
183 // The display rotation in degrees. This is only valid when mCameraState is
184 // not PREVIEW_STOPPED.
185 private int mDisplayRotation;
186 // The value for android.hardware.Camera.setDisplayOrientation.
187 private int mCameraDisplayOrientation;
188 // The value for UI components like indicators.
189 private int mDisplayOrientation;
190 // The value for android.hardware.Camera.Parameters.setRotation.
191 private int mJpegRotation;
Doris Liu29da2db2013-08-28 14:28:45 -0700192 // Indicates whether we are using front camera
193 private boolean mMirror;
Michael Kolb8872c232013-01-29 10:33:22 -0800194 private boolean mFirstTimeInitialized;
195 private boolean mIsImageCaptureIntent;
196
Michael Kolb8872c232013-01-29 10:33:22 -0800197 private int mCameraState = PREVIEW_STOPPED;
198 private boolean mSnapshotOnIdle = false;
199
200 private ContentResolver mContentResolver;
201
202 private LocationManager mLocationManager;
Doris Liu2b906b82013-12-10 16:34:08 -0800203 private AppController mAppController;
Michael Kolb8872c232013-01-29 10:33:22 -0800204
Michael Kolb8872c232013-01-29 10:33:22 -0800205 private final PostViewPictureCallback mPostViewPictureCallback =
206 new PostViewPictureCallback();
207 private final RawPictureCallback mRawPictureCallback =
208 new RawPictureCallback();
209 private final AutoFocusCallback mAutoFocusCallback =
210 new AutoFocusCallback();
211 private final Object mAutoFocusMoveCallback =
212 ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700213 ? new AutoFocusMoveCallback()
214 : null;
Michael Kolb8872c232013-01-29 10:33:22 -0800215
216 private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
217
218 private long mFocusStartTime;
219 private long mShutterCallbackTime;
220 private long mPostViewPictureCallbackTime;
221 private long mRawPictureCallbackTime;
222 private long mJpegPictureCallbackTime;
223 private long mOnResumeTime;
224 private byte[] mJpegImageData;
225
226 // These latency time are for the CameraLatency test.
227 public long mAutoFocusTime;
228 public long mShutterLag;
229 public long mShutterToPictureDisplayedTime;
230 public long mPictureDisplayedToJpegCallbackTime;
231 public long mJpegCallbackFinishTime;
232 public long mCaptureStartTime;
233
234 // This handles everything about focus.
235 private FocusOverlayManager mFocusManager;
236
Michael Kolb8872c232013-01-29 10:33:22 -0800237 private String mSceneMode;
Michael Kolb8872c232013-01-29 10:33:22 -0800238
239 private final Handler mHandler = new MainHandler();
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800240
Michael Kolb8872c232013-01-29 10:33:22 -0800241 private boolean mQuickCapture;
Angus Kong0d00a892013-03-26 11:40:40 -0700242 private SensorManager mSensorManager;
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800243 private final float[] mGData = new float[3];
244 private final float[] mMData = new float[3];
245 private final float[] mR = new float[16];
Angus Kong0d00a892013-03-26 11:40:40 -0700246 private int mHeading = -1;
247
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800248 /** Whether shutter is enabled. */
Spike Sprague215f6b02013-12-12 11:53:49 -0800249 private boolean mShutterEnabled = true;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800250
251 /** True if all the parameters needed to start preview is ready. */
Angus Kongdcccc512013-08-08 17:06:03 -0700252 private boolean mCameraPreviewParamsReady = false;
Doris Liu6432cd62013-06-13 17:20:31 -0700253
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800254 private final MediaSaver.OnMediaSavedListener mOnMediaSavedListener =
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800255 new MediaSaver.OnMediaSavedListener() {
Angus Kongce5480e2013-01-29 17:43:48 -0800256 @Override
257 public void onMediaSaved(Uri uri) {
258 if (uri != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700259 mActivity.notifyNewMedia(uri);
Angus Kongce5480e2013-01-29 17:43:48 -0800260 }
261 }
262 };
Michael Kolb8872c232013-01-29 10:33:22 -0800263
Angus Kongdcccc512013-08-08 17:06:03 -0700264 private void checkDisplayRotation() {
265 // Set the display orientation if display rotation has changed.
266 // Sometimes this happens when the device is held upside
267 // down and camera app is opened. Rotation animation will
268 // take some time and the rotation value we have got may be
269 // wrong. Framework does not have a callback for this now.
270 if (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) {
271 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -0800272 }
Angus Kongdcccc512013-08-08 17:06:03 -0700273 if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
274 mHandler.postDelayed(new Runnable() {
275 @Override
276 public void run() {
277 checkDisplayRotation();
278 }
279 }, 100);
Michael Kolb8872c232013-01-29 10:33:22 -0800280 }
281 }
282
283 /**
284 * This Handler is used to post message back onto the main thread of the
285 * application
286 */
287 private class MainHandler extends Handler {
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800288 public MainHandler() {
289 super(Looper.getMainLooper());
290 }
291
Michael Kolb8872c232013-01-29 10:33:22 -0800292 @Override
293 public void handleMessage(Message msg) {
294 switch (msg.what) {
Angus Kong13e87c42013-11-25 10:02:47 -0800295 case MSG_SETUP_PREVIEW: {
Michael Kolb8872c232013-01-29 10:33:22 -0800296 setupPreview();
297 break;
298 }
299
Angus Kong13e87c42013-11-25 10:02:47 -0800300 case MSG_FIRST_TIME_INIT: {
Michael Kolb8872c232013-01-29 10:33:22 -0800301 initializeFirstTime();
302 break;
303 }
304
Angus Kong13e87c42013-11-25 10:02:47 -0800305 case MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE: {
Michael Kolb8872c232013-01-29 10:33:22 -0800306 setCameraParametersWhenIdle(0);
307 break;
308 }
309
Angus Kong13e87c42013-11-25 10:02:47 -0800310 case MSG_SHOW_TAP_TO_FOCUS_TOAST: {
Michael Kolb8872c232013-01-29 10:33:22 -0800311 showTapToFocusToast();
312 break;
313 }
314
Angus Kong13e87c42013-11-25 10:02:47 -0800315 case MSG_SWITCH_CAMERA: {
Michael Kolb8872c232013-01-29 10:33:22 -0800316 switchCamera();
317 break;
318 }
319
Angus Kong13e87c42013-11-25 10:02:47 -0800320 case MSG_SWITCH_CAMERA_START_ANIMATION: {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700321 // TODO: Need to revisit
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800322 // ((CameraScreenNail)
323 // mActivity.mCameraScreenNail).animateSwitchCamera();
Michael Kolb8872c232013-01-29 10:33:22 -0800324 break;
325 }
326
Angus Kong13e87c42013-11-25 10:02:47 -0800327 case MSG_CAMERA_OPEN_DONE: {
Michael Kolbd6954f32013-03-08 20:43:01 -0800328 onCameraOpened();
Michael Kolb8872c232013-01-29 10:33:22 -0800329 break;
330 }
331
Angus Kong13e87c42013-11-25 10:02:47 -0800332 case MSG_OPEN_CAMERA_FAIL: {
Michael Kolb8872c232013-01-29 10:33:22 -0800333 mOpenCameraFail = true;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700334 CameraUtil.showErrorAndFinish(mActivity,
Michael Kolb8872c232013-01-29 10:33:22 -0800335 R.string.cannot_connect_camera);
336 break;
337 }
338
Angus Kong13e87c42013-11-25 10:02:47 -0800339 case MSG_CAMERA_DISABLED: {
Michael Kolb8872c232013-01-29 10:33:22 -0800340 mCameraDisabled = true;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700341 CameraUtil.showErrorAndFinish(mActivity,
Michael Kolb8872c232013-01-29 10:33:22 -0800342 R.string.camera_disabled);
343 break;
344 }
ztenghui367c7c82013-10-16 14:43:26 -0700345
Angus Kong13e87c42013-11-25 10:02:47 -0800346 case MSG_SWITCH_TO_GCAM_MODULE: {
Erin Dahlgrend7b8cb52013-11-14 17:25:37 -0800347 mActivity.onModeSelected(ModeListView.MODE_GCAM);
ztenghui367c7c82013-10-16 14:43:26 -0700348 }
Michael Kolb8872c232013-01-29 10:33:22 -0800349 }
350 }
351 }
352
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800353 /**
354 * Constructs a new photo module.
355 */
Angus Kongc4e66562013-11-22 23:03:21 -0800356 public PhotoModule(AppController app) {
357 super(app);
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800358 }
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700359
Angus Kong13e87c42013-11-25 10:02:47 -0800360
Michael Kolb8872c232013-01-29 10:33:22 -0800361 @Override
Angus Kong13e87c42013-11-25 10:02:47 -0800362 public void init(AppController app, boolean isSecureCamera, boolean isCaptureIntent) {
363 mActivity = (CameraActivity) app.getAndroidContext();
364 mUI = new PhotoUI(mActivity, this, app.getModuleLayoutRoot());
Doris Liu06db7422013-12-09 19:36:25 -0800365 app.setPreviewStatusListener(mUI);
Erin Dahlgren357b7672013-11-20 17:38:14 -0800366
367 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800368 mCameraId = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_CAMERA_ID));
Michael Kolb8872c232013-01-29 10:33:22 -0800369
370 mContentResolver = mActivity.getContentResolver();
371
Michael Kolb8872c232013-01-29 10:33:22 -0800372 // Surface texture is from camera screen nail and startPreview needs it.
373 // This must be done before startPreview.
374 mIsImageCaptureIntent = isImageCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800375
Angus Kong20fad242013-11-11 18:23:46 -0800376 mActivity.getCameraProvider().requestCamera(mCameraId);
377
Michael Kolb8872c232013-01-29 10:33:22 -0800378 initializeControlByIntent();
379 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800380 mLocationManager = mActivity.getLocationManager();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800381 mSensorManager = (SensorManager) (mActivity.getSystemService(Context.SENSOR_SERVICE));
Doris Liu2b906b82013-12-10 16:34:08 -0800382 mAppController = app;
Michael Kolbd6954f32013-03-08 20:43:01 -0800383 }
384
385 private void initializeControlByIntent() {
386 mUI.initializeControlByIntent();
387 if (mIsImageCaptureIntent) {
388 setupCaptureParams();
389 }
390 }
391
392 private void onPreviewStarted() {
Doris Liu2b906b82013-12-10 16:34:08 -0800393 mAppController.onPreviewStarted();
Michael Kolbd6954f32013-03-08 20:43:01 -0800394 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800395 startFaceDetection();
Sameer Padala2c8cc452013-11-05 18:49:12 -0800396 startSmartCamera();
Michael Kolbd6954f32013-03-08 20:43:01 -0800397 locationFirstRun();
Michael Kolb8872c232013-01-29 10:33:22 -0800398 }
399
400 // Prompt the user to pick to record location for the very first run of
401 // camera only
402 private void locationFirstRun() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800403 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800404 if (settingsManager.isSet(SettingsManager.SETTING_RECORD_LOCATION)) {
Michael Kolb8872c232013-01-29 10:33:22 -0800405 return;
406 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800407 if (mActivity.isSecureCamera()) {
408 return;
409 }
Michael Kolb8872c232013-01-29 10:33:22 -0800410 // Check if the back camera exists
411 int backCameraId = CameraHolder.instance().getBackCameraId();
412 if (backCameraId == -1) {
413 // If there is no back camera, do not show the prompt.
414 return;
415 }
Doris Liu6a83d522013-07-02 12:03:32 -0700416 mUI.showLocationDialog();
417 }
Michael Kolb8872c232013-01-29 10:33:22 -0800418
ztenghui7b265a62013-09-09 14:58:44 -0700419 @Override
Angus Kongdcccc512013-08-08 17:06:03 -0700420 public void onPreviewUIReady() {
Erin Dahlgrendc282e12013-11-12 09:39:08 -0800421 startPreview();
Angus Kongdcccc512013-08-08 17:06:03 -0700422 }
423
424 @Override
425 public void onPreviewUIDestroyed() {
426 if (mCameraDevice == null) {
427 return;
428 }
429 mCameraDevice.setPreviewTexture(null);
430 stopPreview();
431 }
432
Doris Liu1dfe7822013-12-12 00:02:08 -0800433 @Override
434 public void startPreCaptureAnimation() {
435 mAppController.startPreCaptureAnimation();
436 }
437
Michael Kolbd6954f32013-03-08 20:43:01 -0800438 private void onCameraOpened() {
439 View root = mUI.getRootView();
Michael Kolb8872c232013-01-29 10:33:22 -0800440 // These depend on camera parameters.
Michael Kolbd6954f32013-03-08 20:43:01 -0800441
442 int width = root.getWidth();
443 int height = root.getHeight();
Doris Liu6a0de792013-02-26 10:54:25 -0800444 mFocusManager.setPreviewSize(width, height);
Michael Kolbd6954f32013-03-08 20:43:01 -0800445 openCameraCommon();
Michael Kolb8872c232013-01-29 10:33:22 -0800446 }
447
Michael Kolbd6954f32013-03-08 20:43:01 -0800448 private void switchCamera() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800449 if (mPaused) {
450 return;
451 }
Erin Dahlgren357b7672013-11-20 17:38:14 -0800452 SettingsManager settingsManager = mActivity.getSettingsManager();
Michael Kolbd6954f32013-03-08 20:43:01 -0800453
454 Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
455 mCameraId = mPendingSwitchCameraId;
456 mPendingSwitchCameraId = -1;
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800457 settingsManager.set(SettingsManager.SETTING_CAMERA_ID, "" + mCameraId);
Angus Kong20fad242013-11-11 18:23:46 -0800458 mActivity.getCameraProvider().requestCamera(mCameraId);
Michael Kolbd6954f32013-03-08 20:43:01 -0800459 mUI.clearFaces();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800460 if (mFocusManager != null) {
461 mFocusManager.removeMessages();
462 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800463
Erin Dahlgren357b7672013-11-20 17:38:14 -0800464 // TODO: this needs to be brought into onCameraAvailable();
Angus Kong20fad242013-11-11 18:23:46 -0800465 CameraInfo info = mActivity.getCameraProvider().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -0700466 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
467 mFocusManager.setMirror(mMirror);
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700468 // Start switch camera animation. Post a message because
469 // onFrameAvailable from the old camera may already exist.
Angus Kong13e87c42013-11-25 10:02:47 -0800470 mHandler.sendEmptyMessage(MSG_SWITCH_CAMERA_START_ANIMATION);
Doris Liu48239f42013-03-04 22:19:10 -0800471 }
472
Sascha Haeberling29f60562013-12-10 12:18:56 -0800473 private final ButtonManager.ButtonCallback mCameraButtonCallback =
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800474 new ButtonManager.ButtonCallback() {
475 @Override
476 public void onStateChanged(int state) {
477 if (mPaused || mPendingSwitchCameraId != -1) {
478 return;
479 }
480 mPendingSwitchCameraId = state;
481
482 Log.v(TAG, "Start to switch camera. cameraId=" + state);
483 // We need to keep a preview frame for the animation before
484 // releasing the camera. This will trigger onPreviewTextureCopied.
485 //TODO: Need to animate the camera switch
486 switchCamera();
487 }
488 };
489
Sascha Haeberling29f60562013-12-10 12:18:56 -0800490 private final ButtonManager.ButtonCallback mHdrPlusButtonCallback =
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800491 new ButtonManager.ButtonCallback() {
492 @Override
493 public void onStateChanged(int state) {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -0800494 if (GcamHelper.hasGcamCapture()) {
495 mHandler.sendEmptyMessage(MSG_SWITCH_TO_GCAM_MODULE);
496 } else {
497 mSceneMode = CameraUtil.SCENE_MODE_HDR;
498 updateParametersSceneMode();
499 }
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800500 }
501 };
502
Michael Kolbd6954f32013-03-08 20:43:01 -0800503 // either open a new camera or switch cameras
504 private void openCameraCommon() {
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800505 mUI.onCameraOpened(mParameters, mCameraButtonCallback, mHdrPlusButtonCallback);
Angus Kong0fb819b2013-10-08 13:44:19 -0700506 if (mIsImageCaptureIntent) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800507 // Set hdr plus to default: off.
508 SettingsManager settingsManager = mActivity.getSettingsManager();
509 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_HDR_PLUS);
Angus Kong0fb819b2013-10-08 13:44:19 -0700510 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800511 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -0800512 }
513
ztenghui7b265a62013-09-09 14:58:44 -0700514 @Override
Doris Liu36ebcb12013-10-28 14:44:24 -0700515 public void onPreviewRectChanged(Rect previewRect) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800516 if (mFocusManager != null)
517 mFocusManager.setPreviewRect(previewRect);
Michael Kolbd6954f32013-03-08 20:43:01 -0800518 }
Michael Kolb8872c232013-01-29 10:33:22 -0800519
Doris Liu70da9182013-12-17 18:41:15 -0800520 @Override
521 public void updatePreviewAspectRatio(float aspectRatio) {
522 mAppController.updatePreviewAspectRatio(aspectRatio);
523 }
524
Michael Kolb8872c232013-01-29 10:33:22 -0800525 private void resetExposureCompensation() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800526 SettingsManager settingsManager = mActivity.getSettingsManager();
527 if (settingsManager == null) {
528 Log.e(TAG, "Settings manager is null!");
529 return;
Michael Kolb8872c232013-01-29 10:33:22 -0800530 }
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800531 settingsManager.setDefault(SettingsManager.SETTING_EXPOSURE);
Michael Kolb8872c232013-01-29 10:33:22 -0800532 }
533
Michael Kolb8872c232013-01-29 10:33:22 -0800534 // Snapshots can only be taken after this is called. It should be called
535 // once only. We could have done these things in onCreate() but we want to
536 // make preview screen appear as soon as possible.
537 private void initializeFirstTime() {
Sascha Haeberling330dafb2013-10-10 19:00:41 -0700538 if (mFirstTimeInitialized || mPaused) {
539 return;
540 }
Michael Kolb8872c232013-01-29 10:33:22 -0800541
542 // Initialize location service.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800543 SettingsController settingsController = mActivity.getSettingsController();
544 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -0800545
Michael Kolbd6954f32013-03-08 20:43:01 -0800546 mUI.initializeFirstTime();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800547
Angus Kong86d36312013-01-31 18:22:44 -0800548 // We set the listener only when both service and shutterbutton
549 // are initialized.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800550 getServices().getMemoryManager().addListener(this);
Michael Kolb8872c232013-01-29 10:33:22 -0800551
Michael Kolb8872c232013-01-29 10:33:22 -0800552 mNamedImages = new NamedImages();
553
554 mFirstTimeInitialized = true;
555 addIdleHandler();
556
557 mActivity.updateStorageSpaceAndHint();
558 }
559
Michael Kolbd6954f32013-03-08 20:43:01 -0800560 // If the activity is paused and resumed, this method will be called in
561 // onResume.
562 private void initializeSecondTime() {
563 // Start location update if needed.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800564 SettingsController settingsController = mActivity.getSettingsController();
565 settingsController.syncLocationManager();
566
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800567 getServices().getMemoryManager().addListener(this);
Michael Kolbd6954f32013-03-08 20:43:01 -0800568 mNamedImages = new NamedImages();
569 mUI.initializeSecondTime(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -0800570 }
571
Michael Kolb8872c232013-01-29 10:33:22 -0800572 private void addIdleHandler() {
573 MessageQueue queue = Looper.myQueue();
574 queue.addIdleHandler(new MessageQueue.IdleHandler() {
575 @Override
576 public boolean queueIdle() {
577 Storage.ensureOSXCompatible();
578 return false;
579 }
580 });
581 }
582
Sameer Padala2c8cc452013-11-05 18:49:12 -0800583 private void startSmartCamera() {
584 SmartCameraHelper.register(mCameraDevice, mParameters.getPreviewSize(), mActivity,
Doris Liu773e1c92013-12-02 17:35:03 -0800585 (ViewGroup) mActivity.findViewById(R.id.camera_app_root));
Sameer Padala2c8cc452013-11-05 18:49:12 -0800586 }
587
588 private void stopSmartCamera() {
589 SmartCameraHelper.tearDown();
590 }
591
Michael Kolb8872c232013-01-29 10:33:22 -0800592 @Override
593 public void startFaceDetection() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800594 if (mFaceDetectionStarted) {
595 return;
596 }
Michael Kolb8872c232013-01-29 10:33:22 -0800597 if (mParameters.getMaxNumDetectedFaces() > 0) {
598 mFaceDetectionStarted = true;
Michael Kolb8872c232013-01-29 10:33:22 -0800599 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Michael Kolbd6954f32013-03-08 20:43:01 -0800600 mUI.onStartFaceDetection(mDisplayOrientation,
601 (info.facing == CameraInfo.CAMERA_FACING_FRONT));
Angus Kong9e765522013-07-31 14:05:20 -0700602 mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Michael Kolb8872c232013-01-29 10:33:22 -0800603 mCameraDevice.startFaceDetection();
604 }
605 }
606
Michael Kolb8872c232013-01-29 10:33:22 -0800607 @Override
608 public void stopFaceDetection() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800609 if (!mFaceDetectionStarted) {
610 return;
611 }
Michael Kolb8872c232013-01-29 10:33:22 -0800612 if (mParameters.getMaxNumDetectedFaces() > 0) {
613 mFaceDetectionStarted = false;
Angus Kong9e765522013-07-31 14:05:20 -0700614 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -0800615 mCameraDevice.stopFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800616 mUI.clearFaces();
Michael Kolb8872c232013-01-29 10:33:22 -0800617 }
618 }
619
Michael Kolb8872c232013-01-29 10:33:22 -0800620 private final class ShutterCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700621 implements CameraShutterCallback {
Angus Kongdcb0ef12013-03-25 23:11:43 -0700622
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800623 private final boolean mNeedsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700624
Sascha Haeberling37f36112013-08-06 14:31:52 -0700625 public ShutterCallback(boolean needsAnimation) {
626 mNeedsAnimation = needsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700627 }
628
Michael Kolb8872c232013-01-29 10:33:22 -0800629 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700630 public void onShutter(CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800631 mShutterCallbackTime = System.currentTimeMillis();
632 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
633 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Sascha Haeberling37f36112013-08-06 14:31:52 -0700634 if (mNeedsAnimation) {
635 mActivity.runOnUiThread(new Runnable() {
636 @Override
637 public void run() {
638 animateAfterShutter();
639 }
640 });
Angus Kongdcb0ef12013-03-25 23:11:43 -0700641 }
Michael Kolb8872c232013-01-29 10:33:22 -0800642 }
643 }
644
Angus Kong9ef99252013-07-18 18:04:19 -0700645 private final class PostViewPictureCallback
646 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800647 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800648 public void onPictureTaken(byte[] data, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800649 mPostViewPictureCallbackTime = System.currentTimeMillis();
650 Log.v(TAG, "mShutterToPostViewCallbackTime = "
651 + (mPostViewPictureCallbackTime - mShutterCallbackTime)
652 + "ms");
653 }
654 }
655
Angus Kong9ef99252013-07-18 18:04:19 -0700656 private final class RawPictureCallback
657 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800658 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800659 public void onPictureTaken(byte[] rawData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800660 mRawPictureCallbackTime = System.currentTimeMillis();
661 Log.v(TAG, "mShutterToRawCallbackTime = "
662 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
663 }
664 }
665
Angus Kong9ef99252013-07-18 18:04:19 -0700666 private final class JpegPictureCallback
667 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800668 Location mLocation;
669
670 public JpegPictureCallback(Location loc) {
671 mLocation = loc;
672 }
673
674 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800675 public void onPictureTaken(final byte[] jpegData, CameraProxy camera) {
676 setShutterEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800677 if (mPaused) {
678 return;
679 }
Doris Liu6432cd62013-06-13 17:20:31 -0700680 if (mIsImageCaptureIntent) {
681 stopPreview();
682 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700683 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -0700684 mUI.setSwipingEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800685 }
686
687 mJpegPictureCallbackTime = System.currentTimeMillis();
688 // If postview callback has arrived, the captured image is displayed
689 // in postview callback. If not, the captured image is displayed in
690 // raw picture callback.
691 if (mPostViewPictureCallbackTime != 0) {
692 mShutterToPictureDisplayedTime =
693 mPostViewPictureCallbackTime - mShutterCallbackTime;
694 mPictureDisplayedToJpegCallbackTime =
695 mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
696 } else {
697 mShutterToPictureDisplayedTime =
698 mRawPictureCallbackTime - mShutterCallbackTime;
699 mPictureDisplayedToJpegCallbackTime =
700 mJpegPictureCallbackTime - mRawPictureCallbackTime;
701 }
702 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
703 + mPictureDisplayedToJpegCallbackTime + "ms");
704
Michael Kolb8872c232013-01-29 10:33:22 -0800705 mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
706 if (!mIsImageCaptureIntent) {
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700707 setupPreview();
Michael Kolb8872c232013-01-29 10:33:22 -0800708 }
709
Doris Liu36e56fb2013-09-11 17:38:08 -0700710 ExifInterface exif = Exif.getExif(jpegData);
711 int orientation = Exif.getOrientation(exif);
Ruben Brunkd217ed02013-10-08 23:31:13 -0700712
Ruben Brunkd7488272013-10-10 18:45:53 -0700713 if (!mIsImageCaptureIntent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800714 // Calculate the width and the height of the jpeg.
715 Size s = mParameters.getPictureSize();
Michael Kolb8872c232013-01-29 10:33:22 -0800716 int width, height;
717 if ((mJpegRotation + orientation) % 180 == 0) {
718 width = s.width;
719 height = s.height;
720 } else {
721 width = s.height;
722 height = s.width;
723 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700724 NamedEntity name = mNamedImages.getNextNameEntity();
725 String title = (name == null) ? null : name.title;
726 long date = (name == null) ? -1 : name.date;
Ruben Brunkd7488272013-10-10 18:45:53 -0700727
728 // Handle debug mode outputs
729 if (mDebugUri != null) {
730 // If using a debug uri, save jpeg there.
731 saveToDebugUri(jpegData);
732
733 // Adjust the title of the debug image shown in mediastore.
734 if (title != null) {
735 title = DEBUG_IMAGE_PREFIX + title;
736 }
737 }
738
Michael Kolb8872c232013-01-29 10:33:22 -0800739 if (title == null) {
740 Log.e(TAG, "Unbalanced name/data pair");
741 } else {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800742 if (date == -1)
743 date = mCaptureStartTime;
Angus Kong0d00a892013-03-26 11:40:40 -0700744 if (mHeading >= 0) {
745 // heading direction has been updated by the sensor.
746 ExifTag directionRefTag = exif.buildTag(
747 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
748 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
749 ExifTag directionTag = exif.buildTag(
750 ExifInterface.TAG_GPS_IMG_DIRECTION,
751 new Rational(mHeading, 1));
752 exif.setTag(directionRefTag);
753 exif.setTag(directionTag);
754 }
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800755 getServices().getMediaSaver().addImage(
Angus Kong86d36312013-01-31 18:22:44 -0800756 jpegData, title, date, mLocation, width, height,
Angus Kong0d00a892013-03-26 11:40:40 -0700757 orientation, exif, mOnMediaSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -0800758 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800759 // Animate capture with real jpeg data instead of a preview
760 // frame.
Doris Liu29da2db2013-08-28 14:28:45 -0700761 mUI.animateCapture(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800762 } else {
763 mJpegImageData = jpegData;
764 if (!mQuickCapture) {
Doris Liu36e56fb2013-09-11 17:38:08 -0700765 mUI.showCapturedImageForReview(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800766 } else {
Michael Kolbd6954f32013-03-08 20:43:01 -0800767 onCaptureDone();
Michael Kolb8872c232013-01-29 10:33:22 -0800768 }
769 }
770
771 // Check this in advance of each shot so we don't add to shutter
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800772 // latency. It's true that someone else could write to the SD card
773 // in the mean time and fill it, but that could have happened
774 // between the shutter press and saving the JPEG too.
Michael Kolb8872c232013-01-29 10:33:22 -0800775 mActivity.updateStorageSpaceAndHint();
776
777 long now = System.currentTimeMillis();
778 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
779 Log.v(TAG, "mJpegCallbackFinishTime = "
780 + mJpegCallbackFinishTime + "ms");
781 mJpegPictureCallbackTime = 0;
782 }
783 }
784
Angus Kong9ef99252013-07-18 18:04:19 -0700785 private final class AutoFocusCallback implements CameraAFCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800786 @Override
787 public void onAutoFocus(
Angus Kong9ef99252013-07-18 18:04:19 -0700788 boolean focused, CameraProxy camera) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800789 if (mPaused) {
790 return;
791 }
Michael Kolb8872c232013-01-29 10:33:22 -0800792
793 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
794 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
795 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800796 mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
Michael Kolb8872c232013-01-29 10:33:22 -0800797 }
798 }
799
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700800 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -0800801 private final class AutoFocusMoveCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700802 implements CameraAFMoveCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800803 @Override
804 public void onAutoFocusMoving(
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700805 boolean moving, CameraProxy camera) {
806 mFocusManager.onAutoFocusMoving(moving);
Michael Kolb8872c232013-01-29 10:33:22 -0800807 }
808 }
809
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700810 /**
811 * This class is just a thread-safe queue for name,date holder objects.
812 */
813 public static class NamedImages {
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800814 private final Vector<NamedEntity> mQueue;
Michael Kolb8872c232013-01-29 10:33:22 -0800815
816 public NamedImages() {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700817 mQueue = new Vector<NamedEntity>();
Michael Kolb8872c232013-01-29 10:33:22 -0800818 }
819
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700820 public void nameNewImage(long date) {
Michael Kolb8872c232013-01-29 10:33:22 -0800821 NamedEntity r = new NamedEntity();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700822 r.title = CameraUtil.createJpegName(date);
Michael Kolb8872c232013-01-29 10:33:22 -0800823 r.date = date;
824 mQueue.add(r);
825 }
826
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700827 public NamedEntity getNextNameEntity() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800828 synchronized (mQueue) {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700829 if (!mQueue.isEmpty()) {
830 return mQueue.remove(0);
831 }
Michael Kolb8872c232013-01-29 10:33:22 -0800832 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700833 return null;
Michael Kolb8872c232013-01-29 10:33:22 -0800834 }
835
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700836 public static class NamedEntity {
837 public String title;
838 public long date;
Michael Kolb8872c232013-01-29 10:33:22 -0800839 }
840 }
841
842 private void setCameraState(int state) {
843 mCameraState = state;
844 switch (state) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700845 case PhotoController.PREVIEW_STOPPED:
846 case PhotoController.SNAPSHOT_IN_PROGRESS:
847 case PhotoController.SWITCHING_CAMERA:
Doris Liuf55f3c42013-11-20 00:24:46 -0800848 // TODO: Tell app UI to disable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700849 break;
850 case PhotoController.IDLE:
Doris Liuf55f3c42013-11-20 00:24:46 -0800851 // TODO: Tell app UI to enable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700852 break;
Michael Kolb8872c232013-01-29 10:33:22 -0800853 }
854 }
855
Sascha Haeberling37f36112013-08-06 14:31:52 -0700856 private void animateAfterShutter() {
Michael Kolb8872c232013-01-29 10:33:22 -0800857 // Only animate when in full screen capture mode
858 // i.e. If monkey/a user swipes to the gallery during picture taking,
859 // don't show animation
Doris Liuc2e9abd2013-06-19 14:20:51 -0700860 if (!mIsImageCaptureIntent) {
861 mUI.animateFlash();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700862 }
Michael Kolb8872c232013-01-29 10:33:22 -0800863 }
864
865 @Override
866 public boolean capture() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800867 // If we are already in the middle of taking a snapshot or the image
868 // save request is full then ignore.
Michael Kolb8872c232013-01-29 10:33:22 -0800869 if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800870 || mCameraState == SWITCHING_CAMERA || !mShutterEnabled) {
Michael Kolb8872c232013-01-29 10:33:22 -0800871 return false;
872 }
873 mCaptureStartTime = System.currentTimeMillis();
874 mPostViewPictureCallbackTime = 0;
875 mJpegImageData = null;
876
Angus Kongb50b5cb2013-08-09 14:55:20 -0700877 final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
Michael Kolb8872c232013-01-29 10:33:22 -0800878
879 if (animateBefore) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700880 animateAfterShutter();
Michael Kolb8872c232013-01-29 10:33:22 -0800881 }
882
883 // Set rotation and gps data.
Doris Liu3cf565c2013-02-15 10:55:37 -0800884 int orientation;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800885
Doris Liu3cf565c2013-02-15 10:55:37 -0800886 // We need to be consistent with the framework orientation (i.e. the
887 // orientation of the UI.) when the auto-rotate screen setting is on.
888 if (mActivity.isAutoRotateScreen()) {
889 orientation = (360 - mDisplayRotation) % 360;
890 } else {
891 orientation = mOrientation;
892 }
Angus Kong20fad242013-11-11 18:23:46 -0800893 mJpegRotation = CameraUtil.getJpegRotation(mActivity, mCameraId, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800894 mParameters.setRotation(mJpegRotation);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800895 Location loc = mActivity.getLocationManager().getCurrentLocation();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700896 CameraUtil.setGpsParameters(mParameters, loc);
Michael Kolb8872c232013-01-29 10:33:22 -0800897 mCameraDevice.setParameters(mParameters);
898
Sascha Haeberling88901942013-08-28 17:49:00 -0700899 // We don't want user to press the button again while taking a
900 // multi-second HDR photo.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800901 setShutterEnabled(false);
Angus Kong9ef99252013-07-18 18:04:19 -0700902 mCameraDevice.takePicture(mHandler,
903 new ShutterCallback(!animateBefore),
Angus Kongdcb0ef12013-03-25 23:11:43 -0700904 mRawPictureCallback, mPostViewPictureCallback,
Angus Kong9ef99252013-07-18 18:04:19 -0700905 new JpegPictureCallback(loc));
Michael Kolb8872c232013-01-29 10:33:22 -0800906
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700907 mNamedImages.nameNewImage(mCaptureStartTime);
Michael Kolb8872c232013-01-29 10:33:22 -0800908
909 mFaceDetectionStarted = false;
910 setCameraState(SNAPSHOT_IN_PROGRESS);
Bobby Georgescu301b6462013-04-01 15:33:17 -0700911 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
Seth Raphaelcbd82672013-11-05 10:12:36 -0800912 UsageStatistics.ACTION_CAPTURE_DONE, "Photo", 0,
Seth Raphael44973262013-11-27 14:29:24 -0800913 UsageStatistics.hashFileName(mNamedImages.mQueue.lastElement().title + ".jpg"));
Michael Kolb8872c232013-01-29 10:33:22 -0800914 return true;
915 }
916
917 @Override
918 public void setFocusParameters() {
919 setCameraParameters(UPDATE_PARAM_PREFERENCE);
920 }
921
Michael Kolbd6954f32013-03-08 20:43:01 -0800922 private void updateSceneMode() {
Michael Kolb8872c232013-01-29 10:33:22 -0800923 // If scene mode is set, we cannot set flash mode, white balance, and
924 // focus mode, instead, we read it from driver
925 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
926 overrideCameraSettings(mParameters.getFlashMode(),
927 mParameters.getWhiteBalance(), mParameters.getFocusMode());
928 } else {
929 overrideCameraSettings(null, null, null);
930 }
931 }
932
933 private void overrideCameraSettings(final String flashMode,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800934 final String whiteBalance, final String focusMode) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800935 SettingsManager settingsManager = mActivity.getSettingsManager();
936 settingsManager.set(SettingsManager.SETTING_FLASH_MODE, flashMode);
937 settingsManager.set(SettingsManager.SETTING_WHITE_BALANCE, whiteBalance);
938 settingsManager.set(SettingsManager.SETTING_FOCUS_MODE, focusMode);
Michael Kolb8872c232013-01-29 10:33:22 -0800939 }
940
941 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800942 public void onOrientationChanged(int orientation) {
943 // We keep the last known orientation. So if the user first orient
944 // the camera then point the camera to floor or sky, we still have
945 // the correct orientation.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800946 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
947 return;
948 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700949 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800950
951 // Show the toast after getting the first orientation changed.
Angus Kong13e87c42013-11-25 10:02:47 -0800952 if (mHandler.hasMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST)) {
953 mHandler.removeMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST);
Michael Kolb8872c232013-01-29 10:33:22 -0800954 showTapToFocusToast();
955 }
956 }
957
958 @Override
Angus Kong20fad242013-11-11 18:23:46 -0800959 public void onCameraAvailable(CameraProxy cameraProxy) {
960 if (mPaused) {
961 return;
962 }
963 mCameraDevice = cameraProxy;
964
Erin Dahlgren357b7672013-11-20 17:38:14 -0800965 resetExposureCompensation();
Angus Kong20fad242013-11-11 18:23:46 -0800966 initializeCapabilities();
967
968 // Reset zoom value index.
969 mZoomValue = 0;
970 if (mFocusManager == null) {
971 initializeFocusManager();
972 }
973 mFocusManager.setParameters(mInitialParams);
974
975 mParameters = mCameraDevice.getParameters();
976 setCameraParameters(UPDATE_PARAM_ALL);
977 mCameraPreviewParamsReady = true;
978 startPreview();
979
980 onCameraOpened();
981 }
982
983 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -0800984 public void onCaptureCancelled() {
985 mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
986 mActivity.finish();
Michael Kolb8872c232013-01-29 10:33:22 -0800987 }
988
Michael Kolbd6954f32013-03-08 20:43:01 -0800989 @Override
990 public void onCaptureRetake() {
Michael Kolb8872c232013-01-29 10:33:22 -0800991 if (mPaused)
992 return;
Michael Kolbd6954f32013-03-08 20:43:01 -0800993 mUI.hidePostCaptureAlert();
Michael Kolb8872c232013-01-29 10:33:22 -0800994 setupPreview();
995 }
996
Michael Kolbd6954f32013-03-08 20:43:01 -0800997 @Override
998 public void onCaptureDone() {
Michael Kolb8872c232013-01-29 10:33:22 -0800999 if (mPaused) {
1000 return;
1001 }
1002
1003 byte[] data = mJpegImageData;
1004
1005 if (mCropValue == null) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001006 // First handle the no crop case -- just return the value. If the
Michael Kolb8872c232013-01-29 10:33:22 -08001007 // caller specifies a "save uri" then write the data to its
1008 // stream. Otherwise, pass back a scaled down version of the bitmap
1009 // directly in the extras.
1010 if (mSaveUri != null) {
1011 OutputStream outputStream = null;
1012 try {
1013 outputStream = mContentResolver.openOutputStream(mSaveUri);
1014 outputStream.write(data);
1015 outputStream.close();
1016
1017 mActivity.setResultEx(Activity.RESULT_OK);
1018 mActivity.finish();
1019 } catch (IOException ex) {
1020 // ignore exception
1021 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001022 CameraUtil.closeSilently(outputStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001023 }
1024 } else {
Angus Kong0d00a892013-03-26 11:40:40 -07001025 ExifInterface exif = Exif.getExif(data);
1026 int orientation = Exif.getOrientation(exif);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001027 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
1028 bitmap = CameraUtil.rotate(bitmap, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001029 mActivity.setResultEx(Activity.RESULT_OK,
1030 new Intent("inline-data").putExtra("data", bitmap));
1031 mActivity.finish();
1032 }
1033 } else {
1034 // Save the image to a temp file and invoke the cropper
1035 Uri tempUri = null;
1036 FileOutputStream tempStream = null;
1037 try {
1038 File path = mActivity.getFileStreamPath(sTempCropFilename);
1039 path.delete();
1040 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1041 tempStream.write(data);
1042 tempStream.close();
1043 tempUri = Uri.fromFile(path);
1044 } catch (FileNotFoundException ex) {
1045 mActivity.setResultEx(Activity.RESULT_CANCELED);
1046 mActivity.finish();
1047 return;
1048 } catch (IOException ex) {
1049 mActivity.setResultEx(Activity.RESULT_CANCELED);
1050 mActivity.finish();
1051 return;
1052 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001053 CameraUtil.closeSilently(tempStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001054 }
1055
1056 Bundle newExtras = new Bundle();
1057 if (mCropValue.equals("circle")) {
1058 newExtras.putString("circleCrop", "true");
1059 }
1060 if (mSaveUri != null) {
1061 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1062 } else {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001063 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001064 }
1065 if (mActivity.isSecureCamera()) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001066 newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001067 }
1068
Sascha Haeberling37f36112013-08-06 14:31:52 -07001069 // TODO: Share this constant.
Sascha Haeberling8e963a52013-08-06 11:43:02 -07001070 final String CROP_ACTION = "com.android.camera.action.CROP";
1071 Intent cropIntent = new Intent(CROP_ACTION);
Michael Kolb8872c232013-01-29 10:33:22 -08001072
1073 cropIntent.setData(tempUri);
1074 cropIntent.putExtras(newExtras);
1075
1076 mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1077 }
1078 }
1079
Michael Kolb8872c232013-01-29 10:33:22 -08001080 @Override
1081 public void onShutterButtonFocus(boolean pressed) {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001082 if (mPaused || (mCameraState == SNAPSHOT_IN_PROGRESS)
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001083 || (mCameraState == PREVIEW_STOPPED)) {
1084 return;
1085 }
Michael Kolb8872c232013-01-29 10:33:22 -08001086
1087 // Do not do focus if there is not enough storage.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001088 if (pressed && !canTakePicture()) {
1089 return;
1090 }
Michael Kolb8872c232013-01-29 10:33:22 -08001091
1092 if (pressed) {
Michael Kolb8872c232013-01-29 10:33:22 -08001093 mFocusManager.onShutterDown();
1094 } else {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001095 mFocusManager.onShutterUp();
Michael Kolb8872c232013-01-29 10:33:22 -08001096 }
1097 }
1098
1099 @Override
1100 public void onShutterButtonClick() {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001101 if (mPaused || (mCameraState == SWITCHING_CAMERA)
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001102 || (mCameraState == PREVIEW_STOPPED)) {
1103 return;
1104 }
Michael Kolb8872c232013-01-29 10:33:22 -08001105
1106 // Do not take the picture if there is not enough storage.
Angus Kong2dcc0a92013-09-25 13:00:08 -07001107 if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Michael Kolb8872c232013-01-29 10:33:22 -08001108 Log.i(TAG, "Not enough space or storage not ready. remaining="
Angus Kong2dcc0a92013-09-25 13:00:08 -07001109 + mActivity.getStorageSpaceBytes());
Michael Kolb8872c232013-01-29 10:33:22 -08001110 return;
1111 }
1112 Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1113
Angus Kongb50b5cb2013-08-09 14:55:20 -07001114 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -07001115 mUI.setSwipingEnabled(false);
Doris Liu9cdfe002013-04-16 09:50:56 -07001116 }
Michael Kolb8872c232013-01-29 10:33:22 -08001117 // If the user wants to do a snapshot while the previous one is still
1118 // in progress, remember the fact and do it after we finish the previous
1119 // one and re-start the preview. Snapshot in progress also includes the
1120 // state that autofocus is focusing and a picture will be taken when
1121 // focus callback arrives.
1122 if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1123 && !mIsImageCaptureIntent) {
1124 mSnapshotOnIdle = true;
1125 return;
1126 }
1127
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001128 mSnapshotOnIdle = false;
1129 mFocusManager.doSnap();
Michael Kolb8872c232013-01-29 10:33:22 -08001130 }
1131
Andy Huibersdef975d2013-11-22 09:13:39 -08001132 private void onResumeTasks() {
1133 Log.v(TAG, "Executing onResumeTasks.");
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001134 if (mOpenCameraFail || mCameraDisabled) {
1135 return;
1136 }
Michael Kolb8872c232013-01-29 10:33:22 -08001137
Angus Kong20fad242013-11-11 18:23:46 -08001138 mActivity.getCameraProvider().requestCamera(mCameraId);
1139
Michael Kolb8872c232013-01-29 10:33:22 -08001140 mJpegPictureCallbackTime = 0;
1141 mZoomValue = 0;
Angus Kong20fad242013-11-11 18:23:46 -08001142
1143 mOnResumeTime = SystemClock.uptimeMillis();
1144 checkDisplayRotation();
Michael Kolb8872c232013-01-29 10:33:22 -08001145
1146 // If first time initialization is not finished, put it in the
1147 // message queue.
1148 if (!mFirstTimeInitialized) {
Angus Kong13e87c42013-11-25 10:02:47 -08001149 mHandler.sendEmptyMessage(MSG_FIRST_TIME_INIT);
Michael Kolb8872c232013-01-29 10:33:22 -08001150 } else {
1151 initializeSecondTime();
1152 }
Michael Kolb8872c232013-01-29 10:33:22 -08001153
Bobby Georgescu0a7dd572013-03-12 22:45:17 -07001154 UsageStatistics.onContentViewChanged(
1155 UsageStatistics.COMPONENT_CAMERA, "PhotoModule");
Angus Kong0d00a892013-03-26 11:40:40 -07001156
1157 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1158 if (gsensor != null) {
1159 mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1160 }
1161
1162 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1163 if (msensor != null) {
1164 mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1165 }
Michael Kolb8872c232013-01-29 10:33:22 -08001166 }
1167
Angus Kongc4e66562013-11-22 23:03:21 -08001168 /**
1169 * The focus manager is the first UI related element to get initialized,
1170 * and it requires the RenderOverlay, so initialize it here
1171 */
1172 private void initializeFocusManager() {
1173 // Create FocusManager object. startPreview needs it.
1174 // if mFocusManager not null, reuse it
1175 // otherwise create a new instance
1176 if (mFocusManager != null) {
1177 mFocusManager.removeMessages();
1178 } else {
1179 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
1180 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
1181 String[] defaultFocusModes = mActivity.getResources().getStringArray(
1182 R.array.pref_camera_focusmode_default_array);
Erin Dahlgren357b7672013-11-20 17:38:14 -08001183 mFocusManager = new FocusOverlayManager(mActivity.getSettingsManager(),
1184 defaultFocusModes,
Angus Kongc4e66562013-11-22 23:03:21 -08001185 mInitialParams, this, mMirror,
1186 mActivity.getMainLooper(), mUI);
1187 }
Angus Kong20fad242013-11-11 18:23:46 -08001188 }
1189
1190 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001191 public void resume() {
1192 mPaused = false;
1193 // Add delay on resume from lock screen only, in order to to speed up
1194 // the onResume --> onPause --> onResume cycle from lock screen.
1195 // Don't do always because letting go of thread can cause delay.
1196 String action = mActivity.getIntent().getAction();
1197 if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
1198 || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
1199 Log.v(TAG, "On resume, from lock screen.");
1200 // Note: onPauseAfterSuper() will delete this runnable, so we will
1201 // at most have 1 copy queued up.
1202 mHandler.postDelayed(new Runnable() {
Sameer Padala2c8cc452013-11-05 18:49:12 -08001203 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001204 public void run() {
1205 onResumeTasks();
1206 }
1207 }, ON_RESUME_TASKS_DELAY_MSEC);
1208 } else {
1209 Log.v(TAG, "On resume.");
1210 onResumeTasks();
1211 }
1212 }
1213
1214 @Override
1215 public void pause() {
Michael Kolb8872c232013-01-29 10:33:22 -08001216 mPaused = true;
Angus Kong0d00a892013-03-26 11:40:40 -07001217 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1218 if (gsensor != null) {
1219 mSensorManager.unregisterListener(this, gsensor);
1220 }
1221
1222 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1223 if (msensor != null) {
1224 mSensorManager.unregisterListener(this, msensor);
1225 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001226
Michael Kolb8872c232013-01-29 10:33:22 -08001227 // Reset the focus first. Camera CTS does not guarantee that
1228 // cancelAutoFocus is allowed after preview stops.
1229 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1230 mCameraDevice.cancelAutoFocus();
1231 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001232
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -08001233 // If the camera has not been opened asynchronously yet,
1234 // and startPreview hasn't been called, then this is a no-op.
1235 // (e.g. onResume -> onPause -> onResume).
Michael Kolb8872c232013-01-29 10:33:22 -08001236 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001237
Angus Kongce5480e2013-01-29 17:43:48 -08001238 mNamedImages = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001239
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001240 if (mLocationManager != null) {
1241 mLocationManager.recordLocation(false);
1242 }
Michael Kolb8872c232013-01-29 10:33:22 -08001243
1244 // If we are in an image capture intent and has taken
1245 // a picture, we just clear it in onPause.
1246 mJpegImageData = null;
1247
Angus Kongdcccc512013-08-08 17:06:03 -07001248 // Remove the messages and runnables in the queue.
1249 mHandler.removeCallbacksAndMessages(null);
Michael Kolb8872c232013-01-29 10:33:22 -08001250
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001251 closeCamera();
Angus Kong13e87c42013-11-25 10:02:47 -08001252 mActivity.enableKeepScreenOn(false);
Michael Kolbd6954f32013-03-08 20:43:01 -08001253 mUI.onPause();
1254
Michael Kolb8872c232013-01-29 10:33:22 -08001255 mPendingSwitchCameraId = -1;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001256 if (mFocusManager != null) {
1257 mFocusManager.removeMessages();
Angus Kong86d36312013-01-31 18:22:44 -08001258 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001259 getServices().getMemoryManager().removeListener(this);
Michael Kolb8872c232013-01-29 10:33:22 -08001260 }
1261
Angus Kong20fad242013-11-11 18:23:46 -08001262 @Override
1263 public void destroy() {
1264 // TODO: implement this.
1265 }
1266
1267 @Override
1268 public void onPreviewSizeChanged(int width, int height) {
1269 // TODO: implement this.
1270 }
1271
1272 @Override
Angus Kong2f0e4a32013-12-03 10:02:35 -08001273 public void onLayoutOrientationChanged(boolean isLandscape) {
Michael Kolb8872c232013-01-29 10:33:22 -08001274 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001275 }
1276
1277 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001278 public void updateCameraOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001279 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001280 setDisplayOrientation();
1281 }
1282 }
1283
Michael Kolb8872c232013-01-29 10:33:22 -08001284 private boolean canTakePicture() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001285 return isCameraIdle()
1286 && (mActivity.getStorageSpaceBytes() > Storage.LOW_STORAGE_THRESHOLD_BYTES);
Michael Kolb8872c232013-01-29 10:33:22 -08001287 }
1288
1289 @Override
1290 public void autoFocus() {
1291 mFocusStartTime = System.currentTimeMillis();
Angus Kong9ef99252013-07-18 18:04:19 -07001292 mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001293 setCameraState(FOCUSING);
1294 }
1295
1296 @Override
1297 public void cancelAutoFocus() {
1298 mCameraDevice.cancelAutoFocus();
1299 setCameraState(IDLE);
1300 setCameraParameters(UPDATE_PARAM_PREFERENCE);
1301 }
1302
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001303 // Preview area is touched.
Michael Kolb8872c232013-01-29 10:33:22 -08001304 @Override
1305 public void onSingleTapUp(View view, int x, int y) {
Spike Spraguee9a6f802013-12-16 11:18:01 -08001306 cancelAutoFocus();
1307 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001308 }
1309
1310 @Override
1311 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001312 return mUI.onBackPressed();
Michael Kolb8872c232013-01-29 10:33:22 -08001313 }
1314
1315 @Override
1316 public boolean onKeyDown(int keyCode, KeyEvent event) {
1317 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001318 case KeyEvent.KEYCODE_VOLUME_UP:
1319 case KeyEvent.KEYCODE_VOLUME_DOWN:
1320 case KeyEvent.KEYCODE_FOCUS:
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001321 if (/* TODO: mActivity.isInCameraApp() && */mFirstTimeInitialized) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001322 if (event.getRepeatCount() == 0) {
1323 onShutterButtonFocus(true);
1324 }
1325 return true;
1326 }
1327 return false;
1328 case KeyEvent.KEYCODE_CAMERA:
1329 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1330 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001331 }
1332 return true;
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001333 case KeyEvent.KEYCODE_DPAD_CENTER:
1334 // If we get a dpad center event without any focused view, move
1335 // the focus to the shutter button and press it.
1336 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1337 // Start auto-focus immediately to reduce shutter lag. After
1338 // the shutter button gets the focus, onShutterButtonFocus()
1339 // will be called again but it is fine.
1340 onShutterButtonFocus(true);
1341 mUI.pressShutterButton();
1342 }
1343 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001344 }
1345 return false;
1346 }
1347
1348 @Override
1349 public boolean onKeyUp(int keyCode, KeyEvent event) {
1350 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001351 case KeyEvent.KEYCODE_VOLUME_UP:
1352 case KeyEvent.KEYCODE_VOLUME_DOWN:
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001353 if (/* mActivity.isInCameraApp() && */mFirstTimeInitialized) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001354 onShutterButtonClick();
1355 return true;
1356 }
1357 return false;
1358 case KeyEvent.KEYCODE_FOCUS:
1359 if (mFirstTimeInitialized) {
1360 onShutterButtonFocus(false);
1361 }
Michael Kolb8872c232013-01-29 10:33:22 -08001362 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001363 }
1364 return false;
1365 }
1366
Michael Kolb8872c232013-01-29 10:33:22 -08001367 private void closeCamera() {
1368 if (mCameraDevice != null) {
1369 mCameraDevice.setZoomChangeListener(null);
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001370 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001371 mCameraDevice.setErrorCallback(null);
Ruben Brunk59147832013-11-05 15:53:28 -08001372
Michael Kolb8872c232013-01-29 10:33:22 -08001373 mFaceDetectionStarted = false;
Angus Kong20fad242013-11-11 18:23:46 -08001374 mActivity.getCameraProvider().releaseCamera(mCameraDevice.getCameraId());
Michael Kolb8872c232013-01-29 10:33:22 -08001375 mCameraDevice = null;
1376 setCameraState(PREVIEW_STOPPED);
1377 mFocusManager.onCameraReleased();
1378 }
1379 }
1380
1381 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001382 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1383 mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001384 mCameraDisplayOrientation = mDisplayOrientation;
Michael Kolbd6954f32013-03-08 20:43:01 -08001385 mUI.setDisplayOrientation(mDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001386 if (mFocusManager != null) {
1387 mFocusManager.setDisplayOrientation(mDisplayOrientation);
1388 }
Doris Liu6432cd62013-06-13 17:20:31 -07001389 // Change the camera display orientation
1390 if (mCameraDevice != null) {
1391 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1392 }
Michael Kolb8872c232013-01-29 10:33:22 -08001393 }
1394
Sascha Haeberlingddef7792013-08-13 14:41:10 -07001395 /** Only called by UI thread. */
Michael Kolb8872c232013-01-29 10:33:22 -08001396 private void setupPreview() {
1397 mFocusManager.resetTouchFocus();
1398 startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001399 }
1400
Angus Kong20fad242013-11-11 18:23:46 -08001401 /**
1402 * Returns whether we can/should start the preview or not.
1403 */
1404 private boolean checkPreviewPreconditions() {
1405 if (mPaused) {
1406 return false;
Angus Kongdcccc512013-08-08 17:06:03 -07001407 }
Michael Kolb8872c232013-01-29 10:33:22 -08001408
Angus Kong20fad242013-11-11 18:23:46 -08001409 if (mCameraDevice == null) {
1410 Log.w(TAG, "startPreview: camera device not ready yet.");
1411 return false;
1412 }
1413
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001414 SurfaceTexture st = mUI.getSurfaceTexture();
1415 if (st == null) {
1416 Log.w(TAG, "startPreview: surfaceTexture is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001417 return false;
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001418 }
1419
1420 if (!mCameraPreviewParamsReady) {
1421 Log.w(TAG, "startPreview: parameters for preview is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001422 return false;
1423 }
1424 return true;
1425 }
1426
1427 /**
1428 * The start/stop preview should only run on the UI thread.
1429 */
1430 private void startPreview() {
1431 if (!checkPreviewPreconditions()) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001432 return;
1433 }
Angus Kong20fad242013-11-11 18:23:46 -08001434
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001435 mCameraDevice.setErrorCallback(mErrorCallback);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001436 // ICS camera frameworks has a bug. Face detection state is not cleared
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001437 // after taking a picture. Stop the preview to work around it. The bug
1438 // was fixed in JB.
1439 if (mCameraState != PREVIEW_STOPPED) {
1440 stopPreview();
1441 }
1442
1443 setDisplayOrientation();
1444
1445 if (!mSnapshotOnIdle) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001446 // If the focus mode is continuous autofocus, call cancelAutoFocus
1447 // to resume it because it may have been paused by autoFocus call.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001448 String focusMode = mFocusManager.getFocusMode();
1449 if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(focusMode)) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001450 mCameraDevice.cancelAutoFocus();
Michael Kolb8872c232013-01-29 10:33:22 -08001451 }
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001452 mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1453 }
1454 setCameraParameters(UPDATE_PARAM_ALL);
1455 // Let UI set its expected aspect ratio
Angus Kong20fad242013-11-11 18:23:46 -08001456 mCameraDevice.setPreviewTexture(mUI.getSurfaceTexture());
Michael Kolb8872c232013-01-29 10:33:22 -08001457
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001458 Log.v(TAG, "startPreview");
1459 mCameraDevice.startPreview();
Angus Kong20fad242013-11-11 18:23:46 -08001460
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001461 mFocusManager.onPreviewStarted();
1462 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001463
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001464 if (mSnapshotOnIdle) {
1465 mHandler.post(mDoSnapRunnable);
Michael Kolb8872c232013-01-29 10:33:22 -08001466 }
1467 }
1468
Michael Kolbd6954f32013-03-08 20:43:01 -08001469 @Override
1470 public void stopPreview() {
Michael Kolb8872c232013-01-29 10:33:22 -08001471 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1472 Log.v(TAG, "stopPreview");
1473 mCameraDevice.stopPreview();
1474 mFaceDetectionStarted = false;
1475 }
1476 setCameraState(PREVIEW_STOPPED);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001477 if (mFocusManager != null) {
1478 mFocusManager.onPreviewStopped();
1479 }
Sameer Padala2c8cc452013-11-05 18:49:12 -08001480 stopSmartCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001481 }
1482
Michael Kolb8872c232013-01-29 10:33:22 -08001483 private void updateCameraParametersInitialize() {
1484 // Reset preview frame rate to the maximum because it may be lowered by
1485 // video camera application.
ztenghui16a35202013-09-23 11:35:36 -07001486 int[] fpsRange = CameraUtil.getPhotoPreviewFpsRange(mParameters);
1487 if (fpsRange != null && fpsRange.length > 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001488 mParameters.setPreviewFpsRange(
1489 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1490 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
Michael Kolb8872c232013-01-29 10:33:22 -08001491 }
1492
Angus Kongb50b5cb2013-08-09 14:55:20 -07001493 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);
Michael Kolb8872c232013-01-29 10:33:22 -08001494
1495 // Disable video stabilization. Convenience methods not available in API
1496 // level <= 14
1497 String vstabSupported = mParameters.get("video-stabilization-supported");
1498 if ("true".equals(vstabSupported)) {
1499 mParameters.set("video-stabilization", "false");
1500 }
1501 }
1502
1503 private void updateCameraParametersZoom() {
1504 // Set zoom.
1505 if (mParameters.isZoomSupported()) {
1506 mParameters.setZoom(mZoomValue);
1507 }
1508 }
1509
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001510 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001511 private void setAutoExposureLockIfSupported() {
1512 if (mAeLockSupported) {
1513 mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1514 }
1515 }
1516
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001517 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001518 private void setAutoWhiteBalanceLockIfSupported() {
1519 if (mAwbLockSupported) {
1520 mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1521 }
1522 }
1523
Michael Kolb8872c232013-01-29 10:33:22 -08001524 private void setFocusAreasIfSupported() {
1525 if (mFocusAreaSupported) {
1526 mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1527 }
1528 }
1529
Michael Kolb8872c232013-01-29 10:33:22 -08001530 private void setMeteringAreasIfSupported() {
1531 if (mMeteringAreaSupported) {
Michael Kolb8872c232013-01-29 10:33:22 -08001532 mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1533 }
1534 }
1535
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001536 private void updateCameraParametersPreference() {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001537 SettingsManager settingsManager = mActivity.getSettingsManager();
1538
Michael Kolb8872c232013-01-29 10:33:22 -08001539 setAutoExposureLockIfSupported();
1540 setAutoWhiteBalanceLockIfSupported();
1541 setFocusAreasIfSupported();
1542 setMeteringAreasIfSupported();
1543
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001544 // Initialize focus mode.
Michael Kolbd3253f22013-07-12 11:36:47 -07001545 mFocusManager.overrideFocusMode(null);
1546 mParameters.setFocusMode(mFocusManager.getFocusMode());
1547
Michael Kolb8872c232013-01-29 10:33:22 -08001548 // Set picture size.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001549 String pictureSize = settingsManager.get(SettingsManager.SETTING_PICTURE_SIZE);
Michael Kolb8872c232013-01-29 10:33:22 -08001550 if (pictureSize == null) {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001551 //TODO: deprecate CameraSettings.
1552 CameraSettings.initialCameraPictureSize(
1553 mActivity, mParameters, settingsManager);
Michael Kolb8872c232013-01-29 10:33:22 -08001554 } else {
1555 List<Size> supported = mParameters.getSupportedPictureSizes();
1556 CameraSettings.setCameraPictureSize(
1557 pictureSize, supported, mParameters);
1558 }
1559 Size size = mParameters.getPictureSize();
1560
1561 // Set a preview size that is closest to the viewfinder height and has
1562 // the right aspect ratio.
1563 List<Size> sizes = mParameters.getSupportedPreviewSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001564 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
Michael Kolb8872c232013-01-29 10:33:22 -08001565 (double) size.width / size.height);
1566 Size original = mParameters.getPreviewSize();
1567 if (!original.equals(optimalSize)) {
1568 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
Doris Liu6432cd62013-06-13 17:20:31 -07001569
Michael Kolb8872c232013-01-29 10:33:22 -08001570 // Zoom related settings will be changed for different preview
1571 // sizes, so set and read the parameters to get latest values
Michael Kolb4a4d4ef2013-05-30 08:35:26 -07001572 if (mHandler.getLooper() == Looper.myLooper()) {
1573 // On UI thread only, not when camera starts up
1574 setupPreview();
1575 } else {
1576 mCameraDevice.setParameters(mParameters);
1577 }
Michael Kolb8872c232013-01-29 10:33:22 -08001578 mParameters = mCameraDevice.getParameters();
1579 }
Doris Liu95405742013-11-05 15:25:26 -08001580
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001581 if (optimalSize.width != 0 && optimalSize.height != 0) {
Doris Liu95405742013-11-05 15:25:26 -08001582 mUI.updatePreviewAspectRatio((float) optimalSize.width
1583 / (float) optimalSize.height);
1584 }
Michael Kolb8872c232013-01-29 10:33:22 -08001585 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
1586
Michael Kolb8872c232013-01-29 10:33:22 -08001587 // Set JPEG quality.
1588 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1589 CameraProfile.QUALITY_HIGH);
1590 mParameters.setJpegQuality(jpegQuality);
1591
1592 // For the following settings, we need to check if the settings are
1593 // still supported by latest driver, if not, ignore the settings.
1594
1595 // Set exposure compensation
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001596 int value = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_EXPOSURE));
Michael Kolb8872c232013-01-29 10:33:22 -08001597 int max = mParameters.getMaxExposureCompensation();
1598 int min = mParameters.getMinExposureCompensation();
1599 if (value >= min && value <= max) {
1600 mParameters.setExposureCompensation(value);
1601 } else {
1602 Log.w(TAG, "invalid exposure range: " + value);
1603 }
1604
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001605 mSceneMode = settingsManager.get(SettingsManager.SETTING_SCENE_MODE);
1606 updateParametersSceneMode();
1607
1608 if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
1609 updateAutoFocusMoveCallback();
1610 }
1611 }
1612
1613 public void updateParametersSceneMode() {
1614 SettingsManager settingsManager = mActivity.getSettingsManager();
1615
1616 if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
1617 if (!mParameters.getSceneMode().equals(mSceneMode)) {
1618 mParameters.setSceneMode(mSceneMode);
1619
1620 // Setting scene mode will change the settings of flash mode,
1621 // white balance, and focus mode. Here we read back the
1622 // parameters, so we can know those settings.
1623 mCameraDevice.setParameters(mParameters);
1624 mParameters = mCameraDevice.getParameters();
1625 }
1626 } else {
1627 mSceneMode = mParameters.getSceneMode();
1628 if (mSceneMode == null) {
1629 mSceneMode = Parameters.SCENE_MODE_AUTO;
1630 }
1631 }
1632
Michael Kolb8872c232013-01-29 10:33:22 -08001633 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1634 // Set flash mode.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001635 String flashMode = settingsManager.get(SettingsManager.SETTING_FLASH_MODE);
Michael Kolb8872c232013-01-29 10:33:22 -08001636 List<String> supportedFlash = mParameters.getSupportedFlashModes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001637 if (CameraUtil.isSupported(flashMode, supportedFlash)) {
Michael Kolb8872c232013-01-29 10:33:22 -08001638 mParameters.setFlashMode(flashMode);
1639 } else {
1640 flashMode = mParameters.getFlashMode();
1641 if (flashMode == null) {
1642 flashMode = mActivity.getString(
1643 R.string.pref_camera_flashmode_no_flash);
1644 }
1645 }
1646
1647 // Set white balance parameter.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001648 String whiteBalance = settingsManager.get(SettingsManager.SETTING_WHITE_BALANCE);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001649 if (CameraUtil.isSupported(whiteBalance,
Michael Kolb8872c232013-01-29 10:33:22 -08001650 mParameters.getSupportedWhiteBalance())) {
1651 mParameters.setWhiteBalance(whiteBalance);
1652 } else {
1653 whiteBalance = mParameters.getWhiteBalance();
1654 if (whiteBalance == null) {
1655 whiteBalance = Parameters.WHITE_BALANCE_AUTO;
1656 }
1657 }
1658
1659 // Set focus mode.
1660 mFocusManager.overrideFocusMode(null);
1661 mParameters.setFocusMode(mFocusManager.getFocusMode());
1662 } else {
1663 mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1664 }
Michael Kolb8872c232013-01-29 10:33:22 -08001665 }
1666
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001667 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001668 private void updateAutoFocusMoveCallback() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001669 if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Angus Kong9ef99252013-07-18 18:04:19 -07001670 mCameraDevice.setAutoFocusMoveCallback(mHandler,
Angus Kong4f795b82013-09-16 14:25:35 -07001671 (CameraAFMoveCallback) mAutoFocusMoveCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001672 } else {
Angus Kong9ef99252013-07-18 18:04:19 -07001673 mCameraDevice.setAutoFocusMoveCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001674 }
1675 }
1676
1677 // We separate the parameters into several subsets, so we can update only
1678 // the subsets actually need updating. The PREFERENCE set needs extra
1679 // locking because the preference can be changed from GLThread as well.
1680 private void setCameraParameters(int updateSet) {
1681 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1682 updateCameraParametersInitialize();
1683 }
1684
1685 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1686 updateCameraParametersZoom();
1687 }
1688
1689 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001690 updateCameraParametersPreference();
Michael Kolb8872c232013-01-29 10:33:22 -08001691 }
1692
1693 mCameraDevice.setParameters(mParameters);
1694 }
1695
1696 // If the Camera is idle, update the parameters immediately, otherwise
1697 // accumulate them in mUpdateSet and update later.
1698 private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1699 mUpdateSet |= additionalUpdateSet;
1700 if (mCameraDevice == null) {
1701 // We will update all the parameters when we open the device, so
1702 // we don't need to do anything now.
1703 mUpdateSet = 0;
1704 return;
1705 } else if (isCameraIdle()) {
1706 setCameraParameters(mUpdateSet);
Michael Kolbd6954f32013-03-08 20:43:01 -08001707 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001708 mUpdateSet = 0;
1709 } else {
Angus Kong13e87c42013-11-25 10:02:47 -08001710 if (!mHandler.hasMessages(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1711 mHandler.sendEmptyMessageDelayed(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
Michael Kolb8872c232013-01-29 10:33:22 -08001712 }
1713 }
1714 }
1715
ztenghui7b265a62013-09-09 14:58:44 -07001716 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001717 public boolean isCameraIdle() {
Michael Kolb8872c232013-01-29 10:33:22 -08001718 return (mCameraState == IDLE) ||
1719 (mCameraState == PREVIEW_STOPPED) ||
1720 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
1721 && (mCameraState != SWITCHING_CAMERA));
1722 }
1723
ztenghui7b265a62013-09-09 14:58:44 -07001724 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001725 public boolean isImageCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001726 String action = mActivity.getIntent().getAction();
1727 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
Angus Kong6a8e8a12013-07-19 14:55:07 -07001728 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
Michael Kolb8872c232013-01-29 10:33:22 -08001729 }
1730
1731 private void setupCaptureParams() {
1732 Bundle myExtras = mActivity.getIntent().getExtras();
1733 if (myExtras != null) {
1734 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1735 mCropValue = myExtras.getString("crop");
1736 }
1737 }
1738
Michael Kolb8872c232013-01-29 10:33:22 -08001739 public void onSharedPreferenceChanged() {
1740 // ignore the events after "onPause()"
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001741 if (mPaused) {
1742 return;
1743 }
Michael Kolb8872c232013-01-29 10:33:22 -08001744
Erin Dahlgren357b7672013-11-20 17:38:14 -08001745 SettingsController settingsController = mActivity.getSettingsController();
1746 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001747
1748 setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
Michael Kolb8872c232013-01-29 10:33:22 -08001749 }
1750
Michael Kolb8872c232013-01-29 10:33:22 -08001751 private void showTapToFocusToast() {
1752 // TODO: Use a toast?
1753 new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
1754 // Clear the preference.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001755 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001756 settingsManager.setBoolean(
1757 SettingsManager.SETTING_CAMERA_FIRST_USE_HINT_SHOWN, false);
Michael Kolb8872c232013-01-29 10:33:22 -08001758 }
1759
1760 private void initializeCapabilities() {
1761 mInitialParams = mCameraDevice.getParameters();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001762 mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
1763 mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
1764 mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
1765 mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
Angus Kongdcccc512013-08-08 17:06:03 -07001766 mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001767 CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
Michael Kolb8872c232013-01-29 10:33:22 -08001768 }
1769
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001770 private void setShutterEnabled(boolean enabled) {
1771 mShutterEnabled = enabled;
1772 mUI.enableShutter(enabled);
1773 }
1774
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001775 // TODO: Remove this
Michael Kolb8872c232013-01-29 10:33:22 -08001776 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001777 public int onZoomChanged(int index) {
1778 // Not useful to change zoom value when the activity is paused.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001779 if (mPaused) {
1780 return index;
1781 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001782 mZoomValue = index;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001783 if (mParameters == null || mCameraDevice == null) {
1784 return index;
1785 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001786 // Set zoom parameters asynchronously
1787 mParameters.setZoom(mZoomValue);
Angus Kong36ed8672013-04-15 12:11:15 -07001788 mCameraDevice.setParameters(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -08001789 Parameters p = mCameraDevice.getParameters();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001790 if (p != null) {
1791 return p.getZoom();
1792 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001793 return index;
Angus Kongce5480e2013-01-29 17:43:48 -08001794 }
1795
1796 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001797 public int getCameraState() {
1798 return mCameraState;
1799 }
1800
1801 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001802 public void onMemoryStateChanged(int state) {
1803 setShutterEnabled(state == MemoryManager.STATE_OK);
Angus Kongce5480e2013-01-29 17:43:48 -08001804 }
Angus Kong86d36312013-01-31 18:22:44 -08001805
1806 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001807 public void onLowMemory() {
1808 // Not much we can do in the photo module.
Angus Kong86d36312013-01-31 18:22:44 -08001809 }
Angus Kong0d00a892013-03-26 11:40:40 -07001810
1811 @Override
1812 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1813 }
1814
1815 @Override
1816 public void onSensorChanged(SensorEvent event) {
1817 int type = event.sensor.getType();
1818 float[] data;
1819 if (type == Sensor.TYPE_ACCELEROMETER) {
1820 data = mGData;
1821 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
1822 data = mMData;
1823 } else {
1824 // we should not be here.
1825 return;
1826 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001827 for (int i = 0; i < 3; i++) {
Angus Kong0d00a892013-03-26 11:40:40 -07001828 data[i] = event.values[i];
1829 }
1830 float[] orientation = new float[3];
1831 SensorManager.getRotationMatrix(mR, null, mGData, mMData);
1832 SensorManager.getOrientation(mR, orientation);
1833 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
1834 if (mHeading < 0) {
1835 mHeading += 360;
1836 }
Angus Kong0d00a892013-03-26 11:40:40 -07001837 }
Doris Liu6432cd62013-06-13 17:20:31 -07001838
Ruben Brunkd217ed02013-10-08 23:31:13 -07001839 // For debugging only.
1840 public void setDebugUri(Uri uri) {
1841 mDebugUri = uri;
1842 }
1843
1844 // For debugging only.
1845 private void saveToDebugUri(byte[] data) {
1846 if (mDebugUri != null) {
1847 OutputStream outputStream = null;
1848 try {
1849 outputStream = mContentResolver.openOutputStream(mDebugUri);
1850 outputStream.write(data);
1851 outputStream.close();
1852 } catch (IOException e) {
1853 Log.e(TAG, "Exception while writing debug jpeg file", e);
1854 } finally {
1855 CameraUtil.closeSilently(outputStream);
1856 }
1857 }
1858 }
Michael Kolb8872c232013-01-29 10:33:22 -08001859}