blob: 158f07106b283d627a6f4204004c504dc807768c [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,
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080091 SensorEventListener {
Michael Kolb8872c232013-01-29 10:33:22 -080092
93 private static final String TAG = "CAM_PhotoModule";
94
95 // We number the request code from 1000 to avoid collision with Gallery.
96 private static final int REQUEST_CROP = 1000;
97
Angus Kong13e87c42013-11-25 10:02:47 -080098 // Messages defined for the UI thread handler.
Angus Kong1587b042014-01-02 18:09:27 -080099 private static final int MSG_FIRST_TIME_INIT = 1;
100 private static final int MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE = 2;
101 private static final int MSG_SHOW_TAP_TO_FOCUS_TOAST = 3;
102 private static final int MSG_SWITCH_TO_GCAM_MODULE = 4;
Michael Kolb8872c232013-01-29 10:33:22 -0800103
104 // The subset of parameters we need to update in setCameraParameters().
105 private static final int UPDATE_PARAM_INITIALIZE = 1;
106 private static final int UPDATE_PARAM_ZOOM = 2;
107 private static final int UPDATE_PARAM_PREFERENCE = 4;
108 private static final int UPDATE_PARAM_ALL = -1;
109
Andy Huibersdef975d2013-11-22 09:13:39 -0800110 // This is the delay before we execute onResume tasks when coming
111 // from the lock screen, to allow time for onPause to execute.
112 private static final int ON_RESUME_TASKS_DELAY_MSEC = 20;
Michael Kolb8872c232013-01-29 10:33:22 -0800113
Ruben Brunkd7488272013-10-10 18:45:53 -0700114 private static final String DEBUG_IMAGE_PREFIX = "DEBUG_";
115
Michael Kolb8872c232013-01-29 10:33:22 -0800116 // copied from Camera hierarchy
117 private CameraActivity mActivity;
Michael Kolb8872c232013-01-29 10:33:22 -0800118 private CameraProxy mCameraDevice;
119 private int mCameraId;
120 private Parameters mParameters;
121 private boolean mPaused;
Michael Kolbd6954f32013-03-08 20:43:01 -0800122
123 private PhotoUI mUI;
Michael Kolb8872c232013-01-29 10:33:22 -0800124
Michael Kolb8872c232013-01-29 10:33:22 -0800125 // The activity is going to switch to the specified camera id. This is
126 // needed because texture copy is done in GL thread. -1 means camera is not
127 // switching.
128 protected int mPendingSwitchCameraId = -1;
Michael Kolb8872c232013-01-29 10:33:22 -0800129
130 // When setCameraParametersWhenIdle() is called, we accumulate the subsets
131 // needed to be updated in mUpdateSet.
132 private int mUpdateSet;
133
134 private static final int SCREEN_DELAY = 2 * 60 * 1000;
135
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800136 private int mZoomValue; // The current zoom value.
Michael Kolb8872c232013-01-29 10:33:22 -0800137
138 private Parameters mInitialParams;
139 private boolean mFocusAreaSupported;
140 private boolean mMeteringAreaSupported;
141 private boolean mAeLockSupported;
142 private boolean mAwbLockSupported;
Angus Kongdcccc512013-08-08 17:06:03 -0700143 private boolean mContinuousFocusSupported;
Michael Kolb8872c232013-01-29 10:33:22 -0800144
145 // The degrees of the device rotated clockwise from its natural orientation.
146 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
Michael Kolb8872c232013-01-29 10:33:22 -0800147
148 private static final String sTempCropFilename = "crop-temp";
149
Michael Kolb8872c232013-01-29 10:33:22 -0800150 private boolean mFaceDetectionStarted = false;
151
Michael Kolb8872c232013-01-29 10:33:22 -0800152 // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
153 private String mCropValue;
154 private Uri mSaveUri;
155
Ruben Brunkd217ed02013-10-08 23:31:13 -0700156 private Uri mDebugUri;
157
Angus Kongce5480e2013-01-29 17:43:48 -0800158 // We use a queue to generated names of the images to be used later
159 // when the image is ready to be saved.
Michael Kolb8872c232013-01-29 10:33:22 -0800160 private NamedImages mNamedImages;
161
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800162 private final Runnable mDoSnapRunnable = new Runnable() {
Michael Kolb8872c232013-01-29 10:33:22 -0800163 @Override
164 public void run() {
165 onShutterButtonClick();
166 }
167 };
168
Michael Kolb8872c232013-01-29 10:33:22 -0800169 /**
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800170 * An unpublished intent flag requesting to return as soon as capturing is
171 * completed. TODO: consider publishing by moving into MediaStore.
Michael Kolb8872c232013-01-29 10:33:22 -0800172 */
173 private static final String EXTRA_QUICK_CAPTURE =
174 "android.intent.extra.quickCapture";
175
176 // The display rotation in degrees. This is only valid when mCameraState is
177 // not PREVIEW_STOPPED.
178 private int mDisplayRotation;
179 // The value for android.hardware.Camera.setDisplayOrientation.
180 private int mCameraDisplayOrientation;
181 // The value for UI components like indicators.
182 private int mDisplayOrientation;
183 // The value for android.hardware.Camera.Parameters.setRotation.
184 private int mJpegRotation;
Doris Liu29da2db2013-08-28 14:28:45 -0700185 // Indicates whether we are using front camera
186 private boolean mMirror;
Michael Kolb8872c232013-01-29 10:33:22 -0800187 private boolean mFirstTimeInitialized;
188 private boolean mIsImageCaptureIntent;
189
Michael Kolb8872c232013-01-29 10:33:22 -0800190 private int mCameraState = PREVIEW_STOPPED;
191 private boolean mSnapshotOnIdle = false;
192
193 private ContentResolver mContentResolver;
194
195 private LocationManager mLocationManager;
Doris Liu2b906b82013-12-10 16:34:08 -0800196 private AppController mAppController;
Michael Kolb8872c232013-01-29 10:33:22 -0800197
Michael Kolb8872c232013-01-29 10:33:22 -0800198 private final PostViewPictureCallback mPostViewPictureCallback =
199 new PostViewPictureCallback();
200 private final RawPictureCallback mRawPictureCallback =
201 new RawPictureCallback();
202 private final AutoFocusCallback mAutoFocusCallback =
203 new AutoFocusCallback();
204 private final Object mAutoFocusMoveCallback =
205 ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700206 ? new AutoFocusMoveCallback()
207 : null;
Michael Kolb8872c232013-01-29 10:33:22 -0800208
209 private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
210
211 private long mFocusStartTime;
212 private long mShutterCallbackTime;
213 private long mPostViewPictureCallbackTime;
214 private long mRawPictureCallbackTime;
215 private long mJpegPictureCallbackTime;
216 private long mOnResumeTime;
217 private byte[] mJpegImageData;
218
219 // These latency time are for the CameraLatency test.
220 public long mAutoFocusTime;
221 public long mShutterLag;
222 public long mShutterToPictureDisplayedTime;
223 public long mPictureDisplayedToJpegCallbackTime;
224 public long mJpegCallbackFinishTime;
225 public long mCaptureStartTime;
226
227 // This handles everything about focus.
228 private FocusOverlayManager mFocusManager;
229
Michael Kolb8872c232013-01-29 10:33:22 -0800230 private String mSceneMode;
Michael Kolb8872c232013-01-29 10:33:22 -0800231
232 private final Handler mHandler = new MainHandler();
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800233
Michael Kolb8872c232013-01-29 10:33:22 -0800234 private boolean mQuickCapture;
Angus Kong0d00a892013-03-26 11:40:40 -0700235 private SensorManager mSensorManager;
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800236 private final float[] mGData = new float[3];
237 private final float[] mMData = new float[3];
238 private final float[] mR = new float[16];
Angus Kong0d00a892013-03-26 11:40:40 -0700239 private int mHeading = -1;
240
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800241 /** Whether shutter is enabled. */
Spike Sprague215f6b02013-12-12 11:53:49 -0800242 private boolean mShutterEnabled = true;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800243
244 /** True if all the parameters needed to start preview is ready. */
Angus Kongdcccc512013-08-08 17:06:03 -0700245 private boolean mCameraPreviewParamsReady = false;
Doris Liu6432cd62013-06-13 17:20:31 -0700246
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800247 private final MediaSaver.OnMediaSavedListener mOnMediaSavedListener =
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800248 new MediaSaver.OnMediaSavedListener() {
Angus Kongce5480e2013-01-29 17:43:48 -0800249 @Override
250 public void onMediaSaved(Uri uri) {
251 if (uri != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700252 mActivity.notifyNewMedia(uri);
Angus Kongce5480e2013-01-29 17:43:48 -0800253 }
254 }
255 };
Michael Kolb8872c232013-01-29 10:33:22 -0800256
Angus Kongdcccc512013-08-08 17:06:03 -0700257 private void checkDisplayRotation() {
258 // Set the display orientation if display rotation has changed.
259 // Sometimes this happens when the device is held upside
260 // down and camera app is opened. Rotation animation will
261 // take some time and the rotation value we have got may be
262 // wrong. Framework does not have a callback for this now.
263 if (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) {
264 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -0800265 }
Angus Kongdcccc512013-08-08 17:06:03 -0700266 if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
267 mHandler.postDelayed(new Runnable() {
268 @Override
269 public void run() {
270 checkDisplayRotation();
271 }
272 }, 100);
Michael Kolb8872c232013-01-29 10:33:22 -0800273 }
274 }
275
276 /**
277 * This Handler is used to post message back onto the main thread of the
278 * application
279 */
280 private class MainHandler extends Handler {
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800281 public MainHandler() {
282 super(Looper.getMainLooper());
283 }
284
Michael Kolb8872c232013-01-29 10:33:22 -0800285 @Override
286 public void handleMessage(Message msg) {
287 switch (msg.what) {
Angus Kong13e87c42013-11-25 10:02:47 -0800288 case MSG_FIRST_TIME_INIT: {
Michael Kolb8872c232013-01-29 10:33:22 -0800289 initializeFirstTime();
290 break;
291 }
292
Angus Kong13e87c42013-11-25 10:02:47 -0800293 case MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE: {
Michael Kolb8872c232013-01-29 10:33:22 -0800294 setCameraParametersWhenIdle(0);
295 break;
296 }
297
Angus Kong13e87c42013-11-25 10:02:47 -0800298 case MSG_SHOW_TAP_TO_FOCUS_TOAST: {
Michael Kolb8872c232013-01-29 10:33:22 -0800299 showTapToFocusToast();
300 break;
301 }
302
Angus Kong13e87c42013-11-25 10:02:47 -0800303 case MSG_SWITCH_TO_GCAM_MODULE: {
Erin Dahlgrend7b8cb52013-11-14 17:25:37 -0800304 mActivity.onModeSelected(ModeListView.MODE_GCAM);
ztenghui367c7c82013-10-16 14:43:26 -0700305 }
Michael Kolb8872c232013-01-29 10:33:22 -0800306 }
307 }
308 }
309
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800310 /**
311 * Constructs a new photo module.
312 */
Angus Kongc4e66562013-11-22 23:03:21 -0800313 public PhotoModule(AppController app) {
314 super(app);
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800315 }
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700316
Angus Kong13e87c42013-11-25 10:02:47 -0800317
Michael Kolb8872c232013-01-29 10:33:22 -0800318 @Override
Angus Kong13e87c42013-11-25 10:02:47 -0800319 public void init(AppController app, boolean isSecureCamera, boolean isCaptureIntent) {
320 mActivity = (CameraActivity) app.getAndroidContext();
321 mUI = new PhotoUI(mActivity, this, app.getModuleLayoutRoot());
Doris Liu06db7422013-12-09 19:36:25 -0800322 app.setPreviewStatusListener(mUI);
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800323 app.getCameraAppUI().setBottomBarShutterListener(this);
Erin Dahlgren357b7672013-11-20 17:38:14 -0800324
325 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800326 mCameraId = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_CAMERA_ID));
Michael Kolb8872c232013-01-29 10:33:22 -0800327
328 mContentResolver = mActivity.getContentResolver();
329
Michael Kolb8872c232013-01-29 10:33:22 -0800330 // Surface texture is from camera screen nail and startPreview needs it.
331 // This must be done before startPreview.
332 mIsImageCaptureIntent = isImageCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800333
Angus Kong20fad242013-11-11 18:23:46 -0800334 mActivity.getCameraProvider().requestCamera(mCameraId);
335
Michael Kolb8872c232013-01-29 10:33:22 -0800336 initializeControlByIntent();
337 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800338 mLocationManager = mActivity.getLocationManager();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800339 mSensorManager = (SensorManager) (mActivity.getSystemService(Context.SENSOR_SERVICE));
Doris Liu2b906b82013-12-10 16:34:08 -0800340 mAppController = app;
Michael Kolbd6954f32013-03-08 20:43:01 -0800341 }
342
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800343 @Override
344 public boolean isUsingBottomBar() {
345 return true;
346 }
347
Michael Kolbd6954f32013-03-08 20:43:01 -0800348 private void initializeControlByIntent() {
349 mUI.initializeControlByIntent();
350 if (mIsImageCaptureIntent) {
351 setupCaptureParams();
352 }
353 }
354
355 private void onPreviewStarted() {
Doris Liu2b906b82013-12-10 16:34:08 -0800356 mAppController.onPreviewStarted();
Michael Kolbd6954f32013-03-08 20:43:01 -0800357 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800358 startFaceDetection();
Sameer Padala2c8cc452013-11-05 18:49:12 -0800359 startSmartCamera();
Michael Kolbd6954f32013-03-08 20:43:01 -0800360 locationFirstRun();
Michael Kolb8872c232013-01-29 10:33:22 -0800361 }
362
363 // Prompt the user to pick to record location for the very first run of
364 // camera only
365 private void locationFirstRun() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800366 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800367 if (settingsManager.isSet(SettingsManager.SETTING_RECORD_LOCATION)) {
Michael Kolb8872c232013-01-29 10:33:22 -0800368 return;
369 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800370 if (mActivity.isSecureCamera()) {
371 return;
372 }
Michael Kolb8872c232013-01-29 10:33:22 -0800373 // Check if the back camera exists
374 int backCameraId = CameraHolder.instance().getBackCameraId();
375 if (backCameraId == -1) {
376 // If there is no back camera, do not show the prompt.
377 return;
378 }
Doris Liu6a83d522013-07-02 12:03:32 -0700379 mUI.showLocationDialog();
380 }
Michael Kolb8872c232013-01-29 10:33:22 -0800381
ztenghui7b265a62013-09-09 14:58:44 -0700382 @Override
Angus Kongdcccc512013-08-08 17:06:03 -0700383 public void onPreviewUIReady() {
Erin Dahlgrendc282e12013-11-12 09:39:08 -0800384 startPreview();
Angus Kongdcccc512013-08-08 17:06:03 -0700385 }
386
387 @Override
388 public void onPreviewUIDestroyed() {
389 if (mCameraDevice == null) {
390 return;
391 }
392 mCameraDevice.setPreviewTexture(null);
393 stopPreview();
394 }
395
Doris Liu1dfe7822013-12-12 00:02:08 -0800396 @Override
397 public void startPreCaptureAnimation() {
398 mAppController.startPreCaptureAnimation();
399 }
400
Michael Kolbd6954f32013-03-08 20:43:01 -0800401 private void onCameraOpened() {
402 View root = mUI.getRootView();
Michael Kolb8872c232013-01-29 10:33:22 -0800403 // These depend on camera parameters.
Michael Kolbd6954f32013-03-08 20:43:01 -0800404
405 int width = root.getWidth();
406 int height = root.getHeight();
Doris Liu15b99612013-12-21 11:32:28 -0800407 mFocusManager.setPreviewRect(new Rect(0, 0, width, height));
Michael Kolbd6954f32013-03-08 20:43:01 -0800408 openCameraCommon();
Michael Kolb8872c232013-01-29 10:33:22 -0800409 }
410
Michael Kolbd6954f32013-03-08 20:43:01 -0800411 private void switchCamera() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800412 if (mPaused) {
413 return;
414 }
Erin Dahlgren357b7672013-11-20 17:38:14 -0800415 SettingsManager settingsManager = mActivity.getSettingsManager();
Michael Kolbd6954f32013-03-08 20:43:01 -0800416
417 Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
418 mCameraId = mPendingSwitchCameraId;
419 mPendingSwitchCameraId = -1;
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800420 settingsManager.set(SettingsManager.SETTING_CAMERA_ID, "" + mCameraId);
Angus Kong20fad242013-11-11 18:23:46 -0800421 mActivity.getCameraProvider().requestCamera(mCameraId);
Michael Kolbd6954f32013-03-08 20:43:01 -0800422 mUI.clearFaces();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800423 if (mFocusManager != null) {
424 mFocusManager.removeMessages();
425 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800426
Erin Dahlgren357b7672013-11-20 17:38:14 -0800427 // TODO: this needs to be brought into onCameraAvailable();
Angus Kong20fad242013-11-11 18:23:46 -0800428 CameraInfo info = mActivity.getCameraProvider().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -0700429 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
430 mFocusManager.setMirror(mMirror);
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700431 // Start switch camera animation. Post a message because
432 // onFrameAvailable from the old camera may already exist.
Doris Liu48239f42013-03-04 22:19:10 -0800433 }
434
Sascha Haeberling29f60562013-12-10 12:18:56 -0800435 private final ButtonManager.ButtonCallback mCameraButtonCallback =
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800436 new ButtonManager.ButtonCallback() {
437 @Override
438 public void onStateChanged(int state) {
439 if (mPaused || mPendingSwitchCameraId != -1) {
440 return;
441 }
442 mPendingSwitchCameraId = state;
443
444 Log.v(TAG, "Start to switch camera. cameraId=" + state);
445 // We need to keep a preview frame for the animation before
446 // releasing the camera. This will trigger onPreviewTextureCopied.
447 //TODO: Need to animate the camera switch
448 switchCamera();
449 }
450 };
451
Sascha Haeberling29f60562013-12-10 12:18:56 -0800452 private final ButtonManager.ButtonCallback mHdrPlusButtonCallback =
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800453 new ButtonManager.ButtonCallback() {
454 @Override
455 public void onStateChanged(int state) {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -0800456 if (GcamHelper.hasGcamCapture()) {
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800457 // Set the camera setting to default backfacing.
458 SettingsManager settingsManager = mActivity.getSettingsManager();
459 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_ID);
Erin Dahlgrenba6994d2013-12-12 16:04:38 -0800460 mHandler.sendEmptyMessage(MSG_SWITCH_TO_GCAM_MODULE);
461 } else {
462 mSceneMode = CameraUtil.SCENE_MODE_HDR;
463 updateParametersSceneMode();
464 }
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800465 }
466 };
467
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800468 private final ButtonManager.ButtonCallback mRefocusButtonCallback =
469 new ButtonManager.ButtonCallback() {
470 @Override
471 public void onStateChanged(int state) {
472 if (state == ButtonManager.OFF) {
473 throw new IllegalStateException(
474 "Can't switch refocus off because it should already be off.");
475 }
476 mActivity.onModeSelected(ModeListView.MODE_REFOCUS);
477 }
478 };
479
Michael Kolbd6954f32013-03-08 20:43:01 -0800480 // either open a new camera or switch cameras
481 private void openCameraCommon() {
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800482 mUI.onCameraOpened(mParameters, mCameraButtonCallback, mHdrPlusButtonCallback,
483 mRefocusButtonCallback);
Angus Kong0fb819b2013-10-08 13:44:19 -0700484 if (mIsImageCaptureIntent) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800485 // Set hdr plus to default: off.
486 SettingsManager settingsManager = mActivity.getSettingsManager();
487 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_HDR_PLUS);
Angus Kong0fb819b2013-10-08 13:44:19 -0700488 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800489 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -0800490 }
491
ztenghui7b265a62013-09-09 14:58:44 -0700492 @Override
Doris Liu36ebcb12013-10-28 14:44:24 -0700493 public void onPreviewRectChanged(Rect previewRect) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800494 if (mFocusManager != null)
495 mFocusManager.setPreviewRect(previewRect);
Michael Kolbd6954f32013-03-08 20:43:01 -0800496 }
Michael Kolb8872c232013-01-29 10:33:22 -0800497
Doris Liu70da9182013-12-17 18:41:15 -0800498 @Override
499 public void updatePreviewAspectRatio(float aspectRatio) {
500 mAppController.updatePreviewAspectRatio(aspectRatio);
501 }
502
Michael Kolb8872c232013-01-29 10:33:22 -0800503 private void resetExposureCompensation() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800504 SettingsManager settingsManager = mActivity.getSettingsManager();
505 if (settingsManager == null) {
506 Log.e(TAG, "Settings manager is null!");
507 return;
Michael Kolb8872c232013-01-29 10:33:22 -0800508 }
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800509 settingsManager.setDefault(SettingsManager.SETTING_EXPOSURE);
Michael Kolb8872c232013-01-29 10:33:22 -0800510 }
511
Michael Kolb8872c232013-01-29 10:33:22 -0800512 // Snapshots can only be taken after this is called. It should be called
513 // once only. We could have done these things in onCreate() but we want to
514 // make preview screen appear as soon as possible.
515 private void initializeFirstTime() {
Sascha Haeberling330dafb2013-10-10 19:00:41 -0700516 if (mFirstTimeInitialized || mPaused) {
517 return;
518 }
Michael Kolb8872c232013-01-29 10:33:22 -0800519
520 // Initialize location service.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800521 SettingsController settingsController = mActivity.getSettingsController();
522 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -0800523
Michael Kolbd6954f32013-03-08 20:43:01 -0800524 mUI.initializeFirstTime();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800525
Angus Kong86d36312013-01-31 18:22:44 -0800526 // We set the listener only when both service and shutterbutton
527 // are initialized.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800528 getServices().getMemoryManager().addListener(this);
Michael Kolb8872c232013-01-29 10:33:22 -0800529
Michael Kolb8872c232013-01-29 10:33:22 -0800530 mNamedImages = new NamedImages();
531
532 mFirstTimeInitialized = true;
533 addIdleHandler();
534
535 mActivity.updateStorageSpaceAndHint();
536 }
537
Michael Kolbd6954f32013-03-08 20:43:01 -0800538 // If the activity is paused and resumed, this method will be called in
539 // onResume.
540 private void initializeSecondTime() {
541 // Start location update if needed.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800542 SettingsController settingsController = mActivity.getSettingsController();
543 settingsController.syncLocationManager();
544
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800545 getServices().getMemoryManager().addListener(this);
Michael Kolbd6954f32013-03-08 20:43:01 -0800546 mNamedImages = new NamedImages();
547 mUI.initializeSecondTime(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -0800548 }
549
Michael Kolb8872c232013-01-29 10:33:22 -0800550 private void addIdleHandler() {
551 MessageQueue queue = Looper.myQueue();
552 queue.addIdleHandler(new MessageQueue.IdleHandler() {
553 @Override
554 public boolean queueIdle() {
555 Storage.ensureOSXCompatible();
556 return false;
557 }
558 });
559 }
560
Sameer Padala2c8cc452013-11-05 18:49:12 -0800561 private void startSmartCamera() {
562 SmartCameraHelper.register(mCameraDevice, mParameters.getPreviewSize(), mActivity,
Doris Liu773e1c92013-12-02 17:35:03 -0800563 (ViewGroup) mActivity.findViewById(R.id.camera_app_root));
Sameer Padala2c8cc452013-11-05 18:49:12 -0800564 }
565
566 private void stopSmartCamera() {
567 SmartCameraHelper.tearDown();
568 }
569
Michael Kolb8872c232013-01-29 10:33:22 -0800570 @Override
571 public void startFaceDetection() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800572 if (mFaceDetectionStarted) {
573 return;
574 }
Michael Kolb8872c232013-01-29 10:33:22 -0800575 if (mParameters.getMaxNumDetectedFaces() > 0) {
576 mFaceDetectionStarted = true;
Michael Kolb8872c232013-01-29 10:33:22 -0800577 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Michael Kolbd6954f32013-03-08 20:43:01 -0800578 mUI.onStartFaceDetection(mDisplayOrientation,
579 (info.facing == CameraInfo.CAMERA_FACING_FRONT));
Angus Kong9e765522013-07-31 14:05:20 -0700580 mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Michael Kolb8872c232013-01-29 10:33:22 -0800581 mCameraDevice.startFaceDetection();
582 }
583 }
584
Michael Kolb8872c232013-01-29 10:33:22 -0800585 @Override
586 public void stopFaceDetection() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800587 if (!mFaceDetectionStarted) {
588 return;
589 }
Michael Kolb8872c232013-01-29 10:33:22 -0800590 if (mParameters.getMaxNumDetectedFaces() > 0) {
591 mFaceDetectionStarted = false;
Angus Kong9e765522013-07-31 14:05:20 -0700592 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -0800593 mCameraDevice.stopFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800594 mUI.clearFaces();
Michael Kolb8872c232013-01-29 10:33:22 -0800595 }
596 }
597
Michael Kolb8872c232013-01-29 10:33:22 -0800598 private final class ShutterCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700599 implements CameraShutterCallback {
Angus Kongdcb0ef12013-03-25 23:11:43 -0700600
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800601 private final boolean mNeedsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700602
Sascha Haeberling37f36112013-08-06 14:31:52 -0700603 public ShutterCallback(boolean needsAnimation) {
604 mNeedsAnimation = needsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700605 }
606
Michael Kolb8872c232013-01-29 10:33:22 -0800607 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700608 public void onShutter(CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800609 mShutterCallbackTime = System.currentTimeMillis();
610 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
611 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Sascha Haeberling37f36112013-08-06 14:31:52 -0700612 if (mNeedsAnimation) {
613 mActivity.runOnUiThread(new Runnable() {
614 @Override
615 public void run() {
616 animateAfterShutter();
617 }
618 });
Angus Kongdcb0ef12013-03-25 23:11:43 -0700619 }
Michael Kolb8872c232013-01-29 10:33:22 -0800620 }
621 }
622
Angus Kong9ef99252013-07-18 18:04:19 -0700623 private final class PostViewPictureCallback
624 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800625 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800626 public void onPictureTaken(byte[] data, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800627 mPostViewPictureCallbackTime = System.currentTimeMillis();
628 Log.v(TAG, "mShutterToPostViewCallbackTime = "
629 + (mPostViewPictureCallbackTime - mShutterCallbackTime)
630 + "ms");
631 }
632 }
633
Angus Kong9ef99252013-07-18 18:04:19 -0700634 private final class RawPictureCallback
635 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800636 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800637 public void onPictureTaken(byte[] rawData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800638 mRawPictureCallbackTime = System.currentTimeMillis();
639 Log.v(TAG, "mShutterToRawCallbackTime = "
640 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
641 }
642 }
643
Angus Kong9ef99252013-07-18 18:04:19 -0700644 private final class JpegPictureCallback
645 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800646 Location mLocation;
647
648 public JpegPictureCallback(Location loc) {
649 mLocation = loc;
650 }
651
652 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800653 public void onPictureTaken(final byte[] jpegData, CameraProxy camera) {
654 setShutterEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800655 if (mPaused) {
656 return;
657 }
Doris Liu6432cd62013-06-13 17:20:31 -0700658 if (mIsImageCaptureIntent) {
659 stopPreview();
660 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700661 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -0700662 mUI.setSwipingEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800663 }
664
665 mJpegPictureCallbackTime = System.currentTimeMillis();
666 // If postview callback has arrived, the captured image is displayed
667 // in postview callback. If not, the captured image is displayed in
668 // raw picture callback.
669 if (mPostViewPictureCallbackTime != 0) {
670 mShutterToPictureDisplayedTime =
671 mPostViewPictureCallbackTime - mShutterCallbackTime;
672 mPictureDisplayedToJpegCallbackTime =
673 mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
674 } else {
675 mShutterToPictureDisplayedTime =
676 mRawPictureCallbackTime - mShutterCallbackTime;
677 mPictureDisplayedToJpegCallbackTime =
678 mJpegPictureCallbackTime - mRawPictureCallbackTime;
679 }
680 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
681 + mPictureDisplayedToJpegCallbackTime + "ms");
682
Michael Kolb8872c232013-01-29 10:33:22 -0800683 mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
684 if (!mIsImageCaptureIntent) {
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700685 setupPreview();
Michael Kolb8872c232013-01-29 10:33:22 -0800686 }
687
Doris Liu36e56fb2013-09-11 17:38:08 -0700688 ExifInterface exif = Exif.getExif(jpegData);
689 int orientation = Exif.getOrientation(exif);
Ruben Brunkd217ed02013-10-08 23:31:13 -0700690
Ruben Brunkd7488272013-10-10 18:45:53 -0700691 if (!mIsImageCaptureIntent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800692 // Calculate the width and the height of the jpeg.
693 Size s = mParameters.getPictureSize();
Michael Kolb8872c232013-01-29 10:33:22 -0800694 int width, height;
695 if ((mJpegRotation + orientation) % 180 == 0) {
696 width = s.width;
697 height = s.height;
698 } else {
699 width = s.height;
700 height = s.width;
701 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700702 NamedEntity name = mNamedImages.getNextNameEntity();
703 String title = (name == null) ? null : name.title;
704 long date = (name == null) ? -1 : name.date;
Ruben Brunkd7488272013-10-10 18:45:53 -0700705
706 // Handle debug mode outputs
707 if (mDebugUri != null) {
708 // If using a debug uri, save jpeg there.
709 saveToDebugUri(jpegData);
710
711 // Adjust the title of the debug image shown in mediastore.
712 if (title != null) {
713 title = DEBUG_IMAGE_PREFIX + title;
714 }
715 }
716
Michael Kolb8872c232013-01-29 10:33:22 -0800717 if (title == null) {
718 Log.e(TAG, "Unbalanced name/data pair");
719 } else {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800720 if (date == -1)
721 date = mCaptureStartTime;
Angus Kong0d00a892013-03-26 11:40:40 -0700722 if (mHeading >= 0) {
723 // heading direction has been updated by the sensor.
724 ExifTag directionRefTag = exif.buildTag(
725 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
726 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
727 ExifTag directionTag = exif.buildTag(
728 ExifInterface.TAG_GPS_IMG_DIRECTION,
729 new Rational(mHeading, 1));
730 exif.setTag(directionRefTag);
731 exif.setTag(directionTag);
732 }
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800733 getServices().getMediaSaver().addImage(
Angus Kong86d36312013-01-31 18:22:44 -0800734 jpegData, title, date, mLocation, width, height,
Angus Kong0d00a892013-03-26 11:40:40 -0700735 orientation, exif, mOnMediaSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -0800736 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800737 // Animate capture with real jpeg data instead of a preview
738 // frame.
Doris Liu29da2db2013-08-28 14:28:45 -0700739 mUI.animateCapture(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800740 } else {
741 mJpegImageData = jpegData;
742 if (!mQuickCapture) {
Doris Liu36e56fb2013-09-11 17:38:08 -0700743 mUI.showCapturedImageForReview(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800744 } else {
Michael Kolbd6954f32013-03-08 20:43:01 -0800745 onCaptureDone();
Michael Kolb8872c232013-01-29 10:33:22 -0800746 }
747 }
748
749 // Check this in advance of each shot so we don't add to shutter
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800750 // latency. It's true that someone else could write to the SD card
751 // in the mean time and fill it, but that could have happened
752 // between the shutter press and saving the JPEG too.
Michael Kolb8872c232013-01-29 10:33:22 -0800753 mActivity.updateStorageSpaceAndHint();
754
755 long now = System.currentTimeMillis();
756 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
757 Log.v(TAG, "mJpegCallbackFinishTime = "
758 + mJpegCallbackFinishTime + "ms");
759 mJpegPictureCallbackTime = 0;
760 }
761 }
762
Angus Kong9ef99252013-07-18 18:04:19 -0700763 private final class AutoFocusCallback implements CameraAFCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800764 @Override
765 public void onAutoFocus(
Angus Kong9ef99252013-07-18 18:04:19 -0700766 boolean focused, CameraProxy camera) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800767 if (mPaused) {
768 return;
769 }
Michael Kolb8872c232013-01-29 10:33:22 -0800770
771 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
772 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
773 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800774 mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
Michael Kolb8872c232013-01-29 10:33:22 -0800775 }
776 }
777
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700778 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -0800779 private final class AutoFocusMoveCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700780 implements CameraAFMoveCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800781 @Override
782 public void onAutoFocusMoving(
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700783 boolean moving, CameraProxy camera) {
784 mFocusManager.onAutoFocusMoving(moving);
Michael Kolb8872c232013-01-29 10:33:22 -0800785 }
786 }
787
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700788 /**
789 * This class is just a thread-safe queue for name,date holder objects.
790 */
791 public static class NamedImages {
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800792 private final Vector<NamedEntity> mQueue;
Michael Kolb8872c232013-01-29 10:33:22 -0800793
794 public NamedImages() {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700795 mQueue = new Vector<NamedEntity>();
Michael Kolb8872c232013-01-29 10:33:22 -0800796 }
797
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700798 public void nameNewImage(long date) {
Michael Kolb8872c232013-01-29 10:33:22 -0800799 NamedEntity r = new NamedEntity();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700800 r.title = CameraUtil.createJpegName(date);
Michael Kolb8872c232013-01-29 10:33:22 -0800801 r.date = date;
802 mQueue.add(r);
803 }
804
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700805 public NamedEntity getNextNameEntity() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800806 synchronized (mQueue) {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700807 if (!mQueue.isEmpty()) {
808 return mQueue.remove(0);
809 }
Michael Kolb8872c232013-01-29 10:33:22 -0800810 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700811 return null;
Michael Kolb8872c232013-01-29 10:33:22 -0800812 }
813
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700814 public static class NamedEntity {
815 public String title;
816 public long date;
Michael Kolb8872c232013-01-29 10:33:22 -0800817 }
818 }
819
820 private void setCameraState(int state) {
821 mCameraState = state;
822 switch (state) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700823 case PhotoController.PREVIEW_STOPPED:
824 case PhotoController.SNAPSHOT_IN_PROGRESS:
825 case PhotoController.SWITCHING_CAMERA:
Doris Liuf55f3c42013-11-20 00:24:46 -0800826 // TODO: Tell app UI to disable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700827 break;
828 case PhotoController.IDLE:
Doris Liuf55f3c42013-11-20 00:24:46 -0800829 // TODO: Tell app UI to enable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700830 break;
Michael Kolb8872c232013-01-29 10:33:22 -0800831 }
832 }
833
Sascha Haeberling37f36112013-08-06 14:31:52 -0700834 private void animateAfterShutter() {
Michael Kolb8872c232013-01-29 10:33:22 -0800835 // Only animate when in full screen capture mode
836 // i.e. If monkey/a user swipes to the gallery during picture taking,
837 // don't show animation
Doris Liuc2e9abd2013-06-19 14:20:51 -0700838 if (!mIsImageCaptureIntent) {
839 mUI.animateFlash();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700840 }
Michael Kolb8872c232013-01-29 10:33:22 -0800841 }
842
843 @Override
844 public boolean capture() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800845 // If we are already in the middle of taking a snapshot or the image
846 // save request is full then ignore.
Michael Kolb8872c232013-01-29 10:33:22 -0800847 if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800848 || mCameraState == SWITCHING_CAMERA || !mShutterEnabled) {
Michael Kolb8872c232013-01-29 10:33:22 -0800849 return false;
850 }
851 mCaptureStartTime = System.currentTimeMillis();
852 mPostViewPictureCallbackTime = 0;
853 mJpegImageData = null;
854
Angus Kongb50b5cb2013-08-09 14:55:20 -0700855 final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
Michael Kolb8872c232013-01-29 10:33:22 -0800856
857 if (animateBefore) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700858 animateAfterShutter();
Michael Kolb8872c232013-01-29 10:33:22 -0800859 }
860
861 // Set rotation and gps data.
Doris Liu3cf565c2013-02-15 10:55:37 -0800862 int orientation;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800863
Doris Liu3cf565c2013-02-15 10:55:37 -0800864 // We need to be consistent with the framework orientation (i.e. the
865 // orientation of the UI.) when the auto-rotate screen setting is on.
866 if (mActivity.isAutoRotateScreen()) {
867 orientation = (360 - mDisplayRotation) % 360;
868 } else {
869 orientation = mOrientation;
870 }
Angus Kong20fad242013-11-11 18:23:46 -0800871 mJpegRotation = CameraUtil.getJpegRotation(mActivity, mCameraId, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800872 mParameters.setRotation(mJpegRotation);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800873 Location loc = mActivity.getLocationManager().getCurrentLocation();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700874 CameraUtil.setGpsParameters(mParameters, loc);
Michael Kolb8872c232013-01-29 10:33:22 -0800875 mCameraDevice.setParameters(mParameters);
876
Sascha Haeberling88901942013-08-28 17:49:00 -0700877 // We don't want user to press the button again while taking a
878 // multi-second HDR photo.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800879 setShutterEnabled(false);
Angus Kong9ef99252013-07-18 18:04:19 -0700880 mCameraDevice.takePicture(mHandler,
881 new ShutterCallback(!animateBefore),
Angus Kongdcb0ef12013-03-25 23:11:43 -0700882 mRawPictureCallback, mPostViewPictureCallback,
Angus Kong9ef99252013-07-18 18:04:19 -0700883 new JpegPictureCallback(loc));
Michael Kolb8872c232013-01-29 10:33:22 -0800884
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700885 mNamedImages.nameNewImage(mCaptureStartTime);
Michael Kolb8872c232013-01-29 10:33:22 -0800886
887 mFaceDetectionStarted = false;
888 setCameraState(SNAPSHOT_IN_PROGRESS);
Bobby Georgescu301b6462013-04-01 15:33:17 -0700889 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
Seth Raphaelcbd82672013-11-05 10:12:36 -0800890 UsageStatistics.ACTION_CAPTURE_DONE, "Photo", 0,
Seth Raphael44973262013-11-27 14:29:24 -0800891 UsageStatistics.hashFileName(mNamedImages.mQueue.lastElement().title + ".jpg"));
Michael Kolb8872c232013-01-29 10:33:22 -0800892 return true;
893 }
894
895 @Override
896 public void setFocusParameters() {
897 setCameraParameters(UPDATE_PARAM_PREFERENCE);
898 }
899
Michael Kolbd6954f32013-03-08 20:43:01 -0800900 private void updateSceneMode() {
Michael Kolb8872c232013-01-29 10:33:22 -0800901 // If scene mode is set, we cannot set flash mode, white balance, and
902 // focus mode, instead, we read it from driver
903 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
904 overrideCameraSettings(mParameters.getFlashMode(),
905 mParameters.getWhiteBalance(), mParameters.getFocusMode());
906 } else {
907 overrideCameraSettings(null, null, null);
908 }
909 }
910
911 private void overrideCameraSettings(final String flashMode,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800912 final String whiteBalance, final String focusMode) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800913 SettingsManager settingsManager = mActivity.getSettingsManager();
914 settingsManager.set(SettingsManager.SETTING_FLASH_MODE, flashMode);
915 settingsManager.set(SettingsManager.SETTING_WHITE_BALANCE, whiteBalance);
916 settingsManager.set(SettingsManager.SETTING_FOCUS_MODE, focusMode);
Michael Kolb8872c232013-01-29 10:33:22 -0800917 }
918
919 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800920 public void onOrientationChanged(int orientation) {
921 // We keep the last known orientation. So if the user first orient
922 // the camera then point the camera to floor or sky, we still have
923 // the correct orientation.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800924 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
925 return;
926 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700927 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800928
929 // Show the toast after getting the first orientation changed.
Angus Kong13e87c42013-11-25 10:02:47 -0800930 if (mHandler.hasMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST)) {
931 mHandler.removeMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST);
Michael Kolb8872c232013-01-29 10:33:22 -0800932 showTapToFocusToast();
933 }
934 }
935
936 @Override
Angus Kong20fad242013-11-11 18:23:46 -0800937 public void onCameraAvailable(CameraProxy cameraProxy) {
938 if (mPaused) {
939 return;
940 }
941 mCameraDevice = cameraProxy;
942
Erin Dahlgren357b7672013-11-20 17:38:14 -0800943 resetExposureCompensation();
Angus Kong20fad242013-11-11 18:23:46 -0800944 initializeCapabilities();
945
946 // Reset zoom value index.
947 mZoomValue = 0;
948 if (mFocusManager == null) {
949 initializeFocusManager();
950 }
951 mFocusManager.setParameters(mInitialParams);
952
953 mParameters = mCameraDevice.getParameters();
954 setCameraParameters(UPDATE_PARAM_ALL);
955 mCameraPreviewParamsReady = true;
956 startPreview();
957
958 onCameraOpened();
959 }
960
961 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -0800962 public void onCaptureCancelled() {
963 mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
964 mActivity.finish();
Michael Kolb8872c232013-01-29 10:33:22 -0800965 }
966
Michael Kolbd6954f32013-03-08 20:43:01 -0800967 @Override
968 public void onCaptureRetake() {
Michael Kolb8872c232013-01-29 10:33:22 -0800969 if (mPaused)
970 return;
Michael Kolbd6954f32013-03-08 20:43:01 -0800971 mUI.hidePostCaptureAlert();
Michael Kolb8872c232013-01-29 10:33:22 -0800972 setupPreview();
973 }
974
Michael Kolbd6954f32013-03-08 20:43:01 -0800975 @Override
976 public void onCaptureDone() {
Michael Kolb8872c232013-01-29 10:33:22 -0800977 if (mPaused) {
978 return;
979 }
980
981 byte[] data = mJpegImageData;
982
983 if (mCropValue == null) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800984 // First handle the no crop case -- just return the value. If the
Michael Kolb8872c232013-01-29 10:33:22 -0800985 // caller specifies a "save uri" then write the data to its
986 // stream. Otherwise, pass back a scaled down version of the bitmap
987 // directly in the extras.
988 if (mSaveUri != null) {
989 OutputStream outputStream = null;
990 try {
991 outputStream = mContentResolver.openOutputStream(mSaveUri);
992 outputStream.write(data);
993 outputStream.close();
994
995 mActivity.setResultEx(Activity.RESULT_OK);
996 mActivity.finish();
997 } catch (IOException ex) {
998 // ignore exception
999 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001000 CameraUtil.closeSilently(outputStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001001 }
1002 } else {
Angus Kong0d00a892013-03-26 11:40:40 -07001003 ExifInterface exif = Exif.getExif(data);
1004 int orientation = Exif.getOrientation(exif);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001005 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
1006 bitmap = CameraUtil.rotate(bitmap, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001007 mActivity.setResultEx(Activity.RESULT_OK,
1008 new Intent("inline-data").putExtra("data", bitmap));
1009 mActivity.finish();
1010 }
1011 } else {
1012 // Save the image to a temp file and invoke the cropper
1013 Uri tempUri = null;
1014 FileOutputStream tempStream = null;
1015 try {
1016 File path = mActivity.getFileStreamPath(sTempCropFilename);
1017 path.delete();
1018 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1019 tempStream.write(data);
1020 tempStream.close();
1021 tempUri = Uri.fromFile(path);
1022 } catch (FileNotFoundException ex) {
1023 mActivity.setResultEx(Activity.RESULT_CANCELED);
1024 mActivity.finish();
1025 return;
1026 } catch (IOException ex) {
1027 mActivity.setResultEx(Activity.RESULT_CANCELED);
1028 mActivity.finish();
1029 return;
1030 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001031 CameraUtil.closeSilently(tempStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001032 }
1033
1034 Bundle newExtras = new Bundle();
1035 if (mCropValue.equals("circle")) {
1036 newExtras.putString("circleCrop", "true");
1037 }
1038 if (mSaveUri != null) {
1039 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1040 } else {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001041 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001042 }
1043 if (mActivity.isSecureCamera()) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001044 newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001045 }
1046
Sascha Haeberling37f36112013-08-06 14:31:52 -07001047 // TODO: Share this constant.
Sascha Haeberling8e963a52013-08-06 11:43:02 -07001048 final String CROP_ACTION = "com.android.camera.action.CROP";
1049 Intent cropIntent = new Intent(CROP_ACTION);
Michael Kolb8872c232013-01-29 10:33:22 -08001050
1051 cropIntent.setData(tempUri);
1052 cropIntent.putExtras(newExtras);
1053
1054 mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1055 }
1056 }
1057
Michael Kolb8872c232013-01-29 10:33:22 -08001058 @Override
1059 public void onShutterButtonFocus(boolean pressed) {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001060 if (mPaused || (mCameraState == SNAPSHOT_IN_PROGRESS)
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001061 || (mCameraState == PREVIEW_STOPPED)) {
1062 return;
1063 }
Michael Kolb8872c232013-01-29 10:33:22 -08001064
1065 // Do not do focus if there is not enough storage.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001066 if (pressed && !canTakePicture()) {
1067 return;
1068 }
Michael Kolb8872c232013-01-29 10:33:22 -08001069
1070 if (pressed) {
Michael Kolb8872c232013-01-29 10:33:22 -08001071 mFocusManager.onShutterDown();
1072 } else {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001073 mFocusManager.onShutterUp();
Michael Kolb8872c232013-01-29 10:33:22 -08001074 }
1075 }
1076
1077 @Override
1078 public void onShutterButtonClick() {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001079 if (mPaused || (mCameraState == SWITCHING_CAMERA)
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001080 || (mCameraState == PREVIEW_STOPPED)) {
1081 return;
1082 }
Michael Kolb8872c232013-01-29 10:33:22 -08001083
1084 // Do not take the picture if there is not enough storage.
Angus Kong2dcc0a92013-09-25 13:00:08 -07001085 if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Michael Kolb8872c232013-01-29 10:33:22 -08001086 Log.i(TAG, "Not enough space or storage not ready. remaining="
Angus Kong2dcc0a92013-09-25 13:00:08 -07001087 + mActivity.getStorageSpaceBytes());
Michael Kolb8872c232013-01-29 10:33:22 -08001088 return;
1089 }
1090 Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1091
Angus Kongb50b5cb2013-08-09 14:55:20 -07001092 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -07001093 mUI.setSwipingEnabled(false);
Doris Liu9cdfe002013-04-16 09:50:56 -07001094 }
Michael Kolb8872c232013-01-29 10:33:22 -08001095 // If the user wants to do a snapshot while the previous one is still
1096 // in progress, remember the fact and do it after we finish the previous
1097 // one and re-start the preview. Snapshot in progress also includes the
1098 // state that autofocus is focusing and a picture will be taken when
1099 // focus callback arrives.
1100 if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1101 && !mIsImageCaptureIntent) {
1102 mSnapshotOnIdle = true;
1103 return;
1104 }
1105
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001106 mSnapshotOnIdle = false;
1107 mFocusManager.doSnap();
Michael Kolb8872c232013-01-29 10:33:22 -08001108 }
1109
Andy Huibersdef975d2013-11-22 09:13:39 -08001110 private void onResumeTasks() {
1111 Log.v(TAG, "Executing onResumeTasks.");
Angus Kong20fad242013-11-11 18:23:46 -08001112 mActivity.getCameraProvider().requestCamera(mCameraId);
1113
Michael Kolb8872c232013-01-29 10:33:22 -08001114 mJpegPictureCallbackTime = 0;
1115 mZoomValue = 0;
Angus Kong20fad242013-11-11 18:23:46 -08001116
1117 mOnResumeTime = SystemClock.uptimeMillis();
1118 checkDisplayRotation();
Michael Kolb8872c232013-01-29 10:33:22 -08001119
1120 // If first time initialization is not finished, put it in the
1121 // message queue.
1122 if (!mFirstTimeInitialized) {
Angus Kong13e87c42013-11-25 10:02:47 -08001123 mHandler.sendEmptyMessage(MSG_FIRST_TIME_INIT);
Michael Kolb8872c232013-01-29 10:33:22 -08001124 } else {
1125 initializeSecondTime();
1126 }
Michael Kolb8872c232013-01-29 10:33:22 -08001127
Bobby Georgescu0a7dd572013-03-12 22:45:17 -07001128 UsageStatistics.onContentViewChanged(
1129 UsageStatistics.COMPONENT_CAMERA, "PhotoModule");
Angus Kong0d00a892013-03-26 11:40:40 -07001130
1131 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1132 if (gsensor != null) {
1133 mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1134 }
1135
1136 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1137 if (msensor != null) {
1138 mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1139 }
Michael Kolb8872c232013-01-29 10:33:22 -08001140 }
1141
Angus Kongc4e66562013-11-22 23:03:21 -08001142 /**
1143 * The focus manager is the first UI related element to get initialized,
1144 * and it requires the RenderOverlay, so initialize it here
1145 */
1146 private void initializeFocusManager() {
1147 // Create FocusManager object. startPreview needs it.
1148 // if mFocusManager not null, reuse it
1149 // otherwise create a new instance
1150 if (mFocusManager != null) {
1151 mFocusManager.removeMessages();
1152 } else {
1153 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
1154 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
1155 String[] defaultFocusModes = mActivity.getResources().getStringArray(
1156 R.array.pref_camera_focusmode_default_array);
Erin Dahlgren357b7672013-11-20 17:38:14 -08001157 mFocusManager = new FocusOverlayManager(mActivity.getSettingsManager(),
1158 defaultFocusModes,
Angus Kongc4e66562013-11-22 23:03:21 -08001159 mInitialParams, this, mMirror,
Doris Liu482de022013-12-18 19:18:16 -08001160 mActivity.getMainLooper(), mUI.getFocusUI());
Angus Kongc4e66562013-11-22 23:03:21 -08001161 }
Doris Liu482de022013-12-18 19:18:16 -08001162 mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
Angus Kong20fad242013-11-11 18:23:46 -08001163 }
1164
1165 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001166 public void resume() {
1167 mPaused = false;
Doris Liu482de022013-12-18 19:18:16 -08001168 if (mFocusManager != null) {
Doris Liu15b99612013-12-21 11:32:28 -08001169 // If camera is not open when resume is called, focus manager will not
1170 // be initialized yet, in which case it will start listening to
1171 // preview area size change later in the initialization.
Doris Liu482de022013-12-18 19:18:16 -08001172 mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
1173 }
Angus Kongc4e66562013-11-22 23:03:21 -08001174 // Add delay on resume from lock screen only, in order to to speed up
1175 // the onResume --> onPause --> onResume cycle from lock screen.
1176 // Don't do always because letting go of thread can cause delay.
1177 String action = mActivity.getIntent().getAction();
1178 if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
1179 || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
1180 Log.v(TAG, "On resume, from lock screen.");
1181 // Note: onPauseAfterSuper() will delete this runnable, so we will
1182 // at most have 1 copy queued up.
1183 mHandler.postDelayed(new Runnable() {
Sameer Padala2c8cc452013-11-05 18:49:12 -08001184 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001185 public void run() {
1186 onResumeTasks();
1187 }
1188 }, ON_RESUME_TASKS_DELAY_MSEC);
1189 } else {
1190 Log.v(TAG, "On resume.");
1191 onResumeTasks();
1192 }
1193 }
1194
1195 @Override
1196 public void pause() {
Michael Kolb8872c232013-01-29 10:33:22 -08001197 mPaused = true;
Angus Kong0d00a892013-03-26 11:40:40 -07001198 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1199 if (gsensor != null) {
1200 mSensorManager.unregisterListener(this, gsensor);
1201 }
1202
1203 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1204 if (msensor != null) {
1205 mSensorManager.unregisterListener(this, msensor);
1206 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001207
Michael Kolb8872c232013-01-29 10:33:22 -08001208 // Reset the focus first. Camera CTS does not guarantee that
1209 // cancelAutoFocus is allowed after preview stops.
1210 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1211 mCameraDevice.cancelAutoFocus();
1212 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001213
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -08001214 // If the camera has not been opened asynchronously yet,
1215 // and startPreview hasn't been called, then this is a no-op.
1216 // (e.g. onResume -> onPause -> onResume).
Michael Kolb8872c232013-01-29 10:33:22 -08001217 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001218
Angus Kongce5480e2013-01-29 17:43:48 -08001219 mNamedImages = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001220
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001221 if (mLocationManager != null) {
1222 mLocationManager.recordLocation(false);
1223 }
Michael Kolb8872c232013-01-29 10:33:22 -08001224
1225 // If we are in an image capture intent and has taken
1226 // a picture, we just clear it in onPause.
1227 mJpegImageData = null;
1228
Angus Kongdcccc512013-08-08 17:06:03 -07001229 // Remove the messages and runnables in the queue.
1230 mHandler.removeCallbacksAndMessages(null);
Michael Kolb8872c232013-01-29 10:33:22 -08001231
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001232 closeCamera();
Angus Kong13e87c42013-11-25 10:02:47 -08001233 mActivity.enableKeepScreenOn(false);
Michael Kolbd6954f32013-03-08 20:43:01 -08001234 mUI.onPause();
1235
Michael Kolb8872c232013-01-29 10:33:22 -08001236 mPendingSwitchCameraId = -1;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001237 if (mFocusManager != null) {
1238 mFocusManager.removeMessages();
Angus Kong86d36312013-01-31 18:22:44 -08001239 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001240 getServices().getMemoryManager().removeListener(this);
Doris Liu482de022013-12-18 19:18:16 -08001241 mAppController.removePreviewAreaSizeChangedListener(mFocusManager);
Michael Kolb8872c232013-01-29 10:33:22 -08001242 }
1243
Angus Kong20fad242013-11-11 18:23:46 -08001244 @Override
1245 public void destroy() {
1246 // TODO: implement this.
1247 }
1248
1249 @Override
1250 public void onPreviewSizeChanged(int width, int height) {
1251 // TODO: implement this.
1252 }
1253
1254 @Override
Angus Kong2f0e4a32013-12-03 10:02:35 -08001255 public void onLayoutOrientationChanged(boolean isLandscape) {
Michael Kolb8872c232013-01-29 10:33:22 -08001256 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001257 }
1258
1259 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001260 public void updateCameraOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001261 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001262 setDisplayOrientation();
1263 }
1264 }
1265
Michael Kolb8872c232013-01-29 10:33:22 -08001266 private boolean canTakePicture() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001267 return isCameraIdle()
1268 && (mActivity.getStorageSpaceBytes() > Storage.LOW_STORAGE_THRESHOLD_BYTES);
Michael Kolb8872c232013-01-29 10:33:22 -08001269 }
1270
1271 @Override
1272 public void autoFocus() {
1273 mFocusStartTime = System.currentTimeMillis();
Angus Kong9ef99252013-07-18 18:04:19 -07001274 mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001275 setCameraState(FOCUSING);
1276 }
1277
1278 @Override
1279 public void cancelAutoFocus() {
1280 mCameraDevice.cancelAutoFocus();
1281 setCameraState(IDLE);
1282 setCameraParameters(UPDATE_PARAM_PREFERENCE);
1283 }
1284
Michael Kolb8872c232013-01-29 10:33:22 -08001285 @Override
1286 public void onSingleTapUp(View view, int x, int y) {
Doris Liu482de022013-12-18 19:18:16 -08001287 if (mPaused || mCameraDevice == null || !mFirstTimeInitialized
1288 || mCameraState == SNAPSHOT_IN_PROGRESS
1289 || mCameraState == SWITCHING_CAMERA
1290 || mCameraState == PREVIEW_STOPPED) {
1291 return;
1292 }
1293
1294 // Check if metering area or focus area is supported.
Doris Liu15b99612013-12-21 11:32:28 -08001295 if (!mFocusAreaSupported && !mMeteringAreaSupported) {
1296 return;
1297 }
Doris Liu482de022013-12-18 19:18:16 -08001298 mFocusManager.onSingleTapUp(x, y);
Michael Kolb8872c232013-01-29 10:33:22 -08001299 }
1300
1301 @Override
1302 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001303 return mUI.onBackPressed();
Michael Kolb8872c232013-01-29 10:33:22 -08001304 }
1305
1306 @Override
1307 public boolean onKeyDown(int keyCode, KeyEvent event) {
1308 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001309 case KeyEvent.KEYCODE_VOLUME_UP:
1310 case KeyEvent.KEYCODE_VOLUME_DOWN:
1311 case KeyEvent.KEYCODE_FOCUS:
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001312 if (/* TODO: mActivity.isInCameraApp() && */mFirstTimeInitialized) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001313 if (event.getRepeatCount() == 0) {
1314 onShutterButtonFocus(true);
1315 }
1316 return true;
1317 }
1318 return false;
1319 case KeyEvent.KEYCODE_CAMERA:
1320 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1321 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001322 }
1323 return true;
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001324 case KeyEvent.KEYCODE_DPAD_CENTER:
1325 // If we get a dpad center event without any focused view, move
1326 // the focus to the shutter button and press it.
1327 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1328 // Start auto-focus immediately to reduce shutter lag. After
1329 // the shutter button gets the focus, onShutterButtonFocus()
1330 // will be called again but it is fine.
1331 onShutterButtonFocus(true);
1332 mUI.pressShutterButton();
1333 }
1334 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001335 }
1336 return false;
1337 }
1338
1339 @Override
1340 public boolean onKeyUp(int keyCode, KeyEvent event) {
1341 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001342 case KeyEvent.KEYCODE_VOLUME_UP:
1343 case KeyEvent.KEYCODE_VOLUME_DOWN:
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001344 if (/* mActivity.isInCameraApp() && */mFirstTimeInitialized) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001345 onShutterButtonClick();
1346 return true;
1347 }
1348 return false;
1349 case KeyEvent.KEYCODE_FOCUS:
1350 if (mFirstTimeInitialized) {
1351 onShutterButtonFocus(false);
1352 }
Michael Kolb8872c232013-01-29 10:33:22 -08001353 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001354 }
1355 return false;
1356 }
1357
Michael Kolb8872c232013-01-29 10:33:22 -08001358 private void closeCamera() {
1359 if (mCameraDevice != null) {
1360 mCameraDevice.setZoomChangeListener(null);
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001361 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001362 mCameraDevice.setErrorCallback(null);
Ruben Brunk59147832013-11-05 15:53:28 -08001363
Michael Kolb8872c232013-01-29 10:33:22 -08001364 mFaceDetectionStarted = false;
Angus Kong20fad242013-11-11 18:23:46 -08001365 mActivity.getCameraProvider().releaseCamera(mCameraDevice.getCameraId());
Michael Kolb8872c232013-01-29 10:33:22 -08001366 mCameraDevice = null;
1367 setCameraState(PREVIEW_STOPPED);
1368 mFocusManager.onCameraReleased();
1369 }
1370 }
1371
1372 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001373 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1374 mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001375 mCameraDisplayOrientation = mDisplayOrientation;
Michael Kolbd6954f32013-03-08 20:43:01 -08001376 mUI.setDisplayOrientation(mDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001377 if (mFocusManager != null) {
1378 mFocusManager.setDisplayOrientation(mDisplayOrientation);
1379 }
Doris Liu6432cd62013-06-13 17:20:31 -07001380 // Change the camera display orientation
1381 if (mCameraDevice != null) {
1382 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1383 }
Michael Kolb8872c232013-01-29 10:33:22 -08001384 }
1385
Sascha Haeberlingddef7792013-08-13 14:41:10 -07001386 /** Only called by UI thread. */
Michael Kolb8872c232013-01-29 10:33:22 -08001387 private void setupPreview() {
1388 mFocusManager.resetTouchFocus();
1389 startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001390 }
1391
Angus Kong20fad242013-11-11 18:23:46 -08001392 /**
1393 * Returns whether we can/should start the preview or not.
1394 */
1395 private boolean checkPreviewPreconditions() {
1396 if (mPaused) {
1397 return false;
Angus Kongdcccc512013-08-08 17:06:03 -07001398 }
Michael Kolb8872c232013-01-29 10:33:22 -08001399
Angus Kong20fad242013-11-11 18:23:46 -08001400 if (mCameraDevice == null) {
1401 Log.w(TAG, "startPreview: camera device not ready yet.");
1402 return false;
1403 }
1404
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001405 SurfaceTexture st = mUI.getSurfaceTexture();
1406 if (st == null) {
1407 Log.w(TAG, "startPreview: surfaceTexture is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001408 return false;
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001409 }
1410
1411 if (!mCameraPreviewParamsReady) {
1412 Log.w(TAG, "startPreview: parameters for preview is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001413 return false;
1414 }
1415 return true;
1416 }
1417
1418 /**
1419 * The start/stop preview should only run on the UI thread.
1420 */
1421 private void startPreview() {
1422 if (!checkPreviewPreconditions()) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001423 return;
1424 }
Angus Kong20fad242013-11-11 18:23:46 -08001425
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001426 mCameraDevice.setErrorCallback(mErrorCallback);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001427 // ICS camera frameworks has a bug. Face detection state is not cleared
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001428 // after taking a picture. Stop the preview to work around it. The bug
1429 // was fixed in JB.
1430 if (mCameraState != PREVIEW_STOPPED) {
1431 stopPreview();
1432 }
1433
1434 setDisplayOrientation();
1435
1436 if (!mSnapshotOnIdle) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001437 // If the focus mode is continuous autofocus, call cancelAutoFocus
1438 // to resume it because it may have been paused by autoFocus call.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001439 String focusMode = mFocusManager.getFocusMode();
1440 if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(focusMode)) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001441 mCameraDevice.cancelAutoFocus();
Michael Kolb8872c232013-01-29 10:33:22 -08001442 }
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001443 mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1444 }
1445 setCameraParameters(UPDATE_PARAM_ALL);
1446 // Let UI set its expected aspect ratio
Angus Kong20fad242013-11-11 18:23:46 -08001447 mCameraDevice.setPreviewTexture(mUI.getSurfaceTexture());
Michael Kolb8872c232013-01-29 10:33:22 -08001448
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001449 Log.v(TAG, "startPreview");
1450 mCameraDevice.startPreview();
Angus Kong20fad242013-11-11 18:23:46 -08001451
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001452 mFocusManager.onPreviewStarted();
1453 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001454
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001455 if (mSnapshotOnIdle) {
1456 mHandler.post(mDoSnapRunnable);
Michael Kolb8872c232013-01-29 10:33:22 -08001457 }
1458 }
1459
Michael Kolbd6954f32013-03-08 20:43:01 -08001460 @Override
1461 public void stopPreview() {
Michael Kolb8872c232013-01-29 10:33:22 -08001462 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1463 Log.v(TAG, "stopPreview");
1464 mCameraDevice.stopPreview();
1465 mFaceDetectionStarted = false;
1466 }
1467 setCameraState(PREVIEW_STOPPED);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001468 if (mFocusManager != null) {
1469 mFocusManager.onPreviewStopped();
1470 }
Sameer Padala2c8cc452013-11-05 18:49:12 -08001471 stopSmartCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001472 }
1473
Michael Kolb8872c232013-01-29 10:33:22 -08001474 private void updateCameraParametersInitialize() {
1475 // Reset preview frame rate to the maximum because it may be lowered by
1476 // video camera application.
ztenghui16a35202013-09-23 11:35:36 -07001477 int[] fpsRange = CameraUtil.getPhotoPreviewFpsRange(mParameters);
1478 if (fpsRange != null && fpsRange.length > 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001479 mParameters.setPreviewFpsRange(
1480 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1481 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
Michael Kolb8872c232013-01-29 10:33:22 -08001482 }
1483
Angus Kongb50b5cb2013-08-09 14:55:20 -07001484 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);
Michael Kolb8872c232013-01-29 10:33:22 -08001485
1486 // Disable video stabilization. Convenience methods not available in API
1487 // level <= 14
1488 String vstabSupported = mParameters.get("video-stabilization-supported");
1489 if ("true".equals(vstabSupported)) {
1490 mParameters.set("video-stabilization", "false");
1491 }
1492 }
1493
1494 private void updateCameraParametersZoom() {
1495 // Set zoom.
1496 if (mParameters.isZoomSupported()) {
1497 mParameters.setZoom(mZoomValue);
1498 }
1499 }
1500
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001501 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001502 private void setAutoExposureLockIfSupported() {
1503 if (mAeLockSupported) {
1504 mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1505 }
1506 }
1507
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001508 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001509 private void setAutoWhiteBalanceLockIfSupported() {
1510 if (mAwbLockSupported) {
1511 mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1512 }
1513 }
1514
Michael Kolb8872c232013-01-29 10:33:22 -08001515 private void setFocusAreasIfSupported() {
1516 if (mFocusAreaSupported) {
1517 mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1518 }
1519 }
1520
Michael Kolb8872c232013-01-29 10:33:22 -08001521 private void setMeteringAreasIfSupported() {
1522 if (mMeteringAreaSupported) {
Michael Kolb8872c232013-01-29 10:33:22 -08001523 mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1524 }
1525 }
1526
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001527 private void updateCameraParametersPreference() {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001528 SettingsManager settingsManager = mActivity.getSettingsManager();
1529
Michael Kolb8872c232013-01-29 10:33:22 -08001530 setAutoExposureLockIfSupported();
1531 setAutoWhiteBalanceLockIfSupported();
1532 setFocusAreasIfSupported();
1533 setMeteringAreasIfSupported();
1534
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001535 // Initialize focus mode.
Michael Kolbd3253f22013-07-12 11:36:47 -07001536 mFocusManager.overrideFocusMode(null);
1537 mParameters.setFocusMode(mFocusManager.getFocusMode());
1538
Michael Kolb8872c232013-01-29 10:33:22 -08001539 // Set picture size.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001540 String pictureSize = settingsManager.get(SettingsManager.SETTING_PICTURE_SIZE);
Michael Kolb8872c232013-01-29 10:33:22 -08001541 if (pictureSize == null) {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001542 //TODO: deprecate CameraSettings.
1543 CameraSettings.initialCameraPictureSize(
1544 mActivity, mParameters, settingsManager);
Michael Kolb8872c232013-01-29 10:33:22 -08001545 } else {
1546 List<Size> supported = mParameters.getSupportedPictureSizes();
1547 CameraSettings.setCameraPictureSize(
1548 pictureSize, supported, mParameters);
1549 }
1550 Size size = mParameters.getPictureSize();
1551
1552 // Set a preview size that is closest to the viewfinder height and has
1553 // the right aspect ratio.
1554 List<Size> sizes = mParameters.getSupportedPreviewSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001555 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
Michael Kolb8872c232013-01-29 10:33:22 -08001556 (double) size.width / size.height);
1557 Size original = mParameters.getPreviewSize();
1558 if (!original.equals(optimalSize)) {
1559 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
Doris Liu6432cd62013-06-13 17:20:31 -07001560
Michael Kolb8872c232013-01-29 10:33:22 -08001561 // Zoom related settings will be changed for different preview
1562 // sizes, so set and read the parameters to get latest values
Michael Kolb4a4d4ef2013-05-30 08:35:26 -07001563 if (mHandler.getLooper() == Looper.myLooper()) {
1564 // On UI thread only, not when camera starts up
1565 setupPreview();
1566 } else {
1567 mCameraDevice.setParameters(mParameters);
1568 }
Michael Kolb8872c232013-01-29 10:33:22 -08001569 mParameters = mCameraDevice.getParameters();
1570 }
Doris Liu95405742013-11-05 15:25:26 -08001571
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001572 if (optimalSize.width != 0 && optimalSize.height != 0) {
Doris Liu95405742013-11-05 15:25:26 -08001573 mUI.updatePreviewAspectRatio((float) optimalSize.width
1574 / (float) optimalSize.height);
1575 }
Michael Kolb8872c232013-01-29 10:33:22 -08001576 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
1577
Michael Kolb8872c232013-01-29 10:33:22 -08001578 // Set JPEG quality.
1579 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1580 CameraProfile.QUALITY_HIGH);
1581 mParameters.setJpegQuality(jpegQuality);
1582
1583 // For the following settings, we need to check if the settings are
1584 // still supported by latest driver, if not, ignore the settings.
1585
1586 // Set exposure compensation
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001587 int value = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_EXPOSURE));
Michael Kolb8872c232013-01-29 10:33:22 -08001588 int max = mParameters.getMaxExposureCompensation();
1589 int min = mParameters.getMinExposureCompensation();
1590 if (value >= min && value <= max) {
1591 mParameters.setExposureCompensation(value);
1592 } else {
1593 Log.w(TAG, "invalid exposure range: " + value);
1594 }
1595
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001596 mSceneMode = settingsManager.get(SettingsManager.SETTING_SCENE_MODE);
1597 updateParametersSceneMode();
1598
1599 if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
1600 updateAutoFocusMoveCallback();
1601 }
1602 }
1603
1604 public void updateParametersSceneMode() {
1605 SettingsManager settingsManager = mActivity.getSettingsManager();
1606
1607 if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
1608 if (!mParameters.getSceneMode().equals(mSceneMode)) {
1609 mParameters.setSceneMode(mSceneMode);
1610
1611 // Setting scene mode will change the settings of flash mode,
1612 // white balance, and focus mode. Here we read back the
1613 // parameters, so we can know those settings.
1614 mCameraDevice.setParameters(mParameters);
1615 mParameters = mCameraDevice.getParameters();
1616 }
1617 } else {
1618 mSceneMode = mParameters.getSceneMode();
1619 if (mSceneMode == null) {
1620 mSceneMode = Parameters.SCENE_MODE_AUTO;
1621 }
1622 }
1623
Michael Kolb8872c232013-01-29 10:33:22 -08001624 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1625 // Set flash mode.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001626 String flashMode = settingsManager.get(SettingsManager.SETTING_FLASH_MODE);
Michael Kolb8872c232013-01-29 10:33:22 -08001627 List<String> supportedFlash = mParameters.getSupportedFlashModes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001628 if (CameraUtil.isSupported(flashMode, supportedFlash)) {
Michael Kolb8872c232013-01-29 10:33:22 -08001629 mParameters.setFlashMode(flashMode);
1630 } else {
1631 flashMode = mParameters.getFlashMode();
1632 if (flashMode == null) {
1633 flashMode = mActivity.getString(
1634 R.string.pref_camera_flashmode_no_flash);
1635 }
1636 }
1637
1638 // Set white balance parameter.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001639 String whiteBalance = settingsManager.get(SettingsManager.SETTING_WHITE_BALANCE);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001640 if (CameraUtil.isSupported(whiteBalance,
Michael Kolb8872c232013-01-29 10:33:22 -08001641 mParameters.getSupportedWhiteBalance())) {
1642 mParameters.setWhiteBalance(whiteBalance);
1643 } else {
1644 whiteBalance = mParameters.getWhiteBalance();
1645 if (whiteBalance == null) {
1646 whiteBalance = Parameters.WHITE_BALANCE_AUTO;
1647 }
1648 }
1649
1650 // Set focus mode.
1651 mFocusManager.overrideFocusMode(null);
1652 mParameters.setFocusMode(mFocusManager.getFocusMode());
1653 } else {
1654 mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1655 }
Michael Kolb8872c232013-01-29 10:33:22 -08001656 }
1657
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001658 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001659 private void updateAutoFocusMoveCallback() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001660 if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Angus Kong9ef99252013-07-18 18:04:19 -07001661 mCameraDevice.setAutoFocusMoveCallback(mHandler,
Angus Kong4f795b82013-09-16 14:25:35 -07001662 (CameraAFMoveCallback) mAutoFocusMoveCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001663 } else {
Angus Kong9ef99252013-07-18 18:04:19 -07001664 mCameraDevice.setAutoFocusMoveCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001665 }
1666 }
1667
1668 // We separate the parameters into several subsets, so we can update only
1669 // the subsets actually need updating. The PREFERENCE set needs extra
1670 // locking because the preference can be changed from GLThread as well.
1671 private void setCameraParameters(int updateSet) {
1672 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1673 updateCameraParametersInitialize();
1674 }
1675
1676 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1677 updateCameraParametersZoom();
1678 }
1679
1680 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001681 updateCameraParametersPreference();
Michael Kolb8872c232013-01-29 10:33:22 -08001682 }
1683
1684 mCameraDevice.setParameters(mParameters);
1685 }
1686
1687 // If the Camera is idle, update the parameters immediately, otherwise
1688 // accumulate them in mUpdateSet and update later.
1689 private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1690 mUpdateSet |= additionalUpdateSet;
1691 if (mCameraDevice == null) {
1692 // We will update all the parameters when we open the device, so
1693 // we don't need to do anything now.
1694 mUpdateSet = 0;
1695 return;
1696 } else if (isCameraIdle()) {
1697 setCameraParameters(mUpdateSet);
Michael Kolbd6954f32013-03-08 20:43:01 -08001698 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001699 mUpdateSet = 0;
1700 } else {
Angus Kong13e87c42013-11-25 10:02:47 -08001701 if (!mHandler.hasMessages(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1702 mHandler.sendEmptyMessageDelayed(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
Michael Kolb8872c232013-01-29 10:33:22 -08001703 }
1704 }
1705 }
1706
ztenghui7b265a62013-09-09 14:58:44 -07001707 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001708 public boolean isCameraIdle() {
Michael Kolb8872c232013-01-29 10:33:22 -08001709 return (mCameraState == IDLE) ||
1710 (mCameraState == PREVIEW_STOPPED) ||
1711 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
1712 && (mCameraState != SWITCHING_CAMERA));
1713 }
1714
ztenghui7b265a62013-09-09 14:58:44 -07001715 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001716 public boolean isImageCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001717 String action = mActivity.getIntent().getAction();
1718 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
Angus Kong6a8e8a12013-07-19 14:55:07 -07001719 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
Michael Kolb8872c232013-01-29 10:33:22 -08001720 }
1721
1722 private void setupCaptureParams() {
1723 Bundle myExtras = mActivity.getIntent().getExtras();
1724 if (myExtras != null) {
1725 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1726 mCropValue = myExtras.getString("crop");
1727 }
1728 }
1729
Michael Kolb8872c232013-01-29 10:33:22 -08001730 public void onSharedPreferenceChanged() {
1731 // ignore the events after "onPause()"
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001732 if (mPaused) {
1733 return;
1734 }
Michael Kolb8872c232013-01-29 10:33:22 -08001735
Erin Dahlgren357b7672013-11-20 17:38:14 -08001736 SettingsController settingsController = mActivity.getSettingsController();
1737 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001738
1739 setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
Michael Kolb8872c232013-01-29 10:33:22 -08001740 }
1741
Michael Kolb8872c232013-01-29 10:33:22 -08001742 private void showTapToFocusToast() {
1743 // TODO: Use a toast?
1744 new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
1745 // Clear the preference.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001746 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001747 settingsManager.setBoolean(
1748 SettingsManager.SETTING_CAMERA_FIRST_USE_HINT_SHOWN, false);
Michael Kolb8872c232013-01-29 10:33:22 -08001749 }
1750
1751 private void initializeCapabilities() {
1752 mInitialParams = mCameraDevice.getParameters();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001753 mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
1754 mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
1755 mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
1756 mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
Angus Kongdcccc512013-08-08 17:06:03 -07001757 mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001758 CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
Michael Kolb8872c232013-01-29 10:33:22 -08001759 }
1760
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001761 private void setShutterEnabled(boolean enabled) {
1762 mShutterEnabled = enabled;
1763 mUI.enableShutter(enabled);
1764 }
1765
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001766 // TODO: Remove this
Michael Kolb8872c232013-01-29 10:33:22 -08001767 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001768 public int onZoomChanged(int index) {
1769 // Not useful to change zoom value when the activity is paused.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001770 if (mPaused) {
1771 return index;
1772 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001773 mZoomValue = index;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001774 if (mParameters == null || mCameraDevice == null) {
1775 return index;
1776 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001777 // Set zoom parameters asynchronously
1778 mParameters.setZoom(mZoomValue);
Angus Kong36ed8672013-04-15 12:11:15 -07001779 mCameraDevice.setParameters(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -08001780 Parameters p = mCameraDevice.getParameters();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001781 if (p != null) {
1782 return p.getZoom();
1783 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001784 return index;
Angus Kongce5480e2013-01-29 17:43:48 -08001785 }
1786
1787 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001788 public int getCameraState() {
1789 return mCameraState;
1790 }
1791
1792 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001793 public void onMemoryStateChanged(int state) {
1794 setShutterEnabled(state == MemoryManager.STATE_OK);
Angus Kongce5480e2013-01-29 17:43:48 -08001795 }
Angus Kong86d36312013-01-31 18:22:44 -08001796
1797 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001798 public void onLowMemory() {
1799 // Not much we can do in the photo module.
Angus Kong86d36312013-01-31 18:22:44 -08001800 }
Angus Kong0d00a892013-03-26 11:40:40 -07001801
1802 @Override
1803 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1804 }
1805
1806 @Override
1807 public void onSensorChanged(SensorEvent event) {
1808 int type = event.sensor.getType();
1809 float[] data;
1810 if (type == Sensor.TYPE_ACCELEROMETER) {
1811 data = mGData;
1812 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
1813 data = mMData;
1814 } else {
1815 // we should not be here.
1816 return;
1817 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001818 for (int i = 0; i < 3; i++) {
Angus Kong0d00a892013-03-26 11:40:40 -07001819 data[i] = event.values[i];
1820 }
1821 float[] orientation = new float[3];
1822 SensorManager.getRotationMatrix(mR, null, mGData, mMData);
1823 SensorManager.getOrientation(mR, orientation);
1824 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
1825 if (mHeading < 0) {
1826 mHeading += 360;
1827 }
Angus Kong0d00a892013-03-26 11:40:40 -07001828 }
Doris Liu6432cd62013-06-13 17:20:31 -07001829
Ruben Brunkd217ed02013-10-08 23:31:13 -07001830 // For debugging only.
1831 public void setDebugUri(Uri uri) {
1832 mDebugUri = uri;
1833 }
1834
1835 // For debugging only.
1836 private void saveToDebugUri(byte[] data) {
1837 if (mDebugUri != null) {
1838 OutputStream outputStream = null;
1839 try {
1840 outputStream = mContentResolver.openOutputStream(mDebugUri);
1841 outputStream.write(data);
1842 outputStream.close();
1843 } catch (IOException e) {
1844 Log.e(TAG, "Exception while writing debug jpeg file", e);
1845 } finally {
1846 CameraUtil.closeSilently(outputStream);
1847 }
1848 }
1849 }
Michael Kolb8872c232013-01-29 10:33:22 -08001850}