blob: f9d38a6df2bb2df783b5b8864163c5bc896bfc78 [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;
Angus Kongfd4fc0e2013-11-07 15:38:09 -080058import com.android.camera.app.MediaSaver;
ztenghuia16e7b52013-08-23 11:47:56 -070059import com.android.camera.exif.ExifInterface;
60import com.android.camera.exif.ExifTag;
61import com.android.camera.exif.Rational;
Angus Kong20fad242013-11-11 18:23:46 -080062import com.android.camera.module.ModuleController;
Erin Dahlgren357b7672013-11-20 17:38:14 -080063import com.android.camera.settings.SettingsManager;
Doris Liu1c94b7d2013-11-09 19:13:44 -080064import com.android.camera.ui.ModeListView;
Michael Kolb8872c232013-01-29 10:33:22 -080065import com.android.camera.ui.RotateTextToast;
Angus Kongdcccc512013-08-08 17:06:03 -070066import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -070067import com.android.camera.util.CameraUtil;
Ruben Brunk4601f5d2013-09-24 18:35:22 -070068import com.android.camera.util.GcamHelper;
Sameer Padala2c8cc452013-11-05 18:49:12 -080069import com.android.camera.util.SmartCameraHelper;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070070import com.android.camera.util.UsageStatistics;
71import com.android.camera2.R;
Michael Kolb8872c232013-01-29 10:33:22 -080072
Angus Kongdcccc512013-08-08 17:06:03 -070073import java.io.File;
74import java.io.FileNotFoundException;
75import java.io.FileOutputStream;
76import java.io.IOException;
77import java.io.OutputStream;
Angus Kongdcccc512013-08-08 17:06:03 -070078import java.util.List;
Ruben Brunka9d66bd2013-09-06 11:56:32 -070079import java.util.Vector;
Angus Kongdcccc512013-08-08 17:06:03 -070080
Michael Kolb8872c232013-01-29 10:33:22 -080081public class PhotoModule
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080082 extends CameraModule
83 implements PhotoController,
84 ModuleController,
85 FocusOverlayManager.Listener,
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080086 ShutterButton.OnShutterButtonListener, MediaSaver.QueueListener,
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080087 SensorEventListener {
Michael Kolb8872c232013-01-29 10:33:22 -080088
89 private static final String TAG = "CAM_PhotoModule";
90
91 // We number the request code from 1000 to avoid collision with Gallery.
92 private static final int REQUEST_CROP = 1000;
93
Angus Kong13e87c42013-11-25 10:02:47 -080094 // Messages defined for the UI thread handler.
95 private static final int MSG_SETUP_PREVIEW = 1;
96 private static final int MSG_FIRST_TIME_INIT = 2;
97 private static final int MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE = 3;
98 private static final int MSG_SHOW_TAP_TO_FOCUS_TOAST = 4;
99 private static final int MSG_SWITCH_CAMERA = 5;
100 private static final int MSG_SWITCH_CAMERA_START_ANIMATION = 6;
101 private static final int MSG_CAMERA_OPEN_DONE = 7;
102 private static final int MSG_OPEN_CAMERA_FAIL = 8;
103 private static final int MSG_CAMERA_DISABLED = 9;
104 private static final int MSG_SWITCH_TO_GCAM_MODULE = 10;
Michael Kolb8872c232013-01-29 10:33:22 -0800105
106 // The subset of parameters we need to update in setCameraParameters().
107 private static final int UPDATE_PARAM_INITIALIZE = 1;
108 private static final int UPDATE_PARAM_ZOOM = 2;
109 private static final int UPDATE_PARAM_PREFERENCE = 4;
110 private static final int UPDATE_PARAM_ALL = -1;
111
Andy Huibersdef975d2013-11-22 09:13:39 -0800112 // This is the delay before we execute onResume tasks when coming
113 // from the lock screen, to allow time for onPause to execute.
114 private static final int ON_RESUME_TASKS_DELAY_MSEC = 20;
Michael Kolb8872c232013-01-29 10:33:22 -0800115
Ruben Brunkd7488272013-10-10 18:45:53 -0700116 private static final String DEBUG_IMAGE_PREFIX = "DEBUG_";
117
Michael Kolb8872c232013-01-29 10:33:22 -0800118 // copied from Camera hierarchy
119 private CameraActivity mActivity;
Michael Kolb8872c232013-01-29 10:33:22 -0800120 private CameraProxy mCameraDevice;
121 private int mCameraId;
122 private Parameters mParameters;
123 private boolean mPaused;
Michael Kolbd6954f32013-03-08 20:43:01 -0800124
125 private PhotoUI mUI;
Michael Kolb8872c232013-01-29 10:33:22 -0800126
Michael Kolb8872c232013-01-29 10:33:22 -0800127 // The activity is going to switch to the specified camera id. This is
128 // needed because texture copy is done in GL thread. -1 means camera is not
129 // switching.
130 protected int mPendingSwitchCameraId = -1;
131 private boolean mOpenCameraFail;
132 private boolean mCameraDisabled;
133
134 // When setCameraParametersWhenIdle() is called, we accumulate the subsets
135 // needed to be updated in mUpdateSet.
136 private int mUpdateSet;
137
138 private static final int SCREEN_DELAY = 2 * 60 * 1000;
139
140 private int mZoomValue; // The current zoom value.
Michael Kolb8872c232013-01-29 10:33:22 -0800141
142 private Parameters mInitialParams;
143 private boolean mFocusAreaSupported;
144 private boolean mMeteringAreaSupported;
145 private boolean mAeLockSupported;
146 private boolean mAwbLockSupported;
Angus Kongdcccc512013-08-08 17:06:03 -0700147 private boolean mContinuousFocusSupported;
Michael Kolb8872c232013-01-29 10:33:22 -0800148
149 // The degrees of the device rotated clockwise from its natural orientation.
150 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
Michael Kolb8872c232013-01-29 10:33:22 -0800151
152 private static final String sTempCropFilename = "crop-temp";
153
Michael Kolb8872c232013-01-29 10:33:22 -0800154 private boolean mFaceDetectionStarted = false;
155
Michael Kolb8872c232013-01-29 10:33:22 -0800156 // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
157 private String mCropValue;
158 private Uri mSaveUri;
159
Ruben Brunkd217ed02013-10-08 23:31:13 -0700160 private Uri mDebugUri;
161
Angus Kongce5480e2013-01-29 17:43:48 -0800162 // We use a queue to generated names of the images to be used later
163 // when the image is ready to be saved.
Michael Kolb8872c232013-01-29 10:33:22 -0800164 private NamedImages mNamedImages;
165
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800166 private final Runnable mDoSnapRunnable = new Runnable() {
Michael Kolb8872c232013-01-29 10:33:22 -0800167 @Override
168 public void run() {
169 onShutterButtonClick();
170 }
171 };
172
Michael Kolb8872c232013-01-29 10:33:22 -0800173 /**
174 * An unpublished intent flag requesting to return as soon as capturing
175 * is completed.
176 *
177 * TODO: consider publishing by moving into MediaStore.
178 */
179 private static final String EXTRA_QUICK_CAPTURE =
180 "android.intent.extra.quickCapture";
181
182 // The display rotation in degrees. This is only valid when mCameraState is
183 // not PREVIEW_STOPPED.
184 private int mDisplayRotation;
185 // The value for android.hardware.Camera.setDisplayOrientation.
186 private int mCameraDisplayOrientation;
187 // The value for UI components like indicators.
188 private int mDisplayOrientation;
189 // The value for android.hardware.Camera.Parameters.setRotation.
190 private int mJpegRotation;
Doris Liu29da2db2013-08-28 14:28:45 -0700191 // Indicates whether we are using front camera
192 private boolean mMirror;
Michael Kolb8872c232013-01-29 10:33:22 -0800193 private boolean mFirstTimeInitialized;
194 private boolean mIsImageCaptureIntent;
195
Michael Kolb8872c232013-01-29 10:33:22 -0800196 private int mCameraState = PREVIEW_STOPPED;
197 private boolean mSnapshotOnIdle = false;
198
199 private ContentResolver mContentResolver;
200
201 private LocationManager mLocationManager;
Doris Liu2b906b82013-12-10 16:34:08 -0800202 private AppController mAppController;
Michael Kolb8872c232013-01-29 10:33:22 -0800203
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());
Doris Liu06db7422013-12-09 19:36:25 -0800360 app.setPreviewStatusListener(mUI);
Erin Dahlgren357b7672013-11-20 17:38:14 -0800361
362 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800363 mCameraId = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_CAMERA_ID));
Michael Kolb8872c232013-01-29 10:33:22 -0800364
365 mContentResolver = mActivity.getContentResolver();
366
Michael Kolb8872c232013-01-29 10:33:22 -0800367 // Surface texture is from camera screen nail and startPreview needs it.
368 // This must be done before startPreview.
369 mIsImageCaptureIntent = isImageCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800370
Angus Kong20fad242013-11-11 18:23:46 -0800371 mActivity.getCameraProvider().requestCamera(mCameraId);
372
Michael Kolb8872c232013-01-29 10:33:22 -0800373 initializeControlByIntent();
374 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800375 mLocationManager = mActivity.getLocationManager();
Angus Kong0d00a892013-03-26 11:40:40 -0700376 mSensorManager = (SensorManager)(mActivity.getSystemService(Context.SENSOR_SERVICE));
Doris Liu2b906b82013-12-10 16:34:08 -0800377 mAppController = app;
Michael Kolbd6954f32013-03-08 20:43:01 -0800378 }
379
380 private void initializeControlByIntent() {
381 mUI.initializeControlByIntent();
382 if (mIsImageCaptureIntent) {
383 setupCaptureParams();
384 }
385 }
386
387 private void onPreviewStarted() {
Doris Liu2b906b82013-12-10 16:34:08 -0800388 mAppController.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 mUI.clearFaces();
446 if (mFocusManager != null) mFocusManager.removeMessages();
447
Erin Dahlgren357b7672013-11-20 17:38:14 -0800448 // TODO: this needs to be brought into onCameraAvailable();
Angus Kong20fad242013-11-11 18:23:46 -0800449 CameraInfo info = mActivity.getCameraProvider().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -0700450 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
451 mFocusManager.setMirror(mMirror);
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700452 // Start switch camera animation. Post a message because
453 // onFrameAvailable from the old camera may already exist.
Angus Kong13e87c42013-11-25 10:02:47 -0800454 mHandler.sendEmptyMessage(MSG_SWITCH_CAMERA_START_ANIMATION);
Doris Liu48239f42013-03-04 22:19:10 -0800455 }
456
Sascha Haeberling29f60562013-12-10 12:18:56 -0800457 private final ButtonManager.ButtonCallback mCameraButtonCallback =
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800458 new ButtonManager.ButtonCallback() {
459 @Override
460 public void onStateChanged(int state) {
461 if (mPaused || mPendingSwitchCameraId != -1) {
462 return;
463 }
464 mPendingSwitchCameraId = state;
465
466 Log.v(TAG, "Start to switch camera. cameraId=" + state);
467 // We need to keep a preview frame for the animation before
468 // releasing the camera. This will trigger onPreviewTextureCopied.
469 //TODO: Need to animate the camera switch
470 switchCamera();
471 }
472 };
473
Sascha Haeberling29f60562013-12-10 12:18:56 -0800474 private final ButtonManager.ButtonCallback mHdrPlusButtonCallback =
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800475 new ButtonManager.ButtonCallback() {
476 @Override
477 public void onStateChanged(int state) {
478 mHandler.sendEmptyMessage(MSG_SWITCH_TO_GCAM_MODULE);
479 }
480 };
481
Michael Kolbd6954f32013-03-08 20:43:01 -0800482 // either open a new camera or switch cameras
483 private void openCameraCommon() {
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800484 mUI.onCameraOpened(mParameters, mCameraButtonCallback, mHdrPlusButtonCallback);
Angus Kong0fb819b2013-10-08 13:44:19 -0700485 if (mIsImageCaptureIntent) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800486 // Set hdr plus to default: off.
487 SettingsManager settingsManager = mActivity.getSettingsManager();
488 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_HDR_PLUS);
Angus Kong0fb819b2013-10-08 13:44:19 -0700489 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800490 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -0800491 }
492
ztenghui7b265a62013-09-09 14:58:44 -0700493 @Override
Doris Liu36ebcb12013-10-28 14:44:24 -0700494 public void onPreviewRectChanged(Rect previewRect) {
495 if (mFocusManager != null) mFocusManager.setPreviewRect(previewRect);
Michael Kolbd6954f32013-03-08 20:43:01 -0800496 }
Michael Kolb8872c232013-01-29 10:33:22 -0800497
498 private void resetExposureCompensation() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800499 SettingsManager settingsManager = mActivity.getSettingsManager();
500 if (settingsManager == null) {
501 Log.e(TAG, "Settings manager is null!");
502 return;
Michael Kolb8872c232013-01-29 10:33:22 -0800503 }
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800504 settingsManager.setDefault(SettingsManager.SETTING_EXPOSURE);
Michael Kolb8872c232013-01-29 10:33:22 -0800505 }
506
Michael Kolb8872c232013-01-29 10:33:22 -0800507 // Snapshots can only be taken after this is called. It should be called
508 // once only. We could have done these things in onCreate() but we want to
509 // make preview screen appear as soon as possible.
510 private void initializeFirstTime() {
Sascha Haeberling330dafb2013-10-10 19:00:41 -0700511 if (mFirstTimeInitialized || mPaused) {
512 return;
513 }
Michael Kolb8872c232013-01-29 10:33:22 -0800514
515 // Initialize location service.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800516 SettingsController settingsController = mActivity.getSettingsController();
517 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -0800518
Michael Kolbd6954f32013-03-08 20:43:01 -0800519 mUI.initializeFirstTime();
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800520 MediaSaver s = getServices().getMediaSaver();
Angus Kong86d36312013-01-31 18:22:44 -0800521 // We set the listener only when both service and shutterbutton
522 // are initialized.
523 if (s != null) {
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800524 s.setQueueListener(this);
Angus Kong86d36312013-01-31 18:22:44 -0800525 }
Michael Kolb8872c232013-01-29 10:33:22 -0800526
Michael Kolb8872c232013-01-29 10:33:22 -0800527 mNamedImages = new NamedImages();
528
529 mFirstTimeInitialized = true;
530 addIdleHandler();
531
532 mActivity.updateStorageSpaceAndHint();
533 }
534
Michael Kolbd6954f32013-03-08 20:43:01 -0800535 // If the activity is paused and resumed, this method will be called in
536 // onResume.
537 private void initializeSecondTime() {
538 // Start location update if needed.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800539 SettingsController settingsController = mActivity.getSettingsController();
540 settingsController.syncLocationManager();
541
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800542 MediaSaver s = getServices().getMediaSaver();
Michael Kolbd6954f32013-03-08 20:43:01 -0800543 if (s != null) {
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800544 s.setQueueListener(this);
Michael Kolbd6954f32013-03-08 20:43:01 -0800545 }
546 mNamedImages = new NamedImages();
547 mUI.initializeSecondTime(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -0800548 }
549
Michael Kolb8872c232013-01-29 10:33:22 -0800550 private void addIdleHandler() {
551 MessageQueue queue = Looper.myQueue();
552 queue.addIdleHandler(new MessageQueue.IdleHandler() {
553 @Override
554 public boolean queueIdle() {
555 Storage.ensureOSXCompatible();
556 return false;
557 }
558 });
559 }
560
Sameer Padala2c8cc452013-11-05 18:49:12 -0800561 private void startSmartCamera() {
562 SmartCameraHelper.register(mCameraDevice, mParameters.getPreviewSize(), mActivity,
Doris Liu773e1c92013-12-02 17:35:03 -0800563 (ViewGroup) mActivity.findViewById(R.id.camera_app_root));
Sameer Padala2c8cc452013-11-05 18:49:12 -0800564 }
565
566 private void stopSmartCamera() {
567 SmartCameraHelper.tearDown();
568 }
569
Michael Kolb8872c232013-01-29 10:33:22 -0800570 @Override
571 public void startFaceDetection() {
Michael Kolb8872c232013-01-29 10:33:22 -0800572 if (mFaceDetectionStarted) return;
573 if (mParameters.getMaxNumDetectedFaces() > 0) {
574 mFaceDetectionStarted = true;
Michael Kolb8872c232013-01-29 10:33:22 -0800575 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Michael Kolbd6954f32013-03-08 20:43:01 -0800576 mUI.onStartFaceDetection(mDisplayOrientation,
577 (info.facing == CameraInfo.CAMERA_FACING_FRONT));
Angus Kong9e765522013-07-31 14:05:20 -0700578 mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Michael Kolb8872c232013-01-29 10:33:22 -0800579 mCameraDevice.startFaceDetection();
580 }
581 }
582
Michael Kolb8872c232013-01-29 10:33:22 -0800583 @Override
584 public void stopFaceDetection() {
Michael Kolb8872c232013-01-29 10:33:22 -0800585 if (!mFaceDetectionStarted) return;
586 if (mParameters.getMaxNumDetectedFaces() > 0) {
587 mFaceDetectionStarted = false;
Angus Kong9e765522013-07-31 14:05:20 -0700588 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -0800589 mCameraDevice.stopFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800590 mUI.clearFaces();
Michael Kolb8872c232013-01-29 10:33:22 -0800591 }
592 }
593
Michael Kolb8872c232013-01-29 10:33:22 -0800594 private final class ShutterCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700595 implements CameraShutterCallback {
Angus Kongdcb0ef12013-03-25 23:11:43 -0700596
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800597 private final boolean mNeedsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700598
Sascha Haeberling37f36112013-08-06 14:31:52 -0700599 public ShutterCallback(boolean needsAnimation) {
600 mNeedsAnimation = needsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700601 }
602
Michael Kolb8872c232013-01-29 10:33:22 -0800603 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700604 public void onShutter(CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800605 mShutterCallbackTime = System.currentTimeMillis();
606 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
607 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Sascha Haeberling37f36112013-08-06 14:31:52 -0700608 if (mNeedsAnimation) {
609 mActivity.runOnUiThread(new Runnable() {
610 @Override
611 public void run() {
612 animateAfterShutter();
613 }
614 });
Angus Kongdcb0ef12013-03-25 23:11:43 -0700615 }
Michael Kolb8872c232013-01-29 10:33:22 -0800616 }
617 }
618
Angus Kong9ef99252013-07-18 18:04:19 -0700619 private final class PostViewPictureCallback
620 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800621 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700622 public void onPictureTaken(byte [] data, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800623 mPostViewPictureCallbackTime = System.currentTimeMillis();
624 Log.v(TAG, "mShutterToPostViewCallbackTime = "
625 + (mPostViewPictureCallbackTime - mShutterCallbackTime)
626 + "ms");
627 }
628 }
629
Angus Kong9ef99252013-07-18 18:04:19 -0700630 private final class RawPictureCallback
631 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800632 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700633 public void onPictureTaken(byte [] rawData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800634 mRawPictureCallbackTime = System.currentTimeMillis();
635 Log.v(TAG, "mShutterToRawCallbackTime = "
636 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
637 }
638 }
639
Angus Kong9ef99252013-07-18 18:04:19 -0700640 private final class JpegPictureCallback
641 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800642 Location mLocation;
643
644 public JpegPictureCallback(Location loc) {
645 mLocation = loc;
646 }
647
648 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700649 public void onPictureTaken(final byte [] jpegData, CameraProxy camera) {
Sascha Haeberling88901942013-08-28 17:49:00 -0700650 mUI.enableShutter(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800651 if (mPaused) {
652 return;
653 }
Doris Liu6432cd62013-06-13 17:20:31 -0700654 if (mIsImageCaptureIntent) {
655 stopPreview();
656 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700657 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -0700658 mUI.setSwipingEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800659 }
660
661 mJpegPictureCallbackTime = System.currentTimeMillis();
662 // If postview callback has arrived, the captured image is displayed
663 // in postview callback. If not, the captured image is displayed in
664 // raw picture callback.
665 if (mPostViewPictureCallbackTime != 0) {
666 mShutterToPictureDisplayedTime =
667 mPostViewPictureCallbackTime - mShutterCallbackTime;
668 mPictureDisplayedToJpegCallbackTime =
669 mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
670 } else {
671 mShutterToPictureDisplayedTime =
672 mRawPictureCallbackTime - mShutterCallbackTime;
673 mPictureDisplayedToJpegCallbackTime =
674 mJpegPictureCallbackTime - mRawPictureCallbackTime;
675 }
676 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
677 + mPictureDisplayedToJpegCallbackTime + "ms");
678
Michael Kolb8872c232013-01-29 10:33:22 -0800679 mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
680 if (!mIsImageCaptureIntent) {
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700681 setupPreview();
Michael Kolb8872c232013-01-29 10:33:22 -0800682 }
683
Doris Liu36e56fb2013-09-11 17:38:08 -0700684 ExifInterface exif = Exif.getExif(jpegData);
685 int orientation = Exif.getOrientation(exif);
Ruben Brunkd217ed02013-10-08 23:31:13 -0700686
Ruben Brunkd7488272013-10-10 18:45:53 -0700687 if (!mIsImageCaptureIntent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800688 // Calculate the width and the height of the jpeg.
689 Size s = mParameters.getPictureSize();
Michael Kolb8872c232013-01-29 10:33:22 -0800690 int width, height;
691 if ((mJpegRotation + orientation) % 180 == 0) {
692 width = s.width;
693 height = s.height;
694 } else {
695 width = s.height;
696 height = s.width;
697 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700698 NamedEntity name = mNamedImages.getNextNameEntity();
699 String title = (name == null) ? null : name.title;
700 long date = (name == null) ? -1 : name.date;
Ruben Brunkd7488272013-10-10 18:45:53 -0700701
702 // Handle debug mode outputs
703 if (mDebugUri != null) {
704 // If using a debug uri, save jpeg there.
705 saveToDebugUri(jpegData);
706
707 // Adjust the title of the debug image shown in mediastore.
708 if (title != null) {
709 title = DEBUG_IMAGE_PREFIX + title;
710 }
711 }
712
Michael Kolb8872c232013-01-29 10:33:22 -0800713 if (title == null) {
714 Log.e(TAG, "Unbalanced name/data pair");
715 } else {
716 if (date == -1) date = mCaptureStartTime;
Angus Kong0d00a892013-03-26 11:40:40 -0700717 if (mHeading >= 0) {
718 // heading direction has been updated by the sensor.
719 ExifTag directionRefTag = exif.buildTag(
720 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
721 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
722 ExifTag directionTag = exif.buildTag(
723 ExifInterface.TAG_GPS_IMG_DIRECTION,
724 new Rational(mHeading, 1));
725 exif.setTag(directionRefTag);
726 exif.setTag(directionTag);
727 }
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800728 getServices().getMediaSaver().addImage(
Angus Kong86d36312013-01-31 18:22:44 -0800729 jpegData, title, date, mLocation, width, height,
Angus Kong0d00a892013-03-26 11:40:40 -0700730 orientation, exif, mOnMediaSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -0800731 }
Doris Liuce2acbc2013-08-21 18:45:29 -0700732 // Animate capture with real jpeg data instead of a preview frame.
Doris Liu29da2db2013-08-28 14:28:45 -0700733 mUI.animateCapture(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800734 } else {
735 mJpegImageData = jpegData;
736 if (!mQuickCapture) {
Doris Liu36e56fb2013-09-11 17:38:08 -0700737 mUI.showCapturedImageForReview(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800738 } else {
Michael Kolbd6954f32013-03-08 20:43:01 -0800739 onCaptureDone();
Michael Kolb8872c232013-01-29 10:33:22 -0800740 }
741 }
742
743 // Check this in advance of each shot so we don't add to shutter
744 // latency. It's true that someone else could write to the SD card in
745 // the mean time and fill it, but that could have happened between the
746 // shutter press and saving the JPEG too.
747 mActivity.updateStorageSpaceAndHint();
748
749 long now = System.currentTimeMillis();
750 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
751 Log.v(TAG, "mJpegCallbackFinishTime = "
752 + mJpegCallbackFinishTime + "ms");
753 mJpegPictureCallbackTime = 0;
754 }
755 }
756
Angus Kong9ef99252013-07-18 18:04:19 -0700757 private final class AutoFocusCallback implements CameraAFCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800758 @Override
759 public void onAutoFocus(
Angus Kong9ef99252013-07-18 18:04:19 -0700760 boolean focused, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800761 if (mPaused) return;
762
763 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
764 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
765 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800766 mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
Michael Kolb8872c232013-01-29 10:33:22 -0800767 }
768 }
769
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700770 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -0800771 private final class AutoFocusMoveCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700772 implements CameraAFMoveCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800773 @Override
774 public void onAutoFocusMoving(
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700775 boolean moving, CameraProxy camera) {
776 mFocusManager.onAutoFocusMoving(moving);
Michael Kolb8872c232013-01-29 10:33:22 -0800777 }
778 }
779
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700780 /**
781 * This class is just a thread-safe queue for name,date holder objects.
782 */
783 public static class NamedImages {
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800784 private final Vector<NamedEntity> mQueue;
Michael Kolb8872c232013-01-29 10:33:22 -0800785
786 public NamedImages() {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700787 mQueue = new Vector<NamedEntity>();
Michael Kolb8872c232013-01-29 10:33:22 -0800788 }
789
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700790 public void nameNewImage(long date) {
Michael Kolb8872c232013-01-29 10:33:22 -0800791 NamedEntity r = new NamedEntity();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700792 r.title = CameraUtil.createJpegName(date);
Michael Kolb8872c232013-01-29 10:33:22 -0800793 r.date = date;
794 mQueue.add(r);
795 }
796
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700797 public NamedEntity getNextNameEntity() {
798 synchronized(mQueue) {
799 if (!mQueue.isEmpty()) {
800 return mQueue.remove(0);
801 }
Michael Kolb8872c232013-01-29 10:33:22 -0800802 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700803 return null;
Michael Kolb8872c232013-01-29 10:33:22 -0800804 }
805
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700806 public static class NamedEntity {
807 public String title;
808 public long date;
Michael Kolb8872c232013-01-29 10:33:22 -0800809 }
810 }
811
812 private void setCameraState(int state) {
813 mCameraState = state;
814 switch (state) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700815 case PhotoController.PREVIEW_STOPPED:
816 case PhotoController.SNAPSHOT_IN_PROGRESS:
817 case PhotoController.SWITCHING_CAMERA:
Doris Liuf55f3c42013-11-20 00:24:46 -0800818 // TODO: Tell app UI to disable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700819 break;
820 case PhotoController.IDLE:
Doris Liuf55f3c42013-11-20 00:24:46 -0800821 // TODO: Tell app UI to enable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700822 break;
Michael Kolb8872c232013-01-29 10:33:22 -0800823 }
824 }
825
Sascha Haeberling37f36112013-08-06 14:31:52 -0700826 private void animateAfterShutter() {
Michael Kolb8872c232013-01-29 10:33:22 -0800827 // Only animate when in full screen capture mode
828 // i.e. If monkey/a user swipes to the gallery during picture taking,
829 // don't show animation
Doris Liuc2e9abd2013-06-19 14:20:51 -0700830 if (!mIsImageCaptureIntent) {
831 mUI.animateFlash();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700832 }
Michael Kolb8872c232013-01-29 10:33:22 -0800833 }
834
835 @Override
836 public boolean capture() {
837 // If we are already in the middle of taking a snapshot or the image save request
838 // is full then ignore.
839 if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
Angus Kong86d36312013-01-31 18:22:44 -0800840 || mCameraState == SWITCHING_CAMERA
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800841 || getServices().getMediaSaver() == null
842 || getServices().getMediaSaver().isQueueFull()) {
Michael Kolb8872c232013-01-29 10:33:22 -0800843 return false;
844 }
845 mCaptureStartTime = System.currentTimeMillis();
846 mPostViewPictureCallbackTime = 0;
847 mJpegImageData = null;
848
Angus Kongb50b5cb2013-08-09 14:55:20 -0700849 final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
Michael Kolb8872c232013-01-29 10:33:22 -0800850
851 if (animateBefore) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700852 animateAfterShutter();
Michael Kolb8872c232013-01-29 10:33:22 -0800853 }
854
855 // Set rotation and gps data.
Doris Liu3cf565c2013-02-15 10:55:37 -0800856 int orientation;
857 // We need to be consistent with the framework orientation (i.e. the
858 // orientation of the UI.) when the auto-rotate screen setting is on.
859 if (mActivity.isAutoRotateScreen()) {
860 orientation = (360 - mDisplayRotation) % 360;
861 } else {
862 orientation = mOrientation;
863 }
Angus Kong20fad242013-11-11 18:23:46 -0800864 mJpegRotation = CameraUtil.getJpegRotation(mActivity, mCameraId, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800865 mParameters.setRotation(mJpegRotation);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800866 Location loc = mActivity.getLocationManager().getCurrentLocation();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700867 CameraUtil.setGpsParameters(mParameters, loc);
Michael Kolb8872c232013-01-29 10:33:22 -0800868 mCameraDevice.setParameters(mParameters);
869
Sascha Haeberling88901942013-08-28 17:49:00 -0700870 // We don't want user to press the button again while taking a
871 // multi-second HDR photo.
872 mUI.enableShutter(false);
Angus Kong9ef99252013-07-18 18:04:19 -0700873 mCameraDevice.takePicture(mHandler,
874 new ShutterCallback(!animateBefore),
Angus Kongdcb0ef12013-03-25 23:11:43 -0700875 mRawPictureCallback, mPostViewPictureCallback,
Angus Kong9ef99252013-07-18 18:04:19 -0700876 new JpegPictureCallback(loc));
Michael Kolb8872c232013-01-29 10:33:22 -0800877
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700878 mNamedImages.nameNewImage(mCaptureStartTime);
Michael Kolb8872c232013-01-29 10:33:22 -0800879
880 mFaceDetectionStarted = false;
881 setCameraState(SNAPSHOT_IN_PROGRESS);
Bobby Georgescu301b6462013-04-01 15:33:17 -0700882 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
Seth Raphaelcbd82672013-11-05 10:12:36 -0800883 UsageStatistics.ACTION_CAPTURE_DONE, "Photo", 0,
Seth Raphael44973262013-11-27 14:29:24 -0800884 UsageStatistics.hashFileName(mNamedImages.mQueue.lastElement().title + ".jpg"));
Michael Kolb8872c232013-01-29 10:33:22 -0800885 return true;
886 }
887
888 @Override
889 public void setFocusParameters() {
890 setCameraParameters(UPDATE_PARAM_PREFERENCE);
891 }
892
Michael Kolbd6954f32013-03-08 20:43:01 -0800893 private void updateSceneMode() {
Michael Kolb8872c232013-01-29 10:33:22 -0800894 // If scene mode is set, we cannot set flash mode, white balance, and
895 // focus mode, instead, we read it from driver
896 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
897 overrideCameraSettings(mParameters.getFlashMode(),
898 mParameters.getWhiteBalance(), mParameters.getFocusMode());
899 } else {
900 overrideCameraSettings(null, null, null);
901 }
902 }
903
904 private void overrideCameraSettings(final String flashMode,
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700905 final String whiteBalance, final String focusMode) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800906 SettingsManager settingsManager = mActivity.getSettingsManager();
907 settingsManager.set(SettingsManager.SETTING_FLASH_MODE, flashMode);
908 settingsManager.set(SettingsManager.SETTING_WHITE_BALANCE, whiteBalance);
909 settingsManager.set(SettingsManager.SETTING_FOCUS_MODE, focusMode);
Michael Kolb8872c232013-01-29 10:33:22 -0800910 }
911
912 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800913 public void onOrientationChanged(int orientation) {
914 // We keep the last known orientation. So if the user first orient
915 // the camera then point the camera to floor or sky, we still have
916 // the correct orientation.
917 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700918 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800919
920 // Show the toast after getting the first orientation changed.
Angus Kong13e87c42013-11-25 10:02:47 -0800921 if (mHandler.hasMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST)) {
922 mHandler.removeMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST);
Michael Kolb8872c232013-01-29 10:33:22 -0800923 showTapToFocusToast();
924 }
925 }
926
927 @Override
Angus Kong20fad242013-11-11 18:23:46 -0800928 public void onCameraAvailable(CameraProxy cameraProxy) {
929 if (mPaused) {
930 return;
931 }
932 mCameraDevice = cameraProxy;
933
Erin Dahlgren357b7672013-11-20 17:38:14 -0800934 resetExposureCompensation();
Angus Kong20fad242013-11-11 18:23:46 -0800935 initializeCapabilities();
936
937 // Reset zoom value index.
938 mZoomValue = 0;
939 if (mFocusManager == null) {
940 initializeFocusManager();
941 }
942 mFocusManager.setParameters(mInitialParams);
943
944 mParameters = mCameraDevice.getParameters();
945 setCameraParameters(UPDATE_PARAM_ALL);
946 mCameraPreviewParamsReady = true;
947 startPreview();
948
949 onCameraOpened();
950 }
951
952 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -0800953 public void onCaptureCancelled() {
954 mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
955 mActivity.finish();
Michael Kolb8872c232013-01-29 10:33:22 -0800956 }
957
Michael Kolbd6954f32013-03-08 20:43:01 -0800958 @Override
959 public void onCaptureRetake() {
Michael Kolb8872c232013-01-29 10:33:22 -0800960 if (mPaused)
961 return;
Michael Kolbd6954f32013-03-08 20:43:01 -0800962 mUI.hidePostCaptureAlert();
Michael Kolb8872c232013-01-29 10:33:22 -0800963 setupPreview();
964 }
965
Michael Kolbd6954f32013-03-08 20:43:01 -0800966 @Override
967 public void onCaptureDone() {
Michael Kolb8872c232013-01-29 10:33:22 -0800968 if (mPaused) {
969 return;
970 }
971
972 byte[] data = mJpegImageData;
973
974 if (mCropValue == null) {
975 // First handle the no crop case -- just return the value. If the
976 // caller specifies a "save uri" then write the data to its
977 // stream. Otherwise, pass back a scaled down version of the bitmap
978 // directly in the extras.
979 if (mSaveUri != null) {
980 OutputStream outputStream = null;
981 try {
982 outputStream = mContentResolver.openOutputStream(mSaveUri);
983 outputStream.write(data);
984 outputStream.close();
985
986 mActivity.setResultEx(Activity.RESULT_OK);
987 mActivity.finish();
988 } catch (IOException ex) {
989 // ignore exception
990 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700991 CameraUtil.closeSilently(outputStream);
Michael Kolb8872c232013-01-29 10:33:22 -0800992 }
993 } else {
Angus Kong0d00a892013-03-26 11:40:40 -0700994 ExifInterface exif = Exif.getExif(data);
995 int orientation = Exif.getOrientation(exif);
Angus Kongb50b5cb2013-08-09 14:55:20 -0700996 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
997 bitmap = CameraUtil.rotate(bitmap, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800998 mActivity.setResultEx(Activity.RESULT_OK,
999 new Intent("inline-data").putExtra("data", bitmap));
1000 mActivity.finish();
1001 }
1002 } else {
1003 // Save the image to a temp file and invoke the cropper
1004 Uri tempUri = null;
1005 FileOutputStream tempStream = null;
1006 try {
1007 File path = mActivity.getFileStreamPath(sTempCropFilename);
1008 path.delete();
1009 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1010 tempStream.write(data);
1011 tempStream.close();
1012 tempUri = Uri.fromFile(path);
1013 } catch (FileNotFoundException ex) {
1014 mActivity.setResultEx(Activity.RESULT_CANCELED);
1015 mActivity.finish();
1016 return;
1017 } catch (IOException ex) {
1018 mActivity.setResultEx(Activity.RESULT_CANCELED);
1019 mActivity.finish();
1020 return;
1021 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001022 CameraUtil.closeSilently(tempStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001023 }
1024
1025 Bundle newExtras = new Bundle();
1026 if (mCropValue.equals("circle")) {
1027 newExtras.putString("circleCrop", "true");
1028 }
1029 if (mSaveUri != null) {
1030 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1031 } else {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001032 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001033 }
1034 if (mActivity.isSecureCamera()) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001035 newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001036 }
1037
Sascha Haeberling37f36112013-08-06 14:31:52 -07001038 // TODO: Share this constant.
Sascha Haeberling8e963a52013-08-06 11:43:02 -07001039 final String CROP_ACTION = "com.android.camera.action.CROP";
1040 Intent cropIntent = new Intent(CROP_ACTION);
Michael Kolb8872c232013-01-29 10:33:22 -08001041
1042 cropIntent.setData(tempUri);
1043 cropIntent.putExtras(newExtras);
1044
1045 mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1046 }
1047 }
1048
Michael Kolb8872c232013-01-29 10:33:22 -08001049 @Override
1050 public void onShutterButtonFocus(boolean pressed) {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001051 if (mPaused || (mCameraState == SNAPSHOT_IN_PROGRESS)
Michael Kolb8872c232013-01-29 10:33:22 -08001052 || (mCameraState == PREVIEW_STOPPED)) return;
1053
1054 // Do not do focus if there is not enough storage.
1055 if (pressed && !canTakePicture()) return;
1056
1057 if (pressed) {
Michael Kolb8872c232013-01-29 10:33:22 -08001058 mFocusManager.onShutterDown();
1059 } else {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001060 mFocusManager.onShutterUp();
Michael Kolb8872c232013-01-29 10:33:22 -08001061 }
1062 }
1063
1064 @Override
1065 public void onShutterButtonClick() {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001066 if (mPaused || (mCameraState == SWITCHING_CAMERA)
Michael Kolb8872c232013-01-29 10:33:22 -08001067 || (mCameraState == PREVIEW_STOPPED)) return;
1068
1069 // Do not take the picture if there is not enough storage.
Angus Kong2dcc0a92013-09-25 13:00:08 -07001070 if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Michael Kolb8872c232013-01-29 10:33:22 -08001071 Log.i(TAG, "Not enough space or storage not ready. remaining="
Angus Kong2dcc0a92013-09-25 13:00:08 -07001072 + mActivity.getStorageSpaceBytes());
Michael Kolb8872c232013-01-29 10:33:22 -08001073 return;
1074 }
1075 Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1076
Angus Kongb50b5cb2013-08-09 14:55:20 -07001077 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -07001078 mUI.setSwipingEnabled(false);
Doris Liu9cdfe002013-04-16 09:50:56 -07001079 }
Michael Kolb8872c232013-01-29 10:33:22 -08001080 // If the user wants to do a snapshot while the previous one is still
1081 // in progress, remember the fact and do it after we finish the previous
1082 // one and re-start the preview. Snapshot in progress also includes the
1083 // state that autofocus is focusing and a picture will be taken when
1084 // focus callback arrives.
1085 if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1086 && !mIsImageCaptureIntent) {
1087 mSnapshotOnIdle = true;
1088 return;
1089 }
1090
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001091 mSnapshotOnIdle = false;
1092 mFocusManager.doSnap();
Michael Kolb8872c232013-01-29 10:33:22 -08001093 }
1094
Andy Huibersdef975d2013-11-22 09:13:39 -08001095 private void onResumeTasks() {
1096 Log.v(TAG, "Executing onResumeTasks.");
Michael Kolb8872c232013-01-29 10:33:22 -08001097 if (mOpenCameraFail || mCameraDisabled) return;
1098
Angus Kong20fad242013-11-11 18:23:46 -08001099 mActivity.getCameraProvider().requestCamera(mCameraId);
1100
Michael Kolb8872c232013-01-29 10:33:22 -08001101 mJpegPictureCallbackTime = 0;
1102 mZoomValue = 0;
Angus Kong20fad242013-11-11 18:23:46 -08001103
1104 mOnResumeTime = SystemClock.uptimeMillis();
1105 checkDisplayRotation();
Michael Kolb8872c232013-01-29 10:33:22 -08001106
1107 // If first time initialization is not finished, put it in the
1108 // message queue.
1109 if (!mFirstTimeInitialized) {
Angus Kong13e87c42013-11-25 10:02:47 -08001110 mHandler.sendEmptyMessage(MSG_FIRST_TIME_INIT);
Michael Kolb8872c232013-01-29 10:33:22 -08001111 } else {
1112 initializeSecondTime();
1113 }
Michael Kolb8872c232013-01-29 10:33:22 -08001114
Bobby Georgescu0a7dd572013-03-12 22:45:17 -07001115 UsageStatistics.onContentViewChanged(
1116 UsageStatistics.COMPONENT_CAMERA, "PhotoModule");
Angus Kong0d00a892013-03-26 11:40:40 -07001117
1118 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1119 if (gsensor != null) {
1120 mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1121 }
1122
1123 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1124 if (msensor != null) {
1125 mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1126 }
Michael Kolb8872c232013-01-29 10:33:22 -08001127 }
1128
Angus Kongc4e66562013-11-22 23:03:21 -08001129 /**
1130 * The focus manager is the first UI related element to get initialized,
1131 * and it requires the RenderOverlay, so initialize it here
1132 */
1133 private void initializeFocusManager() {
1134 // Create FocusManager object. startPreview needs it.
1135 // if mFocusManager not null, reuse it
1136 // otherwise create a new instance
1137 if (mFocusManager != null) {
1138 mFocusManager.removeMessages();
1139 } else {
1140 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
1141 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
1142 String[] defaultFocusModes = mActivity.getResources().getStringArray(
1143 R.array.pref_camera_focusmode_default_array);
Erin Dahlgren357b7672013-11-20 17:38:14 -08001144 mFocusManager = new FocusOverlayManager(mActivity.getSettingsManager(),
1145 defaultFocusModes,
Angus Kongc4e66562013-11-22 23:03:21 -08001146 mInitialParams, this, mMirror,
1147 mActivity.getMainLooper(), mUI);
1148 }
Angus Kong20fad242013-11-11 18:23:46 -08001149 }
1150
1151 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001152 public void resume() {
1153 mPaused = false;
1154 // Add delay on resume from lock screen only, in order to to speed up
1155 // the onResume --> onPause --> onResume cycle from lock screen.
1156 // Don't do always because letting go of thread can cause delay.
1157 String action = mActivity.getIntent().getAction();
1158 if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
1159 || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
1160 Log.v(TAG, "On resume, from lock screen.");
1161 // Note: onPauseAfterSuper() will delete this runnable, so we will
1162 // at most have 1 copy queued up.
1163 mHandler.postDelayed(new Runnable() {
Sameer Padala2c8cc452013-11-05 18:49:12 -08001164 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001165 public void run() {
1166 onResumeTasks();
1167 }
1168 }, ON_RESUME_TASKS_DELAY_MSEC);
1169 } else {
1170 Log.v(TAG, "On resume.");
1171 onResumeTasks();
1172 }
1173 }
1174
1175 @Override
1176 public void pause() {
Michael Kolb8872c232013-01-29 10:33:22 -08001177 mPaused = true;
Angus Kong0d00a892013-03-26 11:40:40 -07001178 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1179 if (gsensor != null) {
1180 mSensorManager.unregisterListener(this, gsensor);
1181 }
1182
1183 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1184 if (msensor != null) {
1185 mSensorManager.unregisterListener(this, msensor);
1186 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001187
Michael Kolb8872c232013-01-29 10:33:22 -08001188 // Reset the focus first. Camera CTS does not guarantee that
1189 // cancelAutoFocus is allowed after preview stops.
1190 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1191 mCameraDevice.cancelAutoFocus();
1192 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001193
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -08001194 // If the camera has not been opened asynchronously yet,
1195 // and startPreview hasn't been called, then this is a no-op.
1196 // (e.g. onResume -> onPause -> onResume).
Michael Kolb8872c232013-01-29 10:33:22 -08001197 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001198
Angus Kongce5480e2013-01-29 17:43:48 -08001199 mNamedImages = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001200
1201 if (mLocationManager != null) mLocationManager.recordLocation(false);
1202
1203 // If we are in an image capture intent and has taken
1204 // a picture, we just clear it in onPause.
1205 mJpegImageData = null;
1206
Angus Kongdcccc512013-08-08 17:06:03 -07001207 // Remove the messages and runnables in the queue.
1208 mHandler.removeCallbacksAndMessages(null);
Michael Kolb8872c232013-01-29 10:33:22 -08001209
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001210 closeCamera();
Angus Kong13e87c42013-11-25 10:02:47 -08001211 mActivity.enableKeepScreenOn(false);
Michael Kolbd6954f32013-03-08 20:43:01 -08001212 mUI.onPause();
1213
Michael Kolb8872c232013-01-29 10:33:22 -08001214 mPendingSwitchCameraId = -1;
1215 if (mFocusManager != null) mFocusManager.removeMessages();
Sascha Haeberling280fd3e2013-11-21 13:52:15 -08001216 MediaSaver s = getServices().getMediaSaver();
Angus Kong86d36312013-01-31 18:22:44 -08001217 if (s != null) {
Angus Kongfd4fc0e2013-11-07 15:38:09 -08001218 s.setQueueListener(null);
Angus Kong86d36312013-01-31 18:22:44 -08001219 }
Michael Kolb8872c232013-01-29 10:33:22 -08001220 }
1221
Angus Kong20fad242013-11-11 18:23:46 -08001222 @Override
1223 public void destroy() {
1224 // TODO: implement this.
1225 }
1226
1227 @Override
1228 public void onPreviewSizeChanged(int width, int height) {
1229 // TODO: implement this.
1230 }
1231
1232 @Override
Angus Kong2f0e4a32013-12-03 10:02:35 -08001233 public void onLayoutOrientationChanged(boolean isLandscape) {
Michael Kolb8872c232013-01-29 10:33:22 -08001234 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001235 }
1236
1237 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001238 public void updateCameraOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001239 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001240 setDisplayOrientation();
1241 }
1242 }
1243
Michael Kolb8872c232013-01-29 10:33:22 -08001244 private boolean canTakePicture() {
Angus Kong2dcc0a92013-09-25 13:00:08 -07001245 return isCameraIdle() && (mActivity.getStorageSpaceBytes() > Storage.LOW_STORAGE_THRESHOLD_BYTES);
Michael Kolb8872c232013-01-29 10:33:22 -08001246 }
1247
1248 @Override
1249 public void autoFocus() {
1250 mFocusStartTime = System.currentTimeMillis();
Angus Kong9ef99252013-07-18 18:04:19 -07001251 mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001252 setCameraState(FOCUSING);
1253 }
1254
1255 @Override
1256 public void cancelAutoFocus() {
1257 mCameraDevice.cancelAutoFocus();
1258 setCameraState(IDLE);
1259 setCameraParameters(UPDATE_PARAM_PREFERENCE);
1260 }
1261
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001262 // Preview area is touched.
Michael Kolb8872c232013-01-29 10:33:22 -08001263 @Override
1264 public void onSingleTapUp(View view, int x, int y) {
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001265 if (mUI.isImmediateCapture()) {
1266 cancelAutoFocus();
1267 onShutterButtonClick();
1268 } else {
1269 onShutterButtonFocus(true);
1270 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001271 }
Michael Kolb8872c232013-01-29 10:33:22 -08001272 }
1273
1274 @Override
1275 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001276 return mUI.onBackPressed();
Michael Kolb8872c232013-01-29 10:33:22 -08001277 }
1278
1279 @Override
1280 public boolean onKeyDown(int keyCode, KeyEvent event) {
1281 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001282 case KeyEvent.KEYCODE_VOLUME_UP:
1283 case KeyEvent.KEYCODE_VOLUME_DOWN:
1284 case KeyEvent.KEYCODE_FOCUS:
1285 if (/*TODO: mActivity.isInCameraApp() &&*/ mFirstTimeInitialized) {
1286 if (event.getRepeatCount() == 0) {
1287 onShutterButtonFocus(true);
1288 }
1289 return true;
1290 }
1291 return false;
1292 case KeyEvent.KEYCODE_CAMERA:
1293 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1294 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001295 }
1296 return true;
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001297 case KeyEvent.KEYCODE_DPAD_CENTER:
1298 // If we get a dpad center event without any focused view, move
1299 // the focus to the shutter button and press it.
1300 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1301 // Start auto-focus immediately to reduce shutter lag. After
1302 // the shutter button gets the focus, onShutterButtonFocus()
1303 // will be called again but it is fine.
1304 onShutterButtonFocus(true);
1305 mUI.pressShutterButton();
1306 }
1307 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001308 }
1309 return false;
1310 }
1311
1312 @Override
1313 public boolean onKeyUp(int keyCode, KeyEvent event) {
1314 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001315 case KeyEvent.KEYCODE_VOLUME_UP:
1316 case KeyEvent.KEYCODE_VOLUME_DOWN:
1317 if (/*mActivity.isInCameraApp() && */ mFirstTimeInitialized) {
1318 onShutterButtonClick();
1319 return true;
1320 }
1321 return false;
1322 case KeyEvent.KEYCODE_FOCUS:
1323 if (mFirstTimeInitialized) {
1324 onShutterButtonFocus(false);
1325 }
Michael Kolb8872c232013-01-29 10:33:22 -08001326 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001327 }
1328 return false;
1329 }
1330
Michael Kolb8872c232013-01-29 10:33:22 -08001331 private void closeCamera() {
1332 if (mCameraDevice != null) {
1333 mCameraDevice.setZoomChangeListener(null);
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001334 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001335 mCameraDevice.setErrorCallback(null);
Ruben Brunk59147832013-11-05 15:53:28 -08001336
Michael Kolb8872c232013-01-29 10:33:22 -08001337 mFaceDetectionStarted = false;
Angus Kong20fad242013-11-11 18:23:46 -08001338 mActivity.getCameraProvider().releaseCamera(mCameraDevice.getCameraId());
Michael Kolb8872c232013-01-29 10:33:22 -08001339 mCameraDevice = null;
1340 setCameraState(PREVIEW_STOPPED);
1341 mFocusManager.onCameraReleased();
1342 }
1343 }
1344
1345 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001346 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1347 mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001348 mCameraDisplayOrientation = mDisplayOrientation;
Michael Kolbd6954f32013-03-08 20:43:01 -08001349 mUI.setDisplayOrientation(mDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001350 if (mFocusManager != null) {
1351 mFocusManager.setDisplayOrientation(mDisplayOrientation);
1352 }
Doris Liu6432cd62013-06-13 17:20:31 -07001353 // Change the camera display orientation
1354 if (mCameraDevice != null) {
1355 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1356 }
Michael Kolb8872c232013-01-29 10:33:22 -08001357 }
1358
Sascha Haeberlingddef7792013-08-13 14:41:10 -07001359 /** Only called by UI thread. */
Michael Kolb8872c232013-01-29 10:33:22 -08001360 private void setupPreview() {
1361 mFocusManager.resetTouchFocus();
1362 startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001363 }
1364
Angus Kong20fad242013-11-11 18:23:46 -08001365 /**
1366 * Returns whether we can/should start the preview or not.
1367 */
1368 private boolean checkPreviewPreconditions() {
1369 if (mPaused) {
1370 return false;
Angus Kongdcccc512013-08-08 17:06:03 -07001371 }
Michael Kolb8872c232013-01-29 10:33:22 -08001372
Angus Kong20fad242013-11-11 18:23:46 -08001373 if (mCameraDevice == null) {
1374 Log.w(TAG, "startPreview: camera device not ready yet.");
1375 return false;
1376 }
1377
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001378 SurfaceTexture st = mUI.getSurfaceTexture();
1379 if (st == null) {
1380 Log.w(TAG, "startPreview: surfaceTexture is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001381 return false;
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001382 }
1383
1384 if (!mCameraPreviewParamsReady) {
1385 Log.w(TAG, "startPreview: parameters for preview is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001386 return false;
1387 }
1388 return true;
1389 }
1390
1391 /**
1392 * The start/stop preview should only run on the UI thread.
1393 */
1394 private void startPreview() {
1395 if (!checkPreviewPreconditions()) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001396 return;
1397 }
Angus Kong20fad242013-11-11 18:23:46 -08001398
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001399 mCameraDevice.setErrorCallback(mErrorCallback);
1400 // ICS camera frameworks has a bug. Face detection state is not cleared 1589
1401 // after taking a picture. Stop the preview to work around it. The bug
1402 // was fixed in JB.
1403 if (mCameraState != PREVIEW_STOPPED) {
1404 stopPreview();
1405 }
1406
1407 setDisplayOrientation();
1408
1409 if (!mSnapshotOnIdle) {
1410 // If the focus mode is continuous autofocus, call cancelAutoFocus to
1411 // resume it because it may have been paused by autoFocus call.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001412 String focusMode = mFocusManager.getFocusMode();
1413 if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(focusMode)) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001414 mCameraDevice.cancelAutoFocus();
Michael Kolb8872c232013-01-29 10:33:22 -08001415 }
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001416 mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1417 }
1418 setCameraParameters(UPDATE_PARAM_ALL);
1419 // Let UI set its expected aspect ratio
Angus Kong20fad242013-11-11 18:23:46 -08001420 mCameraDevice.setPreviewTexture(mUI.getSurfaceTexture());
Michael Kolb8872c232013-01-29 10:33:22 -08001421
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001422 Log.v(TAG, "startPreview");
1423 mCameraDevice.startPreview();
Angus Kong20fad242013-11-11 18:23:46 -08001424
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001425 mFocusManager.onPreviewStarted();
1426 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001427
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001428 if (mSnapshotOnIdle) {
1429 mHandler.post(mDoSnapRunnable);
Michael Kolb8872c232013-01-29 10:33:22 -08001430 }
1431 }
1432
Michael Kolbd6954f32013-03-08 20:43:01 -08001433 @Override
1434 public void stopPreview() {
Michael Kolb8872c232013-01-29 10:33:22 -08001435 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1436 Log.v(TAG, "stopPreview");
1437 mCameraDevice.stopPreview();
1438 mFaceDetectionStarted = false;
1439 }
1440 setCameraState(PREVIEW_STOPPED);
1441 if (mFocusManager != null) mFocusManager.onPreviewStopped();
Sameer Padala2c8cc452013-11-05 18:49:12 -08001442 stopSmartCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001443 }
1444
1445 @SuppressWarnings("deprecation")
1446 private void updateCameraParametersInitialize() {
1447 // Reset preview frame rate to the maximum because it may be lowered by
1448 // video camera application.
ztenghui16a35202013-09-23 11:35:36 -07001449 int[] fpsRange = CameraUtil.getPhotoPreviewFpsRange(mParameters);
1450 if (fpsRange != null && fpsRange.length > 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001451 mParameters.setPreviewFpsRange(
1452 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1453 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
Michael Kolb8872c232013-01-29 10:33:22 -08001454 }
1455
Angus Kongb50b5cb2013-08-09 14:55:20 -07001456 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);
Michael Kolb8872c232013-01-29 10:33:22 -08001457
1458 // Disable video stabilization. Convenience methods not available in API
1459 // level <= 14
1460 String vstabSupported = mParameters.get("video-stabilization-supported");
1461 if ("true".equals(vstabSupported)) {
1462 mParameters.set("video-stabilization", "false");
1463 }
1464 }
1465
1466 private void updateCameraParametersZoom() {
1467 // Set zoom.
1468 if (mParameters.isZoomSupported()) {
1469 mParameters.setZoom(mZoomValue);
1470 }
1471 }
1472
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001473 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001474 private void setAutoExposureLockIfSupported() {
1475 if (mAeLockSupported) {
1476 mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1477 }
1478 }
1479
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001480 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001481 private void setAutoWhiteBalanceLockIfSupported() {
1482 if (mAwbLockSupported) {
1483 mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1484 }
1485 }
1486
Michael Kolb8872c232013-01-29 10:33:22 -08001487 private void setFocusAreasIfSupported() {
1488 if (mFocusAreaSupported) {
1489 mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1490 }
1491 }
1492
Michael Kolb8872c232013-01-29 10:33:22 -08001493 private void setMeteringAreasIfSupported() {
1494 if (mMeteringAreaSupported) {
Michael Kolb8872c232013-01-29 10:33:22 -08001495 mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1496 }
1497 }
1498
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001499 private boolean updateCameraParametersPreference() {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001500 SettingsManager settingsManager = mActivity.getSettingsManager();
1501
Michael Kolb8872c232013-01-29 10:33:22 -08001502 setAutoExposureLockIfSupported();
1503 setAutoWhiteBalanceLockIfSupported();
1504 setFocusAreasIfSupported();
1505 setMeteringAreasIfSupported();
1506
Michael Kolbd3253f22013-07-12 11:36:47 -07001507 // initialize focus mode
1508 mFocusManager.overrideFocusMode(null);
1509 mParameters.setFocusMode(mFocusManager.getFocusMode());
1510
Michael Kolb8872c232013-01-29 10:33:22 -08001511 // Set picture size.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001512 String pictureSize = settingsManager.get(SettingsManager.SETTING_PICTURE_SIZE);
Michael Kolb8872c232013-01-29 10:33:22 -08001513 if (pictureSize == null) {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001514 //TODO: deprecate CameraSettings.
1515 CameraSettings.initialCameraPictureSize(
1516 mActivity, mParameters, settingsManager);
Michael Kolb8872c232013-01-29 10:33:22 -08001517 } else {
1518 List<Size> supported = mParameters.getSupportedPictureSizes();
1519 CameraSettings.setCameraPictureSize(
1520 pictureSize, supported, mParameters);
1521 }
1522 Size size = mParameters.getPictureSize();
1523
1524 // Set a preview size that is closest to the viewfinder height and has
1525 // the right aspect ratio.
1526 List<Size> sizes = mParameters.getSupportedPreviewSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001527 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
Michael Kolb8872c232013-01-29 10:33:22 -08001528 (double) size.width / size.height);
1529 Size original = mParameters.getPreviewSize();
1530 if (!original.equals(optimalSize)) {
1531 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
Doris Liu6432cd62013-06-13 17:20:31 -07001532
Michael Kolb8872c232013-01-29 10:33:22 -08001533 // Zoom related settings will be changed for different preview
1534 // sizes, so set and read the parameters to get latest values
Michael Kolb4a4d4ef2013-05-30 08:35:26 -07001535 if (mHandler.getLooper() == Looper.myLooper()) {
1536 // On UI thread only, not when camera starts up
1537 setupPreview();
1538 } else {
1539 mCameraDevice.setParameters(mParameters);
1540 }
Michael Kolb8872c232013-01-29 10:33:22 -08001541 mParameters = mCameraDevice.getParameters();
1542 }
Doris Liu95405742013-11-05 15:25:26 -08001543
1544 if(optimalSize.width != 0 && optimalSize.height != 0) {
1545 mUI.updatePreviewAspectRatio((float) optimalSize.width
1546 / (float) optimalSize.height);
1547 }
Michael Kolb8872c232013-01-29 10:33:22 -08001548 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
1549
1550 // Since changing scene mode may change supported values, set scene mode
1551 // first. HDR is a scene mode. To promote it in UI, it is stored in a
1552 // separate preference.
Sascha Haeberling98f38bb2013-09-24 18:58:34 -07001553 String onValue = mActivity.getString(R.string.setting_on_value);
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001554 String hdr = settingsManager.get(SettingsManager.SETTING_CAMERA_HDR);
1555 String hdrPlus = settingsManager.get(SettingsManager.SETTING_CAMERA_HDR_PLUS);
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001556 boolean hdrOn = onValue.equals(hdr);
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001557 boolean hdrPlusOn = onValue.equals(hdrPlus);
Sascha Haeberling98f38bb2013-09-24 18:58:34 -07001558
1559 boolean doGcamModeSwitch = false;
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001560 if (hdrPlusOn && GcamHelper.hasGcamCapture()) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001561 // Kick off mode switch to gcam.
1562 doGcamModeSwitch = true;
Michael Kolb8872c232013-01-29 10:33:22 -08001563 } else {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001564 if (hdrOn) {
1565 mSceneMode = CameraUtil.SCENE_MODE_HDR;
1566 } else {
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001567 mSceneMode = settingsManager.get(SettingsManager.SETTING_SCENE_MODE);
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001568 }
Michael Kolb8872c232013-01-29 10:33:22 -08001569 }
Angus Kongb50b5cb2013-08-09 14:55:20 -07001570 if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
Michael Kolb8872c232013-01-29 10:33:22 -08001571 if (!mParameters.getSceneMode().equals(mSceneMode)) {
1572 mParameters.setSceneMode(mSceneMode);
1573
1574 // Setting scene mode will change the settings of flash mode,
1575 // white balance, and focus mode. Here we read back the
1576 // parameters, so we can know those settings.
1577 mCameraDevice.setParameters(mParameters);
1578 mParameters = mCameraDevice.getParameters();
1579 }
1580 } else {
1581 mSceneMode = mParameters.getSceneMode();
1582 if (mSceneMode == null) {
1583 mSceneMode = Parameters.SCENE_MODE_AUTO;
1584 }
1585 }
1586
1587 // Set JPEG quality.
1588 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1589 CameraProfile.QUALITY_HIGH);
1590 mParameters.setJpegQuality(jpegQuality);
1591
1592 // For the following settings, we need to check if the settings are
1593 // still supported by latest driver, if not, ignore the settings.
1594
1595 // Set exposure compensation
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001596 int value = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_EXPOSURE));
Michael Kolb8872c232013-01-29 10:33:22 -08001597 int max = mParameters.getMaxExposureCompensation();
1598 int min = mParameters.getMinExposureCompensation();
1599 if (value >= min && value <= max) {
1600 mParameters.setExposureCompensation(value);
1601 } else {
1602 Log.w(TAG, "invalid exposure range: " + value);
1603 }
1604
1605 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1606 // Set flash mode.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001607 String flashMode = settingsManager.get(SettingsManager.SETTING_FLASH_MODE);
Michael Kolb8872c232013-01-29 10:33:22 -08001608 List<String> supportedFlash = mParameters.getSupportedFlashModes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001609 if (CameraUtil.isSupported(flashMode, supportedFlash)) {
Michael Kolb8872c232013-01-29 10:33:22 -08001610 mParameters.setFlashMode(flashMode);
1611 } else {
1612 flashMode = mParameters.getFlashMode();
1613 if (flashMode == null) {
1614 flashMode = mActivity.getString(
1615 R.string.pref_camera_flashmode_no_flash);
1616 }
1617 }
1618
1619 // Set white balance parameter.
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001620 String whiteBalance = settingsManager.get(SettingsManager.SETTING_WHITE_BALANCE);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001621 if (CameraUtil.isSupported(whiteBalance,
Michael Kolb8872c232013-01-29 10:33:22 -08001622 mParameters.getSupportedWhiteBalance())) {
1623 mParameters.setWhiteBalance(whiteBalance);
1624 } else {
1625 whiteBalance = mParameters.getWhiteBalance();
1626 if (whiteBalance == null) {
1627 whiteBalance = Parameters.WHITE_BALANCE_AUTO;
1628 }
1629 }
1630
1631 // Set focus mode.
1632 mFocusManager.overrideFocusMode(null);
1633 mParameters.setFocusMode(mFocusManager.getFocusMode());
1634 } else {
1635 mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1636 }
1637
Angus Kongdcccc512013-08-08 17:06:03 -07001638 if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
Michael Kolb8872c232013-01-29 10:33:22 -08001639 updateAutoFocusMoveCallback();
1640 }
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001641
1642 return doGcamModeSwitch;
Michael Kolb8872c232013-01-29 10:33:22 -08001643 }
1644
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001645 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001646 private void updateAutoFocusMoveCallback() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001647 if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Angus Kong9ef99252013-07-18 18:04:19 -07001648 mCameraDevice.setAutoFocusMoveCallback(mHandler,
Angus Kong4f795b82013-09-16 14:25:35 -07001649 (CameraAFMoveCallback) mAutoFocusMoveCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001650 } else {
Angus Kong9ef99252013-07-18 18:04:19 -07001651 mCameraDevice.setAutoFocusMoveCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001652 }
1653 }
1654
1655 // We separate the parameters into several subsets, so we can update only
1656 // the subsets actually need updating. The PREFERENCE set needs extra
1657 // locking because the preference can be changed from GLThread as well.
1658 private void setCameraParameters(int updateSet) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001659 boolean doModeSwitch = false;
1660
Michael Kolb8872c232013-01-29 10:33:22 -08001661 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1662 updateCameraParametersInitialize();
1663 }
1664
1665 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1666 updateCameraParametersZoom();
1667 }
1668
1669 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001670 doModeSwitch = updateCameraParametersPreference();
Michael Kolb8872c232013-01-29 10:33:22 -08001671 }
1672
1673 mCameraDevice.setParameters(mParameters);
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001674
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001675 // Switch to gcam module if HDR+ was selected
Angus Kong0fb819b2013-10-08 13:44:19 -07001676 if (doModeSwitch && !mIsImageCaptureIntent) {
Angus Kong13e87c42013-11-25 10:02:47 -08001677 mHandler.sendEmptyMessage(MSG_SWITCH_TO_GCAM_MODULE);
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001678 }
Michael Kolb8872c232013-01-29 10:33:22 -08001679 }
1680
1681 // If the Camera is idle, update the parameters immediately, otherwise
1682 // accumulate them in mUpdateSet and update later.
1683 private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1684 mUpdateSet |= additionalUpdateSet;
1685 if (mCameraDevice == null) {
1686 // We will update all the parameters when we open the device, so
1687 // we don't need to do anything now.
1688 mUpdateSet = 0;
1689 return;
1690 } else if (isCameraIdle()) {
1691 setCameraParameters(mUpdateSet);
Michael Kolbd6954f32013-03-08 20:43:01 -08001692 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001693 mUpdateSet = 0;
1694 } else {
Angus Kong13e87c42013-11-25 10:02:47 -08001695 if (!mHandler.hasMessages(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1696 mHandler.sendEmptyMessageDelayed(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
Michael Kolb8872c232013-01-29 10:33:22 -08001697 }
1698 }
1699 }
1700
ztenghui7b265a62013-09-09 14:58:44 -07001701 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001702 public boolean isCameraIdle() {
Michael Kolb8872c232013-01-29 10:33:22 -08001703 return (mCameraState == IDLE) ||
1704 (mCameraState == PREVIEW_STOPPED) ||
1705 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
1706 && (mCameraState != SWITCHING_CAMERA));
1707 }
1708
ztenghui7b265a62013-09-09 14:58:44 -07001709 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001710 public boolean isImageCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001711 String action = mActivity.getIntent().getAction();
1712 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
Angus Kong6a8e8a12013-07-19 14:55:07 -07001713 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
Michael Kolb8872c232013-01-29 10:33:22 -08001714 }
1715
1716 private void setupCaptureParams() {
1717 Bundle myExtras = mActivity.getIntent().getExtras();
1718 if (myExtras != null) {
1719 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1720 mCropValue = myExtras.getString("crop");
1721 }
1722 }
1723
Michael Kolb8872c232013-01-29 10:33:22 -08001724 public void onSharedPreferenceChanged() {
1725 // ignore the events after "onPause()"
1726 if (mPaused) return;
1727
Erin Dahlgren357b7672013-11-20 17:38:14 -08001728 SettingsController settingsController = mActivity.getSettingsController();
1729 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001730
1731 setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
Michael Kolb8872c232013-01-29 10:33:22 -08001732 }
1733
Michael Kolb8872c232013-01-29 10:33:22 -08001734 private void showTapToFocusToast() {
1735 // TODO: Use a toast?
1736 new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
1737 // Clear the preference.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001738 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001739 settingsManager.setBoolean(
1740 SettingsManager.SETTING_CAMERA_FIRST_USE_HINT_SHOWN, false);
Michael Kolb8872c232013-01-29 10:33:22 -08001741 }
1742
1743 private void initializeCapabilities() {
1744 mInitialParams = mCameraDevice.getParameters();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001745 mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
1746 mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
1747 mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
1748 mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
Angus Kongdcccc512013-08-08 17:06:03 -07001749 mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001750 CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
Michael Kolb8872c232013-01-29 10:33:22 -08001751 }
1752
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001753 // TODO: Remove this
Michael Kolb8872c232013-01-29 10:33:22 -08001754 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001755 public int onZoomChanged(int index) {
1756 // Not useful to change zoom value when the activity is paused.
1757 if (mPaused) return index;
1758 mZoomValue = index;
1759 if (mParameters == null || mCameraDevice == null) return index;
1760 // Set zoom parameters asynchronously
1761 mParameters.setZoom(mZoomValue);
Angus Kong36ed8672013-04-15 12:11:15 -07001762 mCameraDevice.setParameters(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -08001763 Parameters p = mCameraDevice.getParameters();
1764 if (p != null) return p.getZoom();
1765 return index;
Angus Kongce5480e2013-01-29 17:43:48 -08001766 }
1767
1768 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001769 public int getCameraState() {
1770 return mCameraState;
1771 }
1772
1773 @Override
1774 public void onQueueStatus(boolean full) {
1775 mUI.enableShutter(!full);
Angus Kongce5480e2013-01-29 17:43:48 -08001776 }
Angus Kong86d36312013-01-31 18:22:44 -08001777
1778 @Override
Angus Kongfd4fc0e2013-11-07 15:38:09 -08001779 public void onMediaSaverAvailable(MediaSaver s) {
Angus Kong86d36312013-01-31 18:22:44 -08001780 // We set the listener only when both service and shutterbutton
1781 // are initialized.
Michael Kolbd6954f32013-03-08 20:43:01 -08001782 if (mFirstTimeInitialized) {
Angus Kongfd4fc0e2013-11-07 15:38:09 -08001783 s.setQueueListener(this);
Michael Kolbd6954f32013-03-08 20:43:01 -08001784 }
Angus Kong86d36312013-01-31 18:22:44 -08001785 }
Angus Kong0d00a892013-03-26 11:40:40 -07001786
1787 @Override
1788 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1789 }
1790
1791 @Override
1792 public void onSensorChanged(SensorEvent event) {
1793 int type = event.sensor.getType();
1794 float[] data;
1795 if (type == Sensor.TYPE_ACCELEROMETER) {
1796 data = mGData;
1797 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
1798 data = mMData;
1799 } else {
1800 // we should not be here.
1801 return;
1802 }
1803 for (int i = 0; i < 3 ; i++) {
1804 data[i] = event.values[i];
1805 }
1806 float[] orientation = new float[3];
1807 SensorManager.getRotationMatrix(mR, null, mGData, mMData);
1808 SensorManager.getOrientation(mR, orientation);
1809 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
1810 if (mHeading < 0) {
1811 mHeading += 360;
1812 }
Angus Kong0d00a892013-03-26 11:40:40 -07001813 }
Doris Liu6432cd62013-06-13 17:20:31 -07001814
Ruben Brunkd217ed02013-10-08 23:31:13 -07001815 // For debugging only.
1816 public void setDebugUri(Uri uri) {
1817 mDebugUri = uri;
1818 }
1819
1820 // For debugging only.
1821 private void saveToDebugUri(byte[] data) {
1822 if (mDebugUri != null) {
1823 OutputStream outputStream = null;
1824 try {
1825 outputStream = mContentResolver.openOutputStream(mDebugUri);
1826 outputStream.write(data);
1827 outputStream.close();
1828 } catch (IOException e) {
1829 Log.e(TAG, "Exception while writing debug jpeg file", e);
1830 } finally {
1831 CameraUtil.closeSilently(outputStream);
1832 }
1833 }
1834 }
Michael Kolb8872c232013-01-29 10:33:22 -08001835}