blob: a701c1169c980ef0b341183219cab4a5b59c8b0b [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;
25import android.graphics.SurfaceTexture;
26import android.hardware.Camera.CameraInfo;
Michael Kolb8872c232013-01-29 10:33:22 -080027import android.hardware.Camera.Parameters;
Michael Kolb8872c232013-01-29 10:33:22 -080028import android.hardware.Camera.Size;
Angus Kong0d00a892013-03-26 11:40:40 -070029import android.hardware.Sensor;
30import android.hardware.SensorEvent;
31import android.hardware.SensorEventListener;
32import android.hardware.SensorManager;
Michael Kolb8872c232013-01-29 10:33:22 -080033import android.location.Location;
34import android.media.CameraProfile;
35import android.net.Uri;
Sascha Haeberling638e6f02013-09-18 14:28:51 -070036import android.os.Build;
Michael Kolb8872c232013-01-29 10:33:22 -080037import android.os.Bundle;
Michael Kolb8872c232013-01-29 10:33:22 -080038import android.os.Handler;
39import android.os.Looper;
40import android.os.Message;
41import android.os.MessageQueue;
42import android.os.SystemClock;
43import android.provider.MediaStore;
44import android.util.Log;
Michael Kolb8872c232013-01-29 10:33:22 -080045import android.view.KeyEvent;
Michael Kolb8872c232013-01-29 10:33:22 -080046import android.view.OrientationEventListener;
Michael Kolb8872c232013-01-29 10:33:22 -080047import android.view.View;
Doris Liu773e1c92013-12-02 17:35:03 -080048import android.view.ViewGroup;
Michael Kolb8872c232013-01-29 10:33:22 -080049
Sameer Padala2c8cc452013-11-05 18:49:12 -080050import com.android.camera.PhotoModule.NamedImages.NamedEntity;
51import com.android.camera.app.AppController;
Erin Dahlgrenb1641f52014-01-14 15:58:52 -080052import com.android.camera.app.CameraAppUI;
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;
Erin Dahlgrenb1641f52014-01-14 15:58:52 -080065import com.android.camera.hardware.HardwareSpec;
66import com.android.camera.hardware.HardwareSpecImpl;
Angus Kong20fad242013-11-11 18:23:46 -080067import com.android.camera.module.ModuleController;
Erin Dahlgren357b7672013-11-20 17:38:14 -080068import com.android.camera.settings.SettingsManager;
Sascha Haeberling3b0ab892014-01-29 20:54:39 +010069import com.android.camera.settings.SettingsUtil;
Michael Kolb8872c232013-01-29 10:33:22 -080070import com.android.camera.ui.RotateTextToast;
Angus Kongdcccc512013-08-08 17:06:03 -070071import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -070072import com.android.camera.util.CameraUtil;
Ruben Brunk4601f5d2013-09-24 18:35:22 -070073import com.android.camera.util.GcamHelper;
Sameer Padala2c8cc452013-11-05 18:49:12 -080074import com.android.camera.util.SmartCameraHelper;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070075import com.android.camera.util.UsageStatistics;
76import com.android.camera2.R;
Seth Raphael5e09d012013-12-18 13:45:03 -080077import com.google.common.logging.eventprotos;
Michael Kolb8872c232013-01-29 10:33:22 -080078
Angus Kongdcccc512013-08-08 17:06:03 -070079import java.io.File;
80import java.io.FileNotFoundException;
81import java.io.FileOutputStream;
82import java.io.IOException;
83import java.io.OutputStream;
Sascha Haeberling846d3ab2014-02-04 12:48:55 +010084import java.lang.ref.WeakReference;
Angus Kongdcccc512013-08-08 17:06:03 -070085import java.util.List;
Ruben Brunka9d66bd2013-09-06 11:56:32 -070086import java.util.Vector;
Angus Kongdcccc512013-08-08 17:06:03 -070087
Michael Kolb8872c232013-01-29 10:33:22 -080088public class PhotoModule
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080089 extends CameraModule
90 implements PhotoController,
91 ModuleController,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080092 MemoryListener,
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080093 FocusOverlayManager.Listener,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080094 ShutterButton.OnShutterButtonListener,
Erin Dahlgren7f0151d2014-01-02 16:08:12 -080095 SensorEventListener,
96 SettingsManager.OnSettingChangedListener {
Michael Kolb8872c232013-01-29 10:33:22 -080097
Sascha Haeberling58501152014-01-06 11:02:35 -080098 private static final String TAG = "PhotoModule";
Michael Kolb8872c232013-01-29 10:33:22 -080099
100 // We number the request code from 1000 to avoid collision with Gallery.
101 private static final int REQUEST_CROP = 1000;
102
Angus Kong13e87c42013-11-25 10:02:47 -0800103 // Messages defined for the UI thread handler.
Angus Kong1587b042014-01-02 18:09:27 -0800104 private static final int MSG_FIRST_TIME_INIT = 1;
105 private static final int MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE = 2;
106 private static final int MSG_SHOW_TAP_TO_FOCUS_TOAST = 3;
107 private static final int MSG_SWITCH_TO_GCAM_MODULE = 4;
Michael Kolb8872c232013-01-29 10:33:22 -0800108
109 // The subset of parameters we need to update in setCameraParameters().
110 private static final int UPDATE_PARAM_INITIALIZE = 1;
111 private static final int UPDATE_PARAM_ZOOM = 2;
112 private static final int UPDATE_PARAM_PREFERENCE = 4;
113 private static final int UPDATE_PARAM_ALL = -1;
114
Andy Huibersdef975d2013-11-22 09:13:39 -0800115 // This is the delay before we execute onResume tasks when coming
116 // from the lock screen, to allow time for onPause to execute.
117 private static final int ON_RESUME_TASKS_DELAY_MSEC = 20;
Michael Kolb8872c232013-01-29 10:33:22 -0800118
Ruben Brunkd7488272013-10-10 18:45:53 -0700119 private static final String DEBUG_IMAGE_PREFIX = "DEBUG_";
120
Michael Kolb8872c232013-01-29 10:33:22 -0800121 private CameraActivity mActivity;
Michael Kolb8872c232013-01-29 10:33:22 -0800122 private CameraProxy mCameraDevice;
123 private int mCameraId;
124 private Parameters mParameters;
125 private boolean mPaused;
Michael Kolbd6954f32013-03-08 20:43:01 -0800126
127 private PhotoUI mUI;
Michael Kolb8872c232013-01-29 10:33:22 -0800128
Michael Kolb8872c232013-01-29 10:33:22 -0800129 // The activity is going to switch to the specified camera id. This is
130 // needed because texture copy is done in GL thread. -1 means camera is not
131 // switching.
132 protected int mPendingSwitchCameraId = -1;
Michael Kolb8872c232013-01-29 10:33:22 -0800133
134 // When setCameraParametersWhenIdle() is called, we accumulate the subsets
135 // needed to be updated in mUpdateSet.
136 private int mUpdateSet;
137
138 private static final int SCREEN_DELAY = 2 * 60 * 1000;
139
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800140 private int mZoomValue; // The current zoom value.
Michael Kolb8872c232013-01-29 10:33:22 -0800141
142 private Parameters mInitialParams;
143 private boolean mFocusAreaSupported;
144 private boolean mMeteringAreaSupported;
145 private boolean mAeLockSupported;
146 private boolean mAwbLockSupported;
Angus Kongdcccc512013-08-08 17:06:03 -0700147 private boolean mContinuousFocusSupported;
Michael Kolb8872c232013-01-29 10:33:22 -0800148
149 // The degrees of the device rotated clockwise from its natural orientation.
150 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
Michael Kolb8872c232013-01-29 10:33:22 -0800151
152 private static final String sTempCropFilename = "crop-temp";
153
Michael Kolb8872c232013-01-29 10:33:22 -0800154 private boolean mFaceDetectionStarted = false;
155
Michael Kolb8872c232013-01-29 10:33:22 -0800156 // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
157 private String mCropValue;
158 private Uri mSaveUri;
159
Ruben Brunkd217ed02013-10-08 23:31:13 -0700160 private Uri mDebugUri;
161
Angus Kongce5480e2013-01-29 17:43:48 -0800162 // We use a queue to generated names of the images to be used later
163 // when the image is ready to be saved.
Michael Kolb8872c232013-01-29 10:33:22 -0800164 private NamedImages mNamedImages;
165
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800166 private final Runnable mDoSnapRunnable = new Runnable() {
Michael Kolb8872c232013-01-29 10:33:22 -0800167 @Override
168 public void run() {
169 onShutterButtonClick();
170 }
171 };
172
Michael Kolb8872c232013-01-29 10:33:22 -0800173 /**
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800174 * An unpublished intent flag requesting to return as soon as capturing is
175 * completed. TODO: consider publishing by moving into MediaStore.
Michael Kolb8872c232013-01-29 10:33:22 -0800176 */
177 private static final String EXTRA_QUICK_CAPTURE =
178 "android.intent.extra.quickCapture";
179
180 // The display rotation in degrees. This is only valid when mCameraState is
181 // not PREVIEW_STOPPED.
182 private int mDisplayRotation;
183 // The value for android.hardware.Camera.setDisplayOrientation.
184 private int mCameraDisplayOrientation;
185 // The value for UI components like indicators.
186 private int mDisplayOrientation;
187 // The value for android.hardware.Camera.Parameters.setRotation.
188 private int mJpegRotation;
Doris Liu29da2db2013-08-28 14:28:45 -0700189 // Indicates whether we are using front camera
190 private boolean mMirror;
Michael Kolb8872c232013-01-29 10:33:22 -0800191 private boolean mFirstTimeInitialized;
192 private boolean mIsImageCaptureIntent;
193
Michael Kolb8872c232013-01-29 10:33:22 -0800194 private int mCameraState = PREVIEW_STOPPED;
195 private boolean mSnapshotOnIdle = false;
196
197 private ContentResolver mContentResolver;
198
199 private LocationManager mLocationManager;
Doris Liu2b906b82013-12-10 16:34:08 -0800200 private AppController mAppController;
Michael Kolb8872c232013-01-29 10:33:22 -0800201
Michael Kolb8872c232013-01-29 10:33:22 -0800202 private final PostViewPictureCallback mPostViewPictureCallback =
203 new PostViewPictureCallback();
204 private final RawPictureCallback mRawPictureCallback =
205 new RawPictureCallback();
206 private final AutoFocusCallback mAutoFocusCallback =
207 new AutoFocusCallback();
208 private final Object mAutoFocusMoveCallback =
209 ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700210 ? new AutoFocusMoveCallback()
211 : null;
Michael Kolb8872c232013-01-29 10:33:22 -0800212
213 private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
214
215 private long mFocusStartTime;
216 private long mShutterCallbackTime;
217 private long mPostViewPictureCallbackTime;
218 private long mRawPictureCallbackTime;
219 private long mJpegPictureCallbackTime;
220 private long mOnResumeTime;
221 private byte[] mJpegImageData;
222
223 // These latency time are for the CameraLatency test.
224 public long mAutoFocusTime;
225 public long mShutterLag;
226 public long mShutterToPictureDisplayedTime;
227 public long mPictureDisplayedToJpegCallbackTime;
228 public long mJpegCallbackFinishTime;
229 public long mCaptureStartTime;
230
231 // This handles everything about focus.
232 private FocusOverlayManager mFocusManager;
233
Doris Liubd1b8f92014-01-03 17:59:51 -0800234 private final int mGcamModeIndex;
Doris Liubd1b8f92014-01-03 17:59:51 -0800235
Michael Kolb8872c232013-01-29 10:33:22 -0800236 private String mSceneMode;
Michael Kolb8872c232013-01-29 10:33:22 -0800237
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100238 private final Handler mHandler = new MainHandler(this);
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800239
Michael Kolb8872c232013-01-29 10:33:22 -0800240 private boolean mQuickCapture;
Angus Kong0d00a892013-03-26 11:40:40 -0700241 private SensorManager mSensorManager;
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800242 private final float[] mGData = new float[3];
243 private final float[] mMData = new float[3];
244 private final float[] mR = new float[16];
Angus Kong0d00a892013-03-26 11:40:40 -0700245 private int mHeading = -1;
246
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800247 /** Whether shutter is enabled. */
Spike Sprague215f6b02013-12-12 11:53:49 -0800248 private boolean mShutterEnabled = true;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800249
250 /** True if all the parameters needed to start preview is ready. */
Angus Kongdcccc512013-08-08 17:06:03 -0700251 private boolean mCameraPreviewParamsReady = false;
Doris Liu6432cd62013-06-13 17:20:31 -0700252
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800253 private final MediaSaver.OnMediaSavedListener mOnMediaSavedListener =
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800254 new MediaSaver.OnMediaSavedListener() {
Angus Kongce5480e2013-01-29 17:43:48 -0800255 @Override
256 public void onMediaSaved(Uri uri) {
257 if (uri != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700258 mActivity.notifyNewMedia(uri);
Angus Kongce5480e2013-01-29 17:43:48 -0800259 }
260 }
261 };
Michael Kolb8872c232013-01-29 10:33:22 -0800262
Angus Kongdcccc512013-08-08 17:06:03 -0700263 private void checkDisplayRotation() {
264 // Set the display orientation if display rotation has changed.
265 // Sometimes this happens when the device is held upside
266 // down and camera app is opened. Rotation animation will
267 // take some time and the rotation value we have got may be
268 // wrong. Framework does not have a callback for this now.
269 if (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) {
270 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -0800271 }
Angus Kongdcccc512013-08-08 17:06:03 -0700272 if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
273 mHandler.postDelayed(new Runnable() {
274 @Override
275 public void run() {
276 checkDisplayRotation();
277 }
278 }, 100);
Michael Kolb8872c232013-01-29 10:33:22 -0800279 }
280 }
281
282 /**
283 * This Handler is used to post message back onto the main thread of the
284 * application
285 */
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100286 private static class MainHandler extends Handler {
287 private final WeakReference<PhotoModule> mModule;
288
289 public MainHandler(PhotoModule module) {
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800290 super(Looper.getMainLooper());
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100291 mModule = new WeakReference<PhotoModule>(module);
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800292 }
293
Michael Kolb8872c232013-01-29 10:33:22 -0800294 @Override
295 public void handleMessage(Message msg) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100296 PhotoModule module = mModule.get();
297 if (module == null) {
298 return;
299 }
Michael Kolb8872c232013-01-29 10:33:22 -0800300 switch (msg.what) {
Angus Kong13e87c42013-11-25 10:02:47 -0800301 case MSG_FIRST_TIME_INIT: {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100302 module.initializeFirstTime();
Michael Kolb8872c232013-01-29 10:33:22 -0800303 break;
304 }
305
Angus Kong13e87c42013-11-25 10:02:47 -0800306 case MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE: {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100307 module.setCameraParametersWhenIdle(0);
Michael Kolb8872c232013-01-29 10:33:22 -0800308 break;
309 }
310
Angus Kong13e87c42013-11-25 10:02:47 -0800311 case MSG_SHOW_TAP_TO_FOCUS_TOAST: {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100312 module.showTapToFocusToast();
Michael Kolb8872c232013-01-29 10:33:22 -0800313 break;
314 }
315
Angus Kong13e87c42013-11-25 10:02:47 -0800316 case MSG_SWITCH_TO_GCAM_MODULE: {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100317 module.mActivity.onModeSelected(module.mGcamModeIndex);
ztenghui367c7c82013-10-16 14:43:26 -0700318 }
Michael Kolb8872c232013-01-29 10:33:22 -0800319 }
320 }
321 }
322
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800323 /**
324 * Constructs a new photo module.
325 */
Angus Kongc4e66562013-11-22 23:03:21 -0800326 public PhotoModule(AppController app) {
327 super(app);
Doris Liubd1b8f92014-01-03 17:59:51 -0800328 mGcamModeIndex = app.getAndroidContext().getResources()
329 .getInteger(R.integer.camera_mode_gcam);
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800330 }
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700331
Michael Kolb8872c232013-01-29 10:33:22 -0800332 @Override
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100333 public void init(CameraActivity activity, boolean isSecureCamera, boolean isCaptureIntent) {
334 mActivity = activity;
335 // TODO: Need to look at the controller interface to see if we can get
336 // rid of passing in the activity directly.
337 mAppController = mActivity;
338
339 mUI = new PhotoUI(mActivity, this, mActivity.getModuleLayoutRoot());
340 mActivity.setPreviewStatusListener(mUI);
341 mActivity.getCameraAppUI().setBottomBarShutterListener(this);
Erin Dahlgren357b7672013-11-20 17:38:14 -0800342
343 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800344 mCameraId = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_CAMERA_ID));
Michael Kolb8872c232013-01-29 10:33:22 -0800345
346 mContentResolver = mActivity.getContentResolver();
347
Michael Kolb8872c232013-01-29 10:33:22 -0800348 // Surface texture is from camera screen nail and startPreview needs it.
349 // This must be done before startPreview.
350 mIsImageCaptureIntent = isImageCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800351
Angus Kong20fad242013-11-11 18:23:46 -0800352 mActivity.getCameraProvider().requestCamera(mCameraId);
353
Michael Kolb8872c232013-01-29 10:33:22 -0800354 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800355 mLocationManager = mActivity.getLocationManager();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800356 mSensorManager = (SensorManager) (mActivity.getSystemService(Context.SENSOR_SERVICE));
Michael Kolbd6954f32013-03-08 20:43:01 -0800357 }
358
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800359 @Override
360 public boolean isUsingBottomBar() {
361 return true;
362 }
363
Michael Kolbd6954f32013-03-08 20:43:01 -0800364 private void initializeControlByIntent() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800365 if (mIsImageCaptureIntent) {
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800366 mActivity.getCameraAppUI().transitionToIntentLayout();
Michael Kolbd6954f32013-03-08 20:43:01 -0800367 setupCaptureParams();
368 }
369 }
370
371 private void onPreviewStarted() {
Doris Liu2b906b82013-12-10 16:34:08 -0800372 mAppController.onPreviewStarted();
Michael Kolbd6954f32013-03-08 20:43:01 -0800373 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800374 startFaceDetection();
Sameer Padala2c8cc452013-11-05 18:49:12 -0800375 startSmartCamera();
Michael Kolbd6954f32013-03-08 20:43:01 -0800376 locationFirstRun();
Michael Kolb8872c232013-01-29 10:33:22 -0800377 }
378
379 // Prompt the user to pick to record location for the very first run of
380 // camera only
381 private void locationFirstRun() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800382 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800383 if (settingsManager.isSet(SettingsManager.SETTING_RECORD_LOCATION)) {
Michael Kolb8872c232013-01-29 10:33:22 -0800384 return;
385 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800386 if (mActivity.isSecureCamera()) {
387 return;
388 }
Michael Kolb8872c232013-01-29 10:33:22 -0800389 // Check if the back camera exists
Angus Kongd74e6a12014-01-07 11:29:44 -0800390 int backCameraId = mAppController.getCameraProvider().getFirstBackCameraId();
Michael Kolb8872c232013-01-29 10:33:22 -0800391 if (backCameraId == -1) {
392 // If there is no back camera, do not show the prompt.
393 return;
394 }
Doris Liu6a83d522013-07-02 12:03:32 -0700395 mUI.showLocationDialog();
396 }
Michael Kolb8872c232013-01-29 10:33:22 -0800397
ztenghui7b265a62013-09-09 14:58:44 -0700398 @Override
Angus Kongdcccc512013-08-08 17:06:03 -0700399 public void onPreviewUIReady() {
Erin Dahlgrendc282e12013-11-12 09:39:08 -0800400 startPreview();
Angus Kongdcccc512013-08-08 17:06:03 -0700401 }
402
403 @Override
404 public void onPreviewUIDestroyed() {
405 if (mCameraDevice == null) {
406 return;
407 }
408 mCameraDevice.setPreviewTexture(null);
409 stopPreview();
410 }
411
Doris Liu1dfe7822013-12-12 00:02:08 -0800412 @Override
413 public void startPreCaptureAnimation() {
414 mAppController.startPreCaptureAnimation();
415 }
416
Michael Kolbd6954f32013-03-08 20:43:01 -0800417 private void onCameraOpened() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800418 openCameraCommon();
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800419 initializeControlByIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800420 }
421
Michael Kolbd6954f32013-03-08 20:43:01 -0800422 private void switchCamera() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800423 if (mPaused) {
424 return;
425 }
Erin Dahlgren357b7672013-11-20 17:38:14 -0800426 SettingsManager settingsManager = mActivity.getSettingsManager();
Michael Kolbd6954f32013-03-08 20:43:01 -0800427
428 Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
Angus Kongd4109bc2014-01-08 18:38:03 -0800429 closeCamera();
Michael Kolbd6954f32013-03-08 20:43:01 -0800430 mCameraId = mPendingSwitchCameraId;
431 mPendingSwitchCameraId = -1;
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800432 settingsManager.set(SettingsManager.SETTING_CAMERA_ID, "" + mCameraId);
Angus Kong20fad242013-11-11 18:23:46 -0800433 mActivity.getCameraProvider().requestCamera(mCameraId);
Michael Kolbd6954f32013-03-08 20:43:01 -0800434 mUI.clearFaces();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800435 if (mFocusManager != null) {
436 mFocusManager.removeMessages();
437 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800438
Erin Dahlgren357b7672013-11-20 17:38:14 -0800439 // TODO: this needs to be brought into onCameraAvailable();
Angus Kong20fad242013-11-11 18:23:46 -0800440 CameraInfo info = mActivity.getCameraProvider().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -0700441 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
442 mFocusManager.setMirror(mMirror);
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700443 // Start switch camera animation. Post a message because
444 // onFrameAvailable from the old camera may already exist.
Doris Liu48239f42013-03-04 22:19:10 -0800445 }
446
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800447 private final ButtonManager.ButtonCallback mCameraCallback =
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800448 new ButtonManager.ButtonCallback() {
449 @Override
450 public void onStateChanged(int state) {
451 if (mPaused || mPendingSwitchCameraId != -1) {
452 return;
453 }
454 mPendingSwitchCameraId = state;
455
456 Log.v(TAG, "Start to switch camera. cameraId=" + state);
457 // We need to keep a preview frame for the animation before
458 // releasing the camera. This will trigger onPreviewTextureCopied.
459 //TODO: Need to animate the camera switch
460 switchCamera();
461 }
462 };
463
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800464 private final ButtonManager.ButtonCallback mHdrPlusCallback =
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800465 new ButtonManager.ButtonCallback() {
466 @Override
467 public void onStateChanged(int state) {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -0800468 if (GcamHelper.hasGcamCapture()) {
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800469 // Set the camera setting to default backfacing.
470 SettingsManager settingsManager = mActivity.getSettingsManager();
471 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_ID);
Erin Dahlgrenba6994d2013-12-12 16:04:38 -0800472 mHandler.sendEmptyMessage(MSG_SWITCH_TO_GCAM_MODULE);
473 } else {
474 mSceneMode = CameraUtil.SCENE_MODE_HDR;
475 updateParametersSceneMode();
476 }
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800477 }
478 };
479
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800480 private final View.OnClickListener mCancelCallback = new View.OnClickListener() {
481 @Override
482 public void onClick(View v) {
483 onCaptureCancelled();
484 }
485 };
486
487 private final View.OnClickListener mDoneCallback = new View.OnClickListener() {
488 @Override
489 public void onClick(View v) {
490 onCaptureDone();
491 }
492 };
493
494 private final View.OnClickListener mRetakeCallback = new View.OnClickListener() {
495 @Override
496 public void onClick(View v) {
497 mActivity.getCameraAppUI().transitionToIntentLayout();
498 onCaptureRetake();
499 }
500 };
501
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800502 @Override
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800503 public HardwareSpec getHardwareSpec() {
Erin Dahlgren49ab9222014-01-28 17:40:28 -0800504 return (mParameters != null ? new HardwareSpecImpl(mParameters) : null);
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800505 }
506
507 @Override
508 public CameraAppUI.BottomBarUISpec getBottomBarSpec() {
509 CameraAppUI.BottomBarUISpec bottomBarSpec = new CameraAppUI.BottomBarUISpec();
510
511 bottomBarSpec.enableCamera = true;
512 bottomBarSpec.cameraCallback = mCameraCallback;
513 bottomBarSpec.enableFlash = true;
Erin Dahlgrena6587a12014-02-03 13:24:55 -0800514 bottomBarSpec.enableHdr = true;
515 bottomBarSpec.hdrCallback = mHdrPlusCallback;
Erin Dahlgrend5e51462014-02-07 12:38:57 -0800516 bottomBarSpec.enableGridLines = true;
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800517
518 if (isImageCaptureIntent()) {
519 bottomBarSpec.showCancel = true;
520 bottomBarSpec.cancelCallback = mCancelCallback;
521 bottomBarSpec.showDone = true;
522 bottomBarSpec.doneCallback = mDoneCallback;
523 bottomBarSpec.showRetake = true;
524 bottomBarSpec.retakeCallback = mRetakeCallback;
525 }
526
527 return bottomBarSpec;
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800528 }
529
Michael Kolbd6954f32013-03-08 20:43:01 -0800530 // either open a new camera or switch cameras
531 private void openCameraCommon() {
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800532 mUI.onCameraOpened(mParameters);
Angus Kong0fb819b2013-10-08 13:44:19 -0700533 if (mIsImageCaptureIntent) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800534 // Set hdr plus to default: off.
535 SettingsManager settingsManager = mActivity.getSettingsManager();
536 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_HDR_PLUS);
Angus Kong0fb819b2013-10-08 13:44:19 -0700537 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800538 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -0800539 }
540
ztenghui7b265a62013-09-09 14:58:44 -0700541 @Override
Doris Liu70da9182013-12-17 18:41:15 -0800542 public void updatePreviewAspectRatio(float aspectRatio) {
543 mAppController.updatePreviewAspectRatio(aspectRatio);
544 }
545
Michael Kolb8872c232013-01-29 10:33:22 -0800546 private void resetExposureCompensation() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800547 SettingsManager settingsManager = mActivity.getSettingsManager();
548 if (settingsManager == null) {
549 Log.e(TAG, "Settings manager is null!");
550 return;
Michael Kolb8872c232013-01-29 10:33:22 -0800551 }
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800552 settingsManager.setDefault(SettingsManager.SETTING_EXPOSURE);
Michael Kolb8872c232013-01-29 10:33:22 -0800553 }
554
Michael Kolb8872c232013-01-29 10:33:22 -0800555 // Snapshots can only be taken after this is called. It should be called
556 // once only. We could have done these things in onCreate() but we want to
557 // make preview screen appear as soon as possible.
558 private void initializeFirstTime() {
Sascha Haeberling330dafb2013-10-10 19:00:41 -0700559 if (mFirstTimeInitialized || mPaused) {
560 return;
561 }
Michael Kolb8872c232013-01-29 10:33:22 -0800562
563 // Initialize location service.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800564 SettingsController settingsController = mActivity.getSettingsController();
565 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -0800566
Michael Kolbd6954f32013-03-08 20:43:01 -0800567 mUI.initializeFirstTime();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800568
Angus Kong86d36312013-01-31 18:22:44 -0800569 // We set the listener only when both service and shutterbutton
570 // are initialized.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800571 getServices().getMemoryManager().addListener(this);
Michael Kolb8872c232013-01-29 10:33:22 -0800572
Michael Kolb8872c232013-01-29 10:33:22 -0800573 mNamedImages = new NamedImages();
574
575 mFirstTimeInitialized = true;
576 addIdleHandler();
577
578 mActivity.updateStorageSpaceAndHint();
579 }
580
Michael Kolbd6954f32013-03-08 20:43:01 -0800581 // If the activity is paused and resumed, this method will be called in
582 // onResume.
583 private void initializeSecondTime() {
584 // Start location update if needed.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800585 SettingsController settingsController = mActivity.getSettingsController();
586 settingsController.syncLocationManager();
587
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800588 getServices().getMemoryManager().addListener(this);
Michael Kolbd6954f32013-03-08 20:43:01 -0800589 mNamedImages = new NamedImages();
590 mUI.initializeSecondTime(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -0800591 }
592
Michael Kolb8872c232013-01-29 10:33:22 -0800593 private void addIdleHandler() {
594 MessageQueue queue = Looper.myQueue();
595 queue.addIdleHandler(new MessageQueue.IdleHandler() {
596 @Override
597 public boolean queueIdle() {
598 Storage.ensureOSXCompatible();
599 return false;
600 }
601 });
602 }
603
Sameer Padala2c8cc452013-11-05 18:49:12 -0800604 private void startSmartCamera() {
605 SmartCameraHelper.register(mCameraDevice, mParameters.getPreviewSize(), mActivity,
Doris Liu773e1c92013-12-02 17:35:03 -0800606 (ViewGroup) mActivity.findViewById(R.id.camera_app_root));
Sameer Padala2c8cc452013-11-05 18:49:12 -0800607 }
608
609 private void stopSmartCamera() {
610 SmartCameraHelper.tearDown();
611 }
612
Michael Kolb8872c232013-01-29 10:33:22 -0800613 @Override
614 public void startFaceDetection() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800615 if (mFaceDetectionStarted) {
616 return;
617 }
Michael Kolb8872c232013-01-29 10:33:22 -0800618 if (mParameters.getMaxNumDetectedFaces() > 0) {
619 mFaceDetectionStarted = true;
Angus Kongd74e6a12014-01-07 11:29:44 -0800620 CameraInfo info = mAppController.getCameraProvider().getCameraInfo()[mCameraId];
Michael Kolbd6954f32013-03-08 20:43:01 -0800621 mUI.onStartFaceDetection(mDisplayOrientation,
622 (info.facing == CameraInfo.CAMERA_FACING_FRONT));
Angus Kong9e765522013-07-31 14:05:20 -0700623 mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Michael Kolb8872c232013-01-29 10:33:22 -0800624 mCameraDevice.startFaceDetection();
625 }
626 }
627
Michael Kolb8872c232013-01-29 10:33:22 -0800628 @Override
629 public void stopFaceDetection() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800630 if (!mFaceDetectionStarted) {
631 return;
632 }
Michael Kolb8872c232013-01-29 10:33:22 -0800633 if (mParameters.getMaxNumDetectedFaces() > 0) {
634 mFaceDetectionStarted = false;
Angus Kong9e765522013-07-31 14:05:20 -0700635 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -0800636 mCameraDevice.stopFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800637 mUI.clearFaces();
Michael Kolb8872c232013-01-29 10:33:22 -0800638 }
639 }
640
Michael Kolb8872c232013-01-29 10:33:22 -0800641 private final class ShutterCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700642 implements CameraShutterCallback {
Angus Kongdcb0ef12013-03-25 23:11:43 -0700643
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800644 private final boolean mNeedsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700645
Sascha Haeberling37f36112013-08-06 14:31:52 -0700646 public ShutterCallback(boolean needsAnimation) {
647 mNeedsAnimation = needsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700648 }
649
Michael Kolb8872c232013-01-29 10:33:22 -0800650 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700651 public void onShutter(CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800652 mShutterCallbackTime = System.currentTimeMillis();
653 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
654 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Sascha Haeberling37f36112013-08-06 14:31:52 -0700655 if (mNeedsAnimation) {
656 mActivity.runOnUiThread(new Runnable() {
657 @Override
658 public void run() {
659 animateAfterShutter();
660 }
661 });
Angus Kongdcb0ef12013-03-25 23:11:43 -0700662 }
Michael Kolb8872c232013-01-29 10:33:22 -0800663 }
664 }
665
Angus Kong9ef99252013-07-18 18:04:19 -0700666 private final class PostViewPictureCallback
667 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800668 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800669 public void onPictureTaken(byte[] data, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800670 mPostViewPictureCallbackTime = System.currentTimeMillis();
671 Log.v(TAG, "mShutterToPostViewCallbackTime = "
672 + (mPostViewPictureCallbackTime - mShutterCallbackTime)
673 + "ms");
674 }
675 }
676
Angus Kong9ef99252013-07-18 18:04:19 -0700677 private final class RawPictureCallback
678 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800679 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800680 public void onPictureTaken(byte[] rawData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800681 mRawPictureCallbackTime = System.currentTimeMillis();
682 Log.v(TAG, "mShutterToRawCallbackTime = "
683 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
684 }
685 }
686
Angus Kong9ef99252013-07-18 18:04:19 -0700687 private final class JpegPictureCallback
688 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800689 Location mLocation;
690
691 public JpegPictureCallback(Location loc) {
692 mLocation = loc;
693 }
694
695 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800696 public void onPictureTaken(final byte[] jpegData, CameraProxy camera) {
697 setShutterEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800698 if (mPaused) {
699 return;
700 }
Doris Liu6432cd62013-06-13 17:20:31 -0700701 if (mIsImageCaptureIntent) {
702 stopPreview();
703 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700704 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -0700705 mUI.setSwipingEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800706 }
707
708 mJpegPictureCallbackTime = System.currentTimeMillis();
709 // If postview callback has arrived, the captured image is displayed
710 // in postview callback. If not, the captured image is displayed in
711 // raw picture callback.
712 if (mPostViewPictureCallbackTime != 0) {
713 mShutterToPictureDisplayedTime =
714 mPostViewPictureCallbackTime - mShutterCallbackTime;
715 mPictureDisplayedToJpegCallbackTime =
716 mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
717 } else {
718 mShutterToPictureDisplayedTime =
719 mRawPictureCallbackTime - mShutterCallbackTime;
720 mPictureDisplayedToJpegCallbackTime =
721 mJpegPictureCallbackTime - mRawPictureCallbackTime;
722 }
723 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
724 + mPictureDisplayedToJpegCallbackTime + "ms");
725
Michael Kolb8872c232013-01-29 10:33:22 -0800726 mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
727 if (!mIsImageCaptureIntent) {
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700728 setupPreview();
Michael Kolb8872c232013-01-29 10:33:22 -0800729 }
730
Doris Liu36e56fb2013-09-11 17:38:08 -0700731 ExifInterface exif = Exif.getExif(jpegData);
732 int orientation = Exif.getOrientation(exif);
Ruben Brunkd217ed02013-10-08 23:31:13 -0700733
Ruben Brunkd7488272013-10-10 18:45:53 -0700734 if (!mIsImageCaptureIntent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800735 // Calculate the width and the height of the jpeg.
736 Size s = mParameters.getPictureSize();
Michael Kolb8872c232013-01-29 10:33:22 -0800737 int width, height;
738 if ((mJpegRotation + orientation) % 180 == 0) {
739 width = s.width;
740 height = s.height;
741 } else {
742 width = s.height;
743 height = s.width;
744 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700745 NamedEntity name = mNamedImages.getNextNameEntity();
746 String title = (name == null) ? null : name.title;
747 long date = (name == null) ? -1 : name.date;
Ruben Brunkd7488272013-10-10 18:45:53 -0700748
749 // Handle debug mode outputs
750 if (mDebugUri != null) {
751 // If using a debug uri, save jpeg there.
752 saveToDebugUri(jpegData);
753
754 // Adjust the title of the debug image shown in mediastore.
755 if (title != null) {
756 title = DEBUG_IMAGE_PREFIX + title;
757 }
758 }
759
Michael Kolb8872c232013-01-29 10:33:22 -0800760 if (title == null) {
761 Log.e(TAG, "Unbalanced name/data pair");
762 } else {
Sascha Haeberling3b0ab892014-01-29 20:54:39 +0100763 if (date == -1) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800764 date = mCaptureStartTime;
Sascha Haeberling3b0ab892014-01-29 20:54:39 +0100765 }
Angus Kong0d00a892013-03-26 11:40:40 -0700766 if (mHeading >= 0) {
767 // heading direction has been updated by the sensor.
768 ExifTag directionRefTag = exif.buildTag(
769 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
770 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
771 ExifTag directionTag = exif.buildTag(
772 ExifInterface.TAG_GPS_IMG_DIRECTION,
773 new Rational(mHeading, 1));
774 exif.setTag(directionRefTag);
775 exif.setTag(directionTag);
776 }
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800777 getServices().getMediaSaver().addImage(
Angus Kong86d36312013-01-31 18:22:44 -0800778 jpegData, title, date, mLocation, width, height,
Angus Kong0d00a892013-03-26 11:40:40 -0700779 orientation, exif, mOnMediaSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -0800780 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800781 // Animate capture with real jpeg data instead of a preview
782 // frame.
Doris Liu29da2db2013-08-28 14:28:45 -0700783 mUI.animateCapture(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800784 } else {
785 mJpegImageData = jpegData;
786 if (!mQuickCapture) {
Doris Liu36e56fb2013-09-11 17:38:08 -0700787 mUI.showCapturedImageForReview(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800788 } else {
Michael Kolbd6954f32013-03-08 20:43:01 -0800789 onCaptureDone();
Michael Kolb8872c232013-01-29 10:33:22 -0800790 }
791 }
792
793 // Check this in advance of each shot so we don't add to shutter
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800794 // latency. It's true that someone else could write to the SD card
795 // in the mean time and fill it, but that could have happened
796 // between the shutter press and saving the JPEG too.
Michael Kolb8872c232013-01-29 10:33:22 -0800797 mActivity.updateStorageSpaceAndHint();
798
799 long now = System.currentTimeMillis();
800 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
801 Log.v(TAG, "mJpegCallbackFinishTime = "
802 + mJpegCallbackFinishTime + "ms");
803 mJpegPictureCallbackTime = 0;
804 }
805 }
806
Angus Kong9ef99252013-07-18 18:04:19 -0700807 private final class AutoFocusCallback implements CameraAFCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800808 @Override
809 public void onAutoFocus(
Angus Kong9ef99252013-07-18 18:04:19 -0700810 boolean focused, CameraProxy camera) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800811 if (mPaused) {
812 return;
813 }
Michael Kolb8872c232013-01-29 10:33:22 -0800814
815 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
816 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
817 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800818 mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
Michael Kolb8872c232013-01-29 10:33:22 -0800819 }
820 }
821
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700822 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -0800823 private final class AutoFocusMoveCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700824 implements CameraAFMoveCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800825 @Override
826 public void onAutoFocusMoving(
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700827 boolean moving, CameraProxy camera) {
828 mFocusManager.onAutoFocusMoving(moving);
Michael Kolb8872c232013-01-29 10:33:22 -0800829 }
830 }
831
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700832 /**
833 * This class is just a thread-safe queue for name,date holder objects.
834 */
835 public static class NamedImages {
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800836 private final Vector<NamedEntity> mQueue;
Michael Kolb8872c232013-01-29 10:33:22 -0800837
838 public NamedImages() {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700839 mQueue = new Vector<NamedEntity>();
Michael Kolb8872c232013-01-29 10:33:22 -0800840 }
841
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700842 public void nameNewImage(long date) {
Michael Kolb8872c232013-01-29 10:33:22 -0800843 NamedEntity r = new NamedEntity();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700844 r.title = CameraUtil.createJpegName(date);
Michael Kolb8872c232013-01-29 10:33:22 -0800845 r.date = date;
846 mQueue.add(r);
847 }
848
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700849 public NamedEntity getNextNameEntity() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800850 synchronized (mQueue) {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700851 if (!mQueue.isEmpty()) {
852 return mQueue.remove(0);
853 }
Michael Kolb8872c232013-01-29 10:33:22 -0800854 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700855 return null;
Michael Kolb8872c232013-01-29 10:33:22 -0800856 }
857
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700858 public static class NamedEntity {
859 public String title;
860 public long date;
Michael Kolb8872c232013-01-29 10:33:22 -0800861 }
862 }
863
864 private void setCameraState(int state) {
865 mCameraState = state;
866 switch (state) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700867 case PhotoController.PREVIEW_STOPPED:
868 case PhotoController.SNAPSHOT_IN_PROGRESS:
869 case PhotoController.SWITCHING_CAMERA:
Doris Liuf55f3c42013-11-20 00:24:46 -0800870 // TODO: Tell app UI to disable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700871 break;
872 case PhotoController.IDLE:
Doris Liuf55f3c42013-11-20 00:24:46 -0800873 // TODO: Tell app UI to enable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700874 break;
Michael Kolb8872c232013-01-29 10:33:22 -0800875 }
876 }
877
Sascha Haeberling37f36112013-08-06 14:31:52 -0700878 private void animateAfterShutter() {
Michael Kolb8872c232013-01-29 10:33:22 -0800879 // Only animate when in full screen capture mode
880 // i.e. If monkey/a user swipes to the gallery during picture taking,
881 // don't show animation
Doris Liuc2e9abd2013-06-19 14:20:51 -0700882 if (!mIsImageCaptureIntent) {
883 mUI.animateFlash();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700884 }
Michael Kolb8872c232013-01-29 10:33:22 -0800885 }
886
887 @Override
888 public boolean capture() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800889 // If we are already in the middle of taking a snapshot or the image
890 // save request is full then ignore.
Michael Kolb8872c232013-01-29 10:33:22 -0800891 if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800892 || mCameraState == SWITCHING_CAMERA || !mShutterEnabled) {
Michael Kolb8872c232013-01-29 10:33:22 -0800893 return false;
894 }
895 mCaptureStartTime = System.currentTimeMillis();
896 mPostViewPictureCallbackTime = 0;
897 mJpegImageData = null;
898
Angus Kongb50b5cb2013-08-09 14:55:20 -0700899 final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
Michael Kolb8872c232013-01-29 10:33:22 -0800900
901 if (animateBefore) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700902 animateAfterShutter();
Michael Kolb8872c232013-01-29 10:33:22 -0800903 }
904
905 // Set rotation and gps data.
Doris Liu3cf565c2013-02-15 10:55:37 -0800906 int orientation;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800907
Doris Liu3cf565c2013-02-15 10:55:37 -0800908 // We need to be consistent with the framework orientation (i.e. the
909 // orientation of the UI.) when the auto-rotate screen setting is on.
910 if (mActivity.isAutoRotateScreen()) {
911 orientation = (360 - mDisplayRotation) % 360;
912 } else {
913 orientation = mOrientation;
914 }
Angus Kong20fad242013-11-11 18:23:46 -0800915 mJpegRotation = CameraUtil.getJpegRotation(mActivity, mCameraId, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800916 mParameters.setRotation(mJpegRotation);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800917 Location loc = mActivity.getLocationManager().getCurrentLocation();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700918 CameraUtil.setGpsParameters(mParameters, loc);
Michael Kolb8872c232013-01-29 10:33:22 -0800919 mCameraDevice.setParameters(mParameters);
920
Sascha Haeberling88901942013-08-28 17:49:00 -0700921 // We don't want user to press the button again while taking a
922 // multi-second HDR photo.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800923 setShutterEnabled(false);
Angus Kong9ef99252013-07-18 18:04:19 -0700924 mCameraDevice.takePicture(mHandler,
925 new ShutterCallback(!animateBefore),
Angus Kongdcb0ef12013-03-25 23:11:43 -0700926 mRawPictureCallback, mPostViewPictureCallback,
Angus Kong9ef99252013-07-18 18:04:19 -0700927 new JpegPictureCallback(loc));
Michael Kolb8872c232013-01-29 10:33:22 -0800928
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700929 mNamedImages.nameNewImage(mCaptureStartTime);
Michael Kolb8872c232013-01-29 10:33:22 -0800930
931 mFaceDetectionStarted = false;
932 setCameraState(SNAPSHOT_IN_PROGRESS);
Seth Raphael5e09d012013-12-18 13:45:03 -0800933 UsageStatistics.captureEvent(eventprotos.NavigationChange.Mode.PHOTO_CAPTURE,
934 UsageStatistics.hashFileName(mNamedImages.mQueue.lastElement().title + ".jpg"),
935 mParameters);
Michael Kolb8872c232013-01-29 10:33:22 -0800936 return true;
937 }
938
939 @Override
940 public void setFocusParameters() {
941 setCameraParameters(UPDATE_PARAM_PREFERENCE);
942 }
943
Michael Kolbd6954f32013-03-08 20:43:01 -0800944 private void updateSceneMode() {
Michael Kolb8872c232013-01-29 10:33:22 -0800945 // If scene mode is set, we cannot set flash mode, white balance, and
946 // focus mode, instead, we read it from driver
947 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
948 overrideCameraSettings(mParameters.getFlashMode(),
949 mParameters.getWhiteBalance(), mParameters.getFocusMode());
Michael Kolb8872c232013-01-29 10:33:22 -0800950 }
951 }
952
953 private void overrideCameraSettings(final String flashMode,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800954 final String whiteBalance, final String focusMode) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800955 SettingsManager settingsManager = mActivity.getSettingsManager();
956 settingsManager.set(SettingsManager.SETTING_FLASH_MODE, flashMode);
957 settingsManager.set(SettingsManager.SETTING_WHITE_BALANCE, whiteBalance);
958 settingsManager.set(SettingsManager.SETTING_FOCUS_MODE, focusMode);
Michael Kolb8872c232013-01-29 10:33:22 -0800959 }
960
961 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800962 public void onOrientationChanged(int orientation) {
963 // We keep the last known orientation. So if the user first orient
964 // the camera then point the camera to floor or sky, we still have
965 // the correct orientation.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800966 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
967 return;
968 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700969 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800970
971 // Show the toast after getting the first orientation changed.
Angus Kong13e87c42013-11-25 10:02:47 -0800972 if (mHandler.hasMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST)) {
973 mHandler.removeMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST);
Michael Kolb8872c232013-01-29 10:33:22 -0800974 showTapToFocusToast();
975 }
976 }
977
978 @Override
Angus Kong20fad242013-11-11 18:23:46 -0800979 public void onCameraAvailable(CameraProxy cameraProxy) {
980 if (mPaused) {
981 return;
982 }
983 mCameraDevice = cameraProxy;
984
Erin Dahlgren357b7672013-11-20 17:38:14 -0800985 resetExposureCompensation();
Angus Kong20fad242013-11-11 18:23:46 -0800986 initializeCapabilities();
987
988 // Reset zoom value index.
989 mZoomValue = 0;
990 if (mFocusManager == null) {
991 initializeFocusManager();
992 }
993 mFocusManager.setParameters(mInitialParams);
994
Erin Dahlgren7f0151d2014-01-02 16:08:12 -0800995 // Do camera parameter dependent initialization.
Angus Kong20fad242013-11-11 18:23:46 -0800996 mParameters = mCameraDevice.getParameters();
997 setCameraParameters(UPDATE_PARAM_ALL);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -0800998 // Set a listener which updates camera parameters based
999 // on changed settings.
1000 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren1648c362014-01-06 15:06:04 -08001001 settingsManager.addListener(this);
Angus Kong20fad242013-11-11 18:23:46 -08001002 mCameraPreviewParamsReady = true;
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001003
Angus Kong20fad242013-11-11 18:23:46 -08001004 startPreview();
1005
1006 onCameraOpened();
1007 }
1008
1009 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001010 public void onCaptureCancelled() {
1011 mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
1012 mActivity.finish();
Michael Kolb8872c232013-01-29 10:33:22 -08001013 }
1014
Michael Kolbd6954f32013-03-08 20:43:01 -08001015 @Override
1016 public void onCaptureRetake() {
Sascha Haeberling3b0ab892014-01-29 20:54:39 +01001017 if (mPaused) {
Michael Kolb8872c232013-01-29 10:33:22 -08001018 return;
Sascha Haeberling3b0ab892014-01-29 20:54:39 +01001019 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001020 mUI.hidePostCaptureAlert();
Michael Kolb8872c232013-01-29 10:33:22 -08001021 setupPreview();
1022 }
1023
Michael Kolbd6954f32013-03-08 20:43:01 -08001024 @Override
1025 public void onCaptureDone() {
Michael Kolb8872c232013-01-29 10:33:22 -08001026 if (mPaused) {
1027 return;
1028 }
1029
1030 byte[] data = mJpegImageData;
1031
1032 if (mCropValue == null) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001033 // First handle the no crop case -- just return the value. If the
Michael Kolb8872c232013-01-29 10:33:22 -08001034 // caller specifies a "save uri" then write the data to its
1035 // stream. Otherwise, pass back a scaled down version of the bitmap
1036 // directly in the extras.
1037 if (mSaveUri != null) {
1038 OutputStream outputStream = null;
1039 try {
1040 outputStream = mContentResolver.openOutputStream(mSaveUri);
1041 outputStream.write(data);
1042 outputStream.close();
1043
1044 mActivity.setResultEx(Activity.RESULT_OK);
1045 mActivity.finish();
1046 } catch (IOException ex) {
1047 // ignore exception
1048 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001049 CameraUtil.closeSilently(outputStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001050 }
1051 } else {
Angus Kong0d00a892013-03-26 11:40:40 -07001052 ExifInterface exif = Exif.getExif(data);
1053 int orientation = Exif.getOrientation(exif);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001054 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
1055 bitmap = CameraUtil.rotate(bitmap, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001056 mActivity.setResultEx(Activity.RESULT_OK,
1057 new Intent("inline-data").putExtra("data", bitmap));
1058 mActivity.finish();
1059 }
1060 } else {
1061 // Save the image to a temp file and invoke the cropper
1062 Uri tempUri = null;
1063 FileOutputStream tempStream = null;
1064 try {
1065 File path = mActivity.getFileStreamPath(sTempCropFilename);
1066 path.delete();
1067 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1068 tempStream.write(data);
1069 tempStream.close();
1070 tempUri = Uri.fromFile(path);
1071 } catch (FileNotFoundException ex) {
1072 mActivity.setResultEx(Activity.RESULT_CANCELED);
1073 mActivity.finish();
1074 return;
1075 } catch (IOException ex) {
1076 mActivity.setResultEx(Activity.RESULT_CANCELED);
1077 mActivity.finish();
1078 return;
1079 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001080 CameraUtil.closeSilently(tempStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001081 }
1082
1083 Bundle newExtras = new Bundle();
1084 if (mCropValue.equals("circle")) {
1085 newExtras.putString("circleCrop", "true");
1086 }
1087 if (mSaveUri != null) {
1088 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1089 } else {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001090 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001091 }
1092 if (mActivity.isSecureCamera()) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001093 newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001094 }
1095
Sascha Haeberling37f36112013-08-06 14:31:52 -07001096 // TODO: Share this constant.
Sascha Haeberling8e963a52013-08-06 11:43:02 -07001097 final String CROP_ACTION = "com.android.camera.action.CROP";
1098 Intent cropIntent = new Intent(CROP_ACTION);
Michael Kolb8872c232013-01-29 10:33:22 -08001099
1100 cropIntent.setData(tempUri);
1101 cropIntent.putExtras(newExtras);
1102
1103 mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1104 }
1105 }
1106
Michael Kolb8872c232013-01-29 10:33:22 -08001107 @Override
1108 public void onShutterButtonFocus(boolean pressed) {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001109 if (mPaused || (mCameraState == SNAPSHOT_IN_PROGRESS)
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001110 || (mCameraState == PREVIEW_STOPPED)) {
1111 return;
1112 }
Michael Kolb8872c232013-01-29 10:33:22 -08001113
1114 // Do not do focus if there is not enough storage.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001115 if (pressed && !canTakePicture()) {
1116 return;
1117 }
Michael Kolb8872c232013-01-29 10:33:22 -08001118
1119 if (pressed) {
Michael Kolb8872c232013-01-29 10:33:22 -08001120 mFocusManager.onShutterDown();
1121 } else {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001122 mFocusManager.onShutterUp();
Michael Kolb8872c232013-01-29 10:33:22 -08001123 }
1124 }
1125
1126 @Override
1127 public void onShutterButtonClick() {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001128 if (mPaused || (mCameraState == SWITCHING_CAMERA)
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001129 || (mCameraState == PREVIEW_STOPPED)) {
1130 return;
1131 }
Michael Kolb8872c232013-01-29 10:33:22 -08001132
1133 // Do not take the picture if there is not enough storage.
Angus Kong2dcc0a92013-09-25 13:00:08 -07001134 if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Michael Kolb8872c232013-01-29 10:33:22 -08001135 Log.i(TAG, "Not enough space or storage not ready. remaining="
Angus Kong2dcc0a92013-09-25 13:00:08 -07001136 + mActivity.getStorageSpaceBytes());
Michael Kolb8872c232013-01-29 10:33:22 -08001137 return;
1138 }
1139 Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1140
Angus Kongb50b5cb2013-08-09 14:55:20 -07001141 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -07001142 mUI.setSwipingEnabled(false);
Doris Liu9cdfe002013-04-16 09:50:56 -07001143 }
Michael Kolb8872c232013-01-29 10:33:22 -08001144 // If the user wants to do a snapshot while the previous one is still
1145 // in progress, remember the fact and do it after we finish the previous
1146 // one and re-start the preview. Snapshot in progress also includes the
1147 // state that autofocus is focusing and a picture will be taken when
1148 // focus callback arrives.
1149 if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1150 && !mIsImageCaptureIntent) {
1151 mSnapshotOnIdle = true;
1152 return;
1153 }
1154
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001155 mSnapshotOnIdle = false;
1156 mFocusManager.doSnap();
Michael Kolb8872c232013-01-29 10:33:22 -08001157 }
1158
Andy Huibersdef975d2013-11-22 09:13:39 -08001159 private void onResumeTasks() {
1160 Log.v(TAG, "Executing onResumeTasks.");
Angus Kong20fad242013-11-11 18:23:46 -08001161 mActivity.getCameraProvider().requestCamera(mCameraId);
1162
Michael Kolb8872c232013-01-29 10:33:22 -08001163 mJpegPictureCallbackTime = 0;
1164 mZoomValue = 0;
Angus Kong20fad242013-11-11 18:23:46 -08001165
1166 mOnResumeTime = SystemClock.uptimeMillis();
1167 checkDisplayRotation();
Michael Kolb8872c232013-01-29 10:33:22 -08001168
1169 // If first time initialization is not finished, put it in the
1170 // message queue.
1171 if (!mFirstTimeInitialized) {
Angus Kong13e87c42013-11-25 10:02:47 -08001172 mHandler.sendEmptyMessage(MSG_FIRST_TIME_INIT);
Michael Kolb8872c232013-01-29 10:33:22 -08001173 } else {
1174 initializeSecondTime();
1175 }
Michael Kolb8872c232013-01-29 10:33:22 -08001176
Seth Raphael5e09d012013-12-18 13:45:03 -08001177 UsageStatistics.changeScreen(eventprotos.NavigationChange.Mode.PHOTO_CAPTURE,
1178 eventprotos.CameraEvent.InteractionCause.BUTTON);
Angus Kong0d00a892013-03-26 11:40:40 -07001179
1180 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1181 if (gsensor != null) {
1182 mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1183 }
1184
1185 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1186 if (msensor != null) {
1187 mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1188 }
Michael Kolb8872c232013-01-29 10:33:22 -08001189 }
1190
Angus Kongc4e66562013-11-22 23:03:21 -08001191 /**
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001192 * The focus manager is the first UI related element to get initialized, and
1193 * it requires the RenderOverlay, so initialize it here
Angus Kongc4e66562013-11-22 23:03:21 -08001194 */
1195 private void initializeFocusManager() {
1196 // Create FocusManager object. startPreview needs it.
1197 // if mFocusManager not null, reuse it
1198 // otherwise create a new instance
1199 if (mFocusManager != null) {
1200 mFocusManager.removeMessages();
1201 } else {
Angus Kongd74e6a12014-01-07 11:29:44 -08001202 CameraInfo info = mAppController.getCameraProvider().getCameraInfo()[mCameraId];
Angus Kongc4e66562013-11-22 23:03:21 -08001203 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
1204 String[] defaultFocusModes = mActivity.getResources().getStringArray(
1205 R.array.pref_camera_focusmode_default_array);
Erin Dahlgren357b7672013-11-20 17:38:14 -08001206 mFocusManager = new FocusOverlayManager(mActivity.getSettingsManager(),
1207 defaultFocusModes,
Angus Kongc4e66562013-11-22 23:03:21 -08001208 mInitialParams, this, mMirror,
Doris Liu482de022013-12-18 19:18:16 -08001209 mActivity.getMainLooper(), mUI.getFocusUI());
Angus Kongc4e66562013-11-22 23:03:21 -08001210 }
Doris Liu482de022013-12-18 19:18:16 -08001211 mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
Angus Kong20fad242013-11-11 18:23:46 -08001212 }
1213
1214 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001215 public void resume() {
1216 mPaused = false;
Doris Liu482de022013-12-18 19:18:16 -08001217 if (mFocusManager != null) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001218 // If camera is not open when resume is called, focus manager will
1219 // not
Doris Liu15b99612013-12-21 11:32:28 -08001220 // be initialized yet, in which case it will start listening to
1221 // preview area size change later in the initialization.
Doris Liu482de022013-12-18 19:18:16 -08001222 mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
1223 }
Doris Liu59401042014-01-14 17:51:32 -08001224
1225 if (mUI.getPreviewAreaSizeChangedListener() != null) {
1226 mAppController.addPreviewAreaSizeChangedListener(
1227 mUI.getPreviewAreaSizeChangedListener());
1228 }
1229
Angus Kongc4e66562013-11-22 23:03:21 -08001230 // Add delay on resume from lock screen only, in order to to speed up
1231 // the onResume --> onPause --> onResume cycle from lock screen.
1232 // Don't do always because letting go of thread can cause delay.
1233 String action = mActivity.getIntent().getAction();
1234 if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
1235 || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
1236 Log.v(TAG, "On resume, from lock screen.");
1237 // Note: onPauseAfterSuper() will delete this runnable, so we will
1238 // at most have 1 copy queued up.
1239 mHandler.postDelayed(new Runnable() {
Sameer Padala2c8cc452013-11-05 18:49:12 -08001240 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001241 public void run() {
1242 onResumeTasks();
1243 }
1244 }, ON_RESUME_TASKS_DELAY_MSEC);
1245 } else {
1246 Log.v(TAG, "On resume.");
1247 onResumeTasks();
1248 }
1249 }
1250
1251 @Override
1252 public void pause() {
Michael Kolb8872c232013-01-29 10:33:22 -08001253 mPaused = true;
Angus Kong0d00a892013-03-26 11:40:40 -07001254 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1255 if (gsensor != null) {
1256 mSensorManager.unregisterListener(this, gsensor);
1257 }
1258
1259 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1260 if (msensor != null) {
1261 mSensorManager.unregisterListener(this, msensor);
1262 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001263
Michael Kolb8872c232013-01-29 10:33:22 -08001264 // Reset the focus first. Camera CTS does not guarantee that
1265 // cancelAutoFocus is allowed after preview stops.
1266 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1267 mCameraDevice.cancelAutoFocus();
1268 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001269
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -08001270 // If the camera has not been opened asynchronously yet,
1271 // and startPreview hasn't been called, then this is a no-op.
1272 // (e.g. onResume -> onPause -> onResume).
Michael Kolb8872c232013-01-29 10:33:22 -08001273 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001274
Angus Kongce5480e2013-01-29 17:43:48 -08001275 mNamedImages = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001276
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001277 if (mLocationManager != null) {
1278 mLocationManager.recordLocation(false);
1279 }
Michael Kolb8872c232013-01-29 10:33:22 -08001280
1281 // If we are in an image capture intent and has taken
1282 // a picture, we just clear it in onPause.
1283 mJpegImageData = null;
1284
Angus Kongdcccc512013-08-08 17:06:03 -07001285 // Remove the messages and runnables in the queue.
1286 mHandler.removeCallbacksAndMessages(null);
Michael Kolb8872c232013-01-29 10:33:22 -08001287
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001288 closeCamera();
Angus Kong13e87c42013-11-25 10:02:47 -08001289 mActivity.enableKeepScreenOn(false);
Michael Kolbd6954f32013-03-08 20:43:01 -08001290 mUI.onPause();
1291
Michael Kolb8872c232013-01-29 10:33:22 -08001292 mPendingSwitchCameraId = -1;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001293 if (mFocusManager != null) {
1294 mFocusManager.removeMessages();
Angus Kong86d36312013-01-31 18:22:44 -08001295 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001296 getServices().getMemoryManager().removeListener(this);
Doris Liu482de022013-12-18 19:18:16 -08001297 mAppController.removePreviewAreaSizeChangedListener(mFocusManager);
Doris Liu59401042014-01-14 17:51:32 -08001298 if (mUI.getPreviewAreaSizeChangedListener() != null) {
1299 mAppController.removePreviewAreaSizeChangedListener(
1300 mUI.getPreviewAreaSizeChangedListener());
1301 }
Erin Dahlgren1648c362014-01-06 15:06:04 -08001302
1303 SettingsManager settingsManager = mActivity.getSettingsManager();
1304 settingsManager.removeListener(this);
Michael Kolb8872c232013-01-29 10:33:22 -08001305 }
1306
Angus Kong20fad242013-11-11 18:23:46 -08001307 @Override
1308 public void destroy() {
1309 // TODO: implement this.
1310 }
1311
1312 @Override
Angus Kong2f0e4a32013-12-03 10:02:35 -08001313 public void onLayoutOrientationChanged(boolean isLandscape) {
Michael Kolb8872c232013-01-29 10:33:22 -08001314 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001315 }
1316
1317 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001318 public void updateCameraOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001319 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001320 setDisplayOrientation();
1321 }
1322 }
1323
Michael Kolb8872c232013-01-29 10:33:22 -08001324 private boolean canTakePicture() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001325 return isCameraIdle()
1326 && (mActivity.getStorageSpaceBytes() > Storage.LOW_STORAGE_THRESHOLD_BYTES);
Michael Kolb8872c232013-01-29 10:33:22 -08001327 }
1328
1329 @Override
1330 public void autoFocus() {
1331 mFocusStartTime = System.currentTimeMillis();
Angus Kong9ef99252013-07-18 18:04:19 -07001332 mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001333 setCameraState(FOCUSING);
1334 }
1335
1336 @Override
1337 public void cancelAutoFocus() {
1338 mCameraDevice.cancelAutoFocus();
1339 setCameraState(IDLE);
1340 setCameraParameters(UPDATE_PARAM_PREFERENCE);
1341 }
1342
Michael Kolb8872c232013-01-29 10:33:22 -08001343 @Override
1344 public void onSingleTapUp(View view, int x, int y) {
Doris Liu482de022013-12-18 19:18:16 -08001345 if (mPaused || mCameraDevice == null || !mFirstTimeInitialized
1346 || mCameraState == SNAPSHOT_IN_PROGRESS
1347 || mCameraState == SWITCHING_CAMERA
1348 || mCameraState == PREVIEW_STOPPED) {
1349 return;
1350 }
1351
1352 // Check if metering area or focus area is supported.
Doris Liu15b99612013-12-21 11:32:28 -08001353 if (!mFocusAreaSupported && !mMeteringAreaSupported) {
1354 return;
1355 }
Doris Liu482de022013-12-18 19:18:16 -08001356 mFocusManager.onSingleTapUp(x, y);
Michael Kolb8872c232013-01-29 10:33:22 -08001357 }
1358
1359 @Override
1360 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001361 return mUI.onBackPressed();
Michael Kolb8872c232013-01-29 10:33:22 -08001362 }
1363
1364 @Override
1365 public boolean onKeyDown(int keyCode, KeyEvent event) {
1366 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001367 case KeyEvent.KEYCODE_VOLUME_UP:
1368 case KeyEvent.KEYCODE_VOLUME_DOWN:
1369 case KeyEvent.KEYCODE_FOCUS:
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001370 if (/* TODO: mActivity.isInCameraApp() && */mFirstTimeInitialized) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001371 if (event.getRepeatCount() == 0) {
1372 onShutterButtonFocus(true);
1373 }
1374 return true;
1375 }
1376 return false;
1377 case KeyEvent.KEYCODE_CAMERA:
1378 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1379 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001380 }
1381 return true;
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001382 case KeyEvent.KEYCODE_DPAD_CENTER:
1383 // If we get a dpad center event without any focused view, move
1384 // the focus to the shutter button and press it.
1385 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1386 // Start auto-focus immediately to reduce shutter lag. After
1387 // the shutter button gets the focus, onShutterButtonFocus()
1388 // will be called again but it is fine.
1389 onShutterButtonFocus(true);
1390 mUI.pressShutterButton();
1391 }
1392 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001393 }
1394 return false;
1395 }
1396
1397 @Override
1398 public boolean onKeyUp(int keyCode, KeyEvent event) {
1399 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001400 case KeyEvent.KEYCODE_VOLUME_UP:
1401 case KeyEvent.KEYCODE_VOLUME_DOWN:
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001402 if (/* mActivity.isInCameraApp() && */mFirstTimeInitialized) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001403 onShutterButtonClick();
1404 return true;
1405 }
1406 return false;
1407 case KeyEvent.KEYCODE_FOCUS:
1408 if (mFirstTimeInitialized) {
1409 onShutterButtonFocus(false);
1410 }
Michael Kolb8872c232013-01-29 10:33:22 -08001411 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001412 }
1413 return false;
1414 }
1415
Michael Kolb8872c232013-01-29 10:33:22 -08001416 private void closeCamera() {
1417 if (mCameraDevice != null) {
1418 mCameraDevice.setZoomChangeListener(null);
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001419 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001420 mCameraDevice.setErrorCallback(null);
Ruben Brunk59147832013-11-05 15:53:28 -08001421
Michael Kolb8872c232013-01-29 10:33:22 -08001422 mFaceDetectionStarted = false;
Angus Kong20fad242013-11-11 18:23:46 -08001423 mActivity.getCameraProvider().releaseCamera(mCameraDevice.getCameraId());
Michael Kolb8872c232013-01-29 10:33:22 -08001424 mCameraDevice = null;
1425 setCameraState(PREVIEW_STOPPED);
1426 mFocusManager.onCameraReleased();
1427 }
1428 }
1429
1430 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001431 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1432 mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001433 mCameraDisplayOrientation = mDisplayOrientation;
Michael Kolbd6954f32013-03-08 20:43:01 -08001434 mUI.setDisplayOrientation(mDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001435 if (mFocusManager != null) {
1436 mFocusManager.setDisplayOrientation(mDisplayOrientation);
1437 }
Doris Liu6432cd62013-06-13 17:20:31 -07001438 // Change the camera display orientation
1439 if (mCameraDevice != null) {
1440 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1441 }
Michael Kolb8872c232013-01-29 10:33:22 -08001442 }
1443
Sascha Haeberlingddef7792013-08-13 14:41:10 -07001444 /** Only called by UI thread. */
Michael Kolb8872c232013-01-29 10:33:22 -08001445 private void setupPreview() {
1446 mFocusManager.resetTouchFocus();
1447 startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001448 }
1449
Angus Kong20fad242013-11-11 18:23:46 -08001450 /**
1451 * Returns whether we can/should start the preview or not.
1452 */
1453 private boolean checkPreviewPreconditions() {
1454 if (mPaused) {
1455 return false;
Angus Kongdcccc512013-08-08 17:06:03 -07001456 }
Michael Kolb8872c232013-01-29 10:33:22 -08001457
Angus Kong20fad242013-11-11 18:23:46 -08001458 if (mCameraDevice == null) {
1459 Log.w(TAG, "startPreview: camera device not ready yet.");
1460 return false;
1461 }
1462
Erin Dahlgrend8de0772014-02-03 10:12:27 -08001463 SurfaceTexture st = mActivity.getCameraAppUI().getSurfaceTexture();
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001464 if (st == null) {
1465 Log.w(TAG, "startPreview: surfaceTexture is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001466 return false;
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001467 }
1468
1469 if (!mCameraPreviewParamsReady) {
1470 Log.w(TAG, "startPreview: parameters for preview is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001471 return false;
1472 }
1473 return true;
1474 }
1475
1476 /**
1477 * The start/stop preview should only run on the UI thread.
1478 */
1479 private void startPreview() {
1480 if (!checkPreviewPreconditions()) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001481 return;
1482 }
Angus Kong20fad242013-11-11 18:23:46 -08001483
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001484 mCameraDevice.setErrorCallback(mErrorCallback);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001485 // ICS camera frameworks has a bug. Face detection state is not cleared
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001486 // after taking a picture. Stop the preview to work around it. The bug
1487 // was fixed in JB.
1488 if (mCameraState != PREVIEW_STOPPED) {
1489 stopPreview();
1490 }
1491
1492 setDisplayOrientation();
1493
1494 if (!mSnapshotOnIdle) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001495 // If the focus mode is continuous autofocus, call cancelAutoFocus
1496 // to resume it because it may have been paused by autoFocus call.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001497 String focusMode = mFocusManager.getFocusMode();
1498 if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(focusMode)) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001499 mCameraDevice.cancelAutoFocus();
Michael Kolb8872c232013-01-29 10:33:22 -08001500 }
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001501 mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1502 }
1503 setCameraParameters(UPDATE_PARAM_ALL);
1504 // Let UI set its expected aspect ratio
Erin Dahlgrend8de0772014-02-03 10:12:27 -08001505 mCameraDevice.setPreviewTexture(mActivity.getCameraAppUI().getSurfaceTexture());
Michael Kolb8872c232013-01-29 10:33:22 -08001506
Doris Liu5a367542014-01-17 17:21:42 -08001507 // This is to notify app controller that preview will start next, so app
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001508 // controller can set preview callbacks if needed. This has to happen
1509 // before preview is started as a workaround of the framework bug related to
1510 // preview callbacks at b/12591410.
Doris Liu5a367542014-01-17 17:21:42 -08001511 mAppController.onPreviewReadyToStart();
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001512 Log.v(TAG, "startPreview");
1513 mCameraDevice.startPreview();
Angus Kong20fad242013-11-11 18:23:46 -08001514
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001515 mFocusManager.onPreviewStarted();
1516 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001517
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001518 if (mSnapshotOnIdle) {
1519 mHandler.post(mDoSnapRunnable);
Michael Kolb8872c232013-01-29 10:33:22 -08001520 }
1521 }
1522
Michael Kolbd6954f32013-03-08 20:43:01 -08001523 @Override
1524 public void stopPreview() {
Michael Kolb8872c232013-01-29 10:33:22 -08001525 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1526 Log.v(TAG, "stopPreview");
1527 mCameraDevice.stopPreview();
1528 mFaceDetectionStarted = false;
1529 }
1530 setCameraState(PREVIEW_STOPPED);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001531 if (mFocusManager != null) {
1532 mFocusManager.onPreviewStopped();
1533 }
Sameer Padala2c8cc452013-11-05 18:49:12 -08001534 stopSmartCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001535 }
1536
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001537 @Override
Erin Dahlgren1648c362014-01-06 15:06:04 -08001538 public void onSettingChanged(SettingsManager settingsManager, int id) {
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001539 switch (id) {
1540 case SettingsManager.SETTING_FLASH_MODE: {
1541 updateParametersFlashMode();
1542 break;
1543 }
1544 case SettingsManager.SETTING_PICTURE_SIZE: {
1545 updateParametersPictureSize();
1546 break;
1547 }
1548 case SettingsManager.SETTING_RECORD_LOCATION: {
1549 SettingsController settingsController = mActivity.getSettingsController();
1550 settingsController.syncLocationManager();
1551 break;
1552 }
1553 default: {
1554 // Do nothing.
1555 }
1556 }
Erin Dahlgren1648c362014-01-06 15:06:04 -08001557
1558 if (mCameraDevice != null) {
1559 mCameraDevice.setParameters(mParameters);
1560 }
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001561 }
1562
Michael Kolb8872c232013-01-29 10:33:22 -08001563 private void updateCameraParametersInitialize() {
1564 // Reset preview frame rate to the maximum because it may be lowered by
1565 // video camera application.
ztenghui16a35202013-09-23 11:35:36 -07001566 int[] fpsRange = CameraUtil.getPhotoPreviewFpsRange(mParameters);
1567 if (fpsRange != null && fpsRange.length > 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001568 mParameters.setPreviewFpsRange(
1569 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1570 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
Michael Kolb8872c232013-01-29 10:33:22 -08001571 }
1572
Angus Kongb50b5cb2013-08-09 14:55:20 -07001573 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);
Michael Kolb8872c232013-01-29 10:33:22 -08001574
1575 // Disable video stabilization. Convenience methods not available in API
1576 // level <= 14
1577 String vstabSupported = mParameters.get("video-stabilization-supported");
1578 if ("true".equals(vstabSupported)) {
1579 mParameters.set("video-stabilization", "false");
1580 }
1581 }
1582
1583 private void updateCameraParametersZoom() {
1584 // Set zoom.
1585 if (mParameters.isZoomSupported()) {
1586 mParameters.setZoom(mZoomValue);
1587 }
1588 }
1589
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001590 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001591 private void setAutoExposureLockIfSupported() {
1592 if (mAeLockSupported) {
1593 mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1594 }
1595 }
1596
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001597 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001598 private void setAutoWhiteBalanceLockIfSupported() {
1599 if (mAwbLockSupported) {
1600 mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1601 }
1602 }
1603
Michael Kolb8872c232013-01-29 10:33:22 -08001604 private void setFocusAreasIfSupported() {
1605 if (mFocusAreaSupported) {
1606 mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1607 }
1608 }
1609
Michael Kolb8872c232013-01-29 10:33:22 -08001610 private void setMeteringAreasIfSupported() {
1611 if (mMeteringAreaSupported) {
Michael Kolb8872c232013-01-29 10:33:22 -08001612 mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1613 }
1614 }
1615
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001616 private void updateCameraParametersPreference() {
Michael Kolb8872c232013-01-29 10:33:22 -08001617 setAutoExposureLockIfSupported();
1618 setAutoWhiteBalanceLockIfSupported();
1619 setFocusAreasIfSupported();
1620 setMeteringAreasIfSupported();
1621
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001622 // Initialize focus mode.
Michael Kolbd3253f22013-07-12 11:36:47 -07001623 mFocusManager.overrideFocusMode(null);
1624 mParameters.setFocusMode(mFocusManager.getFocusMode());
1625
Michael Kolb8872c232013-01-29 10:33:22 -08001626 // Set picture size.
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001627 updateParametersPictureSize();
1628
1629 // Set JPEG quality.
1630 updateParametersPictureQuality();
1631
1632 // For the following settings, we need to check if the settings are
1633 // still supported by latest driver, if not, ignore the settings.
1634
1635 // Set exposure compensation
1636 updateParametersExposureCompensation();
1637
1638 // Set the scene mode: also sets flash and white balance.
1639 updateParametersSceneMode();
1640
1641 if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
1642 updateAutoFocusMoveCallback();
1643 }
1644 }
1645
1646 private void updateParametersPictureSize() {
1647 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001648 String pictureSize = settingsManager.get(SettingsManager.SETTING_PICTURE_SIZE);
Sascha Haeberling3b0ab892014-01-29 20:54:39 +01001649
1650 List<Size> supported = mParameters.getSupportedPictureSizes();
1651 SettingsUtil.setCameraPictureSize(pictureSize, supported, mParameters);
Michael Kolb8872c232013-01-29 10:33:22 -08001652 Size size = mParameters.getPictureSize();
1653
1654 // Set a preview size that is closest to the viewfinder height and has
1655 // the right aspect ratio.
1656 List<Size> sizes = mParameters.getSupportedPreviewSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001657 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
Michael Kolb8872c232013-01-29 10:33:22 -08001658 (double) size.width / size.height);
1659 Size original = mParameters.getPreviewSize();
1660 if (!original.equals(optimalSize)) {
1661 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
Doris Liu6432cd62013-06-13 17:20:31 -07001662
Michael Kolb8872c232013-01-29 10:33:22 -08001663 // Zoom related settings will be changed for different preview
1664 // sizes, so set and read the parameters to get latest values
Michael Kolb4a4d4ef2013-05-30 08:35:26 -07001665 if (mHandler.getLooper() == Looper.myLooper()) {
1666 // On UI thread only, not when camera starts up
1667 setupPreview();
1668 } else {
1669 mCameraDevice.setParameters(mParameters);
1670 }
Michael Kolb8872c232013-01-29 10:33:22 -08001671 mParameters = mCameraDevice.getParameters();
1672 }
Doris Liu95405742013-11-05 15:25:26 -08001673
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001674 if (optimalSize.width != 0 && optimalSize.height != 0) {
Doris Liu95405742013-11-05 15:25:26 -08001675 mUI.updatePreviewAspectRatio((float) optimalSize.width
1676 / (float) optimalSize.height);
1677 }
Michael Kolb8872c232013-01-29 10:33:22 -08001678 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001679 }
Michael Kolb8872c232013-01-29 10:33:22 -08001680
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001681 private void updateParametersPictureQuality() {
Michael Kolb8872c232013-01-29 10:33:22 -08001682 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1683 CameraProfile.QUALITY_HIGH);
1684 mParameters.setJpegQuality(jpegQuality);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001685 }
Michael Kolb8872c232013-01-29 10:33:22 -08001686
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001687 private void updateParametersExposureCompensation() {
1688 SettingsManager settingsManager = mActivity.getSettingsManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001689
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001690 int value = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_EXPOSURE));
Michael Kolb8872c232013-01-29 10:33:22 -08001691 int max = mParameters.getMaxExposureCompensation();
1692 int min = mParameters.getMinExposureCompensation();
1693 if (value >= min && value <= max) {
1694 mParameters.setExposureCompensation(value);
1695 } else {
1696 Log.w(TAG, "invalid exposure range: " + value);
1697 }
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001698 }
1699
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001700 private void updateParametersSceneMode() {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001701 SettingsManager settingsManager = mActivity.getSettingsManager();
1702
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001703 mSceneMode = settingsManager.get(SettingsManager.SETTING_SCENE_MODE);
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001704 if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
1705 if (!mParameters.getSceneMode().equals(mSceneMode)) {
1706 mParameters.setSceneMode(mSceneMode);
1707
1708 // Setting scene mode will change the settings of flash mode,
1709 // white balance, and focus mode. Here we read back the
1710 // parameters, so we can know those settings.
1711 mCameraDevice.setParameters(mParameters);
1712 mParameters = mCameraDevice.getParameters();
1713 }
1714 } else {
1715 mSceneMode = mParameters.getSceneMode();
1716 if (mSceneMode == null) {
1717 mSceneMode = Parameters.SCENE_MODE_AUTO;
1718 }
1719 }
1720
Michael Kolb8872c232013-01-29 10:33:22 -08001721 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1722 // Set flash mode.
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001723 updateParametersFlashMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001724
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001725 // Set white balance mode.
1726 updateParametersWhiteBalanceMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001727
1728 // Set focus mode.
1729 mFocusManager.overrideFocusMode(null);
1730 mParameters.setFocusMode(mFocusManager.getFocusMode());
1731 } else {
1732 mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1733 }
Michael Kolb8872c232013-01-29 10:33:22 -08001734 }
1735
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001736 private void updateParametersFlashMode() {
1737 SettingsManager settingsManager = mActivity.getSettingsManager();
1738
1739 String flashMode = settingsManager.get(SettingsManager.SETTING_FLASH_MODE);
1740 List<String> supportedFlash = mParameters.getSupportedFlashModes();
1741 if (CameraUtil.isSupported(flashMode, supportedFlash)) {
1742 mParameters.setFlashMode(flashMode);
1743 }
1744 }
1745
1746 private void updateParametersWhiteBalanceMode() {
1747 SettingsManager settingsManager = mActivity.getSettingsManager();
1748
1749 // Set white balance parameter.
1750 String whiteBalance = settingsManager.get(SettingsManager.SETTING_WHITE_BALANCE);
1751 if (CameraUtil.isSupported(whiteBalance,
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001752 mParameters.getSupportedWhiteBalance())) {
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001753 mParameters.setWhiteBalance(whiteBalance);
1754 }
1755 }
1756
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001757 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001758 private void updateAutoFocusMoveCallback() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001759 if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Angus Kong9ef99252013-07-18 18:04:19 -07001760 mCameraDevice.setAutoFocusMoveCallback(mHandler,
Angus Kong4f795b82013-09-16 14:25:35 -07001761 (CameraAFMoveCallback) mAutoFocusMoveCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001762 } else {
Angus Kong9ef99252013-07-18 18:04:19 -07001763 mCameraDevice.setAutoFocusMoveCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001764 }
1765 }
1766
1767 // We separate the parameters into several subsets, so we can update only
1768 // the subsets actually need updating. The PREFERENCE set needs extra
1769 // locking because the preference can be changed from GLThread as well.
1770 private void setCameraParameters(int updateSet) {
1771 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1772 updateCameraParametersInitialize();
1773 }
1774
1775 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1776 updateCameraParametersZoom();
1777 }
1778
1779 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001780 updateCameraParametersPreference();
Michael Kolb8872c232013-01-29 10:33:22 -08001781 }
1782
1783 mCameraDevice.setParameters(mParameters);
1784 }
1785
1786 // If the Camera is idle, update the parameters immediately, otherwise
1787 // accumulate them in mUpdateSet and update later.
1788 private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1789 mUpdateSet |= additionalUpdateSet;
1790 if (mCameraDevice == null) {
1791 // We will update all the parameters when we open the device, so
1792 // we don't need to do anything now.
1793 mUpdateSet = 0;
1794 return;
1795 } else if (isCameraIdle()) {
1796 setCameraParameters(mUpdateSet);
Michael Kolbd6954f32013-03-08 20:43:01 -08001797 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001798 mUpdateSet = 0;
1799 } else {
Angus Kong13e87c42013-11-25 10:02:47 -08001800 if (!mHandler.hasMessages(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1801 mHandler.sendEmptyMessageDelayed(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
Michael Kolb8872c232013-01-29 10:33:22 -08001802 }
1803 }
1804 }
1805
ztenghui7b265a62013-09-09 14:58:44 -07001806 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001807 public boolean isCameraIdle() {
Michael Kolb8872c232013-01-29 10:33:22 -08001808 return (mCameraState == IDLE) ||
1809 (mCameraState == PREVIEW_STOPPED) ||
1810 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001811 && (mCameraState != SWITCHING_CAMERA));
Michael Kolb8872c232013-01-29 10:33:22 -08001812 }
1813
ztenghui7b265a62013-09-09 14:58:44 -07001814 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001815 public boolean isImageCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001816 String action = mActivity.getIntent().getAction();
1817 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001818 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
Michael Kolb8872c232013-01-29 10:33:22 -08001819 }
1820
1821 private void setupCaptureParams() {
1822 Bundle myExtras = mActivity.getIntent().getExtras();
1823 if (myExtras != null) {
1824 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1825 mCropValue = myExtras.getString("crop");
1826 }
1827 }
1828
Michael Kolb8872c232013-01-29 10:33:22 -08001829 public void onSharedPreferenceChanged() {
1830 // ignore the events after "onPause()"
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001831 if (mPaused) {
1832 return;
1833 }
Michael Kolb8872c232013-01-29 10:33:22 -08001834
Erin Dahlgren357b7672013-11-20 17:38:14 -08001835 SettingsController settingsController = mActivity.getSettingsController();
1836 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001837
1838 setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
Michael Kolb8872c232013-01-29 10:33:22 -08001839 }
1840
Michael Kolb8872c232013-01-29 10:33:22 -08001841 private void showTapToFocusToast() {
1842 // TODO: Use a toast?
1843 new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
1844 // Clear the preference.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001845 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001846 settingsManager.setBoolean(
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001847 SettingsManager.SETTING_CAMERA_FIRST_USE_HINT_SHOWN, false);
Michael Kolb8872c232013-01-29 10:33:22 -08001848 }
1849
1850 private void initializeCapabilities() {
1851 mInitialParams = mCameraDevice.getParameters();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001852 mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
1853 mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
1854 mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
1855 mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
Angus Kongdcccc512013-08-08 17:06:03 -07001856 mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001857 CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
Michael Kolb8872c232013-01-29 10:33:22 -08001858 }
1859
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001860 private void setShutterEnabled(boolean enabled) {
1861 mShutterEnabled = enabled;
1862 mUI.enableShutter(enabled);
1863 }
1864
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001865 // TODO: Remove this
Michael Kolb8872c232013-01-29 10:33:22 -08001866 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001867 public int onZoomChanged(int index) {
1868 // Not useful to change zoom value when the activity is paused.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001869 if (mPaused) {
1870 return index;
1871 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001872 mZoomValue = index;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001873 if (mParameters == null || mCameraDevice == null) {
1874 return index;
1875 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001876 // Set zoom parameters asynchronously
1877 mParameters.setZoom(mZoomValue);
Angus Kong36ed8672013-04-15 12:11:15 -07001878 mCameraDevice.setParameters(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -08001879 Parameters p = mCameraDevice.getParameters();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001880 if (p != null) {
1881 return p.getZoom();
1882 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001883 return index;
Angus Kongce5480e2013-01-29 17:43:48 -08001884 }
1885
1886 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001887 public int getCameraState() {
1888 return mCameraState;
1889 }
1890
1891 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001892 public void onMemoryStateChanged(int state) {
1893 setShutterEnabled(state == MemoryManager.STATE_OK);
Angus Kongce5480e2013-01-29 17:43:48 -08001894 }
Angus Kong86d36312013-01-31 18:22:44 -08001895
1896 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001897 public void onLowMemory() {
1898 // Not much we can do in the photo module.
Angus Kong86d36312013-01-31 18:22:44 -08001899 }
Angus Kong0d00a892013-03-26 11:40:40 -07001900
1901 @Override
1902 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1903 }
1904
1905 @Override
1906 public void onSensorChanged(SensorEvent event) {
1907 int type = event.sensor.getType();
1908 float[] data;
1909 if (type == Sensor.TYPE_ACCELEROMETER) {
1910 data = mGData;
1911 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
1912 data = mMData;
1913 } else {
1914 // we should not be here.
1915 return;
1916 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001917 for (int i = 0; i < 3; i++) {
Angus Kong0d00a892013-03-26 11:40:40 -07001918 data[i] = event.values[i];
1919 }
1920 float[] orientation = new float[3];
1921 SensorManager.getRotationMatrix(mR, null, mGData, mMData);
1922 SensorManager.getOrientation(mR, orientation);
1923 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
1924 if (mHeading < 0) {
1925 mHeading += 360;
1926 }
Angus Kong0d00a892013-03-26 11:40:40 -07001927 }
Doris Liu6432cd62013-06-13 17:20:31 -07001928
Ruben Brunkd217ed02013-10-08 23:31:13 -07001929 // For debugging only.
1930 public void setDebugUri(Uri uri) {
1931 mDebugUri = uri;
1932 }
1933
1934 // For debugging only.
1935 private void saveToDebugUri(byte[] data) {
1936 if (mDebugUri != null) {
1937 OutputStream outputStream = null;
1938 try {
1939 outputStream = mContentResolver.openOutputStream(mDebugUri);
1940 outputStream.write(data);
1941 outputStream.close();
1942 } catch (IOException e) {
1943 Log.e(TAG, "Exception while writing debug jpeg file", e);
1944 } finally {
1945 CameraUtil.closeSilently(outputStream);
1946 }
1947 }
1948 }
Michael Kolb8872c232013-01-29 10:33:22 -08001949}