blob: a569c4a79afc4802520ae67a201976e2493c293f [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.content.res.Configuration;
25import android.graphics.Bitmap;
Doris Liu36ebcb12013-10-28 14:44:24 -070026import android.graphics.Rect;
Michael Kolb8872c232013-01-29 10:33:22 -080027import android.graphics.SurfaceTexture;
28import android.hardware.Camera.CameraInfo;
Michael Kolb8872c232013-01-29 10:33:22 -080029import android.hardware.Camera.Parameters;
Michael Kolb8872c232013-01-29 10:33:22 -080030import android.hardware.Camera.Size;
Angus Kong0d00a892013-03-26 11:40:40 -070031import android.hardware.Sensor;
32import android.hardware.SensorEvent;
33import android.hardware.SensorEventListener;
34import android.hardware.SensorManager;
Michael Kolb8872c232013-01-29 10:33:22 -080035import android.location.Location;
36import android.media.CameraProfile;
37import android.net.Uri;
Sascha Haeberling638e6f02013-09-18 14:28:51 -070038import android.os.Build;
Michael Kolb8872c232013-01-29 10:33:22 -080039import android.os.Bundle;
Michael Kolb8872c232013-01-29 10:33:22 -080040import android.os.Handler;
41import android.os.Looper;
42import android.os.Message;
43import android.os.MessageQueue;
44import android.os.SystemClock;
45import android.provider.MediaStore;
46import android.util.Log;
Michael Kolb8872c232013-01-29 10:33:22 -080047import android.view.KeyEvent;
Michael Kolb8872c232013-01-29 10:33:22 -080048import android.view.OrientationEventListener;
Michael Kolb8872c232013-01-29 10:33:22 -080049import android.view.View;
Doris Liu773e1c92013-12-02 17:35:03 -080050import android.view.ViewGroup;
Michael Kolb8872c232013-01-29 10:33:22 -080051
Sameer Padala2c8cc452013-11-05 18:49:12 -080052import com.android.camera.PhotoModule.NamedImages.NamedEntity;
53import com.android.camera.app.AppController;
Angus Kong20fad242013-11-11 18:23:46 -080054import com.android.camera.app.CameraManager.CameraAFCallback;
55import com.android.camera.app.CameraManager.CameraAFMoveCallback;
56import com.android.camera.app.CameraManager.CameraPictureCallback;
57import com.android.camera.app.CameraManager.CameraProxy;
58import com.android.camera.app.CameraManager.CameraShutterCallback;
Marco Nelissen0744e4a2013-11-22 01:47:37 +000059import com.android.camera.app.AppController;
Angus Kongfd4fc0e2013-11-07 15:38:09 -080060import com.android.camera.app.MediaSaver;
ztenghuia16e7b52013-08-23 11:47:56 -070061import com.android.camera.exif.ExifInterface;
62import com.android.camera.exif.ExifTag;
63import com.android.camera.exif.Rational;
Angus Kong20fad242013-11-11 18:23:46 -080064import com.android.camera.module.ModuleController;
Erin Dahlgren357b7672013-11-20 17:38:14 -080065import com.android.camera.settings.SettingsManager;
Michael Kolbd6954f32013-03-08 20:43:01 -080066import com.android.camera.ui.CountDownView.OnCountDownFinishedListener;
Doris Liu1c94b7d2013-11-09 19:13:44 -080067import com.android.camera.ui.ModeListView;
Michael Kolb8872c232013-01-29 10:33:22 -080068import com.android.camera.ui.RotateTextToast;
Angus Kongdcccc512013-08-08 17:06:03 -070069import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -070070import com.android.camera.util.CameraUtil;
Ruben Brunk4601f5d2013-09-24 18:35:22 -070071import com.android.camera.util.GcamHelper;
Sameer Padala2c8cc452013-11-05 18:49:12 -080072import com.android.camera.util.SmartCameraHelper;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070073import com.android.camera.util.UsageStatistics;
74import com.android.camera2.R;
Michael Kolb8872c232013-01-29 10:33:22 -080075
Angus Kongdcccc512013-08-08 17:06:03 -070076import java.io.File;
77import java.io.FileNotFoundException;
78import java.io.FileOutputStream;
79import java.io.IOException;
80import java.io.OutputStream;
Angus Kongdcccc512013-08-08 17:06:03 -070081import java.util.List;
Ruben Brunka9d66bd2013-09-06 11:56:32 -070082import java.util.Vector;
Angus Kongdcccc512013-08-08 17:06:03 -070083
Michael Kolb8872c232013-01-29 10:33:22 -080084public class PhotoModule
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080085 extends CameraModule
86 implements PhotoController,
87 ModuleController,
88 FocusOverlayManager.Listener,
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080089 ShutterButton.OnShutterButtonListener, MediaSaver.QueueListener,
90 OnCountDownFinishedListener,
91 SensorEventListener {
Michael Kolb8872c232013-01-29 10:33:22 -080092
93 private static final String TAG = "CAM_PhotoModule";
94
95 // We number the request code from 1000 to avoid collision with Gallery.
96 private static final int REQUEST_CROP = 1000;
97
Angus Kong13e87c42013-11-25 10:02:47 -080098 // Messages defined for the UI thread handler.
99 private static final int MSG_SETUP_PREVIEW = 1;
100 private static final int MSG_FIRST_TIME_INIT = 2;
101 private static final int MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE = 3;
102 private static final int MSG_SHOW_TAP_TO_FOCUS_TOAST = 4;
103 private static final int MSG_SWITCH_CAMERA = 5;
104 private static final int MSG_SWITCH_CAMERA_START_ANIMATION = 6;
105 private static final int MSG_CAMERA_OPEN_DONE = 7;
106 private static final int MSG_OPEN_CAMERA_FAIL = 8;
107 private static final int MSG_CAMERA_DISABLED = 9;
108 private static final int MSG_SWITCH_TO_GCAM_MODULE = 10;
Michael Kolb8872c232013-01-29 10:33:22 -0800109
110 // The subset of parameters we need to update in setCameraParameters().
111 private static final int UPDATE_PARAM_INITIALIZE = 1;
112 private static final int UPDATE_PARAM_ZOOM = 2;
113 private static final int UPDATE_PARAM_PREFERENCE = 4;
114 private static final int UPDATE_PARAM_ALL = -1;
115
Andy Huibersdef975d2013-11-22 09:13:39 -0800116 // This is the delay before we execute onResume tasks when coming
117 // from the lock screen, to allow time for onPause to execute.
118 private static final int ON_RESUME_TASKS_DELAY_MSEC = 20;
Michael Kolb8872c232013-01-29 10:33:22 -0800119
Ruben Brunkd7488272013-10-10 18:45:53 -0700120 private static final String DEBUG_IMAGE_PREFIX = "DEBUG_";
121
Michael Kolb8872c232013-01-29 10:33:22 -0800122 // copied from Camera hierarchy
123 private CameraActivity mActivity;
Michael Kolb8872c232013-01-29 10:33:22 -0800124 private CameraProxy mCameraDevice;
125 private int mCameraId;
126 private Parameters mParameters;
127 private boolean mPaused;
Michael Kolbd6954f32013-03-08 20:43:01 -0800128
129 private PhotoUI mUI;
Michael Kolb8872c232013-01-29 10:33:22 -0800130
Michael Kolb8872c232013-01-29 10:33:22 -0800131 // The activity is going to switch to the specified camera id. This is
132 // needed because texture copy is done in GL thread. -1 means camera is not
133 // switching.
134 protected int mPendingSwitchCameraId = -1;
135 private boolean mOpenCameraFail;
136 private boolean mCameraDisabled;
137
138 // When setCameraParametersWhenIdle() is called, we accumulate the subsets
139 // needed to be updated in mUpdateSet.
140 private int mUpdateSet;
141
142 private static final int SCREEN_DELAY = 2 * 60 * 1000;
143
144 private int mZoomValue; // The current zoom value.
Michael Kolb8872c232013-01-29 10:33:22 -0800145
146 private Parameters mInitialParams;
147 private boolean mFocusAreaSupported;
148 private boolean mMeteringAreaSupported;
149 private boolean mAeLockSupported;
150 private boolean mAwbLockSupported;
Angus Kongdcccc512013-08-08 17:06:03 -0700151 private boolean mContinuousFocusSupported;
Michael Kolb8872c232013-01-29 10:33:22 -0800152
153 // The degrees of the device rotated clockwise from its natural orientation.
154 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
Michael Kolb8872c232013-01-29 10:33:22 -0800155
156 private static final String sTempCropFilename = "crop-temp";
157
Michael Kolb8872c232013-01-29 10:33:22 -0800158 private boolean mFaceDetectionStarted = false;
159
Michael Kolb8872c232013-01-29 10:33:22 -0800160 // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
161 private String mCropValue;
162 private Uri mSaveUri;
163
Ruben Brunkd217ed02013-10-08 23:31:13 -0700164 private Uri mDebugUri;
165
Angus Kongce5480e2013-01-29 17:43:48 -0800166 // We use a queue to generated names of the images to be used later
167 // when the image is ready to be saved.
Michael Kolb8872c232013-01-29 10:33:22 -0800168 private NamedImages mNamedImages;
169
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800170 private final Runnable mDoSnapRunnable = new Runnable() {
Michael Kolb8872c232013-01-29 10:33:22 -0800171 @Override
172 public void run() {
173 onShutterButtonClick();
174 }
175 };
176
Michael Kolb8872c232013-01-29 10:33:22 -0800177 /**
178 * An unpublished intent flag requesting to return as soon as capturing
179 * is completed.
180 *
181 * TODO: consider publishing by moving into MediaStore.
182 */
183 private static final String EXTRA_QUICK_CAPTURE =
184 "android.intent.extra.quickCapture";
185
186 // The display rotation in degrees. This is only valid when mCameraState is
187 // not PREVIEW_STOPPED.
188 private int mDisplayRotation;
189 // The value for android.hardware.Camera.setDisplayOrientation.
190 private int mCameraDisplayOrientation;
191 // The value for UI components like indicators.
192 private int mDisplayOrientation;
193 // The value for android.hardware.Camera.Parameters.setRotation.
194 private int mJpegRotation;
Doris Liu29da2db2013-08-28 14:28:45 -0700195 // Indicates whether we are using front camera
196 private boolean mMirror;
Michael Kolb8872c232013-01-29 10:33:22 -0800197 private boolean mFirstTimeInitialized;
198 private boolean mIsImageCaptureIntent;
199
Michael Kolb8872c232013-01-29 10:33:22 -0800200 private int mCameraState = PREVIEW_STOPPED;
201 private boolean mSnapshotOnIdle = false;
202
203 private ContentResolver mContentResolver;
204
205 private LocationManager mLocationManager;
206
Michael Kolb8872c232013-01-29 10:33:22 -0800207 private final PostViewPictureCallback mPostViewPictureCallback =
208 new PostViewPictureCallback();
209 private final RawPictureCallback mRawPictureCallback =
210 new RawPictureCallback();
211 private final AutoFocusCallback mAutoFocusCallback =
212 new AutoFocusCallback();
213 private final Object mAutoFocusMoveCallback =
214 ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700215 ? new AutoFocusMoveCallback()
216 : null;
Michael Kolb8872c232013-01-29 10:33:22 -0800217
218 private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
219
220 private long mFocusStartTime;
221 private long mShutterCallbackTime;
222 private long mPostViewPictureCallbackTime;
223 private long mRawPictureCallbackTime;
224 private long mJpegPictureCallbackTime;
225 private long mOnResumeTime;
226 private byte[] mJpegImageData;
227
228 // These latency time are for the CameraLatency test.
229 public long mAutoFocusTime;
230 public long mShutterLag;
231 public long mShutterToPictureDisplayedTime;
232 public long mPictureDisplayedToJpegCallbackTime;
233 public long mJpegCallbackFinishTime;
234 public long mCaptureStartTime;
235
236 // This handles everything about focus.
237 private FocusOverlayManager mFocusManager;
238
Michael Kolb8872c232013-01-29 10:33:22 -0800239 private String mSceneMode;
Michael Kolb8872c232013-01-29 10:33:22 -0800240
241 private final Handler mHandler = new MainHandler();
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800242
Michael Kolb8872c232013-01-29 10:33:22 -0800243 private boolean mQuickCapture;
Angus Kong0d00a892013-03-26 11:40:40 -0700244 private SensorManager mSensorManager;
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800245 private final float[] mGData = new float[3];
246 private final float[] mMData = new float[3];
247 private final float[] mR = new float[16];
Angus Kong0d00a892013-03-26 11:40:40 -0700248 private int mHeading = -1;
249
Angus Kongdcccc512013-08-08 17:06:03 -0700250 // True if all the parameters needed to start preview is ready.
251 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 */
286 private class MainHandler extends Handler {
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800287 public MainHandler() {
288 super(Looper.getMainLooper());
289 }
290
Michael Kolb8872c232013-01-29 10:33:22 -0800291 @Override
292 public void handleMessage(Message msg) {
293 switch (msg.what) {
Angus Kong13e87c42013-11-25 10:02:47 -0800294 case MSG_SETUP_PREVIEW: {
Michael Kolb8872c232013-01-29 10:33:22 -0800295 setupPreview();
296 break;
297 }
298
Angus Kong13e87c42013-11-25 10:02:47 -0800299 case MSG_FIRST_TIME_INIT: {
Michael Kolb8872c232013-01-29 10:33:22 -0800300 initializeFirstTime();
301 break;
302 }
303
Angus Kong13e87c42013-11-25 10:02:47 -0800304 case MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE: {
Michael Kolb8872c232013-01-29 10:33:22 -0800305 setCameraParametersWhenIdle(0);
306 break;
307 }
308
Angus Kong13e87c42013-11-25 10:02:47 -0800309 case MSG_SHOW_TAP_TO_FOCUS_TOAST: {
Michael Kolb8872c232013-01-29 10:33:22 -0800310 showTapToFocusToast();
311 break;
312 }
313
Angus Kong13e87c42013-11-25 10:02:47 -0800314 case MSG_SWITCH_CAMERA: {
Michael Kolb8872c232013-01-29 10:33:22 -0800315 switchCamera();
316 break;
317 }
318
Angus Kong13e87c42013-11-25 10:02:47 -0800319 case MSG_SWITCH_CAMERA_START_ANIMATION: {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700320 // TODO: Need to revisit
321 // ((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera();
Michael Kolb8872c232013-01-29 10:33:22 -0800322 break;
323 }
324
Angus Kong13e87c42013-11-25 10:02:47 -0800325 case MSG_CAMERA_OPEN_DONE: {
Michael Kolbd6954f32013-03-08 20:43:01 -0800326 onCameraOpened();
Michael Kolb8872c232013-01-29 10:33:22 -0800327 break;
328 }
329
Angus Kong13e87c42013-11-25 10:02:47 -0800330 case MSG_OPEN_CAMERA_FAIL: {
Michael Kolb8872c232013-01-29 10:33:22 -0800331 mOpenCameraFail = true;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700332 CameraUtil.showErrorAndFinish(mActivity,
Michael Kolb8872c232013-01-29 10:33:22 -0800333 R.string.cannot_connect_camera);
334 break;
335 }
336
Angus Kong13e87c42013-11-25 10:02:47 -0800337 case MSG_CAMERA_DISABLED: {
Michael Kolb8872c232013-01-29 10:33:22 -0800338 mCameraDisabled = true;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700339 CameraUtil.showErrorAndFinish(mActivity,
Michael Kolb8872c232013-01-29 10:33:22 -0800340 R.string.camera_disabled);
341 break;
342 }
ztenghui367c7c82013-10-16 14:43:26 -0700343
Angus Kong13e87c42013-11-25 10:02:47 -0800344 case MSG_SWITCH_TO_GCAM_MODULE: {
Erin Dahlgrend7b8cb52013-11-14 17:25:37 -0800345 mActivity.onModeSelected(ModeListView.MODE_GCAM);
ztenghui367c7c82013-10-16 14:43:26 -0700346 }
Michael Kolb8872c232013-01-29 10:33:22 -0800347 }
348 }
349 }
350
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800351 /**
352 * Constructs a new photo module.
353 */
Angus Kongc4e66562013-11-22 23:03:21 -0800354 public PhotoModule(AppController app) {
355 super(app);
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800356 }
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700357
Angus Kong13e87c42013-11-25 10:02:47 -0800358
Michael Kolb8872c232013-01-29 10:33:22 -0800359 @Override
Angus Kong13e87c42013-11-25 10:02:47 -0800360 public void init(AppController app, boolean isSecureCamera, boolean isCaptureIntent) {
361 mActivity = (CameraActivity) app.getAndroidContext();
362 mUI = new PhotoUI(mActivity, this, app.getModuleLayoutRoot());
Erin Dahlgren357b7672013-11-20 17:38:14 -0800363
364 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800365 mCameraId = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_CAMERA_ID));
Michael Kolb8872c232013-01-29 10:33:22 -0800366
367 mContentResolver = mActivity.getContentResolver();
368
Michael Kolb8872c232013-01-29 10:33:22 -0800369 // Surface texture is from camera screen nail and startPreview needs it.
370 // This must be done before startPreview.
371 mIsImageCaptureIntent = isImageCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800372
Angus Kong20fad242013-11-11 18:23:46 -0800373 mActivity.getCameraProvider().requestCamera(mCameraId);
374
Michael Kolb8872c232013-01-29 10:33:22 -0800375 initializeControlByIntent();
376 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800377 mLocationManager = mActivity.getLocationManager();
Angus Kong0d00a892013-03-26 11:40:40 -0700378 mSensorManager = (SensorManager)(mActivity.getSystemService(Context.SENSOR_SERVICE));
Michael Kolbd6954f32013-03-08 20:43:01 -0800379 }
380
381 private void initializeControlByIntent() {
382 mUI.initializeControlByIntent();
383 if (mIsImageCaptureIntent) {
384 setupCaptureParams();
385 }
386 }
387
388 private void onPreviewStarted() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800389 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800390 startFaceDetection();
Sameer Padala2c8cc452013-11-05 18:49:12 -0800391 startSmartCamera();
Michael Kolbd6954f32013-03-08 20:43:01 -0800392 locationFirstRun();
Michael Kolb8872c232013-01-29 10:33:22 -0800393 }
394
395 // Prompt the user to pick to record location for the very first run of
396 // camera only
397 private void locationFirstRun() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800398 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800399 if (settingsManager.isSet(SettingsManager.SETTING_RECORD_LOCATION)) {
Michael Kolb8872c232013-01-29 10:33:22 -0800400 return;
401 }
402 if (mActivity.isSecureCamera()) return;
403 // Check if the back camera exists
404 int backCameraId = CameraHolder.instance().getBackCameraId();
405 if (backCameraId == -1) {
406 // If there is no back camera, do not show the prompt.
407 return;
408 }
Doris Liu6a83d522013-07-02 12:03:32 -0700409 mUI.showLocationDialog();
410 }
Michael Kolb8872c232013-01-29 10:33:22 -0800411
ztenghui7b265a62013-09-09 14:58:44 -0700412 @Override
Angus Kongdcccc512013-08-08 17:06:03 -0700413 public void onPreviewUIReady() {
Erin Dahlgrendc282e12013-11-12 09:39:08 -0800414 startPreview();
Angus Kongdcccc512013-08-08 17:06:03 -0700415 }
416
417 @Override
418 public void onPreviewUIDestroyed() {
419 if (mCameraDevice == null) {
420 return;
421 }
422 mCameraDevice.setPreviewTexture(null);
423 stopPreview();
424 }
425
Michael Kolbd6954f32013-03-08 20:43:01 -0800426 private void onCameraOpened() {
427 View root = mUI.getRootView();
Michael Kolb8872c232013-01-29 10:33:22 -0800428 // These depend on camera parameters.
Michael Kolbd6954f32013-03-08 20:43:01 -0800429
430 int width = root.getWidth();
431 int height = root.getHeight();
Doris Liu6a0de792013-02-26 10:54:25 -0800432 mFocusManager.setPreviewSize(width, height);
Michael Kolbd6954f32013-03-08 20:43:01 -0800433 openCameraCommon();
Michael Kolb8872c232013-01-29 10:33:22 -0800434 }
435
Michael Kolbd6954f32013-03-08 20:43:01 -0800436 private void switchCamera() {
437 if (mPaused) return;
Erin Dahlgren357b7672013-11-20 17:38:14 -0800438 SettingsManager settingsManager = mActivity.getSettingsManager();
Michael Kolbd6954f32013-03-08 20:43:01 -0800439
440 Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
441 mCameraId = mPendingSwitchCameraId;
442 mPendingSwitchCameraId = -1;
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800443 settingsManager.set(SettingsManager.SETTING_CAMERA_ID, "" + mCameraId);
Angus Kong20fad242013-11-11 18:23:46 -0800444 mActivity.getCameraProvider().requestCamera(mCameraId);
Michael Kolbd6954f32013-03-08 20:43:01 -0800445
Michael Kolbd6954f32013-03-08 20:43:01 -0800446 mUI.collapseCameraControls();
447 mUI.clearFaces();
448 if (mFocusManager != null) mFocusManager.removeMessages();
449
Erin Dahlgren357b7672013-11-20 17:38:14 -0800450 // TODO: this needs to be brought into onCameraAvailable();
Angus Kong20fad242013-11-11 18:23:46 -0800451 CameraInfo info = mActivity.getCameraProvider().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -0700452 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
453 mFocusManager.setMirror(mMirror);
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700454 // Start switch camera animation. Post a message because
455 // onFrameAvailable from the old camera may already exist.
Angus Kong13e87c42013-11-25 10:02:47 -0800456 mHandler.sendEmptyMessage(MSG_SWITCH_CAMERA_START_ANIMATION);
Doris Liu48239f42013-03-04 22:19:10 -0800457 }
458
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800459 private ButtonManager.ButtonCallback mCameraButtonCallback =
460 new ButtonManager.ButtonCallback() {
461 @Override
462 public void onStateChanged(int state) {
463 if (mPaused || mPendingSwitchCameraId != -1) {
464 return;
465 }
466 mPendingSwitchCameraId = state;
467
468 Log.v(TAG, "Start to switch camera. cameraId=" + state);
469 // We need to keep a preview frame for the animation before
470 // releasing the camera. This will trigger onPreviewTextureCopied.
471 //TODO: Need to animate the camera switch
472 switchCamera();
473 }
474 };
475
476 private ButtonManager.ButtonCallback mHdrPlusButtonCallback =
477 new ButtonManager.ButtonCallback() {
478 @Override
479 public void onStateChanged(int state) {
480 mHandler.sendEmptyMessage(MSG_SWITCH_TO_GCAM_MODULE);
481 }
482 };
483
Michael Kolbd6954f32013-03-08 20:43:01 -0800484 // either open a new camera or switch cameras
485 private void openCameraCommon() {
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800486 mUI.onCameraOpened(mParameters, mCameraButtonCallback, mHdrPlusButtonCallback);
Angus Kong0fb819b2013-10-08 13:44:19 -0700487 if (mIsImageCaptureIntent) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800488 // Set hdr plus to default: off.
489 SettingsManager settingsManager = mActivity.getSettingsManager();
490 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_HDR_PLUS);
Angus Kong0fb819b2013-10-08 13:44:19 -0700491 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800492 updateSceneMode();
493 showTapToFocusToastIfNeeded();
Michael Kolb8872c232013-01-29 10:33:22 -0800494 }
495
ztenghui7b265a62013-09-09 14:58:44 -0700496 @Override
Doris Liu36ebcb12013-10-28 14:44:24 -0700497 public void onPreviewRectChanged(Rect previewRect) {
498 if (mFocusManager != null) mFocusManager.setPreviewRect(previewRect);
Michael Kolbd6954f32013-03-08 20:43:01 -0800499 }
Michael Kolb8872c232013-01-29 10:33:22 -0800500
501 private void resetExposureCompensation() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800502 SettingsManager settingsManager = mActivity.getSettingsManager();
503 if (settingsManager == null) {
504 Log.e(TAG, "Settings manager is null!");
505 return;
Michael Kolb8872c232013-01-29 10:33:22 -0800506 }
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800507 settingsManager.setDefault(SettingsManager.SETTING_EXPOSURE);
Michael Kolb8872c232013-01-29 10:33:22 -0800508 }
509
Michael Kolb8872c232013-01-29 10:33:22 -0800510 // Snapshots can only be taken after this is called. It should be called
511 // once only. We could have done these things in onCreate() but we want to
512 // make preview screen appear as soon as possible.
513 private void initializeFirstTime() {
Sascha Haeberling330dafb2013-10-10 19:00:41 -0700514 if (mFirstTimeInitialized || mPaused) {
515 return;
516 }
Michael Kolb8872c232013-01-29 10:33:22 -0800517
518 // Initialize location service.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800519 SettingsController settingsController = mActivity.getSettingsController();
520 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -0800521
Michael Kolbd6954f32013-03-08 20:43:01 -0800522 mUI.initializeFirstTime();
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800523 MediaSaver s = getServices().getMediaSaver();
Angus Kong86d36312013-01-31 18:22:44 -0800524 // We set the listener only when both service and shutterbutton
525 // are initialized.
526 if (s != null) {
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800527 s.setQueueListener(this);
Angus Kong86d36312013-01-31 18:22:44 -0800528 }
Michael Kolb8872c232013-01-29 10:33:22 -0800529
Michael Kolb8872c232013-01-29 10:33:22 -0800530 mNamedImages = new NamedImages();
531
532 mFirstTimeInitialized = true;
533 addIdleHandler();
534
535 mActivity.updateStorageSpaceAndHint();
536 }
537
Michael Kolbd6954f32013-03-08 20:43:01 -0800538 // If the activity is paused and resumed, this method will be called in
539 // onResume.
540 private void initializeSecondTime() {
541 // Start location update if needed.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800542 SettingsController settingsController = mActivity.getSettingsController();
543 settingsController.syncLocationManager();
544
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800545 MediaSaver s = getServices().getMediaSaver();
Michael Kolbd6954f32013-03-08 20:43:01 -0800546 if (s != null) {
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800547 s.setQueueListener(this);
Michael Kolbd6954f32013-03-08 20:43:01 -0800548 }
549 mNamedImages = new NamedImages();
550 mUI.initializeSecondTime(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -0800551 }
552
Michael Kolb8872c232013-01-29 10:33:22 -0800553 private void showTapToFocusToastIfNeeded() {
554 // Show the tap to focus toast if this is the first start.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800555 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800556 boolean showHint = settingsManager.getBoolean(
557 SettingsManager.SETTING_CAMERA_FIRST_USE_HINT_SHOWN);
Erin Dahlgren357b7672013-11-20 17:38:14 -0800558 // CONVERT THIS SETTING TO A STRING
559 if (mFocusAreaSupported && showHint) {
Michael Kolb8872c232013-01-29 10:33:22 -0800560 // Delay the toast for one second to wait for orientation.
Angus Kong13e87c42013-11-25 10:02:47 -0800561 mHandler.sendEmptyMessageDelayed(MSG_SHOW_TAP_TO_FOCUS_TOAST, 1000);
Michael Kolb8872c232013-01-29 10:33:22 -0800562 }
563 }
564
565 private void addIdleHandler() {
566 MessageQueue queue = Looper.myQueue();
567 queue.addIdleHandler(new MessageQueue.IdleHandler() {
568 @Override
569 public boolean queueIdle() {
570 Storage.ensureOSXCompatible();
571 return false;
572 }
573 });
574 }
575
Sameer Padala2c8cc452013-11-05 18:49:12 -0800576 private void startSmartCamera() {
577 SmartCameraHelper.register(mCameraDevice, mParameters.getPreviewSize(), mActivity,
Doris Liu773e1c92013-12-02 17:35:03 -0800578 (ViewGroup) mActivity.findViewById(R.id.camera_app_root));
Sameer Padala2c8cc452013-11-05 18:49:12 -0800579 }
580
581 private void stopSmartCamera() {
582 SmartCameraHelper.tearDown();
583 }
584
Michael Kolb8872c232013-01-29 10:33:22 -0800585 @Override
586 public void startFaceDetection() {
Michael Kolb8872c232013-01-29 10:33:22 -0800587 if (mFaceDetectionStarted) return;
588 if (mParameters.getMaxNumDetectedFaces() > 0) {
589 mFaceDetectionStarted = true;
Michael Kolb8872c232013-01-29 10:33:22 -0800590 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Michael Kolbd6954f32013-03-08 20:43:01 -0800591 mUI.onStartFaceDetection(mDisplayOrientation,
592 (info.facing == CameraInfo.CAMERA_FACING_FRONT));
Angus Kong9e765522013-07-31 14:05:20 -0700593 mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Michael Kolb8872c232013-01-29 10:33:22 -0800594 mCameraDevice.startFaceDetection();
595 }
596 }
597
Michael Kolb8872c232013-01-29 10:33:22 -0800598 @Override
599 public void stopFaceDetection() {
Michael Kolb8872c232013-01-29 10:33:22 -0800600 if (!mFaceDetectionStarted) return;
601 if (mParameters.getMaxNumDetectedFaces() > 0) {
602 mFaceDetectionStarted = false;
Angus Kong9e765522013-07-31 14:05:20 -0700603 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -0800604 mCameraDevice.stopFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800605 mUI.clearFaces();
Michael Kolb8872c232013-01-29 10:33:22 -0800606 }
607 }
608
Michael Kolb8872c232013-01-29 10:33:22 -0800609 private final class ShutterCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700610 implements CameraShutterCallback {
Angus Kongdcb0ef12013-03-25 23:11:43 -0700611
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800612 private final boolean mNeedsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700613
Sascha Haeberling37f36112013-08-06 14:31:52 -0700614 public ShutterCallback(boolean needsAnimation) {
615 mNeedsAnimation = needsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700616 }
617
Michael Kolb8872c232013-01-29 10:33:22 -0800618 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700619 public void onShutter(CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800620 mShutterCallbackTime = System.currentTimeMillis();
621 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
622 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Sascha Haeberling37f36112013-08-06 14:31:52 -0700623 if (mNeedsAnimation) {
624 mActivity.runOnUiThread(new Runnable() {
625 @Override
626 public void run() {
627 animateAfterShutter();
628 }
629 });
Angus Kongdcb0ef12013-03-25 23:11:43 -0700630 }
Michael Kolb8872c232013-01-29 10:33:22 -0800631 }
632 }
633
Angus Kong9ef99252013-07-18 18:04:19 -0700634 private final class PostViewPictureCallback
635 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800636 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700637 public void onPictureTaken(byte [] data, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800638 mPostViewPictureCallbackTime = System.currentTimeMillis();
639 Log.v(TAG, "mShutterToPostViewCallbackTime = "
640 + (mPostViewPictureCallbackTime - mShutterCallbackTime)
641 + "ms");
642 }
643 }
644
Angus Kong9ef99252013-07-18 18:04:19 -0700645 private final class RawPictureCallback
646 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800647 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700648 public void onPictureTaken(byte [] rawData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800649 mRawPictureCallbackTime = System.currentTimeMillis();
650 Log.v(TAG, "mShutterToRawCallbackTime = "
651 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
652 }
653 }
654
Angus Kong9ef99252013-07-18 18:04:19 -0700655 private final class JpegPictureCallback
656 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800657 Location mLocation;
658
659 public JpegPictureCallback(Location loc) {
660 mLocation = loc;
661 }
662
663 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700664 public void onPictureTaken(final byte [] jpegData, CameraProxy camera) {
Sascha Haeberling88901942013-08-28 17:49:00 -0700665 mUI.enableShutter(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800666 if (mPaused) {
667 return;
668 }
Doris Liu6432cd62013-06-13 17:20:31 -0700669 if (mIsImageCaptureIntent) {
670 stopPreview();
671 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700672 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -0700673 mUI.setSwipingEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800674 }
675
676 mJpegPictureCallbackTime = System.currentTimeMillis();
677 // If postview callback has arrived, the captured image is displayed
678 // in postview callback. If not, the captured image is displayed in
679 // raw picture callback.
680 if (mPostViewPictureCallbackTime != 0) {
681 mShutterToPictureDisplayedTime =
682 mPostViewPictureCallbackTime - mShutterCallbackTime;
683 mPictureDisplayedToJpegCallbackTime =
684 mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
685 } else {
686 mShutterToPictureDisplayedTime =
687 mRawPictureCallbackTime - mShutterCallbackTime;
688 mPictureDisplayedToJpegCallbackTime =
689 mJpegPictureCallbackTime - mRawPictureCallbackTime;
690 }
691 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
692 + mPictureDisplayedToJpegCallbackTime + "ms");
693
Michael Kolb8872c232013-01-29 10:33:22 -0800694 mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
695 if (!mIsImageCaptureIntent) {
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700696 setupPreview();
Michael Kolb8872c232013-01-29 10:33:22 -0800697 }
698
Doris Liu36e56fb2013-09-11 17:38:08 -0700699 ExifInterface exif = Exif.getExif(jpegData);
700 int orientation = Exif.getOrientation(exif);
Ruben Brunkd217ed02013-10-08 23:31:13 -0700701
Ruben Brunkd7488272013-10-10 18:45:53 -0700702 if (!mIsImageCaptureIntent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800703 // Calculate the width and the height of the jpeg.
704 Size s = mParameters.getPictureSize();
Michael Kolb8872c232013-01-29 10:33:22 -0800705 int width, height;
706 if ((mJpegRotation + orientation) % 180 == 0) {
707 width = s.width;
708 height = s.height;
709 } else {
710 width = s.height;
711 height = s.width;
712 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700713 NamedEntity name = mNamedImages.getNextNameEntity();
714 String title = (name == null) ? null : name.title;
715 long date = (name == null) ? -1 : name.date;
Ruben Brunkd7488272013-10-10 18:45:53 -0700716
717 // Handle debug mode outputs
718 if (mDebugUri != null) {
719 // If using a debug uri, save jpeg there.
720 saveToDebugUri(jpegData);
721
722 // Adjust the title of the debug image shown in mediastore.
723 if (title != null) {
724 title = DEBUG_IMAGE_PREFIX + title;
725 }
726 }
727
Michael Kolb8872c232013-01-29 10:33:22 -0800728 if (title == null) {
729 Log.e(TAG, "Unbalanced name/data pair");
730 } else {
731 if (date == -1) date = mCaptureStartTime;
Angus Kong0d00a892013-03-26 11:40:40 -0700732 if (mHeading >= 0) {
733 // heading direction has been updated by the sensor.
734 ExifTag directionRefTag = exif.buildTag(
735 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
736 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
737 ExifTag directionTag = exif.buildTag(
738 ExifInterface.TAG_GPS_IMG_DIRECTION,
739 new Rational(mHeading, 1));
740 exif.setTag(directionRefTag);
741 exif.setTag(directionTag);
742 }
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800743 getServices().getMediaSaver().addImage(
Angus Kong86d36312013-01-31 18:22:44 -0800744 jpegData, title, date, mLocation, width, height,
Angus Kong0d00a892013-03-26 11:40:40 -0700745 orientation, exif, mOnMediaSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -0800746 }
Doris Liuce2acbc2013-08-21 18:45:29 -0700747 // Animate capture with real jpeg data instead of a preview frame.
Doris Liu29da2db2013-08-28 14:28:45 -0700748 mUI.animateCapture(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800749 } else {
750 mJpegImageData = jpegData;
751 if (!mQuickCapture) {
Doris Liu36e56fb2013-09-11 17:38:08 -0700752 mUI.showCapturedImageForReview(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800753 } else {
Michael Kolbd6954f32013-03-08 20:43:01 -0800754 onCaptureDone();
Michael Kolb8872c232013-01-29 10:33:22 -0800755 }
756 }
757
758 // Check this in advance of each shot so we don't add to shutter
759 // latency. It's true that someone else could write to the SD card in
760 // the mean time and fill it, but that could have happened between the
761 // shutter press and saving the JPEG too.
762 mActivity.updateStorageSpaceAndHint();
763
764 long now = System.currentTimeMillis();
765 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
766 Log.v(TAG, "mJpegCallbackFinishTime = "
767 + mJpegCallbackFinishTime + "ms");
768 mJpegPictureCallbackTime = 0;
769 }
770 }
771
Angus Kong9ef99252013-07-18 18:04:19 -0700772 private final class AutoFocusCallback implements CameraAFCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800773 @Override
774 public void onAutoFocus(
Angus Kong9ef99252013-07-18 18:04:19 -0700775 boolean focused, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800776 if (mPaused) return;
777
778 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
779 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
780 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800781 mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
Michael Kolb8872c232013-01-29 10:33:22 -0800782 }
783 }
784
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700785 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -0800786 private final class AutoFocusMoveCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700787 implements CameraAFMoveCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800788 @Override
789 public void onAutoFocusMoving(
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700790 boolean moving, CameraProxy camera) {
791 mFocusManager.onAutoFocusMoving(moving);
Michael Kolb8872c232013-01-29 10:33:22 -0800792 }
793 }
794
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700795 /**
796 * This class is just a thread-safe queue for name,date holder objects.
797 */
798 public static class NamedImages {
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800799 private final Vector<NamedEntity> mQueue;
Michael Kolb8872c232013-01-29 10:33:22 -0800800
801 public NamedImages() {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700802 mQueue = new Vector<NamedEntity>();
Michael Kolb8872c232013-01-29 10:33:22 -0800803 }
804
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700805 public void nameNewImage(long date) {
Michael Kolb8872c232013-01-29 10:33:22 -0800806 NamedEntity r = new NamedEntity();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700807 r.title = CameraUtil.createJpegName(date);
Michael Kolb8872c232013-01-29 10:33:22 -0800808 r.date = date;
809 mQueue.add(r);
810 }
811
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700812 public NamedEntity getNextNameEntity() {
813 synchronized(mQueue) {
814 if (!mQueue.isEmpty()) {
815 return mQueue.remove(0);
816 }
Michael Kolb8872c232013-01-29 10:33:22 -0800817 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700818 return null;
Michael Kolb8872c232013-01-29 10:33:22 -0800819 }
820
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700821 public static class NamedEntity {
822 public String title;
823 public long date;
Michael Kolb8872c232013-01-29 10:33:22 -0800824 }
825 }
826
827 private void setCameraState(int state) {
828 mCameraState = state;
829 switch (state) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700830 case PhotoController.PREVIEW_STOPPED:
831 case PhotoController.SNAPSHOT_IN_PROGRESS:
832 case PhotoController.SWITCHING_CAMERA:
Doris Liuf55f3c42013-11-20 00:24:46 -0800833 // TODO: Tell app UI to disable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700834 break;
835 case PhotoController.IDLE:
Doris Liuf55f3c42013-11-20 00:24:46 -0800836 // TODO: Tell app UI to enable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700837 break;
Michael Kolb8872c232013-01-29 10:33:22 -0800838 }
839 }
840
Sascha Haeberling37f36112013-08-06 14:31:52 -0700841 private void animateAfterShutter() {
Michael Kolb8872c232013-01-29 10:33:22 -0800842 // Only animate when in full screen capture mode
843 // i.e. If monkey/a user swipes to the gallery during picture taking,
844 // don't show animation
Doris Liuc2e9abd2013-06-19 14:20:51 -0700845 if (!mIsImageCaptureIntent) {
846 mUI.animateFlash();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700847 }
Michael Kolb8872c232013-01-29 10:33:22 -0800848 }
849
850 @Override
851 public boolean capture() {
852 // If we are already in the middle of taking a snapshot or the image save request
853 // is full then ignore.
854 if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
Angus Kong86d36312013-01-31 18:22:44 -0800855 || mCameraState == SWITCHING_CAMERA
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800856 || getServices().getMediaSaver() == null
857 || getServices().getMediaSaver().isQueueFull()) {
Michael Kolb8872c232013-01-29 10:33:22 -0800858 return false;
859 }
860 mCaptureStartTime = System.currentTimeMillis();
861 mPostViewPictureCallbackTime = 0;
862 mJpegImageData = null;
863
Angus Kongb50b5cb2013-08-09 14:55:20 -0700864 final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
Michael Kolb8872c232013-01-29 10:33:22 -0800865
866 if (animateBefore) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700867 animateAfterShutter();
Michael Kolb8872c232013-01-29 10:33:22 -0800868 }
869
870 // Set rotation and gps data.
Doris Liu3cf565c2013-02-15 10:55:37 -0800871 int orientation;
872 // We need to be consistent with the framework orientation (i.e. the
873 // orientation of the UI.) when the auto-rotate screen setting is on.
874 if (mActivity.isAutoRotateScreen()) {
875 orientation = (360 - mDisplayRotation) % 360;
876 } else {
877 orientation = mOrientation;
878 }
Angus Kong20fad242013-11-11 18:23:46 -0800879 mJpegRotation = CameraUtil.getJpegRotation(mActivity, mCameraId, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800880 mParameters.setRotation(mJpegRotation);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800881 Location loc = mActivity.getLocationManager().getCurrentLocation();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700882 CameraUtil.setGpsParameters(mParameters, loc);
Michael Kolb8872c232013-01-29 10:33:22 -0800883 mCameraDevice.setParameters(mParameters);
884
Sascha Haeberling88901942013-08-28 17:49:00 -0700885 // We don't want user to press the button again while taking a
886 // multi-second HDR photo.
887 mUI.enableShutter(false);
Angus Kong9ef99252013-07-18 18:04:19 -0700888 mCameraDevice.takePicture(mHandler,
889 new ShutterCallback(!animateBefore),
Angus Kongdcb0ef12013-03-25 23:11:43 -0700890 mRawPictureCallback, mPostViewPictureCallback,
Angus Kong9ef99252013-07-18 18:04:19 -0700891 new JpegPictureCallback(loc));
Michael Kolb8872c232013-01-29 10:33:22 -0800892
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700893 mNamedImages.nameNewImage(mCaptureStartTime);
Michael Kolb8872c232013-01-29 10:33:22 -0800894
895 mFaceDetectionStarted = false;
896 setCameraState(SNAPSHOT_IN_PROGRESS);
Bobby Georgescu301b6462013-04-01 15:33:17 -0700897 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
Seth Raphaelcbd82672013-11-05 10:12:36 -0800898 UsageStatistics.ACTION_CAPTURE_DONE, "Photo", 0,
Seth Raphael44973262013-11-27 14:29:24 -0800899 UsageStatistics.hashFileName(mNamedImages.mQueue.lastElement().title + ".jpg"));
Michael Kolb8872c232013-01-29 10:33:22 -0800900 return true;
901 }
902
903 @Override
904 public void setFocusParameters() {
905 setCameraParameters(UPDATE_PARAM_PREFERENCE);
906 }
907
Michael Kolbd6954f32013-03-08 20:43:01 -0800908 private void updateSceneMode() {
Michael Kolb8872c232013-01-29 10:33:22 -0800909 // If scene mode is set, we cannot set flash mode, white balance, and
910 // focus mode, instead, we read it from driver
911 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
912 overrideCameraSettings(mParameters.getFlashMode(),
913 mParameters.getWhiteBalance(), mParameters.getFocusMode());
914 } else {
915 overrideCameraSettings(null, null, null);
916 }
917 }
918
919 private void overrideCameraSettings(final String flashMode,
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700920 final String whiteBalance, final String focusMode) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800921 SettingsManager settingsManager = mActivity.getSettingsManager();
922 settingsManager.set(SettingsManager.SETTING_FLASH_MODE, flashMode);
923 settingsManager.set(SettingsManager.SETTING_WHITE_BALANCE, whiteBalance);
924 settingsManager.set(SettingsManager.SETTING_FOCUS_MODE, focusMode);
Michael Kolb8872c232013-01-29 10:33:22 -0800925 }
926
927 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800928 public void onOrientationChanged(int orientation) {
929 // We keep the last known orientation. So if the user first orient
930 // the camera then point the camera to floor or sky, we still have
931 // the correct orientation.
932 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700933 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800934
935 // Show the toast after getting the first orientation changed.
Angus Kong13e87c42013-11-25 10:02:47 -0800936 if (mHandler.hasMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST)) {
937 mHandler.removeMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST);
Michael Kolb8872c232013-01-29 10:33:22 -0800938 showTapToFocusToast();
939 }
940 }
941
942 @Override
Angus Kong20fad242013-11-11 18:23:46 -0800943 public void onCameraAvailable(CameraProxy cameraProxy) {
944 if (mPaused) {
945 return;
946 }
947 mCameraDevice = cameraProxy;
948
Erin Dahlgren357b7672013-11-20 17:38:14 -0800949 resetExposureCompensation();
Angus Kong20fad242013-11-11 18:23:46 -0800950 initializeCapabilities();
951
952 // Reset zoom value index.
953 mZoomValue = 0;
954 if (mFocusManager == null) {
955 initializeFocusManager();
956 }
957 mFocusManager.setParameters(mInitialParams);
958
959 mParameters = mCameraDevice.getParameters();
960 setCameraParameters(UPDATE_PARAM_ALL);
961 mCameraPreviewParamsReady = true;
962 startPreview();
963
964 onCameraOpened();
965 }
966
967 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -0800968 public void onCaptureCancelled() {
969 mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
970 mActivity.finish();
Michael Kolb8872c232013-01-29 10:33:22 -0800971 }
972
Michael Kolbd6954f32013-03-08 20:43:01 -0800973 @Override
974 public void onCaptureRetake() {
Michael Kolb8872c232013-01-29 10:33:22 -0800975 if (mPaused)
976 return;
Michael Kolbd6954f32013-03-08 20:43:01 -0800977 mUI.hidePostCaptureAlert();
Michael Kolb8872c232013-01-29 10:33:22 -0800978 setupPreview();
979 }
980
Michael Kolbd6954f32013-03-08 20:43:01 -0800981 @Override
982 public void onCaptureDone() {
Michael Kolb8872c232013-01-29 10:33:22 -0800983 if (mPaused) {
984 return;
985 }
986
987 byte[] data = mJpegImageData;
988
989 if (mCropValue == null) {
990 // First handle the no crop case -- just return the value. If the
991 // caller specifies a "save uri" then write the data to its
992 // stream. Otherwise, pass back a scaled down version of the bitmap
993 // directly in the extras.
994 if (mSaveUri != null) {
995 OutputStream outputStream = null;
996 try {
997 outputStream = mContentResolver.openOutputStream(mSaveUri);
998 outputStream.write(data);
999 outputStream.close();
1000
1001 mActivity.setResultEx(Activity.RESULT_OK);
1002 mActivity.finish();
1003 } catch (IOException ex) {
1004 // ignore exception
1005 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001006 CameraUtil.closeSilently(outputStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001007 }
1008 } else {
Angus Kong0d00a892013-03-26 11:40:40 -07001009 ExifInterface exif = Exif.getExif(data);
1010 int orientation = Exif.getOrientation(exif);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001011 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
1012 bitmap = CameraUtil.rotate(bitmap, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001013 mActivity.setResultEx(Activity.RESULT_OK,
1014 new Intent("inline-data").putExtra("data", bitmap));
1015 mActivity.finish();
1016 }
1017 } else {
1018 // Save the image to a temp file and invoke the cropper
1019 Uri tempUri = null;
1020 FileOutputStream tempStream = null;
1021 try {
1022 File path = mActivity.getFileStreamPath(sTempCropFilename);
1023 path.delete();
1024 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1025 tempStream.write(data);
1026 tempStream.close();
1027 tempUri = Uri.fromFile(path);
1028 } catch (FileNotFoundException ex) {
1029 mActivity.setResultEx(Activity.RESULT_CANCELED);
1030 mActivity.finish();
1031 return;
1032 } catch (IOException ex) {
1033 mActivity.setResultEx(Activity.RESULT_CANCELED);
1034 mActivity.finish();
1035 return;
1036 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001037 CameraUtil.closeSilently(tempStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001038 }
1039
1040 Bundle newExtras = new Bundle();
1041 if (mCropValue.equals("circle")) {
1042 newExtras.putString("circleCrop", "true");
1043 }
1044 if (mSaveUri != null) {
1045 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1046 } else {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001047 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001048 }
1049 if (mActivity.isSecureCamera()) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001050 newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001051 }
1052
Sascha Haeberling37f36112013-08-06 14:31:52 -07001053 // TODO: Share this constant.
Sascha Haeberling8e963a52013-08-06 11:43:02 -07001054 final String CROP_ACTION = "com.android.camera.action.CROP";
1055 Intent cropIntent = new Intent(CROP_ACTION);
Michael Kolb8872c232013-01-29 10:33:22 -08001056
1057 cropIntent.setData(tempUri);
1058 cropIntent.putExtras(newExtras);
1059
1060 mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1061 }
1062 }
1063
Michael Kolb8872c232013-01-29 10:33:22 -08001064 @Override
1065 public void onShutterButtonFocus(boolean pressed) {
Michael Kolbd6954f32013-03-08 20:43:01 -08001066 if (mPaused || mUI.collapseCameraControls()
Michael Kolb8872c232013-01-29 10:33:22 -08001067 || (mCameraState == SNAPSHOT_IN_PROGRESS)
1068 || (mCameraState == PREVIEW_STOPPED)) return;
1069
1070 // Do not do focus if there is not enough storage.
1071 if (pressed && !canTakePicture()) return;
1072
1073 if (pressed) {
Michael Kolb8872c232013-01-29 10:33:22 -08001074 mFocusManager.onShutterDown();
1075 } else {
Doris Liuda50e052013-02-07 14:36:32 -08001076 // for countdown mode, we need to postpone the shutter release
1077 // i.e. lock the focus during countdown.
Michael Kolbd6954f32013-03-08 20:43:01 -08001078 if (!mUI.isCountingDown()) {
Doris Liuda50e052013-02-07 14:36:32 -08001079 mFocusManager.onShutterUp();
1080 }
Michael Kolb8872c232013-01-29 10:33:22 -08001081 }
1082 }
1083
1084 @Override
1085 public void onShutterButtonClick() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001086 if (mPaused || mUI.collapseCameraControls()
Michael Kolb8872c232013-01-29 10:33:22 -08001087 || (mCameraState == SWITCHING_CAMERA)
1088 || (mCameraState == PREVIEW_STOPPED)) return;
1089
1090 // Do not take the picture if there is not enough storage.
Angus Kong2dcc0a92013-09-25 13:00:08 -07001091 if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Michael Kolb8872c232013-01-29 10:33:22 -08001092 Log.i(TAG, "Not enough space or storage not ready. remaining="
Angus Kong2dcc0a92013-09-25 13:00:08 -07001093 + mActivity.getStorageSpaceBytes());
Michael Kolb8872c232013-01-29 10:33:22 -08001094 return;
1095 }
1096 Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1097
Angus Kongb50b5cb2013-08-09 14:55:20 -07001098 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -07001099 mUI.setSwipingEnabled(false);
Doris Liu9cdfe002013-04-16 09:50:56 -07001100 }
Michael Kolb8872c232013-01-29 10:33:22 -08001101 // If the user wants to do a snapshot while the previous one is still
1102 // in progress, remember the fact and do it after we finish the previous
1103 // one and re-start the preview. Snapshot in progress also includes the
1104 // state that autofocus is focusing and a picture will be taken when
1105 // focus callback arrives.
1106 if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1107 && !mIsImageCaptureIntent) {
1108 mSnapshotOnIdle = true;
1109 return;
1110 }
1111
Erin Dahlgren357b7672013-11-20 17:38:14 -08001112 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001113 String timer = settingsManager.get(SettingsManager.SETTING_TIMER);
1114 String playSound = settingsManager.get(SettingsManager.SETTING_TIMER_SOUND_EFFECTS);
Michael Kolb8872c232013-01-29 10:33:22 -08001115 int seconds = Integer.parseInt(timer);
1116 // When shutter button is pressed, check whether the previous countdown is
1117 // finished. If not, cancel the previous countdown and start a new one.
Michael Kolbd6954f32013-03-08 20:43:01 -08001118 if (mUI.isCountingDown()) {
1119 mUI.cancelCountDown();
1120 }
1121 if (seconds > 0) {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001122 mUI.startCountDown(seconds, playSound.equals(SettingsManager.VALUE_ON));
Michael Kolb8872c232013-01-29 10:33:22 -08001123 } else {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001124 mSnapshotOnIdle = false;
1125 mFocusManager.doSnap();
Michael Kolb8872c232013-01-29 10:33:22 -08001126 }
1127 }
1128
Andy Huibersdef975d2013-11-22 09:13:39 -08001129 private void onResumeTasks() {
1130 Log.v(TAG, "Executing onResumeTasks.");
Michael Kolb8872c232013-01-29 10:33:22 -08001131 if (mOpenCameraFail || mCameraDisabled) return;
1132
Angus Kong20fad242013-11-11 18:23:46 -08001133 mActivity.getCameraProvider().requestCamera(mCameraId);
1134
Michael Kolb8872c232013-01-29 10:33:22 -08001135 mJpegPictureCallbackTime = 0;
1136 mZoomValue = 0;
Angus Kong20fad242013-11-11 18:23:46 -08001137
1138 mOnResumeTime = SystemClock.uptimeMillis();
1139 checkDisplayRotation();
Michael Kolb8872c232013-01-29 10:33:22 -08001140
1141 // If first time initialization is not finished, put it in the
1142 // message queue.
1143 if (!mFirstTimeInitialized) {
Angus Kong13e87c42013-11-25 10:02:47 -08001144 mHandler.sendEmptyMessage(MSG_FIRST_TIME_INIT);
Michael Kolb8872c232013-01-29 10:33:22 -08001145 } else {
1146 initializeSecondTime();
1147 }
Michael Kolb8872c232013-01-29 10:33:22 -08001148
Bobby Georgescu0a7dd572013-03-12 22:45:17 -07001149 UsageStatistics.onContentViewChanged(
1150 UsageStatistics.COMPONENT_CAMERA, "PhotoModule");
Angus Kong0d00a892013-03-26 11:40:40 -07001151
1152 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1153 if (gsensor != null) {
1154 mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1155 }
1156
1157 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1158 if (msensor != null) {
1159 mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1160 }
Michael Kolb8872c232013-01-29 10:33:22 -08001161 }
1162
Angus Kongc4e66562013-11-22 23:03:21 -08001163 /**
1164 * The focus manager is the first UI related element to get initialized,
1165 * and it requires the RenderOverlay, so initialize it here
1166 */
1167 private void initializeFocusManager() {
1168 // Create FocusManager object. startPreview needs it.
1169 // if mFocusManager not null, reuse it
1170 // otherwise create a new instance
1171 if (mFocusManager != null) {
1172 mFocusManager.removeMessages();
1173 } else {
1174 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
1175 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
1176 String[] defaultFocusModes = mActivity.getResources().getStringArray(
1177 R.array.pref_camera_focusmode_default_array);
Erin Dahlgren357b7672013-11-20 17:38:14 -08001178 mFocusManager = new FocusOverlayManager(mActivity.getSettingsManager(),
1179 defaultFocusModes,
Angus Kongc4e66562013-11-22 23:03:21 -08001180 mInitialParams, this, mMirror,
1181 mActivity.getMainLooper(), mUI);
1182 }
Angus Kong20fad242013-11-11 18:23:46 -08001183 }
1184
1185 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001186 public void resume() {
1187 mPaused = false;
1188 // Add delay on resume from lock screen only, in order to to speed up
1189 // the onResume --> onPause --> onResume cycle from lock screen.
1190 // Don't do always because letting go of thread can cause delay.
1191 String action = mActivity.getIntent().getAction();
1192 if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
1193 || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
1194 Log.v(TAG, "On resume, from lock screen.");
1195 // Note: onPauseAfterSuper() will delete this runnable, so we will
1196 // at most have 1 copy queued up.
1197 mHandler.postDelayed(new Runnable() {
Sameer Padala2c8cc452013-11-05 18:49:12 -08001198 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001199 public void run() {
1200 onResumeTasks();
1201 }
1202 }, ON_RESUME_TASKS_DELAY_MSEC);
1203 } else {
1204 Log.v(TAG, "On resume.");
1205 onResumeTasks();
1206 }
1207 }
1208
1209 @Override
1210 public void pause() {
Michael Kolb8872c232013-01-29 10:33:22 -08001211 mPaused = true;
Angus Kong0d00a892013-03-26 11:40:40 -07001212 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1213 if (gsensor != null) {
1214 mSensorManager.unregisterListener(this, gsensor);
1215 }
1216
1217 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1218 if (msensor != null) {
1219 mSensorManager.unregisterListener(this, msensor);
1220 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001221
Michael Kolb8872c232013-01-29 10:33:22 -08001222 // Reset the focus first. Camera CTS does not guarantee that
1223 // cancelAutoFocus is allowed after preview stops.
1224 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1225 mCameraDevice.cancelAutoFocus();
1226 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001227
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -08001228 // If the camera has not been opened asynchronously yet,
1229 // and startPreview hasn't been called, then this is a no-op.
1230 // (e.g. onResume -> onPause -> onResume).
Michael Kolb8872c232013-01-29 10:33:22 -08001231 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001232
Angus Kongce5480e2013-01-29 17:43:48 -08001233 mNamedImages = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001234
1235 if (mLocationManager != null) mLocationManager.recordLocation(false);
1236
1237 // If we are in an image capture intent and has taken
1238 // a picture, we just clear it in onPause.
1239 mJpegImageData = null;
1240
Angus Kongdcccc512013-08-08 17:06:03 -07001241 // Remove the messages and runnables in the queue.
1242 mHandler.removeCallbacksAndMessages(null);
Michael Kolb8872c232013-01-29 10:33:22 -08001243
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001244 closeCamera();
Angus Kong13e87c42013-11-25 10:02:47 -08001245 mActivity.enableKeepScreenOn(false);
Michael Kolbd6954f32013-03-08 20:43:01 -08001246 mUI.onPause();
1247
Michael Kolb8872c232013-01-29 10:33:22 -08001248 mPendingSwitchCameraId = -1;
1249 if (mFocusManager != null) mFocusManager.removeMessages();
Sascha Haeberling280fd3e2013-11-21 13:52:15 -08001250 MediaSaver s = getServices().getMediaSaver();
Angus Kong86d36312013-01-31 18:22:44 -08001251 if (s != null) {
Angus Kongfd4fc0e2013-11-07 15:38:09 -08001252 s.setQueueListener(null);
Angus Kong86d36312013-01-31 18:22:44 -08001253 }
Michael Kolb8872c232013-01-29 10:33:22 -08001254 }
1255
Angus Kong20fad242013-11-11 18:23:46 -08001256 @Override
1257 public void destroy() {
1258 // TODO: implement this.
1259 }
1260
1261 @Override
1262 public void onPreviewSizeChanged(int width, int height) {
1263 // TODO: implement this.
1264 }
1265
1266 @Override
Angus Kong2f0e4a32013-12-03 10:02:35 -08001267 public void onLayoutOrientationChanged(boolean isLandscape) {
Michael Kolb8872c232013-01-29 10:33:22 -08001268 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001269 }
1270
1271 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001272 public void updateCameraOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001273 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001274 setDisplayOrientation();
1275 }
1276 }
1277
Michael Kolb8872c232013-01-29 10:33:22 -08001278 private boolean canTakePicture() {
Angus Kong2dcc0a92013-09-25 13:00:08 -07001279 return isCameraIdle() && (mActivity.getStorageSpaceBytes() > Storage.LOW_STORAGE_THRESHOLD_BYTES);
Michael Kolb8872c232013-01-29 10:33:22 -08001280 }
1281
1282 @Override
1283 public void autoFocus() {
1284 mFocusStartTime = System.currentTimeMillis();
Angus Kong9ef99252013-07-18 18:04:19 -07001285 mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001286 setCameraState(FOCUSING);
1287 }
1288
1289 @Override
1290 public void cancelAutoFocus() {
1291 mCameraDevice.cancelAutoFocus();
1292 setCameraState(IDLE);
1293 setCameraParameters(UPDATE_PARAM_PREFERENCE);
1294 }
1295
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001296 // Preview area is touched.
Michael Kolb8872c232013-01-29 10:33:22 -08001297 @Override
1298 public void onSingleTapUp(View view, int x, int y) {
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001299 if (mUI.isImmediateCapture()) {
1300 cancelAutoFocus();
1301 onShutterButtonClick();
1302 } else {
1303 onShutterButtonFocus(true);
1304 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001305 }
Michael Kolb8872c232013-01-29 10:33:22 -08001306 }
1307
1308 @Override
1309 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001310 return mUI.onBackPressed();
Michael Kolb8872c232013-01-29 10:33:22 -08001311 }
1312
1313 @Override
1314 public boolean onKeyDown(int keyCode, KeyEvent event) {
1315 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001316 case KeyEvent.KEYCODE_VOLUME_UP:
1317 case KeyEvent.KEYCODE_VOLUME_DOWN:
1318 case KeyEvent.KEYCODE_FOCUS:
1319 if (/*TODO: mActivity.isInCameraApp() &&*/ mFirstTimeInitialized) {
1320 if (event.getRepeatCount() == 0) {
1321 onShutterButtonFocus(true);
1322 }
1323 return true;
1324 }
1325 return false;
1326 case KeyEvent.KEYCODE_CAMERA:
1327 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1328 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001329 }
1330 return true;
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001331 case KeyEvent.KEYCODE_DPAD_CENTER:
1332 // If we get a dpad center event without any focused view, move
1333 // the focus to the shutter button and press it.
1334 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1335 // Start auto-focus immediately to reduce shutter lag. After
1336 // the shutter button gets the focus, onShutterButtonFocus()
1337 // will be called again but it is fine.
1338 onShutterButtonFocus(true);
1339 mUI.pressShutterButton();
1340 }
1341 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001342 }
1343 return false;
1344 }
1345
1346 @Override
1347 public boolean onKeyUp(int keyCode, KeyEvent event) {
1348 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001349 case KeyEvent.KEYCODE_VOLUME_UP:
1350 case KeyEvent.KEYCODE_VOLUME_DOWN:
1351 if (/*mActivity.isInCameraApp() && */ mFirstTimeInitialized) {
1352 onShutterButtonClick();
1353 return true;
1354 }
1355 return false;
1356 case KeyEvent.KEYCODE_FOCUS:
1357 if (mFirstTimeInitialized) {
1358 onShutterButtonFocus(false);
1359 }
Michael Kolb8872c232013-01-29 10:33:22 -08001360 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001361 }
1362 return false;
1363 }
1364
Michael Kolb8872c232013-01-29 10:33:22 -08001365 private void closeCamera() {
1366 if (mCameraDevice != null) {
1367 mCameraDevice.setZoomChangeListener(null);
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001368 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001369 mCameraDevice.setErrorCallback(null);
Ruben Brunk59147832013-11-05 15:53:28 -08001370
Michael Kolb8872c232013-01-29 10:33:22 -08001371 mFaceDetectionStarted = false;
Angus Kong20fad242013-11-11 18:23:46 -08001372 mActivity.getCameraProvider().releaseCamera(mCameraDevice.getCameraId());
Michael Kolb8872c232013-01-29 10:33:22 -08001373 mCameraDevice = null;
1374 setCameraState(PREVIEW_STOPPED);
1375 mFocusManager.onCameraReleased();
1376 }
1377 }
1378
1379 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001380 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1381 mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001382 mCameraDisplayOrientation = mDisplayOrientation;
Michael Kolbd6954f32013-03-08 20:43:01 -08001383 mUI.setDisplayOrientation(mDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001384 if (mFocusManager != null) {
1385 mFocusManager.setDisplayOrientation(mDisplayOrientation);
1386 }
Doris Liu6432cd62013-06-13 17:20:31 -07001387 // Change the camera display orientation
1388 if (mCameraDevice != null) {
1389 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1390 }
Michael Kolb8872c232013-01-29 10:33:22 -08001391 }
1392
Sascha Haeberlingddef7792013-08-13 14:41:10 -07001393 /** Only called by UI thread. */
Michael Kolb8872c232013-01-29 10:33:22 -08001394 private void setupPreview() {
1395 mFocusManager.resetTouchFocus();
1396 startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001397 }
1398
Angus Kong20fad242013-11-11 18:23:46 -08001399 /**
1400 * Returns whether we can/should start the preview or not.
1401 */
1402 private boolean checkPreviewPreconditions() {
1403 if (mPaused) {
1404 return false;
Angus Kongdcccc512013-08-08 17:06:03 -07001405 }
Michael Kolb8872c232013-01-29 10:33:22 -08001406
Angus Kong20fad242013-11-11 18:23:46 -08001407 if (mCameraDevice == null) {
1408 Log.w(TAG, "startPreview: camera device not ready yet.");
1409 return false;
1410 }
1411
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001412 SurfaceTexture st = mUI.getSurfaceTexture();
1413 if (st == null) {
1414 Log.w(TAG, "startPreview: surfaceTexture is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001415 return false;
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001416 }
1417
1418 if (!mCameraPreviewParamsReady) {
1419 Log.w(TAG, "startPreview: parameters for preview is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001420 return false;
1421 }
1422 return true;
1423 }
1424
1425 /**
1426 * The start/stop preview should only run on the UI thread.
1427 */
1428 private void startPreview() {
1429 if (!checkPreviewPreconditions()) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001430 return;
1431 }
Angus Kong20fad242013-11-11 18:23:46 -08001432
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001433 mCameraDevice.setErrorCallback(mErrorCallback);
1434 // ICS camera frameworks has a bug. Face detection state is not cleared 1589
1435 // after taking a picture. Stop the preview to work around it. The bug
1436 // was fixed in JB.
1437 if (mCameraState != PREVIEW_STOPPED) {
1438 stopPreview();
1439 }
1440
1441 setDisplayOrientation();
1442
1443 if (!mSnapshotOnIdle) {
1444 // If the focus mode is continuous autofocus, call cancelAutoFocus to
1445 // resume it because it may have been paused by autoFocus call.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001446 String focusMode = mFocusManager.getFocusMode();
1447 if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(focusMode)) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001448 mCameraDevice.cancelAutoFocus();
Michael Kolb8872c232013-01-29 10:33:22 -08001449 }
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001450 mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1451 }
1452 setCameraParameters(UPDATE_PARAM_ALL);
1453 // Let UI set its expected aspect ratio
Angus Kong20fad242013-11-11 18:23:46 -08001454 mCameraDevice.setPreviewTexture(mUI.getSurfaceTexture());
Michael Kolb8872c232013-01-29 10:33:22 -08001455
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001456 Log.v(TAG, "startPreview");
1457 mCameraDevice.startPreview();
Angus Kong20fad242013-11-11 18:23:46 -08001458
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001459 mFocusManager.onPreviewStarted();
1460 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001461
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001462 if (mSnapshotOnIdle) {
1463 mHandler.post(mDoSnapRunnable);
Michael Kolb8872c232013-01-29 10:33:22 -08001464 }
1465 }
1466
Michael Kolbd6954f32013-03-08 20:43:01 -08001467 @Override
1468 public void stopPreview() {
Michael Kolb8872c232013-01-29 10:33:22 -08001469 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1470 Log.v(TAG, "stopPreview");
1471 mCameraDevice.stopPreview();
1472 mFaceDetectionStarted = false;
1473 }
1474 setCameraState(PREVIEW_STOPPED);
1475 if (mFocusManager != null) mFocusManager.onPreviewStopped();
Sameer Padala2c8cc452013-11-05 18:49:12 -08001476 stopSmartCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001477 }
1478
1479 @SuppressWarnings("deprecation")
1480 private void updateCameraParametersInitialize() {
1481 // Reset preview frame rate to the maximum because it may be lowered by
1482 // video camera application.
ztenghui16a35202013-09-23 11:35:36 -07001483 int[] fpsRange = CameraUtil.getPhotoPreviewFpsRange(mParameters);
1484 if (fpsRange != null && fpsRange.length > 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001485 mParameters.setPreviewFpsRange(
1486 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1487 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
Michael Kolb8872c232013-01-29 10:33:22 -08001488 }
1489
Angus Kongb50b5cb2013-08-09 14:55:20 -07001490 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);
Michael Kolb8872c232013-01-29 10:33:22 -08001491
1492 // Disable video stabilization. Convenience methods not available in API
1493 // level <= 14
1494 String vstabSupported = mParameters.get("video-stabilization-supported");
1495 if ("true".equals(vstabSupported)) {
1496 mParameters.set("video-stabilization", "false");
1497 }
1498 }
1499
1500 private void updateCameraParametersZoom() {
1501 // Set zoom.
1502 if (mParameters.isZoomSupported()) {
1503 mParameters.setZoom(mZoomValue);
1504 }
1505 }
1506
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001507 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001508 private void setAutoExposureLockIfSupported() {
1509 if (mAeLockSupported) {
1510 mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1511 }
1512 }
1513
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001514 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001515 private void setAutoWhiteBalanceLockIfSupported() {
1516 if (mAwbLockSupported) {
1517 mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1518 }
1519 }
1520
Michael Kolb8872c232013-01-29 10:33:22 -08001521 private void setFocusAreasIfSupported() {
1522 if (mFocusAreaSupported) {
1523 mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1524 }
1525 }
1526
Michael Kolb8872c232013-01-29 10:33:22 -08001527 private void setMeteringAreasIfSupported() {
1528 if (mMeteringAreaSupported) {
Michael Kolb8872c232013-01-29 10:33:22 -08001529 mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1530 }
1531 }
1532
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001533 private boolean updateCameraParametersPreference() {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001534 SettingsManager settingsManager = mActivity.getSettingsManager();
1535
Michael Kolb8872c232013-01-29 10:33:22 -08001536 setAutoExposureLockIfSupported();
1537 setAutoWhiteBalanceLockIfSupported();
1538 setFocusAreasIfSupported();
1539 setMeteringAreasIfSupported();
1540
Michael Kolbd3253f22013-07-12 11:36:47 -07001541 // initialize focus mode
1542 mFocusManager.overrideFocusMode(null);
1543 mParameters.setFocusMode(mFocusManager.getFocusMode());
1544
Michael Kolb8872c232013-01-29 10:33:22 -08001545 // Set picture size.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001546 String pictureSize = settingsManager.get(SettingsManager.SETTING_PICTURE_SIZE);
Michael Kolb8872c232013-01-29 10:33:22 -08001547 if (pictureSize == null) {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001548 //TODO: deprecate CameraSettings.
1549 CameraSettings.initialCameraPictureSize(
1550 mActivity, mParameters, settingsManager);
Michael Kolb8872c232013-01-29 10:33:22 -08001551 } else {
1552 List<Size> supported = mParameters.getSupportedPictureSizes();
1553 CameraSettings.setCameraPictureSize(
1554 pictureSize, supported, mParameters);
1555 }
1556 Size size = mParameters.getPictureSize();
1557
1558 // Set a preview size that is closest to the viewfinder height and has
1559 // the right aspect ratio.
1560 List<Size> sizes = mParameters.getSupportedPreviewSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001561 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
Michael Kolb8872c232013-01-29 10:33:22 -08001562 (double) size.width / size.height);
1563 Size original = mParameters.getPreviewSize();
1564 if (!original.equals(optimalSize)) {
1565 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
Doris Liu6432cd62013-06-13 17:20:31 -07001566
Michael Kolb8872c232013-01-29 10:33:22 -08001567 // Zoom related settings will be changed for different preview
1568 // sizes, so set and read the parameters to get latest values
Michael Kolb4a4d4ef2013-05-30 08:35:26 -07001569 if (mHandler.getLooper() == Looper.myLooper()) {
1570 // On UI thread only, not when camera starts up
1571 setupPreview();
1572 } else {
1573 mCameraDevice.setParameters(mParameters);
1574 }
Michael Kolb8872c232013-01-29 10:33:22 -08001575 mParameters = mCameraDevice.getParameters();
1576 }
Doris Liu95405742013-11-05 15:25:26 -08001577
1578 if(optimalSize.width != 0 && optimalSize.height != 0) {
1579 mUI.updatePreviewAspectRatio((float) optimalSize.width
1580 / (float) optimalSize.height);
1581 }
Michael Kolb8872c232013-01-29 10:33:22 -08001582 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
1583
1584 // Since changing scene mode may change supported values, set scene mode
1585 // first. HDR is a scene mode. To promote it in UI, it is stored in a
1586 // separate preference.
Sascha Haeberling98f38bb2013-09-24 18:58:34 -07001587 String onValue = mActivity.getString(R.string.setting_on_value);
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001588 String hdr = settingsManager.get(SettingsManager.SETTING_CAMERA_HDR);
1589 String hdrPlus = settingsManager.get(SettingsManager.SETTING_CAMERA_HDR_PLUS);
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001590 boolean hdrOn = onValue.equals(hdr);
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001591 boolean hdrPlusOn = onValue.equals(hdrPlus);
Sascha Haeberling98f38bb2013-09-24 18:58:34 -07001592
1593 boolean doGcamModeSwitch = false;
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001594 if (hdrPlusOn && GcamHelper.hasGcamCapture()) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001595 // Kick off mode switch to gcam.
1596 doGcamModeSwitch = true;
Michael Kolb8872c232013-01-29 10:33:22 -08001597 } else {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001598 if (hdrOn) {
1599 mSceneMode = CameraUtil.SCENE_MODE_HDR;
1600 } else {
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001601 mSceneMode = settingsManager.get(SettingsManager.SETTING_SCENE_MODE);
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001602 }
Michael Kolb8872c232013-01-29 10:33:22 -08001603 }
Angus Kongb50b5cb2013-08-09 14:55:20 -07001604 if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
Michael Kolb8872c232013-01-29 10:33:22 -08001605 if (!mParameters.getSceneMode().equals(mSceneMode)) {
1606 mParameters.setSceneMode(mSceneMode);
1607
1608 // Setting scene mode will change the settings of flash mode,
1609 // white balance, and focus mode. Here we read back the
1610 // parameters, so we can know those settings.
1611 mCameraDevice.setParameters(mParameters);
1612 mParameters = mCameraDevice.getParameters();
1613 }
1614 } else {
1615 mSceneMode = mParameters.getSceneMode();
1616 if (mSceneMode == null) {
1617 mSceneMode = Parameters.SCENE_MODE_AUTO;
1618 }
1619 }
1620
1621 // Set JPEG quality.
1622 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1623 CameraProfile.QUALITY_HIGH);
1624 mParameters.setJpegQuality(jpegQuality);
1625
1626 // For the following settings, we need to check if the settings are
1627 // still supported by latest driver, if not, ignore the settings.
1628
1629 // Set exposure compensation
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001630 int value = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_EXPOSURE));
Michael Kolb8872c232013-01-29 10:33:22 -08001631 int max = mParameters.getMaxExposureCompensation();
1632 int min = mParameters.getMinExposureCompensation();
1633 if (value >= min && value <= max) {
1634 mParameters.setExposureCompensation(value);
1635 } else {
1636 Log.w(TAG, "invalid exposure range: " + value);
1637 }
1638
1639 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1640 // Set flash mode.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001641 String flashMode = settingsManager.get(SettingsManager.SETTING_FLASH_MODE);
Michael Kolb8872c232013-01-29 10:33:22 -08001642 List<String> supportedFlash = mParameters.getSupportedFlashModes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001643 if (CameraUtil.isSupported(flashMode, supportedFlash)) {
Michael Kolb8872c232013-01-29 10:33:22 -08001644 mParameters.setFlashMode(flashMode);
1645 } else {
1646 flashMode = mParameters.getFlashMode();
1647 if (flashMode == null) {
1648 flashMode = mActivity.getString(
1649 R.string.pref_camera_flashmode_no_flash);
1650 }
1651 }
1652
1653 // Set white balance parameter.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001654 String whiteBalance = settingsManager.get(SettingsManager.SETTING_WHITE_BALANCE);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001655 if (CameraUtil.isSupported(whiteBalance,
Michael Kolb8872c232013-01-29 10:33:22 -08001656 mParameters.getSupportedWhiteBalance())) {
1657 mParameters.setWhiteBalance(whiteBalance);
1658 } else {
1659 whiteBalance = mParameters.getWhiteBalance();
1660 if (whiteBalance == null) {
1661 whiteBalance = Parameters.WHITE_BALANCE_AUTO;
1662 }
1663 }
1664
1665 // Set focus mode.
1666 mFocusManager.overrideFocusMode(null);
1667 mParameters.setFocusMode(mFocusManager.getFocusMode());
1668 } else {
1669 mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1670 }
1671
Angus Kongdcccc512013-08-08 17:06:03 -07001672 if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
Michael Kolb8872c232013-01-29 10:33:22 -08001673 updateAutoFocusMoveCallback();
1674 }
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001675
1676 return doGcamModeSwitch;
Michael Kolb8872c232013-01-29 10:33:22 -08001677 }
1678
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001679 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001680 private void updateAutoFocusMoveCallback() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001681 if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Angus Kong9ef99252013-07-18 18:04:19 -07001682 mCameraDevice.setAutoFocusMoveCallback(mHandler,
Angus Kong4f795b82013-09-16 14:25:35 -07001683 (CameraAFMoveCallback) mAutoFocusMoveCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001684 } else {
Angus Kong9ef99252013-07-18 18:04:19 -07001685 mCameraDevice.setAutoFocusMoveCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001686 }
1687 }
1688
1689 // We separate the parameters into several subsets, so we can update only
1690 // the subsets actually need updating. The PREFERENCE set needs extra
1691 // locking because the preference can be changed from GLThread as well.
1692 private void setCameraParameters(int updateSet) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001693 boolean doModeSwitch = false;
1694
Michael Kolb8872c232013-01-29 10:33:22 -08001695 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1696 updateCameraParametersInitialize();
1697 }
1698
1699 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1700 updateCameraParametersZoom();
1701 }
1702
1703 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001704 doModeSwitch = updateCameraParametersPreference();
Michael Kolb8872c232013-01-29 10:33:22 -08001705 }
1706
1707 mCameraDevice.setParameters(mParameters);
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001708
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001709 // Switch to gcam module if HDR+ was selected
Angus Kong0fb819b2013-10-08 13:44:19 -07001710 if (doModeSwitch && !mIsImageCaptureIntent) {
Angus Kong13e87c42013-11-25 10:02:47 -08001711 mHandler.sendEmptyMessage(MSG_SWITCH_TO_GCAM_MODULE);
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001712 }
Michael Kolb8872c232013-01-29 10:33:22 -08001713 }
1714
1715 // If the Camera is idle, update the parameters immediately, otherwise
1716 // accumulate them in mUpdateSet and update later.
1717 private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1718 mUpdateSet |= additionalUpdateSet;
1719 if (mCameraDevice == null) {
1720 // We will update all the parameters when we open the device, so
1721 // we don't need to do anything now.
1722 mUpdateSet = 0;
1723 return;
1724 } else if (isCameraIdle()) {
1725 setCameraParameters(mUpdateSet);
Michael Kolbd6954f32013-03-08 20:43:01 -08001726 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001727 mUpdateSet = 0;
1728 } else {
Angus Kong13e87c42013-11-25 10:02:47 -08001729 if (!mHandler.hasMessages(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1730 mHandler.sendEmptyMessageDelayed(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
Michael Kolb8872c232013-01-29 10:33:22 -08001731 }
1732 }
1733 }
1734
ztenghui7b265a62013-09-09 14:58:44 -07001735 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001736 public boolean isCameraIdle() {
Michael Kolb8872c232013-01-29 10:33:22 -08001737 return (mCameraState == IDLE) ||
1738 (mCameraState == PREVIEW_STOPPED) ||
1739 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
1740 && (mCameraState != SWITCHING_CAMERA));
1741 }
1742
ztenghui7b265a62013-09-09 14:58:44 -07001743 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001744 public boolean isImageCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001745 String action = mActivity.getIntent().getAction();
1746 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
Angus Kong6a8e8a12013-07-19 14:55:07 -07001747 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
Michael Kolb8872c232013-01-29 10:33:22 -08001748 }
1749
1750 private void setupCaptureParams() {
1751 Bundle myExtras = mActivity.getIntent().getExtras();
1752 if (myExtras != null) {
1753 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1754 mCropValue = myExtras.getString("crop");
1755 }
1756 }
1757
Michael Kolb8872c232013-01-29 10:33:22 -08001758 public void onSharedPreferenceChanged() {
1759 // ignore the events after "onPause()"
1760 if (mPaused) return;
1761
Erin Dahlgren357b7672013-11-20 17:38:14 -08001762 SettingsController settingsController = mActivity.getSettingsController();
1763 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001764
1765 setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
Michael Kolb8872c232013-01-29 10:33:22 -08001766 }
1767
Michael Kolb8872c232013-01-29 10:33:22 -08001768 private void showTapToFocusToast() {
1769 // TODO: Use a toast?
1770 new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
1771 // Clear the preference.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001772 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001773 settingsManager.setBoolean(
1774 SettingsManager.SETTING_CAMERA_FIRST_USE_HINT_SHOWN, false);
Michael Kolb8872c232013-01-29 10:33:22 -08001775 }
1776
1777 private void initializeCapabilities() {
1778 mInitialParams = mCameraDevice.getParameters();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001779 mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
1780 mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
1781 mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
1782 mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
Angus Kongdcccc512013-08-08 17:06:03 -07001783 mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001784 CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
Michael Kolb8872c232013-01-29 10:33:22 -08001785 }
1786
Michael Kolb8872c232013-01-29 10:33:22 -08001787 @Override
1788 public void onCountDownFinished() {
1789 mSnapshotOnIdle = false;
1790 mFocusManager.doSnap();
Doris Liuda50e052013-02-07 14:36:32 -08001791 mFocusManager.onShutterUp();
Michael Kolb8872c232013-01-29 10:33:22 -08001792 }
1793
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001794 // TODO: Remove this
Michael Kolb8872c232013-01-29 10:33:22 -08001795 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001796 public int onZoomChanged(int index) {
1797 // Not useful to change zoom value when the activity is paused.
1798 if (mPaused) return index;
1799 mZoomValue = index;
1800 if (mParameters == null || mCameraDevice == null) return index;
1801 // Set zoom parameters asynchronously
1802 mParameters.setZoom(mZoomValue);
Angus Kong36ed8672013-04-15 12:11:15 -07001803 mCameraDevice.setParameters(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -08001804 Parameters p = mCameraDevice.getParameters();
1805 if (p != null) return p.getZoom();
1806 return index;
Angus Kongce5480e2013-01-29 17:43:48 -08001807 }
1808
1809 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001810 public int getCameraState() {
1811 return mCameraState;
1812 }
1813
1814 @Override
1815 public void onQueueStatus(boolean full) {
1816 mUI.enableShutter(!full);
Angus Kongce5480e2013-01-29 17:43:48 -08001817 }
Angus Kong86d36312013-01-31 18:22:44 -08001818
1819 @Override
Angus Kongfd4fc0e2013-11-07 15:38:09 -08001820 public void onMediaSaverAvailable(MediaSaver s) {
Angus Kong86d36312013-01-31 18:22:44 -08001821 // We set the listener only when both service and shutterbutton
1822 // are initialized.
Michael Kolbd6954f32013-03-08 20:43:01 -08001823 if (mFirstTimeInitialized) {
Angus Kongfd4fc0e2013-11-07 15:38:09 -08001824 s.setQueueListener(this);
Michael Kolbd6954f32013-03-08 20:43:01 -08001825 }
Angus Kong86d36312013-01-31 18:22:44 -08001826 }
Angus Kong0d00a892013-03-26 11:40:40 -07001827
1828 @Override
1829 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1830 }
1831
1832 @Override
1833 public void onSensorChanged(SensorEvent event) {
1834 int type = event.sensor.getType();
1835 float[] data;
1836 if (type == Sensor.TYPE_ACCELEROMETER) {
1837 data = mGData;
1838 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
1839 data = mMData;
1840 } else {
1841 // we should not be here.
1842 return;
1843 }
1844 for (int i = 0; i < 3 ; i++) {
1845 data[i] = event.values[i];
1846 }
1847 float[] orientation = new float[3];
1848 SensorManager.getRotationMatrix(mR, null, mGData, mMData);
1849 SensorManager.getOrientation(mR, orientation);
1850 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
1851 if (mHeading < 0) {
1852 mHeading += 360;
1853 }
Angus Kong0d00a892013-03-26 11:40:40 -07001854 }
Doris Liu6432cd62013-06-13 17:20:31 -07001855
1856 @Override
ztenghui7b265a62013-09-09 14:58:44 -07001857 public void onPreviewFocusChanged(boolean previewFocused) {
1858 mUI.onPreviewFocusChanged(previewFocused);
Doris Liu6432cd62013-06-13 17:20:31 -07001859 }
1860
Erin Dahlgren3044d8c2013-10-10 18:23:45 -07001861 @Override
1862 public boolean arePreviewControlsVisible() {
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001863 return false;
Erin Dahlgren3044d8c2013-10-10 18:23:45 -07001864 }
1865
Ruben Brunkd217ed02013-10-08 23:31:13 -07001866 // For debugging only.
1867 public void setDebugUri(Uri uri) {
1868 mDebugUri = uri;
1869 }
1870
1871 // For debugging only.
1872 private void saveToDebugUri(byte[] data) {
1873 if (mDebugUri != null) {
1874 OutputStream outputStream = null;
1875 try {
1876 outputStream = mContentResolver.openOutputStream(mDebugUri);
1877 outputStream.write(data);
1878 outputStream.close();
1879 } catch (IOException e) {
1880 Log.e(TAG, "Exception while writing debug jpeg file", e);
1881 } finally {
1882 CameraUtil.closeSilently(outputStream);
1883 }
1884 }
1885 }
Michael Kolb8872c232013-01-29 10:33:22 -08001886}