blob: 9042525fbc24875bb13dfe83f361767a82d26393 [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;
Kevin Gabayanffbc43c2013-12-09 11:41:50 -080058import com.android.camera.app.LocationManager;
Angus Kongfd4fc0e2013-11-07 15:38:09 -080059import com.android.camera.app.MediaSaver;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080060import com.android.camera.app.MemoryManager;
61import com.android.camera.app.MemoryManager.MemoryListener;
ztenghuia16e7b52013-08-23 11:47:56 -070062import com.android.camera.exif.ExifInterface;
63import com.android.camera.exif.ExifTag;
64import com.android.camera.exif.Rational;
Angus Kong20fad242013-11-11 18:23:46 -080065import com.android.camera.module.ModuleController;
Erin Dahlgren357b7672013-11-20 17:38:14 -080066import com.android.camera.settings.SettingsManager;
Doris Liu1c94b7d2013-11-09 19:13:44 -080067import com.android.camera.ui.ModeListView;
Michael Kolb8872c232013-01-29 10:33:22 -080068import com.android.camera.ui.RotateTextToast;
Angus Kongdcccc512013-08-08 17:06:03 -070069import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -070070import com.android.camera.util.CameraUtil;
Ruben Brunk4601f5d2013-09-24 18:35:22 -070071import com.android.camera.util.GcamHelper;
Sameer Padala2c8cc452013-11-05 18:49:12 -080072import com.android.camera.util.SmartCameraHelper;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070073import com.android.camera.util.UsageStatistics;
74import com.android.camera2.R;
Michael Kolb8872c232013-01-29 10:33:22 -080075
Angus Kongdcccc512013-08-08 17:06:03 -070076import java.io.File;
77import java.io.FileNotFoundException;
78import java.io.FileOutputStream;
79import java.io.IOException;
80import java.io.OutputStream;
Angus Kongdcccc512013-08-08 17:06:03 -070081import java.util.List;
Ruben Brunka9d66bd2013-09-06 11:56:32 -070082import java.util.Vector;
Angus Kongdcccc512013-08-08 17:06:03 -070083
Michael Kolb8872c232013-01-29 10:33:22 -080084public class PhotoModule
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080085 extends CameraModule
86 implements PhotoController,
87 ModuleController,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080088 MemoryListener,
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080089 FocusOverlayManager.Listener,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080090 ShutterButton.OnShutterButtonListener,
Erin Dahlgren7f0151d2014-01-02 16:08:12 -080091 SensorEventListener,
92 SettingsManager.OnSettingChangedListener {
Michael Kolb8872c232013-01-29 10:33:22 -080093
Sascha Haeberling58501152014-01-06 11:02:35 -080094 private static final String TAG = "PhotoModule";
Michael Kolb8872c232013-01-29 10:33:22 -080095
96 // We number the request code from 1000 to avoid collision with Gallery.
97 private static final int REQUEST_CROP = 1000;
98
Angus Kong13e87c42013-11-25 10:02:47 -080099 // Messages defined for the UI thread handler.
Angus Kong1587b042014-01-02 18:09:27 -0800100 private static final int MSG_FIRST_TIME_INIT = 1;
101 private static final int MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE = 2;
102 private static final int MSG_SHOW_TAP_TO_FOCUS_TOAST = 3;
103 private static final int MSG_SWITCH_TO_GCAM_MODULE = 4;
Michael Kolb8872c232013-01-29 10:33:22 -0800104
105 // The subset of parameters we need to update in setCameraParameters().
106 private static final int UPDATE_PARAM_INITIALIZE = 1;
107 private static final int UPDATE_PARAM_ZOOM = 2;
108 private static final int UPDATE_PARAM_PREFERENCE = 4;
109 private static final int UPDATE_PARAM_ALL = -1;
110
Andy Huibersdef975d2013-11-22 09:13:39 -0800111 // This is the delay before we execute onResume tasks when coming
112 // from the lock screen, to allow time for onPause to execute.
113 private static final int ON_RESUME_TASKS_DELAY_MSEC = 20;
Michael Kolb8872c232013-01-29 10:33:22 -0800114
Ruben Brunkd7488272013-10-10 18:45:53 -0700115 private static final String DEBUG_IMAGE_PREFIX = "DEBUG_";
116
Michael Kolb8872c232013-01-29 10:33:22 -0800117 // copied from Camera hierarchy
118 private CameraActivity mActivity;
Michael Kolb8872c232013-01-29 10:33:22 -0800119 private CameraProxy mCameraDevice;
120 private int mCameraId;
121 private Parameters mParameters;
122 private boolean mPaused;
Michael Kolbd6954f32013-03-08 20:43:01 -0800123
124 private PhotoUI mUI;
Michael Kolb8872c232013-01-29 10:33:22 -0800125
Michael Kolb8872c232013-01-29 10:33:22 -0800126 // The activity is going to switch to the specified camera id. This is
127 // needed because texture copy is done in GL thread. -1 means camera is not
128 // switching.
129 protected int mPendingSwitchCameraId = -1;
Michael Kolb8872c232013-01-29 10:33:22 -0800130
131 // When setCameraParametersWhenIdle() is called, we accumulate the subsets
132 // needed to be updated in mUpdateSet.
133 private int mUpdateSet;
134
135 private static final int SCREEN_DELAY = 2 * 60 * 1000;
136
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800137 private int mZoomValue; // The current zoom value.
Michael Kolb8872c232013-01-29 10:33:22 -0800138
139 private Parameters mInitialParams;
140 private boolean mFocusAreaSupported;
141 private boolean mMeteringAreaSupported;
142 private boolean mAeLockSupported;
143 private boolean mAwbLockSupported;
Angus Kongdcccc512013-08-08 17:06:03 -0700144 private boolean mContinuousFocusSupported;
Michael Kolb8872c232013-01-29 10:33:22 -0800145
146 // The degrees of the device rotated clockwise from its natural orientation.
147 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
Michael Kolb8872c232013-01-29 10:33:22 -0800148
149 private static final String sTempCropFilename = "crop-temp";
150
Michael Kolb8872c232013-01-29 10:33:22 -0800151 private boolean mFaceDetectionStarted = false;
152
Michael Kolb8872c232013-01-29 10:33:22 -0800153 // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
154 private String mCropValue;
155 private Uri mSaveUri;
156
Ruben Brunkd217ed02013-10-08 23:31:13 -0700157 private Uri mDebugUri;
158
Angus Kongce5480e2013-01-29 17:43:48 -0800159 // We use a queue to generated names of the images to be used later
160 // when the image is ready to be saved.
Michael Kolb8872c232013-01-29 10:33:22 -0800161 private NamedImages mNamedImages;
162
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800163 private final Runnable mDoSnapRunnable = new Runnable() {
Michael Kolb8872c232013-01-29 10:33:22 -0800164 @Override
165 public void run() {
166 onShutterButtonClick();
167 }
168 };
169
Michael Kolb8872c232013-01-29 10:33:22 -0800170 /**
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800171 * An unpublished intent flag requesting to return as soon as capturing is
172 * completed. TODO: consider publishing by moving into MediaStore.
Michael Kolb8872c232013-01-29 10:33:22 -0800173 */
174 private static final String EXTRA_QUICK_CAPTURE =
175 "android.intent.extra.quickCapture";
176
177 // The display rotation in degrees. This is only valid when mCameraState is
178 // not PREVIEW_STOPPED.
179 private int mDisplayRotation;
180 // The value for android.hardware.Camera.setDisplayOrientation.
181 private int mCameraDisplayOrientation;
182 // The value for UI components like indicators.
183 private int mDisplayOrientation;
184 // The value for android.hardware.Camera.Parameters.setRotation.
185 private int mJpegRotation;
Doris Liu29da2db2013-08-28 14:28:45 -0700186 // Indicates whether we are using front camera
187 private boolean mMirror;
Michael Kolb8872c232013-01-29 10:33:22 -0800188 private boolean mFirstTimeInitialized;
189 private boolean mIsImageCaptureIntent;
190
Michael Kolb8872c232013-01-29 10:33:22 -0800191 private int mCameraState = PREVIEW_STOPPED;
192 private boolean mSnapshotOnIdle = false;
193
194 private ContentResolver mContentResolver;
195
196 private LocationManager mLocationManager;
Doris Liu2b906b82013-12-10 16:34:08 -0800197 private AppController mAppController;
Michael Kolb8872c232013-01-29 10:33:22 -0800198
Michael Kolb8872c232013-01-29 10:33:22 -0800199 private final PostViewPictureCallback mPostViewPictureCallback =
200 new PostViewPictureCallback();
201 private final RawPictureCallback mRawPictureCallback =
202 new RawPictureCallback();
203 private final AutoFocusCallback mAutoFocusCallback =
204 new AutoFocusCallback();
205 private final Object mAutoFocusMoveCallback =
206 ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700207 ? new AutoFocusMoveCallback()
208 : null;
Michael Kolb8872c232013-01-29 10:33:22 -0800209
210 private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
211
212 private long mFocusStartTime;
213 private long mShutterCallbackTime;
214 private long mPostViewPictureCallbackTime;
215 private long mRawPictureCallbackTime;
216 private long mJpegPictureCallbackTime;
217 private long mOnResumeTime;
218 private byte[] mJpegImageData;
219
220 // These latency time are for the CameraLatency test.
221 public long mAutoFocusTime;
222 public long mShutterLag;
223 public long mShutterToPictureDisplayedTime;
224 public long mPictureDisplayedToJpegCallbackTime;
225 public long mJpegCallbackFinishTime;
226 public long mCaptureStartTime;
227
228 // This handles everything about focus.
229 private FocusOverlayManager mFocusManager;
230
Michael Kolb8872c232013-01-29 10:33:22 -0800231 private String mSceneMode;
Michael Kolb8872c232013-01-29 10:33:22 -0800232
233 private final Handler mHandler = new MainHandler();
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800234
Michael Kolb8872c232013-01-29 10:33:22 -0800235 private boolean mQuickCapture;
Angus Kong0d00a892013-03-26 11:40:40 -0700236 private SensorManager mSensorManager;
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800237 private final float[] mGData = new float[3];
238 private final float[] mMData = new float[3];
239 private final float[] mR = new float[16];
Angus Kong0d00a892013-03-26 11:40:40 -0700240 private int mHeading = -1;
241
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800242 /** Whether shutter is enabled. */
Spike Sprague215f6b02013-12-12 11:53:49 -0800243 private boolean mShutterEnabled = true;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800244
245 /** True if all the parameters needed to start preview is ready. */
Angus Kongdcccc512013-08-08 17:06:03 -0700246 private boolean mCameraPreviewParamsReady = false;
Doris Liu6432cd62013-06-13 17:20:31 -0700247
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800248 private final MediaSaver.OnMediaSavedListener mOnMediaSavedListener =
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800249 new MediaSaver.OnMediaSavedListener() {
Angus Kongce5480e2013-01-29 17:43:48 -0800250 @Override
251 public void onMediaSaved(Uri uri) {
252 if (uri != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700253 mActivity.notifyNewMedia(uri);
Angus Kongce5480e2013-01-29 17:43:48 -0800254 }
255 }
256 };
Michael Kolb8872c232013-01-29 10:33:22 -0800257
Angus Kongdcccc512013-08-08 17:06:03 -0700258 private void checkDisplayRotation() {
259 // Set the display orientation if display rotation has changed.
260 // Sometimes this happens when the device is held upside
261 // down and camera app is opened. Rotation animation will
262 // take some time and the rotation value we have got may be
263 // wrong. Framework does not have a callback for this now.
264 if (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) {
265 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -0800266 }
Angus Kongdcccc512013-08-08 17:06:03 -0700267 if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
268 mHandler.postDelayed(new Runnable() {
269 @Override
270 public void run() {
271 checkDisplayRotation();
272 }
273 }, 100);
Michael Kolb8872c232013-01-29 10:33:22 -0800274 }
275 }
276
277 /**
278 * This Handler is used to post message back onto the main thread of the
279 * application
280 */
281 private class MainHandler extends Handler {
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800282 public MainHandler() {
283 super(Looper.getMainLooper());
284 }
285
Michael Kolb8872c232013-01-29 10:33:22 -0800286 @Override
287 public void handleMessage(Message msg) {
288 switch (msg.what) {
Angus Kong13e87c42013-11-25 10:02:47 -0800289 case MSG_FIRST_TIME_INIT: {
Michael Kolb8872c232013-01-29 10:33:22 -0800290 initializeFirstTime();
291 break;
292 }
293
Angus Kong13e87c42013-11-25 10:02:47 -0800294 case MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE: {
Michael Kolb8872c232013-01-29 10:33:22 -0800295 setCameraParametersWhenIdle(0);
296 break;
297 }
298
Angus Kong13e87c42013-11-25 10:02:47 -0800299 case MSG_SHOW_TAP_TO_FOCUS_TOAST: {
Michael Kolb8872c232013-01-29 10:33:22 -0800300 showTapToFocusToast();
301 break;
302 }
303
Angus Kong13e87c42013-11-25 10:02:47 -0800304 case MSG_SWITCH_TO_GCAM_MODULE: {
Erin Dahlgrend7b8cb52013-11-14 17:25:37 -0800305 mActivity.onModeSelected(ModeListView.MODE_GCAM);
ztenghui367c7c82013-10-16 14:43:26 -0700306 }
Michael Kolb8872c232013-01-29 10:33:22 -0800307 }
308 }
309 }
310
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800311 /**
312 * Constructs a new photo module.
313 */
Angus Kongc4e66562013-11-22 23:03:21 -0800314 public PhotoModule(AppController app) {
315 super(app);
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800316 }
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700317
Angus Kong13e87c42013-11-25 10:02:47 -0800318
Michael Kolb8872c232013-01-29 10:33:22 -0800319 @Override
Angus Kong13e87c42013-11-25 10:02:47 -0800320 public void init(AppController app, boolean isSecureCamera, boolean isCaptureIntent) {
321 mActivity = (CameraActivity) app.getAndroidContext();
322 mUI = new PhotoUI(mActivity, this, app.getModuleLayoutRoot());
Doris Liu06db7422013-12-09 19:36:25 -0800323 app.setPreviewStatusListener(mUI);
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800324 app.getCameraAppUI().setBottomBarShutterListener(this);
Erin Dahlgren357b7672013-11-20 17:38:14 -0800325
326 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800327 mCameraId = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_CAMERA_ID));
Michael Kolb8872c232013-01-29 10:33:22 -0800328
329 mContentResolver = mActivity.getContentResolver();
330
Michael Kolb8872c232013-01-29 10:33:22 -0800331 // Surface texture is from camera screen nail and startPreview needs it.
332 // This must be done before startPreview.
333 mIsImageCaptureIntent = isImageCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800334
Angus Kong20fad242013-11-11 18:23:46 -0800335 mActivity.getCameraProvider().requestCamera(mCameraId);
336
Michael Kolb8872c232013-01-29 10:33:22 -0800337 initializeControlByIntent();
338 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800339 mLocationManager = mActivity.getLocationManager();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800340 mSensorManager = (SensorManager) (mActivity.getSystemService(Context.SENSOR_SERVICE));
Doris Liu2b906b82013-12-10 16:34:08 -0800341 mAppController = app;
Michael Kolbd6954f32013-03-08 20:43:01 -0800342 }
343
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800344 @Override
345 public boolean isUsingBottomBar() {
346 return true;
347 }
348
Michael Kolbd6954f32013-03-08 20:43:01 -0800349 private void initializeControlByIntent() {
350 mUI.initializeControlByIntent();
351 if (mIsImageCaptureIntent) {
352 setupCaptureParams();
353 }
354 }
355
356 private void onPreviewStarted() {
Doris Liu2b906b82013-12-10 16:34:08 -0800357 mAppController.onPreviewStarted();
Michael Kolbd6954f32013-03-08 20:43:01 -0800358 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800359 startFaceDetection();
Sameer Padala2c8cc452013-11-05 18:49:12 -0800360 startSmartCamera();
Michael Kolbd6954f32013-03-08 20:43:01 -0800361 locationFirstRun();
Michael Kolb8872c232013-01-29 10:33:22 -0800362 }
363
364 // Prompt the user to pick to record location for the very first run of
365 // camera only
366 private void locationFirstRun() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800367 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800368 if (settingsManager.isSet(SettingsManager.SETTING_RECORD_LOCATION)) {
Michael Kolb8872c232013-01-29 10:33:22 -0800369 return;
370 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800371 if (mActivity.isSecureCamera()) {
372 return;
373 }
Michael Kolb8872c232013-01-29 10:33:22 -0800374 // Check if the back camera exists
375 int backCameraId = CameraHolder.instance().getBackCameraId();
376 if (backCameraId == -1) {
377 // If there is no back camera, do not show the prompt.
378 return;
379 }
Doris Liu6a83d522013-07-02 12:03:32 -0700380 mUI.showLocationDialog();
381 }
Michael Kolb8872c232013-01-29 10:33:22 -0800382
ztenghui7b265a62013-09-09 14:58:44 -0700383 @Override
Angus Kongdcccc512013-08-08 17:06:03 -0700384 public void onPreviewUIReady() {
Erin Dahlgrendc282e12013-11-12 09:39:08 -0800385 startPreview();
Angus Kongdcccc512013-08-08 17:06:03 -0700386 }
387
388 @Override
389 public void onPreviewUIDestroyed() {
390 if (mCameraDevice == null) {
391 return;
392 }
393 mCameraDevice.setPreviewTexture(null);
394 stopPreview();
395 }
396
Doris Liu1dfe7822013-12-12 00:02:08 -0800397 @Override
398 public void startPreCaptureAnimation() {
399 mAppController.startPreCaptureAnimation();
400 }
401
Michael Kolbd6954f32013-03-08 20:43:01 -0800402 private void onCameraOpened() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800403 openCameraCommon();
Michael Kolb8872c232013-01-29 10:33:22 -0800404 }
405
Michael Kolbd6954f32013-03-08 20:43:01 -0800406 private void switchCamera() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800407 if (mPaused) {
408 return;
409 }
Erin Dahlgren357b7672013-11-20 17:38:14 -0800410 SettingsManager settingsManager = mActivity.getSettingsManager();
Michael Kolbd6954f32013-03-08 20:43:01 -0800411
412 Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
413 mCameraId = mPendingSwitchCameraId;
414 mPendingSwitchCameraId = -1;
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800415 settingsManager.set(SettingsManager.SETTING_CAMERA_ID, "" + mCameraId);
Angus Kong20fad242013-11-11 18:23:46 -0800416 mActivity.getCameraProvider().requestCamera(mCameraId);
Michael Kolbd6954f32013-03-08 20:43:01 -0800417 mUI.clearFaces();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800418 if (mFocusManager != null) {
419 mFocusManager.removeMessages();
420 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800421
Erin Dahlgren357b7672013-11-20 17:38:14 -0800422 // TODO: this needs to be brought into onCameraAvailable();
Angus Kong20fad242013-11-11 18:23:46 -0800423 CameraInfo info = mActivity.getCameraProvider().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -0700424 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
425 mFocusManager.setMirror(mMirror);
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700426 // Start switch camera animation. Post a message because
427 // onFrameAvailable from the old camera may already exist.
Doris Liu48239f42013-03-04 22:19:10 -0800428 }
429
Sascha Haeberling29f60562013-12-10 12:18:56 -0800430 private final ButtonManager.ButtonCallback mCameraButtonCallback =
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800431 new ButtonManager.ButtonCallback() {
432 @Override
433 public void onStateChanged(int state) {
434 if (mPaused || mPendingSwitchCameraId != -1) {
435 return;
436 }
437 mPendingSwitchCameraId = state;
438
439 Log.v(TAG, "Start to switch camera. cameraId=" + state);
440 // We need to keep a preview frame for the animation before
441 // releasing the camera. This will trigger onPreviewTextureCopied.
442 //TODO: Need to animate the camera switch
443 switchCamera();
444 }
445 };
446
Sascha Haeberling29f60562013-12-10 12:18:56 -0800447 private final ButtonManager.ButtonCallback mHdrPlusButtonCallback =
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800448 new ButtonManager.ButtonCallback() {
449 @Override
450 public void onStateChanged(int state) {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -0800451 if (GcamHelper.hasGcamCapture()) {
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800452 // Set the camera setting to default backfacing.
453 SettingsManager settingsManager = mActivity.getSettingsManager();
454 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_ID);
Erin Dahlgrenba6994d2013-12-12 16:04:38 -0800455 mHandler.sendEmptyMessage(MSG_SWITCH_TO_GCAM_MODULE);
456 } else {
457 mSceneMode = CameraUtil.SCENE_MODE_HDR;
458 updateParametersSceneMode();
459 }
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800460 }
461 };
462
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800463 private final ButtonManager.ButtonCallback mRefocusButtonCallback =
464 new ButtonManager.ButtonCallback() {
465 @Override
466 public void onStateChanged(int state) {
467 if (state == ButtonManager.OFF) {
468 throw new IllegalStateException(
469 "Can't switch refocus off because it should already be off.");
470 }
471 mActivity.onModeSelected(ModeListView.MODE_REFOCUS);
472 }
473 };
474
Michael Kolbd6954f32013-03-08 20:43:01 -0800475 // either open a new camera or switch cameras
476 private void openCameraCommon() {
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800477 mUI.onCameraOpened(mParameters, mCameraButtonCallback, mHdrPlusButtonCallback,
478 mRefocusButtonCallback);
Angus Kong0fb819b2013-10-08 13:44:19 -0700479 if (mIsImageCaptureIntent) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800480 // Set hdr plus to default: off.
481 SettingsManager settingsManager = mActivity.getSettingsManager();
482 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_HDR_PLUS);
Angus Kong0fb819b2013-10-08 13:44:19 -0700483 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800484 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -0800485 }
486
ztenghui7b265a62013-09-09 14:58:44 -0700487 @Override
Doris Liu36ebcb12013-10-28 14:44:24 -0700488 public void onPreviewRectChanged(Rect previewRect) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800489 if (mFocusManager != null)
490 mFocusManager.setPreviewRect(previewRect);
Michael Kolbd6954f32013-03-08 20:43:01 -0800491 }
Michael Kolb8872c232013-01-29 10:33:22 -0800492
Doris Liu70da9182013-12-17 18:41:15 -0800493 @Override
494 public void updatePreviewAspectRatio(float aspectRatio) {
495 mAppController.updatePreviewAspectRatio(aspectRatio);
496 }
497
Michael Kolb8872c232013-01-29 10:33:22 -0800498 private void resetExposureCompensation() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800499 SettingsManager settingsManager = mActivity.getSettingsManager();
500 if (settingsManager == null) {
501 Log.e(TAG, "Settings manager is null!");
502 return;
Michael Kolb8872c232013-01-29 10:33:22 -0800503 }
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800504 settingsManager.setDefault(SettingsManager.SETTING_EXPOSURE);
Michael Kolb8872c232013-01-29 10:33:22 -0800505 }
506
Michael Kolb8872c232013-01-29 10:33:22 -0800507 // Snapshots can only be taken after this is called. It should be called
508 // once only. We could have done these things in onCreate() but we want to
509 // make preview screen appear as soon as possible.
510 private void initializeFirstTime() {
Sascha Haeberling330dafb2013-10-10 19:00:41 -0700511 if (mFirstTimeInitialized || mPaused) {
512 return;
513 }
Michael Kolb8872c232013-01-29 10:33:22 -0800514
515 // Initialize location service.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800516 SettingsController settingsController = mActivity.getSettingsController();
517 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -0800518
Michael Kolbd6954f32013-03-08 20:43:01 -0800519 mUI.initializeFirstTime();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800520
Angus Kong86d36312013-01-31 18:22:44 -0800521 // We set the listener only when both service and shutterbutton
522 // are initialized.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800523 getServices().getMemoryManager().addListener(this);
Michael Kolb8872c232013-01-29 10:33:22 -0800524
Michael Kolb8872c232013-01-29 10:33:22 -0800525 mNamedImages = new NamedImages();
526
527 mFirstTimeInitialized = true;
528 addIdleHandler();
529
530 mActivity.updateStorageSpaceAndHint();
531 }
532
Michael Kolbd6954f32013-03-08 20:43:01 -0800533 // If the activity is paused and resumed, this method will be called in
534 // onResume.
535 private void initializeSecondTime() {
536 // Start location update if needed.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800537 SettingsController settingsController = mActivity.getSettingsController();
538 settingsController.syncLocationManager();
539
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800540 getServices().getMemoryManager().addListener(this);
Michael Kolbd6954f32013-03-08 20:43:01 -0800541 mNamedImages = new NamedImages();
542 mUI.initializeSecondTime(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -0800543 }
544
Michael Kolb8872c232013-01-29 10:33:22 -0800545 private void addIdleHandler() {
546 MessageQueue queue = Looper.myQueue();
547 queue.addIdleHandler(new MessageQueue.IdleHandler() {
548 @Override
549 public boolean queueIdle() {
550 Storage.ensureOSXCompatible();
551 return false;
552 }
553 });
554 }
555
Sameer Padala2c8cc452013-11-05 18:49:12 -0800556 private void startSmartCamera() {
557 SmartCameraHelper.register(mCameraDevice, mParameters.getPreviewSize(), mActivity,
Doris Liu773e1c92013-12-02 17:35:03 -0800558 (ViewGroup) mActivity.findViewById(R.id.camera_app_root));
Sameer Padala2c8cc452013-11-05 18:49:12 -0800559 }
560
561 private void stopSmartCamera() {
562 SmartCameraHelper.tearDown();
563 }
564
Michael Kolb8872c232013-01-29 10:33:22 -0800565 @Override
566 public void startFaceDetection() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800567 if (mFaceDetectionStarted) {
568 return;
569 }
Michael Kolb8872c232013-01-29 10:33:22 -0800570 if (mParameters.getMaxNumDetectedFaces() > 0) {
571 mFaceDetectionStarted = true;
Michael Kolb8872c232013-01-29 10:33:22 -0800572 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Michael Kolbd6954f32013-03-08 20:43:01 -0800573 mUI.onStartFaceDetection(mDisplayOrientation,
574 (info.facing == CameraInfo.CAMERA_FACING_FRONT));
Angus Kong9e765522013-07-31 14:05:20 -0700575 mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Michael Kolb8872c232013-01-29 10:33:22 -0800576 mCameraDevice.startFaceDetection();
577 }
578 }
579
Michael Kolb8872c232013-01-29 10:33:22 -0800580 @Override
581 public void stopFaceDetection() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800582 if (!mFaceDetectionStarted) {
583 return;
584 }
Michael Kolb8872c232013-01-29 10:33:22 -0800585 if (mParameters.getMaxNumDetectedFaces() > 0) {
586 mFaceDetectionStarted = false;
Angus Kong9e765522013-07-31 14:05:20 -0700587 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -0800588 mCameraDevice.stopFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800589 mUI.clearFaces();
Michael Kolb8872c232013-01-29 10:33:22 -0800590 }
591 }
592
Michael Kolb8872c232013-01-29 10:33:22 -0800593 private final class ShutterCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700594 implements CameraShutterCallback {
Angus Kongdcb0ef12013-03-25 23:11:43 -0700595
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800596 private final boolean mNeedsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700597
Sascha Haeberling37f36112013-08-06 14:31:52 -0700598 public ShutterCallback(boolean needsAnimation) {
599 mNeedsAnimation = needsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700600 }
601
Michael Kolb8872c232013-01-29 10:33:22 -0800602 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700603 public void onShutter(CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800604 mShutterCallbackTime = System.currentTimeMillis();
605 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
606 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Sascha Haeberling37f36112013-08-06 14:31:52 -0700607 if (mNeedsAnimation) {
608 mActivity.runOnUiThread(new Runnable() {
609 @Override
610 public void run() {
611 animateAfterShutter();
612 }
613 });
Angus Kongdcb0ef12013-03-25 23:11:43 -0700614 }
Michael Kolb8872c232013-01-29 10:33:22 -0800615 }
616 }
617
Angus Kong9ef99252013-07-18 18:04:19 -0700618 private final class PostViewPictureCallback
619 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800620 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800621 public void onPictureTaken(byte[] data, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800622 mPostViewPictureCallbackTime = System.currentTimeMillis();
623 Log.v(TAG, "mShutterToPostViewCallbackTime = "
624 + (mPostViewPictureCallbackTime - mShutterCallbackTime)
625 + "ms");
626 }
627 }
628
Angus Kong9ef99252013-07-18 18:04:19 -0700629 private final class RawPictureCallback
630 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800631 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800632 public void onPictureTaken(byte[] rawData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800633 mRawPictureCallbackTime = System.currentTimeMillis();
634 Log.v(TAG, "mShutterToRawCallbackTime = "
635 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
636 }
637 }
638
Angus Kong9ef99252013-07-18 18:04:19 -0700639 private final class JpegPictureCallback
640 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800641 Location mLocation;
642
643 public JpegPictureCallback(Location loc) {
644 mLocation = loc;
645 }
646
647 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800648 public void onPictureTaken(final byte[] jpegData, CameraProxy camera) {
649 setShutterEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800650 if (mPaused) {
651 return;
652 }
Doris Liu6432cd62013-06-13 17:20:31 -0700653 if (mIsImageCaptureIntent) {
654 stopPreview();
655 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700656 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -0700657 mUI.setSwipingEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800658 }
659
660 mJpegPictureCallbackTime = System.currentTimeMillis();
661 // If postview callback has arrived, the captured image is displayed
662 // in postview callback. If not, the captured image is displayed in
663 // raw picture callback.
664 if (mPostViewPictureCallbackTime != 0) {
665 mShutterToPictureDisplayedTime =
666 mPostViewPictureCallbackTime - mShutterCallbackTime;
667 mPictureDisplayedToJpegCallbackTime =
668 mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
669 } else {
670 mShutterToPictureDisplayedTime =
671 mRawPictureCallbackTime - mShutterCallbackTime;
672 mPictureDisplayedToJpegCallbackTime =
673 mJpegPictureCallbackTime - mRawPictureCallbackTime;
674 }
675 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
676 + mPictureDisplayedToJpegCallbackTime + "ms");
677
Michael Kolb8872c232013-01-29 10:33:22 -0800678 mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
679 if (!mIsImageCaptureIntent) {
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700680 setupPreview();
Michael Kolb8872c232013-01-29 10:33:22 -0800681 }
682
Doris Liu36e56fb2013-09-11 17:38:08 -0700683 ExifInterface exif = Exif.getExif(jpegData);
684 int orientation = Exif.getOrientation(exif);
Ruben Brunkd217ed02013-10-08 23:31:13 -0700685
Ruben Brunkd7488272013-10-10 18:45:53 -0700686 if (!mIsImageCaptureIntent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800687 // Calculate the width and the height of the jpeg.
688 Size s = mParameters.getPictureSize();
Michael Kolb8872c232013-01-29 10:33:22 -0800689 int width, height;
690 if ((mJpegRotation + orientation) % 180 == 0) {
691 width = s.width;
692 height = s.height;
693 } else {
694 width = s.height;
695 height = s.width;
696 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700697 NamedEntity name = mNamedImages.getNextNameEntity();
698 String title = (name == null) ? null : name.title;
699 long date = (name == null) ? -1 : name.date;
Ruben Brunkd7488272013-10-10 18:45:53 -0700700
701 // Handle debug mode outputs
702 if (mDebugUri != null) {
703 // If using a debug uri, save jpeg there.
704 saveToDebugUri(jpegData);
705
706 // Adjust the title of the debug image shown in mediastore.
707 if (title != null) {
708 title = DEBUG_IMAGE_PREFIX + title;
709 }
710 }
711
Michael Kolb8872c232013-01-29 10:33:22 -0800712 if (title == null) {
713 Log.e(TAG, "Unbalanced name/data pair");
714 } else {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800715 if (date == -1)
716 date = mCaptureStartTime;
Angus Kong0d00a892013-03-26 11:40:40 -0700717 if (mHeading >= 0) {
718 // heading direction has been updated by the sensor.
719 ExifTag directionRefTag = exif.buildTag(
720 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
721 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
722 ExifTag directionTag = exif.buildTag(
723 ExifInterface.TAG_GPS_IMG_DIRECTION,
724 new Rational(mHeading, 1));
725 exif.setTag(directionRefTag);
726 exif.setTag(directionTag);
727 }
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800728 getServices().getMediaSaver().addImage(
Angus Kong86d36312013-01-31 18:22:44 -0800729 jpegData, title, date, mLocation, width, height,
Angus Kong0d00a892013-03-26 11:40:40 -0700730 orientation, exif, mOnMediaSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -0800731 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800732 // Animate capture with real jpeg data instead of a preview
733 // frame.
Doris Liu29da2db2013-08-28 14:28:45 -0700734 mUI.animateCapture(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800735 } else {
736 mJpegImageData = jpegData;
737 if (!mQuickCapture) {
Doris Liu36e56fb2013-09-11 17:38:08 -0700738 mUI.showCapturedImageForReview(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800739 } else {
Michael Kolbd6954f32013-03-08 20:43:01 -0800740 onCaptureDone();
Michael Kolb8872c232013-01-29 10:33:22 -0800741 }
742 }
743
744 // Check this in advance of each shot so we don't add to shutter
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800745 // latency. It's true that someone else could write to the SD card
746 // in the mean time and fill it, but that could have happened
747 // between the shutter press and saving the JPEG too.
Michael Kolb8872c232013-01-29 10:33:22 -0800748 mActivity.updateStorageSpaceAndHint();
749
750 long now = System.currentTimeMillis();
751 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
752 Log.v(TAG, "mJpegCallbackFinishTime = "
753 + mJpegCallbackFinishTime + "ms");
754 mJpegPictureCallbackTime = 0;
755 }
756 }
757
Angus Kong9ef99252013-07-18 18:04:19 -0700758 private final class AutoFocusCallback implements CameraAFCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800759 @Override
760 public void onAutoFocus(
Angus Kong9ef99252013-07-18 18:04:19 -0700761 boolean focused, CameraProxy camera) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800762 if (mPaused) {
763 return;
764 }
Michael Kolb8872c232013-01-29 10:33:22 -0800765
766 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
767 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
768 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800769 mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
Michael Kolb8872c232013-01-29 10:33:22 -0800770 }
771 }
772
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700773 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -0800774 private final class AutoFocusMoveCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700775 implements CameraAFMoveCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800776 @Override
777 public void onAutoFocusMoving(
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700778 boolean moving, CameraProxy camera) {
779 mFocusManager.onAutoFocusMoving(moving);
Michael Kolb8872c232013-01-29 10:33:22 -0800780 }
781 }
782
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700783 /**
784 * This class is just a thread-safe queue for name,date holder objects.
785 */
786 public static class NamedImages {
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800787 private final Vector<NamedEntity> mQueue;
Michael Kolb8872c232013-01-29 10:33:22 -0800788
789 public NamedImages() {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700790 mQueue = new Vector<NamedEntity>();
Michael Kolb8872c232013-01-29 10:33:22 -0800791 }
792
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700793 public void nameNewImage(long date) {
Michael Kolb8872c232013-01-29 10:33:22 -0800794 NamedEntity r = new NamedEntity();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700795 r.title = CameraUtil.createJpegName(date);
Michael Kolb8872c232013-01-29 10:33:22 -0800796 r.date = date;
797 mQueue.add(r);
798 }
799
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700800 public NamedEntity getNextNameEntity() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800801 synchronized (mQueue) {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700802 if (!mQueue.isEmpty()) {
803 return mQueue.remove(0);
804 }
Michael Kolb8872c232013-01-29 10:33:22 -0800805 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700806 return null;
Michael Kolb8872c232013-01-29 10:33:22 -0800807 }
808
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700809 public static class NamedEntity {
810 public String title;
811 public long date;
Michael Kolb8872c232013-01-29 10:33:22 -0800812 }
813 }
814
815 private void setCameraState(int state) {
816 mCameraState = state;
817 switch (state) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700818 case PhotoController.PREVIEW_STOPPED:
819 case PhotoController.SNAPSHOT_IN_PROGRESS:
820 case PhotoController.SWITCHING_CAMERA:
Doris Liuf55f3c42013-11-20 00:24:46 -0800821 // TODO: Tell app UI to disable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700822 break;
823 case PhotoController.IDLE:
Doris Liuf55f3c42013-11-20 00:24:46 -0800824 // TODO: Tell app UI to enable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700825 break;
Michael Kolb8872c232013-01-29 10:33:22 -0800826 }
827 }
828
Sascha Haeberling37f36112013-08-06 14:31:52 -0700829 private void animateAfterShutter() {
Michael Kolb8872c232013-01-29 10:33:22 -0800830 // Only animate when in full screen capture mode
831 // i.e. If monkey/a user swipes to the gallery during picture taking,
832 // don't show animation
Doris Liuc2e9abd2013-06-19 14:20:51 -0700833 if (!mIsImageCaptureIntent) {
834 mUI.animateFlash();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700835 }
Michael Kolb8872c232013-01-29 10:33:22 -0800836 }
837
838 @Override
839 public boolean capture() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800840 // If we are already in the middle of taking a snapshot or the image
841 // save request is full then ignore.
Michael Kolb8872c232013-01-29 10:33:22 -0800842 if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800843 || mCameraState == SWITCHING_CAMERA || !mShutterEnabled) {
Michael Kolb8872c232013-01-29 10:33:22 -0800844 return false;
845 }
846 mCaptureStartTime = System.currentTimeMillis();
847 mPostViewPictureCallbackTime = 0;
848 mJpegImageData = null;
849
Angus Kongb50b5cb2013-08-09 14:55:20 -0700850 final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
Michael Kolb8872c232013-01-29 10:33:22 -0800851
852 if (animateBefore) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700853 animateAfterShutter();
Michael Kolb8872c232013-01-29 10:33:22 -0800854 }
855
856 // Set rotation and gps data.
Doris Liu3cf565c2013-02-15 10:55:37 -0800857 int orientation;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800858
Doris Liu3cf565c2013-02-15 10:55:37 -0800859 // We need to be consistent with the framework orientation (i.e. the
860 // orientation of the UI.) when the auto-rotate screen setting is on.
861 if (mActivity.isAutoRotateScreen()) {
862 orientation = (360 - mDisplayRotation) % 360;
863 } else {
864 orientation = mOrientation;
865 }
Angus Kong20fad242013-11-11 18:23:46 -0800866 mJpegRotation = CameraUtil.getJpegRotation(mActivity, mCameraId, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800867 mParameters.setRotation(mJpegRotation);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800868 Location loc = mActivity.getLocationManager().getCurrentLocation();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700869 CameraUtil.setGpsParameters(mParameters, loc);
Michael Kolb8872c232013-01-29 10:33:22 -0800870 mCameraDevice.setParameters(mParameters);
871
Sascha Haeberling88901942013-08-28 17:49:00 -0700872 // We don't want user to press the button again while taking a
873 // multi-second HDR photo.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800874 setShutterEnabled(false);
Angus Kong9ef99252013-07-18 18:04:19 -0700875 mCameraDevice.takePicture(mHandler,
876 new ShutterCallback(!animateBefore),
Angus Kongdcb0ef12013-03-25 23:11:43 -0700877 mRawPictureCallback, mPostViewPictureCallback,
Angus Kong9ef99252013-07-18 18:04:19 -0700878 new JpegPictureCallback(loc));
Michael Kolb8872c232013-01-29 10:33:22 -0800879
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700880 mNamedImages.nameNewImage(mCaptureStartTime);
Michael Kolb8872c232013-01-29 10:33:22 -0800881
882 mFaceDetectionStarted = false;
883 setCameraState(SNAPSHOT_IN_PROGRESS);
Bobby Georgescu301b6462013-04-01 15:33:17 -0700884 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
Seth Raphaelcbd82672013-11-05 10:12:36 -0800885 UsageStatistics.ACTION_CAPTURE_DONE, "Photo", 0,
Seth Raphael44973262013-11-27 14:29:24 -0800886 UsageStatistics.hashFileName(mNamedImages.mQueue.lastElement().title + ".jpg"));
Michael Kolb8872c232013-01-29 10:33:22 -0800887 return true;
888 }
889
890 @Override
891 public void setFocusParameters() {
892 setCameraParameters(UPDATE_PARAM_PREFERENCE);
893 }
894
Michael Kolbd6954f32013-03-08 20:43:01 -0800895 private void updateSceneMode() {
Michael Kolb8872c232013-01-29 10:33:22 -0800896 // If scene mode is set, we cannot set flash mode, white balance, and
897 // focus mode, instead, we read it from driver
898 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
899 overrideCameraSettings(mParameters.getFlashMode(),
900 mParameters.getWhiteBalance(), mParameters.getFocusMode());
901 } else {
902 overrideCameraSettings(null, null, null);
903 }
904 }
905
906 private void overrideCameraSettings(final String flashMode,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800907 final String whiteBalance, final String focusMode) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800908 SettingsManager settingsManager = mActivity.getSettingsManager();
909 settingsManager.set(SettingsManager.SETTING_FLASH_MODE, flashMode);
910 settingsManager.set(SettingsManager.SETTING_WHITE_BALANCE, whiteBalance);
911 settingsManager.set(SettingsManager.SETTING_FOCUS_MODE, focusMode);
Michael Kolb8872c232013-01-29 10:33:22 -0800912 }
913
914 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800915 public void onOrientationChanged(int orientation) {
916 // We keep the last known orientation. So if the user first orient
917 // the camera then point the camera to floor or sky, we still have
918 // the correct orientation.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800919 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
920 return;
921 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700922 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800923
924 // Show the toast after getting the first orientation changed.
Angus Kong13e87c42013-11-25 10:02:47 -0800925 if (mHandler.hasMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST)) {
926 mHandler.removeMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST);
Michael Kolb8872c232013-01-29 10:33:22 -0800927 showTapToFocusToast();
928 }
929 }
930
931 @Override
Angus Kong20fad242013-11-11 18:23:46 -0800932 public void onCameraAvailable(CameraProxy cameraProxy) {
933 if (mPaused) {
934 return;
935 }
936 mCameraDevice = cameraProxy;
937
Erin Dahlgren357b7672013-11-20 17:38:14 -0800938 resetExposureCompensation();
Angus Kong20fad242013-11-11 18:23:46 -0800939 initializeCapabilities();
940
941 // Reset zoom value index.
942 mZoomValue = 0;
943 if (mFocusManager == null) {
944 initializeFocusManager();
945 }
946 mFocusManager.setParameters(mInitialParams);
947
Erin Dahlgren7f0151d2014-01-02 16:08:12 -0800948 // Do camera parameter dependent initialization.
Angus Kong20fad242013-11-11 18:23:46 -0800949 mParameters = mCameraDevice.getParameters();
950 setCameraParameters(UPDATE_PARAM_ALL);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -0800951 // Set a listener which updates camera parameters based
952 // on changed settings.
953 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren1648c362014-01-06 15:06:04 -0800954 settingsManager.addListener(this);
Angus Kong20fad242013-11-11 18:23:46 -0800955 mCameraPreviewParamsReady = true;
Erin Dahlgren7f0151d2014-01-02 16:08:12 -0800956
Angus Kong20fad242013-11-11 18:23:46 -0800957 startPreview();
958
959 onCameraOpened();
960 }
961
962 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -0800963 public void onCaptureCancelled() {
964 mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
965 mActivity.finish();
Michael Kolb8872c232013-01-29 10:33:22 -0800966 }
967
Michael Kolbd6954f32013-03-08 20:43:01 -0800968 @Override
969 public void onCaptureRetake() {
Michael Kolb8872c232013-01-29 10:33:22 -0800970 if (mPaused)
971 return;
Michael Kolbd6954f32013-03-08 20:43:01 -0800972 mUI.hidePostCaptureAlert();
Michael Kolb8872c232013-01-29 10:33:22 -0800973 setupPreview();
974 }
975
Michael Kolbd6954f32013-03-08 20:43:01 -0800976 @Override
977 public void onCaptureDone() {
Michael Kolb8872c232013-01-29 10:33:22 -0800978 if (mPaused) {
979 return;
980 }
981
982 byte[] data = mJpegImageData;
983
984 if (mCropValue == null) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800985 // First handle the no crop case -- just return the value. If the
Michael Kolb8872c232013-01-29 10:33:22 -0800986 // caller specifies a "save uri" then write the data to its
987 // stream. Otherwise, pass back a scaled down version of the bitmap
988 // directly in the extras.
989 if (mSaveUri != null) {
990 OutputStream outputStream = null;
991 try {
992 outputStream = mContentResolver.openOutputStream(mSaveUri);
993 outputStream.write(data);
994 outputStream.close();
995
996 mActivity.setResultEx(Activity.RESULT_OK);
997 mActivity.finish();
998 } catch (IOException ex) {
999 // ignore exception
1000 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001001 CameraUtil.closeSilently(outputStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001002 }
1003 } else {
Angus Kong0d00a892013-03-26 11:40:40 -07001004 ExifInterface exif = Exif.getExif(data);
1005 int orientation = Exif.getOrientation(exif);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001006 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
1007 bitmap = CameraUtil.rotate(bitmap, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001008 mActivity.setResultEx(Activity.RESULT_OK,
1009 new Intent("inline-data").putExtra("data", bitmap));
1010 mActivity.finish();
1011 }
1012 } else {
1013 // Save the image to a temp file and invoke the cropper
1014 Uri tempUri = null;
1015 FileOutputStream tempStream = null;
1016 try {
1017 File path = mActivity.getFileStreamPath(sTempCropFilename);
1018 path.delete();
1019 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1020 tempStream.write(data);
1021 tempStream.close();
1022 tempUri = Uri.fromFile(path);
1023 } catch (FileNotFoundException ex) {
1024 mActivity.setResultEx(Activity.RESULT_CANCELED);
1025 mActivity.finish();
1026 return;
1027 } catch (IOException ex) {
1028 mActivity.setResultEx(Activity.RESULT_CANCELED);
1029 mActivity.finish();
1030 return;
1031 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001032 CameraUtil.closeSilently(tempStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001033 }
1034
1035 Bundle newExtras = new Bundle();
1036 if (mCropValue.equals("circle")) {
1037 newExtras.putString("circleCrop", "true");
1038 }
1039 if (mSaveUri != null) {
1040 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1041 } else {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001042 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001043 }
1044 if (mActivity.isSecureCamera()) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001045 newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001046 }
1047
Sascha Haeberling37f36112013-08-06 14:31:52 -07001048 // TODO: Share this constant.
Sascha Haeberling8e963a52013-08-06 11:43:02 -07001049 final String CROP_ACTION = "com.android.camera.action.CROP";
1050 Intent cropIntent = new Intent(CROP_ACTION);
Michael Kolb8872c232013-01-29 10:33:22 -08001051
1052 cropIntent.setData(tempUri);
1053 cropIntent.putExtras(newExtras);
1054
1055 mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1056 }
1057 }
1058
Michael Kolb8872c232013-01-29 10:33:22 -08001059 @Override
1060 public void onShutterButtonFocus(boolean pressed) {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001061 if (mPaused || (mCameraState == SNAPSHOT_IN_PROGRESS)
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001062 || (mCameraState == PREVIEW_STOPPED)) {
1063 return;
1064 }
Michael Kolb8872c232013-01-29 10:33:22 -08001065
1066 // Do not do focus if there is not enough storage.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001067 if (pressed && !canTakePicture()) {
1068 return;
1069 }
Michael Kolb8872c232013-01-29 10:33:22 -08001070
1071 if (pressed) {
Michael Kolb8872c232013-01-29 10:33:22 -08001072 mFocusManager.onShutterDown();
1073 } else {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001074 mFocusManager.onShutterUp();
Michael Kolb8872c232013-01-29 10:33:22 -08001075 }
1076 }
1077
1078 @Override
1079 public void onShutterButtonClick() {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001080 if (mPaused || (mCameraState == SWITCHING_CAMERA)
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001081 || (mCameraState == PREVIEW_STOPPED)) {
1082 return;
1083 }
Michael Kolb8872c232013-01-29 10:33:22 -08001084
1085 // Do not take the picture if there is not enough storage.
Angus Kong2dcc0a92013-09-25 13:00:08 -07001086 if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Michael Kolb8872c232013-01-29 10:33:22 -08001087 Log.i(TAG, "Not enough space or storage not ready. remaining="
Angus Kong2dcc0a92013-09-25 13:00:08 -07001088 + mActivity.getStorageSpaceBytes());
Michael Kolb8872c232013-01-29 10:33:22 -08001089 return;
1090 }
1091 Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1092
Angus Kongb50b5cb2013-08-09 14:55:20 -07001093 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -07001094 mUI.setSwipingEnabled(false);
Doris Liu9cdfe002013-04-16 09:50:56 -07001095 }
Michael Kolb8872c232013-01-29 10:33:22 -08001096 // If the user wants to do a snapshot while the previous one is still
1097 // in progress, remember the fact and do it after we finish the previous
1098 // one and re-start the preview. Snapshot in progress also includes the
1099 // state that autofocus is focusing and a picture will be taken when
1100 // focus callback arrives.
1101 if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1102 && !mIsImageCaptureIntent) {
1103 mSnapshotOnIdle = true;
1104 return;
1105 }
1106
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001107 mSnapshotOnIdle = false;
1108 mFocusManager.doSnap();
Michael Kolb8872c232013-01-29 10:33:22 -08001109 }
1110
Andy Huibersdef975d2013-11-22 09:13:39 -08001111 private void onResumeTasks() {
1112 Log.v(TAG, "Executing onResumeTasks.");
Angus Kong20fad242013-11-11 18:23:46 -08001113 mActivity.getCameraProvider().requestCamera(mCameraId);
1114
Michael Kolb8872c232013-01-29 10:33:22 -08001115 mJpegPictureCallbackTime = 0;
1116 mZoomValue = 0;
Angus Kong20fad242013-11-11 18:23:46 -08001117
1118 mOnResumeTime = SystemClock.uptimeMillis();
1119 checkDisplayRotation();
Michael Kolb8872c232013-01-29 10:33:22 -08001120
1121 // If first time initialization is not finished, put it in the
1122 // message queue.
1123 if (!mFirstTimeInitialized) {
Angus Kong13e87c42013-11-25 10:02:47 -08001124 mHandler.sendEmptyMessage(MSG_FIRST_TIME_INIT);
Michael Kolb8872c232013-01-29 10:33:22 -08001125 } else {
1126 initializeSecondTime();
1127 }
Michael Kolb8872c232013-01-29 10:33:22 -08001128
Bobby Georgescu0a7dd572013-03-12 22:45:17 -07001129 UsageStatistics.onContentViewChanged(
1130 UsageStatistics.COMPONENT_CAMERA, "PhotoModule");
Angus Kong0d00a892013-03-26 11:40:40 -07001131
1132 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1133 if (gsensor != null) {
1134 mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1135 }
1136
1137 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1138 if (msensor != null) {
1139 mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1140 }
Michael Kolb8872c232013-01-29 10:33:22 -08001141 }
1142
Angus Kongc4e66562013-11-22 23:03:21 -08001143 /**
1144 * The focus manager is the first UI related element to get initialized,
1145 * and it requires the RenderOverlay, so initialize it here
1146 */
1147 private void initializeFocusManager() {
1148 // Create FocusManager object. startPreview needs it.
1149 // if mFocusManager not null, reuse it
1150 // otherwise create a new instance
1151 if (mFocusManager != null) {
1152 mFocusManager.removeMessages();
1153 } else {
1154 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
1155 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
1156 String[] defaultFocusModes = mActivity.getResources().getStringArray(
1157 R.array.pref_camera_focusmode_default_array);
Erin Dahlgren357b7672013-11-20 17:38:14 -08001158 mFocusManager = new FocusOverlayManager(mActivity.getSettingsManager(),
1159 defaultFocusModes,
Angus Kongc4e66562013-11-22 23:03:21 -08001160 mInitialParams, this, mMirror,
Doris Liu482de022013-12-18 19:18:16 -08001161 mActivity.getMainLooper(), mUI.getFocusUI());
Angus Kongc4e66562013-11-22 23:03:21 -08001162 }
Doris Liu482de022013-12-18 19:18:16 -08001163 mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
Angus Kong20fad242013-11-11 18:23:46 -08001164 }
1165
1166 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001167 public void resume() {
1168 mPaused = false;
Doris Liu482de022013-12-18 19:18:16 -08001169 if (mFocusManager != null) {
Doris Liu15b99612013-12-21 11:32:28 -08001170 // If camera is not open when resume is called, focus manager will not
1171 // be initialized yet, in which case it will start listening to
1172 // preview area size change later in the initialization.
Doris Liu482de022013-12-18 19:18:16 -08001173 mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
1174 }
Angus Kongc4e66562013-11-22 23:03:21 -08001175 // Add delay on resume from lock screen only, in order to to speed up
1176 // the onResume --> onPause --> onResume cycle from lock screen.
1177 // Don't do always because letting go of thread can cause delay.
1178 String action = mActivity.getIntent().getAction();
1179 if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
1180 || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
1181 Log.v(TAG, "On resume, from lock screen.");
1182 // Note: onPauseAfterSuper() will delete this runnable, so we will
1183 // at most have 1 copy queued up.
1184 mHandler.postDelayed(new Runnable() {
Sameer Padala2c8cc452013-11-05 18:49:12 -08001185 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001186 public void run() {
1187 onResumeTasks();
1188 }
1189 }, ON_RESUME_TASKS_DELAY_MSEC);
1190 } else {
1191 Log.v(TAG, "On resume.");
1192 onResumeTasks();
1193 }
1194 }
1195
1196 @Override
1197 public void pause() {
Michael Kolb8872c232013-01-29 10:33:22 -08001198 mPaused = true;
Angus Kong0d00a892013-03-26 11:40:40 -07001199 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1200 if (gsensor != null) {
1201 mSensorManager.unregisterListener(this, gsensor);
1202 }
1203
1204 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1205 if (msensor != null) {
1206 mSensorManager.unregisterListener(this, msensor);
1207 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001208
Michael Kolb8872c232013-01-29 10:33:22 -08001209 // Reset the focus first. Camera CTS does not guarantee that
1210 // cancelAutoFocus is allowed after preview stops.
1211 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1212 mCameraDevice.cancelAutoFocus();
1213 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001214
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -08001215 // If the camera has not been opened asynchronously yet,
1216 // and startPreview hasn't been called, then this is a no-op.
1217 // (e.g. onResume -> onPause -> onResume).
Michael Kolb8872c232013-01-29 10:33:22 -08001218 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001219
Angus Kongce5480e2013-01-29 17:43:48 -08001220 mNamedImages = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001221
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001222 if (mLocationManager != null) {
1223 mLocationManager.recordLocation(false);
1224 }
Michael Kolb8872c232013-01-29 10:33:22 -08001225
1226 // If we are in an image capture intent and has taken
1227 // a picture, we just clear it in onPause.
1228 mJpegImageData = null;
1229
Angus Kongdcccc512013-08-08 17:06:03 -07001230 // Remove the messages and runnables in the queue.
1231 mHandler.removeCallbacksAndMessages(null);
Michael Kolb8872c232013-01-29 10:33:22 -08001232
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001233 closeCamera();
Angus Kong13e87c42013-11-25 10:02:47 -08001234 mActivity.enableKeepScreenOn(false);
Michael Kolbd6954f32013-03-08 20:43:01 -08001235 mUI.onPause();
1236
Michael Kolb8872c232013-01-29 10:33:22 -08001237 mPendingSwitchCameraId = -1;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001238 if (mFocusManager != null) {
1239 mFocusManager.removeMessages();
Angus Kong86d36312013-01-31 18:22:44 -08001240 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001241 getServices().getMemoryManager().removeListener(this);
Doris Liu482de022013-12-18 19:18:16 -08001242 mAppController.removePreviewAreaSizeChangedListener(mFocusManager);
Erin Dahlgren1648c362014-01-06 15:06:04 -08001243
1244 SettingsManager settingsManager = mActivity.getSettingsManager();
1245 settingsManager.removeListener(this);
Michael Kolb8872c232013-01-29 10:33:22 -08001246 }
1247
Angus Kong20fad242013-11-11 18:23:46 -08001248 @Override
1249 public void destroy() {
1250 // TODO: implement this.
1251 }
1252
1253 @Override
1254 public void onPreviewSizeChanged(int width, int height) {
1255 // TODO: implement this.
1256 }
1257
1258 @Override
Angus Kong2f0e4a32013-12-03 10:02:35 -08001259 public void onLayoutOrientationChanged(boolean isLandscape) {
Michael Kolb8872c232013-01-29 10:33:22 -08001260 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001261 }
1262
1263 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001264 public void updateCameraOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001265 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001266 setDisplayOrientation();
1267 }
1268 }
1269
Michael Kolb8872c232013-01-29 10:33:22 -08001270 private boolean canTakePicture() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001271 return isCameraIdle()
1272 && (mActivity.getStorageSpaceBytes() > Storage.LOW_STORAGE_THRESHOLD_BYTES);
Michael Kolb8872c232013-01-29 10:33:22 -08001273 }
1274
1275 @Override
1276 public void autoFocus() {
1277 mFocusStartTime = System.currentTimeMillis();
Angus Kong9ef99252013-07-18 18:04:19 -07001278 mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001279 setCameraState(FOCUSING);
1280 }
1281
1282 @Override
1283 public void cancelAutoFocus() {
1284 mCameraDevice.cancelAutoFocus();
1285 setCameraState(IDLE);
1286 setCameraParameters(UPDATE_PARAM_PREFERENCE);
1287 }
1288
Michael Kolb8872c232013-01-29 10:33:22 -08001289 @Override
1290 public void onSingleTapUp(View view, int x, int y) {
Doris Liu482de022013-12-18 19:18:16 -08001291 if (mPaused || mCameraDevice == null || !mFirstTimeInitialized
1292 || mCameraState == SNAPSHOT_IN_PROGRESS
1293 || mCameraState == SWITCHING_CAMERA
1294 || mCameraState == PREVIEW_STOPPED) {
1295 return;
1296 }
1297
1298 // Check if metering area or focus area is supported.
Doris Liu15b99612013-12-21 11:32:28 -08001299 if (!mFocusAreaSupported && !mMeteringAreaSupported) {
1300 return;
1301 }
Doris Liu482de022013-12-18 19:18:16 -08001302 mFocusManager.onSingleTapUp(x, y);
Michael Kolb8872c232013-01-29 10:33:22 -08001303 }
1304
1305 @Override
1306 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001307 return mUI.onBackPressed();
Michael Kolb8872c232013-01-29 10:33:22 -08001308 }
1309
1310 @Override
1311 public boolean onKeyDown(int keyCode, KeyEvent event) {
1312 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001313 case KeyEvent.KEYCODE_VOLUME_UP:
1314 case KeyEvent.KEYCODE_VOLUME_DOWN:
1315 case KeyEvent.KEYCODE_FOCUS:
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001316 if (/* TODO: mActivity.isInCameraApp() && */mFirstTimeInitialized) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001317 if (event.getRepeatCount() == 0) {
1318 onShutterButtonFocus(true);
1319 }
1320 return true;
1321 }
1322 return false;
1323 case KeyEvent.KEYCODE_CAMERA:
1324 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1325 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001326 }
1327 return true;
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001328 case KeyEvent.KEYCODE_DPAD_CENTER:
1329 // If we get a dpad center event without any focused view, move
1330 // the focus to the shutter button and press it.
1331 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1332 // Start auto-focus immediately to reduce shutter lag. After
1333 // the shutter button gets the focus, onShutterButtonFocus()
1334 // will be called again but it is fine.
1335 onShutterButtonFocus(true);
1336 mUI.pressShutterButton();
1337 }
1338 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001339 }
1340 return false;
1341 }
1342
1343 @Override
1344 public boolean onKeyUp(int keyCode, KeyEvent event) {
1345 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001346 case KeyEvent.KEYCODE_VOLUME_UP:
1347 case KeyEvent.KEYCODE_VOLUME_DOWN:
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001348 if (/* mActivity.isInCameraApp() && */mFirstTimeInitialized) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001349 onShutterButtonClick();
1350 return true;
1351 }
1352 return false;
1353 case KeyEvent.KEYCODE_FOCUS:
1354 if (mFirstTimeInitialized) {
1355 onShutterButtonFocus(false);
1356 }
Michael Kolb8872c232013-01-29 10:33:22 -08001357 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001358 }
1359 return false;
1360 }
1361
Michael Kolb8872c232013-01-29 10:33:22 -08001362 private void closeCamera() {
1363 if (mCameraDevice != null) {
1364 mCameraDevice.setZoomChangeListener(null);
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001365 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001366 mCameraDevice.setErrorCallback(null);
Ruben Brunk59147832013-11-05 15:53:28 -08001367
Michael Kolb8872c232013-01-29 10:33:22 -08001368 mFaceDetectionStarted = false;
Angus Kong20fad242013-11-11 18:23:46 -08001369 mActivity.getCameraProvider().releaseCamera(mCameraDevice.getCameraId());
Michael Kolb8872c232013-01-29 10:33:22 -08001370 mCameraDevice = null;
1371 setCameraState(PREVIEW_STOPPED);
1372 mFocusManager.onCameraReleased();
1373 }
1374 }
1375
1376 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001377 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1378 mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001379 mCameraDisplayOrientation = mDisplayOrientation;
Michael Kolbd6954f32013-03-08 20:43:01 -08001380 mUI.setDisplayOrientation(mDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001381 if (mFocusManager != null) {
1382 mFocusManager.setDisplayOrientation(mDisplayOrientation);
1383 }
Doris Liu6432cd62013-06-13 17:20:31 -07001384 // Change the camera display orientation
1385 if (mCameraDevice != null) {
1386 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1387 }
Michael Kolb8872c232013-01-29 10:33:22 -08001388 }
1389
Sascha Haeberlingddef7792013-08-13 14:41:10 -07001390 /** Only called by UI thread. */
Michael Kolb8872c232013-01-29 10:33:22 -08001391 private void setupPreview() {
1392 mFocusManager.resetTouchFocus();
1393 startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001394 }
1395
Angus Kong20fad242013-11-11 18:23:46 -08001396 /**
1397 * Returns whether we can/should start the preview or not.
1398 */
1399 private boolean checkPreviewPreconditions() {
1400 if (mPaused) {
1401 return false;
Angus Kongdcccc512013-08-08 17:06:03 -07001402 }
Michael Kolb8872c232013-01-29 10:33:22 -08001403
Angus Kong20fad242013-11-11 18:23:46 -08001404 if (mCameraDevice == null) {
1405 Log.w(TAG, "startPreview: camera device not ready yet.");
1406 return false;
1407 }
1408
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001409 SurfaceTexture st = mUI.getSurfaceTexture();
1410 if (st == null) {
1411 Log.w(TAG, "startPreview: surfaceTexture is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001412 return false;
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001413 }
1414
1415 if (!mCameraPreviewParamsReady) {
1416 Log.w(TAG, "startPreview: parameters for preview is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001417 return false;
1418 }
1419 return true;
1420 }
1421
1422 /**
1423 * The start/stop preview should only run on the UI thread.
1424 */
1425 private void startPreview() {
1426 if (!checkPreviewPreconditions()) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001427 return;
1428 }
Angus Kong20fad242013-11-11 18:23:46 -08001429
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001430 mCameraDevice.setErrorCallback(mErrorCallback);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001431 // ICS camera frameworks has a bug. Face detection state is not cleared
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001432 // after taking a picture. Stop the preview to work around it. The bug
1433 // was fixed in JB.
1434 if (mCameraState != PREVIEW_STOPPED) {
1435 stopPreview();
1436 }
1437
1438 setDisplayOrientation();
1439
1440 if (!mSnapshotOnIdle) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001441 // If the focus mode is continuous autofocus, call cancelAutoFocus
1442 // to resume it because it may have been paused by autoFocus call.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001443 String focusMode = mFocusManager.getFocusMode();
1444 if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(focusMode)) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001445 mCameraDevice.cancelAutoFocus();
Michael Kolb8872c232013-01-29 10:33:22 -08001446 }
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001447 mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1448 }
1449 setCameraParameters(UPDATE_PARAM_ALL);
1450 // Let UI set its expected aspect ratio
Angus Kong20fad242013-11-11 18:23:46 -08001451 mCameraDevice.setPreviewTexture(mUI.getSurfaceTexture());
Michael Kolb8872c232013-01-29 10:33:22 -08001452
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001453 Log.v(TAG, "startPreview");
1454 mCameraDevice.startPreview();
Angus Kong20fad242013-11-11 18:23:46 -08001455
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001456 mFocusManager.onPreviewStarted();
1457 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001458
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001459 if (mSnapshotOnIdle) {
1460 mHandler.post(mDoSnapRunnable);
Michael Kolb8872c232013-01-29 10:33:22 -08001461 }
1462 }
1463
Michael Kolbd6954f32013-03-08 20:43:01 -08001464 @Override
1465 public void stopPreview() {
Michael Kolb8872c232013-01-29 10:33:22 -08001466 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1467 Log.v(TAG, "stopPreview");
1468 mCameraDevice.stopPreview();
1469 mFaceDetectionStarted = false;
1470 }
1471 setCameraState(PREVIEW_STOPPED);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001472 if (mFocusManager != null) {
1473 mFocusManager.onPreviewStopped();
1474 }
Sameer Padala2c8cc452013-11-05 18:49:12 -08001475 stopSmartCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001476 }
1477
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001478 @Override
Erin Dahlgren1648c362014-01-06 15:06:04 -08001479 public void onSettingChanged(SettingsManager settingsManager, int id) {
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001480 switch (id) {
1481 case SettingsManager.SETTING_FLASH_MODE: {
1482 updateParametersFlashMode();
1483 break;
1484 }
1485 case SettingsManager.SETTING_PICTURE_SIZE: {
1486 updateParametersPictureSize();
1487 break;
1488 }
1489 case SettingsManager.SETTING_RECORD_LOCATION: {
1490 SettingsController settingsController = mActivity.getSettingsController();
1491 settingsController.syncLocationManager();
1492 break;
1493 }
1494 default: {
1495 // Do nothing.
1496 }
1497 }
Erin Dahlgren1648c362014-01-06 15:06:04 -08001498
1499 if (mCameraDevice != null) {
1500 mCameraDevice.setParameters(mParameters);
1501 }
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001502 }
1503
Michael Kolb8872c232013-01-29 10:33:22 -08001504 private void updateCameraParametersInitialize() {
1505 // Reset preview frame rate to the maximum because it may be lowered by
1506 // video camera application.
ztenghui16a35202013-09-23 11:35:36 -07001507 int[] fpsRange = CameraUtil.getPhotoPreviewFpsRange(mParameters);
1508 if (fpsRange != null && fpsRange.length > 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001509 mParameters.setPreviewFpsRange(
1510 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1511 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
Michael Kolb8872c232013-01-29 10:33:22 -08001512 }
1513
Angus Kongb50b5cb2013-08-09 14:55:20 -07001514 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);
Michael Kolb8872c232013-01-29 10:33:22 -08001515
1516 // Disable video stabilization. Convenience methods not available in API
1517 // level <= 14
1518 String vstabSupported = mParameters.get("video-stabilization-supported");
1519 if ("true".equals(vstabSupported)) {
1520 mParameters.set("video-stabilization", "false");
1521 }
1522 }
1523
1524 private void updateCameraParametersZoom() {
1525 // Set zoom.
1526 if (mParameters.isZoomSupported()) {
1527 mParameters.setZoom(mZoomValue);
1528 }
1529 }
1530
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001531 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001532 private void setAutoExposureLockIfSupported() {
1533 if (mAeLockSupported) {
1534 mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1535 }
1536 }
1537
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001538 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001539 private void setAutoWhiteBalanceLockIfSupported() {
1540 if (mAwbLockSupported) {
1541 mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1542 }
1543 }
1544
Michael Kolb8872c232013-01-29 10:33:22 -08001545 private void setFocusAreasIfSupported() {
1546 if (mFocusAreaSupported) {
1547 mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1548 }
1549 }
1550
Michael Kolb8872c232013-01-29 10:33:22 -08001551 private void setMeteringAreasIfSupported() {
1552 if (mMeteringAreaSupported) {
Michael Kolb8872c232013-01-29 10:33:22 -08001553 mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1554 }
1555 }
1556
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001557 private void updateCameraParametersPreference() {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001558 SettingsManager settingsManager = mActivity.getSettingsManager();
1559
Michael Kolb8872c232013-01-29 10:33:22 -08001560 setAutoExposureLockIfSupported();
1561 setAutoWhiteBalanceLockIfSupported();
1562 setFocusAreasIfSupported();
1563 setMeteringAreasIfSupported();
1564
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001565 // Initialize focus mode.
Michael Kolbd3253f22013-07-12 11:36:47 -07001566 mFocusManager.overrideFocusMode(null);
1567 mParameters.setFocusMode(mFocusManager.getFocusMode());
1568
Michael Kolb8872c232013-01-29 10:33:22 -08001569 // Set picture size.
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001570 updateParametersPictureSize();
1571
1572 // Set JPEG quality.
1573 updateParametersPictureQuality();
1574
1575 // For the following settings, we need to check if the settings are
1576 // still supported by latest driver, if not, ignore the settings.
1577
1578 // Set exposure compensation
1579 updateParametersExposureCompensation();
1580
1581 // Set the scene mode: also sets flash and white balance.
1582 updateParametersSceneMode();
1583
1584 if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
1585 updateAutoFocusMoveCallback();
1586 }
1587 }
1588
1589 private void updateParametersPictureSize() {
1590 SettingsManager settingsManager = mActivity.getSettingsManager();
1591
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001592 String pictureSize = settingsManager.get(SettingsManager.SETTING_PICTURE_SIZE);
Michael Kolb8872c232013-01-29 10:33:22 -08001593 if (pictureSize == null) {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001594 //TODO: deprecate CameraSettings.
1595 CameraSettings.initialCameraPictureSize(
1596 mActivity, mParameters, settingsManager);
Michael Kolb8872c232013-01-29 10:33:22 -08001597 } else {
1598 List<Size> supported = mParameters.getSupportedPictureSizes();
1599 CameraSettings.setCameraPictureSize(
1600 pictureSize, supported, mParameters);
1601 }
1602 Size size = mParameters.getPictureSize();
1603
1604 // Set a preview size that is closest to the viewfinder height and has
1605 // the right aspect ratio.
1606 List<Size> sizes = mParameters.getSupportedPreviewSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001607 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
Michael Kolb8872c232013-01-29 10:33:22 -08001608 (double) size.width / size.height);
1609 Size original = mParameters.getPreviewSize();
1610 if (!original.equals(optimalSize)) {
1611 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
Doris Liu6432cd62013-06-13 17:20:31 -07001612
Michael Kolb8872c232013-01-29 10:33:22 -08001613 // Zoom related settings will be changed for different preview
1614 // sizes, so set and read the parameters to get latest values
Michael Kolb4a4d4ef2013-05-30 08:35:26 -07001615 if (mHandler.getLooper() == Looper.myLooper()) {
1616 // On UI thread only, not when camera starts up
1617 setupPreview();
1618 } else {
1619 mCameraDevice.setParameters(mParameters);
1620 }
Michael Kolb8872c232013-01-29 10:33:22 -08001621 mParameters = mCameraDevice.getParameters();
1622 }
Doris Liu95405742013-11-05 15:25:26 -08001623
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001624 if (optimalSize.width != 0 && optimalSize.height != 0) {
Doris Liu95405742013-11-05 15:25:26 -08001625 mUI.updatePreviewAspectRatio((float) optimalSize.width
1626 / (float) optimalSize.height);
1627 }
Michael Kolb8872c232013-01-29 10:33:22 -08001628 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001629 }
Michael Kolb8872c232013-01-29 10:33:22 -08001630
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001631 private void updateParametersPictureQuality() {
Michael Kolb8872c232013-01-29 10:33:22 -08001632 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1633 CameraProfile.QUALITY_HIGH);
1634 mParameters.setJpegQuality(jpegQuality);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001635 }
Michael Kolb8872c232013-01-29 10:33:22 -08001636
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001637 private void updateParametersExposureCompensation() {
1638 SettingsManager settingsManager = mActivity.getSettingsManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001639
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001640 int value = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_EXPOSURE));
Michael Kolb8872c232013-01-29 10:33:22 -08001641 int max = mParameters.getMaxExposureCompensation();
1642 int min = mParameters.getMinExposureCompensation();
1643 if (value >= min && value <= max) {
1644 mParameters.setExposureCompensation(value);
1645 } else {
1646 Log.w(TAG, "invalid exposure range: " + value);
1647 }
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001648 }
1649
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001650 private void updateParametersSceneMode() {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001651 SettingsManager settingsManager = mActivity.getSettingsManager();
1652
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001653 mSceneMode = settingsManager.get(SettingsManager.SETTING_SCENE_MODE);
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001654 if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
1655 if (!mParameters.getSceneMode().equals(mSceneMode)) {
1656 mParameters.setSceneMode(mSceneMode);
1657
1658 // Setting scene mode will change the settings of flash mode,
1659 // white balance, and focus mode. Here we read back the
1660 // parameters, so we can know those settings.
1661 mCameraDevice.setParameters(mParameters);
1662 mParameters = mCameraDevice.getParameters();
1663 }
1664 } else {
1665 mSceneMode = mParameters.getSceneMode();
1666 if (mSceneMode == null) {
1667 mSceneMode = Parameters.SCENE_MODE_AUTO;
1668 }
1669 }
1670
Michael Kolb8872c232013-01-29 10:33:22 -08001671 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1672 // Set flash mode.
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001673 updateParametersFlashMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001674
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001675 // Set white balance mode.
1676 updateParametersWhiteBalanceMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001677
1678 // Set focus mode.
1679 mFocusManager.overrideFocusMode(null);
1680 mParameters.setFocusMode(mFocusManager.getFocusMode());
1681 } else {
1682 mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1683 }
Michael Kolb8872c232013-01-29 10:33:22 -08001684 }
1685
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001686 private void updateParametersFlashMode() {
1687 SettingsManager settingsManager = mActivity.getSettingsManager();
1688
1689 String flashMode = settingsManager.get(SettingsManager.SETTING_FLASH_MODE);
1690 List<String> supportedFlash = mParameters.getSupportedFlashModes();
1691 if (CameraUtil.isSupported(flashMode, supportedFlash)) {
1692 mParameters.setFlashMode(flashMode);
1693 }
1694 }
1695
1696 private void updateParametersWhiteBalanceMode() {
1697 SettingsManager settingsManager = mActivity.getSettingsManager();
1698
1699 // Set white balance parameter.
1700 String whiteBalance = settingsManager.get(SettingsManager.SETTING_WHITE_BALANCE);
1701 if (CameraUtil.isSupported(whiteBalance,
1702 mParameters.getSupportedWhiteBalance())) {
1703 mParameters.setWhiteBalance(whiteBalance);
1704 }
1705 }
1706
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001707 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001708 private void updateAutoFocusMoveCallback() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001709 if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Angus Kong9ef99252013-07-18 18:04:19 -07001710 mCameraDevice.setAutoFocusMoveCallback(mHandler,
Angus Kong4f795b82013-09-16 14:25:35 -07001711 (CameraAFMoveCallback) mAutoFocusMoveCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001712 } else {
Angus Kong9ef99252013-07-18 18:04:19 -07001713 mCameraDevice.setAutoFocusMoveCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001714 }
1715 }
1716
1717 // We separate the parameters into several subsets, so we can update only
1718 // the subsets actually need updating. The PREFERENCE set needs extra
1719 // locking because the preference can be changed from GLThread as well.
1720 private void setCameraParameters(int updateSet) {
1721 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1722 updateCameraParametersInitialize();
1723 }
1724
1725 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1726 updateCameraParametersZoom();
1727 }
1728
1729 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001730 updateCameraParametersPreference();
Michael Kolb8872c232013-01-29 10:33:22 -08001731 }
1732
1733 mCameraDevice.setParameters(mParameters);
1734 }
1735
1736 // If the Camera is idle, update the parameters immediately, otherwise
1737 // accumulate them in mUpdateSet and update later.
1738 private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1739 mUpdateSet |= additionalUpdateSet;
1740 if (mCameraDevice == null) {
1741 // We will update all the parameters when we open the device, so
1742 // we don't need to do anything now.
1743 mUpdateSet = 0;
1744 return;
1745 } else if (isCameraIdle()) {
1746 setCameraParameters(mUpdateSet);
Michael Kolbd6954f32013-03-08 20:43:01 -08001747 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001748 mUpdateSet = 0;
1749 } else {
Angus Kong13e87c42013-11-25 10:02:47 -08001750 if (!mHandler.hasMessages(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1751 mHandler.sendEmptyMessageDelayed(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
Michael Kolb8872c232013-01-29 10:33:22 -08001752 }
1753 }
1754 }
1755
ztenghui7b265a62013-09-09 14:58:44 -07001756 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001757 public boolean isCameraIdle() {
Michael Kolb8872c232013-01-29 10:33:22 -08001758 return (mCameraState == IDLE) ||
1759 (mCameraState == PREVIEW_STOPPED) ||
1760 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
1761 && (mCameraState != SWITCHING_CAMERA));
1762 }
1763
ztenghui7b265a62013-09-09 14:58:44 -07001764 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001765 public boolean isImageCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001766 String action = mActivity.getIntent().getAction();
1767 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
Angus Kong6a8e8a12013-07-19 14:55:07 -07001768 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
Michael Kolb8872c232013-01-29 10:33:22 -08001769 }
1770
1771 private void setupCaptureParams() {
1772 Bundle myExtras = mActivity.getIntent().getExtras();
1773 if (myExtras != null) {
1774 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1775 mCropValue = myExtras.getString("crop");
1776 }
1777 }
1778
Michael Kolb8872c232013-01-29 10:33:22 -08001779 public void onSharedPreferenceChanged() {
1780 // ignore the events after "onPause()"
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001781 if (mPaused) {
1782 return;
1783 }
Michael Kolb8872c232013-01-29 10:33:22 -08001784
Erin Dahlgren357b7672013-11-20 17:38:14 -08001785 SettingsController settingsController = mActivity.getSettingsController();
1786 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001787
1788 setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
Michael Kolb8872c232013-01-29 10:33:22 -08001789 }
1790
Michael Kolb8872c232013-01-29 10:33:22 -08001791 private void showTapToFocusToast() {
1792 // TODO: Use a toast?
1793 new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
1794 // Clear the preference.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001795 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001796 settingsManager.setBoolean(
1797 SettingsManager.SETTING_CAMERA_FIRST_USE_HINT_SHOWN, false);
Michael Kolb8872c232013-01-29 10:33:22 -08001798 }
1799
1800 private void initializeCapabilities() {
1801 mInitialParams = mCameraDevice.getParameters();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001802 mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
1803 mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
1804 mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
1805 mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
Angus Kongdcccc512013-08-08 17:06:03 -07001806 mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001807 CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
Michael Kolb8872c232013-01-29 10:33:22 -08001808 }
1809
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001810 private void setShutterEnabled(boolean enabled) {
1811 mShutterEnabled = enabled;
1812 mUI.enableShutter(enabled);
1813 }
1814
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001815 // TODO: Remove this
Michael Kolb8872c232013-01-29 10:33:22 -08001816 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001817 public int onZoomChanged(int index) {
1818 // Not useful to change zoom value when the activity is paused.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001819 if (mPaused) {
1820 return index;
1821 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001822 mZoomValue = index;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001823 if (mParameters == null || mCameraDevice == null) {
1824 return index;
1825 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001826 // Set zoom parameters asynchronously
1827 mParameters.setZoom(mZoomValue);
Angus Kong36ed8672013-04-15 12:11:15 -07001828 mCameraDevice.setParameters(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -08001829 Parameters p = mCameraDevice.getParameters();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001830 if (p != null) {
1831 return p.getZoom();
1832 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001833 return index;
Angus Kongce5480e2013-01-29 17:43:48 -08001834 }
1835
1836 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001837 public int getCameraState() {
1838 return mCameraState;
1839 }
1840
1841 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001842 public void onMemoryStateChanged(int state) {
1843 setShutterEnabled(state == MemoryManager.STATE_OK);
Angus Kongce5480e2013-01-29 17:43:48 -08001844 }
Angus Kong86d36312013-01-31 18:22:44 -08001845
1846 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001847 public void onLowMemory() {
1848 // Not much we can do in the photo module.
Angus Kong86d36312013-01-31 18:22:44 -08001849 }
Angus Kong0d00a892013-03-26 11:40:40 -07001850
1851 @Override
1852 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1853 }
1854
1855 @Override
1856 public void onSensorChanged(SensorEvent event) {
1857 int type = event.sensor.getType();
1858 float[] data;
1859 if (type == Sensor.TYPE_ACCELEROMETER) {
1860 data = mGData;
1861 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
1862 data = mMData;
1863 } else {
1864 // we should not be here.
1865 return;
1866 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001867 for (int i = 0; i < 3; i++) {
Angus Kong0d00a892013-03-26 11:40:40 -07001868 data[i] = event.values[i];
1869 }
1870 float[] orientation = new float[3];
1871 SensorManager.getRotationMatrix(mR, null, mGData, mMData);
1872 SensorManager.getOrientation(mR, orientation);
1873 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
1874 if (mHeading < 0) {
1875 mHeading += 360;
1876 }
Angus Kong0d00a892013-03-26 11:40:40 -07001877 }
Doris Liu6432cd62013-06-13 17:20:31 -07001878
Ruben Brunkd217ed02013-10-08 23:31:13 -07001879 // For debugging only.
1880 public void setDebugUri(Uri uri) {
1881 mDebugUri = uri;
1882 }
1883
1884 // For debugging only.
1885 private void saveToDebugUri(byte[] data) {
1886 if (mDebugUri != null) {
1887 OutputStream outputStream = null;
1888 try {
1889 outputStream = mContentResolver.openOutputStream(mDebugUri);
1890 outputStream.write(data);
1891 outputStream.close();
1892 } catch (IOException e) {
1893 Log.e(TAG, "Exception while writing debug jpeg file", e);
1894 } finally {
1895 CameraUtil.closeSilently(outputStream);
1896 }
1897 }
1898 }
Michael Kolb8872c232013-01-29 10:33:22 -08001899}