blob: 4b610f54fd2450ab7325632316320355402c69a1 [file] [log] [blame]
Michael Kolb8872c232013-01-29 10:33:22 -08001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera;
18
19import android.annotation.TargetApi;
20import android.app.Activity;
Michael Kolb8872c232013-01-29 10:33:22 -080021import android.content.ContentResolver;
Angus Kong0d00a892013-03-26 11:40:40 -070022import android.content.Context;
Michael Kolb8872c232013-01-29 10:33:22 -080023import android.content.Intent;
Michael Kolb8872c232013-01-29 10:33:22 -080024import android.graphics.Bitmap;
Doris Liu36ebcb12013-10-28 14:44:24 -070025import android.graphics.Rect;
Michael Kolb8872c232013-01-29 10:33:22 -080026import android.graphics.SurfaceTexture;
27import android.hardware.Camera.CameraInfo;
Michael Kolb8872c232013-01-29 10:33:22 -080028import android.hardware.Camera.Parameters;
Michael Kolb8872c232013-01-29 10:33:22 -080029import android.hardware.Camera.Size;
Angus Kong0d00a892013-03-26 11:40:40 -070030import android.hardware.Sensor;
31import android.hardware.SensorEvent;
32import android.hardware.SensorEventListener;
33import android.hardware.SensorManager;
Michael Kolb8872c232013-01-29 10:33:22 -080034import android.location.Location;
35import android.media.CameraProfile;
36import android.net.Uri;
Sascha Haeberling638e6f02013-09-18 14:28:51 -070037import android.os.Build;
Michael Kolb8872c232013-01-29 10:33:22 -080038import android.os.Bundle;
Michael Kolb8872c232013-01-29 10:33:22 -080039import android.os.Handler;
40import android.os.Looper;
41import android.os.Message;
42import android.os.MessageQueue;
43import android.os.SystemClock;
44import android.provider.MediaStore;
45import android.util.Log;
Michael Kolb8872c232013-01-29 10:33:22 -080046import android.view.KeyEvent;
Michael Kolb8872c232013-01-29 10:33:22 -080047import android.view.OrientationEventListener;
Michael Kolb8872c232013-01-29 10:33:22 -080048import android.view.View;
Doris Liu773e1c92013-12-02 17:35:03 -080049import android.view.ViewGroup;
Michael Kolb8872c232013-01-29 10:33:22 -080050
Sameer Padala2c8cc452013-11-05 18:49:12 -080051import com.android.camera.PhotoModule.NamedImages.NamedEntity;
52import com.android.camera.app.AppController;
Angus Kong20fad242013-11-11 18:23:46 -080053import com.android.camera.app.CameraManager.CameraAFCallback;
54import com.android.camera.app.CameraManager.CameraAFMoveCallback;
55import com.android.camera.app.CameraManager.CameraPictureCallback;
56import com.android.camera.app.CameraManager.CameraProxy;
57import com.android.camera.app.CameraManager.CameraShutterCallback;
Marco Nelissen0744e4a2013-11-22 01:47:37 +000058import com.android.camera.app.AppController;
Angus Kongfd4fc0e2013-11-07 15:38:09 -080059import com.android.camera.app.MediaSaver;
ztenghuia16e7b52013-08-23 11:47:56 -070060import com.android.camera.exif.ExifInterface;
61import com.android.camera.exif.ExifTag;
62import com.android.camera.exif.Rational;
Angus Kong20fad242013-11-11 18:23:46 -080063import com.android.camera.module.ModuleController;
Erin Dahlgren357b7672013-11-20 17:38:14 -080064import com.android.camera.settings.SettingsManager;
Doris Liu1c94b7d2013-11-09 19:13:44 -080065import com.android.camera.ui.ModeListView;
Michael Kolb8872c232013-01-29 10:33:22 -080066import com.android.camera.ui.RotateTextToast;
Angus Kongdcccc512013-08-08 17:06:03 -070067import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -070068import com.android.camera.util.CameraUtil;
Ruben Brunk4601f5d2013-09-24 18:35:22 -070069import com.android.camera.util.GcamHelper;
Sameer Padala2c8cc452013-11-05 18:49:12 -080070import com.android.camera.util.SmartCameraHelper;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070071import com.android.camera.util.UsageStatistics;
72import com.android.camera2.R;
Michael Kolb8872c232013-01-29 10:33:22 -080073
Angus Kongdcccc512013-08-08 17:06:03 -070074import java.io.File;
75import java.io.FileNotFoundException;
76import java.io.FileOutputStream;
77import java.io.IOException;
78import java.io.OutputStream;
Angus Kongdcccc512013-08-08 17:06:03 -070079import java.util.List;
Ruben Brunka9d66bd2013-09-06 11:56:32 -070080import java.util.Vector;
Angus Kongdcccc512013-08-08 17:06:03 -070081
Michael Kolb8872c232013-01-29 10:33:22 -080082public class PhotoModule
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080083 extends CameraModule
84 implements PhotoController,
85 ModuleController,
86 FocusOverlayManager.Listener,
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080087 ShutterButton.OnShutterButtonListener, MediaSaver.QueueListener,
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080088 SensorEventListener {
Michael Kolb8872c232013-01-29 10:33:22 -080089
90 private static final String TAG = "CAM_PhotoModule";
91
92 // We number the request code from 1000 to avoid collision with Gallery.
93 private static final int REQUEST_CROP = 1000;
94
Angus Kong13e87c42013-11-25 10:02:47 -080095 // Messages defined for the UI thread handler.
96 private static final int MSG_SETUP_PREVIEW = 1;
97 private static final int MSG_FIRST_TIME_INIT = 2;
98 private static final int MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE = 3;
99 private static final int MSG_SHOW_TAP_TO_FOCUS_TOAST = 4;
100 private static final int MSG_SWITCH_CAMERA = 5;
101 private static final int MSG_SWITCH_CAMERA_START_ANIMATION = 6;
102 private static final int MSG_CAMERA_OPEN_DONE = 7;
103 private static final int MSG_OPEN_CAMERA_FAIL = 8;
104 private static final int MSG_CAMERA_DISABLED = 9;
105 private static final int MSG_SWITCH_TO_GCAM_MODULE = 10;
Michael Kolb8872c232013-01-29 10:33:22 -0800106
107 // The subset of parameters we need to update in setCameraParameters().
108 private static final int UPDATE_PARAM_INITIALIZE = 1;
109 private static final int UPDATE_PARAM_ZOOM = 2;
110 private static final int UPDATE_PARAM_PREFERENCE = 4;
111 private static final int UPDATE_PARAM_ALL = -1;
112
Andy Huibersdef975d2013-11-22 09:13:39 -0800113 // This is the delay before we execute onResume tasks when coming
114 // from the lock screen, to allow time for onPause to execute.
115 private static final int ON_RESUME_TASKS_DELAY_MSEC = 20;
Michael Kolb8872c232013-01-29 10:33:22 -0800116
Ruben Brunkd7488272013-10-10 18:45:53 -0700117 private static final String DEBUG_IMAGE_PREFIX = "DEBUG_";
118
Michael Kolb8872c232013-01-29 10:33:22 -0800119 // copied from Camera hierarchy
120 private CameraActivity mActivity;
Michael Kolb8872c232013-01-29 10:33:22 -0800121 private CameraProxy mCameraDevice;
122 private int mCameraId;
123 private Parameters mParameters;
124 private boolean mPaused;
Michael Kolbd6954f32013-03-08 20:43:01 -0800125
126 private PhotoUI mUI;
Michael Kolb8872c232013-01-29 10:33:22 -0800127
Michael Kolb8872c232013-01-29 10:33:22 -0800128 // The activity is going to switch to the specified camera id. This is
129 // needed because texture copy is done in GL thread. -1 means camera is not
130 // switching.
131 protected int mPendingSwitchCameraId = -1;
132 private boolean mOpenCameraFail;
133 private boolean mCameraDisabled;
134
135 // When setCameraParametersWhenIdle() is called, we accumulate the subsets
136 // needed to be updated in mUpdateSet.
137 private int mUpdateSet;
138
139 private static final int SCREEN_DELAY = 2 * 60 * 1000;
140
141 private int mZoomValue; // The current zoom value.
Michael Kolb8872c232013-01-29 10:33:22 -0800142
143 private Parameters mInitialParams;
144 private boolean mFocusAreaSupported;
145 private boolean mMeteringAreaSupported;
146 private boolean mAeLockSupported;
147 private boolean mAwbLockSupported;
Angus Kongdcccc512013-08-08 17:06:03 -0700148 private boolean mContinuousFocusSupported;
Michael Kolb8872c232013-01-29 10:33:22 -0800149
150 // The degrees of the device rotated clockwise from its natural orientation.
151 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
Michael Kolb8872c232013-01-29 10:33:22 -0800152
153 private static final String sTempCropFilename = "crop-temp";
154
Michael Kolb8872c232013-01-29 10:33:22 -0800155 private boolean mFaceDetectionStarted = false;
156
Michael Kolb8872c232013-01-29 10:33:22 -0800157 // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
158 private String mCropValue;
159 private Uri mSaveUri;
160
Ruben Brunkd217ed02013-10-08 23:31:13 -0700161 private Uri mDebugUri;
162
Angus Kongce5480e2013-01-29 17:43:48 -0800163 // We use a queue to generated names of the images to be used later
164 // when the image is ready to be saved.
Michael Kolb8872c232013-01-29 10:33:22 -0800165 private NamedImages mNamedImages;
166
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800167 private final Runnable mDoSnapRunnable = new Runnable() {
Michael Kolb8872c232013-01-29 10:33:22 -0800168 @Override
169 public void run() {
170 onShutterButtonClick();
171 }
172 };
173
Michael Kolb8872c232013-01-29 10:33:22 -0800174 /**
175 * An unpublished intent flag requesting to return as soon as capturing
176 * is completed.
177 *
178 * TODO: consider publishing by moving into MediaStore.
179 */
180 private static final String EXTRA_QUICK_CAPTURE =
181 "android.intent.extra.quickCapture";
182
183 // The display rotation in degrees. This is only valid when mCameraState is
184 // not PREVIEW_STOPPED.
185 private int mDisplayRotation;
186 // The value for android.hardware.Camera.setDisplayOrientation.
187 private int mCameraDisplayOrientation;
188 // The value for UI components like indicators.
189 private int mDisplayOrientation;
190 // The value for android.hardware.Camera.Parameters.setRotation.
191 private int mJpegRotation;
Doris Liu29da2db2013-08-28 14:28:45 -0700192 // Indicates whether we are using front camera
193 private boolean mMirror;
Michael Kolb8872c232013-01-29 10:33:22 -0800194 private boolean mFirstTimeInitialized;
195 private boolean mIsImageCaptureIntent;
196
Michael Kolb8872c232013-01-29 10:33:22 -0800197 private int mCameraState = PREVIEW_STOPPED;
198 private boolean mSnapshotOnIdle = false;
199
200 private ContentResolver mContentResolver;
201
202 private LocationManager mLocationManager;
203
Michael Kolb8872c232013-01-29 10:33:22 -0800204 private final PostViewPictureCallback mPostViewPictureCallback =
205 new PostViewPictureCallback();
206 private final RawPictureCallback mRawPictureCallback =
207 new RawPictureCallback();
208 private final AutoFocusCallback mAutoFocusCallback =
209 new AutoFocusCallback();
210 private final Object mAutoFocusMoveCallback =
211 ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700212 ? new AutoFocusMoveCallback()
213 : null;
Michael Kolb8872c232013-01-29 10:33:22 -0800214
215 private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
216
217 private long mFocusStartTime;
218 private long mShutterCallbackTime;
219 private long mPostViewPictureCallbackTime;
220 private long mRawPictureCallbackTime;
221 private long mJpegPictureCallbackTime;
222 private long mOnResumeTime;
223 private byte[] mJpegImageData;
224
225 // These latency time are for the CameraLatency test.
226 public long mAutoFocusTime;
227 public long mShutterLag;
228 public long mShutterToPictureDisplayedTime;
229 public long mPictureDisplayedToJpegCallbackTime;
230 public long mJpegCallbackFinishTime;
231 public long mCaptureStartTime;
232
233 // This handles everything about focus.
234 private FocusOverlayManager mFocusManager;
235
Michael Kolb8872c232013-01-29 10:33:22 -0800236 private String mSceneMode;
Michael Kolb8872c232013-01-29 10:33:22 -0800237
238 private final Handler mHandler = new MainHandler();
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
Angus Kongdcccc512013-08-08 17:06:03 -0700247 // True if all the parameters needed to start preview is ready.
248 private boolean mCameraPreviewParamsReady = false;
Doris Liu6432cd62013-06-13 17:20:31 -0700249
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800250 private final MediaSaver.OnMediaSavedListener mOnMediaSavedListener =
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800251 new MediaSaver.OnMediaSavedListener() {
Angus Kongce5480e2013-01-29 17:43:48 -0800252 @Override
253 public void onMediaSaved(Uri uri) {
254 if (uri != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700255 mActivity.notifyNewMedia(uri);
Angus Kongce5480e2013-01-29 17:43:48 -0800256 }
257 }
258 };
Michael Kolb8872c232013-01-29 10:33:22 -0800259
Angus Kongdcccc512013-08-08 17:06:03 -0700260 private void checkDisplayRotation() {
261 // Set the display orientation if display rotation has changed.
262 // Sometimes this happens when the device is held upside
263 // down and camera app is opened. Rotation animation will
264 // take some time and the rotation value we have got may be
265 // wrong. Framework does not have a callback for this now.
266 if (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) {
267 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -0800268 }
Angus Kongdcccc512013-08-08 17:06:03 -0700269 if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
270 mHandler.postDelayed(new Runnable() {
271 @Override
272 public void run() {
273 checkDisplayRotation();
274 }
275 }, 100);
Michael Kolb8872c232013-01-29 10:33:22 -0800276 }
277 }
278
279 /**
280 * This Handler is used to post message back onto the main thread of the
281 * application
282 */
283 private class MainHandler extends Handler {
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800284 public MainHandler() {
285 super(Looper.getMainLooper());
286 }
287
Michael Kolb8872c232013-01-29 10:33:22 -0800288 @Override
289 public void handleMessage(Message msg) {
290 switch (msg.what) {
Angus Kong13e87c42013-11-25 10:02:47 -0800291 case MSG_SETUP_PREVIEW: {
Michael Kolb8872c232013-01-29 10:33:22 -0800292 setupPreview();
293 break;
294 }
295
Angus Kong13e87c42013-11-25 10:02:47 -0800296 case MSG_FIRST_TIME_INIT: {
Michael Kolb8872c232013-01-29 10:33:22 -0800297 initializeFirstTime();
298 break;
299 }
300
Angus Kong13e87c42013-11-25 10:02:47 -0800301 case MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE: {
Michael Kolb8872c232013-01-29 10:33:22 -0800302 setCameraParametersWhenIdle(0);
303 break;
304 }
305
Angus Kong13e87c42013-11-25 10:02:47 -0800306 case MSG_SHOW_TAP_TO_FOCUS_TOAST: {
Michael Kolb8872c232013-01-29 10:33:22 -0800307 showTapToFocusToast();
308 break;
309 }
310
Angus Kong13e87c42013-11-25 10:02:47 -0800311 case MSG_SWITCH_CAMERA: {
Michael Kolb8872c232013-01-29 10:33:22 -0800312 switchCamera();
313 break;
314 }
315
Angus Kong13e87c42013-11-25 10:02:47 -0800316 case MSG_SWITCH_CAMERA_START_ANIMATION: {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700317 // TODO: Need to revisit
318 // ((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera();
Michael Kolb8872c232013-01-29 10:33:22 -0800319 break;
320 }
321
Angus Kong13e87c42013-11-25 10:02:47 -0800322 case MSG_CAMERA_OPEN_DONE: {
Michael Kolbd6954f32013-03-08 20:43:01 -0800323 onCameraOpened();
Michael Kolb8872c232013-01-29 10:33:22 -0800324 break;
325 }
326
Angus Kong13e87c42013-11-25 10:02:47 -0800327 case MSG_OPEN_CAMERA_FAIL: {
Michael Kolb8872c232013-01-29 10:33:22 -0800328 mOpenCameraFail = true;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700329 CameraUtil.showErrorAndFinish(mActivity,
Michael Kolb8872c232013-01-29 10:33:22 -0800330 R.string.cannot_connect_camera);
331 break;
332 }
333
Angus Kong13e87c42013-11-25 10:02:47 -0800334 case MSG_CAMERA_DISABLED: {
Michael Kolb8872c232013-01-29 10:33:22 -0800335 mCameraDisabled = true;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700336 CameraUtil.showErrorAndFinish(mActivity,
Michael Kolb8872c232013-01-29 10:33:22 -0800337 R.string.camera_disabled);
338 break;
339 }
ztenghui367c7c82013-10-16 14:43:26 -0700340
Angus Kong13e87c42013-11-25 10:02:47 -0800341 case MSG_SWITCH_TO_GCAM_MODULE: {
Erin Dahlgrend7b8cb52013-11-14 17:25:37 -0800342 mActivity.onModeSelected(ModeListView.MODE_GCAM);
ztenghui367c7c82013-10-16 14:43:26 -0700343 }
Michael Kolb8872c232013-01-29 10:33:22 -0800344 }
345 }
346 }
347
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800348 /**
349 * Constructs a new photo module.
350 */
Angus Kongc4e66562013-11-22 23:03:21 -0800351 public PhotoModule(AppController app) {
352 super(app);
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800353 }
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700354
Angus Kong13e87c42013-11-25 10:02:47 -0800355
Michael Kolb8872c232013-01-29 10:33:22 -0800356 @Override
Angus Kong13e87c42013-11-25 10:02:47 -0800357 public void init(AppController app, boolean isSecureCamera, boolean isCaptureIntent) {
358 mActivity = (CameraActivity) app.getAndroidContext();
359 mUI = new PhotoUI(mActivity, this, app.getModuleLayoutRoot());
Erin Dahlgren357b7672013-11-20 17:38:14 -0800360
361 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800362 mCameraId = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_CAMERA_ID));
Michael Kolb8872c232013-01-29 10:33:22 -0800363
364 mContentResolver = mActivity.getContentResolver();
365
Michael Kolb8872c232013-01-29 10:33:22 -0800366 // Surface texture is from camera screen nail and startPreview needs it.
367 // This must be done before startPreview.
368 mIsImageCaptureIntent = isImageCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800369
Angus Kong20fad242013-11-11 18:23:46 -0800370 mActivity.getCameraProvider().requestCamera(mCameraId);
371
Michael Kolb8872c232013-01-29 10:33:22 -0800372 initializeControlByIntent();
373 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800374 mLocationManager = mActivity.getLocationManager();
Angus Kong0d00a892013-03-26 11:40:40 -0700375 mSensorManager = (SensorManager)(mActivity.getSystemService(Context.SENSOR_SERVICE));
Michael Kolbd6954f32013-03-08 20:43:01 -0800376 }
377
378 private void initializeControlByIntent() {
379 mUI.initializeControlByIntent();
380 if (mIsImageCaptureIntent) {
381 setupCaptureParams();
382 }
383 }
384
385 private void onPreviewStarted() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800386 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800387 startFaceDetection();
Sameer Padala2c8cc452013-11-05 18:49:12 -0800388 startSmartCamera();
Michael Kolbd6954f32013-03-08 20:43:01 -0800389 locationFirstRun();
Michael Kolb8872c232013-01-29 10:33:22 -0800390 }
391
392 // Prompt the user to pick to record location for the very first run of
393 // camera only
394 private void locationFirstRun() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800395 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800396 if (settingsManager.isSet(SettingsManager.SETTING_RECORD_LOCATION)) {
Michael Kolb8872c232013-01-29 10:33:22 -0800397 return;
398 }
399 if (mActivity.isSecureCamera()) return;
400 // Check if the back camera exists
401 int backCameraId = CameraHolder.instance().getBackCameraId();
402 if (backCameraId == -1) {
403 // If there is no back camera, do not show the prompt.
404 return;
405 }
Doris Liu6a83d522013-07-02 12:03:32 -0700406 mUI.showLocationDialog();
407 }
Michael Kolb8872c232013-01-29 10:33:22 -0800408
ztenghui7b265a62013-09-09 14:58:44 -0700409 @Override
Angus Kongdcccc512013-08-08 17:06:03 -0700410 public void onPreviewUIReady() {
Erin Dahlgrendc282e12013-11-12 09:39:08 -0800411 startPreview();
Angus Kongdcccc512013-08-08 17:06:03 -0700412 }
413
414 @Override
415 public void onPreviewUIDestroyed() {
416 if (mCameraDevice == null) {
417 return;
418 }
419 mCameraDevice.setPreviewTexture(null);
420 stopPreview();
421 }
422
Michael Kolbd6954f32013-03-08 20:43:01 -0800423 private void onCameraOpened() {
424 View root = mUI.getRootView();
Michael Kolb8872c232013-01-29 10:33:22 -0800425 // These depend on camera parameters.
Michael Kolbd6954f32013-03-08 20:43:01 -0800426
427 int width = root.getWidth();
428 int height = root.getHeight();
Doris Liu6a0de792013-02-26 10:54:25 -0800429 mFocusManager.setPreviewSize(width, height);
Michael Kolbd6954f32013-03-08 20:43:01 -0800430 openCameraCommon();
Michael Kolb8872c232013-01-29 10:33:22 -0800431 }
432
Michael Kolbd6954f32013-03-08 20:43:01 -0800433 private void switchCamera() {
434 if (mPaused) return;
Erin Dahlgren357b7672013-11-20 17:38:14 -0800435 SettingsManager settingsManager = mActivity.getSettingsManager();
Michael Kolbd6954f32013-03-08 20:43:01 -0800436
437 Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
438 mCameraId = mPendingSwitchCameraId;
439 mPendingSwitchCameraId = -1;
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800440 settingsManager.set(SettingsManager.SETTING_CAMERA_ID, "" + mCameraId);
Angus Kong20fad242013-11-11 18:23:46 -0800441 mActivity.getCameraProvider().requestCamera(mCameraId);
Michael Kolbd6954f32013-03-08 20:43:01 -0800442 mUI.clearFaces();
443 if (mFocusManager != null) mFocusManager.removeMessages();
444
Erin Dahlgren357b7672013-11-20 17:38:14 -0800445 // TODO: this needs to be brought into onCameraAvailable();
Angus Kong20fad242013-11-11 18:23:46 -0800446 CameraInfo info = mActivity.getCameraProvider().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -0700447 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
448 mFocusManager.setMirror(mMirror);
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700449 // Start switch camera animation. Post a message because
450 // onFrameAvailable from the old camera may already exist.
Angus Kong13e87c42013-11-25 10:02:47 -0800451 mHandler.sendEmptyMessage(MSG_SWITCH_CAMERA_START_ANIMATION);
Doris Liu48239f42013-03-04 22:19:10 -0800452 }
453
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800454 private ButtonManager.ButtonCallback mCameraButtonCallback =
455 new ButtonManager.ButtonCallback() {
456 @Override
457 public void onStateChanged(int state) {
458 if (mPaused || mPendingSwitchCameraId != -1) {
459 return;
460 }
461 mPendingSwitchCameraId = state;
462
463 Log.v(TAG, "Start to switch camera. cameraId=" + state);
464 // We need to keep a preview frame for the animation before
465 // releasing the camera. This will trigger onPreviewTextureCopied.
466 //TODO: Need to animate the camera switch
467 switchCamera();
468 }
469 };
470
471 private ButtonManager.ButtonCallback mHdrPlusButtonCallback =
472 new ButtonManager.ButtonCallback() {
473 @Override
474 public void onStateChanged(int state) {
475 mHandler.sendEmptyMessage(MSG_SWITCH_TO_GCAM_MODULE);
476 }
477 };
478
Michael Kolbd6954f32013-03-08 20:43:01 -0800479 // either open a new camera or switch cameras
480 private void openCameraCommon() {
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800481 mUI.onCameraOpened(mParameters, mCameraButtonCallback, mHdrPlusButtonCallback);
Angus Kong0fb819b2013-10-08 13:44:19 -0700482 if (mIsImageCaptureIntent) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800483 // Set hdr plus to default: off.
484 SettingsManager settingsManager = mActivity.getSettingsManager();
485 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_HDR_PLUS);
Angus Kong0fb819b2013-10-08 13:44:19 -0700486 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800487 updateSceneMode();
488 showTapToFocusToastIfNeeded();
Michael Kolb8872c232013-01-29 10:33:22 -0800489 }
490
ztenghui7b265a62013-09-09 14:58:44 -0700491 @Override
Doris Liu36ebcb12013-10-28 14:44:24 -0700492 public void onPreviewRectChanged(Rect previewRect) {
493 if (mFocusManager != null) mFocusManager.setPreviewRect(previewRect);
Michael Kolbd6954f32013-03-08 20:43:01 -0800494 }
Michael Kolb8872c232013-01-29 10:33:22 -0800495
496 private void resetExposureCompensation() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800497 SettingsManager settingsManager = mActivity.getSettingsManager();
498 if (settingsManager == null) {
499 Log.e(TAG, "Settings manager is null!");
500 return;
Michael Kolb8872c232013-01-29 10:33:22 -0800501 }
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800502 settingsManager.setDefault(SettingsManager.SETTING_EXPOSURE);
Michael Kolb8872c232013-01-29 10:33:22 -0800503 }
504
Michael Kolb8872c232013-01-29 10:33:22 -0800505 // Snapshots can only be taken after this is called. It should be called
506 // once only. We could have done these things in onCreate() but we want to
507 // make preview screen appear as soon as possible.
508 private void initializeFirstTime() {
Sascha Haeberling330dafb2013-10-10 19:00:41 -0700509 if (mFirstTimeInitialized || mPaused) {
510 return;
511 }
Michael Kolb8872c232013-01-29 10:33:22 -0800512
513 // Initialize location service.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800514 SettingsController settingsController = mActivity.getSettingsController();
515 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -0800516
Michael Kolbd6954f32013-03-08 20:43:01 -0800517 mUI.initializeFirstTime();
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800518 MediaSaver s = getServices().getMediaSaver();
Angus Kong86d36312013-01-31 18:22:44 -0800519 // We set the listener only when both service and shutterbutton
520 // are initialized.
521 if (s != null) {
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800522 s.setQueueListener(this);
Angus Kong86d36312013-01-31 18:22:44 -0800523 }
Michael Kolb8872c232013-01-29 10:33:22 -0800524
Michael Kolb8872c232013-01-29 10:33:22 -0800525 mNamedImages = new NamedImages();
526
527 mFirstTimeInitialized = true;
528 addIdleHandler();
529
530 mActivity.updateStorageSpaceAndHint();
531 }
532
Michael Kolbd6954f32013-03-08 20:43:01 -0800533 // If the activity is paused and resumed, this method will be called in
534 // onResume.
535 private void initializeSecondTime() {
536 // Start location update if needed.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800537 SettingsController settingsController = mActivity.getSettingsController();
538 settingsController.syncLocationManager();
539
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800540 MediaSaver s = getServices().getMediaSaver();
Michael Kolbd6954f32013-03-08 20:43:01 -0800541 if (s != null) {
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800542 s.setQueueListener(this);
Michael Kolbd6954f32013-03-08 20:43:01 -0800543 }
544 mNamedImages = new NamedImages();
545 mUI.initializeSecondTime(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -0800546 }
547
Michael Kolb8872c232013-01-29 10:33:22 -0800548 private void showTapToFocusToastIfNeeded() {
549 // Show the tap to focus toast if this is the first start.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800550 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800551 boolean showHint = settingsManager.getBoolean(
552 SettingsManager.SETTING_CAMERA_FIRST_USE_HINT_SHOWN);
Erin Dahlgren357b7672013-11-20 17:38:14 -0800553 // CONVERT THIS SETTING TO A STRING
554 if (mFocusAreaSupported && showHint) {
Michael Kolb8872c232013-01-29 10:33:22 -0800555 // Delay the toast for one second to wait for orientation.
Angus Kong13e87c42013-11-25 10:02:47 -0800556 mHandler.sendEmptyMessageDelayed(MSG_SHOW_TAP_TO_FOCUS_TOAST, 1000);
Michael Kolb8872c232013-01-29 10:33:22 -0800557 }
558 }
559
560 private void addIdleHandler() {
561 MessageQueue queue = Looper.myQueue();
562 queue.addIdleHandler(new MessageQueue.IdleHandler() {
563 @Override
564 public boolean queueIdle() {
565 Storage.ensureOSXCompatible();
566 return false;
567 }
568 });
569 }
570
Sameer Padala2c8cc452013-11-05 18:49:12 -0800571 private void startSmartCamera() {
572 SmartCameraHelper.register(mCameraDevice, mParameters.getPreviewSize(), mActivity,
Doris Liu773e1c92013-12-02 17:35:03 -0800573 (ViewGroup) mActivity.findViewById(R.id.camera_app_root));
Sameer Padala2c8cc452013-11-05 18:49:12 -0800574 }
575
576 private void stopSmartCamera() {
577 SmartCameraHelper.tearDown();
578 }
579
Michael Kolb8872c232013-01-29 10:33:22 -0800580 @Override
581 public void startFaceDetection() {
Michael Kolb8872c232013-01-29 10:33:22 -0800582 if (mFaceDetectionStarted) return;
583 if (mParameters.getMaxNumDetectedFaces() > 0) {
584 mFaceDetectionStarted = true;
Michael Kolb8872c232013-01-29 10:33:22 -0800585 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Michael Kolbd6954f32013-03-08 20:43:01 -0800586 mUI.onStartFaceDetection(mDisplayOrientation,
587 (info.facing == CameraInfo.CAMERA_FACING_FRONT));
Angus Kong9e765522013-07-31 14:05:20 -0700588 mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Michael Kolb8872c232013-01-29 10:33:22 -0800589 mCameraDevice.startFaceDetection();
590 }
591 }
592
Michael Kolb8872c232013-01-29 10:33:22 -0800593 @Override
594 public void stopFaceDetection() {
Michael Kolb8872c232013-01-29 10:33:22 -0800595 if (!mFaceDetectionStarted) return;
596 if (mParameters.getMaxNumDetectedFaces() > 0) {
597 mFaceDetectionStarted = false;
Angus Kong9e765522013-07-31 14:05:20 -0700598 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -0800599 mCameraDevice.stopFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800600 mUI.clearFaces();
Michael Kolb8872c232013-01-29 10:33:22 -0800601 }
602 }
603
Michael Kolb8872c232013-01-29 10:33:22 -0800604 private final class ShutterCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700605 implements CameraShutterCallback {
Angus Kongdcb0ef12013-03-25 23:11:43 -0700606
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800607 private final boolean mNeedsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700608
Sascha Haeberling37f36112013-08-06 14:31:52 -0700609 public ShutterCallback(boolean needsAnimation) {
610 mNeedsAnimation = needsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700611 }
612
Michael Kolb8872c232013-01-29 10:33:22 -0800613 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700614 public void onShutter(CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800615 mShutterCallbackTime = System.currentTimeMillis();
616 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
617 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Sascha Haeberling37f36112013-08-06 14:31:52 -0700618 if (mNeedsAnimation) {
619 mActivity.runOnUiThread(new Runnable() {
620 @Override
621 public void run() {
622 animateAfterShutter();
623 }
624 });
Angus Kongdcb0ef12013-03-25 23:11:43 -0700625 }
Michael Kolb8872c232013-01-29 10:33:22 -0800626 }
627 }
628
Angus Kong9ef99252013-07-18 18:04:19 -0700629 private final class PostViewPictureCallback
630 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800631 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700632 public void onPictureTaken(byte [] data, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800633 mPostViewPictureCallbackTime = System.currentTimeMillis();
634 Log.v(TAG, "mShutterToPostViewCallbackTime = "
635 + (mPostViewPictureCallbackTime - mShutterCallbackTime)
636 + "ms");
637 }
638 }
639
Angus Kong9ef99252013-07-18 18:04:19 -0700640 private final class RawPictureCallback
641 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800642 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700643 public void onPictureTaken(byte [] rawData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800644 mRawPictureCallbackTime = System.currentTimeMillis();
645 Log.v(TAG, "mShutterToRawCallbackTime = "
646 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
647 }
648 }
649
Angus Kong9ef99252013-07-18 18:04:19 -0700650 private final class JpegPictureCallback
651 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800652 Location mLocation;
653
654 public JpegPictureCallback(Location loc) {
655 mLocation = loc;
656 }
657
658 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700659 public void onPictureTaken(final byte [] jpegData, CameraProxy camera) {
Sascha Haeberling88901942013-08-28 17:49:00 -0700660 mUI.enableShutter(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800661 if (mPaused) {
662 return;
663 }
Doris Liu6432cd62013-06-13 17:20:31 -0700664 if (mIsImageCaptureIntent) {
665 stopPreview();
666 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700667 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -0700668 mUI.setSwipingEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800669 }
670
671 mJpegPictureCallbackTime = System.currentTimeMillis();
672 // If postview callback has arrived, the captured image is displayed
673 // in postview callback. If not, the captured image is displayed in
674 // raw picture callback.
675 if (mPostViewPictureCallbackTime != 0) {
676 mShutterToPictureDisplayedTime =
677 mPostViewPictureCallbackTime - mShutterCallbackTime;
678 mPictureDisplayedToJpegCallbackTime =
679 mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
680 } else {
681 mShutterToPictureDisplayedTime =
682 mRawPictureCallbackTime - mShutterCallbackTime;
683 mPictureDisplayedToJpegCallbackTime =
684 mJpegPictureCallbackTime - mRawPictureCallbackTime;
685 }
686 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
687 + mPictureDisplayedToJpegCallbackTime + "ms");
688
Michael Kolb8872c232013-01-29 10:33:22 -0800689 mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
690 if (!mIsImageCaptureIntent) {
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700691 setupPreview();
Michael Kolb8872c232013-01-29 10:33:22 -0800692 }
693
Doris Liu36e56fb2013-09-11 17:38:08 -0700694 ExifInterface exif = Exif.getExif(jpegData);
695 int orientation = Exif.getOrientation(exif);
Ruben Brunkd217ed02013-10-08 23:31:13 -0700696
Ruben Brunkd7488272013-10-10 18:45:53 -0700697 if (!mIsImageCaptureIntent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800698 // Calculate the width and the height of the jpeg.
699 Size s = mParameters.getPictureSize();
Michael Kolb8872c232013-01-29 10:33:22 -0800700 int width, height;
701 if ((mJpegRotation + orientation) % 180 == 0) {
702 width = s.width;
703 height = s.height;
704 } else {
705 width = s.height;
706 height = s.width;
707 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700708 NamedEntity name = mNamedImages.getNextNameEntity();
709 String title = (name == null) ? null : name.title;
710 long date = (name == null) ? -1 : name.date;
Ruben Brunkd7488272013-10-10 18:45:53 -0700711
712 // Handle debug mode outputs
713 if (mDebugUri != null) {
714 // If using a debug uri, save jpeg there.
715 saveToDebugUri(jpegData);
716
717 // Adjust the title of the debug image shown in mediastore.
718 if (title != null) {
719 title = DEBUG_IMAGE_PREFIX + title;
720 }
721 }
722
Michael Kolb8872c232013-01-29 10:33:22 -0800723 if (title == null) {
724 Log.e(TAG, "Unbalanced name/data pair");
725 } else {
726 if (date == -1) date = mCaptureStartTime;
Angus Kong0d00a892013-03-26 11:40:40 -0700727 if (mHeading >= 0) {
728 // heading direction has been updated by the sensor.
729 ExifTag directionRefTag = exif.buildTag(
730 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
731 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
732 ExifTag directionTag = exif.buildTag(
733 ExifInterface.TAG_GPS_IMG_DIRECTION,
734 new Rational(mHeading, 1));
735 exif.setTag(directionRefTag);
736 exif.setTag(directionTag);
737 }
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800738 getServices().getMediaSaver().addImage(
Angus Kong86d36312013-01-31 18:22:44 -0800739 jpegData, title, date, mLocation, width, height,
Angus Kong0d00a892013-03-26 11:40:40 -0700740 orientation, exif, mOnMediaSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -0800741 }
Doris Liuce2acbc2013-08-21 18:45:29 -0700742 // Animate capture with real jpeg data instead of a preview frame.
Doris Liu29da2db2013-08-28 14:28:45 -0700743 mUI.animateCapture(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800744 } else {
745 mJpegImageData = jpegData;
746 if (!mQuickCapture) {
Doris Liu36e56fb2013-09-11 17:38:08 -0700747 mUI.showCapturedImageForReview(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800748 } else {
Michael Kolbd6954f32013-03-08 20:43:01 -0800749 onCaptureDone();
Michael Kolb8872c232013-01-29 10:33:22 -0800750 }
751 }
752
753 // Check this in advance of each shot so we don't add to shutter
754 // latency. It's true that someone else could write to the SD card in
755 // the mean time and fill it, but that could have happened between the
756 // shutter press and saving the JPEG too.
757 mActivity.updateStorageSpaceAndHint();
758
759 long now = System.currentTimeMillis();
760 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
761 Log.v(TAG, "mJpegCallbackFinishTime = "
762 + mJpegCallbackFinishTime + "ms");
763 mJpegPictureCallbackTime = 0;
764 }
765 }
766
Angus Kong9ef99252013-07-18 18:04:19 -0700767 private final class AutoFocusCallback implements CameraAFCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800768 @Override
769 public void onAutoFocus(
Angus Kong9ef99252013-07-18 18:04:19 -0700770 boolean focused, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800771 if (mPaused) return;
772
773 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
774 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
775 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800776 mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
Michael Kolb8872c232013-01-29 10:33:22 -0800777 }
778 }
779
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700780 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -0800781 private final class AutoFocusMoveCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700782 implements CameraAFMoveCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800783 @Override
784 public void onAutoFocusMoving(
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700785 boolean moving, CameraProxy camera) {
786 mFocusManager.onAutoFocusMoving(moving);
Michael Kolb8872c232013-01-29 10:33:22 -0800787 }
788 }
789
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700790 /**
791 * This class is just a thread-safe queue for name,date holder objects.
792 */
793 public static class NamedImages {
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800794 private final Vector<NamedEntity> mQueue;
Michael Kolb8872c232013-01-29 10:33:22 -0800795
796 public NamedImages() {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700797 mQueue = new Vector<NamedEntity>();
Michael Kolb8872c232013-01-29 10:33:22 -0800798 }
799
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700800 public void nameNewImage(long date) {
Michael Kolb8872c232013-01-29 10:33:22 -0800801 NamedEntity r = new NamedEntity();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700802 r.title = CameraUtil.createJpegName(date);
Michael Kolb8872c232013-01-29 10:33:22 -0800803 r.date = date;
804 mQueue.add(r);
805 }
806
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700807 public NamedEntity getNextNameEntity() {
808 synchronized(mQueue) {
809 if (!mQueue.isEmpty()) {
810 return mQueue.remove(0);
811 }
Michael Kolb8872c232013-01-29 10:33:22 -0800812 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700813 return null;
Michael Kolb8872c232013-01-29 10:33:22 -0800814 }
815
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700816 public static class NamedEntity {
817 public String title;
818 public long date;
Michael Kolb8872c232013-01-29 10:33:22 -0800819 }
820 }
821
822 private void setCameraState(int state) {
823 mCameraState = state;
824 switch (state) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700825 case PhotoController.PREVIEW_STOPPED:
826 case PhotoController.SNAPSHOT_IN_PROGRESS:
827 case PhotoController.SWITCHING_CAMERA:
Doris Liuf55f3c42013-11-20 00:24:46 -0800828 // TODO: Tell app UI to disable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700829 break;
830 case PhotoController.IDLE:
Doris Liuf55f3c42013-11-20 00:24:46 -0800831 // TODO: Tell app UI to enable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700832 break;
Michael Kolb8872c232013-01-29 10:33:22 -0800833 }
834 }
835
Sascha Haeberling37f36112013-08-06 14:31:52 -0700836 private void animateAfterShutter() {
Michael Kolb8872c232013-01-29 10:33:22 -0800837 // Only animate when in full screen capture mode
838 // i.e. If monkey/a user swipes to the gallery during picture taking,
839 // don't show animation
Doris Liuc2e9abd2013-06-19 14:20:51 -0700840 if (!mIsImageCaptureIntent) {
841 mUI.animateFlash();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700842 }
Michael Kolb8872c232013-01-29 10:33:22 -0800843 }
844
845 @Override
846 public boolean capture() {
847 // If we are already in the middle of taking a snapshot or the image save request
848 // is full then ignore.
849 if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
Angus Kong86d36312013-01-31 18:22:44 -0800850 || mCameraState == SWITCHING_CAMERA
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800851 || getServices().getMediaSaver() == null
852 || getServices().getMediaSaver().isQueueFull()) {
Michael Kolb8872c232013-01-29 10:33:22 -0800853 return false;
854 }
855 mCaptureStartTime = System.currentTimeMillis();
856 mPostViewPictureCallbackTime = 0;
857 mJpegImageData = null;
858
Angus Kongb50b5cb2013-08-09 14:55:20 -0700859 final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
Michael Kolb8872c232013-01-29 10:33:22 -0800860
861 if (animateBefore) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700862 animateAfterShutter();
Michael Kolb8872c232013-01-29 10:33:22 -0800863 }
864
865 // Set rotation and gps data.
Doris Liu3cf565c2013-02-15 10:55:37 -0800866 int orientation;
867 // We need to be consistent with the framework orientation (i.e. the
868 // orientation of the UI.) when the auto-rotate screen setting is on.
869 if (mActivity.isAutoRotateScreen()) {
870 orientation = (360 - mDisplayRotation) % 360;
871 } else {
872 orientation = mOrientation;
873 }
Angus Kong20fad242013-11-11 18:23:46 -0800874 mJpegRotation = CameraUtil.getJpegRotation(mActivity, mCameraId, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800875 mParameters.setRotation(mJpegRotation);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800876 Location loc = mActivity.getLocationManager().getCurrentLocation();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700877 CameraUtil.setGpsParameters(mParameters, loc);
Michael Kolb8872c232013-01-29 10:33:22 -0800878 mCameraDevice.setParameters(mParameters);
879
Sascha Haeberling88901942013-08-28 17:49:00 -0700880 // We don't want user to press the button again while taking a
881 // multi-second HDR photo.
882 mUI.enableShutter(false);
Angus Kong9ef99252013-07-18 18:04:19 -0700883 mCameraDevice.takePicture(mHandler,
884 new ShutterCallback(!animateBefore),
Angus Kongdcb0ef12013-03-25 23:11:43 -0700885 mRawPictureCallback, mPostViewPictureCallback,
Angus Kong9ef99252013-07-18 18:04:19 -0700886 new JpegPictureCallback(loc));
Michael Kolb8872c232013-01-29 10:33:22 -0800887
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700888 mNamedImages.nameNewImage(mCaptureStartTime);
Michael Kolb8872c232013-01-29 10:33:22 -0800889
890 mFaceDetectionStarted = false;
891 setCameraState(SNAPSHOT_IN_PROGRESS);
Bobby Georgescu301b6462013-04-01 15:33:17 -0700892 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
Seth Raphaelcbd82672013-11-05 10:12:36 -0800893 UsageStatistics.ACTION_CAPTURE_DONE, "Photo", 0,
Seth Raphael44973262013-11-27 14:29:24 -0800894 UsageStatistics.hashFileName(mNamedImages.mQueue.lastElement().title + ".jpg"));
Michael Kolb8872c232013-01-29 10:33:22 -0800895 return true;
896 }
897
898 @Override
899 public void setFocusParameters() {
900 setCameraParameters(UPDATE_PARAM_PREFERENCE);
901 }
902
Michael Kolbd6954f32013-03-08 20:43:01 -0800903 private void updateSceneMode() {
Michael Kolb8872c232013-01-29 10:33:22 -0800904 // If scene mode is set, we cannot set flash mode, white balance, and
905 // focus mode, instead, we read it from driver
906 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
907 overrideCameraSettings(mParameters.getFlashMode(),
908 mParameters.getWhiteBalance(), mParameters.getFocusMode());
909 } else {
910 overrideCameraSettings(null, null, null);
911 }
912 }
913
914 private void overrideCameraSettings(final String flashMode,
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700915 final String whiteBalance, final String focusMode) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800916 SettingsManager settingsManager = mActivity.getSettingsManager();
917 settingsManager.set(SettingsManager.SETTING_FLASH_MODE, flashMode);
918 settingsManager.set(SettingsManager.SETTING_WHITE_BALANCE, whiteBalance);
919 settingsManager.set(SettingsManager.SETTING_FOCUS_MODE, focusMode);
Michael Kolb8872c232013-01-29 10:33:22 -0800920 }
921
922 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800923 public void onOrientationChanged(int orientation) {
924 // We keep the last known orientation. So if the user first orient
925 // the camera then point the camera to floor or sky, we still have
926 // the correct orientation.
927 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700928 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800929
930 // Show the toast after getting the first orientation changed.
Angus Kong13e87c42013-11-25 10:02:47 -0800931 if (mHandler.hasMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST)) {
932 mHandler.removeMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST);
Michael Kolb8872c232013-01-29 10:33:22 -0800933 showTapToFocusToast();
934 }
935 }
936
937 @Override
Angus Kong20fad242013-11-11 18:23:46 -0800938 public void onCameraAvailable(CameraProxy cameraProxy) {
939 if (mPaused) {
940 return;
941 }
942 mCameraDevice = cameraProxy;
943
Erin Dahlgren357b7672013-11-20 17:38:14 -0800944 resetExposureCompensation();
Angus Kong20fad242013-11-11 18:23:46 -0800945 initializeCapabilities();
946
947 // Reset zoom value index.
948 mZoomValue = 0;
949 if (mFocusManager == null) {
950 initializeFocusManager();
951 }
952 mFocusManager.setParameters(mInitialParams);
953
954 mParameters = mCameraDevice.getParameters();
955 setCameraParameters(UPDATE_PARAM_ALL);
956 mCameraPreviewParamsReady = true;
957 startPreview();
958
959 onCameraOpened();
960 }
961
962 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -0800963 public void onCaptureCancelled() {
964 mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
965 mActivity.finish();
Michael Kolb8872c232013-01-29 10:33:22 -0800966 }
967
Michael Kolbd6954f32013-03-08 20:43:01 -0800968 @Override
969 public void onCaptureRetake() {
Michael Kolb8872c232013-01-29 10:33:22 -0800970 if (mPaused)
971 return;
Michael Kolbd6954f32013-03-08 20:43:01 -0800972 mUI.hidePostCaptureAlert();
Michael Kolb8872c232013-01-29 10:33:22 -0800973 setupPreview();
974 }
975
Michael Kolbd6954f32013-03-08 20:43:01 -0800976 @Override
977 public void onCaptureDone() {
Michael Kolb8872c232013-01-29 10:33:22 -0800978 if (mPaused) {
979 return;
980 }
981
982 byte[] data = mJpegImageData;
983
984 if (mCropValue == null) {
985 // First handle the no crop case -- just return the value. If the
986 // caller specifies a "save uri" then write the data to its
987 // stream. Otherwise, pass back a scaled down version of the bitmap
988 // directly in the extras.
989 if (mSaveUri != null) {
990 OutputStream outputStream = null;
991 try {
992 outputStream = mContentResolver.openOutputStream(mSaveUri);
993 outputStream.write(data);
994 outputStream.close();
995
996 mActivity.setResultEx(Activity.RESULT_OK);
997 mActivity.finish();
998 } catch (IOException ex) {
999 // ignore exception
1000 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001001 CameraUtil.closeSilently(outputStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001002 }
1003 } else {
Angus Kong0d00a892013-03-26 11:40:40 -07001004 ExifInterface exif = Exif.getExif(data);
1005 int orientation = Exif.getOrientation(exif);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001006 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
1007 bitmap = CameraUtil.rotate(bitmap, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001008 mActivity.setResultEx(Activity.RESULT_OK,
1009 new Intent("inline-data").putExtra("data", bitmap));
1010 mActivity.finish();
1011 }
1012 } else {
1013 // Save the image to a temp file and invoke the cropper
1014 Uri tempUri = null;
1015 FileOutputStream tempStream = null;
1016 try {
1017 File path = mActivity.getFileStreamPath(sTempCropFilename);
1018 path.delete();
1019 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1020 tempStream.write(data);
1021 tempStream.close();
1022 tempUri = Uri.fromFile(path);
1023 } catch (FileNotFoundException ex) {
1024 mActivity.setResultEx(Activity.RESULT_CANCELED);
1025 mActivity.finish();
1026 return;
1027 } catch (IOException ex) {
1028 mActivity.setResultEx(Activity.RESULT_CANCELED);
1029 mActivity.finish();
1030 return;
1031 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001032 CameraUtil.closeSilently(tempStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001033 }
1034
1035 Bundle newExtras = new Bundle();
1036 if (mCropValue.equals("circle")) {
1037 newExtras.putString("circleCrop", "true");
1038 }
1039 if (mSaveUri != null) {
1040 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1041 } else {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001042 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001043 }
1044 if (mActivity.isSecureCamera()) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001045 newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001046 }
1047
Sascha Haeberling37f36112013-08-06 14:31:52 -07001048 // TODO: Share this constant.
Sascha Haeberling8e963a52013-08-06 11:43:02 -07001049 final String CROP_ACTION = "com.android.camera.action.CROP";
1050 Intent cropIntent = new Intent(CROP_ACTION);
Michael Kolb8872c232013-01-29 10:33:22 -08001051
1052 cropIntent.setData(tempUri);
1053 cropIntent.putExtras(newExtras);
1054
1055 mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1056 }
1057 }
1058
Michael Kolb8872c232013-01-29 10:33:22 -08001059 @Override
1060 public void onShutterButtonFocus(boolean pressed) {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001061 if (mPaused || (mCameraState == SNAPSHOT_IN_PROGRESS)
Michael Kolb8872c232013-01-29 10:33:22 -08001062 || (mCameraState == PREVIEW_STOPPED)) return;
1063
1064 // Do not do focus if there is not enough storage.
1065 if (pressed && !canTakePicture()) return;
1066
1067 if (pressed) {
Michael Kolb8872c232013-01-29 10:33:22 -08001068 mFocusManager.onShutterDown();
1069 } else {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001070 mFocusManager.onShutterUp();
Michael Kolb8872c232013-01-29 10:33:22 -08001071 }
1072 }
1073
1074 @Override
1075 public void onShutterButtonClick() {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001076 if (mPaused || (mCameraState == SWITCHING_CAMERA)
Michael Kolb8872c232013-01-29 10:33:22 -08001077 || (mCameraState == PREVIEW_STOPPED)) return;
1078
1079 // Do not take the picture if there is not enough storage.
Angus Kong2dcc0a92013-09-25 13:00:08 -07001080 if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Michael Kolb8872c232013-01-29 10:33:22 -08001081 Log.i(TAG, "Not enough space or storage not ready. remaining="
Angus Kong2dcc0a92013-09-25 13:00:08 -07001082 + mActivity.getStorageSpaceBytes());
Michael Kolb8872c232013-01-29 10:33:22 -08001083 return;
1084 }
1085 Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1086
Angus Kongb50b5cb2013-08-09 14:55:20 -07001087 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -07001088 mUI.setSwipingEnabled(false);
Doris Liu9cdfe002013-04-16 09:50:56 -07001089 }
Michael Kolb8872c232013-01-29 10:33:22 -08001090 // If the user wants to do a snapshot while the previous one is still
1091 // in progress, remember the fact and do it after we finish the previous
1092 // one and re-start the preview. Snapshot in progress also includes the
1093 // state that autofocus is focusing and a picture will be taken when
1094 // focus callback arrives.
1095 if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1096 && !mIsImageCaptureIntent) {
1097 mSnapshotOnIdle = true;
1098 return;
1099 }
1100
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001101 mSnapshotOnIdle = false;
1102 mFocusManager.doSnap();
Michael Kolb8872c232013-01-29 10:33:22 -08001103 }
1104
Andy Huibersdef975d2013-11-22 09:13:39 -08001105 private void onResumeTasks() {
1106 Log.v(TAG, "Executing onResumeTasks.");
Michael Kolb8872c232013-01-29 10:33:22 -08001107 if (mOpenCameraFail || mCameraDisabled) return;
1108
Angus Kong20fad242013-11-11 18:23:46 -08001109 mActivity.getCameraProvider().requestCamera(mCameraId);
1110
Michael Kolb8872c232013-01-29 10:33:22 -08001111 mJpegPictureCallbackTime = 0;
1112 mZoomValue = 0;
Angus Kong20fad242013-11-11 18:23:46 -08001113
1114 mOnResumeTime = SystemClock.uptimeMillis();
1115 checkDisplayRotation();
Michael Kolb8872c232013-01-29 10:33:22 -08001116
1117 // If first time initialization is not finished, put it in the
1118 // message queue.
1119 if (!mFirstTimeInitialized) {
Angus Kong13e87c42013-11-25 10:02:47 -08001120 mHandler.sendEmptyMessage(MSG_FIRST_TIME_INIT);
Michael Kolb8872c232013-01-29 10:33:22 -08001121 } else {
1122 initializeSecondTime();
1123 }
Michael Kolb8872c232013-01-29 10:33:22 -08001124
Bobby Georgescu0a7dd572013-03-12 22:45:17 -07001125 UsageStatistics.onContentViewChanged(
1126 UsageStatistics.COMPONENT_CAMERA, "PhotoModule");
Angus Kong0d00a892013-03-26 11:40:40 -07001127
1128 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1129 if (gsensor != null) {
1130 mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1131 }
1132
1133 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1134 if (msensor != null) {
1135 mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1136 }
Michael Kolb8872c232013-01-29 10:33:22 -08001137 }
1138
Angus Kongc4e66562013-11-22 23:03:21 -08001139 /**
1140 * The focus manager is the first UI related element to get initialized,
1141 * and it requires the RenderOverlay, so initialize it here
1142 */
1143 private void initializeFocusManager() {
1144 // Create FocusManager object. startPreview needs it.
1145 // if mFocusManager not null, reuse it
1146 // otherwise create a new instance
1147 if (mFocusManager != null) {
1148 mFocusManager.removeMessages();
1149 } else {
1150 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
1151 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
1152 String[] defaultFocusModes = mActivity.getResources().getStringArray(
1153 R.array.pref_camera_focusmode_default_array);
Erin Dahlgren357b7672013-11-20 17:38:14 -08001154 mFocusManager = new FocusOverlayManager(mActivity.getSettingsManager(),
1155 defaultFocusModes,
Angus Kongc4e66562013-11-22 23:03:21 -08001156 mInitialParams, this, mMirror,
1157 mActivity.getMainLooper(), mUI);
1158 }
Angus Kong20fad242013-11-11 18:23:46 -08001159 }
1160
1161 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001162 public void resume() {
1163 mPaused = false;
1164 // Add delay on resume from lock screen only, in order to to speed up
1165 // the onResume --> onPause --> onResume cycle from lock screen.
1166 // Don't do always because letting go of thread can cause delay.
1167 String action = mActivity.getIntent().getAction();
1168 if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
1169 || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
1170 Log.v(TAG, "On resume, from lock screen.");
1171 // Note: onPauseAfterSuper() will delete this runnable, so we will
1172 // at most have 1 copy queued up.
1173 mHandler.postDelayed(new Runnable() {
Sameer Padala2c8cc452013-11-05 18:49:12 -08001174 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001175 public void run() {
1176 onResumeTasks();
1177 }
1178 }, ON_RESUME_TASKS_DELAY_MSEC);
1179 } else {
1180 Log.v(TAG, "On resume.");
1181 onResumeTasks();
1182 }
1183 }
1184
1185 @Override
1186 public void pause() {
Michael Kolb8872c232013-01-29 10:33:22 -08001187 mPaused = true;
Angus Kong0d00a892013-03-26 11:40:40 -07001188 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1189 if (gsensor != null) {
1190 mSensorManager.unregisterListener(this, gsensor);
1191 }
1192
1193 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1194 if (msensor != null) {
1195 mSensorManager.unregisterListener(this, msensor);
1196 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001197
Michael Kolb8872c232013-01-29 10:33:22 -08001198 // Reset the focus first. Camera CTS does not guarantee that
1199 // cancelAutoFocus is allowed after preview stops.
1200 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1201 mCameraDevice.cancelAutoFocus();
1202 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001203
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -08001204 // If the camera has not been opened asynchronously yet,
1205 // and startPreview hasn't been called, then this is a no-op.
1206 // (e.g. onResume -> onPause -> onResume).
Michael Kolb8872c232013-01-29 10:33:22 -08001207 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001208
Angus Kongce5480e2013-01-29 17:43:48 -08001209 mNamedImages = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001210
1211 if (mLocationManager != null) mLocationManager.recordLocation(false);
1212
1213 // If we are in an image capture intent and has taken
1214 // a picture, we just clear it in onPause.
1215 mJpegImageData = null;
1216
Angus Kongdcccc512013-08-08 17:06:03 -07001217 // Remove the messages and runnables in the queue.
1218 mHandler.removeCallbacksAndMessages(null);
Michael Kolb8872c232013-01-29 10:33:22 -08001219
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001220 closeCamera();
Angus Kong13e87c42013-11-25 10:02:47 -08001221 mActivity.enableKeepScreenOn(false);
Michael Kolbd6954f32013-03-08 20:43:01 -08001222 mUI.onPause();
1223
Michael Kolb8872c232013-01-29 10:33:22 -08001224 mPendingSwitchCameraId = -1;
1225 if (mFocusManager != null) mFocusManager.removeMessages();
Sascha Haeberling280fd3e2013-11-21 13:52:15 -08001226 MediaSaver s = getServices().getMediaSaver();
Angus Kong86d36312013-01-31 18:22:44 -08001227 if (s != null) {
Angus Kongfd4fc0e2013-11-07 15:38:09 -08001228 s.setQueueListener(null);
Angus Kong86d36312013-01-31 18:22:44 -08001229 }
Michael Kolb8872c232013-01-29 10:33:22 -08001230 }
1231
Angus Kong20fad242013-11-11 18:23:46 -08001232 @Override
1233 public void destroy() {
1234 // TODO: implement this.
1235 }
1236
1237 @Override
1238 public void onPreviewSizeChanged(int width, int height) {
1239 // TODO: implement this.
1240 }
1241
1242 @Override
Angus Kong2f0e4a32013-12-03 10:02:35 -08001243 public void onLayoutOrientationChanged(boolean isLandscape) {
Michael Kolb8872c232013-01-29 10:33:22 -08001244 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001245 }
1246
1247 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001248 public void updateCameraOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001249 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001250 setDisplayOrientation();
1251 }
1252 }
1253
Michael Kolb8872c232013-01-29 10:33:22 -08001254 private boolean canTakePicture() {
Angus Kong2dcc0a92013-09-25 13:00:08 -07001255 return isCameraIdle() && (mActivity.getStorageSpaceBytes() > Storage.LOW_STORAGE_THRESHOLD_BYTES);
Michael Kolb8872c232013-01-29 10:33:22 -08001256 }
1257
1258 @Override
1259 public void autoFocus() {
1260 mFocusStartTime = System.currentTimeMillis();
Angus Kong9ef99252013-07-18 18:04:19 -07001261 mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001262 setCameraState(FOCUSING);
1263 }
1264
1265 @Override
1266 public void cancelAutoFocus() {
1267 mCameraDevice.cancelAutoFocus();
1268 setCameraState(IDLE);
1269 setCameraParameters(UPDATE_PARAM_PREFERENCE);
1270 }
1271
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001272 // Preview area is touched.
Michael Kolb8872c232013-01-29 10:33:22 -08001273 @Override
1274 public void onSingleTapUp(View view, int x, int y) {
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001275 if (mUI.isImmediateCapture()) {
1276 cancelAutoFocus();
1277 onShutterButtonClick();
1278 } else {
1279 onShutterButtonFocus(true);
1280 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001281 }
Michael Kolb8872c232013-01-29 10:33:22 -08001282 }
1283
1284 @Override
1285 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001286 return mUI.onBackPressed();
Michael Kolb8872c232013-01-29 10:33:22 -08001287 }
1288
1289 @Override
1290 public boolean onKeyDown(int keyCode, KeyEvent event) {
1291 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001292 case KeyEvent.KEYCODE_VOLUME_UP:
1293 case KeyEvent.KEYCODE_VOLUME_DOWN:
1294 case KeyEvent.KEYCODE_FOCUS:
1295 if (/*TODO: mActivity.isInCameraApp() &&*/ mFirstTimeInitialized) {
1296 if (event.getRepeatCount() == 0) {
1297 onShutterButtonFocus(true);
1298 }
1299 return true;
1300 }
1301 return false;
1302 case KeyEvent.KEYCODE_CAMERA:
1303 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1304 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001305 }
1306 return true;
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001307 case KeyEvent.KEYCODE_DPAD_CENTER:
1308 // If we get a dpad center event without any focused view, move
1309 // the focus to the shutter button and press it.
1310 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1311 // Start auto-focus immediately to reduce shutter lag. After
1312 // the shutter button gets the focus, onShutterButtonFocus()
1313 // will be called again but it is fine.
1314 onShutterButtonFocus(true);
1315 mUI.pressShutterButton();
1316 }
1317 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001318 }
1319 return false;
1320 }
1321
1322 @Override
1323 public boolean onKeyUp(int keyCode, KeyEvent event) {
1324 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001325 case KeyEvent.KEYCODE_VOLUME_UP:
1326 case KeyEvent.KEYCODE_VOLUME_DOWN:
1327 if (/*mActivity.isInCameraApp() && */ mFirstTimeInitialized) {
1328 onShutterButtonClick();
1329 return true;
1330 }
1331 return false;
1332 case KeyEvent.KEYCODE_FOCUS:
1333 if (mFirstTimeInitialized) {
1334 onShutterButtonFocus(false);
1335 }
Michael Kolb8872c232013-01-29 10:33:22 -08001336 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001337 }
1338 return false;
1339 }
1340
Michael Kolb8872c232013-01-29 10:33:22 -08001341 private void closeCamera() {
1342 if (mCameraDevice != null) {
1343 mCameraDevice.setZoomChangeListener(null);
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001344 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001345 mCameraDevice.setErrorCallback(null);
Ruben Brunk59147832013-11-05 15:53:28 -08001346
Michael Kolb8872c232013-01-29 10:33:22 -08001347 mFaceDetectionStarted = false;
Angus Kong20fad242013-11-11 18:23:46 -08001348 mActivity.getCameraProvider().releaseCamera(mCameraDevice.getCameraId());
Michael Kolb8872c232013-01-29 10:33:22 -08001349 mCameraDevice = null;
1350 setCameraState(PREVIEW_STOPPED);
1351 mFocusManager.onCameraReleased();
1352 }
1353 }
1354
1355 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001356 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1357 mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001358 mCameraDisplayOrientation = mDisplayOrientation;
Michael Kolbd6954f32013-03-08 20:43:01 -08001359 mUI.setDisplayOrientation(mDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001360 if (mFocusManager != null) {
1361 mFocusManager.setDisplayOrientation(mDisplayOrientation);
1362 }
Doris Liu6432cd62013-06-13 17:20:31 -07001363 // Change the camera display orientation
1364 if (mCameraDevice != null) {
1365 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1366 }
Michael Kolb8872c232013-01-29 10:33:22 -08001367 }
1368
Sascha Haeberlingddef7792013-08-13 14:41:10 -07001369 /** Only called by UI thread. */
Michael Kolb8872c232013-01-29 10:33:22 -08001370 private void setupPreview() {
1371 mFocusManager.resetTouchFocus();
1372 startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001373 }
1374
Angus Kong20fad242013-11-11 18:23:46 -08001375 /**
1376 * Returns whether we can/should start the preview or not.
1377 */
1378 private boolean checkPreviewPreconditions() {
1379 if (mPaused) {
1380 return false;
Angus Kongdcccc512013-08-08 17:06:03 -07001381 }
Michael Kolb8872c232013-01-29 10:33:22 -08001382
Angus Kong20fad242013-11-11 18:23:46 -08001383 if (mCameraDevice == null) {
1384 Log.w(TAG, "startPreview: camera device not ready yet.");
1385 return false;
1386 }
1387
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001388 SurfaceTexture st = mUI.getSurfaceTexture();
1389 if (st == null) {
1390 Log.w(TAG, "startPreview: surfaceTexture is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001391 return false;
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001392 }
1393
1394 if (!mCameraPreviewParamsReady) {
1395 Log.w(TAG, "startPreview: parameters for preview is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001396 return false;
1397 }
1398 return true;
1399 }
1400
1401 /**
1402 * The start/stop preview should only run on the UI thread.
1403 */
1404 private void startPreview() {
1405 if (!checkPreviewPreconditions()) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001406 return;
1407 }
Angus Kong20fad242013-11-11 18:23:46 -08001408
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001409 mCameraDevice.setErrorCallback(mErrorCallback);
1410 // ICS camera frameworks has a bug. Face detection state is not cleared 1589
1411 // after taking a picture. Stop the preview to work around it. The bug
1412 // was fixed in JB.
1413 if (mCameraState != PREVIEW_STOPPED) {
1414 stopPreview();
1415 }
1416
1417 setDisplayOrientation();
1418
1419 if (!mSnapshotOnIdle) {
1420 // If the focus mode is continuous autofocus, call cancelAutoFocus to
1421 // resume it because it may have been paused by autoFocus call.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001422 String focusMode = mFocusManager.getFocusMode();
1423 if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(focusMode)) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001424 mCameraDevice.cancelAutoFocus();
Michael Kolb8872c232013-01-29 10:33:22 -08001425 }
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001426 mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1427 }
1428 setCameraParameters(UPDATE_PARAM_ALL);
1429 // Let UI set its expected aspect ratio
Angus Kong20fad242013-11-11 18:23:46 -08001430 mCameraDevice.setPreviewTexture(mUI.getSurfaceTexture());
Michael Kolb8872c232013-01-29 10:33:22 -08001431
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001432 Log.v(TAG, "startPreview");
1433 mCameraDevice.startPreview();
Angus Kong20fad242013-11-11 18:23:46 -08001434
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001435 mFocusManager.onPreviewStarted();
1436 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001437
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001438 if (mSnapshotOnIdle) {
1439 mHandler.post(mDoSnapRunnable);
Michael Kolb8872c232013-01-29 10:33:22 -08001440 }
1441 }
1442
Michael Kolbd6954f32013-03-08 20:43:01 -08001443 @Override
1444 public void stopPreview() {
Michael Kolb8872c232013-01-29 10:33:22 -08001445 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1446 Log.v(TAG, "stopPreview");
1447 mCameraDevice.stopPreview();
1448 mFaceDetectionStarted = false;
1449 }
1450 setCameraState(PREVIEW_STOPPED);
1451 if (mFocusManager != null) mFocusManager.onPreviewStopped();
Sameer Padala2c8cc452013-11-05 18:49:12 -08001452 stopSmartCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001453 }
1454
1455 @SuppressWarnings("deprecation")
1456 private void updateCameraParametersInitialize() {
1457 // Reset preview frame rate to the maximum because it may be lowered by
1458 // video camera application.
ztenghui16a35202013-09-23 11:35:36 -07001459 int[] fpsRange = CameraUtil.getPhotoPreviewFpsRange(mParameters);
1460 if (fpsRange != null && fpsRange.length > 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001461 mParameters.setPreviewFpsRange(
1462 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1463 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
Michael Kolb8872c232013-01-29 10:33:22 -08001464 }
1465
Angus Kongb50b5cb2013-08-09 14:55:20 -07001466 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);
Michael Kolb8872c232013-01-29 10:33:22 -08001467
1468 // Disable video stabilization. Convenience methods not available in API
1469 // level <= 14
1470 String vstabSupported = mParameters.get("video-stabilization-supported");
1471 if ("true".equals(vstabSupported)) {
1472 mParameters.set("video-stabilization", "false");
1473 }
1474 }
1475
1476 private void updateCameraParametersZoom() {
1477 // Set zoom.
1478 if (mParameters.isZoomSupported()) {
1479 mParameters.setZoom(mZoomValue);
1480 }
1481 }
1482
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001483 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001484 private void setAutoExposureLockIfSupported() {
1485 if (mAeLockSupported) {
1486 mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1487 }
1488 }
1489
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001490 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001491 private void setAutoWhiteBalanceLockIfSupported() {
1492 if (mAwbLockSupported) {
1493 mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1494 }
1495 }
1496
Michael Kolb8872c232013-01-29 10:33:22 -08001497 private void setFocusAreasIfSupported() {
1498 if (mFocusAreaSupported) {
1499 mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1500 }
1501 }
1502
Michael Kolb8872c232013-01-29 10:33:22 -08001503 private void setMeteringAreasIfSupported() {
1504 if (mMeteringAreaSupported) {
Michael Kolb8872c232013-01-29 10:33:22 -08001505 mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1506 }
1507 }
1508
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001509 private boolean updateCameraParametersPreference() {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001510 SettingsManager settingsManager = mActivity.getSettingsManager();
1511
Michael Kolb8872c232013-01-29 10:33:22 -08001512 setAutoExposureLockIfSupported();
1513 setAutoWhiteBalanceLockIfSupported();
1514 setFocusAreasIfSupported();
1515 setMeteringAreasIfSupported();
1516
Michael Kolbd3253f22013-07-12 11:36:47 -07001517 // initialize focus mode
1518 mFocusManager.overrideFocusMode(null);
1519 mParameters.setFocusMode(mFocusManager.getFocusMode());
1520
Michael Kolb8872c232013-01-29 10:33:22 -08001521 // Set picture size.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001522 String pictureSize = settingsManager.get(SettingsManager.SETTING_PICTURE_SIZE);
Michael Kolb8872c232013-01-29 10:33:22 -08001523 if (pictureSize == null) {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001524 //TODO: deprecate CameraSettings.
1525 CameraSettings.initialCameraPictureSize(
1526 mActivity, mParameters, settingsManager);
Michael Kolb8872c232013-01-29 10:33:22 -08001527 } else {
1528 List<Size> supported = mParameters.getSupportedPictureSizes();
1529 CameraSettings.setCameraPictureSize(
1530 pictureSize, supported, mParameters);
1531 }
1532 Size size = mParameters.getPictureSize();
1533
1534 // Set a preview size that is closest to the viewfinder height and has
1535 // the right aspect ratio.
1536 List<Size> sizes = mParameters.getSupportedPreviewSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001537 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
Michael Kolb8872c232013-01-29 10:33:22 -08001538 (double) size.width / size.height);
1539 Size original = mParameters.getPreviewSize();
1540 if (!original.equals(optimalSize)) {
1541 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
Doris Liu6432cd62013-06-13 17:20:31 -07001542
Michael Kolb8872c232013-01-29 10:33:22 -08001543 // Zoom related settings will be changed for different preview
1544 // sizes, so set and read the parameters to get latest values
Michael Kolb4a4d4ef2013-05-30 08:35:26 -07001545 if (mHandler.getLooper() == Looper.myLooper()) {
1546 // On UI thread only, not when camera starts up
1547 setupPreview();
1548 } else {
1549 mCameraDevice.setParameters(mParameters);
1550 }
Michael Kolb8872c232013-01-29 10:33:22 -08001551 mParameters = mCameraDevice.getParameters();
1552 }
Doris Liu95405742013-11-05 15:25:26 -08001553
1554 if(optimalSize.width != 0 && optimalSize.height != 0) {
1555 mUI.updatePreviewAspectRatio((float) optimalSize.width
1556 / (float) optimalSize.height);
1557 }
Michael Kolb8872c232013-01-29 10:33:22 -08001558 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
1559
1560 // Since changing scene mode may change supported values, set scene mode
1561 // first. HDR is a scene mode. To promote it in UI, it is stored in a
1562 // separate preference.
Sascha Haeberling98f38bb2013-09-24 18:58:34 -07001563 String onValue = mActivity.getString(R.string.setting_on_value);
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001564 String hdr = settingsManager.get(SettingsManager.SETTING_CAMERA_HDR);
1565 String hdrPlus = settingsManager.get(SettingsManager.SETTING_CAMERA_HDR_PLUS);
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001566 boolean hdrOn = onValue.equals(hdr);
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001567 boolean hdrPlusOn = onValue.equals(hdrPlus);
Sascha Haeberling98f38bb2013-09-24 18:58:34 -07001568
1569 boolean doGcamModeSwitch = false;
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001570 if (hdrPlusOn && GcamHelper.hasGcamCapture()) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001571 // Kick off mode switch to gcam.
1572 doGcamModeSwitch = true;
Michael Kolb8872c232013-01-29 10:33:22 -08001573 } else {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001574 if (hdrOn) {
1575 mSceneMode = CameraUtil.SCENE_MODE_HDR;
1576 } else {
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001577 mSceneMode = settingsManager.get(SettingsManager.SETTING_SCENE_MODE);
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001578 }
Michael Kolb8872c232013-01-29 10:33:22 -08001579 }
Angus Kongb50b5cb2013-08-09 14:55:20 -07001580 if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
Michael Kolb8872c232013-01-29 10:33:22 -08001581 if (!mParameters.getSceneMode().equals(mSceneMode)) {
1582 mParameters.setSceneMode(mSceneMode);
1583
1584 // Setting scene mode will change the settings of flash mode,
1585 // white balance, and focus mode. Here we read back the
1586 // parameters, so we can know those settings.
1587 mCameraDevice.setParameters(mParameters);
1588 mParameters = mCameraDevice.getParameters();
1589 }
1590 } else {
1591 mSceneMode = mParameters.getSceneMode();
1592 if (mSceneMode == null) {
1593 mSceneMode = Parameters.SCENE_MODE_AUTO;
1594 }
1595 }
1596
1597 // Set JPEG quality.
1598 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1599 CameraProfile.QUALITY_HIGH);
1600 mParameters.setJpegQuality(jpegQuality);
1601
1602 // For the following settings, we need to check if the settings are
1603 // still supported by latest driver, if not, ignore the settings.
1604
1605 // Set exposure compensation
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001606 int value = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_EXPOSURE));
Michael Kolb8872c232013-01-29 10:33:22 -08001607 int max = mParameters.getMaxExposureCompensation();
1608 int min = mParameters.getMinExposureCompensation();
1609 if (value >= min && value <= max) {
1610 mParameters.setExposureCompensation(value);
1611 } else {
1612 Log.w(TAG, "invalid exposure range: " + value);
1613 }
1614
1615 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1616 // Set flash mode.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001617 String flashMode = settingsManager.get(SettingsManager.SETTING_FLASH_MODE);
Michael Kolb8872c232013-01-29 10:33:22 -08001618 List<String> supportedFlash = mParameters.getSupportedFlashModes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001619 if (CameraUtil.isSupported(flashMode, supportedFlash)) {
Michael Kolb8872c232013-01-29 10:33:22 -08001620 mParameters.setFlashMode(flashMode);
1621 } else {
1622 flashMode = mParameters.getFlashMode();
1623 if (flashMode == null) {
1624 flashMode = mActivity.getString(
1625 R.string.pref_camera_flashmode_no_flash);
1626 }
1627 }
1628
1629 // Set white balance parameter.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001630 String whiteBalance = settingsManager.get(SettingsManager.SETTING_WHITE_BALANCE);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001631 if (CameraUtil.isSupported(whiteBalance,
Michael Kolb8872c232013-01-29 10:33:22 -08001632 mParameters.getSupportedWhiteBalance())) {
1633 mParameters.setWhiteBalance(whiteBalance);
1634 } else {
1635 whiteBalance = mParameters.getWhiteBalance();
1636 if (whiteBalance == null) {
1637 whiteBalance = Parameters.WHITE_BALANCE_AUTO;
1638 }
1639 }
1640
1641 // Set focus mode.
1642 mFocusManager.overrideFocusMode(null);
1643 mParameters.setFocusMode(mFocusManager.getFocusMode());
1644 } else {
1645 mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1646 }
1647
Angus Kongdcccc512013-08-08 17:06:03 -07001648 if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
Michael Kolb8872c232013-01-29 10:33:22 -08001649 updateAutoFocusMoveCallback();
1650 }
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001651
1652 return doGcamModeSwitch;
Michael Kolb8872c232013-01-29 10:33:22 -08001653 }
1654
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001655 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001656 private void updateAutoFocusMoveCallback() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001657 if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Angus Kong9ef99252013-07-18 18:04:19 -07001658 mCameraDevice.setAutoFocusMoveCallback(mHandler,
Angus Kong4f795b82013-09-16 14:25:35 -07001659 (CameraAFMoveCallback) mAutoFocusMoveCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001660 } else {
Angus Kong9ef99252013-07-18 18:04:19 -07001661 mCameraDevice.setAutoFocusMoveCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001662 }
1663 }
1664
1665 // We separate the parameters into several subsets, so we can update only
1666 // the subsets actually need updating. The PREFERENCE set needs extra
1667 // locking because the preference can be changed from GLThread as well.
1668 private void setCameraParameters(int updateSet) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001669 boolean doModeSwitch = false;
1670
Michael Kolb8872c232013-01-29 10:33:22 -08001671 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1672 updateCameraParametersInitialize();
1673 }
1674
1675 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1676 updateCameraParametersZoom();
1677 }
1678
1679 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001680 doModeSwitch = updateCameraParametersPreference();
Michael Kolb8872c232013-01-29 10:33:22 -08001681 }
1682
1683 mCameraDevice.setParameters(mParameters);
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001684
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001685 // Switch to gcam module if HDR+ was selected
Angus Kong0fb819b2013-10-08 13:44:19 -07001686 if (doModeSwitch && !mIsImageCaptureIntent) {
Angus Kong13e87c42013-11-25 10:02:47 -08001687 mHandler.sendEmptyMessage(MSG_SWITCH_TO_GCAM_MODULE);
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001688 }
Michael Kolb8872c232013-01-29 10:33:22 -08001689 }
1690
1691 // If the Camera is idle, update the parameters immediately, otherwise
1692 // accumulate them in mUpdateSet and update later.
1693 private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1694 mUpdateSet |= additionalUpdateSet;
1695 if (mCameraDevice == null) {
1696 // We will update all the parameters when we open the device, so
1697 // we don't need to do anything now.
1698 mUpdateSet = 0;
1699 return;
1700 } else if (isCameraIdle()) {
1701 setCameraParameters(mUpdateSet);
Michael Kolbd6954f32013-03-08 20:43:01 -08001702 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001703 mUpdateSet = 0;
1704 } else {
Angus Kong13e87c42013-11-25 10:02:47 -08001705 if (!mHandler.hasMessages(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1706 mHandler.sendEmptyMessageDelayed(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
Michael Kolb8872c232013-01-29 10:33:22 -08001707 }
1708 }
1709 }
1710
ztenghui7b265a62013-09-09 14:58:44 -07001711 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001712 public boolean isCameraIdle() {
Michael Kolb8872c232013-01-29 10:33:22 -08001713 return (mCameraState == IDLE) ||
1714 (mCameraState == PREVIEW_STOPPED) ||
1715 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
1716 && (mCameraState != SWITCHING_CAMERA));
1717 }
1718
ztenghui7b265a62013-09-09 14:58:44 -07001719 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001720 public boolean isImageCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001721 String action = mActivity.getIntent().getAction();
1722 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
Angus Kong6a8e8a12013-07-19 14:55:07 -07001723 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
Michael Kolb8872c232013-01-29 10:33:22 -08001724 }
1725
1726 private void setupCaptureParams() {
1727 Bundle myExtras = mActivity.getIntent().getExtras();
1728 if (myExtras != null) {
1729 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1730 mCropValue = myExtras.getString("crop");
1731 }
1732 }
1733
Michael Kolb8872c232013-01-29 10:33:22 -08001734 public void onSharedPreferenceChanged() {
1735 // ignore the events after "onPause()"
1736 if (mPaused) return;
1737
Erin Dahlgren357b7672013-11-20 17:38:14 -08001738 SettingsController settingsController = mActivity.getSettingsController();
1739 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001740
1741 setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
Michael Kolb8872c232013-01-29 10:33:22 -08001742 }
1743
Michael Kolb8872c232013-01-29 10:33:22 -08001744 private void showTapToFocusToast() {
1745 // TODO: Use a toast?
1746 new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
1747 // Clear the preference.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001748 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001749 settingsManager.setBoolean(
1750 SettingsManager.SETTING_CAMERA_FIRST_USE_HINT_SHOWN, false);
Michael Kolb8872c232013-01-29 10:33:22 -08001751 }
1752
1753 private void initializeCapabilities() {
1754 mInitialParams = mCameraDevice.getParameters();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001755 mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
1756 mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
1757 mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
1758 mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
Angus Kongdcccc512013-08-08 17:06:03 -07001759 mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001760 CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
Michael Kolb8872c232013-01-29 10:33:22 -08001761 }
1762
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001763 // TODO: Remove this
Michael Kolb8872c232013-01-29 10:33:22 -08001764 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001765 public int onZoomChanged(int index) {
1766 // Not useful to change zoom value when the activity is paused.
1767 if (mPaused) return index;
1768 mZoomValue = index;
1769 if (mParameters == null || mCameraDevice == null) return index;
1770 // Set zoom parameters asynchronously
1771 mParameters.setZoom(mZoomValue);
Angus Kong36ed8672013-04-15 12:11:15 -07001772 mCameraDevice.setParameters(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -08001773 Parameters p = mCameraDevice.getParameters();
1774 if (p != null) return p.getZoom();
1775 return index;
Angus Kongce5480e2013-01-29 17:43:48 -08001776 }
1777
1778 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001779 public int getCameraState() {
1780 return mCameraState;
1781 }
1782
1783 @Override
1784 public void onQueueStatus(boolean full) {
1785 mUI.enableShutter(!full);
Angus Kongce5480e2013-01-29 17:43:48 -08001786 }
Angus Kong86d36312013-01-31 18:22:44 -08001787
1788 @Override
Angus Kongfd4fc0e2013-11-07 15:38:09 -08001789 public void onMediaSaverAvailable(MediaSaver s) {
Angus Kong86d36312013-01-31 18:22:44 -08001790 // We set the listener only when both service and shutterbutton
1791 // are initialized.
Michael Kolbd6954f32013-03-08 20:43:01 -08001792 if (mFirstTimeInitialized) {
Angus Kongfd4fc0e2013-11-07 15:38:09 -08001793 s.setQueueListener(this);
Michael Kolbd6954f32013-03-08 20:43:01 -08001794 }
Angus Kong86d36312013-01-31 18:22:44 -08001795 }
Angus Kong0d00a892013-03-26 11:40:40 -07001796
1797 @Override
1798 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1799 }
1800
1801 @Override
1802 public void onSensorChanged(SensorEvent event) {
1803 int type = event.sensor.getType();
1804 float[] data;
1805 if (type == Sensor.TYPE_ACCELEROMETER) {
1806 data = mGData;
1807 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
1808 data = mMData;
1809 } else {
1810 // we should not be here.
1811 return;
1812 }
1813 for (int i = 0; i < 3 ; i++) {
1814 data[i] = event.values[i];
1815 }
1816 float[] orientation = new float[3];
1817 SensorManager.getRotationMatrix(mR, null, mGData, mMData);
1818 SensorManager.getOrientation(mR, orientation);
1819 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
1820 if (mHeading < 0) {
1821 mHeading += 360;
1822 }
Angus Kong0d00a892013-03-26 11:40:40 -07001823 }
Doris Liu6432cd62013-06-13 17:20:31 -07001824
1825 @Override
ztenghui7b265a62013-09-09 14:58:44 -07001826 public void onPreviewFocusChanged(boolean previewFocused) {
1827 mUI.onPreviewFocusChanged(previewFocused);
Doris Liu6432cd62013-06-13 17:20:31 -07001828 }
1829
Erin Dahlgren3044d8c2013-10-10 18:23:45 -07001830 @Override
1831 public boolean arePreviewControlsVisible() {
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001832 return false;
Erin Dahlgren3044d8c2013-10-10 18:23:45 -07001833 }
1834
Ruben Brunkd217ed02013-10-08 23:31:13 -07001835 // For debugging only.
1836 public void setDebugUri(Uri uri) {
1837 mDebugUri = uri;
1838 }
1839
1840 // For debugging only.
1841 private void saveToDebugUri(byte[] data) {
1842 if (mDebugUri != null) {
1843 OutputStream outputStream = null;
1844 try {
1845 outputStream = mContentResolver.openOutputStream(mDebugUri);
1846 outputStream.write(data);
1847 outputStream.close();
1848 } catch (IOException e) {
1849 Log.e(TAG, "Exception while writing debug jpeg file", e);
1850 } finally {
1851 CameraUtil.closeSilently(outputStream);
1852 }
1853 }
1854 }
Michael Kolb8872c232013-01-29 10:33:22 -08001855}