blob: 938a0766f4e75bd646c2a86e4c4e6426231f4eaf [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;
Dan Aminzade92ae10e2013-08-13 14:44:25 -070021import android.content.BroadcastReceiver;
Michael Kolb8872c232013-01-29 10:33:22 -080022import android.content.ContentProviderClient;
23import android.content.ContentResolver;
Angus Kong0d00a892013-03-26 11:40:40 -070024import android.content.Context;
Michael Kolb8872c232013-01-29 10:33:22 -080025import android.content.Intent;
Dan Aminzade92ae10e2013-08-13 14:44:25 -070026import android.content.IntentFilter;
Michael Kolb8872c232013-01-29 10:33:22 -080027import android.content.SharedPreferences.Editor;
28import android.content.res.Configuration;
29import android.graphics.Bitmap;
30import android.graphics.SurfaceTexture;
31import android.hardware.Camera.CameraInfo;
Michael Kolb8872c232013-01-29 10:33:22 -080032import android.hardware.Camera.Parameters;
Michael Kolb8872c232013-01-29 10:33:22 -080033import android.hardware.Camera.Size;
Angus Kong0d00a892013-03-26 11:40:40 -070034import android.hardware.Sensor;
35import android.hardware.SensorEvent;
36import android.hardware.SensorEventListener;
37import android.hardware.SensorManager;
Michael Kolb8872c232013-01-29 10:33:22 -080038import android.location.Location;
39import android.media.CameraProfile;
40import android.net.Uri;
Sascha Haeberling638e6f02013-09-18 14:28:51 -070041import android.os.Build;
Michael Kolb8872c232013-01-29 10:33:22 -080042import android.os.Bundle;
Michael Kolb8872c232013-01-29 10:33:22 -080043import android.os.Handler;
44import android.os.Looper;
45import android.os.Message;
46import android.os.MessageQueue;
47import android.os.SystemClock;
48import android.provider.MediaStore;
49import android.util.Log;
Michael Kolb8872c232013-01-29 10:33:22 -080050import android.view.KeyEvent;
Michael Kolb8872c232013-01-29 10:33:22 -080051import android.view.OrientationEventListener;
Michael Kolb8872c232013-01-29 10:33:22 -080052import android.view.View;
Michael Kolb8872c232013-01-29 10:33:22 -080053import android.view.WindowManager;
Michael Kolb8872c232013-01-29 10:33:22 -080054
Angus Kong9ef99252013-07-18 18:04:19 -070055import com.android.camera.CameraManager.CameraAFCallback;
56import com.android.camera.CameraManager.CameraAFMoveCallback;
57import com.android.camera.CameraManager.CameraPictureCallback;
Michael Kolb8872c232013-01-29 10:33:22 -080058import com.android.camera.CameraManager.CameraProxy;
Angus Kong9ef99252013-07-18 18:04:19 -070059import com.android.camera.CameraManager.CameraShutterCallback;
Ruben Brunka9d66bd2013-09-06 11:56:32 -070060import com.android.camera.PhotoModule.NamedImages.NamedEntity;
ztenghuia16e7b52013-08-23 11:47:56 -070061import com.android.camera.exif.ExifInterface;
62import com.android.camera.exif.ExifTag;
63import com.android.camera.exif.Rational;
Michael Kolbd6954f32013-03-08 20:43:01 -080064import com.android.camera.ui.CountDownView.OnCountDownFinishedListener;
Michael Kolb8872c232013-01-29 10:33:22 -080065import com.android.camera.ui.PopupManager;
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;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070069import com.android.camera.util.UsageStatistics;
70import com.android.camera2.R;
Michael Kolb8872c232013-01-29 10:33:22 -080071
Angus Kongdcccc512013-08-08 17:06:03 -070072import java.io.File;
73import java.io.FileNotFoundException;
74import java.io.FileOutputStream;
75import java.io.IOException;
76import java.io.OutputStream;
77import java.util.ArrayList;
78import 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
Dan Aminzade92ae10e2013-08-13 14:44:25 -070082 implements CameraModule,
83 PhotoController,
84 FocusOverlayManager.Listener,
85 CameraPreference.OnPreferenceChangedListener,
86 ShutterButton.OnShutterButtonListener,
87 MediaSaveService.Listener,
88 OnCountDownFinishedListener,
89 SensorEventListener {
Michael Kolb8872c232013-01-29 10:33:22 -080090
91 private static final String TAG = "CAM_PhotoModule";
92
93 // We number the request code from 1000 to avoid collision with Gallery.
94 private static final int REQUEST_CROP = 1000;
95
96 private static final int SETUP_PREVIEW = 1;
97 private static final int FIRST_TIME_INIT = 2;
98 private static final int CLEAR_SCREEN_DELAY = 3;
99 private static final int SET_CAMERA_PARAMETERS_WHEN_IDLE = 4;
Angus Kongdcccc512013-08-08 17:06:03 -0700100 private static final int SHOW_TAP_TO_FOCUS_TOAST = 5;
101 private static final int SWITCH_CAMERA = 6;
102 private static final int SWITCH_CAMERA_START_ANIMATION = 7;
103 private static final int CAMERA_OPEN_DONE = 8;
104 private static final int OPEN_CAMERA_FAIL = 9;
105 private static final int CAMERA_DISABLED = 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
113 // This is the timeout to keep the camera in onPause for the first time
114 // after screen on if the activity is started from secure lock screen.
115 private static final int KEEP_CAMERA_TIMEOUT = 1000; // ms
116
117 // copied from Camera hierarchy
118 private CameraActivity mActivity;
Michael Kolb8872c232013-01-29 10:33:22 -0800119 private CameraProxy mCameraDevice;
120 private int mCameraId;
121 private Parameters mParameters;
122 private boolean mPaused;
Michael Kolbd6954f32013-03-08 20:43:01 -0800123
124 private PhotoUI mUI;
Michael Kolb8872c232013-01-29 10:33:22 -0800125
Michael Kolb8872c232013-01-29 10:33:22 -0800126 // The activity is going to switch to the specified camera id. This is
127 // needed because texture copy is done in GL thread. -1 means camera is not
128 // switching.
129 protected int mPendingSwitchCameraId = -1;
130 private boolean mOpenCameraFail;
131 private boolean mCameraDisabled;
132
133 // When setCameraParametersWhenIdle() is called, we accumulate the subsets
134 // needed to be updated in mUpdateSet.
135 private int mUpdateSet;
136
137 private static final int SCREEN_DELAY = 2 * 60 * 1000;
138
139 private int mZoomValue; // The current zoom value.
Michael Kolb8872c232013-01-29 10:33:22 -0800140
141 private Parameters mInitialParams;
142 private boolean mFocusAreaSupported;
143 private boolean mMeteringAreaSupported;
144 private boolean mAeLockSupported;
145 private boolean mAwbLockSupported;
Angus Kongdcccc512013-08-08 17:06:03 -0700146 private boolean mContinuousFocusSupported;
Michael Kolb8872c232013-01-29 10:33:22 -0800147
148 // The degrees of the device rotated clockwise from its natural orientation.
149 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
150 private ComboPreferences mPreferences;
151
152 private static final String sTempCropFilename = "crop-temp";
153
154 private ContentProviderClient mMediaProviderClient;
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
Angus Kongce5480e2013-01-29 17:43:48 -0800161 // We use a queue to generated names of the images to be used later
162 // when the image is ready to be saved.
Michael Kolb8872c232013-01-29 10:33:22 -0800163 private NamedImages mNamedImages;
164
165 private Runnable mDoSnapRunnable = new Runnable() {
166 @Override
167 public void run() {
168 onShutterButtonClick();
169 }
170 };
171
Michael Kolb8872c232013-01-29 10:33:22 -0800172 /**
173 * An unpublished intent flag requesting to return as soon as capturing
174 * is completed.
175 *
176 * TODO: consider publishing by moving into MediaStore.
177 */
178 private static final String EXTRA_QUICK_CAPTURE =
179 "android.intent.extra.quickCapture";
180
181 // The display rotation in degrees. This is only valid when mCameraState is
182 // not PREVIEW_STOPPED.
183 private int mDisplayRotation;
184 // The value for android.hardware.Camera.setDisplayOrientation.
185 private int mCameraDisplayOrientation;
186 // The value for UI components like indicators.
187 private int mDisplayOrientation;
188 // The value for android.hardware.Camera.Parameters.setRotation.
189 private int mJpegRotation;
Doris Liu29da2db2013-08-28 14:28:45 -0700190 // Indicates whether we are using front camera
191 private boolean mMirror;
Michael Kolb8872c232013-01-29 10:33:22 -0800192 private boolean mFirstTimeInitialized;
193 private boolean mIsImageCaptureIntent;
194
Michael Kolb8872c232013-01-29 10:33:22 -0800195 private int mCameraState = PREVIEW_STOPPED;
196 private boolean mSnapshotOnIdle = false;
197
198 private ContentResolver mContentResolver;
199
200 private LocationManager mLocationManager;
201
Michael Kolb8872c232013-01-29 10:33:22 -0800202 private final PostViewPictureCallback mPostViewPictureCallback =
203 new PostViewPictureCallback();
204 private final RawPictureCallback mRawPictureCallback =
205 new RawPictureCallback();
206 private final AutoFocusCallback mAutoFocusCallback =
207 new AutoFocusCallback();
208 private final Object mAutoFocusMoveCallback =
209 ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700210 ? new AutoFocusMoveCallback()
211 : null;
Michael Kolb8872c232013-01-29 10:33:22 -0800212
213 private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
214
215 private long mFocusStartTime;
216 private long mShutterCallbackTime;
217 private long mPostViewPictureCallbackTime;
218 private long mRawPictureCallbackTime;
219 private long mJpegPictureCallbackTime;
220 private long mOnResumeTime;
221 private byte[] mJpegImageData;
222
223 // These latency time are for the CameraLatency test.
224 public long mAutoFocusTime;
225 public long mShutterLag;
226 public long mShutterToPictureDisplayedTime;
227 public long mPictureDisplayedToJpegCallbackTime;
228 public long mJpegCallbackFinishTime;
229 public long mCaptureStartTime;
230
231 // This handles everything about focus.
232 private FocusOverlayManager mFocusManager;
233
Michael Kolb8872c232013-01-29 10:33:22 -0800234 private String mSceneMode;
Michael Kolb8872c232013-01-29 10:33:22 -0800235
236 private final Handler mHandler = new MainHandler();
237 private PreferenceGroup mPreferenceGroup;
238
239 private boolean mQuickCapture;
Angus Kong0d00a892013-03-26 11:40:40 -0700240 private SensorManager mSensorManager;
241 private float[] mGData = new float[3];
242 private float[] mMData = new float[3];
243 private float[] mR = new float[16];
244 private int mHeading = -1;
245
Angus Kongdcccc512013-08-08 17:06:03 -0700246 // True if all the parameters needed to start preview is ready.
247 private boolean mCameraPreviewParamsReady = false;
Doris Liu6432cd62013-06-13 17:20:31 -0700248
Angus Kongce5480e2013-01-29 17:43:48 -0800249 private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener =
250 new MediaSaveService.OnMediaSavedListener() {
251 @Override
252 public void onMediaSaved(Uri uri) {
253 if (uri != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700254 mActivity.notifyNewMedia(uri);
Angus Kongce5480e2013-01-29 17:43:48 -0800255 }
256 }
257 };
Michael Kolb8872c232013-01-29 10:33:22 -0800258
Angus Kongdcccc512013-08-08 17:06:03 -0700259 private void checkDisplayRotation() {
260 // Set the display orientation if display rotation has changed.
261 // Sometimes this happens when the device is held upside
262 // down and camera app is opened. Rotation animation will
263 // take some time and the rotation value we have got may be
264 // wrong. Framework does not have a callback for this now.
265 if (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) {
266 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -0800267 }
Angus Kongdcccc512013-08-08 17:06:03 -0700268 if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
269 mHandler.postDelayed(new Runnable() {
270 @Override
271 public void run() {
272 checkDisplayRotation();
273 }
274 }, 100);
Michael Kolb8872c232013-01-29 10:33:22 -0800275 }
276 }
277
278 /**
279 * This Handler is used to post message back onto the main thread of the
280 * application
281 */
282 private class MainHandler extends Handler {
283 @Override
284 public void handleMessage(Message msg) {
285 switch (msg.what) {
286 case SETUP_PREVIEW: {
287 setupPreview();
288 break;
289 }
290
291 case CLEAR_SCREEN_DELAY: {
292 mActivity.getWindow().clearFlags(
293 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
294 break;
295 }
296
297 case FIRST_TIME_INIT: {
298 initializeFirstTime();
299 break;
300 }
301
302 case SET_CAMERA_PARAMETERS_WHEN_IDLE: {
303 setCameraParametersWhenIdle(0);
304 break;
305 }
306
Michael Kolb8872c232013-01-29 10:33:22 -0800307 case SHOW_TAP_TO_FOCUS_TOAST: {
308 showTapToFocusToast();
309 break;
310 }
311
312 case SWITCH_CAMERA: {
313 switchCamera();
314 break;
315 }
316
317 case SWITCH_CAMERA_START_ANIMATION: {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700318 // TODO: Need to revisit
319 // ((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera();
Michael Kolb8872c232013-01-29 10:33:22 -0800320 break;
321 }
322
323 case CAMERA_OPEN_DONE: {
Michael Kolbd6954f32013-03-08 20:43:01 -0800324 onCameraOpened();
Michael Kolb8872c232013-01-29 10:33:22 -0800325 break;
326 }
327
Michael Kolb8872c232013-01-29 10:33:22 -0800328 case OPEN_CAMERA_FAIL: {
Michael Kolb8872c232013-01-29 10:33:22 -0800329 mOpenCameraFail = true;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700330 CameraUtil.showErrorAndFinish(mActivity,
Michael Kolb8872c232013-01-29 10:33:22 -0800331 R.string.cannot_connect_camera);
332 break;
333 }
334
335 case CAMERA_DISABLED: {
Michael Kolb8872c232013-01-29 10:33:22 -0800336 mCameraDisabled = true;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700337 CameraUtil.showErrorAndFinish(mActivity,
Michael Kolb8872c232013-01-29 10:33:22 -0800338 R.string.camera_disabled);
339 break;
340 }
Michael Kolb8872c232013-01-29 10:33:22 -0800341 }
342 }
343 }
344
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700345 private BroadcastReceiver mReceiver = null;
346
347 private class ShutterBroadcastReceiver extends BroadcastReceiver {
348 @Override
349 public void onReceive(Context context, Intent intent) {
350 String action = intent.getAction();
Dan Aminzadefca1c5e2013-08-14 17:36:56 -0700351 if (action.equals(CameraUtil.ACTION_CAMERA_SHUTTER_CLICK)) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700352 onShutterButtonFocus(true);
353 onShutterButtonClick();
354 }
355 }
356 }
357
Michael Kolb8872c232013-01-29 10:33:22 -0800358 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700359 public void init(CameraActivity activity, View parent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800360 mActivity = activity;
Michael Kolbd6954f32013-03-08 20:43:01 -0800361 mUI = new PhotoUI(activity, this, parent);
Michael Kolb8872c232013-01-29 10:33:22 -0800362 mPreferences = new ComboPreferences(mActivity);
363 CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal());
364 mCameraId = getPreferredCameraId(mPreferences);
365
366 mContentResolver = mActivity.getContentResolver();
367
Michael Kolb8872c232013-01-29 10:33:22 -0800368 // Surface texture is from camera screen nail and startPreview needs it.
369 // This must be done before startPreview.
370 mIsImageCaptureIntent = isImageCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800371
372 mPreferences.setLocalId(mActivity, mCameraId);
373 CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
374 // we need to reset exposure for the preview
375 resetExposureCompensation();
Michael Kolb8872c232013-01-29 10:33:22 -0800376
377 initializeControlByIntent();
378 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
Michael Kolbd6954f32013-03-08 20:43:01 -0800379 mLocationManager = new LocationManager(mActivity, mUI);
Angus Kong0d00a892013-03-26 11:40:40 -0700380 mSensorManager = (SensorManager)(mActivity.getSystemService(Context.SENSOR_SERVICE));
Michael Kolbd6954f32013-03-08 20:43:01 -0800381 }
382
383 private void initializeControlByIntent() {
384 mUI.initializeControlByIntent();
385 if (mIsImageCaptureIntent) {
386 setupCaptureParams();
387 }
388 }
389
390 private void onPreviewStarted() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800391 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800392 startFaceDetection();
393 locationFirstRun();
Michael Kolb8872c232013-01-29 10:33:22 -0800394 }
395
396 // Prompt the user to pick to record location for the very first run of
397 // camera only
398 private void locationFirstRun() {
399 if (RecordLocationPreference.isSet(mPreferences)) {
400 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
Doris Liu6a83d522013-07-02 12:03:32 -0700413 public void enableRecordingLocation(boolean enable) {
414 setLocationPreference(enable ? RecordLocationPreference.VALUE_ON
415 : RecordLocationPreference.VALUE_OFF);
Michael Kolb8872c232013-01-29 10:33:22 -0800416 }
417
Angus Kongdcccc512013-08-08 17:06:03 -0700418 @Override
419 public void onPreviewUIReady() {
420 startPreview();
421 }
422
423 @Override
424 public void onPreviewUIDestroyed() {
425 if (mCameraDevice == null) {
426 return;
427 }
428 mCameraDevice.setPreviewTexture(null);
429 stopPreview();
430 }
431
Michael Kolb8872c232013-01-29 10:33:22 -0800432 private void setLocationPreference(String value) {
433 mPreferences.edit()
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700434 .putString(CameraSettings.KEY_RECORD_LOCATION, value)
435 .apply();
Michael Kolb8872c232013-01-29 10:33:22 -0800436 // TODO: Fix this to use the actual onSharedPreferencesChanged listener
437 // instead of invoking manually
438 onSharedPreferenceChanged();
439 }
440
Michael Kolbd6954f32013-03-08 20:43:01 -0800441 private void onCameraOpened() {
442 View root = mUI.getRootView();
Michael Kolb8872c232013-01-29 10:33:22 -0800443 // These depend on camera parameters.
Michael Kolbd6954f32013-03-08 20:43:01 -0800444
445 int width = root.getWidth();
446 int height = root.getHeight();
Doris Liu6a0de792013-02-26 10:54:25 -0800447 mFocusManager.setPreviewSize(width, height);
Michael Kolbd6954f32013-03-08 20:43:01 -0800448 openCameraCommon();
Michael Kolb8872c232013-01-29 10:33:22 -0800449 }
450
Michael Kolbd6954f32013-03-08 20:43:01 -0800451 private void switchCamera() {
452 if (mPaused) return;
453
454 Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
455 mCameraId = mPendingSwitchCameraId;
456 mPendingSwitchCameraId = -1;
457 setCameraId(mCameraId);
458
459 // from onPause
460 closeCamera();
461 mUI.collapseCameraControls();
462 mUI.clearFaces();
463 if (mFocusManager != null) mFocusManager.removeMessages();
464
465 // Restart the camera and initialize the UI. From onCreate.
466 mPreferences.setLocalId(mActivity, mCameraId);
467 CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
Angus Kong4f795b82013-09-16 14:25:35 -0700468 mCameraDevice = CameraUtil.openCamera(
469 mActivity, mCameraId, mHandler,
470 mActivity.getCameraOpenErrorCallback());
471 if (mCameraDevice == null) {
472 Log.e(TAG, "Failed to open camera:" + mCameraId + ", aborting.");
Michael Kolbd6954f32013-03-08 20:43:01 -0800473 return;
Doris Liu09106a42013-03-05 09:54:25 -0800474 }
Angus Kong4f795b82013-09-16 14:25:35 -0700475 mParameters = mCameraDevice.getParameters();
Michael Kolbd6954f32013-03-08 20:43:01 -0800476 initializeCapabilities();
477 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -0700478 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
479 mFocusManager.setMirror(mMirror);
Michael Kolbd6954f32013-03-08 20:43:01 -0800480 mFocusManager.setParameters(mInitialParams);
481 setupPreview();
482
Doris Liu6432cd62013-06-13 17:20:31 -0700483 // reset zoom value index
484 mZoomValue = 0;
Michael Kolbd6954f32013-03-08 20:43:01 -0800485 openCameraCommon();
486
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700487 // Start switch camera animation. Post a message because
488 // onFrameAvailable from the old camera may already exist.
489 mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION);
Doris Liu48239f42013-03-04 22:19:10 -0800490 }
491
Michael Kolbd6954f32013-03-08 20:43:01 -0800492 protected void setCameraId(int cameraId) {
493 ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID);
494 pref.setValue("" + cameraId);
495 }
496
497 // either open a new camera or switch cameras
498 private void openCameraCommon() {
Michael Kolb8872c232013-01-29 10:33:22 -0800499 loadCameraPreferences();
Michael Kolbd6954f32013-03-08 20:43:01 -0800500
501 mUI.onCameraOpened(mPreferenceGroup, mPreferences, mParameters, this);
502 updateSceneMode();
503 showTapToFocusToastIfNeeded();
504
505
Michael Kolb8872c232013-01-29 10:33:22 -0800506 }
507
ztenghui7b265a62013-09-09 14:58:44 -0700508 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -0800509 public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) {
Michael Kolbd6954f32013-03-08 20:43:01 -0800510 if (mFocusManager != null) mFocusManager.setPreviewSize(width, height);
Michael Kolbd6954f32013-03-08 20:43:01 -0800511 }
Michael Kolb8872c232013-01-29 10:33:22 -0800512
513 private void resetExposureCompensation() {
514 String value = mPreferences.getString(CameraSettings.KEY_EXPOSURE,
515 CameraSettings.EXPOSURE_DEFAULT_VALUE);
516 if (!CameraSettings.EXPOSURE_DEFAULT_VALUE.equals(value)) {
517 Editor editor = mPreferences.edit();
518 editor.putString(CameraSettings.KEY_EXPOSURE, "0");
519 editor.apply();
520 }
521 }
522
523 private void keepMediaProviderInstance() {
524 // We want to keep a reference to MediaProvider in camera's lifecycle.
525 // TODO: Utilize mMediaProviderClient instance to replace
526 // ContentResolver calls.
527 if (mMediaProviderClient == null) {
528 mMediaProviderClient = mContentResolver
529 .acquireContentProviderClient(MediaStore.AUTHORITY);
530 }
531 }
532
533 // Snapshots can only be taken after this is called. It should be called
534 // once only. We could have done these things in onCreate() but we want to
535 // make preview screen appear as soon as possible.
536 private void initializeFirstTime() {
537 if (mFirstTimeInitialized) return;
538
539 // Initialize location service.
540 boolean recordLocation = RecordLocationPreference.get(
541 mPreferences, mContentResolver);
542 mLocationManager.recordLocation(recordLocation);
543
544 keepMediaProviderInstance();
545
Michael Kolbd6954f32013-03-08 20:43:01 -0800546 mUI.initializeFirstTime();
Angus Kong86d36312013-01-31 18:22:44 -0800547 MediaSaveService s = mActivity.getMediaSaveService();
548 // We set the listener only when both service and shutterbutton
549 // are initialized.
550 if (s != null) {
551 s.setListener(this);
552 }
Michael Kolb8872c232013-01-29 10:33:22 -0800553
Michael Kolb8872c232013-01-29 10:33:22 -0800554 mNamedImages = new NamedImages();
555
556 mFirstTimeInitialized = true;
557 addIdleHandler();
558
559 mActivity.updateStorageSpaceAndHint();
560 }
561
Michael Kolbd6954f32013-03-08 20:43:01 -0800562 // If the activity is paused and resumed, this method will be called in
563 // onResume.
564 private void initializeSecondTime() {
565 // Start location update if needed.
566 boolean recordLocation = RecordLocationPreference.get(
567 mPreferences, mContentResolver);
568 mLocationManager.recordLocation(recordLocation);
569 MediaSaveService s = mActivity.getMediaSaveService();
570 if (s != null) {
571 s.setListener(this);
572 }
573 mNamedImages = new NamedImages();
574 mUI.initializeSecondTime(mParameters);
575 keepMediaProviderInstance();
576 }
577
Michael Kolb8872c232013-01-29 10:33:22 -0800578 private void showTapToFocusToastIfNeeded() {
579 // Show the tap to focus toast if this is the first start.
580 if (mFocusAreaSupported &&
581 mPreferences.getBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, true)) {
582 // Delay the toast for one second to wait for orientation.
583 mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_FOCUS_TOAST, 1000);
584 }
585 }
586
587 private void addIdleHandler() {
588 MessageQueue queue = Looper.myQueue();
589 queue.addIdleHandler(new MessageQueue.IdleHandler() {
590 @Override
591 public boolean queueIdle() {
592 Storage.ensureOSXCompatible();
593 return false;
594 }
595 });
596 }
597
Michael Kolb8872c232013-01-29 10:33:22 -0800598 @Override
599 public void startFaceDetection() {
Michael Kolb8872c232013-01-29 10:33:22 -0800600 if (mFaceDetectionStarted) return;
601 if (mParameters.getMaxNumDetectedFaces() > 0) {
602 mFaceDetectionStarted = true;
Michael Kolb8872c232013-01-29 10:33:22 -0800603 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Michael Kolbd6954f32013-03-08 20:43:01 -0800604 mUI.onStartFaceDetection(mDisplayOrientation,
605 (info.facing == CameraInfo.CAMERA_FACING_FRONT));
Angus Kong9e765522013-07-31 14:05:20 -0700606 mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Michael Kolb8872c232013-01-29 10:33:22 -0800607 mCameraDevice.startFaceDetection();
608 }
609 }
610
Michael Kolb8872c232013-01-29 10:33:22 -0800611 @Override
612 public void stopFaceDetection() {
Michael Kolb8872c232013-01-29 10:33:22 -0800613 if (!mFaceDetectionStarted) return;
614 if (mParameters.getMaxNumDetectedFaces() > 0) {
615 mFaceDetectionStarted = false;
Angus Kong9e765522013-07-31 14:05:20 -0700616 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -0800617 mCameraDevice.stopFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800618 mUI.clearFaces();
Michael Kolb8872c232013-01-29 10:33:22 -0800619 }
620 }
621
Michael Kolb8872c232013-01-29 10:33:22 -0800622 private final class ShutterCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700623 implements CameraShutterCallback {
Angus Kongdcb0ef12013-03-25 23:11:43 -0700624
Sascha Haeberling37f36112013-08-06 14:31:52 -0700625 private boolean mNeedsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700626
Sascha Haeberling37f36112013-08-06 14:31:52 -0700627 public ShutterCallback(boolean needsAnimation) {
628 mNeedsAnimation = needsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700629 }
630
Michael Kolb8872c232013-01-29 10:33:22 -0800631 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700632 public void onShutter(CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800633 mShutterCallbackTime = System.currentTimeMillis();
634 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
635 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Sascha Haeberling37f36112013-08-06 14:31:52 -0700636 if (mNeedsAnimation) {
637 mActivity.runOnUiThread(new Runnable() {
638 @Override
639 public void run() {
640 animateAfterShutter();
641 }
642 });
Angus Kongdcb0ef12013-03-25 23:11:43 -0700643 }
Michael Kolb8872c232013-01-29 10:33:22 -0800644 }
645 }
646
Angus Kong9ef99252013-07-18 18:04:19 -0700647 private final class PostViewPictureCallback
648 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800649 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700650 public void onPictureTaken(byte [] data, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800651 mPostViewPictureCallbackTime = System.currentTimeMillis();
652 Log.v(TAG, "mShutterToPostViewCallbackTime = "
653 + (mPostViewPictureCallbackTime - mShutterCallbackTime)
654 + "ms");
655 }
656 }
657
Angus Kong9ef99252013-07-18 18:04:19 -0700658 private final class RawPictureCallback
659 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800660 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700661 public void onPictureTaken(byte [] rawData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800662 mRawPictureCallbackTime = System.currentTimeMillis();
663 Log.v(TAG, "mShutterToRawCallbackTime = "
664 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
665 }
666 }
667
Angus Kong9ef99252013-07-18 18:04:19 -0700668 private final class JpegPictureCallback
669 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800670 Location mLocation;
671
672 public JpegPictureCallback(Location loc) {
673 mLocation = loc;
674 }
675
676 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700677 public void onPictureTaken(final byte [] jpegData, CameraProxy camera) {
Sascha Haeberling88901942013-08-28 17:49:00 -0700678 mUI.enableShutter(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800679 if (mPaused) {
680 return;
681 }
Doris Liu6432cd62013-06-13 17:20:31 -0700682 if (mIsImageCaptureIntent) {
683 stopPreview();
684 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700685 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -0700686 mUI.showSwitcher();
687 mUI.setSwipingEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800688 }
689
690 mJpegPictureCallbackTime = System.currentTimeMillis();
691 // If postview callback has arrived, the captured image is displayed
692 // in postview callback. If not, the captured image is displayed in
693 // raw picture callback.
694 if (mPostViewPictureCallbackTime != 0) {
695 mShutterToPictureDisplayedTime =
696 mPostViewPictureCallbackTime - mShutterCallbackTime;
697 mPictureDisplayedToJpegCallbackTime =
698 mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
699 } else {
700 mShutterToPictureDisplayedTime =
701 mRawPictureCallbackTime - mShutterCallbackTime;
702 mPictureDisplayedToJpegCallbackTime =
703 mJpegPictureCallbackTime - mRawPictureCallbackTime;
704 }
705 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
706 + mPictureDisplayedToJpegCallbackTime + "ms");
707
Michael Kolb8872c232013-01-29 10:33:22 -0800708 mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
709 if (!mIsImageCaptureIntent) {
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700710 setupPreview();
Michael Kolb8872c232013-01-29 10:33:22 -0800711 }
712
Doris Liu36e56fb2013-09-11 17:38:08 -0700713 ExifInterface exif = Exif.getExif(jpegData);
714 int orientation = Exif.getOrientation(exif);
Michael Kolb8872c232013-01-29 10:33:22 -0800715 if (!mIsImageCaptureIntent) {
716 // Calculate the width and the height of the jpeg.
717 Size s = mParameters.getPictureSize();
Michael Kolb8872c232013-01-29 10:33:22 -0800718 int width, height;
719 if ((mJpegRotation + orientation) % 180 == 0) {
720 width = s.width;
721 height = s.height;
722 } else {
723 width = s.height;
724 height = s.width;
725 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700726 NamedEntity name = mNamedImages.getNextNameEntity();
727 String title = (name == null) ? null : name.title;
728 long date = (name == null) ? -1 : name.date;
Michael Kolb8872c232013-01-29 10:33:22 -0800729 if (title == null) {
730 Log.e(TAG, "Unbalanced name/data pair");
731 } else {
732 if (date == -1) date = mCaptureStartTime;
Angus Kong0d00a892013-03-26 11:40:40 -0700733 if (mHeading >= 0) {
734 // heading direction has been updated by the sensor.
735 ExifTag directionRefTag = exif.buildTag(
736 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
737 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
738 ExifTag directionTag = exif.buildTag(
739 ExifInterface.TAG_GPS_IMG_DIRECTION,
740 new Rational(mHeading, 1));
741 exif.setTag(directionRefTag);
742 exif.setTag(directionTag);
743 }
Angus Kong86d36312013-01-31 18:22:44 -0800744 mActivity.getMediaSaveService().addImage(
745 jpegData, title, date, mLocation, width, height,
Angus Kong0d00a892013-03-26 11:40:40 -0700746 orientation, exif, mOnMediaSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -0800747 }
Doris Liuce2acbc2013-08-21 18:45:29 -0700748 // Animate capture with real jpeg data instead of a preview frame.
Doris Liu29da2db2013-08-28 14:28:45 -0700749 mUI.animateCapture(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800750 } else {
751 mJpegImageData = jpegData;
752 if (!mQuickCapture) {
Doris Liu36e56fb2013-09-11 17:38:08 -0700753 mUI.showCapturedImageForReview(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800754 } else {
Michael Kolbd6954f32013-03-08 20:43:01 -0800755 onCaptureDone();
Michael Kolb8872c232013-01-29 10:33:22 -0800756 }
757 }
758
759 // Check this in advance of each shot so we don't add to shutter
760 // latency. It's true that someone else could write to the SD card in
761 // the mean time and fill it, but that could have happened between the
762 // shutter press and saving the JPEG too.
763 mActivity.updateStorageSpaceAndHint();
764
765 long now = System.currentTimeMillis();
766 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
767 Log.v(TAG, "mJpegCallbackFinishTime = "
768 + mJpegCallbackFinishTime + "ms");
769 mJpegPictureCallbackTime = 0;
770 }
771 }
772
Angus Kong9ef99252013-07-18 18:04:19 -0700773 private final class AutoFocusCallback implements CameraAFCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800774 @Override
775 public void onAutoFocus(
Angus Kong9ef99252013-07-18 18:04:19 -0700776 boolean focused, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800777 if (mPaused) return;
778
779 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
780 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
781 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800782 mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
Michael Kolb8872c232013-01-29 10:33:22 -0800783 }
784 }
785
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700786 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -0800787 private final class AutoFocusMoveCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700788 implements CameraAFMoveCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800789 @Override
790 public void onAutoFocusMoving(
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700791 boolean moving, CameraProxy camera) {
792 mFocusManager.onAutoFocusMoving(moving);
Michael Kolb8872c232013-01-29 10:33:22 -0800793 }
794 }
795
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700796 /**
797 * This class is just a thread-safe queue for name,date holder objects.
798 */
799 public static class NamedImages {
800 private Vector<NamedEntity> mQueue;
Michael Kolb8872c232013-01-29 10:33:22 -0800801
802 public NamedImages() {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700803 mQueue = new Vector<NamedEntity>();
Michael Kolb8872c232013-01-29 10:33:22 -0800804 }
805
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700806 public void nameNewImage(long date) {
Michael Kolb8872c232013-01-29 10:33:22 -0800807 NamedEntity r = new NamedEntity();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700808 r.title = CameraUtil.createJpegName(date);
Michael Kolb8872c232013-01-29 10:33:22 -0800809 r.date = date;
810 mQueue.add(r);
811 }
812
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700813 public NamedEntity getNextNameEntity() {
814 synchronized(mQueue) {
815 if (!mQueue.isEmpty()) {
816 return mQueue.remove(0);
817 }
Michael Kolb8872c232013-01-29 10:33:22 -0800818 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700819 return null;
Michael Kolb8872c232013-01-29 10:33:22 -0800820 }
821
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700822 public static class NamedEntity {
823 public String title;
824 public long date;
Michael Kolb8872c232013-01-29 10:33:22 -0800825 }
826 }
827
828 private void setCameraState(int state) {
829 mCameraState = state;
830 switch (state) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700831 case PhotoController.PREVIEW_STOPPED:
832 case PhotoController.SNAPSHOT_IN_PROGRESS:
833 case PhotoController.SWITCHING_CAMERA:
834 mUI.enableGestures(false);
835 break;
836 case PhotoController.IDLE:
837 mUI.enableGestures(true);
838 break;
Michael Kolb8872c232013-01-29 10:33:22 -0800839 }
840 }
841
Sascha Haeberling37f36112013-08-06 14:31:52 -0700842 private void animateAfterShutter() {
Michael Kolb8872c232013-01-29 10:33:22 -0800843 // Only animate when in full screen capture mode
844 // i.e. If monkey/a user swipes to the gallery during picture taking,
845 // don't show animation
Doris Liuc2e9abd2013-06-19 14:20:51 -0700846 if (!mIsImageCaptureIntent) {
847 mUI.animateFlash();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700848 }
Michael Kolb8872c232013-01-29 10:33:22 -0800849 }
850
851 @Override
852 public boolean capture() {
853 // If we are already in the middle of taking a snapshot or the image save request
854 // is full then ignore.
855 if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
Angus Kong86d36312013-01-31 18:22:44 -0800856 || mCameraState == SWITCHING_CAMERA
857 || mActivity.getMediaSaveService().isQueueFull()) {
Michael Kolb8872c232013-01-29 10:33:22 -0800858 return false;
859 }
860 mCaptureStartTime = System.currentTimeMillis();
861 mPostViewPictureCallbackTime = 0;
862 mJpegImageData = null;
863
Angus Kongb50b5cb2013-08-09 14:55:20 -0700864 final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
Michael Kolb8872c232013-01-29 10:33:22 -0800865
866 if (animateBefore) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700867 animateAfterShutter();
Michael Kolb8872c232013-01-29 10:33:22 -0800868 }
869
870 // Set rotation and gps data.
Doris Liu3cf565c2013-02-15 10:55:37 -0800871 int orientation;
872 // We need to be consistent with the framework orientation (i.e. the
873 // orientation of the UI.) when the auto-rotate screen setting is on.
874 if (mActivity.isAutoRotateScreen()) {
875 orientation = (360 - mDisplayRotation) % 360;
876 } else {
877 orientation = mOrientation;
878 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700879 mJpegRotation = CameraUtil.getJpegRotation(mCameraId, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800880 mParameters.setRotation(mJpegRotation);
881 Location loc = mLocationManager.getCurrentLocation();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700882 CameraUtil.setGpsParameters(mParameters, loc);
Michael Kolb8872c232013-01-29 10:33:22 -0800883 mCameraDevice.setParameters(mParameters);
884
Sascha Haeberling88901942013-08-28 17:49:00 -0700885 // We don't want user to press the button again while taking a
886 // multi-second HDR photo.
887 mUI.enableShutter(false);
Angus Kong9ef99252013-07-18 18:04:19 -0700888 mCameraDevice.takePicture(mHandler,
889 new ShutterCallback(!animateBefore),
Angus Kongdcb0ef12013-03-25 23:11:43 -0700890 mRawPictureCallback, mPostViewPictureCallback,
Angus Kong9ef99252013-07-18 18:04:19 -0700891 new JpegPictureCallback(loc));
Michael Kolb8872c232013-01-29 10:33:22 -0800892
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700893 mNamedImages.nameNewImage(mCaptureStartTime);
Michael Kolb8872c232013-01-29 10:33:22 -0800894
895 mFaceDetectionStarted = false;
896 setCameraState(SNAPSHOT_IN_PROGRESS);
Bobby Georgescu301b6462013-04-01 15:33:17 -0700897 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
898 UsageStatistics.ACTION_CAPTURE_DONE, "Photo");
Michael Kolb8872c232013-01-29 10:33:22 -0800899 return true;
900 }
901
902 @Override
903 public void setFocusParameters() {
904 setCameraParameters(UPDATE_PARAM_PREFERENCE);
905 }
906
907 private int getPreferredCameraId(ComboPreferences preferences) {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700908 int intentCameraId = CameraUtil.getCameraFacingIntentExtras(mActivity);
Michael Kolb8872c232013-01-29 10:33:22 -0800909 if (intentCameraId != -1) {
910 // Testing purpose. Launch a specific camera through the intent
911 // extras.
912 return intentCameraId;
913 } else {
914 return CameraSettings.readPreferredCameraId(preferences);
915 }
916 }
917
Michael Kolbd6954f32013-03-08 20:43:01 -0800918 private void updateSceneMode() {
Michael Kolb8872c232013-01-29 10:33:22 -0800919 // If scene mode is set, we cannot set flash mode, white balance, and
920 // focus mode, instead, we read it from driver
921 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
922 overrideCameraSettings(mParameters.getFlashMode(),
923 mParameters.getWhiteBalance(), mParameters.getFocusMode());
924 } else {
925 overrideCameraSettings(null, null, null);
926 }
927 }
928
929 private void overrideCameraSettings(final String flashMode,
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700930 final String whiteBalance, final String focusMode) {
Michael Kolbd6954f32013-03-08 20:43:01 -0800931 mUI.overrideSettings(
932 CameraSettings.KEY_FLASH_MODE, flashMode,
933 CameraSettings.KEY_WHITE_BALANCE, whiteBalance,
934 CameraSettings.KEY_FOCUS_MODE, focusMode);
Michael Kolb8872c232013-01-29 10:33:22 -0800935 }
936
937 private void loadCameraPreferences() {
938 CameraSettings settings = new CameraSettings(mActivity, mInitialParams,
939 mCameraId, CameraHolder.instance().getCameraInfo());
940 mPreferenceGroup = settings.getPreferenceGroup(R.xml.camera_preferences);
941 }
942
943 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800944 public void onOrientationChanged(int orientation) {
945 // We keep the last known orientation. So if the user first orient
946 // the camera then point the camera to floor or sky, we still have
947 // the correct orientation.
948 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700949 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800950
951 // Show the toast after getting the first orientation changed.
952 if (mHandler.hasMessages(SHOW_TAP_TO_FOCUS_TOAST)) {
953 mHandler.removeMessages(SHOW_TAP_TO_FOCUS_TOAST);
954 showTapToFocusToast();
955 }
956 }
957
958 @Override
959 public void onStop() {
960 if (mMediaProviderClient != null) {
961 mMediaProviderClient.release();
962 mMediaProviderClient = null;
963 }
964 }
965
Michael Kolbd6954f32013-03-08 20:43:01 -0800966 @Override
967 public void onCaptureCancelled() {
968 mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
969 mActivity.finish();
Michael Kolb8872c232013-01-29 10:33:22 -0800970 }
971
Michael Kolbd6954f32013-03-08 20:43:01 -0800972 @Override
973 public void onCaptureRetake() {
Michael Kolb8872c232013-01-29 10:33:22 -0800974 if (mPaused)
975 return;
Michael Kolbd6954f32013-03-08 20:43:01 -0800976 mUI.hidePostCaptureAlert();
Michael Kolb8872c232013-01-29 10:33:22 -0800977 setupPreview();
978 }
979
Michael Kolbd6954f32013-03-08 20:43:01 -0800980 @Override
981 public void onCaptureDone() {
Michael Kolb8872c232013-01-29 10:33:22 -0800982 if (mPaused) {
983 return;
984 }
985
986 byte[] data = mJpegImageData;
987
988 if (mCropValue == null) {
989 // First handle the no crop case -- just return the value. If the
990 // caller specifies a "save uri" then write the data to its
991 // stream. Otherwise, pass back a scaled down version of the bitmap
992 // directly in the extras.
993 if (mSaveUri != null) {
994 OutputStream outputStream = null;
995 try {
996 outputStream = mContentResolver.openOutputStream(mSaveUri);
997 outputStream.write(data);
998 outputStream.close();
999
1000 mActivity.setResultEx(Activity.RESULT_OK);
1001 mActivity.finish();
1002 } catch (IOException ex) {
1003 // ignore exception
1004 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001005 CameraUtil.closeSilently(outputStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001006 }
1007 } else {
Angus Kong0d00a892013-03-26 11:40:40 -07001008 ExifInterface exif = Exif.getExif(data);
1009 int orientation = Exif.getOrientation(exif);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001010 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
1011 bitmap = CameraUtil.rotate(bitmap, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001012 mActivity.setResultEx(Activity.RESULT_OK,
1013 new Intent("inline-data").putExtra("data", bitmap));
1014 mActivity.finish();
1015 }
1016 } else {
1017 // Save the image to a temp file and invoke the cropper
1018 Uri tempUri = null;
1019 FileOutputStream tempStream = null;
1020 try {
1021 File path = mActivity.getFileStreamPath(sTempCropFilename);
1022 path.delete();
1023 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1024 tempStream.write(data);
1025 tempStream.close();
1026 tempUri = Uri.fromFile(path);
1027 } catch (FileNotFoundException ex) {
1028 mActivity.setResultEx(Activity.RESULT_CANCELED);
1029 mActivity.finish();
1030 return;
1031 } catch (IOException ex) {
1032 mActivity.setResultEx(Activity.RESULT_CANCELED);
1033 mActivity.finish();
1034 return;
1035 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001036 CameraUtil.closeSilently(tempStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001037 }
1038
1039 Bundle newExtras = new Bundle();
1040 if (mCropValue.equals("circle")) {
1041 newExtras.putString("circleCrop", "true");
1042 }
1043 if (mSaveUri != null) {
1044 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1045 } else {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001046 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001047 }
1048 if (mActivity.isSecureCamera()) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001049 newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001050 }
1051
Sascha Haeberling37f36112013-08-06 14:31:52 -07001052 // TODO: Share this constant.
Sascha Haeberling8e963a52013-08-06 11:43:02 -07001053 final String CROP_ACTION = "com.android.camera.action.CROP";
1054 Intent cropIntent = new Intent(CROP_ACTION);
Michael Kolb8872c232013-01-29 10:33:22 -08001055
1056 cropIntent.setData(tempUri);
1057 cropIntent.putExtras(newExtras);
1058
1059 mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1060 }
1061 }
1062
Michael Kolb8872c232013-01-29 10:33:22 -08001063 @Override
1064 public void onShutterButtonFocus(boolean pressed) {
Michael Kolbd6954f32013-03-08 20:43:01 -08001065 if (mPaused || mUI.collapseCameraControls()
Michael Kolb8872c232013-01-29 10:33:22 -08001066 || (mCameraState == SNAPSHOT_IN_PROGRESS)
1067 || (mCameraState == PREVIEW_STOPPED)) return;
1068
1069 // Do not do focus if there is not enough storage.
1070 if (pressed && !canTakePicture()) return;
1071
1072 if (pressed) {
Michael Kolb8872c232013-01-29 10:33:22 -08001073 mFocusManager.onShutterDown();
1074 } else {
Doris Liuda50e052013-02-07 14:36:32 -08001075 // for countdown mode, we need to postpone the shutter release
1076 // i.e. lock the focus during countdown.
Michael Kolbd6954f32013-03-08 20:43:01 -08001077 if (!mUI.isCountingDown()) {
Doris Liuda50e052013-02-07 14:36:32 -08001078 mFocusManager.onShutterUp();
1079 }
Michael Kolb8872c232013-01-29 10:33:22 -08001080 }
1081 }
1082
1083 @Override
1084 public void onShutterButtonClick() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001085 if (mPaused || mUI.collapseCameraControls()
Michael Kolb8872c232013-01-29 10:33:22 -08001086 || (mCameraState == SWITCHING_CAMERA)
1087 || (mCameraState == PREVIEW_STOPPED)) return;
1088
1089 // Do not take the picture if there is not enough storage.
1090 if (mActivity.getStorageSpace() <= Storage.LOW_STORAGE_THRESHOLD) {
1091 Log.i(TAG, "Not enough space or storage not ready. remaining="
1092 + mActivity.getStorageSpace());
1093 return;
1094 }
1095 Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1096
Angus Kongb50b5cb2013-08-09 14:55:20 -07001097 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -07001098 mUI.hideSwitcher();
1099 mUI.setSwipingEnabled(false);
Doris Liu9cdfe002013-04-16 09:50:56 -07001100 }
Michael Kolb8872c232013-01-29 10:33:22 -08001101 // If the user wants to do a snapshot while the previous one is still
1102 // in progress, remember the fact and do it after we finish the previous
1103 // one and re-start the preview. Snapshot in progress also includes the
1104 // state that autofocus is focusing and a picture will be taken when
1105 // focus callback arrives.
1106 if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1107 && !mIsImageCaptureIntent) {
1108 mSnapshotOnIdle = true;
1109 return;
1110 }
1111
1112 String timer = mPreferences.getString(
1113 CameraSettings.KEY_TIMER,
1114 mActivity.getString(R.string.pref_camera_timer_default));
1115 boolean playSound = mPreferences.getString(CameraSettings.KEY_TIMER_SOUND_EFFECTS,
1116 mActivity.getString(R.string.pref_camera_timer_sound_default))
1117 .equals(mActivity.getString(R.string.setting_on_value));
1118
1119 int seconds = Integer.parseInt(timer);
1120 // When shutter button is pressed, check whether the previous countdown is
1121 // finished. If not, cancel the previous countdown and start a new one.
Michael Kolbd6954f32013-03-08 20:43:01 -08001122 if (mUI.isCountingDown()) {
1123 mUI.cancelCountDown();
1124 }
1125 if (seconds > 0) {
1126 mUI.startCountDown(seconds, playSound);
Michael Kolb8872c232013-01-29 10:33:22 -08001127 } else {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001128 mSnapshotOnIdle = false;
1129 mFocusManager.doSnap();
Michael Kolb8872c232013-01-29 10:33:22 -08001130 }
1131 }
1132
1133 @Override
1134 public void installIntentFilter() {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001135 // Install an intent filter to receive remote shutter events.
1136 IntentFilter intentFilter =
Dan Aminzadefca1c5e2013-08-14 17:36:56 -07001137 new IntentFilter(CameraUtil.ACTION_CAMERA_SHUTTER_CLICK);
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001138 mReceiver = new ShutterBroadcastReceiver();
1139 mActivity.registerReceiver(mReceiver, intentFilter);
Michael Kolb8872c232013-01-29 10:33:22 -08001140 }
1141
1142 @Override
1143 public boolean updateStorageHintOnResume() {
1144 return mFirstTimeInitialized;
1145 }
1146
1147 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001148 public void onResumeBeforeSuper() {
1149 mPaused = false;
1150 }
1151
Angus Kong4f795b82013-09-16 14:25:35 -07001152 /**
1153 * Opens the camera device.
1154 *
1155 * @return Whether the camera was opened successfully.
1156 */
1157 private boolean prepareCamera() {
1158 // We need to check whether the activity is paused before long
1159 // operations to ensure that onPause() can be done ASAP.
1160 mCameraDevice = CameraUtil.openCamera(
1161 mActivity, mCameraId, mHandler,
1162 mActivity.getCameraOpenErrorCallback());
1163 if (mCameraDevice == null) {
1164 Log.e(TAG, "Failed to open camera:" + mCameraId);
1165 return false;
Angus Kongdcccc512013-08-08 17:06:03 -07001166 }
Angus Kong4f795b82013-09-16 14:25:35 -07001167 mParameters = mCameraDevice.getParameters();
1168
1169 initializeCapabilities();
1170 if (mFocusManager == null) initializeFocusManager();
1171 setCameraParameters(UPDATE_PARAM_ALL);
1172 mHandler.sendEmptyMessage(CAMERA_OPEN_DONE);
1173 mCameraPreviewParamsReady = true;
1174 startPreview();
1175 mOnResumeTime = SystemClock.uptimeMillis();
1176 checkDisplayRotation();
1177 return true;
Angus Kongdcccc512013-08-08 17:06:03 -07001178 }
1179
1180
Michael Kolb8872c232013-01-29 10:33:22 -08001181 @Override
1182 public void onResumeAfterSuper() {
1183 if (mOpenCameraFail || mCameraDisabled) return;
1184
1185 mJpegPictureCallbackTime = 0;
1186 mZoomValue = 0;
Angus Kongdcccc512013-08-08 17:06:03 -07001187 resetExposureCompensation();
Angus Kong4f795b82013-09-16 14:25:35 -07001188 if (!prepareCamera()) {
1189 // Camera failure.
1190 return;
1191 }
Michael Kolb8872c232013-01-29 10:33:22 -08001192
1193 // If first time initialization is not finished, put it in the
1194 // message queue.
1195 if (!mFirstTimeInitialized) {
1196 mHandler.sendEmptyMessage(FIRST_TIME_INIT);
1197 } else {
1198 initializeSecondTime();
1199 }
1200 keepScreenOnAwhile();
1201
1202 // Dismiss open menu if exists.
1203 PopupManager.getInstance(mActivity).notifyShowPopup(null);
Bobby Georgescu0a7dd572013-03-12 22:45:17 -07001204 UsageStatistics.onContentViewChanged(
1205 UsageStatistics.COMPONENT_CAMERA, "PhotoModule");
Angus Kong0d00a892013-03-26 11:40:40 -07001206
1207 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1208 if (gsensor != null) {
1209 mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1210 }
1211
1212 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1213 if (msensor != null) {
1214 mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1215 }
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001216
1217 installIntentFilter();
Dan Aminzadefca1c5e2013-08-14 17:36:56 -07001218 Intent intent = new Intent(CameraUtil.ACTION_CAMERA_STARTED);
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001219 mActivity.sendBroadcast(intent);
Michael Kolb8872c232013-01-29 10:33:22 -08001220 }
1221
Michael Kolb8872c232013-01-29 10:33:22 -08001222 @Override
1223 public void onPauseBeforeSuper() {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001224
Dan Aminzadefca1c5e2013-08-14 17:36:56 -07001225 Intent intent = new Intent(CameraUtil.ACTION_CAMERA_STOPPED);
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001226 mActivity.sendBroadcast(intent);
1227
1228 if (mReceiver != null) {
1229 mActivity.unregisterReceiver(mReceiver);
1230 mReceiver = null;
1231 }
1232
Michael Kolb8872c232013-01-29 10:33:22 -08001233 mPaused = true;
Angus Kong0d00a892013-03-26 11:40:40 -07001234 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1235 if (gsensor != null) {
1236 mSensorManager.unregisterListener(this, gsensor);
1237 }
1238
1239 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1240 if (msensor != null) {
1241 mSensorManager.unregisterListener(this, msensor);
1242 }
Michael Kolb8872c232013-01-29 10:33:22 -08001243 }
1244
1245 @Override
1246 public void onPauseAfterSuper() {
Michael Kolb8872c232013-01-29 10:33:22 -08001247 // When camera is started from secure lock screen for the first time
1248 // after screen on, the activity gets onCreate->onResume->onPause->onResume.
1249 // To reduce the latency, keep the camera for a short time so it does
1250 // not need to be opened again.
1251 if (mCameraDevice != null && mActivity.isSecureCamera()
Angus Kong6a8e8a12013-07-19 14:55:07 -07001252 && CameraActivity.isFirstStartAfterScreenOn()) {
1253 CameraActivity.resetFirstStartAfterScreenOn();
Michael Kolb8872c232013-01-29 10:33:22 -08001254 CameraHolder.instance().keep(KEEP_CAMERA_TIMEOUT);
1255 }
1256 // Reset the focus first. Camera CTS does not guarantee that
1257 // cancelAutoFocus is allowed after preview stops.
1258 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1259 mCameraDevice.cancelAutoFocus();
1260 }
1261 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001262
Angus Kongce5480e2013-01-29 17:43:48 -08001263 mNamedImages = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001264
1265 if (mLocationManager != null) mLocationManager.recordLocation(false);
1266
1267 // If we are in an image capture intent and has taken
1268 // a picture, we just clear it in onPause.
1269 mJpegImageData = null;
1270
Angus Kongdcccc512013-08-08 17:06:03 -07001271 // Remove the messages and runnables in the queue.
1272 mHandler.removeCallbacksAndMessages(null);
Michael Kolb8872c232013-01-29 10:33:22 -08001273
Michael Kolbd6954f32013-03-08 20:43:01 -08001274 closeCamera();
1275
1276 resetScreenOn();
1277 mUI.onPause();
1278
Michael Kolb8872c232013-01-29 10:33:22 -08001279 mPendingSwitchCameraId = -1;
1280 if (mFocusManager != null) mFocusManager.removeMessages();
Angus Kong86d36312013-01-31 18:22:44 -08001281 MediaSaveService s = mActivity.getMediaSaveService();
1282 if (s != null) {
1283 s.setListener(null);
1284 }
Michael Kolb8872c232013-01-29 10:33:22 -08001285 }
1286
Michael Kolb8872c232013-01-29 10:33:22 -08001287 /**
1288 * The focus manager is the first UI related element to get initialized,
1289 * and it requires the RenderOverlay, so initialize it here
1290 */
1291 private void initializeFocusManager() {
1292 // Create FocusManager object. startPreview needs it.
Michael Kolb8872c232013-01-29 10:33:22 -08001293 // if mFocusManager not null, reuse it
1294 // otherwise create a new instance
1295 if (mFocusManager != null) {
1296 mFocusManager.removeMessages();
1297 } else {
1298 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -07001299 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
Michael Kolb8872c232013-01-29 10:33:22 -08001300 String[] defaultFocusModes = mActivity.getResources().getStringArray(
1301 R.array.pref_camera_focusmode_default_array);
1302 mFocusManager = new FocusOverlayManager(mPreferences, defaultFocusModes,
Doris Liu29da2db2013-08-28 14:28:45 -07001303 mInitialParams, this, mMirror,
Michael Kolbd6954f32013-03-08 20:43:01 -08001304 mActivity.getMainLooper(), mUI);
Michael Kolb8872c232013-01-29 10:33:22 -08001305 }
1306 }
1307
Michael Kolb8872c232013-01-29 10:33:22 -08001308 @Override
1309 public void onConfigurationChanged(Configuration newConfig) {
1310 Log.v(TAG, "onConfigurationChanged");
1311 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001312 }
1313
1314 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001315 public void updateCameraOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001316 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001317 setDisplayOrientation();
1318 }
1319 }
1320
1321 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001322 public void onActivityResult(
1323 int requestCode, int resultCode, Intent data) {
1324 switch (requestCode) {
1325 case REQUEST_CROP: {
1326 Intent intent = new Intent();
1327 if (data != null) {
1328 Bundle extras = data.getExtras();
1329 if (extras != null) {
1330 intent.putExtras(extras);
1331 }
1332 }
1333 mActivity.setResultEx(resultCode, intent);
1334 mActivity.finish();
1335
1336 File path = mActivity.getFileStreamPath(sTempCropFilename);
1337 path.delete();
1338
1339 break;
1340 }
1341 }
1342 }
1343
1344 private boolean canTakePicture() {
1345 return isCameraIdle() && (mActivity.getStorageSpace() > Storage.LOW_STORAGE_THRESHOLD);
1346 }
1347
1348 @Override
1349 public void autoFocus() {
1350 mFocusStartTime = System.currentTimeMillis();
Angus Kong9ef99252013-07-18 18:04:19 -07001351 mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001352 setCameraState(FOCUSING);
1353 }
1354
1355 @Override
1356 public void cancelAutoFocus() {
1357 mCameraDevice.cancelAutoFocus();
1358 setCameraState(IDLE);
1359 setCameraParameters(UPDATE_PARAM_PREFERENCE);
1360 }
1361
1362 // Preview area is touched. Handle touch focus.
1363 @Override
1364 public void onSingleTapUp(View view, int x, int y) {
1365 if (mPaused || mCameraDevice == null || !mFirstTimeInitialized
1366 || mCameraState == SNAPSHOT_IN_PROGRESS
1367 || mCameraState == SWITCHING_CAMERA
1368 || mCameraState == PREVIEW_STOPPED) {
1369 return;
1370 }
1371
Michael Kolb8872c232013-01-29 10:33:22 -08001372 // Check if metering area or focus area is supported.
1373 if (!mFocusAreaSupported && !mMeteringAreaSupported) return;
1374 mFocusManager.onSingleTapUp(x, y);
1375 }
1376
1377 @Override
1378 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001379 return mUI.onBackPressed();
Michael Kolb8872c232013-01-29 10:33:22 -08001380 }
1381
1382 @Override
1383 public boolean onKeyDown(int keyCode, KeyEvent event) {
1384 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001385 case KeyEvent.KEYCODE_VOLUME_UP:
1386 case KeyEvent.KEYCODE_VOLUME_DOWN:
1387 case KeyEvent.KEYCODE_FOCUS:
1388 if (/*TODO: mActivity.isInCameraApp() &&*/ mFirstTimeInitialized) {
1389 if (event.getRepeatCount() == 0) {
1390 onShutterButtonFocus(true);
1391 }
1392 return true;
1393 }
1394 return false;
1395 case KeyEvent.KEYCODE_CAMERA:
1396 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1397 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001398 }
1399 return true;
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001400 case KeyEvent.KEYCODE_DPAD_CENTER:
1401 // If we get a dpad center event without any focused view, move
1402 // the focus to the shutter button and press it.
1403 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1404 // Start auto-focus immediately to reduce shutter lag. After
1405 // the shutter button gets the focus, onShutterButtonFocus()
1406 // will be called again but it is fine.
1407 onShutterButtonFocus(true);
1408 mUI.pressShutterButton();
1409 }
1410 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001411 }
1412 return false;
1413 }
1414
1415 @Override
1416 public boolean onKeyUp(int keyCode, KeyEvent event) {
1417 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001418 case KeyEvent.KEYCODE_VOLUME_UP:
1419 case KeyEvent.KEYCODE_VOLUME_DOWN:
1420 if (/*mActivity.isInCameraApp() && */ mFirstTimeInitialized) {
1421 onShutterButtonClick();
1422 return true;
1423 }
1424 return false;
1425 case KeyEvent.KEYCODE_FOCUS:
1426 if (mFirstTimeInitialized) {
1427 onShutterButtonFocus(false);
1428 }
Michael Kolb8872c232013-01-29 10:33:22 -08001429 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001430 }
1431 return false;
1432 }
1433
Michael Kolb8872c232013-01-29 10:33:22 -08001434 private void closeCamera() {
1435 if (mCameraDevice != null) {
1436 mCameraDevice.setZoomChangeListener(null);
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001437 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001438 mCameraDevice.setErrorCallback(null);
1439 CameraHolder.instance().release();
1440 mFaceDetectionStarted = false;
1441 mCameraDevice = null;
1442 setCameraState(PREVIEW_STOPPED);
1443 mFocusManager.onCameraReleased();
1444 }
1445 }
1446
1447 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001448 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1449 mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001450 mCameraDisplayOrientation = mDisplayOrientation;
Michael Kolbd6954f32013-03-08 20:43:01 -08001451 mUI.setDisplayOrientation(mDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001452 if (mFocusManager != null) {
1453 mFocusManager.setDisplayOrientation(mDisplayOrientation);
1454 }
Doris Liu6432cd62013-06-13 17:20:31 -07001455 // Change the camera display orientation
1456 if (mCameraDevice != null) {
1457 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1458 }
Michael Kolb8872c232013-01-29 10:33:22 -08001459 }
1460
Sascha Haeberlingddef7792013-08-13 14:41:10 -07001461 /** Only called by UI thread. */
Michael Kolb8872c232013-01-29 10:33:22 -08001462 private void setupPreview() {
1463 mFocusManager.resetTouchFocus();
1464 startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001465 }
1466
Angus Kongdcccc512013-08-08 17:06:03 -07001467 // This can only be called by UI Thread.
Michael Kolb8872c232013-01-29 10:33:22 -08001468 private void startPreview() {
Angus Kongdcccc512013-08-08 17:06:03 -07001469 if (mPaused) {
1470 return;
1471 }
1472 SurfaceTexture st = mUI.getSurfaceTexture();
1473 if (st == null) {
1474 Log.w(TAG, "startPreview: surfaceTexture is not ready.");
1475 return;
1476 }
1477 if (!mCameraPreviewParamsReady) {
1478 Log.w(TAG, "startPreview: parameters for preview is not ready.");
1479 return;
1480 }
Michael Kolb8872c232013-01-29 10:33:22 -08001481 mCameraDevice.setErrorCallback(mErrorCallback);
1482
1483 // ICS camera frameworks has a bug. Face detection state is not cleared
1484 // after taking a picture. Stop the preview to work around it. The bug
1485 // was fixed in JB.
1486 if (mCameraState != PREVIEW_STOPPED) stopPreview();
1487
1488 setDisplayOrientation();
1489
1490 if (!mSnapshotOnIdle) {
1491 // If the focus mode is continuous autofocus, call cancelAutoFocus to
1492 // resume it because it may have been paused by autoFocus call.
Angus Kongb50b5cb2013-08-09 14:55:20 -07001493 if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) {
Michael Kolb8872c232013-01-29 10:33:22 -08001494 mCameraDevice.cancelAutoFocus();
1495 }
1496 mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1497 }
1498 setCameraParameters(UPDATE_PARAM_ALL);
Doris Liu6432cd62013-06-13 17:20:31 -07001499 // Let UI set its expected aspect ratio
Angus Kongdcccc512013-08-08 17:06:03 -07001500 mCameraDevice.setPreviewTexture(st);
Michael Kolb8872c232013-01-29 10:33:22 -08001501
1502 Log.v(TAG, "startPreview");
Angus Kong9ef99252013-07-18 18:04:19 -07001503 mCameraDevice.startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001504 mFocusManager.onPreviewStarted();
Angus Kongdcccc512013-08-08 17:06:03 -07001505 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001506
1507 if (mSnapshotOnIdle) {
1508 mHandler.post(mDoSnapRunnable);
1509 }
1510 }
1511
Michael Kolbd6954f32013-03-08 20:43:01 -08001512 @Override
1513 public void stopPreview() {
Michael Kolb8872c232013-01-29 10:33:22 -08001514 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1515 Log.v(TAG, "stopPreview");
1516 mCameraDevice.stopPreview();
1517 mFaceDetectionStarted = false;
1518 }
1519 setCameraState(PREVIEW_STOPPED);
1520 if (mFocusManager != null) mFocusManager.onPreviewStopped();
1521 }
1522
1523 @SuppressWarnings("deprecation")
1524 private void updateCameraParametersInitialize() {
1525 // Reset preview frame rate to the maximum because it may be lowered by
1526 // video camera application.
ztenghui16a35202013-09-23 11:35:36 -07001527 int[] fpsRange = CameraUtil.getPhotoPreviewFpsRange(mParameters);
1528 if (fpsRange != null && fpsRange.length > 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001529 mParameters.setPreviewFpsRange(
1530 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1531 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
Michael Kolb8872c232013-01-29 10:33:22 -08001532 }
1533
Angus Kongb50b5cb2013-08-09 14:55:20 -07001534 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);
Michael Kolb8872c232013-01-29 10:33:22 -08001535
1536 // Disable video stabilization. Convenience methods not available in API
1537 // level <= 14
1538 String vstabSupported = mParameters.get("video-stabilization-supported");
1539 if ("true".equals(vstabSupported)) {
1540 mParameters.set("video-stabilization", "false");
1541 }
1542 }
1543
1544 private void updateCameraParametersZoom() {
1545 // Set zoom.
1546 if (mParameters.isZoomSupported()) {
1547 mParameters.setZoom(mZoomValue);
1548 }
1549 }
1550
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001551 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001552 private void setAutoExposureLockIfSupported() {
1553 if (mAeLockSupported) {
1554 mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1555 }
1556 }
1557
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001558 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001559 private void setAutoWhiteBalanceLockIfSupported() {
1560 if (mAwbLockSupported) {
1561 mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1562 }
1563 }
1564
Michael Kolb8872c232013-01-29 10:33:22 -08001565 private void setFocusAreasIfSupported() {
1566 if (mFocusAreaSupported) {
1567 mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1568 }
1569 }
1570
Michael Kolb8872c232013-01-29 10:33:22 -08001571 private void setMeteringAreasIfSupported() {
1572 if (mMeteringAreaSupported) {
1573 // Use the same area for focus and metering.
1574 mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1575 }
1576 }
1577
1578 private void updateCameraParametersPreference() {
1579 setAutoExposureLockIfSupported();
1580 setAutoWhiteBalanceLockIfSupported();
1581 setFocusAreasIfSupported();
1582 setMeteringAreasIfSupported();
1583
1584 // Set picture size.
1585 String pictureSize = mPreferences.getString(
1586 CameraSettings.KEY_PICTURE_SIZE, null);
1587 if (pictureSize == null) {
1588 CameraSettings.initialCameraPictureSize(mActivity, mParameters);
1589 } else {
1590 List<Size> supported = mParameters.getSupportedPictureSizes();
1591 CameraSettings.setCameraPictureSize(
1592 pictureSize, supported, mParameters);
1593 }
1594 Size size = mParameters.getPictureSize();
1595
1596 // Set a preview size that is closest to the viewfinder height and has
1597 // the right aspect ratio.
1598 List<Size> sizes = mParameters.getSupportedPreviewSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001599 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
Michael Kolb8872c232013-01-29 10:33:22 -08001600 (double) size.width / size.height);
1601 Size original = mParameters.getPreviewSize();
1602 if (!original.equals(optimalSize)) {
1603 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
Doris Liu6432cd62013-06-13 17:20:31 -07001604
Michael Kolb8872c232013-01-29 10:33:22 -08001605 // Zoom related settings will be changed for different preview
1606 // sizes, so set and read the parameters to get latest values
Michael Kolb4a4d4ef2013-05-30 08:35:26 -07001607 if (mHandler.getLooper() == Looper.myLooper()) {
1608 // On UI thread only, not when camera starts up
1609 setupPreview();
1610 } else {
1611 mCameraDevice.setParameters(mParameters);
1612 }
Michael Kolb8872c232013-01-29 10:33:22 -08001613 mParameters = mCameraDevice.getParameters();
1614 }
1615 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
1616
1617 // Since changing scene mode may change supported values, set scene mode
1618 // first. HDR is a scene mode. To promote it in UI, it is stored in a
1619 // separate preference.
1620 String hdr = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR,
1621 mActivity.getString(R.string.pref_camera_hdr_default));
1622 if (mActivity.getString(R.string.setting_on_value).equals(hdr)) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001623 mSceneMode = CameraUtil.SCENE_MODE_HDR;
Michael Kolb8872c232013-01-29 10:33:22 -08001624 } else {
1625 mSceneMode = mPreferences.getString(
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001626 CameraSettings.KEY_SCENE_MODE,
1627 mActivity.getString(R.string.pref_camera_scenemode_default));
Michael Kolb8872c232013-01-29 10:33:22 -08001628 }
Angus Kongb50b5cb2013-08-09 14:55:20 -07001629 if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
Michael Kolb8872c232013-01-29 10:33:22 -08001630 if (!mParameters.getSceneMode().equals(mSceneMode)) {
1631 mParameters.setSceneMode(mSceneMode);
1632
1633 // Setting scene mode will change the settings of flash mode,
1634 // white balance, and focus mode. Here we read back the
1635 // parameters, so we can know those settings.
1636 mCameraDevice.setParameters(mParameters);
1637 mParameters = mCameraDevice.getParameters();
1638 }
1639 } else {
1640 mSceneMode = mParameters.getSceneMode();
1641 if (mSceneMode == null) {
1642 mSceneMode = Parameters.SCENE_MODE_AUTO;
1643 }
1644 }
1645
1646 // Set JPEG quality.
1647 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1648 CameraProfile.QUALITY_HIGH);
1649 mParameters.setJpegQuality(jpegQuality);
1650
1651 // For the following settings, we need to check if the settings are
1652 // still supported by latest driver, if not, ignore the settings.
1653
1654 // Set exposure compensation
1655 int value = CameraSettings.readExposure(mPreferences);
1656 int max = mParameters.getMaxExposureCompensation();
1657 int min = mParameters.getMinExposureCompensation();
1658 if (value >= min && value <= max) {
1659 mParameters.setExposureCompensation(value);
1660 } else {
1661 Log.w(TAG, "invalid exposure range: " + value);
1662 }
1663
1664 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1665 // Set flash mode.
1666 String flashMode = mPreferences.getString(
1667 CameraSettings.KEY_FLASH_MODE,
1668 mActivity.getString(R.string.pref_camera_flashmode_default));
1669 List<String> supportedFlash = mParameters.getSupportedFlashModes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001670 if (CameraUtil.isSupported(flashMode, supportedFlash)) {
Michael Kolb8872c232013-01-29 10:33:22 -08001671 mParameters.setFlashMode(flashMode);
1672 } else {
1673 flashMode = mParameters.getFlashMode();
1674 if (flashMode == null) {
1675 flashMode = mActivity.getString(
1676 R.string.pref_camera_flashmode_no_flash);
1677 }
1678 }
1679
1680 // Set white balance parameter.
1681 String whiteBalance = mPreferences.getString(
1682 CameraSettings.KEY_WHITE_BALANCE,
1683 mActivity.getString(R.string.pref_camera_whitebalance_default));
Angus Kongb50b5cb2013-08-09 14:55:20 -07001684 if (CameraUtil.isSupported(whiteBalance,
Michael Kolb8872c232013-01-29 10:33:22 -08001685 mParameters.getSupportedWhiteBalance())) {
1686 mParameters.setWhiteBalance(whiteBalance);
1687 } else {
1688 whiteBalance = mParameters.getWhiteBalance();
1689 if (whiteBalance == null) {
1690 whiteBalance = Parameters.WHITE_BALANCE_AUTO;
1691 }
1692 }
1693
1694 // Set focus mode.
1695 mFocusManager.overrideFocusMode(null);
1696 mParameters.setFocusMode(mFocusManager.getFocusMode());
1697 } else {
1698 mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1699 }
1700
Angus Kongdcccc512013-08-08 17:06:03 -07001701 if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
Michael Kolb8872c232013-01-29 10:33:22 -08001702 updateAutoFocusMoveCallback();
1703 }
1704 }
1705
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001706 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001707 private void updateAutoFocusMoveCallback() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001708 if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Angus Kong9ef99252013-07-18 18:04:19 -07001709 mCameraDevice.setAutoFocusMoveCallback(mHandler,
Angus Kong4f795b82013-09-16 14:25:35 -07001710 (CameraAFMoveCallback) mAutoFocusMoveCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001711 } else {
Angus Kong9ef99252013-07-18 18:04:19 -07001712 mCameraDevice.setAutoFocusMoveCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001713 }
1714 }
1715
1716 // We separate the parameters into several subsets, so we can update only
1717 // the subsets actually need updating. The PREFERENCE set needs extra
1718 // locking because the preference can be changed from GLThread as well.
1719 private void setCameraParameters(int updateSet) {
1720 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1721 updateCameraParametersInitialize();
1722 }
1723
1724 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1725 updateCameraParametersZoom();
1726 }
1727
1728 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
1729 updateCameraParametersPreference();
1730 }
1731
1732 mCameraDevice.setParameters(mParameters);
1733 }
1734
1735 // If the Camera is idle, update the parameters immediately, otherwise
1736 // accumulate them in mUpdateSet and update later.
1737 private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1738 mUpdateSet |= additionalUpdateSet;
1739 if (mCameraDevice == null) {
1740 // We will update all the parameters when we open the device, so
1741 // we don't need to do anything now.
1742 mUpdateSet = 0;
1743 return;
1744 } else if (isCameraIdle()) {
1745 setCameraParameters(mUpdateSet);
Michael Kolbd6954f32013-03-08 20:43:01 -08001746 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001747 mUpdateSet = 0;
1748 } else {
1749 if (!mHandler.hasMessages(SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1750 mHandler.sendEmptyMessageDelayed(
1751 SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
1752 }
1753 }
1754 }
1755
ztenghui7b265a62013-09-09 14:58:44 -07001756 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001757 public boolean isCameraIdle() {
Michael Kolb8872c232013-01-29 10:33:22 -08001758 return (mCameraState == IDLE) ||
1759 (mCameraState == PREVIEW_STOPPED) ||
1760 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
1761 && (mCameraState != SWITCHING_CAMERA));
1762 }
1763
ztenghui7b265a62013-09-09 14:58:44 -07001764 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001765 public boolean isImageCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001766 String action = mActivity.getIntent().getAction();
1767 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
Angus Kong6a8e8a12013-07-19 14:55:07 -07001768 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
Michael Kolb8872c232013-01-29 10:33:22 -08001769 }
1770
1771 private void setupCaptureParams() {
1772 Bundle myExtras = mActivity.getIntent().getExtras();
1773 if (myExtras != null) {
1774 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1775 mCropValue = myExtras.getString("crop");
1776 }
1777 }
1778
Michael Kolb8872c232013-01-29 10:33:22 -08001779 @Override
1780 public void onSharedPreferenceChanged() {
1781 // ignore the events after "onPause()"
1782 if (mPaused) return;
1783
1784 boolean recordLocation = RecordLocationPreference.get(
1785 mPreferences, mContentResolver);
1786 mLocationManager.recordLocation(recordLocation);
1787
1788 setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
Michael Kolbeb8adc12013-04-26 11:09:29 -07001789 mUI.updateOnScreenIndicators(mParameters, mPreferenceGroup, mPreferences);
Michael Kolb8872c232013-01-29 10:33:22 -08001790 }
1791
1792 @Override
1793 public void onCameraPickerClicked(int cameraId) {
1794 if (mPaused || mPendingSwitchCameraId != -1) return;
1795
1796 mPendingSwitchCameraId = cameraId;
Doris Liu6432cd62013-06-13 17:20:31 -07001797
1798 Log.v(TAG, "Start to switch camera. cameraId=" + cameraId);
1799 // We need to keep a preview frame for the animation before
1800 // releasing the camera. This will trigger onPreviewTextureCopied.
1801 //TODO: Need to animate the camera switch
1802 switchCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001803 }
1804
Michael Kolb8872c232013-01-29 10:33:22 -08001805 // Preview texture has been copied. Now camera can be released and the
1806 // animation can be started.
1807 @Override
1808 public void onPreviewTextureCopied() {
1809 mHandler.sendEmptyMessage(SWITCH_CAMERA);
1810 }
1811
1812 @Override
1813 public void onCaptureTextureCopied() {
1814 }
1815
1816 @Override
1817 public void onUserInteraction() {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001818 if (!mActivity.isFinishing()) keepScreenOnAwhile();
Michael Kolb8872c232013-01-29 10:33:22 -08001819 }
1820
1821 private void resetScreenOn() {
1822 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1823 mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1824 }
1825
1826 private void keepScreenOnAwhile() {
1827 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1828 mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1829 mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
1830 }
1831
Michael Kolb8872c232013-01-29 10:33:22 -08001832 @Override
1833 public void onOverriddenPreferencesClicked() {
1834 if (mPaused) return;
Michael Kolbd6954f32013-03-08 20:43:01 -08001835 mUI.showPreferencesToast();
Michael Kolb8872c232013-01-29 10:33:22 -08001836 }
1837
1838 private void showTapToFocusToast() {
1839 // TODO: Use a toast?
1840 new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
1841 // Clear the preference.
1842 Editor editor = mPreferences.edit();
1843 editor.putBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, false);
1844 editor.apply();
1845 }
1846
1847 private void initializeCapabilities() {
1848 mInitialParams = mCameraDevice.getParameters();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001849 mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
1850 mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
1851 mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
1852 mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
Angus Kongdcccc512013-08-08 17:06:03 -07001853 mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001854 CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
Michael Kolb8872c232013-01-29 10:33:22 -08001855 }
1856
Michael Kolb8872c232013-01-29 10:33:22 -08001857 @Override
1858 public void onCountDownFinished() {
1859 mSnapshotOnIdle = false;
1860 mFocusManager.doSnap();
Doris Liuda50e052013-02-07 14:36:32 -08001861 mFocusManager.onShutterUp();
Michael Kolb8872c232013-01-29 10:33:22 -08001862 }
1863
Michael Kolb8872c232013-01-29 10:33:22 -08001864 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001865 public void onShowSwitcherPopup() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001866 mUI.onShowSwitcherPopup();
Michael Kolb8872c232013-01-29 10:33:22 -08001867 }
1868
Angus Kongce5480e2013-01-29 17:43:48 -08001869 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001870 public int onZoomChanged(int index) {
1871 // Not useful to change zoom value when the activity is paused.
1872 if (mPaused) return index;
1873 mZoomValue = index;
1874 if (mParameters == null || mCameraDevice == null) return index;
1875 // Set zoom parameters asynchronously
1876 mParameters.setZoom(mZoomValue);
Angus Kong36ed8672013-04-15 12:11:15 -07001877 mCameraDevice.setParameters(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -08001878 Parameters p = mCameraDevice.getParameters();
1879 if (p != null) return p.getZoom();
1880 return index;
Angus Kongce5480e2013-01-29 17:43:48 -08001881 }
1882
1883 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001884 public int getCameraState() {
1885 return mCameraState;
1886 }
1887
1888 @Override
1889 public void onQueueStatus(boolean full) {
1890 mUI.enableShutter(!full);
Angus Kongce5480e2013-01-29 17:43:48 -08001891 }
Angus Kong86d36312013-01-31 18:22:44 -08001892
1893 @Override
1894 public void onMediaSaveServiceConnected(MediaSaveService s) {
1895 // We set the listener only when both service and shutterbutton
1896 // are initialized.
Michael Kolbd6954f32013-03-08 20:43:01 -08001897 if (mFirstTimeInitialized) {
1898 s.setListener(this);
1899 }
Angus Kong86d36312013-01-31 18:22:44 -08001900 }
Angus Kong0d00a892013-03-26 11:40:40 -07001901
1902 @Override
1903 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1904 }
1905
1906 @Override
1907 public void onSensorChanged(SensorEvent event) {
1908 int type = event.sensor.getType();
1909 float[] data;
1910 if (type == Sensor.TYPE_ACCELEROMETER) {
1911 data = mGData;
1912 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
1913 data = mMData;
1914 } else {
1915 // we should not be here.
1916 return;
1917 }
1918 for (int i = 0; i < 3 ; i++) {
1919 data[i] = event.values[i];
1920 }
1921 float[] orientation = new float[3];
1922 SensorManager.getRotationMatrix(mR, null, mGData, mMData);
1923 SensorManager.getOrientation(mR, orientation);
1924 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
1925 if (mHeading < 0) {
1926 mHeading += 360;
1927 }
Angus Kong0d00a892013-03-26 11:40:40 -07001928 }
Doris Liu6432cd62013-06-13 17:20:31 -07001929
1930 @Override
ztenghui7b265a62013-09-09 14:58:44 -07001931 public void onPreviewFocusChanged(boolean previewFocused) {
1932 mUI.onPreviewFocusChanged(previewFocused);
Doris Liu6432cd62013-06-13 17:20:31 -07001933 }
1934
1935/* Below is no longer needed, except to get rid of compile error
1936 * TODO: Remove these
1937 */
1938
1939 // TODO: Delete this function after old camera code is removed
1940 @Override
1941 public void onRestorePreferencesClicked() {}
1942
Michael Kolb8872c232013-01-29 10:33:22 -08001943}