blob: d64303bca3b1603fce78773bc81a85ff9fb75cf9 [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
Doris Liubd1b8f92014-01-03 17:59:51 -0800231 private final int mGcamModeIndex;
232 private final int mRefocusModeIndex;
233
Michael Kolb8872c232013-01-29 10:33:22 -0800234 private String mSceneMode;
Michael Kolb8872c232013-01-29 10:33:22 -0800235
236 private final Handler mHandler = new MainHandler();
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800237
Michael Kolb8872c232013-01-29 10:33:22 -0800238 private boolean mQuickCapture;
Angus Kong0d00a892013-03-26 11:40:40 -0700239 private SensorManager mSensorManager;
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800240 private final float[] mGData = new float[3];
241 private final float[] mMData = new float[3];
242 private final float[] mR = new float[16];
Angus Kong0d00a892013-03-26 11:40:40 -0700243 private int mHeading = -1;
244
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800245 /** Whether shutter is enabled. */
Spike Sprague215f6b02013-12-12 11:53:49 -0800246 private boolean mShutterEnabled = true;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800247
248 /** True if all the parameters needed to start preview is ready. */
Angus Kongdcccc512013-08-08 17:06:03 -0700249 private boolean mCameraPreviewParamsReady = false;
Doris Liu6432cd62013-06-13 17:20:31 -0700250
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800251 private final MediaSaver.OnMediaSavedListener mOnMediaSavedListener =
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800252 new MediaSaver.OnMediaSavedListener() {
Angus Kongce5480e2013-01-29 17:43:48 -0800253 @Override
254 public void onMediaSaved(Uri uri) {
255 if (uri != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700256 mActivity.notifyNewMedia(uri);
Angus Kongce5480e2013-01-29 17:43:48 -0800257 }
258 }
259 };
Michael Kolb8872c232013-01-29 10:33:22 -0800260
Angus Kongdcccc512013-08-08 17:06:03 -0700261 private void checkDisplayRotation() {
262 // Set the display orientation if display rotation has changed.
263 // Sometimes this happens when the device is held upside
264 // down and camera app is opened. Rotation animation will
265 // take some time and the rotation value we have got may be
266 // wrong. Framework does not have a callback for this now.
267 if (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) {
268 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -0800269 }
Angus Kongdcccc512013-08-08 17:06:03 -0700270 if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
271 mHandler.postDelayed(new Runnable() {
272 @Override
273 public void run() {
274 checkDisplayRotation();
275 }
276 }, 100);
Michael Kolb8872c232013-01-29 10:33:22 -0800277 }
278 }
279
280 /**
281 * This Handler is used to post message back onto the main thread of the
282 * application
283 */
284 private class MainHandler extends Handler {
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800285 public MainHandler() {
286 super(Looper.getMainLooper());
287 }
288
Michael Kolb8872c232013-01-29 10:33:22 -0800289 @Override
290 public void handleMessage(Message msg) {
291 switch (msg.what) {
Angus Kong13e87c42013-11-25 10:02:47 -0800292 case MSG_FIRST_TIME_INIT: {
Michael Kolb8872c232013-01-29 10:33:22 -0800293 initializeFirstTime();
294 break;
295 }
296
Angus Kong13e87c42013-11-25 10:02:47 -0800297 case MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE: {
Michael Kolb8872c232013-01-29 10:33:22 -0800298 setCameraParametersWhenIdle(0);
299 break;
300 }
301
Angus Kong13e87c42013-11-25 10:02:47 -0800302 case MSG_SHOW_TAP_TO_FOCUS_TOAST: {
Michael Kolb8872c232013-01-29 10:33:22 -0800303 showTapToFocusToast();
304 break;
305 }
306
Angus Kong13e87c42013-11-25 10:02:47 -0800307 case MSG_SWITCH_TO_GCAM_MODULE: {
Doris Liubd1b8f92014-01-03 17:59:51 -0800308 mActivity.onModeSelected(mGcamModeIndex);
ztenghui367c7c82013-10-16 14:43:26 -0700309 }
Michael Kolb8872c232013-01-29 10:33:22 -0800310 }
311 }
312 }
313
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800314 /**
315 * Constructs a new photo module.
316 */
Angus Kongc4e66562013-11-22 23:03:21 -0800317 public PhotoModule(AppController app) {
318 super(app);
Doris Liubd1b8f92014-01-03 17:59:51 -0800319 mGcamModeIndex = app.getAndroidContext().getResources()
320 .getInteger(R.integer.camera_mode_gcam);
321 mRefocusModeIndex = app.getAndroidContext().getResources()
322 .getInteger(R.integer.camera_mode_refocus);
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800323 }
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700324
Angus Kong13e87c42013-11-25 10:02:47 -0800325
Michael Kolb8872c232013-01-29 10:33:22 -0800326 @Override
Angus Kong13e87c42013-11-25 10:02:47 -0800327 public void init(AppController app, boolean isSecureCamera, boolean isCaptureIntent) {
328 mActivity = (CameraActivity) app.getAndroidContext();
329 mUI = new PhotoUI(mActivity, this, app.getModuleLayoutRoot());
Doris Liu06db7422013-12-09 19:36:25 -0800330 app.setPreviewStatusListener(mUI);
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800331 app.getCameraAppUI().setBottomBarShutterListener(this);
Erin Dahlgren357b7672013-11-20 17:38:14 -0800332
333 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800334 mCameraId = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_CAMERA_ID));
Michael Kolb8872c232013-01-29 10:33:22 -0800335
336 mContentResolver = mActivity.getContentResolver();
337
Michael Kolb8872c232013-01-29 10:33:22 -0800338 // Surface texture is from camera screen nail and startPreview needs it.
339 // This must be done before startPreview.
340 mIsImageCaptureIntent = isImageCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800341
Angus Kong20fad242013-11-11 18:23:46 -0800342 mActivity.getCameraProvider().requestCamera(mCameraId);
343
Michael Kolb8872c232013-01-29 10:33:22 -0800344 initializeControlByIntent();
345 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800346 mLocationManager = mActivity.getLocationManager();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800347 mSensorManager = (SensorManager) (mActivity.getSystemService(Context.SENSOR_SERVICE));
Doris Liu2b906b82013-12-10 16:34:08 -0800348 mAppController = app;
Michael Kolbd6954f32013-03-08 20:43:01 -0800349 }
350
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800351 @Override
352 public boolean isUsingBottomBar() {
353 return true;
354 }
355
Michael Kolbd6954f32013-03-08 20:43:01 -0800356 private void initializeControlByIntent() {
357 mUI.initializeControlByIntent();
358 if (mIsImageCaptureIntent) {
359 setupCaptureParams();
360 }
361 }
362
363 private void onPreviewStarted() {
Doris Liu2b906b82013-12-10 16:34:08 -0800364 mAppController.onPreviewStarted();
Michael Kolbd6954f32013-03-08 20:43:01 -0800365 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800366 startFaceDetection();
Sameer Padala2c8cc452013-11-05 18:49:12 -0800367 startSmartCamera();
Michael Kolbd6954f32013-03-08 20:43:01 -0800368 locationFirstRun();
Michael Kolb8872c232013-01-29 10:33:22 -0800369 }
370
371 // Prompt the user to pick to record location for the very first run of
372 // camera only
373 private void locationFirstRun() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800374 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800375 if (settingsManager.isSet(SettingsManager.SETTING_RECORD_LOCATION)) {
Michael Kolb8872c232013-01-29 10:33:22 -0800376 return;
377 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800378 if (mActivity.isSecureCamera()) {
379 return;
380 }
Michael Kolb8872c232013-01-29 10:33:22 -0800381 // Check if the back camera exists
Angus Kongd74e6a12014-01-07 11:29:44 -0800382 int backCameraId = mAppController.getCameraProvider().getFirstBackCameraId();
Michael Kolb8872c232013-01-29 10:33:22 -0800383 if (backCameraId == -1) {
384 // If there is no back camera, do not show the prompt.
385 return;
386 }
Doris Liu6a83d522013-07-02 12:03:32 -0700387 mUI.showLocationDialog();
388 }
Michael Kolb8872c232013-01-29 10:33:22 -0800389
ztenghui7b265a62013-09-09 14:58:44 -0700390 @Override
Angus Kongdcccc512013-08-08 17:06:03 -0700391 public void onPreviewUIReady() {
Erin Dahlgrendc282e12013-11-12 09:39:08 -0800392 startPreview();
Angus Kongdcccc512013-08-08 17:06:03 -0700393 }
394
395 @Override
396 public void onPreviewUIDestroyed() {
397 if (mCameraDevice == null) {
398 return;
399 }
400 mCameraDevice.setPreviewTexture(null);
401 stopPreview();
402 }
403
Doris Liu1dfe7822013-12-12 00:02:08 -0800404 @Override
405 public void startPreCaptureAnimation() {
406 mAppController.startPreCaptureAnimation();
407 }
408
Michael Kolbd6954f32013-03-08 20:43:01 -0800409 private void onCameraOpened() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800410 openCameraCommon();
Michael Kolb8872c232013-01-29 10:33:22 -0800411 }
412
Michael Kolbd6954f32013-03-08 20:43:01 -0800413 private void switchCamera() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800414 if (mPaused) {
415 return;
416 }
Erin Dahlgren357b7672013-11-20 17:38:14 -0800417 SettingsManager settingsManager = mActivity.getSettingsManager();
Michael Kolbd6954f32013-03-08 20:43:01 -0800418
419 Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
420 mCameraId = mPendingSwitchCameraId;
421 mPendingSwitchCameraId = -1;
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800422 settingsManager.set(SettingsManager.SETTING_CAMERA_ID, "" + mCameraId);
Angus Kong20fad242013-11-11 18:23:46 -0800423 mActivity.getCameraProvider().requestCamera(mCameraId);
Michael Kolbd6954f32013-03-08 20:43:01 -0800424 mUI.clearFaces();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800425 if (mFocusManager != null) {
426 mFocusManager.removeMessages();
427 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800428
Erin Dahlgren357b7672013-11-20 17:38:14 -0800429 // TODO: this needs to be brought into onCameraAvailable();
Angus Kong20fad242013-11-11 18:23:46 -0800430 CameraInfo info = mActivity.getCameraProvider().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -0700431 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
432 mFocusManager.setMirror(mMirror);
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700433 // Start switch camera animation. Post a message because
434 // onFrameAvailable from the old camera may already exist.
Doris Liu48239f42013-03-04 22:19:10 -0800435 }
436
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800437 private final ButtonManager.ButtonCallback mCameraCallback =
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800438 new ButtonManager.ButtonCallback() {
439 @Override
440 public void onStateChanged(int state) {
441 if (mPaused || mPendingSwitchCameraId != -1) {
442 return;
443 }
444 mPendingSwitchCameraId = state;
445
446 Log.v(TAG, "Start to switch camera. cameraId=" + state);
447 // We need to keep a preview frame for the animation before
448 // releasing the camera. This will trigger onPreviewTextureCopied.
449 //TODO: Need to animate the camera switch
450 switchCamera();
451 }
452 };
453
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800454 private final ButtonManager.ButtonCallback mHdrPlusCallback =
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800455 new ButtonManager.ButtonCallback() {
456 @Override
457 public void onStateChanged(int state) {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -0800458 if (GcamHelper.hasGcamCapture()) {
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800459 // Set the camera setting to default backfacing.
460 SettingsManager settingsManager = mActivity.getSettingsManager();
461 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_ID);
Erin Dahlgrenba6994d2013-12-12 16:04:38 -0800462 mHandler.sendEmptyMessage(MSG_SWITCH_TO_GCAM_MODULE);
463 } else {
464 mSceneMode = CameraUtil.SCENE_MODE_HDR;
465 updateParametersSceneMode();
466 }
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800467 }
468 };
469
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800470 private final ButtonManager.ButtonCallback mRefocusCallback =
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800471 new ButtonManager.ButtonCallback() {
472 @Override
473 public void onStateChanged(int state) {
474 if (state == ButtonManager.OFF) {
475 throw new IllegalStateException(
476 "Can't switch refocus off because it should already be off.");
477 }
Doris Liubd1b8f92014-01-03 17:59:51 -0800478 mActivity.onModeSelected(mRefocusModeIndex);
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800479 }
480 };
481
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800482 @Override
483 public void customizeButtons(ButtonManager buttonManager) {
484 mUI.customizeButtons(buttonManager, mCameraCallback, mHdrPlusCallback,
485 mRefocusCallback);
486 }
487
Michael Kolbd6954f32013-03-08 20:43:01 -0800488 // either open a new camera or switch cameras
489 private void openCameraCommon() {
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800490 mUI.onCameraOpened(mParameters, mCameraCallback, mHdrPlusCallback, mRefocusCallback);
Angus Kong0fb819b2013-10-08 13:44:19 -0700491 if (mIsImageCaptureIntent) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800492 // Set hdr plus to default: off.
493 SettingsManager settingsManager = mActivity.getSettingsManager();
494 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_HDR_PLUS);
Angus Kong0fb819b2013-10-08 13:44:19 -0700495 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800496 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -0800497 }
498
ztenghui7b265a62013-09-09 14:58:44 -0700499 @Override
Doris Liu36ebcb12013-10-28 14:44:24 -0700500 public void onPreviewRectChanged(Rect previewRect) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800501 if (mFocusManager != null)
502 mFocusManager.setPreviewRect(previewRect);
Michael Kolbd6954f32013-03-08 20:43:01 -0800503 }
Michael Kolb8872c232013-01-29 10:33:22 -0800504
Doris Liu70da9182013-12-17 18:41:15 -0800505 @Override
506 public void updatePreviewAspectRatio(float aspectRatio) {
507 mAppController.updatePreviewAspectRatio(aspectRatio);
508 }
509
Michael Kolb8872c232013-01-29 10:33:22 -0800510 private void resetExposureCompensation() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800511 SettingsManager settingsManager = mActivity.getSettingsManager();
512 if (settingsManager == null) {
513 Log.e(TAG, "Settings manager is null!");
514 return;
Michael Kolb8872c232013-01-29 10:33:22 -0800515 }
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800516 settingsManager.setDefault(SettingsManager.SETTING_EXPOSURE);
Michael Kolb8872c232013-01-29 10:33:22 -0800517 }
518
Michael Kolb8872c232013-01-29 10:33:22 -0800519 // Snapshots can only be taken after this is called. It should be called
520 // once only. We could have done these things in onCreate() but we want to
521 // make preview screen appear as soon as possible.
522 private void initializeFirstTime() {
Sascha Haeberling330dafb2013-10-10 19:00:41 -0700523 if (mFirstTimeInitialized || mPaused) {
524 return;
525 }
Michael Kolb8872c232013-01-29 10:33:22 -0800526
527 // Initialize location service.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800528 SettingsController settingsController = mActivity.getSettingsController();
529 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -0800530
Michael Kolbd6954f32013-03-08 20:43:01 -0800531 mUI.initializeFirstTime();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800532
Angus Kong86d36312013-01-31 18:22:44 -0800533 // We set the listener only when both service and shutterbutton
534 // are initialized.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800535 getServices().getMemoryManager().addListener(this);
Michael Kolb8872c232013-01-29 10:33:22 -0800536
Michael Kolb8872c232013-01-29 10:33:22 -0800537 mNamedImages = new NamedImages();
538
539 mFirstTimeInitialized = true;
540 addIdleHandler();
541
542 mActivity.updateStorageSpaceAndHint();
543 }
544
Michael Kolbd6954f32013-03-08 20:43:01 -0800545 // If the activity is paused and resumed, this method will be called in
546 // onResume.
547 private void initializeSecondTime() {
548 // Start location update if needed.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800549 SettingsController settingsController = mActivity.getSettingsController();
550 settingsController.syncLocationManager();
551
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800552 getServices().getMemoryManager().addListener(this);
Michael Kolbd6954f32013-03-08 20:43:01 -0800553 mNamedImages = new NamedImages();
554 mUI.initializeSecondTime(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -0800555 }
556
Michael Kolb8872c232013-01-29 10:33:22 -0800557 private void addIdleHandler() {
558 MessageQueue queue = Looper.myQueue();
559 queue.addIdleHandler(new MessageQueue.IdleHandler() {
560 @Override
561 public boolean queueIdle() {
562 Storage.ensureOSXCompatible();
563 return false;
564 }
565 });
566 }
567
Sameer Padala2c8cc452013-11-05 18:49:12 -0800568 private void startSmartCamera() {
569 SmartCameraHelper.register(mCameraDevice, mParameters.getPreviewSize(), mActivity,
Doris Liu773e1c92013-12-02 17:35:03 -0800570 (ViewGroup) mActivity.findViewById(R.id.camera_app_root));
Sameer Padala2c8cc452013-11-05 18:49:12 -0800571 }
572
573 private void stopSmartCamera() {
574 SmartCameraHelper.tearDown();
575 }
576
Michael Kolb8872c232013-01-29 10:33:22 -0800577 @Override
578 public void startFaceDetection() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800579 if (mFaceDetectionStarted) {
580 return;
581 }
Michael Kolb8872c232013-01-29 10:33:22 -0800582 if (mParameters.getMaxNumDetectedFaces() > 0) {
583 mFaceDetectionStarted = true;
Angus Kongd74e6a12014-01-07 11:29:44 -0800584 CameraInfo info = mAppController.getCameraProvider().getCameraInfo()[mCameraId];
Michael Kolbd6954f32013-03-08 20:43:01 -0800585 mUI.onStartFaceDetection(mDisplayOrientation,
586 (info.facing == CameraInfo.CAMERA_FACING_FRONT));
Angus Kong9e765522013-07-31 14:05:20 -0700587 mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Michael Kolb8872c232013-01-29 10:33:22 -0800588 mCameraDevice.startFaceDetection();
589 }
590 }
591
Michael Kolb8872c232013-01-29 10:33:22 -0800592 @Override
593 public void stopFaceDetection() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800594 if (!mFaceDetectionStarted) {
595 return;
596 }
Michael Kolb8872c232013-01-29 10:33:22 -0800597 if (mParameters.getMaxNumDetectedFaces() > 0) {
598 mFaceDetectionStarted = false;
Angus Kong9e765522013-07-31 14:05:20 -0700599 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -0800600 mCameraDevice.stopFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800601 mUI.clearFaces();
Michael Kolb8872c232013-01-29 10:33:22 -0800602 }
603 }
604
Michael Kolb8872c232013-01-29 10:33:22 -0800605 private final class ShutterCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700606 implements CameraShutterCallback {
Angus Kongdcb0ef12013-03-25 23:11:43 -0700607
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800608 private final boolean mNeedsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700609
Sascha Haeberling37f36112013-08-06 14:31:52 -0700610 public ShutterCallback(boolean needsAnimation) {
611 mNeedsAnimation = needsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700612 }
613
Michael Kolb8872c232013-01-29 10:33:22 -0800614 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700615 public void onShutter(CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800616 mShutterCallbackTime = System.currentTimeMillis();
617 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
618 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Sascha Haeberling37f36112013-08-06 14:31:52 -0700619 if (mNeedsAnimation) {
620 mActivity.runOnUiThread(new Runnable() {
621 @Override
622 public void run() {
623 animateAfterShutter();
624 }
625 });
Angus Kongdcb0ef12013-03-25 23:11:43 -0700626 }
Michael Kolb8872c232013-01-29 10:33:22 -0800627 }
628 }
629
Angus Kong9ef99252013-07-18 18:04:19 -0700630 private final class PostViewPictureCallback
631 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800632 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800633 public void onPictureTaken(byte[] data, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800634 mPostViewPictureCallbackTime = System.currentTimeMillis();
635 Log.v(TAG, "mShutterToPostViewCallbackTime = "
636 + (mPostViewPictureCallbackTime - mShutterCallbackTime)
637 + "ms");
638 }
639 }
640
Angus Kong9ef99252013-07-18 18:04:19 -0700641 private final class RawPictureCallback
642 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800643 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800644 public void onPictureTaken(byte[] rawData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800645 mRawPictureCallbackTime = System.currentTimeMillis();
646 Log.v(TAG, "mShutterToRawCallbackTime = "
647 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
648 }
649 }
650
Angus Kong9ef99252013-07-18 18:04:19 -0700651 private final class JpegPictureCallback
652 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800653 Location mLocation;
654
655 public JpegPictureCallback(Location loc) {
656 mLocation = loc;
657 }
658
659 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800660 public void onPictureTaken(final byte[] jpegData, CameraProxy camera) {
661 setShutterEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800662 if (mPaused) {
663 return;
664 }
Doris Liu6432cd62013-06-13 17:20:31 -0700665 if (mIsImageCaptureIntent) {
666 stopPreview();
667 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700668 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -0700669 mUI.setSwipingEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800670 }
671
672 mJpegPictureCallbackTime = System.currentTimeMillis();
673 // If postview callback has arrived, the captured image is displayed
674 // in postview callback. If not, the captured image is displayed in
675 // raw picture callback.
676 if (mPostViewPictureCallbackTime != 0) {
677 mShutterToPictureDisplayedTime =
678 mPostViewPictureCallbackTime - mShutterCallbackTime;
679 mPictureDisplayedToJpegCallbackTime =
680 mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
681 } else {
682 mShutterToPictureDisplayedTime =
683 mRawPictureCallbackTime - mShutterCallbackTime;
684 mPictureDisplayedToJpegCallbackTime =
685 mJpegPictureCallbackTime - mRawPictureCallbackTime;
686 }
687 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
688 + mPictureDisplayedToJpegCallbackTime + "ms");
689
Michael Kolb8872c232013-01-29 10:33:22 -0800690 mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
691 if (!mIsImageCaptureIntent) {
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700692 setupPreview();
Michael Kolb8872c232013-01-29 10:33:22 -0800693 }
694
Doris Liu36e56fb2013-09-11 17:38:08 -0700695 ExifInterface exif = Exif.getExif(jpegData);
696 int orientation = Exif.getOrientation(exif);
Ruben Brunkd217ed02013-10-08 23:31:13 -0700697
Ruben Brunkd7488272013-10-10 18:45:53 -0700698 if (!mIsImageCaptureIntent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800699 // Calculate the width and the height of the jpeg.
700 Size s = mParameters.getPictureSize();
Michael Kolb8872c232013-01-29 10:33:22 -0800701 int width, height;
702 if ((mJpegRotation + orientation) % 180 == 0) {
703 width = s.width;
704 height = s.height;
705 } else {
706 width = s.height;
707 height = s.width;
708 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700709 NamedEntity name = mNamedImages.getNextNameEntity();
710 String title = (name == null) ? null : name.title;
711 long date = (name == null) ? -1 : name.date;
Ruben Brunkd7488272013-10-10 18:45:53 -0700712
713 // Handle debug mode outputs
714 if (mDebugUri != null) {
715 // If using a debug uri, save jpeg there.
716 saveToDebugUri(jpegData);
717
718 // Adjust the title of the debug image shown in mediastore.
719 if (title != null) {
720 title = DEBUG_IMAGE_PREFIX + title;
721 }
722 }
723
Michael Kolb8872c232013-01-29 10:33:22 -0800724 if (title == null) {
725 Log.e(TAG, "Unbalanced name/data pair");
726 } else {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800727 if (date == -1)
728 date = mCaptureStartTime;
Angus Kong0d00a892013-03-26 11:40:40 -0700729 if (mHeading >= 0) {
730 // heading direction has been updated by the sensor.
731 ExifTag directionRefTag = exif.buildTag(
732 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
733 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
734 ExifTag directionTag = exif.buildTag(
735 ExifInterface.TAG_GPS_IMG_DIRECTION,
736 new Rational(mHeading, 1));
737 exif.setTag(directionRefTag);
738 exif.setTag(directionTag);
739 }
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800740 getServices().getMediaSaver().addImage(
Angus Kong86d36312013-01-31 18:22:44 -0800741 jpegData, title, date, mLocation, width, height,
Angus Kong0d00a892013-03-26 11:40:40 -0700742 orientation, exif, mOnMediaSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -0800743 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800744 // Animate capture with real jpeg data instead of a preview
745 // frame.
Doris Liu29da2db2013-08-28 14:28:45 -0700746 mUI.animateCapture(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800747 } else {
748 mJpegImageData = jpegData;
749 if (!mQuickCapture) {
Doris Liu36e56fb2013-09-11 17:38:08 -0700750 mUI.showCapturedImageForReview(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800751 } else {
Michael Kolbd6954f32013-03-08 20:43:01 -0800752 onCaptureDone();
Michael Kolb8872c232013-01-29 10:33:22 -0800753 }
754 }
755
756 // Check this in advance of each shot so we don't add to shutter
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800757 // latency. It's true that someone else could write to the SD card
758 // in the mean time and fill it, but that could have happened
759 // between the shutter press and saving the JPEG too.
Michael Kolb8872c232013-01-29 10:33:22 -0800760 mActivity.updateStorageSpaceAndHint();
761
762 long now = System.currentTimeMillis();
763 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
764 Log.v(TAG, "mJpegCallbackFinishTime = "
765 + mJpegCallbackFinishTime + "ms");
766 mJpegPictureCallbackTime = 0;
767 }
768 }
769
Angus Kong9ef99252013-07-18 18:04:19 -0700770 private final class AutoFocusCallback implements CameraAFCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800771 @Override
772 public void onAutoFocus(
Angus Kong9ef99252013-07-18 18:04:19 -0700773 boolean focused, CameraProxy camera) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800774 if (mPaused) {
775 return;
776 }
Michael Kolb8872c232013-01-29 10:33:22 -0800777
778 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
779 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
780 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800781 mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
Michael Kolb8872c232013-01-29 10:33:22 -0800782 }
783 }
784
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700785 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -0800786 private final class AutoFocusMoveCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700787 implements CameraAFMoveCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800788 @Override
789 public void onAutoFocusMoving(
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700790 boolean moving, CameraProxy camera) {
791 mFocusManager.onAutoFocusMoving(moving);
Michael Kolb8872c232013-01-29 10:33:22 -0800792 }
793 }
794
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700795 /**
796 * This class is just a thread-safe queue for name,date holder objects.
797 */
798 public static class NamedImages {
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800799 private final Vector<NamedEntity> mQueue;
Michael Kolb8872c232013-01-29 10:33:22 -0800800
801 public NamedImages() {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700802 mQueue = new Vector<NamedEntity>();
Michael Kolb8872c232013-01-29 10:33:22 -0800803 }
804
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700805 public void nameNewImage(long date) {
Michael Kolb8872c232013-01-29 10:33:22 -0800806 NamedEntity r = new NamedEntity();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700807 r.title = CameraUtil.createJpegName(date);
Michael Kolb8872c232013-01-29 10:33:22 -0800808 r.date = date;
809 mQueue.add(r);
810 }
811
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700812 public NamedEntity getNextNameEntity() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800813 synchronized (mQueue) {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700814 if (!mQueue.isEmpty()) {
815 return mQueue.remove(0);
816 }
Michael Kolb8872c232013-01-29 10:33:22 -0800817 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700818 return null;
Michael Kolb8872c232013-01-29 10:33:22 -0800819 }
820
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700821 public static class NamedEntity {
822 public String title;
823 public long date;
Michael Kolb8872c232013-01-29 10:33:22 -0800824 }
825 }
826
827 private void setCameraState(int state) {
828 mCameraState = state;
829 switch (state) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700830 case PhotoController.PREVIEW_STOPPED:
831 case PhotoController.SNAPSHOT_IN_PROGRESS:
832 case PhotoController.SWITCHING_CAMERA:
Doris Liuf55f3c42013-11-20 00:24:46 -0800833 // TODO: Tell app UI to disable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700834 break;
835 case PhotoController.IDLE:
Doris Liuf55f3c42013-11-20 00:24:46 -0800836 // TODO: Tell app UI to enable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700837 break;
Michael Kolb8872c232013-01-29 10:33:22 -0800838 }
839 }
840
Sascha Haeberling37f36112013-08-06 14:31:52 -0700841 private void animateAfterShutter() {
Michael Kolb8872c232013-01-29 10:33:22 -0800842 // Only animate when in full screen capture mode
843 // i.e. If monkey/a user swipes to the gallery during picture taking,
844 // don't show animation
Doris Liuc2e9abd2013-06-19 14:20:51 -0700845 if (!mIsImageCaptureIntent) {
846 mUI.animateFlash();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700847 }
Michael Kolb8872c232013-01-29 10:33:22 -0800848 }
849
850 @Override
851 public boolean capture() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800852 // If we are already in the middle of taking a snapshot or the image
853 // save request is full then ignore.
Michael Kolb8872c232013-01-29 10:33:22 -0800854 if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800855 || mCameraState == SWITCHING_CAMERA || !mShutterEnabled) {
Michael Kolb8872c232013-01-29 10:33:22 -0800856 return false;
857 }
858 mCaptureStartTime = System.currentTimeMillis();
859 mPostViewPictureCallbackTime = 0;
860 mJpegImageData = null;
861
Angus Kongb50b5cb2013-08-09 14:55:20 -0700862 final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
Michael Kolb8872c232013-01-29 10:33:22 -0800863
864 if (animateBefore) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700865 animateAfterShutter();
Michael Kolb8872c232013-01-29 10:33:22 -0800866 }
867
868 // Set rotation and gps data.
Doris Liu3cf565c2013-02-15 10:55:37 -0800869 int orientation;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800870
Doris Liu3cf565c2013-02-15 10:55:37 -0800871 // We need to be consistent with the framework orientation (i.e. the
872 // orientation of the UI.) when the auto-rotate screen setting is on.
873 if (mActivity.isAutoRotateScreen()) {
874 orientation = (360 - mDisplayRotation) % 360;
875 } else {
876 orientation = mOrientation;
877 }
Angus Kong20fad242013-11-11 18:23:46 -0800878 mJpegRotation = CameraUtil.getJpegRotation(mActivity, mCameraId, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800879 mParameters.setRotation(mJpegRotation);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800880 Location loc = mActivity.getLocationManager().getCurrentLocation();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700881 CameraUtil.setGpsParameters(mParameters, loc);
Michael Kolb8872c232013-01-29 10:33:22 -0800882 mCameraDevice.setParameters(mParameters);
883
Sascha Haeberling88901942013-08-28 17:49:00 -0700884 // We don't want user to press the button again while taking a
885 // multi-second HDR photo.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800886 setShutterEnabled(false);
Angus Kong9ef99252013-07-18 18:04:19 -0700887 mCameraDevice.takePicture(mHandler,
888 new ShutterCallback(!animateBefore),
Angus Kongdcb0ef12013-03-25 23:11:43 -0700889 mRawPictureCallback, mPostViewPictureCallback,
Angus Kong9ef99252013-07-18 18:04:19 -0700890 new JpegPictureCallback(loc));
Michael Kolb8872c232013-01-29 10:33:22 -0800891
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700892 mNamedImages.nameNewImage(mCaptureStartTime);
Michael Kolb8872c232013-01-29 10:33:22 -0800893
894 mFaceDetectionStarted = false;
895 setCameraState(SNAPSHOT_IN_PROGRESS);
Bobby Georgescu301b6462013-04-01 15:33:17 -0700896 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
Seth Raphaelcbd82672013-11-05 10:12:36 -0800897 UsageStatistics.ACTION_CAPTURE_DONE, "Photo", 0,
Seth Raphael44973262013-11-27 14:29:24 -0800898 UsageStatistics.hashFileName(mNamedImages.mQueue.lastElement().title + ".jpg"));
Michael Kolb8872c232013-01-29 10:33:22 -0800899 return true;
900 }
901
902 @Override
903 public void setFocusParameters() {
904 setCameraParameters(UPDATE_PARAM_PREFERENCE);
905 }
906
Michael Kolbd6954f32013-03-08 20:43:01 -0800907 private void updateSceneMode() {
Michael Kolb8872c232013-01-29 10:33:22 -0800908 // If scene mode is set, we cannot set flash mode, white balance, and
909 // focus mode, instead, we read it from driver
910 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
911 overrideCameraSettings(mParameters.getFlashMode(),
912 mParameters.getWhiteBalance(), mParameters.getFocusMode());
Michael Kolb8872c232013-01-29 10:33:22 -0800913 }
914 }
915
916 private void overrideCameraSettings(final String flashMode,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800917 final String whiteBalance, final String focusMode) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800918 SettingsManager settingsManager = mActivity.getSettingsManager();
919 settingsManager.set(SettingsManager.SETTING_FLASH_MODE, flashMode);
920 settingsManager.set(SettingsManager.SETTING_WHITE_BALANCE, whiteBalance);
921 settingsManager.set(SettingsManager.SETTING_FOCUS_MODE, focusMode);
Michael Kolb8872c232013-01-29 10:33:22 -0800922 }
923
924 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800925 public void onOrientationChanged(int orientation) {
926 // We keep the last known orientation. So if the user first orient
927 // the camera then point the camera to floor or sky, we still have
928 // the correct orientation.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800929 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
930 return;
931 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700932 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800933
934 // Show the toast after getting the first orientation changed.
Angus Kong13e87c42013-11-25 10:02:47 -0800935 if (mHandler.hasMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST)) {
936 mHandler.removeMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST);
Michael Kolb8872c232013-01-29 10:33:22 -0800937 showTapToFocusToast();
938 }
939 }
940
941 @Override
Angus Kong20fad242013-11-11 18:23:46 -0800942 public void onCameraAvailable(CameraProxy cameraProxy) {
943 if (mPaused) {
944 return;
945 }
946 mCameraDevice = cameraProxy;
947
Erin Dahlgren357b7672013-11-20 17:38:14 -0800948 resetExposureCompensation();
Angus Kong20fad242013-11-11 18:23:46 -0800949 initializeCapabilities();
950
951 // Reset zoom value index.
952 mZoomValue = 0;
953 if (mFocusManager == null) {
954 initializeFocusManager();
955 }
956 mFocusManager.setParameters(mInitialParams);
957
Erin Dahlgren7f0151d2014-01-02 16:08:12 -0800958 // Do camera parameter dependent initialization.
Angus Kong20fad242013-11-11 18:23:46 -0800959 mParameters = mCameraDevice.getParameters();
960 setCameraParameters(UPDATE_PARAM_ALL);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -0800961 // Set a listener which updates camera parameters based
962 // on changed settings.
963 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren1648c362014-01-06 15:06:04 -0800964 settingsManager.addListener(this);
Angus Kong20fad242013-11-11 18:23:46 -0800965 mCameraPreviewParamsReady = true;
Erin Dahlgren7f0151d2014-01-02 16:08:12 -0800966
Angus Kong20fad242013-11-11 18:23:46 -0800967 startPreview();
968
969 onCameraOpened();
970 }
971
972 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -0800973 public void onCaptureCancelled() {
974 mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
975 mActivity.finish();
Michael Kolb8872c232013-01-29 10:33:22 -0800976 }
977
Michael Kolbd6954f32013-03-08 20:43:01 -0800978 @Override
979 public void onCaptureRetake() {
Michael Kolb8872c232013-01-29 10:33:22 -0800980 if (mPaused)
981 return;
Michael Kolbd6954f32013-03-08 20:43:01 -0800982 mUI.hidePostCaptureAlert();
Michael Kolb8872c232013-01-29 10:33:22 -0800983 setupPreview();
984 }
985
Michael Kolbd6954f32013-03-08 20:43:01 -0800986 @Override
987 public void onCaptureDone() {
Michael Kolb8872c232013-01-29 10:33:22 -0800988 if (mPaused) {
989 return;
990 }
991
992 byte[] data = mJpegImageData;
993
994 if (mCropValue == null) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800995 // First handle the no crop case -- just return the value. If the
Michael Kolb8872c232013-01-29 10:33:22 -0800996 // caller specifies a "save uri" then write the data to its
997 // stream. Otherwise, pass back a scaled down version of the bitmap
998 // directly in the extras.
999 if (mSaveUri != null) {
1000 OutputStream outputStream = null;
1001 try {
1002 outputStream = mContentResolver.openOutputStream(mSaveUri);
1003 outputStream.write(data);
1004 outputStream.close();
1005
1006 mActivity.setResultEx(Activity.RESULT_OK);
1007 mActivity.finish();
1008 } catch (IOException ex) {
1009 // ignore exception
1010 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001011 CameraUtil.closeSilently(outputStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001012 }
1013 } else {
Angus Kong0d00a892013-03-26 11:40:40 -07001014 ExifInterface exif = Exif.getExif(data);
1015 int orientation = Exif.getOrientation(exif);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001016 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
1017 bitmap = CameraUtil.rotate(bitmap, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001018 mActivity.setResultEx(Activity.RESULT_OK,
1019 new Intent("inline-data").putExtra("data", bitmap));
1020 mActivity.finish();
1021 }
1022 } else {
1023 // Save the image to a temp file and invoke the cropper
1024 Uri tempUri = null;
1025 FileOutputStream tempStream = null;
1026 try {
1027 File path = mActivity.getFileStreamPath(sTempCropFilename);
1028 path.delete();
1029 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1030 tempStream.write(data);
1031 tempStream.close();
1032 tempUri = Uri.fromFile(path);
1033 } catch (FileNotFoundException ex) {
1034 mActivity.setResultEx(Activity.RESULT_CANCELED);
1035 mActivity.finish();
1036 return;
1037 } catch (IOException ex) {
1038 mActivity.setResultEx(Activity.RESULT_CANCELED);
1039 mActivity.finish();
1040 return;
1041 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001042 CameraUtil.closeSilently(tempStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001043 }
1044
1045 Bundle newExtras = new Bundle();
1046 if (mCropValue.equals("circle")) {
1047 newExtras.putString("circleCrop", "true");
1048 }
1049 if (mSaveUri != null) {
1050 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1051 } else {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001052 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001053 }
1054 if (mActivity.isSecureCamera()) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001055 newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001056 }
1057
Sascha Haeberling37f36112013-08-06 14:31:52 -07001058 // TODO: Share this constant.
Sascha Haeberling8e963a52013-08-06 11:43:02 -07001059 final String CROP_ACTION = "com.android.camera.action.CROP";
1060 Intent cropIntent = new Intent(CROP_ACTION);
Michael Kolb8872c232013-01-29 10:33:22 -08001061
1062 cropIntent.setData(tempUri);
1063 cropIntent.putExtras(newExtras);
1064
1065 mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1066 }
1067 }
1068
Michael Kolb8872c232013-01-29 10:33:22 -08001069 @Override
1070 public void onShutterButtonFocus(boolean pressed) {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001071 if (mPaused || (mCameraState == SNAPSHOT_IN_PROGRESS)
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001072 || (mCameraState == PREVIEW_STOPPED)) {
1073 return;
1074 }
Michael Kolb8872c232013-01-29 10:33:22 -08001075
1076 // Do not do focus if there is not enough storage.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001077 if (pressed && !canTakePicture()) {
1078 return;
1079 }
Michael Kolb8872c232013-01-29 10:33:22 -08001080
1081 if (pressed) {
Michael Kolb8872c232013-01-29 10:33:22 -08001082 mFocusManager.onShutterDown();
1083 } else {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001084 mFocusManager.onShutterUp();
Michael Kolb8872c232013-01-29 10:33:22 -08001085 }
1086 }
1087
1088 @Override
1089 public void onShutterButtonClick() {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001090 if (mPaused || (mCameraState == SWITCHING_CAMERA)
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001091 || (mCameraState == PREVIEW_STOPPED)) {
1092 return;
1093 }
Michael Kolb8872c232013-01-29 10:33:22 -08001094
1095 // Do not take the picture if there is not enough storage.
Angus Kong2dcc0a92013-09-25 13:00:08 -07001096 if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Michael Kolb8872c232013-01-29 10:33:22 -08001097 Log.i(TAG, "Not enough space or storage not ready. remaining="
Angus Kong2dcc0a92013-09-25 13:00:08 -07001098 + mActivity.getStorageSpaceBytes());
Michael Kolb8872c232013-01-29 10:33:22 -08001099 return;
1100 }
1101 Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1102
Angus Kongb50b5cb2013-08-09 14:55:20 -07001103 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -07001104 mUI.setSwipingEnabled(false);
Doris Liu9cdfe002013-04-16 09:50:56 -07001105 }
Michael Kolb8872c232013-01-29 10:33:22 -08001106 // If the user wants to do a snapshot while the previous one is still
1107 // in progress, remember the fact and do it after we finish the previous
1108 // one and re-start the preview. Snapshot in progress also includes the
1109 // state that autofocus is focusing and a picture will be taken when
1110 // focus callback arrives.
1111 if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1112 && !mIsImageCaptureIntent) {
1113 mSnapshotOnIdle = true;
1114 return;
1115 }
1116
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001117 mSnapshotOnIdle = false;
1118 mFocusManager.doSnap();
Michael Kolb8872c232013-01-29 10:33:22 -08001119 }
1120
Andy Huibersdef975d2013-11-22 09:13:39 -08001121 private void onResumeTasks() {
1122 Log.v(TAG, "Executing onResumeTasks.");
Angus Kong20fad242013-11-11 18:23:46 -08001123 mActivity.getCameraProvider().requestCamera(mCameraId);
1124
Michael Kolb8872c232013-01-29 10:33:22 -08001125 mJpegPictureCallbackTime = 0;
1126 mZoomValue = 0;
Angus Kong20fad242013-11-11 18:23:46 -08001127
1128 mOnResumeTime = SystemClock.uptimeMillis();
1129 checkDisplayRotation();
Michael Kolb8872c232013-01-29 10:33:22 -08001130
1131 // If first time initialization is not finished, put it in the
1132 // message queue.
1133 if (!mFirstTimeInitialized) {
Angus Kong13e87c42013-11-25 10:02:47 -08001134 mHandler.sendEmptyMessage(MSG_FIRST_TIME_INIT);
Michael Kolb8872c232013-01-29 10:33:22 -08001135 } else {
1136 initializeSecondTime();
1137 }
Michael Kolb8872c232013-01-29 10:33:22 -08001138
Bobby Georgescu0a7dd572013-03-12 22:45:17 -07001139 UsageStatistics.onContentViewChanged(
1140 UsageStatistics.COMPONENT_CAMERA, "PhotoModule");
Angus Kong0d00a892013-03-26 11:40:40 -07001141
1142 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1143 if (gsensor != null) {
1144 mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1145 }
1146
1147 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1148 if (msensor != null) {
1149 mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1150 }
Michael Kolb8872c232013-01-29 10:33:22 -08001151 }
1152
Angus Kongc4e66562013-11-22 23:03:21 -08001153 /**
1154 * The focus manager is the first UI related element to get initialized,
1155 * and it requires the RenderOverlay, so initialize it here
1156 */
1157 private void initializeFocusManager() {
1158 // Create FocusManager object. startPreview needs it.
1159 // if mFocusManager not null, reuse it
1160 // otherwise create a new instance
1161 if (mFocusManager != null) {
1162 mFocusManager.removeMessages();
1163 } else {
Angus Kongd74e6a12014-01-07 11:29:44 -08001164 CameraInfo info = mAppController.getCameraProvider().getCameraInfo()[mCameraId];
Angus Kongc4e66562013-11-22 23:03:21 -08001165 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
1166 String[] defaultFocusModes = mActivity.getResources().getStringArray(
1167 R.array.pref_camera_focusmode_default_array);
Erin Dahlgren357b7672013-11-20 17:38:14 -08001168 mFocusManager = new FocusOverlayManager(mActivity.getSettingsManager(),
1169 defaultFocusModes,
Angus Kongc4e66562013-11-22 23:03:21 -08001170 mInitialParams, this, mMirror,
Doris Liu482de022013-12-18 19:18:16 -08001171 mActivity.getMainLooper(), mUI.getFocusUI());
Angus Kongc4e66562013-11-22 23:03:21 -08001172 }
Doris Liu482de022013-12-18 19:18:16 -08001173 mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
Angus Kong20fad242013-11-11 18:23:46 -08001174 }
1175
1176 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001177 public void resume() {
1178 mPaused = false;
Doris Liu482de022013-12-18 19:18:16 -08001179 if (mFocusManager != null) {
Doris Liu15b99612013-12-21 11:32:28 -08001180 // If camera is not open when resume is called, focus manager will not
1181 // be initialized yet, in which case it will start listening to
1182 // preview area size change later in the initialization.
Doris Liu482de022013-12-18 19:18:16 -08001183 mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
1184 }
Angus Kongc4e66562013-11-22 23:03:21 -08001185 // Add delay on resume from lock screen only, in order to to speed up
1186 // the onResume --> onPause --> onResume cycle from lock screen.
1187 // Don't do always because letting go of thread can cause delay.
1188 String action = mActivity.getIntent().getAction();
1189 if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
1190 || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
1191 Log.v(TAG, "On resume, from lock screen.");
1192 // Note: onPauseAfterSuper() will delete this runnable, so we will
1193 // at most have 1 copy queued up.
1194 mHandler.postDelayed(new Runnable() {
Sameer Padala2c8cc452013-11-05 18:49:12 -08001195 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001196 public void run() {
1197 onResumeTasks();
1198 }
1199 }, ON_RESUME_TASKS_DELAY_MSEC);
1200 } else {
1201 Log.v(TAG, "On resume.");
1202 onResumeTasks();
1203 }
1204 }
1205
1206 @Override
1207 public void pause() {
Michael Kolb8872c232013-01-29 10:33:22 -08001208 mPaused = true;
Angus Kong0d00a892013-03-26 11:40:40 -07001209 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1210 if (gsensor != null) {
1211 mSensorManager.unregisterListener(this, gsensor);
1212 }
1213
1214 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1215 if (msensor != null) {
1216 mSensorManager.unregisterListener(this, msensor);
1217 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001218
Michael Kolb8872c232013-01-29 10:33:22 -08001219 // Reset the focus first. Camera CTS does not guarantee that
1220 // cancelAutoFocus is allowed after preview stops.
1221 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1222 mCameraDevice.cancelAutoFocus();
1223 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001224
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -08001225 // If the camera has not been opened asynchronously yet,
1226 // and startPreview hasn't been called, then this is a no-op.
1227 // (e.g. onResume -> onPause -> onResume).
Michael Kolb8872c232013-01-29 10:33:22 -08001228 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001229
Angus Kongce5480e2013-01-29 17:43:48 -08001230 mNamedImages = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001231
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001232 if (mLocationManager != null) {
1233 mLocationManager.recordLocation(false);
1234 }
Michael Kolb8872c232013-01-29 10:33:22 -08001235
1236 // If we are in an image capture intent and has taken
1237 // a picture, we just clear it in onPause.
1238 mJpegImageData = null;
1239
Angus Kongdcccc512013-08-08 17:06:03 -07001240 // Remove the messages and runnables in the queue.
1241 mHandler.removeCallbacksAndMessages(null);
Michael Kolb8872c232013-01-29 10:33:22 -08001242
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001243 closeCamera();
Angus Kong13e87c42013-11-25 10:02:47 -08001244 mActivity.enableKeepScreenOn(false);
Michael Kolbd6954f32013-03-08 20:43:01 -08001245 mUI.onPause();
1246
Michael Kolb8872c232013-01-29 10:33:22 -08001247 mPendingSwitchCameraId = -1;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001248 if (mFocusManager != null) {
1249 mFocusManager.removeMessages();
Angus Kong86d36312013-01-31 18:22:44 -08001250 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001251 getServices().getMemoryManager().removeListener(this);
Doris Liu482de022013-12-18 19:18:16 -08001252 mAppController.removePreviewAreaSizeChangedListener(mFocusManager);
Erin Dahlgren1648c362014-01-06 15:06:04 -08001253
1254 SettingsManager settingsManager = mActivity.getSettingsManager();
1255 settingsManager.removeListener(this);
Michael Kolb8872c232013-01-29 10:33:22 -08001256 }
1257
Angus Kong20fad242013-11-11 18:23:46 -08001258 @Override
1259 public void destroy() {
1260 // TODO: implement this.
1261 }
1262
1263 @Override
1264 public void onPreviewSizeChanged(int width, int height) {
1265 // TODO: implement this.
1266 }
1267
1268 @Override
Angus Kong2f0e4a32013-12-03 10:02:35 -08001269 public void onLayoutOrientationChanged(boolean isLandscape) {
Michael Kolb8872c232013-01-29 10:33:22 -08001270 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001271 }
1272
1273 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001274 public void updateCameraOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001275 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001276 setDisplayOrientation();
1277 }
1278 }
1279
Michael Kolb8872c232013-01-29 10:33:22 -08001280 private boolean canTakePicture() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001281 return isCameraIdle()
1282 && (mActivity.getStorageSpaceBytes() > Storage.LOW_STORAGE_THRESHOLD_BYTES);
Michael Kolb8872c232013-01-29 10:33:22 -08001283 }
1284
1285 @Override
1286 public void autoFocus() {
1287 mFocusStartTime = System.currentTimeMillis();
Angus Kong9ef99252013-07-18 18:04:19 -07001288 mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001289 setCameraState(FOCUSING);
1290 }
1291
1292 @Override
1293 public void cancelAutoFocus() {
1294 mCameraDevice.cancelAutoFocus();
1295 setCameraState(IDLE);
1296 setCameraParameters(UPDATE_PARAM_PREFERENCE);
1297 }
1298
Michael Kolb8872c232013-01-29 10:33:22 -08001299 @Override
1300 public void onSingleTapUp(View view, int x, int y) {
Doris Liu482de022013-12-18 19:18:16 -08001301 if (mPaused || mCameraDevice == null || !mFirstTimeInitialized
1302 || mCameraState == SNAPSHOT_IN_PROGRESS
1303 || mCameraState == SWITCHING_CAMERA
1304 || mCameraState == PREVIEW_STOPPED) {
1305 return;
1306 }
1307
1308 // Check if metering area or focus area is supported.
Doris Liu15b99612013-12-21 11:32:28 -08001309 if (!mFocusAreaSupported && !mMeteringAreaSupported) {
1310 return;
1311 }
Doris Liu482de022013-12-18 19:18:16 -08001312 mFocusManager.onSingleTapUp(x, y);
Michael Kolb8872c232013-01-29 10:33:22 -08001313 }
1314
1315 @Override
1316 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001317 return mUI.onBackPressed();
Michael Kolb8872c232013-01-29 10:33:22 -08001318 }
1319
1320 @Override
1321 public boolean onKeyDown(int keyCode, KeyEvent event) {
1322 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001323 case KeyEvent.KEYCODE_VOLUME_UP:
1324 case KeyEvent.KEYCODE_VOLUME_DOWN:
1325 case KeyEvent.KEYCODE_FOCUS:
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001326 if (/* TODO: mActivity.isInCameraApp() && */mFirstTimeInitialized) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001327 if (event.getRepeatCount() == 0) {
1328 onShutterButtonFocus(true);
1329 }
1330 return true;
1331 }
1332 return false;
1333 case KeyEvent.KEYCODE_CAMERA:
1334 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1335 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001336 }
1337 return true;
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001338 case KeyEvent.KEYCODE_DPAD_CENTER:
1339 // If we get a dpad center event without any focused view, move
1340 // the focus to the shutter button and press it.
1341 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1342 // Start auto-focus immediately to reduce shutter lag. After
1343 // the shutter button gets the focus, onShutterButtonFocus()
1344 // will be called again but it is fine.
1345 onShutterButtonFocus(true);
1346 mUI.pressShutterButton();
1347 }
1348 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001349 }
1350 return false;
1351 }
1352
1353 @Override
1354 public boolean onKeyUp(int keyCode, KeyEvent event) {
1355 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001356 case KeyEvent.KEYCODE_VOLUME_UP:
1357 case KeyEvent.KEYCODE_VOLUME_DOWN:
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001358 if (/* mActivity.isInCameraApp() && */mFirstTimeInitialized) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001359 onShutterButtonClick();
1360 return true;
1361 }
1362 return false;
1363 case KeyEvent.KEYCODE_FOCUS:
1364 if (mFirstTimeInitialized) {
1365 onShutterButtonFocus(false);
1366 }
Michael Kolb8872c232013-01-29 10:33:22 -08001367 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001368 }
1369 return false;
1370 }
1371
Michael Kolb8872c232013-01-29 10:33:22 -08001372 private void closeCamera() {
1373 if (mCameraDevice != null) {
1374 mCameraDevice.setZoomChangeListener(null);
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001375 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001376 mCameraDevice.setErrorCallback(null);
Ruben Brunk59147832013-11-05 15:53:28 -08001377
Michael Kolb8872c232013-01-29 10:33:22 -08001378 mFaceDetectionStarted = false;
Angus Kong20fad242013-11-11 18:23:46 -08001379 mActivity.getCameraProvider().releaseCamera(mCameraDevice.getCameraId());
Michael Kolb8872c232013-01-29 10:33:22 -08001380 mCameraDevice = null;
1381 setCameraState(PREVIEW_STOPPED);
1382 mFocusManager.onCameraReleased();
1383 }
1384 }
1385
1386 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001387 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1388 mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001389 mCameraDisplayOrientation = mDisplayOrientation;
Michael Kolbd6954f32013-03-08 20:43:01 -08001390 mUI.setDisplayOrientation(mDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001391 if (mFocusManager != null) {
1392 mFocusManager.setDisplayOrientation(mDisplayOrientation);
1393 }
Doris Liu6432cd62013-06-13 17:20:31 -07001394 // Change the camera display orientation
1395 if (mCameraDevice != null) {
1396 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1397 }
Michael Kolb8872c232013-01-29 10:33:22 -08001398 }
1399
Sascha Haeberlingddef7792013-08-13 14:41:10 -07001400 /** Only called by UI thread. */
Michael Kolb8872c232013-01-29 10:33:22 -08001401 private void setupPreview() {
1402 mFocusManager.resetTouchFocus();
1403 startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001404 }
1405
Angus Kong20fad242013-11-11 18:23:46 -08001406 /**
1407 * Returns whether we can/should start the preview or not.
1408 */
1409 private boolean checkPreviewPreconditions() {
1410 if (mPaused) {
1411 return false;
Angus Kongdcccc512013-08-08 17:06:03 -07001412 }
Michael Kolb8872c232013-01-29 10:33:22 -08001413
Angus Kong20fad242013-11-11 18:23:46 -08001414 if (mCameraDevice == null) {
1415 Log.w(TAG, "startPreview: camera device not ready yet.");
1416 return false;
1417 }
1418
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001419 SurfaceTexture st = mUI.getSurfaceTexture();
1420 if (st == null) {
1421 Log.w(TAG, "startPreview: surfaceTexture is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001422 return false;
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001423 }
1424
1425 if (!mCameraPreviewParamsReady) {
1426 Log.w(TAG, "startPreview: parameters for preview is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001427 return false;
1428 }
1429 return true;
1430 }
1431
1432 /**
1433 * The start/stop preview should only run on the UI thread.
1434 */
1435 private void startPreview() {
1436 if (!checkPreviewPreconditions()) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001437 return;
1438 }
Angus Kong20fad242013-11-11 18:23:46 -08001439
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001440 mCameraDevice.setErrorCallback(mErrorCallback);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001441 // ICS camera frameworks has a bug. Face detection state is not cleared
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001442 // after taking a picture. Stop the preview to work around it. The bug
1443 // was fixed in JB.
1444 if (mCameraState != PREVIEW_STOPPED) {
1445 stopPreview();
1446 }
1447
1448 setDisplayOrientation();
1449
1450 if (!mSnapshotOnIdle) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001451 // If the focus mode is continuous autofocus, call cancelAutoFocus
1452 // to resume it because it may have been paused by autoFocus call.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001453 String focusMode = mFocusManager.getFocusMode();
1454 if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(focusMode)) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001455 mCameraDevice.cancelAutoFocus();
Michael Kolb8872c232013-01-29 10:33:22 -08001456 }
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001457 mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1458 }
1459 setCameraParameters(UPDATE_PARAM_ALL);
1460 // Let UI set its expected aspect ratio
Angus Kong20fad242013-11-11 18:23:46 -08001461 mCameraDevice.setPreviewTexture(mUI.getSurfaceTexture());
Michael Kolb8872c232013-01-29 10:33:22 -08001462
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001463 Log.v(TAG, "startPreview");
1464 mCameraDevice.startPreview();
Angus Kong20fad242013-11-11 18:23:46 -08001465
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001466 mFocusManager.onPreviewStarted();
1467 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001468
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001469 if (mSnapshotOnIdle) {
1470 mHandler.post(mDoSnapRunnable);
Michael Kolb8872c232013-01-29 10:33:22 -08001471 }
1472 }
1473
Michael Kolbd6954f32013-03-08 20:43:01 -08001474 @Override
1475 public void stopPreview() {
Michael Kolb8872c232013-01-29 10:33:22 -08001476 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1477 Log.v(TAG, "stopPreview");
1478 mCameraDevice.stopPreview();
1479 mFaceDetectionStarted = false;
1480 }
1481 setCameraState(PREVIEW_STOPPED);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001482 if (mFocusManager != null) {
1483 mFocusManager.onPreviewStopped();
1484 }
Sameer Padala2c8cc452013-11-05 18:49:12 -08001485 stopSmartCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001486 }
1487
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001488 @Override
Erin Dahlgren1648c362014-01-06 15:06:04 -08001489 public void onSettingChanged(SettingsManager settingsManager, int id) {
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001490 switch (id) {
1491 case SettingsManager.SETTING_FLASH_MODE: {
1492 updateParametersFlashMode();
1493 break;
1494 }
1495 case SettingsManager.SETTING_PICTURE_SIZE: {
1496 updateParametersPictureSize();
1497 break;
1498 }
1499 case SettingsManager.SETTING_RECORD_LOCATION: {
1500 SettingsController settingsController = mActivity.getSettingsController();
1501 settingsController.syncLocationManager();
1502 break;
1503 }
1504 default: {
1505 // Do nothing.
1506 }
1507 }
Erin Dahlgren1648c362014-01-06 15:06:04 -08001508
1509 if (mCameraDevice != null) {
1510 mCameraDevice.setParameters(mParameters);
1511 }
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001512 }
1513
Michael Kolb8872c232013-01-29 10:33:22 -08001514 private void updateCameraParametersInitialize() {
1515 // Reset preview frame rate to the maximum because it may be lowered by
1516 // video camera application.
ztenghui16a35202013-09-23 11:35:36 -07001517 int[] fpsRange = CameraUtil.getPhotoPreviewFpsRange(mParameters);
1518 if (fpsRange != null && fpsRange.length > 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001519 mParameters.setPreviewFpsRange(
1520 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1521 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
Michael Kolb8872c232013-01-29 10:33:22 -08001522 }
1523
Angus Kongb50b5cb2013-08-09 14:55:20 -07001524 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);
Michael Kolb8872c232013-01-29 10:33:22 -08001525
1526 // Disable video stabilization. Convenience methods not available in API
1527 // level <= 14
1528 String vstabSupported = mParameters.get("video-stabilization-supported");
1529 if ("true".equals(vstabSupported)) {
1530 mParameters.set("video-stabilization", "false");
1531 }
1532 }
1533
1534 private void updateCameraParametersZoom() {
1535 // Set zoom.
1536 if (mParameters.isZoomSupported()) {
1537 mParameters.setZoom(mZoomValue);
1538 }
1539 }
1540
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001541 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001542 private void setAutoExposureLockIfSupported() {
1543 if (mAeLockSupported) {
1544 mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1545 }
1546 }
1547
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001548 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001549 private void setAutoWhiteBalanceLockIfSupported() {
1550 if (mAwbLockSupported) {
1551 mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1552 }
1553 }
1554
Michael Kolb8872c232013-01-29 10:33:22 -08001555 private void setFocusAreasIfSupported() {
1556 if (mFocusAreaSupported) {
1557 mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1558 }
1559 }
1560
Michael Kolb8872c232013-01-29 10:33:22 -08001561 private void setMeteringAreasIfSupported() {
1562 if (mMeteringAreaSupported) {
Michael Kolb8872c232013-01-29 10:33:22 -08001563 mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1564 }
1565 }
1566
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001567 private void updateCameraParametersPreference() {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001568 SettingsManager settingsManager = mActivity.getSettingsManager();
1569
Michael Kolb8872c232013-01-29 10:33:22 -08001570 setAutoExposureLockIfSupported();
1571 setAutoWhiteBalanceLockIfSupported();
1572 setFocusAreasIfSupported();
1573 setMeteringAreasIfSupported();
1574
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001575 // Initialize focus mode.
Michael Kolbd3253f22013-07-12 11:36:47 -07001576 mFocusManager.overrideFocusMode(null);
1577 mParameters.setFocusMode(mFocusManager.getFocusMode());
1578
Michael Kolb8872c232013-01-29 10:33:22 -08001579 // Set picture size.
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001580 updateParametersPictureSize();
1581
1582 // Set JPEG quality.
1583 updateParametersPictureQuality();
1584
1585 // For the following settings, we need to check if the settings are
1586 // still supported by latest driver, if not, ignore the settings.
1587
1588 // Set exposure compensation
1589 updateParametersExposureCompensation();
1590
1591 // Set the scene mode: also sets flash and white balance.
1592 updateParametersSceneMode();
1593
1594 if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
1595 updateAutoFocusMoveCallback();
1596 }
1597 }
1598
1599 private void updateParametersPictureSize() {
1600 SettingsManager settingsManager = mActivity.getSettingsManager();
1601
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001602 String pictureSize = settingsManager.get(SettingsManager.SETTING_PICTURE_SIZE);
Michael Kolb8872c232013-01-29 10:33:22 -08001603 if (pictureSize == null) {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001604 //TODO: deprecate CameraSettings.
1605 CameraSettings.initialCameraPictureSize(
1606 mActivity, mParameters, settingsManager);
Michael Kolb8872c232013-01-29 10:33:22 -08001607 } else {
1608 List<Size> supported = mParameters.getSupportedPictureSizes();
1609 CameraSettings.setCameraPictureSize(
1610 pictureSize, supported, mParameters);
1611 }
1612 Size size = mParameters.getPictureSize();
1613
1614 // Set a preview size that is closest to the viewfinder height and has
1615 // the right aspect ratio.
1616 List<Size> sizes = mParameters.getSupportedPreviewSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001617 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
Michael Kolb8872c232013-01-29 10:33:22 -08001618 (double) size.width / size.height);
1619 Size original = mParameters.getPreviewSize();
1620 if (!original.equals(optimalSize)) {
1621 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
Doris Liu6432cd62013-06-13 17:20:31 -07001622
Michael Kolb8872c232013-01-29 10:33:22 -08001623 // Zoom related settings will be changed for different preview
1624 // sizes, so set and read the parameters to get latest values
Michael Kolb4a4d4ef2013-05-30 08:35:26 -07001625 if (mHandler.getLooper() == Looper.myLooper()) {
1626 // On UI thread only, not when camera starts up
1627 setupPreview();
1628 } else {
1629 mCameraDevice.setParameters(mParameters);
1630 }
Michael Kolb8872c232013-01-29 10:33:22 -08001631 mParameters = mCameraDevice.getParameters();
1632 }
Doris Liu95405742013-11-05 15:25:26 -08001633
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001634 if (optimalSize.width != 0 && optimalSize.height != 0) {
Doris Liu95405742013-11-05 15:25:26 -08001635 mUI.updatePreviewAspectRatio((float) optimalSize.width
1636 / (float) optimalSize.height);
1637 }
Michael Kolb8872c232013-01-29 10:33:22 -08001638 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001639 }
Michael Kolb8872c232013-01-29 10:33:22 -08001640
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001641 private void updateParametersPictureQuality() {
Michael Kolb8872c232013-01-29 10:33:22 -08001642 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1643 CameraProfile.QUALITY_HIGH);
1644 mParameters.setJpegQuality(jpegQuality);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001645 }
Michael Kolb8872c232013-01-29 10:33:22 -08001646
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001647 private void updateParametersExposureCompensation() {
1648 SettingsManager settingsManager = mActivity.getSettingsManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001649
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001650 int value = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_EXPOSURE));
Michael Kolb8872c232013-01-29 10:33:22 -08001651 int max = mParameters.getMaxExposureCompensation();
1652 int min = mParameters.getMinExposureCompensation();
1653 if (value >= min && value <= max) {
1654 mParameters.setExposureCompensation(value);
1655 } else {
1656 Log.w(TAG, "invalid exposure range: " + value);
1657 }
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001658 }
1659
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001660 private void updateParametersSceneMode() {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001661 SettingsManager settingsManager = mActivity.getSettingsManager();
1662
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001663 mSceneMode = settingsManager.get(SettingsManager.SETTING_SCENE_MODE);
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001664 if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
1665 if (!mParameters.getSceneMode().equals(mSceneMode)) {
1666 mParameters.setSceneMode(mSceneMode);
1667
1668 // Setting scene mode will change the settings of flash mode,
1669 // white balance, and focus mode. Here we read back the
1670 // parameters, so we can know those settings.
1671 mCameraDevice.setParameters(mParameters);
1672 mParameters = mCameraDevice.getParameters();
1673 }
1674 } else {
1675 mSceneMode = mParameters.getSceneMode();
1676 if (mSceneMode == null) {
1677 mSceneMode = Parameters.SCENE_MODE_AUTO;
1678 }
1679 }
1680
Michael Kolb8872c232013-01-29 10:33:22 -08001681 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1682 // Set flash mode.
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001683 updateParametersFlashMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001684
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001685 // Set white balance mode.
1686 updateParametersWhiteBalanceMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001687
1688 // Set focus mode.
1689 mFocusManager.overrideFocusMode(null);
1690 mParameters.setFocusMode(mFocusManager.getFocusMode());
1691 } else {
1692 mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1693 }
Michael Kolb8872c232013-01-29 10:33:22 -08001694 }
1695
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001696 private void updateParametersFlashMode() {
1697 SettingsManager settingsManager = mActivity.getSettingsManager();
1698
1699 String flashMode = settingsManager.get(SettingsManager.SETTING_FLASH_MODE);
1700 List<String> supportedFlash = mParameters.getSupportedFlashModes();
1701 if (CameraUtil.isSupported(flashMode, supportedFlash)) {
1702 mParameters.setFlashMode(flashMode);
1703 }
1704 }
1705
1706 private void updateParametersWhiteBalanceMode() {
1707 SettingsManager settingsManager = mActivity.getSettingsManager();
1708
1709 // Set white balance parameter.
1710 String whiteBalance = settingsManager.get(SettingsManager.SETTING_WHITE_BALANCE);
1711 if (CameraUtil.isSupported(whiteBalance,
1712 mParameters.getSupportedWhiteBalance())) {
1713 mParameters.setWhiteBalance(whiteBalance);
1714 }
1715 }
1716
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001717 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001718 private void updateAutoFocusMoveCallback() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001719 if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Angus Kong9ef99252013-07-18 18:04:19 -07001720 mCameraDevice.setAutoFocusMoveCallback(mHandler,
Angus Kong4f795b82013-09-16 14:25:35 -07001721 (CameraAFMoveCallback) mAutoFocusMoveCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001722 } else {
Angus Kong9ef99252013-07-18 18:04:19 -07001723 mCameraDevice.setAutoFocusMoveCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001724 }
1725 }
1726
1727 // We separate the parameters into several subsets, so we can update only
1728 // the subsets actually need updating. The PREFERENCE set needs extra
1729 // locking because the preference can be changed from GLThread as well.
1730 private void setCameraParameters(int updateSet) {
1731 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1732 updateCameraParametersInitialize();
1733 }
1734
1735 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1736 updateCameraParametersZoom();
1737 }
1738
1739 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001740 updateCameraParametersPreference();
Michael Kolb8872c232013-01-29 10:33:22 -08001741 }
1742
1743 mCameraDevice.setParameters(mParameters);
1744 }
1745
1746 // If the Camera is idle, update the parameters immediately, otherwise
1747 // accumulate them in mUpdateSet and update later.
1748 private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1749 mUpdateSet |= additionalUpdateSet;
1750 if (mCameraDevice == null) {
1751 // We will update all the parameters when we open the device, so
1752 // we don't need to do anything now.
1753 mUpdateSet = 0;
1754 return;
1755 } else if (isCameraIdle()) {
1756 setCameraParameters(mUpdateSet);
Michael Kolbd6954f32013-03-08 20:43:01 -08001757 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001758 mUpdateSet = 0;
1759 } else {
Angus Kong13e87c42013-11-25 10:02:47 -08001760 if (!mHandler.hasMessages(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1761 mHandler.sendEmptyMessageDelayed(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
Michael Kolb8872c232013-01-29 10:33:22 -08001762 }
1763 }
1764 }
1765
ztenghui7b265a62013-09-09 14:58:44 -07001766 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001767 public boolean isCameraIdle() {
Michael Kolb8872c232013-01-29 10:33:22 -08001768 return (mCameraState == IDLE) ||
1769 (mCameraState == PREVIEW_STOPPED) ||
1770 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
1771 && (mCameraState != SWITCHING_CAMERA));
1772 }
1773
ztenghui7b265a62013-09-09 14:58:44 -07001774 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001775 public boolean isImageCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001776 String action = mActivity.getIntent().getAction();
1777 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
Angus Kong6a8e8a12013-07-19 14:55:07 -07001778 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
Michael Kolb8872c232013-01-29 10:33:22 -08001779 }
1780
1781 private void setupCaptureParams() {
1782 Bundle myExtras = mActivity.getIntent().getExtras();
1783 if (myExtras != null) {
1784 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1785 mCropValue = myExtras.getString("crop");
1786 }
1787 }
1788
Michael Kolb8872c232013-01-29 10:33:22 -08001789 public void onSharedPreferenceChanged() {
1790 // ignore the events after "onPause()"
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001791 if (mPaused) {
1792 return;
1793 }
Michael Kolb8872c232013-01-29 10:33:22 -08001794
Erin Dahlgren357b7672013-11-20 17:38:14 -08001795 SettingsController settingsController = mActivity.getSettingsController();
1796 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001797
1798 setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
Michael Kolb8872c232013-01-29 10:33:22 -08001799 }
1800
Michael Kolb8872c232013-01-29 10:33:22 -08001801 private void showTapToFocusToast() {
1802 // TODO: Use a toast?
1803 new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
1804 // Clear the preference.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001805 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001806 settingsManager.setBoolean(
1807 SettingsManager.SETTING_CAMERA_FIRST_USE_HINT_SHOWN, false);
Michael Kolb8872c232013-01-29 10:33:22 -08001808 }
1809
1810 private void initializeCapabilities() {
1811 mInitialParams = mCameraDevice.getParameters();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001812 mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
1813 mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
1814 mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
1815 mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
Angus Kongdcccc512013-08-08 17:06:03 -07001816 mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001817 CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
Michael Kolb8872c232013-01-29 10:33:22 -08001818 }
1819
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001820 private void setShutterEnabled(boolean enabled) {
1821 mShutterEnabled = enabled;
1822 mUI.enableShutter(enabled);
1823 }
1824
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001825 // TODO: Remove this
Michael Kolb8872c232013-01-29 10:33:22 -08001826 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001827 public int onZoomChanged(int index) {
1828 // Not useful to change zoom value when the activity is paused.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001829 if (mPaused) {
1830 return index;
1831 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001832 mZoomValue = index;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001833 if (mParameters == null || mCameraDevice == null) {
1834 return index;
1835 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001836 // Set zoom parameters asynchronously
1837 mParameters.setZoom(mZoomValue);
Angus Kong36ed8672013-04-15 12:11:15 -07001838 mCameraDevice.setParameters(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -08001839 Parameters p = mCameraDevice.getParameters();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001840 if (p != null) {
1841 return p.getZoom();
1842 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001843 return index;
Angus Kongce5480e2013-01-29 17:43:48 -08001844 }
1845
1846 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001847 public int getCameraState() {
1848 return mCameraState;
1849 }
1850
1851 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001852 public void onMemoryStateChanged(int state) {
1853 setShutterEnabled(state == MemoryManager.STATE_OK);
Angus Kongce5480e2013-01-29 17:43:48 -08001854 }
Angus Kong86d36312013-01-31 18:22:44 -08001855
1856 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001857 public void onLowMemory() {
1858 // Not much we can do in the photo module.
Angus Kong86d36312013-01-31 18:22:44 -08001859 }
Angus Kong0d00a892013-03-26 11:40:40 -07001860
1861 @Override
1862 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1863 }
1864
1865 @Override
1866 public void onSensorChanged(SensorEvent event) {
1867 int type = event.sensor.getType();
1868 float[] data;
1869 if (type == Sensor.TYPE_ACCELEROMETER) {
1870 data = mGData;
1871 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
1872 data = mMData;
1873 } else {
1874 // we should not be here.
1875 return;
1876 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001877 for (int i = 0; i < 3; i++) {
Angus Kong0d00a892013-03-26 11:40:40 -07001878 data[i] = event.values[i];
1879 }
1880 float[] orientation = new float[3];
1881 SensorManager.getRotationMatrix(mR, null, mGData, mMData);
1882 SensorManager.getOrientation(mR, orientation);
1883 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
1884 if (mHeading < 0) {
1885 mHeading += 360;
1886 }
Angus Kong0d00a892013-03-26 11:40:40 -07001887 }
Doris Liu6432cd62013-06-13 17:20:31 -07001888
Ruben Brunkd217ed02013-10-08 23:31:13 -07001889 // For debugging only.
1890 public void setDebugUri(Uri uri) {
1891 mDebugUri = uri;
1892 }
1893
1894 // For debugging only.
1895 private void saveToDebugUri(byte[] data) {
1896 if (mDebugUri != null) {
1897 OutputStream outputStream = null;
1898 try {
1899 outputStream = mContentResolver.openOutputStream(mDebugUri);
1900 outputStream.write(data);
1901 outputStream.close();
1902 } catch (IOException e) {
1903 Log.e(TAG, "Exception while writing debug jpeg file", e);
1904 } finally {
1905 CameraUtil.closeSilently(outputStream);
1906 }
1907 }
1908 }
Michael Kolb8872c232013-01-29 10:33:22 -08001909}