blob: 3c495dbfee9519a6b640cd3d8c979f273df04b8d [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;
Ruben Brunk4601f5d2013-09-24 18:35:22 -070065import com.android.camera.ui.ModuleSwitcher;
Michael Kolb8872c232013-01-29 10:33:22 -080066import com.android.camera.ui.RotateTextToast;
Angus Kongdcccc512013-08-08 17:06:03 -070067import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -070068import com.android.camera.util.CameraUtil;
Ruben Brunk4601f5d2013-09-24 18:35:22 -070069import com.android.camera.util.GcamHelper;
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
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
Michael Kolb8872c232013-01-29 10:33:22 -0800346 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700347 public void init(CameraActivity activity, View parent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800348 mActivity = activity;
Michael Kolbd6954f32013-03-08 20:43:01 -0800349 mUI = new PhotoUI(activity, this, parent);
Michael Kolb8872c232013-01-29 10:33:22 -0800350 mPreferences = new ComboPreferences(mActivity);
351 CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal());
352 mCameraId = getPreferredCameraId(mPreferences);
353
354 mContentResolver = mActivity.getContentResolver();
355
Michael Kolb8872c232013-01-29 10:33:22 -0800356 // Surface texture is from camera screen nail and startPreview needs it.
357 // This must be done before startPreview.
358 mIsImageCaptureIntent = isImageCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800359
360 mPreferences.setLocalId(mActivity, mCameraId);
361 CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
362 // we need to reset exposure for the preview
363 resetExposureCompensation();
Michael Kolb8872c232013-01-29 10:33:22 -0800364
365 initializeControlByIntent();
366 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
Michael Kolbd6954f32013-03-08 20:43:01 -0800367 mLocationManager = new LocationManager(mActivity, mUI);
Angus Kong0d00a892013-03-26 11:40:40 -0700368 mSensorManager = (SensorManager)(mActivity.getSystemService(Context.SENSOR_SERVICE));
Michael Kolbd6954f32013-03-08 20:43:01 -0800369 }
370
371 private void initializeControlByIntent() {
372 mUI.initializeControlByIntent();
373 if (mIsImageCaptureIntent) {
374 setupCaptureParams();
375 }
376 }
377
378 private void onPreviewStarted() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800379 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800380 startFaceDetection();
381 locationFirstRun();
Michael Kolb8872c232013-01-29 10:33:22 -0800382 }
383
384 // Prompt the user to pick to record location for the very first run of
385 // camera only
386 private void locationFirstRun() {
387 if (RecordLocationPreference.isSet(mPreferences)) {
388 return;
389 }
390 if (mActivity.isSecureCamera()) return;
391 // Check if the back camera exists
392 int backCameraId = CameraHolder.instance().getBackCameraId();
393 if (backCameraId == -1) {
394 // If there is no back camera, do not show the prompt.
395 return;
396 }
Doris Liu6a83d522013-07-02 12:03:32 -0700397 mUI.showLocationDialog();
398 }
Michael Kolb8872c232013-01-29 10:33:22 -0800399
ztenghui7b265a62013-09-09 14:58:44 -0700400 @Override
Doris Liu6a83d522013-07-02 12:03:32 -0700401 public void enableRecordingLocation(boolean enable) {
402 setLocationPreference(enable ? RecordLocationPreference.VALUE_ON
403 : RecordLocationPreference.VALUE_OFF);
Michael Kolb8872c232013-01-29 10:33:22 -0800404 }
405
Angus Kongdcccc512013-08-08 17:06:03 -0700406 @Override
407 public void onPreviewUIReady() {
408 startPreview();
409 }
410
411 @Override
412 public void onPreviewUIDestroyed() {
413 if (mCameraDevice == null) {
414 return;
415 }
416 mCameraDevice.setPreviewTexture(null);
417 stopPreview();
418 }
419
Michael Kolb8872c232013-01-29 10:33:22 -0800420 private void setLocationPreference(String value) {
421 mPreferences.edit()
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700422 .putString(CameraSettings.KEY_RECORD_LOCATION, value)
423 .apply();
Michael Kolb8872c232013-01-29 10:33:22 -0800424 // TODO: Fix this to use the actual onSharedPreferencesChanged listener
425 // instead of invoking manually
426 onSharedPreferenceChanged();
427 }
428
Michael Kolbd6954f32013-03-08 20:43:01 -0800429 private void onCameraOpened() {
430 View root = mUI.getRootView();
Michael Kolb8872c232013-01-29 10:33:22 -0800431 // These depend on camera parameters.
Michael Kolbd6954f32013-03-08 20:43:01 -0800432
433 int width = root.getWidth();
434 int height = root.getHeight();
Doris Liu6a0de792013-02-26 10:54:25 -0800435 mFocusManager.setPreviewSize(width, height);
Michael Kolbd6954f32013-03-08 20:43:01 -0800436 openCameraCommon();
Michael Kolb8872c232013-01-29 10:33:22 -0800437 }
438
Michael Kolbd6954f32013-03-08 20:43:01 -0800439 private void switchCamera() {
440 if (mPaused) return;
441
442 Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
443 mCameraId = mPendingSwitchCameraId;
444 mPendingSwitchCameraId = -1;
445 setCameraId(mCameraId);
446
447 // from onPause
448 closeCamera();
449 mUI.collapseCameraControls();
450 mUI.clearFaces();
451 if (mFocusManager != null) mFocusManager.removeMessages();
452
453 // Restart the camera and initialize the UI. From onCreate.
454 mPreferences.setLocalId(mActivity, mCameraId);
455 CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
Angus Kong4f795b82013-09-16 14:25:35 -0700456 mCameraDevice = CameraUtil.openCamera(
457 mActivity, mCameraId, mHandler,
458 mActivity.getCameraOpenErrorCallback());
459 if (mCameraDevice == null) {
460 Log.e(TAG, "Failed to open camera:" + mCameraId + ", aborting.");
Michael Kolbd6954f32013-03-08 20:43:01 -0800461 return;
Doris Liu09106a42013-03-05 09:54:25 -0800462 }
Angus Kong4f795b82013-09-16 14:25:35 -0700463 mParameters = mCameraDevice.getParameters();
Michael Kolbd6954f32013-03-08 20:43:01 -0800464 initializeCapabilities();
465 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -0700466 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
467 mFocusManager.setMirror(mMirror);
Michael Kolbd6954f32013-03-08 20:43:01 -0800468 mFocusManager.setParameters(mInitialParams);
469 setupPreview();
470
Doris Liu6432cd62013-06-13 17:20:31 -0700471 // reset zoom value index
472 mZoomValue = 0;
Michael Kolbd6954f32013-03-08 20:43:01 -0800473 openCameraCommon();
474
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700475 // Start switch camera animation. Post a message because
476 // onFrameAvailable from the old camera may already exist.
477 mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION);
Doris Liu48239f42013-03-04 22:19:10 -0800478 }
479
Michael Kolbd6954f32013-03-08 20:43:01 -0800480 protected void setCameraId(int cameraId) {
481 ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID);
482 pref.setValue("" + cameraId);
483 }
484
485 // either open a new camera or switch cameras
486 private void openCameraCommon() {
Michael Kolb8872c232013-01-29 10:33:22 -0800487 loadCameraPreferences();
Michael Kolbd6954f32013-03-08 20:43:01 -0800488
489 mUI.onCameraOpened(mPreferenceGroup, mPreferences, mParameters, this);
Angus Kong0fb819b2013-10-08 13:44:19 -0700490 if (mIsImageCaptureIntent) {
491 mUI.overrideSettings(CameraSettings.KEY_CAMERA_HDR_PLUS,
492 mActivity.getString(R.string.setting_off_value));
493 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800494 updateSceneMode();
495 showTapToFocusToastIfNeeded();
496
497
Michael Kolb8872c232013-01-29 10:33:22 -0800498 }
499
ztenghui7b265a62013-09-09 14:58:44 -0700500 @Override
Doris Liub3749f22013-09-25 12:22:08 -0700501 public void onScreenSizeChanged(int width, int height) {
Michael Kolbd6954f32013-03-08 20:43:01 -0800502 if (mFocusManager != null) mFocusManager.setPreviewSize(width, height);
Michael Kolbd6954f32013-03-08 20:43:01 -0800503 }
Michael Kolb8872c232013-01-29 10:33:22 -0800504
505 private void resetExposureCompensation() {
506 String value = mPreferences.getString(CameraSettings.KEY_EXPOSURE,
507 CameraSettings.EXPOSURE_DEFAULT_VALUE);
508 if (!CameraSettings.EXPOSURE_DEFAULT_VALUE.equals(value)) {
509 Editor editor = mPreferences.edit();
510 editor.putString(CameraSettings.KEY_EXPOSURE, "0");
511 editor.apply();
512 }
513 }
514
515 private void keepMediaProviderInstance() {
516 // We want to keep a reference to MediaProvider in camera's lifecycle.
517 // TODO: Utilize mMediaProviderClient instance to replace
518 // ContentResolver calls.
519 if (mMediaProviderClient == null) {
520 mMediaProviderClient = mContentResolver
521 .acquireContentProviderClient(MediaStore.AUTHORITY);
522 }
523 }
524
525 // Snapshots can only be taken after this is called. It should be called
526 // once only. We could have done these things in onCreate() but we want to
527 // make preview screen appear as soon as possible.
528 private void initializeFirstTime() {
529 if (mFirstTimeInitialized) return;
530
531 // Initialize location service.
532 boolean recordLocation = RecordLocationPreference.get(
533 mPreferences, mContentResolver);
534 mLocationManager.recordLocation(recordLocation);
535
536 keepMediaProviderInstance();
537
Michael Kolbd6954f32013-03-08 20:43:01 -0800538 mUI.initializeFirstTime();
Angus Kong86d36312013-01-31 18:22:44 -0800539 MediaSaveService s = mActivity.getMediaSaveService();
540 // We set the listener only when both service and shutterbutton
541 // are initialized.
542 if (s != null) {
543 s.setListener(this);
544 }
Michael Kolb8872c232013-01-29 10:33:22 -0800545
Michael Kolb8872c232013-01-29 10:33:22 -0800546 mNamedImages = new NamedImages();
547
548 mFirstTimeInitialized = true;
549 addIdleHandler();
550
551 mActivity.updateStorageSpaceAndHint();
552 }
553
Michael Kolbd6954f32013-03-08 20:43:01 -0800554 // If the activity is paused and resumed, this method will be called in
555 // onResume.
556 private void initializeSecondTime() {
557 // Start location update if needed.
558 boolean recordLocation = RecordLocationPreference.get(
559 mPreferences, mContentResolver);
560 mLocationManager.recordLocation(recordLocation);
561 MediaSaveService s = mActivity.getMediaSaveService();
562 if (s != null) {
563 s.setListener(this);
564 }
565 mNamedImages = new NamedImages();
566 mUI.initializeSecondTime(mParameters);
567 keepMediaProviderInstance();
568 }
569
Michael Kolb8872c232013-01-29 10:33:22 -0800570 private void showTapToFocusToastIfNeeded() {
571 // Show the tap to focus toast if this is the first start.
572 if (mFocusAreaSupported &&
573 mPreferences.getBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, true)) {
574 // Delay the toast for one second to wait for orientation.
575 mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_FOCUS_TOAST, 1000);
576 }
577 }
578
579 private void addIdleHandler() {
580 MessageQueue queue = Looper.myQueue();
581 queue.addIdleHandler(new MessageQueue.IdleHandler() {
582 @Override
583 public boolean queueIdle() {
584 Storage.ensureOSXCompatible();
585 return false;
586 }
587 });
588 }
589
Michael Kolb8872c232013-01-29 10:33:22 -0800590 @Override
591 public void startFaceDetection() {
Michael Kolb8872c232013-01-29 10:33:22 -0800592 if (mFaceDetectionStarted) return;
593 if (mParameters.getMaxNumDetectedFaces() > 0) {
594 mFaceDetectionStarted = true;
Michael Kolb8872c232013-01-29 10:33:22 -0800595 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Michael Kolbd6954f32013-03-08 20:43:01 -0800596 mUI.onStartFaceDetection(mDisplayOrientation,
597 (info.facing == CameraInfo.CAMERA_FACING_FRONT));
Angus Kong9e765522013-07-31 14:05:20 -0700598 mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Michael Kolb8872c232013-01-29 10:33:22 -0800599 mCameraDevice.startFaceDetection();
600 }
601 }
602
Michael Kolb8872c232013-01-29 10:33:22 -0800603 @Override
604 public void stopFaceDetection() {
Michael Kolb8872c232013-01-29 10:33:22 -0800605 if (!mFaceDetectionStarted) return;
606 if (mParameters.getMaxNumDetectedFaces() > 0) {
607 mFaceDetectionStarted = false;
Angus Kong9e765522013-07-31 14:05:20 -0700608 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -0800609 mCameraDevice.stopFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800610 mUI.clearFaces();
Michael Kolb8872c232013-01-29 10:33:22 -0800611 }
612 }
613
Michael Kolb8872c232013-01-29 10:33:22 -0800614 private final class ShutterCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700615 implements CameraShutterCallback {
Angus Kongdcb0ef12013-03-25 23:11:43 -0700616
Sascha Haeberling37f36112013-08-06 14:31:52 -0700617 private boolean mNeedsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700618
Sascha Haeberling37f36112013-08-06 14:31:52 -0700619 public ShutterCallback(boolean needsAnimation) {
620 mNeedsAnimation = needsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700621 }
622
Michael Kolb8872c232013-01-29 10:33:22 -0800623 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700624 public void onShutter(CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800625 mShutterCallbackTime = System.currentTimeMillis();
626 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
627 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Sascha Haeberling37f36112013-08-06 14:31:52 -0700628 if (mNeedsAnimation) {
629 mActivity.runOnUiThread(new Runnable() {
630 @Override
631 public void run() {
632 animateAfterShutter();
633 }
634 });
Angus Kongdcb0ef12013-03-25 23:11:43 -0700635 }
Michael Kolb8872c232013-01-29 10:33:22 -0800636 }
637 }
638
Angus Kong9ef99252013-07-18 18:04:19 -0700639 private final class PostViewPictureCallback
640 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800641 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700642 public void onPictureTaken(byte [] data, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800643 mPostViewPictureCallbackTime = System.currentTimeMillis();
644 Log.v(TAG, "mShutterToPostViewCallbackTime = "
645 + (mPostViewPictureCallbackTime - mShutterCallbackTime)
646 + "ms");
647 }
648 }
649
Angus Kong9ef99252013-07-18 18:04:19 -0700650 private final class RawPictureCallback
651 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800652 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700653 public void onPictureTaken(byte [] rawData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800654 mRawPictureCallbackTime = System.currentTimeMillis();
655 Log.v(TAG, "mShutterToRawCallbackTime = "
656 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
657 }
658 }
659
Angus Kong9ef99252013-07-18 18:04:19 -0700660 private final class JpegPictureCallback
661 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800662 Location mLocation;
663
664 public JpegPictureCallback(Location loc) {
665 mLocation = loc;
666 }
667
668 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700669 public void onPictureTaken(final byte [] jpegData, CameraProxy camera) {
Sascha Haeberling88901942013-08-28 17:49:00 -0700670 mUI.enableShutter(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800671 if (mPaused) {
672 return;
673 }
Doris Liu6432cd62013-06-13 17:20:31 -0700674 if (mIsImageCaptureIntent) {
675 stopPreview();
676 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700677 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -0700678 mUI.showSwitcher();
679 mUI.setSwipingEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800680 }
681
682 mJpegPictureCallbackTime = System.currentTimeMillis();
683 // If postview callback has arrived, the captured image is displayed
684 // in postview callback. If not, the captured image is displayed in
685 // raw picture callback.
686 if (mPostViewPictureCallbackTime != 0) {
687 mShutterToPictureDisplayedTime =
688 mPostViewPictureCallbackTime - mShutterCallbackTime;
689 mPictureDisplayedToJpegCallbackTime =
690 mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
691 } else {
692 mShutterToPictureDisplayedTime =
693 mRawPictureCallbackTime - mShutterCallbackTime;
694 mPictureDisplayedToJpegCallbackTime =
695 mJpegPictureCallbackTime - mRawPictureCallbackTime;
696 }
697 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
698 + mPictureDisplayedToJpegCallbackTime + "ms");
699
Michael Kolb8872c232013-01-29 10:33:22 -0800700 mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
701 if (!mIsImageCaptureIntent) {
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700702 setupPreview();
Michael Kolb8872c232013-01-29 10:33:22 -0800703 }
704
Doris Liu36e56fb2013-09-11 17:38:08 -0700705 ExifInterface exif = Exif.getExif(jpegData);
706 int orientation = Exif.getOrientation(exif);
Michael Kolb8872c232013-01-29 10:33:22 -0800707 if (!mIsImageCaptureIntent) {
708 // Calculate the width and the height of the jpeg.
709 Size s = mParameters.getPictureSize();
Michael Kolb8872c232013-01-29 10:33:22 -0800710 int width, height;
711 if ((mJpegRotation + orientation) % 180 == 0) {
712 width = s.width;
713 height = s.height;
714 } else {
715 width = s.height;
716 height = s.width;
717 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700718 NamedEntity name = mNamedImages.getNextNameEntity();
719 String title = (name == null) ? null : name.title;
720 long date = (name == null) ? -1 : name.date;
Michael Kolb8872c232013-01-29 10:33:22 -0800721 if (title == null) {
722 Log.e(TAG, "Unbalanced name/data pair");
723 } else {
724 if (date == -1) date = mCaptureStartTime;
Angus Kong0d00a892013-03-26 11:40:40 -0700725 if (mHeading >= 0) {
726 // heading direction has been updated by the sensor.
727 ExifTag directionRefTag = exif.buildTag(
728 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
729 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
730 ExifTag directionTag = exif.buildTag(
731 ExifInterface.TAG_GPS_IMG_DIRECTION,
732 new Rational(mHeading, 1));
733 exif.setTag(directionRefTag);
734 exif.setTag(directionTag);
735 }
Angus Kong86d36312013-01-31 18:22:44 -0800736 mActivity.getMediaSaveService().addImage(
737 jpegData, title, date, mLocation, width, height,
Angus Kong0d00a892013-03-26 11:40:40 -0700738 orientation, exif, mOnMediaSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -0800739 }
Doris Liuce2acbc2013-08-21 18:45:29 -0700740 // Animate capture with real jpeg data instead of a preview frame.
Doris Liu29da2db2013-08-28 14:28:45 -0700741 mUI.animateCapture(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800742 } else {
743 mJpegImageData = jpegData;
744 if (!mQuickCapture) {
Doris Liu36e56fb2013-09-11 17:38:08 -0700745 mUI.showCapturedImageForReview(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800746 } else {
Michael Kolbd6954f32013-03-08 20:43:01 -0800747 onCaptureDone();
Michael Kolb8872c232013-01-29 10:33:22 -0800748 }
749 }
750
751 // Check this in advance of each shot so we don't add to shutter
752 // latency. It's true that someone else could write to the SD card in
753 // the mean time and fill it, but that could have happened between the
754 // shutter press and saving the JPEG too.
755 mActivity.updateStorageSpaceAndHint();
756
757 long now = System.currentTimeMillis();
758 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
759 Log.v(TAG, "mJpegCallbackFinishTime = "
760 + mJpegCallbackFinishTime + "ms");
761 mJpegPictureCallbackTime = 0;
762 }
763 }
764
Angus Kong9ef99252013-07-18 18:04:19 -0700765 private final class AutoFocusCallback implements CameraAFCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800766 @Override
767 public void onAutoFocus(
Angus Kong9ef99252013-07-18 18:04:19 -0700768 boolean focused, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800769 if (mPaused) return;
770
771 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
772 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
773 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800774 mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
Michael Kolb8872c232013-01-29 10:33:22 -0800775 }
776 }
777
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700778 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -0800779 private final class AutoFocusMoveCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700780 implements CameraAFMoveCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800781 @Override
782 public void onAutoFocusMoving(
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700783 boolean moving, CameraProxy camera) {
784 mFocusManager.onAutoFocusMoving(moving);
Michael Kolb8872c232013-01-29 10:33:22 -0800785 }
786 }
787
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700788 /**
789 * This class is just a thread-safe queue for name,date holder objects.
790 */
791 public static class NamedImages {
792 private Vector<NamedEntity> mQueue;
Michael Kolb8872c232013-01-29 10:33:22 -0800793
794 public NamedImages() {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700795 mQueue = new Vector<NamedEntity>();
Michael Kolb8872c232013-01-29 10:33:22 -0800796 }
797
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700798 public void nameNewImage(long date) {
Michael Kolb8872c232013-01-29 10:33:22 -0800799 NamedEntity r = new NamedEntity();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700800 r.title = CameraUtil.createJpegName(date);
Michael Kolb8872c232013-01-29 10:33:22 -0800801 r.date = date;
802 mQueue.add(r);
803 }
804
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700805 public NamedEntity getNextNameEntity() {
806 synchronized(mQueue) {
807 if (!mQueue.isEmpty()) {
808 return mQueue.remove(0);
809 }
Michael Kolb8872c232013-01-29 10:33:22 -0800810 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700811 return null;
Michael Kolb8872c232013-01-29 10:33:22 -0800812 }
813
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700814 public static class NamedEntity {
815 public String title;
816 public long date;
Michael Kolb8872c232013-01-29 10:33:22 -0800817 }
818 }
819
820 private void setCameraState(int state) {
821 mCameraState = state;
822 switch (state) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700823 case PhotoController.PREVIEW_STOPPED:
824 case PhotoController.SNAPSHOT_IN_PROGRESS:
825 case PhotoController.SWITCHING_CAMERA:
826 mUI.enableGestures(false);
827 break;
828 case PhotoController.IDLE:
829 mUI.enableGestures(true);
830 break;
Michael Kolb8872c232013-01-29 10:33:22 -0800831 }
832 }
833
Sascha Haeberling37f36112013-08-06 14:31:52 -0700834 private void animateAfterShutter() {
Michael Kolb8872c232013-01-29 10:33:22 -0800835 // Only animate when in full screen capture mode
836 // i.e. If monkey/a user swipes to the gallery during picture taking,
837 // don't show animation
Doris Liuc2e9abd2013-06-19 14:20:51 -0700838 if (!mIsImageCaptureIntent) {
839 mUI.animateFlash();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700840 }
Michael Kolb8872c232013-01-29 10:33:22 -0800841 }
842
843 @Override
844 public boolean capture() {
845 // If we are already in the middle of taking a snapshot or the image save request
846 // is full then ignore.
847 if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
Angus Kong86d36312013-01-31 18:22:44 -0800848 || mCameraState == SWITCHING_CAMERA
849 || mActivity.getMediaSaveService().isQueueFull()) {
Michael Kolb8872c232013-01-29 10:33:22 -0800850 return false;
851 }
852 mCaptureStartTime = System.currentTimeMillis();
853 mPostViewPictureCallbackTime = 0;
854 mJpegImageData = null;
855
Angus Kongb50b5cb2013-08-09 14:55:20 -0700856 final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
Michael Kolb8872c232013-01-29 10:33:22 -0800857
858 if (animateBefore) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700859 animateAfterShutter();
Michael Kolb8872c232013-01-29 10:33:22 -0800860 }
861
862 // Set rotation and gps data.
Doris Liu3cf565c2013-02-15 10:55:37 -0800863 int orientation;
864 // We need to be consistent with the framework orientation (i.e. the
865 // orientation of the UI.) when the auto-rotate screen setting is on.
866 if (mActivity.isAutoRotateScreen()) {
867 orientation = (360 - mDisplayRotation) % 360;
868 } else {
869 orientation = mOrientation;
870 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700871 mJpegRotation = CameraUtil.getJpegRotation(mCameraId, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800872 mParameters.setRotation(mJpegRotation);
873 Location loc = mLocationManager.getCurrentLocation();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700874 CameraUtil.setGpsParameters(mParameters, loc);
Michael Kolb8872c232013-01-29 10:33:22 -0800875 mCameraDevice.setParameters(mParameters);
876
Sascha Haeberling88901942013-08-28 17:49:00 -0700877 // We don't want user to press the button again while taking a
878 // multi-second HDR photo.
879 mUI.enableShutter(false);
Angus Kong9ef99252013-07-18 18:04:19 -0700880 mCameraDevice.takePicture(mHandler,
881 new ShutterCallback(!animateBefore),
Angus Kongdcb0ef12013-03-25 23:11:43 -0700882 mRawPictureCallback, mPostViewPictureCallback,
Angus Kong9ef99252013-07-18 18:04:19 -0700883 new JpegPictureCallback(loc));
Michael Kolb8872c232013-01-29 10:33:22 -0800884
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700885 mNamedImages.nameNewImage(mCaptureStartTime);
Michael Kolb8872c232013-01-29 10:33:22 -0800886
887 mFaceDetectionStarted = false;
888 setCameraState(SNAPSHOT_IN_PROGRESS);
Bobby Georgescu301b6462013-04-01 15:33:17 -0700889 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
890 UsageStatistics.ACTION_CAPTURE_DONE, "Photo");
Michael Kolb8872c232013-01-29 10:33:22 -0800891 return true;
892 }
893
894 @Override
895 public void setFocusParameters() {
896 setCameraParameters(UPDATE_PARAM_PREFERENCE);
897 }
898
899 private int getPreferredCameraId(ComboPreferences preferences) {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700900 int intentCameraId = CameraUtil.getCameraFacingIntentExtras(mActivity);
Michael Kolb8872c232013-01-29 10:33:22 -0800901 if (intentCameraId != -1) {
902 // Testing purpose. Launch a specific camera through the intent
903 // extras.
904 return intentCameraId;
905 } else {
906 return CameraSettings.readPreferredCameraId(preferences);
907 }
908 }
909
Michael Kolbd6954f32013-03-08 20:43:01 -0800910 private void updateSceneMode() {
Michael Kolb8872c232013-01-29 10:33:22 -0800911 // If scene mode is set, we cannot set flash mode, white balance, and
912 // focus mode, instead, we read it from driver
913 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
914 overrideCameraSettings(mParameters.getFlashMode(),
915 mParameters.getWhiteBalance(), mParameters.getFocusMode());
916 } else {
917 overrideCameraSettings(null, null, null);
918 }
919 }
920
921 private void overrideCameraSettings(final String flashMode,
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700922 final String whiteBalance, final String focusMode) {
Michael Kolbd6954f32013-03-08 20:43:01 -0800923 mUI.overrideSettings(
924 CameraSettings.KEY_FLASH_MODE, flashMode,
925 CameraSettings.KEY_WHITE_BALANCE, whiteBalance,
926 CameraSettings.KEY_FOCUS_MODE, focusMode);
Michael Kolb8872c232013-01-29 10:33:22 -0800927 }
928
929 private void loadCameraPreferences() {
930 CameraSettings settings = new CameraSettings(mActivity, mInitialParams,
931 mCameraId, CameraHolder.instance().getCameraInfo());
932 mPreferenceGroup = settings.getPreferenceGroup(R.xml.camera_preferences);
933 }
934
935 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800936 public void onOrientationChanged(int orientation) {
937 // We keep the last known orientation. So if the user first orient
938 // the camera then point the camera to floor or sky, we still have
939 // the correct orientation.
940 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700941 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800942
943 // Show the toast after getting the first orientation changed.
944 if (mHandler.hasMessages(SHOW_TAP_TO_FOCUS_TOAST)) {
945 mHandler.removeMessages(SHOW_TAP_TO_FOCUS_TOAST);
946 showTapToFocusToast();
947 }
948 }
949
950 @Override
951 public void onStop() {
952 if (mMediaProviderClient != null) {
953 mMediaProviderClient.release();
954 mMediaProviderClient = null;
955 }
956 }
957
Michael Kolbd6954f32013-03-08 20:43:01 -0800958 @Override
959 public void onCaptureCancelled() {
960 mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
961 mActivity.finish();
Michael Kolb8872c232013-01-29 10:33:22 -0800962 }
963
Michael Kolbd6954f32013-03-08 20:43:01 -0800964 @Override
965 public void onCaptureRetake() {
Michael Kolb8872c232013-01-29 10:33:22 -0800966 if (mPaused)
967 return;
Michael Kolbd6954f32013-03-08 20:43:01 -0800968 mUI.hidePostCaptureAlert();
Michael Kolb8872c232013-01-29 10:33:22 -0800969 setupPreview();
970 }
971
Michael Kolbd6954f32013-03-08 20:43:01 -0800972 @Override
973 public void onCaptureDone() {
Michael Kolb8872c232013-01-29 10:33:22 -0800974 if (mPaused) {
975 return;
976 }
977
978 byte[] data = mJpegImageData;
979
980 if (mCropValue == null) {
981 // First handle the no crop case -- just return the value. If the
982 // caller specifies a "save uri" then write the data to its
983 // stream. Otherwise, pass back a scaled down version of the bitmap
984 // directly in the extras.
985 if (mSaveUri != null) {
986 OutputStream outputStream = null;
987 try {
988 outputStream = mContentResolver.openOutputStream(mSaveUri);
989 outputStream.write(data);
990 outputStream.close();
991
992 mActivity.setResultEx(Activity.RESULT_OK);
993 mActivity.finish();
994 } catch (IOException ex) {
995 // ignore exception
996 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700997 CameraUtil.closeSilently(outputStream);
Michael Kolb8872c232013-01-29 10:33:22 -0800998 }
999 } else {
Angus Kong0d00a892013-03-26 11:40:40 -07001000 ExifInterface exif = Exif.getExif(data);
1001 int orientation = Exif.getOrientation(exif);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001002 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
1003 bitmap = CameraUtil.rotate(bitmap, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001004 mActivity.setResultEx(Activity.RESULT_OK,
1005 new Intent("inline-data").putExtra("data", bitmap));
1006 mActivity.finish();
1007 }
1008 } else {
1009 // Save the image to a temp file and invoke the cropper
1010 Uri tempUri = null;
1011 FileOutputStream tempStream = null;
1012 try {
1013 File path = mActivity.getFileStreamPath(sTempCropFilename);
1014 path.delete();
1015 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1016 tempStream.write(data);
1017 tempStream.close();
1018 tempUri = Uri.fromFile(path);
1019 } catch (FileNotFoundException ex) {
1020 mActivity.setResultEx(Activity.RESULT_CANCELED);
1021 mActivity.finish();
1022 return;
1023 } catch (IOException ex) {
1024 mActivity.setResultEx(Activity.RESULT_CANCELED);
1025 mActivity.finish();
1026 return;
1027 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001028 CameraUtil.closeSilently(tempStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001029 }
1030
1031 Bundle newExtras = new Bundle();
1032 if (mCropValue.equals("circle")) {
1033 newExtras.putString("circleCrop", "true");
1034 }
1035 if (mSaveUri != null) {
1036 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1037 } else {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001038 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001039 }
1040 if (mActivity.isSecureCamera()) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001041 newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001042 }
1043
Sascha Haeberling37f36112013-08-06 14:31:52 -07001044 // TODO: Share this constant.
Sascha Haeberling8e963a52013-08-06 11:43:02 -07001045 final String CROP_ACTION = "com.android.camera.action.CROP";
1046 Intent cropIntent = new Intent(CROP_ACTION);
Michael Kolb8872c232013-01-29 10:33:22 -08001047
1048 cropIntent.setData(tempUri);
1049 cropIntent.putExtras(newExtras);
1050
1051 mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1052 }
1053 }
1054
Michael Kolb8872c232013-01-29 10:33:22 -08001055 @Override
1056 public void onShutterButtonFocus(boolean pressed) {
Michael Kolbd6954f32013-03-08 20:43:01 -08001057 if (mPaused || mUI.collapseCameraControls()
Michael Kolb8872c232013-01-29 10:33:22 -08001058 || (mCameraState == SNAPSHOT_IN_PROGRESS)
1059 || (mCameraState == PREVIEW_STOPPED)) return;
1060
1061 // Do not do focus if there is not enough storage.
1062 if (pressed && !canTakePicture()) return;
1063
1064 if (pressed) {
Michael Kolb8872c232013-01-29 10:33:22 -08001065 mFocusManager.onShutterDown();
1066 } else {
Doris Liuda50e052013-02-07 14:36:32 -08001067 // for countdown mode, we need to postpone the shutter release
1068 // i.e. lock the focus during countdown.
Michael Kolbd6954f32013-03-08 20:43:01 -08001069 if (!mUI.isCountingDown()) {
Doris Liuda50e052013-02-07 14:36:32 -08001070 mFocusManager.onShutterUp();
1071 }
Michael Kolb8872c232013-01-29 10:33:22 -08001072 }
1073 }
1074
1075 @Override
1076 public void onShutterButtonClick() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001077 if (mPaused || mUI.collapseCameraControls()
Michael Kolb8872c232013-01-29 10:33:22 -08001078 || (mCameraState == SWITCHING_CAMERA)
1079 || (mCameraState == PREVIEW_STOPPED)) return;
1080
1081 // Do not take the picture if there is not enough storage.
Angus Kong2dcc0a92013-09-25 13:00:08 -07001082 if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Michael Kolb8872c232013-01-29 10:33:22 -08001083 Log.i(TAG, "Not enough space or storage not ready. remaining="
Angus Kong2dcc0a92013-09-25 13:00:08 -07001084 + mActivity.getStorageSpaceBytes());
Michael Kolb8872c232013-01-29 10:33:22 -08001085 return;
1086 }
1087 Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1088
Angus Kongb50b5cb2013-08-09 14:55:20 -07001089 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -07001090 mUI.hideSwitcher();
1091 mUI.setSwipingEnabled(false);
Doris Liu9cdfe002013-04-16 09:50:56 -07001092 }
Michael Kolb8872c232013-01-29 10:33:22 -08001093 // If the user wants to do a snapshot while the previous one is still
1094 // in progress, remember the fact and do it after we finish the previous
1095 // one and re-start the preview. Snapshot in progress also includes the
1096 // state that autofocus is focusing and a picture will be taken when
1097 // focus callback arrives.
1098 if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1099 && !mIsImageCaptureIntent) {
1100 mSnapshotOnIdle = true;
1101 return;
1102 }
1103
1104 String timer = mPreferences.getString(
1105 CameraSettings.KEY_TIMER,
1106 mActivity.getString(R.string.pref_camera_timer_default));
1107 boolean playSound = mPreferences.getString(CameraSettings.KEY_TIMER_SOUND_EFFECTS,
1108 mActivity.getString(R.string.pref_camera_timer_sound_default))
1109 .equals(mActivity.getString(R.string.setting_on_value));
1110
1111 int seconds = Integer.parseInt(timer);
1112 // When shutter button is pressed, check whether the previous countdown is
1113 // finished. If not, cancel the previous countdown and start a new one.
Michael Kolbd6954f32013-03-08 20:43:01 -08001114 if (mUI.isCountingDown()) {
1115 mUI.cancelCountDown();
1116 }
1117 if (seconds > 0) {
1118 mUI.startCountDown(seconds, playSound);
Michael Kolb8872c232013-01-29 10:33:22 -08001119 } else {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001120 mSnapshotOnIdle = false;
1121 mFocusManager.doSnap();
Michael Kolb8872c232013-01-29 10:33:22 -08001122 }
1123 }
1124
1125 @Override
1126 public void installIntentFilter() {
Sascha Haeberling4de78802013-10-06 18:07:07 -07001127 // Do nothing.
Michael Kolb8872c232013-01-29 10:33:22 -08001128 }
1129
1130 @Override
1131 public boolean updateStorageHintOnResume() {
1132 return mFirstTimeInitialized;
1133 }
1134
1135 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001136 public void onResumeBeforeSuper() {
1137 mPaused = false;
1138 }
1139
Angus Kong4f795b82013-09-16 14:25:35 -07001140 /**
1141 * Opens the camera device.
1142 *
1143 * @return Whether the camera was opened successfully.
1144 */
1145 private boolean prepareCamera() {
1146 // We need to check whether the activity is paused before long
1147 // operations to ensure that onPause() can be done ASAP.
1148 mCameraDevice = CameraUtil.openCamera(
1149 mActivity, mCameraId, mHandler,
1150 mActivity.getCameraOpenErrorCallback());
1151 if (mCameraDevice == null) {
1152 Log.e(TAG, "Failed to open camera:" + mCameraId);
1153 return false;
Angus Kongdcccc512013-08-08 17:06:03 -07001154 }
Angus Kong4f795b82013-09-16 14:25:35 -07001155 mParameters = mCameraDevice.getParameters();
1156
1157 initializeCapabilities();
1158 if (mFocusManager == null) initializeFocusManager();
1159 setCameraParameters(UPDATE_PARAM_ALL);
1160 mHandler.sendEmptyMessage(CAMERA_OPEN_DONE);
1161 mCameraPreviewParamsReady = true;
1162 startPreview();
1163 mOnResumeTime = SystemClock.uptimeMillis();
1164 checkDisplayRotation();
1165 return true;
Angus Kongdcccc512013-08-08 17:06:03 -07001166 }
1167
1168
Michael Kolb8872c232013-01-29 10:33:22 -08001169 @Override
1170 public void onResumeAfterSuper() {
1171 if (mOpenCameraFail || mCameraDisabled) return;
1172
1173 mJpegPictureCallbackTime = 0;
1174 mZoomValue = 0;
Angus Kongdcccc512013-08-08 17:06:03 -07001175 resetExposureCompensation();
Angus Kong4f795b82013-09-16 14:25:35 -07001176 if (!prepareCamera()) {
1177 // Camera failure.
1178 return;
1179 }
Michael Kolb8872c232013-01-29 10:33:22 -08001180
1181 // If first time initialization is not finished, put it in the
1182 // message queue.
1183 if (!mFirstTimeInitialized) {
1184 mHandler.sendEmptyMessage(FIRST_TIME_INIT);
1185 } else {
1186 initializeSecondTime();
1187 }
1188 keepScreenOnAwhile();
1189
Bobby Georgescu0a7dd572013-03-12 22:45:17 -07001190 UsageStatistics.onContentViewChanged(
1191 UsageStatistics.COMPONENT_CAMERA, "PhotoModule");
Angus Kong0d00a892013-03-26 11:40:40 -07001192
1193 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1194 if (gsensor != null) {
1195 mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1196 }
1197
1198 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1199 if (msensor != null) {
1200 mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1201 }
Michael Kolb8872c232013-01-29 10:33:22 -08001202 }
1203
Michael Kolb8872c232013-01-29 10:33:22 -08001204 @Override
1205 public void onPauseBeforeSuper() {
1206 mPaused = true;
Angus Kong0d00a892013-03-26 11:40:40 -07001207 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1208 if (gsensor != null) {
1209 mSensorManager.unregisterListener(this, gsensor);
1210 }
1211
1212 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1213 if (msensor != null) {
1214 mSensorManager.unregisterListener(this, msensor);
1215 }
Michael Kolb8872c232013-01-29 10:33:22 -08001216 }
1217
1218 @Override
1219 public void onPauseAfterSuper() {
Michael Kolb8872c232013-01-29 10:33:22 -08001220 // When camera is started from secure lock screen for the first time
1221 // after screen on, the activity gets onCreate->onResume->onPause->onResume.
1222 // To reduce the latency, keep the camera for a short time so it does
1223 // not need to be opened again.
1224 if (mCameraDevice != null && mActivity.isSecureCamera()
Angus Kong6a8e8a12013-07-19 14:55:07 -07001225 && CameraActivity.isFirstStartAfterScreenOn()) {
1226 CameraActivity.resetFirstStartAfterScreenOn();
Michael Kolb8872c232013-01-29 10:33:22 -08001227 CameraHolder.instance().keep(KEEP_CAMERA_TIMEOUT);
1228 }
1229 // Reset the focus first. Camera CTS does not guarantee that
1230 // cancelAutoFocus is allowed after preview stops.
1231 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1232 mCameraDevice.cancelAutoFocus();
1233 }
1234 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001235
Angus Kongce5480e2013-01-29 17:43:48 -08001236 mNamedImages = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001237
1238 if (mLocationManager != null) mLocationManager.recordLocation(false);
1239
1240 // If we are in an image capture intent and has taken
1241 // a picture, we just clear it in onPause.
1242 mJpegImageData = null;
1243
Angus Kongdcccc512013-08-08 17:06:03 -07001244 // Remove the messages and runnables in the queue.
1245 mHandler.removeCallbacksAndMessages(null);
Michael Kolb8872c232013-01-29 10:33:22 -08001246
Michael Kolbd6954f32013-03-08 20:43:01 -08001247 closeCamera();
1248
1249 resetScreenOn();
1250 mUI.onPause();
1251
Michael Kolb8872c232013-01-29 10:33:22 -08001252 mPendingSwitchCameraId = -1;
1253 if (mFocusManager != null) mFocusManager.removeMessages();
Angus Kong86d36312013-01-31 18:22:44 -08001254 MediaSaveService s = mActivity.getMediaSaveService();
1255 if (s != null) {
1256 s.setListener(null);
1257 }
Michael Kolb8872c232013-01-29 10:33:22 -08001258 }
1259
Michael Kolb8872c232013-01-29 10:33:22 -08001260 /**
1261 * The focus manager is the first UI related element to get initialized,
1262 * and it requires the RenderOverlay, so initialize it here
1263 */
1264 private void initializeFocusManager() {
1265 // Create FocusManager object. startPreview needs it.
Michael Kolb8872c232013-01-29 10:33:22 -08001266 // if mFocusManager not null, reuse it
1267 // otherwise create a new instance
1268 if (mFocusManager != null) {
1269 mFocusManager.removeMessages();
1270 } else {
1271 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -07001272 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
Michael Kolb8872c232013-01-29 10:33:22 -08001273 String[] defaultFocusModes = mActivity.getResources().getStringArray(
1274 R.array.pref_camera_focusmode_default_array);
1275 mFocusManager = new FocusOverlayManager(mPreferences, defaultFocusModes,
Doris Liu29da2db2013-08-28 14:28:45 -07001276 mInitialParams, this, mMirror,
Michael Kolbd6954f32013-03-08 20:43:01 -08001277 mActivity.getMainLooper(), mUI);
Michael Kolb8872c232013-01-29 10:33:22 -08001278 }
1279 }
1280
Michael Kolb8872c232013-01-29 10:33:22 -08001281 @Override
1282 public void onConfigurationChanged(Configuration newConfig) {
1283 Log.v(TAG, "onConfigurationChanged");
1284 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001285 }
1286
1287 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001288 public void updateCameraOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001289 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001290 setDisplayOrientation();
1291 }
1292 }
1293
1294 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001295 public void onActivityResult(
1296 int requestCode, int resultCode, Intent data) {
1297 switch (requestCode) {
1298 case REQUEST_CROP: {
1299 Intent intent = new Intent();
1300 if (data != null) {
1301 Bundle extras = data.getExtras();
1302 if (extras != null) {
1303 intent.putExtras(extras);
1304 }
1305 }
1306 mActivity.setResultEx(resultCode, intent);
1307 mActivity.finish();
1308
1309 File path = mActivity.getFileStreamPath(sTempCropFilename);
1310 path.delete();
1311
1312 break;
1313 }
1314 }
1315 }
1316
1317 private boolean canTakePicture() {
Angus Kong2dcc0a92013-09-25 13:00:08 -07001318 return isCameraIdle() && (mActivity.getStorageSpaceBytes() > Storage.LOW_STORAGE_THRESHOLD_BYTES);
Michael Kolb8872c232013-01-29 10:33:22 -08001319 }
1320
1321 @Override
1322 public void autoFocus() {
1323 mFocusStartTime = System.currentTimeMillis();
Angus Kong9ef99252013-07-18 18:04:19 -07001324 mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001325 setCameraState(FOCUSING);
1326 }
1327
1328 @Override
1329 public void cancelAutoFocus() {
1330 mCameraDevice.cancelAutoFocus();
1331 setCameraState(IDLE);
1332 setCameraParameters(UPDATE_PARAM_PREFERENCE);
1333 }
1334
1335 // Preview area is touched. Handle touch focus.
1336 @Override
1337 public void onSingleTapUp(View view, int x, int y) {
1338 if (mPaused || mCameraDevice == null || !mFirstTimeInitialized
1339 || mCameraState == SNAPSHOT_IN_PROGRESS
1340 || mCameraState == SWITCHING_CAMERA
1341 || mCameraState == PREVIEW_STOPPED) {
1342 return;
1343 }
1344
Michael Kolb8872c232013-01-29 10:33:22 -08001345 // Check if metering area or focus area is supported.
1346 if (!mFocusAreaSupported && !mMeteringAreaSupported) return;
1347 mFocusManager.onSingleTapUp(x, y);
1348 }
1349
1350 @Override
1351 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001352 return mUI.onBackPressed();
Michael Kolb8872c232013-01-29 10:33:22 -08001353 }
1354
1355 @Override
1356 public boolean onKeyDown(int keyCode, KeyEvent event) {
1357 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001358 case KeyEvent.KEYCODE_VOLUME_UP:
1359 case KeyEvent.KEYCODE_VOLUME_DOWN:
1360 case KeyEvent.KEYCODE_FOCUS:
1361 if (/*TODO: mActivity.isInCameraApp() &&*/ mFirstTimeInitialized) {
1362 if (event.getRepeatCount() == 0) {
1363 onShutterButtonFocus(true);
1364 }
1365 return true;
1366 }
1367 return false;
1368 case KeyEvent.KEYCODE_CAMERA:
1369 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1370 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001371 }
1372 return true;
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001373 case KeyEvent.KEYCODE_DPAD_CENTER:
1374 // If we get a dpad center event without any focused view, move
1375 // the focus to the shutter button and press it.
1376 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1377 // Start auto-focus immediately to reduce shutter lag. After
1378 // the shutter button gets the focus, onShutterButtonFocus()
1379 // will be called again but it is fine.
1380 onShutterButtonFocus(true);
1381 mUI.pressShutterButton();
1382 }
1383 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001384 }
1385 return false;
1386 }
1387
1388 @Override
1389 public boolean onKeyUp(int keyCode, KeyEvent event) {
1390 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001391 case KeyEvent.KEYCODE_VOLUME_UP:
1392 case KeyEvent.KEYCODE_VOLUME_DOWN:
1393 if (/*mActivity.isInCameraApp() && */ mFirstTimeInitialized) {
1394 onShutterButtonClick();
1395 return true;
1396 }
1397 return false;
1398 case KeyEvent.KEYCODE_FOCUS:
1399 if (mFirstTimeInitialized) {
1400 onShutterButtonFocus(false);
1401 }
Michael Kolb8872c232013-01-29 10:33:22 -08001402 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001403 }
1404 return false;
1405 }
1406
Michael Kolb8872c232013-01-29 10:33:22 -08001407 private void closeCamera() {
1408 if (mCameraDevice != null) {
1409 mCameraDevice.setZoomChangeListener(null);
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001410 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001411 mCameraDevice.setErrorCallback(null);
1412 CameraHolder.instance().release();
1413 mFaceDetectionStarted = false;
1414 mCameraDevice = null;
1415 setCameraState(PREVIEW_STOPPED);
1416 mFocusManager.onCameraReleased();
1417 }
1418 }
1419
1420 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001421 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1422 mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001423 mCameraDisplayOrientation = mDisplayOrientation;
Michael Kolbd6954f32013-03-08 20:43:01 -08001424 mUI.setDisplayOrientation(mDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001425 if (mFocusManager != null) {
1426 mFocusManager.setDisplayOrientation(mDisplayOrientation);
1427 }
Doris Liu6432cd62013-06-13 17:20:31 -07001428 // Change the camera display orientation
1429 if (mCameraDevice != null) {
1430 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1431 }
Michael Kolb8872c232013-01-29 10:33:22 -08001432 }
1433
Sascha Haeberlingddef7792013-08-13 14:41:10 -07001434 /** Only called by UI thread. */
Michael Kolb8872c232013-01-29 10:33:22 -08001435 private void setupPreview() {
1436 mFocusManager.resetTouchFocus();
1437 startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001438 }
1439
Angus Kongdcccc512013-08-08 17:06:03 -07001440 // This can only be called by UI Thread.
Michael Kolb8872c232013-01-29 10:33:22 -08001441 private void startPreview() {
Angus Kongdcccc512013-08-08 17:06:03 -07001442 if (mPaused) {
1443 return;
1444 }
1445 SurfaceTexture st = mUI.getSurfaceTexture();
1446 if (st == null) {
1447 Log.w(TAG, "startPreview: surfaceTexture is not ready.");
1448 return;
1449 }
1450 if (!mCameraPreviewParamsReady) {
1451 Log.w(TAG, "startPreview: parameters for preview is not ready.");
1452 return;
1453 }
Michael Kolb8872c232013-01-29 10:33:22 -08001454 mCameraDevice.setErrorCallback(mErrorCallback);
1455
1456 // ICS camera frameworks has a bug. Face detection state is not cleared
1457 // after taking a picture. Stop the preview to work around it. The bug
1458 // was fixed in JB.
1459 if (mCameraState != PREVIEW_STOPPED) stopPreview();
1460
1461 setDisplayOrientation();
1462
1463 if (!mSnapshotOnIdle) {
1464 // If the focus mode is continuous autofocus, call cancelAutoFocus to
1465 // resume it because it may have been paused by autoFocus call.
Angus Kongb50b5cb2013-08-09 14:55:20 -07001466 if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) {
Michael Kolb8872c232013-01-29 10:33:22 -08001467 mCameraDevice.cancelAutoFocus();
1468 }
1469 mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1470 }
1471 setCameraParameters(UPDATE_PARAM_ALL);
Doris Liu6432cd62013-06-13 17:20:31 -07001472 // Let UI set its expected aspect ratio
Angus Kongdcccc512013-08-08 17:06:03 -07001473 mCameraDevice.setPreviewTexture(st);
Michael Kolb8872c232013-01-29 10:33:22 -08001474
1475 Log.v(TAG, "startPreview");
Angus Kong9ef99252013-07-18 18:04:19 -07001476 mCameraDevice.startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001477 mFocusManager.onPreviewStarted();
Angus Kongdcccc512013-08-08 17:06:03 -07001478 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001479
1480 if (mSnapshotOnIdle) {
1481 mHandler.post(mDoSnapRunnable);
1482 }
1483 }
1484
Michael Kolbd6954f32013-03-08 20:43:01 -08001485 @Override
1486 public void stopPreview() {
Michael Kolb8872c232013-01-29 10:33:22 -08001487 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1488 Log.v(TAG, "stopPreview");
1489 mCameraDevice.stopPreview();
1490 mFaceDetectionStarted = false;
1491 }
1492 setCameraState(PREVIEW_STOPPED);
1493 if (mFocusManager != null) mFocusManager.onPreviewStopped();
1494 }
1495
1496 @SuppressWarnings("deprecation")
1497 private void updateCameraParametersInitialize() {
1498 // Reset preview frame rate to the maximum because it may be lowered by
1499 // video camera application.
ztenghui16a35202013-09-23 11:35:36 -07001500 int[] fpsRange = CameraUtil.getPhotoPreviewFpsRange(mParameters);
1501 if (fpsRange != null && fpsRange.length > 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001502 mParameters.setPreviewFpsRange(
1503 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1504 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
Michael Kolb8872c232013-01-29 10:33:22 -08001505 }
1506
Angus Kongb50b5cb2013-08-09 14:55:20 -07001507 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);
Michael Kolb8872c232013-01-29 10:33:22 -08001508
1509 // Disable video stabilization. Convenience methods not available in API
1510 // level <= 14
1511 String vstabSupported = mParameters.get("video-stabilization-supported");
1512 if ("true".equals(vstabSupported)) {
1513 mParameters.set("video-stabilization", "false");
1514 }
1515 }
1516
1517 private void updateCameraParametersZoom() {
1518 // Set zoom.
1519 if (mParameters.isZoomSupported()) {
1520 mParameters.setZoom(mZoomValue);
1521 }
1522 }
1523
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001524 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001525 private void setAutoExposureLockIfSupported() {
1526 if (mAeLockSupported) {
1527 mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1528 }
1529 }
1530
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001531 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001532 private void setAutoWhiteBalanceLockIfSupported() {
1533 if (mAwbLockSupported) {
1534 mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1535 }
1536 }
1537
Michael Kolb8872c232013-01-29 10:33:22 -08001538 private void setFocusAreasIfSupported() {
1539 if (mFocusAreaSupported) {
1540 mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1541 }
1542 }
1543
Michael Kolb8872c232013-01-29 10:33:22 -08001544 private void setMeteringAreasIfSupported() {
1545 if (mMeteringAreaSupported) {
Michael Kolb8872c232013-01-29 10:33:22 -08001546 mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1547 }
1548 }
1549
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001550 private boolean updateCameraParametersPreference() {
Michael Kolb8872c232013-01-29 10:33:22 -08001551 setAutoExposureLockIfSupported();
1552 setAutoWhiteBalanceLockIfSupported();
1553 setFocusAreasIfSupported();
1554 setMeteringAreasIfSupported();
1555
1556 // Set picture size.
1557 String pictureSize = mPreferences.getString(
1558 CameraSettings.KEY_PICTURE_SIZE, null);
1559 if (pictureSize == null) {
1560 CameraSettings.initialCameraPictureSize(mActivity, mParameters);
1561 } else {
1562 List<Size> supported = mParameters.getSupportedPictureSizes();
1563 CameraSettings.setCameraPictureSize(
1564 pictureSize, supported, mParameters);
1565 }
1566 Size size = mParameters.getPictureSize();
1567
1568 // Set a preview size that is closest to the viewfinder height and has
1569 // the right aspect ratio.
1570 List<Size> sizes = mParameters.getSupportedPreviewSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001571 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
Michael Kolb8872c232013-01-29 10:33:22 -08001572 (double) size.width / size.height);
1573 Size original = mParameters.getPreviewSize();
1574 if (!original.equals(optimalSize)) {
1575 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
Doris Liu6432cd62013-06-13 17:20:31 -07001576
Michael Kolb8872c232013-01-29 10:33:22 -08001577 // Zoom related settings will be changed for different preview
1578 // sizes, so set and read the parameters to get latest values
Michael Kolb4a4d4ef2013-05-30 08:35:26 -07001579 if (mHandler.getLooper() == Looper.myLooper()) {
1580 // On UI thread only, not when camera starts up
1581 setupPreview();
1582 } else {
1583 mCameraDevice.setParameters(mParameters);
1584 }
Michael Kolb8872c232013-01-29 10:33:22 -08001585 mParameters = mCameraDevice.getParameters();
1586 }
1587 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
1588
1589 // Since changing scene mode may change supported values, set scene mode
1590 // first. HDR is a scene mode. To promote it in UI, it is stored in a
1591 // separate preference.
Sascha Haeberling98f38bb2013-09-24 18:58:34 -07001592 String onValue = mActivity.getString(R.string.setting_on_value);
Michael Kolb8872c232013-01-29 10:33:22 -08001593 String hdr = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR,
1594 mActivity.getString(R.string.pref_camera_hdr_default));
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001595 String hdrPlus = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR_PLUS,
1596 mActivity.getString(R.string.pref_camera_hdr_plus_default));
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001597 boolean hdrOn = onValue.equals(hdr);
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001598 boolean hdrPlusOn = onValue.equals(hdrPlus);
Sascha Haeberling98f38bb2013-09-24 18:58:34 -07001599
1600 boolean doGcamModeSwitch = false;
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001601 if (hdrPlusOn && GcamHelper.hasGcamCapture()) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001602 // Kick off mode switch to gcam.
1603 doGcamModeSwitch = true;
Michael Kolb8872c232013-01-29 10:33:22 -08001604 } else {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001605 if (hdrOn) {
1606 mSceneMode = CameraUtil.SCENE_MODE_HDR;
1607 } else {
1608 mSceneMode = mPreferences.getString(
1609 CameraSettings.KEY_SCENE_MODE,
1610 mActivity.getString(R.string.pref_camera_scenemode_default));
1611 }
Michael Kolb8872c232013-01-29 10:33:22 -08001612 }
Angus Kongb50b5cb2013-08-09 14:55:20 -07001613 if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
Michael Kolb8872c232013-01-29 10:33:22 -08001614 if (!mParameters.getSceneMode().equals(mSceneMode)) {
1615 mParameters.setSceneMode(mSceneMode);
1616
1617 // Setting scene mode will change the settings of flash mode,
1618 // white balance, and focus mode. Here we read back the
1619 // parameters, so we can know those settings.
1620 mCameraDevice.setParameters(mParameters);
1621 mParameters = mCameraDevice.getParameters();
1622 }
1623 } else {
1624 mSceneMode = mParameters.getSceneMode();
1625 if (mSceneMode == null) {
1626 mSceneMode = Parameters.SCENE_MODE_AUTO;
1627 }
1628 }
1629
1630 // Set JPEG quality.
1631 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1632 CameraProfile.QUALITY_HIGH);
1633 mParameters.setJpegQuality(jpegQuality);
1634
1635 // For the following settings, we need to check if the settings are
1636 // still supported by latest driver, if not, ignore the settings.
1637
1638 // Set exposure compensation
1639 int value = CameraSettings.readExposure(mPreferences);
1640 int max = mParameters.getMaxExposureCompensation();
1641 int min = mParameters.getMinExposureCompensation();
1642 if (value >= min && value <= max) {
1643 mParameters.setExposureCompensation(value);
1644 } else {
1645 Log.w(TAG, "invalid exposure range: " + value);
1646 }
1647
1648 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1649 // Set flash mode.
1650 String flashMode = mPreferences.getString(
1651 CameraSettings.KEY_FLASH_MODE,
1652 mActivity.getString(R.string.pref_camera_flashmode_default));
1653 List<String> supportedFlash = mParameters.getSupportedFlashModes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001654 if (CameraUtil.isSupported(flashMode, supportedFlash)) {
Michael Kolb8872c232013-01-29 10:33:22 -08001655 mParameters.setFlashMode(flashMode);
1656 } else {
1657 flashMode = mParameters.getFlashMode();
1658 if (flashMode == null) {
1659 flashMode = mActivity.getString(
1660 R.string.pref_camera_flashmode_no_flash);
1661 }
1662 }
1663
1664 // Set white balance parameter.
1665 String whiteBalance = mPreferences.getString(
1666 CameraSettings.KEY_WHITE_BALANCE,
1667 mActivity.getString(R.string.pref_camera_whitebalance_default));
Angus Kongb50b5cb2013-08-09 14:55:20 -07001668 if (CameraUtil.isSupported(whiteBalance,
Michael Kolb8872c232013-01-29 10:33:22 -08001669 mParameters.getSupportedWhiteBalance())) {
1670 mParameters.setWhiteBalance(whiteBalance);
1671 } else {
1672 whiteBalance = mParameters.getWhiteBalance();
1673 if (whiteBalance == null) {
1674 whiteBalance = Parameters.WHITE_BALANCE_AUTO;
1675 }
1676 }
1677
1678 // Set focus mode.
1679 mFocusManager.overrideFocusMode(null);
1680 mParameters.setFocusMode(mFocusManager.getFocusMode());
1681 } else {
1682 mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1683 }
1684
Angus Kongdcccc512013-08-08 17:06:03 -07001685 if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
Michael Kolb8872c232013-01-29 10:33:22 -08001686 updateAutoFocusMoveCallback();
1687 }
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001688
1689 return doGcamModeSwitch;
Michael Kolb8872c232013-01-29 10:33:22 -08001690 }
1691
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001692 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001693 private void updateAutoFocusMoveCallback() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001694 if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Angus Kong9ef99252013-07-18 18:04:19 -07001695 mCameraDevice.setAutoFocusMoveCallback(mHandler,
Angus Kong4f795b82013-09-16 14:25:35 -07001696 (CameraAFMoveCallback) mAutoFocusMoveCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001697 } else {
Angus Kong9ef99252013-07-18 18:04:19 -07001698 mCameraDevice.setAutoFocusMoveCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001699 }
1700 }
1701
1702 // We separate the parameters into several subsets, so we can update only
1703 // the subsets actually need updating. The PREFERENCE set needs extra
1704 // locking because the preference can be changed from GLThread as well.
1705 private void setCameraParameters(int updateSet) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001706 boolean doModeSwitch = false;
1707
Michael Kolb8872c232013-01-29 10:33:22 -08001708 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1709 updateCameraParametersInitialize();
1710 }
1711
1712 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1713 updateCameraParametersZoom();
1714 }
1715
1716 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001717 doModeSwitch = updateCameraParametersPreference();
Michael Kolb8872c232013-01-29 10:33:22 -08001718 }
1719
1720 mCameraDevice.setParameters(mParameters);
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001721
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001722 // Switch to gcam module if HDR+ was selected
Angus Kong0fb819b2013-10-08 13:44:19 -07001723 if (doModeSwitch && !mIsImageCaptureIntent) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001724 mActivity.onModuleSelected(ModuleSwitcher.GCAM_MODULE_INDEX);
1725 }
Michael Kolb8872c232013-01-29 10:33:22 -08001726 }
1727
1728 // If the Camera is idle, update the parameters immediately, otherwise
1729 // accumulate them in mUpdateSet and update later.
1730 private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1731 mUpdateSet |= additionalUpdateSet;
1732 if (mCameraDevice == null) {
1733 // We will update all the parameters when we open the device, so
1734 // we don't need to do anything now.
1735 mUpdateSet = 0;
1736 return;
1737 } else if (isCameraIdle()) {
1738 setCameraParameters(mUpdateSet);
Michael Kolbd6954f32013-03-08 20:43:01 -08001739 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001740 mUpdateSet = 0;
1741 } else {
1742 if (!mHandler.hasMessages(SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1743 mHandler.sendEmptyMessageDelayed(
1744 SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
1745 }
1746 }
1747 }
1748
ztenghui7b265a62013-09-09 14:58:44 -07001749 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001750 public boolean isCameraIdle() {
Michael Kolb8872c232013-01-29 10:33:22 -08001751 return (mCameraState == IDLE) ||
1752 (mCameraState == PREVIEW_STOPPED) ||
1753 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
1754 && (mCameraState != SWITCHING_CAMERA));
1755 }
1756
ztenghui7b265a62013-09-09 14:58:44 -07001757 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001758 public boolean isImageCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001759 String action = mActivity.getIntent().getAction();
1760 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
Angus Kong6a8e8a12013-07-19 14:55:07 -07001761 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
Michael Kolb8872c232013-01-29 10:33:22 -08001762 }
1763
1764 private void setupCaptureParams() {
1765 Bundle myExtras = mActivity.getIntent().getExtras();
1766 if (myExtras != null) {
1767 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1768 mCropValue = myExtras.getString("crop");
1769 }
1770 }
1771
Michael Kolb8872c232013-01-29 10:33:22 -08001772 @Override
1773 public void onSharedPreferenceChanged() {
1774 // ignore the events after "onPause()"
1775 if (mPaused) return;
1776
1777 boolean recordLocation = RecordLocationPreference.get(
1778 mPreferences, mContentResolver);
1779 mLocationManager.recordLocation(recordLocation);
1780
1781 setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
Michael Kolbeb8adc12013-04-26 11:09:29 -07001782 mUI.updateOnScreenIndicators(mParameters, mPreferenceGroup, mPreferences);
Michael Kolb8872c232013-01-29 10:33:22 -08001783 }
1784
1785 @Override
1786 public void onCameraPickerClicked(int cameraId) {
1787 if (mPaused || mPendingSwitchCameraId != -1) return;
1788
1789 mPendingSwitchCameraId = cameraId;
Doris Liu6432cd62013-06-13 17:20:31 -07001790
1791 Log.v(TAG, "Start to switch camera. cameraId=" + cameraId);
1792 // We need to keep a preview frame for the animation before
1793 // releasing the camera. This will trigger onPreviewTextureCopied.
1794 //TODO: Need to animate the camera switch
1795 switchCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001796 }
1797
Michael Kolb8872c232013-01-29 10:33:22 -08001798 // Preview texture has been copied. Now camera can be released and the
1799 // animation can be started.
1800 @Override
1801 public void onPreviewTextureCopied() {
1802 mHandler.sendEmptyMessage(SWITCH_CAMERA);
1803 }
1804
1805 @Override
1806 public void onCaptureTextureCopied() {
1807 }
1808
1809 @Override
1810 public void onUserInteraction() {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001811 if (!mActivity.isFinishing()) keepScreenOnAwhile();
Michael Kolb8872c232013-01-29 10:33:22 -08001812 }
1813
1814 private void resetScreenOn() {
1815 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1816 mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1817 }
1818
1819 private void keepScreenOnAwhile() {
1820 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1821 mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1822 mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
1823 }
1824
Michael Kolb8872c232013-01-29 10:33:22 -08001825 @Override
1826 public void onOverriddenPreferencesClicked() {
1827 if (mPaused) return;
Michael Kolbd6954f32013-03-08 20:43:01 -08001828 mUI.showPreferencesToast();
Michael Kolb8872c232013-01-29 10:33:22 -08001829 }
1830
1831 private void showTapToFocusToast() {
1832 // TODO: Use a toast?
1833 new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
1834 // Clear the preference.
1835 Editor editor = mPreferences.edit();
1836 editor.putBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, false);
1837 editor.apply();
1838 }
1839
1840 private void initializeCapabilities() {
1841 mInitialParams = mCameraDevice.getParameters();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001842 mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
1843 mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
1844 mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
1845 mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
Angus Kongdcccc512013-08-08 17:06:03 -07001846 mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001847 CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
Michael Kolb8872c232013-01-29 10:33:22 -08001848 }
1849
Michael Kolb8872c232013-01-29 10:33:22 -08001850 @Override
1851 public void onCountDownFinished() {
1852 mSnapshotOnIdle = false;
1853 mFocusManager.doSnap();
Doris Liuda50e052013-02-07 14:36:32 -08001854 mFocusManager.onShutterUp();
Michael Kolb8872c232013-01-29 10:33:22 -08001855 }
1856
Michael Kolb8872c232013-01-29 10:33:22 -08001857 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001858 public void onShowSwitcherPopup() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001859 mUI.onShowSwitcherPopup();
Michael Kolb8872c232013-01-29 10:33:22 -08001860 }
1861
Angus Kongce5480e2013-01-29 17:43:48 -08001862 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001863 public int onZoomChanged(int index) {
1864 // Not useful to change zoom value when the activity is paused.
1865 if (mPaused) return index;
1866 mZoomValue = index;
1867 if (mParameters == null || mCameraDevice == null) return index;
1868 // Set zoom parameters asynchronously
1869 mParameters.setZoom(mZoomValue);
Angus Kong36ed8672013-04-15 12:11:15 -07001870 mCameraDevice.setParameters(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -08001871 Parameters p = mCameraDevice.getParameters();
1872 if (p != null) return p.getZoom();
1873 return index;
Angus Kongce5480e2013-01-29 17:43:48 -08001874 }
1875
1876 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001877 public int getCameraState() {
1878 return mCameraState;
1879 }
1880
1881 @Override
1882 public void onQueueStatus(boolean full) {
1883 mUI.enableShutter(!full);
Angus Kongce5480e2013-01-29 17:43:48 -08001884 }
Angus Kong86d36312013-01-31 18:22:44 -08001885
1886 @Override
1887 public void onMediaSaveServiceConnected(MediaSaveService s) {
1888 // We set the listener only when both service and shutterbutton
1889 // are initialized.
Michael Kolbd6954f32013-03-08 20:43:01 -08001890 if (mFirstTimeInitialized) {
1891 s.setListener(this);
1892 }
Angus Kong86d36312013-01-31 18:22:44 -08001893 }
Angus Kong0d00a892013-03-26 11:40:40 -07001894
1895 @Override
1896 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1897 }
1898
1899 @Override
1900 public void onSensorChanged(SensorEvent event) {
1901 int type = event.sensor.getType();
1902 float[] data;
1903 if (type == Sensor.TYPE_ACCELEROMETER) {
1904 data = mGData;
1905 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
1906 data = mMData;
1907 } else {
1908 // we should not be here.
1909 return;
1910 }
1911 for (int i = 0; i < 3 ; i++) {
1912 data[i] = event.values[i];
1913 }
1914 float[] orientation = new float[3];
1915 SensorManager.getRotationMatrix(mR, null, mGData, mMData);
1916 SensorManager.getOrientation(mR, orientation);
1917 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
1918 if (mHeading < 0) {
1919 mHeading += 360;
1920 }
Angus Kong0d00a892013-03-26 11:40:40 -07001921 }
Doris Liu6432cd62013-06-13 17:20:31 -07001922
1923 @Override
ztenghui7b265a62013-09-09 14:58:44 -07001924 public void onPreviewFocusChanged(boolean previewFocused) {
1925 mUI.onPreviewFocusChanged(previewFocused);
Doris Liu6432cd62013-06-13 17:20:31 -07001926 }
1927
1928/* Below is no longer needed, except to get rid of compile error
1929 * TODO: Remove these
1930 */
1931
1932 // TODO: Delete this function after old camera code is removed
1933 @Override
1934 public void onRestorePreferencesClicked() {}
1935
Michael Kolb8872c232013-01-29 10:33:22 -08001936}