blob: 1cebb4eb51e0ae506f2b20b88dc1649804c57c8e [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
Ruben Brunkd7488272013-10-10 18:45:53 -0700117 private static final String DEBUG_IMAGE_PREFIX = "DEBUG_";
118
Michael Kolb8872c232013-01-29 10:33:22 -0800119 // copied from Camera hierarchy
120 private CameraActivity mActivity;
Michael Kolb8872c232013-01-29 10:33:22 -0800121 private CameraProxy mCameraDevice;
122 private int mCameraId;
123 private Parameters mParameters;
124 private boolean mPaused;
Michael Kolbd6954f32013-03-08 20:43:01 -0800125
126 private PhotoUI mUI;
Michael Kolb8872c232013-01-29 10:33:22 -0800127
Michael Kolb8872c232013-01-29 10:33:22 -0800128 // The activity is going to switch to the specified camera id. This is
129 // needed because texture copy is done in GL thread. -1 means camera is not
130 // switching.
131 protected int mPendingSwitchCameraId = -1;
132 private boolean mOpenCameraFail;
133 private boolean mCameraDisabled;
134
135 // When setCameraParametersWhenIdle() is called, we accumulate the subsets
136 // needed to be updated in mUpdateSet.
137 private int mUpdateSet;
138
139 private static final int SCREEN_DELAY = 2 * 60 * 1000;
140
141 private int mZoomValue; // The current zoom value.
Michael Kolb8872c232013-01-29 10:33:22 -0800142
143 private Parameters mInitialParams;
144 private boolean mFocusAreaSupported;
145 private boolean mMeteringAreaSupported;
146 private boolean mAeLockSupported;
147 private boolean mAwbLockSupported;
Angus Kongdcccc512013-08-08 17:06:03 -0700148 private boolean mContinuousFocusSupported;
Michael Kolb8872c232013-01-29 10:33:22 -0800149
150 // The degrees of the device rotated clockwise from its natural orientation.
151 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
152 private ComboPreferences mPreferences;
153
154 private static final String sTempCropFilename = "crop-temp";
155
156 private ContentProviderClient mMediaProviderClient;
Michael Kolb8872c232013-01-29 10:33:22 -0800157 private boolean mFaceDetectionStarted = false;
158
Michael Kolb8872c232013-01-29 10:33:22 -0800159 // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
160 private String mCropValue;
161 private Uri mSaveUri;
162
Ruben Brunkd217ed02013-10-08 23:31:13 -0700163 private Uri mDebugUri;
164
Angus Kongce5480e2013-01-29 17:43:48 -0800165 // We use a queue to generated names of the images to be used later
166 // when the image is ready to be saved.
Michael Kolb8872c232013-01-29 10:33:22 -0800167 private NamedImages mNamedImages;
168
169 private Runnable mDoSnapRunnable = new Runnable() {
170 @Override
171 public void run() {
172 onShutterButtonClick();
173 }
174 };
175
Michael Kolb8872c232013-01-29 10:33:22 -0800176 /**
177 * An unpublished intent flag requesting to return as soon as capturing
178 * is completed.
179 *
180 * TODO: consider publishing by moving into MediaStore.
181 */
182 private static final String EXTRA_QUICK_CAPTURE =
183 "android.intent.extra.quickCapture";
184
185 // The display rotation in degrees. This is only valid when mCameraState is
186 // not PREVIEW_STOPPED.
187 private int mDisplayRotation;
188 // The value for android.hardware.Camera.setDisplayOrientation.
189 private int mCameraDisplayOrientation;
190 // The value for UI components like indicators.
191 private int mDisplayOrientation;
192 // The value for android.hardware.Camera.Parameters.setRotation.
193 private int mJpegRotation;
Doris Liu29da2db2013-08-28 14:28:45 -0700194 // Indicates whether we are using front camera
195 private boolean mMirror;
Michael Kolb8872c232013-01-29 10:33:22 -0800196 private boolean mFirstTimeInitialized;
197 private boolean mIsImageCaptureIntent;
198
Michael Kolb8872c232013-01-29 10:33:22 -0800199 private int mCameraState = PREVIEW_STOPPED;
200 private boolean mSnapshotOnIdle = false;
201
202 private ContentResolver mContentResolver;
203
204 private LocationManager mLocationManager;
205
Michael Kolb8872c232013-01-29 10:33:22 -0800206 private final PostViewPictureCallback mPostViewPictureCallback =
207 new PostViewPictureCallback();
208 private final RawPictureCallback mRawPictureCallback =
209 new RawPictureCallback();
210 private final AutoFocusCallback mAutoFocusCallback =
211 new AutoFocusCallback();
212 private final Object mAutoFocusMoveCallback =
213 ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700214 ? new AutoFocusMoveCallback()
215 : null;
Michael Kolb8872c232013-01-29 10:33:22 -0800216
217 private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
218
219 private long mFocusStartTime;
220 private long mShutterCallbackTime;
221 private long mPostViewPictureCallbackTime;
222 private long mRawPictureCallbackTime;
223 private long mJpegPictureCallbackTime;
224 private long mOnResumeTime;
225 private byte[] mJpegImageData;
226
227 // These latency time are for the CameraLatency test.
228 public long mAutoFocusTime;
229 public long mShutterLag;
230 public long mShutterToPictureDisplayedTime;
231 public long mPictureDisplayedToJpegCallbackTime;
232 public long mJpegCallbackFinishTime;
233 public long mCaptureStartTime;
234
235 // This handles everything about focus.
236 private FocusOverlayManager mFocusManager;
237
Michael Kolb8872c232013-01-29 10:33:22 -0800238 private String mSceneMode;
Michael Kolb8872c232013-01-29 10:33:22 -0800239
240 private final Handler mHandler = new MainHandler();
241 private PreferenceGroup mPreferenceGroup;
242
243 private boolean mQuickCapture;
Angus Kong0d00a892013-03-26 11:40:40 -0700244 private SensorManager mSensorManager;
245 private float[] mGData = new float[3];
246 private float[] mMData = new float[3];
247 private float[] mR = new float[16];
248 private int mHeading = -1;
249
Angus Kongdcccc512013-08-08 17:06:03 -0700250 // True if all the parameters needed to start preview is ready.
251 private boolean mCameraPreviewParamsReady = false;
Doris Liu6432cd62013-06-13 17:20:31 -0700252
Angus Kongce5480e2013-01-29 17:43:48 -0800253 private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener =
254 new MediaSaveService.OnMediaSavedListener() {
255 @Override
256 public void onMediaSaved(Uri uri) {
257 if (uri != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700258 mActivity.notifyNewMedia(uri);
Angus Kongce5480e2013-01-29 17:43:48 -0800259 }
260 }
261 };
Michael Kolb8872c232013-01-29 10:33:22 -0800262
Angus Kongdcccc512013-08-08 17:06:03 -0700263 private void checkDisplayRotation() {
264 // Set the display orientation if display rotation has changed.
265 // Sometimes this happens when the device is held upside
266 // down and camera app is opened. Rotation animation will
267 // take some time and the rotation value we have got may be
268 // wrong. Framework does not have a callback for this now.
269 if (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) {
270 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -0800271 }
Angus Kongdcccc512013-08-08 17:06:03 -0700272 if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
273 mHandler.postDelayed(new Runnable() {
274 @Override
275 public void run() {
276 checkDisplayRotation();
277 }
278 }, 100);
Michael Kolb8872c232013-01-29 10:33:22 -0800279 }
280 }
281
282 /**
283 * This Handler is used to post message back onto the main thread of the
284 * application
285 */
286 private class MainHandler extends Handler {
287 @Override
288 public void handleMessage(Message msg) {
289 switch (msg.what) {
290 case SETUP_PREVIEW: {
291 setupPreview();
292 break;
293 }
294
295 case CLEAR_SCREEN_DELAY: {
296 mActivity.getWindow().clearFlags(
297 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
298 break;
299 }
300
301 case FIRST_TIME_INIT: {
302 initializeFirstTime();
303 break;
304 }
305
306 case SET_CAMERA_PARAMETERS_WHEN_IDLE: {
307 setCameraParametersWhenIdle(0);
308 break;
309 }
310
Michael Kolb8872c232013-01-29 10:33:22 -0800311 case SHOW_TAP_TO_FOCUS_TOAST: {
312 showTapToFocusToast();
313 break;
314 }
315
316 case SWITCH_CAMERA: {
317 switchCamera();
318 break;
319 }
320
321 case SWITCH_CAMERA_START_ANIMATION: {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700322 // TODO: Need to revisit
323 // ((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera();
Michael Kolb8872c232013-01-29 10:33:22 -0800324 break;
325 }
326
327 case CAMERA_OPEN_DONE: {
Michael Kolbd6954f32013-03-08 20:43:01 -0800328 onCameraOpened();
Michael Kolb8872c232013-01-29 10:33:22 -0800329 break;
330 }
331
Michael Kolb8872c232013-01-29 10:33:22 -0800332 case OPEN_CAMERA_FAIL: {
Michael Kolb8872c232013-01-29 10:33:22 -0800333 mOpenCameraFail = true;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700334 CameraUtil.showErrorAndFinish(mActivity,
Michael Kolb8872c232013-01-29 10:33:22 -0800335 R.string.cannot_connect_camera);
336 break;
337 }
338
339 case CAMERA_DISABLED: {
Michael Kolb8872c232013-01-29 10:33:22 -0800340 mCameraDisabled = true;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700341 CameraUtil.showErrorAndFinish(mActivity,
Michael Kolb8872c232013-01-29 10:33:22 -0800342 R.string.camera_disabled);
343 break;
344 }
Michael Kolb8872c232013-01-29 10:33:22 -0800345 }
346 }
347 }
348
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700349
Michael Kolb8872c232013-01-29 10:33:22 -0800350 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700351 public void init(CameraActivity activity, View parent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800352 mActivity = activity;
Michael Kolbd6954f32013-03-08 20:43:01 -0800353 mUI = new PhotoUI(activity, this, parent);
Michael Kolb8872c232013-01-29 10:33:22 -0800354 mPreferences = new ComboPreferences(mActivity);
355 CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal());
356 mCameraId = getPreferredCameraId(mPreferences);
357
358 mContentResolver = mActivity.getContentResolver();
359
Michael Kolb8872c232013-01-29 10:33:22 -0800360 // Surface texture is from camera screen nail and startPreview needs it.
361 // This must be done before startPreview.
362 mIsImageCaptureIntent = isImageCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800363
364 mPreferences.setLocalId(mActivity, mCameraId);
365 CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
366 // we need to reset exposure for the preview
367 resetExposureCompensation();
Michael Kolb8872c232013-01-29 10:33:22 -0800368
369 initializeControlByIntent();
370 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
Michael Kolbd6954f32013-03-08 20:43:01 -0800371 mLocationManager = new LocationManager(mActivity, mUI);
Angus Kong0d00a892013-03-26 11:40:40 -0700372 mSensorManager = (SensorManager)(mActivity.getSystemService(Context.SENSOR_SERVICE));
Michael Kolbd6954f32013-03-08 20:43:01 -0800373 }
374
375 private void initializeControlByIntent() {
376 mUI.initializeControlByIntent();
377 if (mIsImageCaptureIntent) {
378 setupCaptureParams();
379 }
380 }
381
382 private void onPreviewStarted() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800383 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800384 startFaceDetection();
385 locationFirstRun();
Michael Kolb8872c232013-01-29 10:33:22 -0800386 }
387
388 // Prompt the user to pick to record location for the very first run of
389 // camera only
390 private void locationFirstRun() {
391 if (RecordLocationPreference.isSet(mPreferences)) {
392 return;
393 }
394 if (mActivity.isSecureCamera()) return;
395 // Check if the back camera exists
396 int backCameraId = CameraHolder.instance().getBackCameraId();
397 if (backCameraId == -1) {
398 // If there is no back camera, do not show the prompt.
399 return;
400 }
Doris Liu6a83d522013-07-02 12:03:32 -0700401 mUI.showLocationDialog();
402 }
Michael Kolb8872c232013-01-29 10:33:22 -0800403
ztenghui7b265a62013-09-09 14:58:44 -0700404 @Override
Doris Liu6a83d522013-07-02 12:03:32 -0700405 public void enableRecordingLocation(boolean enable) {
406 setLocationPreference(enable ? RecordLocationPreference.VALUE_ON
407 : RecordLocationPreference.VALUE_OFF);
Michael Kolb8872c232013-01-29 10:33:22 -0800408 }
409
Angus Kongdcccc512013-08-08 17:06:03 -0700410 @Override
411 public void onPreviewUIReady() {
412 startPreview();
413 }
414
415 @Override
416 public void onPreviewUIDestroyed() {
417 if (mCameraDevice == null) {
418 return;
419 }
420 mCameraDevice.setPreviewTexture(null);
421 stopPreview();
422 }
423
Michael Kolb8872c232013-01-29 10:33:22 -0800424 private void setLocationPreference(String value) {
425 mPreferences.edit()
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700426 .putString(CameraSettings.KEY_RECORD_LOCATION, value)
427 .apply();
Michael Kolb8872c232013-01-29 10:33:22 -0800428 // TODO: Fix this to use the actual onSharedPreferencesChanged listener
429 // instead of invoking manually
430 onSharedPreferenceChanged();
431 }
432
Michael Kolbd6954f32013-03-08 20:43:01 -0800433 private void onCameraOpened() {
434 View root = mUI.getRootView();
Michael Kolb8872c232013-01-29 10:33:22 -0800435 // These depend on camera parameters.
Michael Kolbd6954f32013-03-08 20:43:01 -0800436
437 int width = root.getWidth();
438 int height = root.getHeight();
Doris Liu6a0de792013-02-26 10:54:25 -0800439 mFocusManager.setPreviewSize(width, height);
Michael Kolbd6954f32013-03-08 20:43:01 -0800440 openCameraCommon();
Michael Kolb8872c232013-01-29 10:33:22 -0800441 }
442
Michael Kolbd6954f32013-03-08 20:43:01 -0800443 private void switchCamera() {
444 if (mPaused) return;
445
446 Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
447 mCameraId = mPendingSwitchCameraId;
448 mPendingSwitchCameraId = -1;
449 setCameraId(mCameraId);
450
451 // from onPause
452 closeCamera();
453 mUI.collapseCameraControls();
454 mUI.clearFaces();
455 if (mFocusManager != null) mFocusManager.removeMessages();
456
457 // Restart the camera and initialize the UI. From onCreate.
458 mPreferences.setLocalId(mActivity, mCameraId);
459 CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
Angus Kong4f795b82013-09-16 14:25:35 -0700460 mCameraDevice = CameraUtil.openCamera(
461 mActivity, mCameraId, mHandler,
462 mActivity.getCameraOpenErrorCallback());
463 if (mCameraDevice == null) {
464 Log.e(TAG, "Failed to open camera:" + mCameraId + ", aborting.");
Michael Kolbd6954f32013-03-08 20:43:01 -0800465 return;
Doris Liu09106a42013-03-05 09:54:25 -0800466 }
Angus Kong4f795b82013-09-16 14:25:35 -0700467 mParameters = mCameraDevice.getParameters();
Michael Kolbd6954f32013-03-08 20:43:01 -0800468 initializeCapabilities();
469 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -0700470 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
471 mFocusManager.setMirror(mMirror);
Michael Kolbd6954f32013-03-08 20:43:01 -0800472 mFocusManager.setParameters(mInitialParams);
473 setupPreview();
474
Doris Liu6432cd62013-06-13 17:20:31 -0700475 // reset zoom value index
476 mZoomValue = 0;
Michael Kolbd6954f32013-03-08 20:43:01 -0800477 openCameraCommon();
478
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700479 // Start switch camera animation. Post a message because
480 // onFrameAvailable from the old camera may already exist.
481 mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION);
Doris Liu48239f42013-03-04 22:19:10 -0800482 }
483
Michael Kolbd6954f32013-03-08 20:43:01 -0800484 protected void setCameraId(int cameraId) {
485 ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID);
486 pref.setValue("" + cameraId);
487 }
488
489 // either open a new camera or switch cameras
490 private void openCameraCommon() {
Michael Kolb8872c232013-01-29 10:33:22 -0800491 loadCameraPreferences();
Michael Kolbd6954f32013-03-08 20:43:01 -0800492
493 mUI.onCameraOpened(mPreferenceGroup, mPreferences, mParameters, this);
Angus Kong0fb819b2013-10-08 13:44:19 -0700494 if (mIsImageCaptureIntent) {
495 mUI.overrideSettings(CameraSettings.KEY_CAMERA_HDR_PLUS,
496 mActivity.getString(R.string.setting_off_value));
497 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800498 updateSceneMode();
499 showTapToFocusToastIfNeeded();
500
501
Michael Kolb8872c232013-01-29 10:33:22 -0800502 }
503
ztenghui7b265a62013-09-09 14:58:44 -0700504 @Override
Doris Liub3749f22013-09-25 12:22:08 -0700505 public void onScreenSizeChanged(int width, int height) {
Michael Kolbd6954f32013-03-08 20:43:01 -0800506 if (mFocusManager != null) mFocusManager.setPreviewSize(width, height);
Michael Kolbd6954f32013-03-08 20:43:01 -0800507 }
Michael Kolb8872c232013-01-29 10:33:22 -0800508
509 private void resetExposureCompensation() {
510 String value = mPreferences.getString(CameraSettings.KEY_EXPOSURE,
511 CameraSettings.EXPOSURE_DEFAULT_VALUE);
512 if (!CameraSettings.EXPOSURE_DEFAULT_VALUE.equals(value)) {
513 Editor editor = mPreferences.edit();
514 editor.putString(CameraSettings.KEY_EXPOSURE, "0");
515 editor.apply();
516 }
517 }
518
519 private void keepMediaProviderInstance() {
520 // We want to keep a reference to MediaProvider in camera's lifecycle.
521 // TODO: Utilize mMediaProviderClient instance to replace
522 // ContentResolver calls.
523 if (mMediaProviderClient == null) {
524 mMediaProviderClient = mContentResolver
525 .acquireContentProviderClient(MediaStore.AUTHORITY);
526 }
527 }
528
529 // Snapshots can only be taken after this is called. It should be called
530 // once only. We could have done these things in onCreate() but we want to
531 // make preview screen appear as soon as possible.
532 private void initializeFirstTime() {
533 if (mFirstTimeInitialized) return;
534
535 // Initialize location service.
536 boolean recordLocation = RecordLocationPreference.get(
537 mPreferences, mContentResolver);
538 mLocationManager.recordLocation(recordLocation);
539
540 keepMediaProviderInstance();
541
Michael Kolbd6954f32013-03-08 20:43:01 -0800542 mUI.initializeFirstTime();
Angus Kong86d36312013-01-31 18:22:44 -0800543 MediaSaveService s = mActivity.getMediaSaveService();
544 // We set the listener only when both service and shutterbutton
545 // are initialized.
546 if (s != null) {
547 s.setListener(this);
548 }
Michael Kolb8872c232013-01-29 10:33:22 -0800549
Michael Kolb8872c232013-01-29 10:33:22 -0800550 mNamedImages = new NamedImages();
551
552 mFirstTimeInitialized = true;
553 addIdleHandler();
554
555 mActivity.updateStorageSpaceAndHint();
556 }
557
Michael Kolbd6954f32013-03-08 20:43:01 -0800558 // If the activity is paused and resumed, this method will be called in
559 // onResume.
560 private void initializeSecondTime() {
561 // Start location update if needed.
562 boolean recordLocation = RecordLocationPreference.get(
563 mPreferences, mContentResolver);
564 mLocationManager.recordLocation(recordLocation);
565 MediaSaveService s = mActivity.getMediaSaveService();
566 if (s != null) {
567 s.setListener(this);
568 }
569 mNamedImages = new NamedImages();
570 mUI.initializeSecondTime(mParameters);
571 keepMediaProviderInstance();
572 }
573
Michael Kolb8872c232013-01-29 10:33:22 -0800574 private void showTapToFocusToastIfNeeded() {
575 // Show the tap to focus toast if this is the first start.
576 if (mFocusAreaSupported &&
577 mPreferences.getBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, true)) {
578 // Delay the toast for one second to wait for orientation.
579 mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_FOCUS_TOAST, 1000);
580 }
581 }
582
583 private void addIdleHandler() {
584 MessageQueue queue = Looper.myQueue();
585 queue.addIdleHandler(new MessageQueue.IdleHandler() {
586 @Override
587 public boolean queueIdle() {
588 Storage.ensureOSXCompatible();
589 return false;
590 }
591 });
592 }
593
Michael Kolb8872c232013-01-29 10:33:22 -0800594 @Override
595 public void startFaceDetection() {
Michael Kolb8872c232013-01-29 10:33:22 -0800596 if (mFaceDetectionStarted) return;
597 if (mParameters.getMaxNumDetectedFaces() > 0) {
598 mFaceDetectionStarted = true;
Michael Kolb8872c232013-01-29 10:33:22 -0800599 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Michael Kolbd6954f32013-03-08 20:43:01 -0800600 mUI.onStartFaceDetection(mDisplayOrientation,
601 (info.facing == CameraInfo.CAMERA_FACING_FRONT));
Angus Kong9e765522013-07-31 14:05:20 -0700602 mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Michael Kolb8872c232013-01-29 10:33:22 -0800603 mCameraDevice.startFaceDetection();
604 }
605 }
606
Michael Kolb8872c232013-01-29 10:33:22 -0800607 @Override
608 public void stopFaceDetection() {
Michael Kolb8872c232013-01-29 10:33:22 -0800609 if (!mFaceDetectionStarted) return;
610 if (mParameters.getMaxNumDetectedFaces() > 0) {
611 mFaceDetectionStarted = false;
Angus Kong9e765522013-07-31 14:05:20 -0700612 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -0800613 mCameraDevice.stopFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800614 mUI.clearFaces();
Michael Kolb8872c232013-01-29 10:33:22 -0800615 }
616 }
617
Michael Kolb8872c232013-01-29 10:33:22 -0800618 private final class ShutterCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700619 implements CameraShutterCallback {
Angus Kongdcb0ef12013-03-25 23:11:43 -0700620
Sascha Haeberling37f36112013-08-06 14:31:52 -0700621 private boolean mNeedsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700622
Sascha Haeberling37f36112013-08-06 14:31:52 -0700623 public ShutterCallback(boolean needsAnimation) {
624 mNeedsAnimation = needsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700625 }
626
Michael Kolb8872c232013-01-29 10:33:22 -0800627 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700628 public void onShutter(CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800629 mShutterCallbackTime = System.currentTimeMillis();
630 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
631 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Sascha Haeberling37f36112013-08-06 14:31:52 -0700632 if (mNeedsAnimation) {
633 mActivity.runOnUiThread(new Runnable() {
634 @Override
635 public void run() {
636 animateAfterShutter();
637 }
638 });
Angus Kongdcb0ef12013-03-25 23:11:43 -0700639 }
Michael Kolb8872c232013-01-29 10:33:22 -0800640 }
641 }
642
Angus Kong9ef99252013-07-18 18:04:19 -0700643 private final class PostViewPictureCallback
644 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800645 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700646 public void onPictureTaken(byte [] data, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800647 mPostViewPictureCallbackTime = System.currentTimeMillis();
648 Log.v(TAG, "mShutterToPostViewCallbackTime = "
649 + (mPostViewPictureCallbackTime - mShutterCallbackTime)
650 + "ms");
651 }
652 }
653
Angus Kong9ef99252013-07-18 18:04:19 -0700654 private final class RawPictureCallback
655 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800656 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700657 public void onPictureTaken(byte [] rawData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800658 mRawPictureCallbackTime = System.currentTimeMillis();
659 Log.v(TAG, "mShutterToRawCallbackTime = "
660 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
661 }
662 }
663
Angus Kong9ef99252013-07-18 18:04:19 -0700664 private final class JpegPictureCallback
665 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800666 Location mLocation;
667
668 public JpegPictureCallback(Location loc) {
669 mLocation = loc;
670 }
671
672 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700673 public void onPictureTaken(final byte [] jpegData, CameraProxy camera) {
Sascha Haeberling88901942013-08-28 17:49:00 -0700674 mUI.enableShutter(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800675 if (mPaused) {
676 return;
677 }
Doris Liu6432cd62013-06-13 17:20:31 -0700678 if (mIsImageCaptureIntent) {
679 stopPreview();
680 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700681 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -0700682 mUI.showSwitcher();
683 mUI.setSwipingEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800684 }
685
686 mJpegPictureCallbackTime = System.currentTimeMillis();
687 // If postview callback has arrived, the captured image is displayed
688 // in postview callback. If not, the captured image is displayed in
689 // raw picture callback.
690 if (mPostViewPictureCallbackTime != 0) {
691 mShutterToPictureDisplayedTime =
692 mPostViewPictureCallbackTime - mShutterCallbackTime;
693 mPictureDisplayedToJpegCallbackTime =
694 mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
695 } else {
696 mShutterToPictureDisplayedTime =
697 mRawPictureCallbackTime - mShutterCallbackTime;
698 mPictureDisplayedToJpegCallbackTime =
699 mJpegPictureCallbackTime - mRawPictureCallbackTime;
700 }
701 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
702 + mPictureDisplayedToJpegCallbackTime + "ms");
703
Michael Kolb8872c232013-01-29 10:33:22 -0800704 mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
705 if (!mIsImageCaptureIntent) {
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700706 setupPreview();
Michael Kolb8872c232013-01-29 10:33:22 -0800707 }
708
Doris Liu36e56fb2013-09-11 17:38:08 -0700709 ExifInterface exif = Exif.getExif(jpegData);
710 int orientation = Exif.getOrientation(exif);
Ruben Brunkd217ed02013-10-08 23:31:13 -0700711
Ruben Brunkd7488272013-10-10 18:45:53 -0700712 if (!mIsImageCaptureIntent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800713 // Calculate the width and the height of the jpeg.
714 Size s = mParameters.getPictureSize();
Michael Kolb8872c232013-01-29 10:33:22 -0800715 int width, height;
716 if ((mJpegRotation + orientation) % 180 == 0) {
717 width = s.width;
718 height = s.height;
719 } else {
720 width = s.height;
721 height = s.width;
722 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700723 NamedEntity name = mNamedImages.getNextNameEntity();
724 String title = (name == null) ? null : name.title;
725 long date = (name == null) ? -1 : name.date;
Ruben Brunkd7488272013-10-10 18:45:53 -0700726
727 // Handle debug mode outputs
728 if (mDebugUri != null) {
729 // If using a debug uri, save jpeg there.
730 saveToDebugUri(jpegData);
731
732 // Adjust the title of the debug image shown in mediastore.
733 if (title != null) {
734 title = DEBUG_IMAGE_PREFIX + title;
735 }
736 }
737
Michael Kolb8872c232013-01-29 10:33:22 -0800738 if (title == null) {
739 Log.e(TAG, "Unbalanced name/data pair");
740 } else {
741 if (date == -1) date = mCaptureStartTime;
Angus Kong0d00a892013-03-26 11:40:40 -0700742 if (mHeading >= 0) {
743 // heading direction has been updated by the sensor.
744 ExifTag directionRefTag = exif.buildTag(
745 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
746 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
747 ExifTag directionTag = exif.buildTag(
748 ExifInterface.TAG_GPS_IMG_DIRECTION,
749 new Rational(mHeading, 1));
750 exif.setTag(directionRefTag);
751 exif.setTag(directionTag);
752 }
Angus Kong86d36312013-01-31 18:22:44 -0800753 mActivity.getMediaSaveService().addImage(
754 jpegData, title, date, mLocation, width, height,
Angus Kong0d00a892013-03-26 11:40:40 -0700755 orientation, exif, mOnMediaSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -0800756 }
Doris Liuce2acbc2013-08-21 18:45:29 -0700757 // Animate capture with real jpeg data instead of a preview frame.
Doris Liu29da2db2013-08-28 14:28:45 -0700758 mUI.animateCapture(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800759 } else {
760 mJpegImageData = jpegData;
761 if (!mQuickCapture) {
Doris Liu36e56fb2013-09-11 17:38:08 -0700762 mUI.showCapturedImageForReview(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800763 } else {
Michael Kolbd6954f32013-03-08 20:43:01 -0800764 onCaptureDone();
Michael Kolb8872c232013-01-29 10:33:22 -0800765 }
766 }
767
768 // Check this in advance of each shot so we don't add to shutter
769 // latency. It's true that someone else could write to the SD card in
770 // the mean time and fill it, but that could have happened between the
771 // shutter press and saving the JPEG too.
772 mActivity.updateStorageSpaceAndHint();
773
774 long now = System.currentTimeMillis();
775 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
776 Log.v(TAG, "mJpegCallbackFinishTime = "
777 + mJpegCallbackFinishTime + "ms");
778 mJpegPictureCallbackTime = 0;
779 }
780 }
781
Angus Kong9ef99252013-07-18 18:04:19 -0700782 private final class AutoFocusCallback implements CameraAFCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800783 @Override
784 public void onAutoFocus(
Angus Kong9ef99252013-07-18 18:04:19 -0700785 boolean focused, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800786 if (mPaused) return;
787
788 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
789 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
790 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800791 mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
Michael Kolb8872c232013-01-29 10:33:22 -0800792 }
793 }
794
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700795 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -0800796 private final class AutoFocusMoveCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700797 implements CameraAFMoveCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800798 @Override
799 public void onAutoFocusMoving(
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700800 boolean moving, CameraProxy camera) {
801 mFocusManager.onAutoFocusMoving(moving);
Michael Kolb8872c232013-01-29 10:33:22 -0800802 }
803 }
804
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700805 /**
806 * This class is just a thread-safe queue for name,date holder objects.
807 */
808 public static class NamedImages {
809 private Vector<NamedEntity> mQueue;
Michael Kolb8872c232013-01-29 10:33:22 -0800810
811 public NamedImages() {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700812 mQueue = new Vector<NamedEntity>();
Michael Kolb8872c232013-01-29 10:33:22 -0800813 }
814
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700815 public void nameNewImage(long date) {
Michael Kolb8872c232013-01-29 10:33:22 -0800816 NamedEntity r = new NamedEntity();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700817 r.title = CameraUtil.createJpegName(date);
Michael Kolb8872c232013-01-29 10:33:22 -0800818 r.date = date;
819 mQueue.add(r);
820 }
821
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700822 public NamedEntity getNextNameEntity() {
823 synchronized(mQueue) {
824 if (!mQueue.isEmpty()) {
825 return mQueue.remove(0);
826 }
Michael Kolb8872c232013-01-29 10:33:22 -0800827 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700828 return null;
Michael Kolb8872c232013-01-29 10:33:22 -0800829 }
830
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700831 public static class NamedEntity {
832 public String title;
833 public long date;
Michael Kolb8872c232013-01-29 10:33:22 -0800834 }
835 }
836
837 private void setCameraState(int state) {
838 mCameraState = state;
839 switch (state) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700840 case PhotoController.PREVIEW_STOPPED:
841 case PhotoController.SNAPSHOT_IN_PROGRESS:
842 case PhotoController.SWITCHING_CAMERA:
843 mUI.enableGestures(false);
844 break;
845 case PhotoController.IDLE:
846 mUI.enableGestures(true);
847 break;
Michael Kolb8872c232013-01-29 10:33:22 -0800848 }
849 }
850
Sascha Haeberling37f36112013-08-06 14:31:52 -0700851 private void animateAfterShutter() {
Michael Kolb8872c232013-01-29 10:33:22 -0800852 // Only animate when in full screen capture mode
853 // i.e. If monkey/a user swipes to the gallery during picture taking,
854 // don't show animation
Doris Liuc2e9abd2013-06-19 14:20:51 -0700855 if (!mIsImageCaptureIntent) {
856 mUI.animateFlash();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700857 }
Michael Kolb8872c232013-01-29 10:33:22 -0800858 }
859
860 @Override
861 public boolean capture() {
862 // If we are already in the middle of taking a snapshot or the image save request
863 // is full then ignore.
864 if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
Angus Kong86d36312013-01-31 18:22:44 -0800865 || mCameraState == SWITCHING_CAMERA
866 || mActivity.getMediaSaveService().isQueueFull()) {
Michael Kolb8872c232013-01-29 10:33:22 -0800867 return false;
868 }
869 mCaptureStartTime = System.currentTimeMillis();
870 mPostViewPictureCallbackTime = 0;
871 mJpegImageData = null;
872
Angus Kongb50b5cb2013-08-09 14:55:20 -0700873 final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
Michael Kolb8872c232013-01-29 10:33:22 -0800874
875 if (animateBefore) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700876 animateAfterShutter();
Michael Kolb8872c232013-01-29 10:33:22 -0800877 }
878
879 // Set rotation and gps data.
Doris Liu3cf565c2013-02-15 10:55:37 -0800880 int orientation;
881 // We need to be consistent with the framework orientation (i.e. the
882 // orientation of the UI.) when the auto-rotate screen setting is on.
883 if (mActivity.isAutoRotateScreen()) {
884 orientation = (360 - mDisplayRotation) % 360;
885 } else {
886 orientation = mOrientation;
887 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700888 mJpegRotation = CameraUtil.getJpegRotation(mCameraId, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800889 mParameters.setRotation(mJpegRotation);
890 Location loc = mLocationManager.getCurrentLocation();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700891 CameraUtil.setGpsParameters(mParameters, loc);
Michael Kolb8872c232013-01-29 10:33:22 -0800892 mCameraDevice.setParameters(mParameters);
893
Sascha Haeberling88901942013-08-28 17:49:00 -0700894 // We don't want user to press the button again while taking a
895 // multi-second HDR photo.
896 mUI.enableShutter(false);
Angus Kong9ef99252013-07-18 18:04:19 -0700897 mCameraDevice.takePicture(mHandler,
898 new ShutterCallback(!animateBefore),
Angus Kongdcb0ef12013-03-25 23:11:43 -0700899 mRawPictureCallback, mPostViewPictureCallback,
Angus Kong9ef99252013-07-18 18:04:19 -0700900 new JpegPictureCallback(loc));
Michael Kolb8872c232013-01-29 10:33:22 -0800901
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700902 mNamedImages.nameNewImage(mCaptureStartTime);
Michael Kolb8872c232013-01-29 10:33:22 -0800903
904 mFaceDetectionStarted = false;
905 setCameraState(SNAPSHOT_IN_PROGRESS);
Bobby Georgescu301b6462013-04-01 15:33:17 -0700906 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
907 UsageStatistics.ACTION_CAPTURE_DONE, "Photo");
Michael Kolb8872c232013-01-29 10:33:22 -0800908 return true;
909 }
910
911 @Override
912 public void setFocusParameters() {
913 setCameraParameters(UPDATE_PARAM_PREFERENCE);
914 }
915
916 private int getPreferredCameraId(ComboPreferences preferences) {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700917 int intentCameraId = CameraUtil.getCameraFacingIntentExtras(mActivity);
Michael Kolb8872c232013-01-29 10:33:22 -0800918 if (intentCameraId != -1) {
919 // Testing purpose. Launch a specific camera through the intent
920 // extras.
921 return intentCameraId;
922 } else {
923 return CameraSettings.readPreferredCameraId(preferences);
924 }
925 }
926
Michael Kolbd6954f32013-03-08 20:43:01 -0800927 private void updateSceneMode() {
Michael Kolb8872c232013-01-29 10:33:22 -0800928 // If scene mode is set, we cannot set flash mode, white balance, and
929 // focus mode, instead, we read it from driver
930 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
931 overrideCameraSettings(mParameters.getFlashMode(),
932 mParameters.getWhiteBalance(), mParameters.getFocusMode());
933 } else {
934 overrideCameraSettings(null, null, null);
935 }
936 }
937
938 private void overrideCameraSettings(final String flashMode,
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700939 final String whiteBalance, final String focusMode) {
Michael Kolbd6954f32013-03-08 20:43:01 -0800940 mUI.overrideSettings(
941 CameraSettings.KEY_FLASH_MODE, flashMode,
942 CameraSettings.KEY_WHITE_BALANCE, whiteBalance,
943 CameraSettings.KEY_FOCUS_MODE, focusMode);
Michael Kolb8872c232013-01-29 10:33:22 -0800944 }
945
946 private void loadCameraPreferences() {
947 CameraSettings settings = new CameraSettings(mActivity, mInitialParams,
948 mCameraId, CameraHolder.instance().getCameraInfo());
949 mPreferenceGroup = settings.getPreferenceGroup(R.xml.camera_preferences);
950 }
951
952 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800953 public void onOrientationChanged(int orientation) {
954 // We keep the last known orientation. So if the user first orient
955 // the camera then point the camera to floor or sky, we still have
956 // the correct orientation.
957 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700958 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800959
960 // Show the toast after getting the first orientation changed.
961 if (mHandler.hasMessages(SHOW_TAP_TO_FOCUS_TOAST)) {
962 mHandler.removeMessages(SHOW_TAP_TO_FOCUS_TOAST);
963 showTapToFocusToast();
964 }
965 }
966
967 @Override
968 public void onStop() {
969 if (mMediaProviderClient != null) {
970 mMediaProviderClient.release();
971 mMediaProviderClient = null;
972 }
973 }
974
Michael Kolbd6954f32013-03-08 20:43:01 -0800975 @Override
976 public void onCaptureCancelled() {
977 mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
978 mActivity.finish();
Michael Kolb8872c232013-01-29 10:33:22 -0800979 }
980
Michael Kolbd6954f32013-03-08 20:43:01 -0800981 @Override
982 public void onCaptureRetake() {
Michael Kolb8872c232013-01-29 10:33:22 -0800983 if (mPaused)
984 return;
Michael Kolbd6954f32013-03-08 20:43:01 -0800985 mUI.hidePostCaptureAlert();
Michael Kolb8872c232013-01-29 10:33:22 -0800986 setupPreview();
987 }
988
Michael Kolbd6954f32013-03-08 20:43:01 -0800989 @Override
990 public void onCaptureDone() {
Michael Kolb8872c232013-01-29 10:33:22 -0800991 if (mPaused) {
992 return;
993 }
994
995 byte[] data = mJpegImageData;
996
997 if (mCropValue == null) {
998 // First handle the no crop case -- just return the value. If the
999 // caller specifies a "save uri" then write the data to its
1000 // stream. Otherwise, pass back a scaled down version of the bitmap
1001 // directly in the extras.
1002 if (mSaveUri != null) {
1003 OutputStream outputStream = null;
1004 try {
1005 outputStream = mContentResolver.openOutputStream(mSaveUri);
1006 outputStream.write(data);
1007 outputStream.close();
1008
1009 mActivity.setResultEx(Activity.RESULT_OK);
1010 mActivity.finish();
1011 } catch (IOException ex) {
1012 // ignore exception
1013 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001014 CameraUtil.closeSilently(outputStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001015 }
1016 } else {
Angus Kong0d00a892013-03-26 11:40:40 -07001017 ExifInterface exif = Exif.getExif(data);
1018 int orientation = Exif.getOrientation(exif);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001019 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
1020 bitmap = CameraUtil.rotate(bitmap, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001021 mActivity.setResultEx(Activity.RESULT_OK,
1022 new Intent("inline-data").putExtra("data", bitmap));
1023 mActivity.finish();
1024 }
1025 } else {
1026 // Save the image to a temp file and invoke the cropper
1027 Uri tempUri = null;
1028 FileOutputStream tempStream = null;
1029 try {
1030 File path = mActivity.getFileStreamPath(sTempCropFilename);
1031 path.delete();
1032 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1033 tempStream.write(data);
1034 tempStream.close();
1035 tempUri = Uri.fromFile(path);
1036 } catch (FileNotFoundException ex) {
1037 mActivity.setResultEx(Activity.RESULT_CANCELED);
1038 mActivity.finish();
1039 return;
1040 } catch (IOException ex) {
1041 mActivity.setResultEx(Activity.RESULT_CANCELED);
1042 mActivity.finish();
1043 return;
1044 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001045 CameraUtil.closeSilently(tempStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001046 }
1047
1048 Bundle newExtras = new Bundle();
1049 if (mCropValue.equals("circle")) {
1050 newExtras.putString("circleCrop", "true");
1051 }
1052 if (mSaveUri != null) {
1053 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1054 } else {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001055 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001056 }
1057 if (mActivity.isSecureCamera()) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001058 newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001059 }
1060
Sascha Haeberling37f36112013-08-06 14:31:52 -07001061 // TODO: Share this constant.
Sascha Haeberling8e963a52013-08-06 11:43:02 -07001062 final String CROP_ACTION = "com.android.camera.action.CROP";
1063 Intent cropIntent = new Intent(CROP_ACTION);
Michael Kolb8872c232013-01-29 10:33:22 -08001064
1065 cropIntent.setData(tempUri);
1066 cropIntent.putExtras(newExtras);
1067
1068 mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1069 }
1070 }
1071
Michael Kolb8872c232013-01-29 10:33:22 -08001072 @Override
1073 public void onShutterButtonFocus(boolean pressed) {
Michael Kolbd6954f32013-03-08 20:43:01 -08001074 if (mPaused || mUI.collapseCameraControls()
Michael Kolb8872c232013-01-29 10:33:22 -08001075 || (mCameraState == SNAPSHOT_IN_PROGRESS)
1076 || (mCameraState == PREVIEW_STOPPED)) return;
1077
1078 // Do not do focus if there is not enough storage.
1079 if (pressed && !canTakePicture()) return;
1080
1081 if (pressed) {
Michael Kolb8872c232013-01-29 10:33:22 -08001082 mFocusManager.onShutterDown();
1083 } else {
Doris Liuda50e052013-02-07 14:36:32 -08001084 // for countdown mode, we need to postpone the shutter release
1085 // i.e. lock the focus during countdown.
Michael Kolbd6954f32013-03-08 20:43:01 -08001086 if (!mUI.isCountingDown()) {
Doris Liuda50e052013-02-07 14:36:32 -08001087 mFocusManager.onShutterUp();
1088 }
Michael Kolb8872c232013-01-29 10:33:22 -08001089 }
1090 }
1091
1092 @Override
1093 public void onShutterButtonClick() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001094 if (mPaused || mUI.collapseCameraControls()
Michael Kolb8872c232013-01-29 10:33:22 -08001095 || (mCameraState == SWITCHING_CAMERA)
1096 || (mCameraState == PREVIEW_STOPPED)) return;
1097
1098 // Do not take the picture if there is not enough storage.
Angus Kong2dcc0a92013-09-25 13:00:08 -07001099 if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Michael Kolb8872c232013-01-29 10:33:22 -08001100 Log.i(TAG, "Not enough space or storage not ready. remaining="
Angus Kong2dcc0a92013-09-25 13:00:08 -07001101 + mActivity.getStorageSpaceBytes());
Michael Kolb8872c232013-01-29 10:33:22 -08001102 return;
1103 }
1104 Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1105
Angus Kongb50b5cb2013-08-09 14:55:20 -07001106 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -07001107 mUI.hideSwitcher();
1108 mUI.setSwipingEnabled(false);
Doris Liu9cdfe002013-04-16 09:50:56 -07001109 }
Michael Kolb8872c232013-01-29 10:33:22 -08001110 // If the user wants to do a snapshot while the previous one is still
1111 // in progress, remember the fact and do it after we finish the previous
1112 // one and re-start the preview. Snapshot in progress also includes the
1113 // state that autofocus is focusing and a picture will be taken when
1114 // focus callback arrives.
1115 if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1116 && !mIsImageCaptureIntent) {
1117 mSnapshotOnIdle = true;
1118 return;
1119 }
1120
1121 String timer = mPreferences.getString(
1122 CameraSettings.KEY_TIMER,
1123 mActivity.getString(R.string.pref_camera_timer_default));
1124 boolean playSound = mPreferences.getString(CameraSettings.KEY_TIMER_SOUND_EFFECTS,
1125 mActivity.getString(R.string.pref_camera_timer_sound_default))
1126 .equals(mActivity.getString(R.string.setting_on_value));
1127
1128 int seconds = Integer.parseInt(timer);
1129 // When shutter button is pressed, check whether the previous countdown is
1130 // finished. If not, cancel the previous countdown and start a new one.
Michael Kolbd6954f32013-03-08 20:43:01 -08001131 if (mUI.isCountingDown()) {
1132 mUI.cancelCountDown();
1133 }
1134 if (seconds > 0) {
1135 mUI.startCountDown(seconds, playSound);
Michael Kolb8872c232013-01-29 10:33:22 -08001136 } else {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001137 mSnapshotOnIdle = false;
1138 mFocusManager.doSnap();
Michael Kolb8872c232013-01-29 10:33:22 -08001139 }
1140 }
1141
1142 @Override
1143 public void installIntentFilter() {
Sascha Haeberling4de78802013-10-06 18:07:07 -07001144 // Do nothing.
Michael Kolb8872c232013-01-29 10:33:22 -08001145 }
1146
1147 @Override
1148 public boolean updateStorageHintOnResume() {
1149 return mFirstTimeInitialized;
1150 }
1151
1152 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001153 public void onResumeBeforeSuper() {
1154 mPaused = false;
1155 }
1156
Angus Kong4f795b82013-09-16 14:25:35 -07001157 /**
1158 * Opens the camera device.
1159 *
1160 * @return Whether the camera was opened successfully.
1161 */
1162 private boolean prepareCamera() {
1163 // We need to check whether the activity is paused before long
1164 // operations to ensure that onPause() can be done ASAP.
1165 mCameraDevice = CameraUtil.openCamera(
1166 mActivity, mCameraId, mHandler,
1167 mActivity.getCameraOpenErrorCallback());
1168 if (mCameraDevice == null) {
1169 Log.e(TAG, "Failed to open camera:" + mCameraId);
1170 return false;
Angus Kongdcccc512013-08-08 17:06:03 -07001171 }
Angus Kong4f795b82013-09-16 14:25:35 -07001172 mParameters = mCameraDevice.getParameters();
1173
1174 initializeCapabilities();
1175 if (mFocusManager == null) initializeFocusManager();
1176 setCameraParameters(UPDATE_PARAM_ALL);
1177 mHandler.sendEmptyMessage(CAMERA_OPEN_DONE);
1178 mCameraPreviewParamsReady = true;
1179 startPreview();
1180 mOnResumeTime = SystemClock.uptimeMillis();
1181 checkDisplayRotation();
1182 return true;
Angus Kongdcccc512013-08-08 17:06:03 -07001183 }
1184
1185
Michael Kolb8872c232013-01-29 10:33:22 -08001186 @Override
1187 public void onResumeAfterSuper() {
1188 if (mOpenCameraFail || mCameraDisabled) return;
1189
1190 mJpegPictureCallbackTime = 0;
1191 mZoomValue = 0;
Angus Kongdcccc512013-08-08 17:06:03 -07001192 resetExposureCompensation();
Angus Kong4f795b82013-09-16 14:25:35 -07001193 if (!prepareCamera()) {
1194 // Camera failure.
1195 return;
1196 }
Michael Kolb8872c232013-01-29 10:33:22 -08001197
1198 // If first time initialization is not finished, put it in the
1199 // message queue.
1200 if (!mFirstTimeInitialized) {
1201 mHandler.sendEmptyMessage(FIRST_TIME_INIT);
1202 } else {
1203 initializeSecondTime();
1204 }
1205 keepScreenOnAwhile();
1206
Bobby Georgescu0a7dd572013-03-12 22:45:17 -07001207 UsageStatistics.onContentViewChanged(
1208 UsageStatistics.COMPONENT_CAMERA, "PhotoModule");
Angus Kong0d00a892013-03-26 11:40:40 -07001209
1210 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1211 if (gsensor != null) {
1212 mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1213 }
1214
1215 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1216 if (msensor != null) {
1217 mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1218 }
Michael Kolb8872c232013-01-29 10:33:22 -08001219 }
1220
Michael Kolb8872c232013-01-29 10:33:22 -08001221 @Override
1222 public void onPauseBeforeSuper() {
1223 mPaused = true;
Angus Kong0d00a892013-03-26 11:40:40 -07001224 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1225 if (gsensor != null) {
1226 mSensorManager.unregisterListener(this, gsensor);
1227 }
1228
1229 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1230 if (msensor != null) {
1231 mSensorManager.unregisterListener(this, msensor);
1232 }
Michael Kolb8872c232013-01-29 10:33:22 -08001233 }
1234
1235 @Override
1236 public void onPauseAfterSuper() {
Michael Kolb8872c232013-01-29 10:33:22 -08001237 // When camera is started from secure lock screen for the first time
1238 // after screen on, the activity gets onCreate->onResume->onPause->onResume.
1239 // To reduce the latency, keep the camera for a short time so it does
1240 // not need to be opened again.
1241 if (mCameraDevice != null && mActivity.isSecureCamera()
Angus Kong6a8e8a12013-07-19 14:55:07 -07001242 && CameraActivity.isFirstStartAfterScreenOn()) {
1243 CameraActivity.resetFirstStartAfterScreenOn();
Michael Kolb8872c232013-01-29 10:33:22 -08001244 CameraHolder.instance().keep(KEEP_CAMERA_TIMEOUT);
1245 }
1246 // Reset the focus first. Camera CTS does not guarantee that
1247 // cancelAutoFocus is allowed after preview stops.
1248 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1249 mCameraDevice.cancelAutoFocus();
1250 }
1251 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001252
Angus Kongce5480e2013-01-29 17:43:48 -08001253 mNamedImages = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001254
1255 if (mLocationManager != null) mLocationManager.recordLocation(false);
1256
1257 // If we are in an image capture intent and has taken
1258 // a picture, we just clear it in onPause.
1259 mJpegImageData = null;
1260
Angus Kongdcccc512013-08-08 17:06:03 -07001261 // Remove the messages and runnables in the queue.
1262 mHandler.removeCallbacksAndMessages(null);
Michael Kolb8872c232013-01-29 10:33:22 -08001263
Michael Kolbd6954f32013-03-08 20:43:01 -08001264 closeCamera();
1265
1266 resetScreenOn();
1267 mUI.onPause();
1268
Michael Kolb8872c232013-01-29 10:33:22 -08001269 mPendingSwitchCameraId = -1;
1270 if (mFocusManager != null) mFocusManager.removeMessages();
Angus Kong86d36312013-01-31 18:22:44 -08001271 MediaSaveService s = mActivity.getMediaSaveService();
1272 if (s != null) {
1273 s.setListener(null);
1274 }
Michael Kolb8872c232013-01-29 10:33:22 -08001275 }
1276
Michael Kolb8872c232013-01-29 10:33:22 -08001277 /**
1278 * The focus manager is the first UI related element to get initialized,
1279 * and it requires the RenderOverlay, so initialize it here
1280 */
1281 private void initializeFocusManager() {
1282 // Create FocusManager object. startPreview needs it.
Michael Kolb8872c232013-01-29 10:33:22 -08001283 // if mFocusManager not null, reuse it
1284 // otherwise create a new instance
1285 if (mFocusManager != null) {
1286 mFocusManager.removeMessages();
1287 } else {
1288 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -07001289 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
Michael Kolb8872c232013-01-29 10:33:22 -08001290 String[] defaultFocusModes = mActivity.getResources().getStringArray(
1291 R.array.pref_camera_focusmode_default_array);
1292 mFocusManager = new FocusOverlayManager(mPreferences, defaultFocusModes,
Doris Liu29da2db2013-08-28 14:28:45 -07001293 mInitialParams, this, mMirror,
Michael Kolbd6954f32013-03-08 20:43:01 -08001294 mActivity.getMainLooper(), mUI);
Michael Kolb8872c232013-01-29 10:33:22 -08001295 }
1296 }
1297
Michael Kolb8872c232013-01-29 10:33:22 -08001298 @Override
1299 public void onConfigurationChanged(Configuration newConfig) {
1300 Log.v(TAG, "onConfigurationChanged");
1301 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001302 }
1303
1304 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001305 public void updateCameraOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001306 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001307 setDisplayOrientation();
1308 }
1309 }
1310
1311 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001312 public void onActivityResult(
1313 int requestCode, int resultCode, Intent data) {
1314 switch (requestCode) {
1315 case REQUEST_CROP: {
1316 Intent intent = new Intent();
1317 if (data != null) {
1318 Bundle extras = data.getExtras();
1319 if (extras != null) {
1320 intent.putExtras(extras);
1321 }
1322 }
1323 mActivity.setResultEx(resultCode, intent);
1324 mActivity.finish();
1325
1326 File path = mActivity.getFileStreamPath(sTempCropFilename);
1327 path.delete();
1328
1329 break;
1330 }
1331 }
1332 }
1333
1334 private boolean canTakePicture() {
Angus Kong2dcc0a92013-09-25 13:00:08 -07001335 return isCameraIdle() && (mActivity.getStorageSpaceBytes() > Storage.LOW_STORAGE_THRESHOLD_BYTES);
Michael Kolb8872c232013-01-29 10:33:22 -08001336 }
1337
1338 @Override
1339 public void autoFocus() {
1340 mFocusStartTime = System.currentTimeMillis();
Angus Kong9ef99252013-07-18 18:04:19 -07001341 mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001342 setCameraState(FOCUSING);
1343 }
1344
1345 @Override
1346 public void cancelAutoFocus() {
1347 mCameraDevice.cancelAutoFocus();
1348 setCameraState(IDLE);
1349 setCameraParameters(UPDATE_PARAM_PREFERENCE);
1350 }
1351
1352 // Preview area is touched. Handle touch focus.
1353 @Override
1354 public void onSingleTapUp(View view, int x, int y) {
1355 if (mPaused || mCameraDevice == null || !mFirstTimeInitialized
1356 || mCameraState == SNAPSHOT_IN_PROGRESS
1357 || mCameraState == SWITCHING_CAMERA
1358 || mCameraState == PREVIEW_STOPPED) {
1359 return;
1360 }
1361
Michael Kolb8872c232013-01-29 10:33:22 -08001362 // Check if metering area or focus area is supported.
1363 if (!mFocusAreaSupported && !mMeteringAreaSupported) return;
1364 mFocusManager.onSingleTapUp(x, y);
1365 }
1366
1367 @Override
1368 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001369 return mUI.onBackPressed();
Michael Kolb8872c232013-01-29 10:33:22 -08001370 }
1371
1372 @Override
1373 public boolean onKeyDown(int keyCode, KeyEvent event) {
1374 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001375 case KeyEvent.KEYCODE_VOLUME_UP:
1376 case KeyEvent.KEYCODE_VOLUME_DOWN:
1377 case KeyEvent.KEYCODE_FOCUS:
1378 if (/*TODO: mActivity.isInCameraApp() &&*/ mFirstTimeInitialized) {
1379 if (event.getRepeatCount() == 0) {
1380 onShutterButtonFocus(true);
1381 }
1382 return true;
1383 }
1384 return false;
1385 case KeyEvent.KEYCODE_CAMERA:
1386 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1387 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001388 }
1389 return true;
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001390 case KeyEvent.KEYCODE_DPAD_CENTER:
1391 // If we get a dpad center event without any focused view, move
1392 // the focus to the shutter button and press it.
1393 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1394 // Start auto-focus immediately to reduce shutter lag. After
1395 // the shutter button gets the focus, onShutterButtonFocus()
1396 // will be called again but it is fine.
1397 onShutterButtonFocus(true);
1398 mUI.pressShutterButton();
1399 }
1400 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001401 }
1402 return false;
1403 }
1404
1405 @Override
1406 public boolean onKeyUp(int keyCode, KeyEvent event) {
1407 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001408 case KeyEvent.KEYCODE_VOLUME_UP:
1409 case KeyEvent.KEYCODE_VOLUME_DOWN:
1410 if (/*mActivity.isInCameraApp() && */ mFirstTimeInitialized) {
1411 onShutterButtonClick();
1412 return true;
1413 }
1414 return false;
1415 case KeyEvent.KEYCODE_FOCUS:
1416 if (mFirstTimeInitialized) {
1417 onShutterButtonFocus(false);
1418 }
Michael Kolb8872c232013-01-29 10:33:22 -08001419 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001420 }
1421 return false;
1422 }
1423
Michael Kolb8872c232013-01-29 10:33:22 -08001424 private void closeCamera() {
1425 if (mCameraDevice != null) {
1426 mCameraDevice.setZoomChangeListener(null);
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001427 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001428 mCameraDevice.setErrorCallback(null);
1429 CameraHolder.instance().release();
1430 mFaceDetectionStarted = false;
1431 mCameraDevice = null;
1432 setCameraState(PREVIEW_STOPPED);
1433 mFocusManager.onCameraReleased();
1434 }
1435 }
1436
1437 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001438 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1439 mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001440 mCameraDisplayOrientation = mDisplayOrientation;
Michael Kolbd6954f32013-03-08 20:43:01 -08001441 mUI.setDisplayOrientation(mDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001442 if (mFocusManager != null) {
1443 mFocusManager.setDisplayOrientation(mDisplayOrientation);
1444 }
Doris Liu6432cd62013-06-13 17:20:31 -07001445 // Change the camera display orientation
1446 if (mCameraDevice != null) {
1447 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1448 }
Michael Kolb8872c232013-01-29 10:33:22 -08001449 }
1450
Sascha Haeberlingddef7792013-08-13 14:41:10 -07001451 /** Only called by UI thread. */
Michael Kolb8872c232013-01-29 10:33:22 -08001452 private void setupPreview() {
1453 mFocusManager.resetTouchFocus();
1454 startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001455 }
1456
Angus Kongdcccc512013-08-08 17:06:03 -07001457 // This can only be called by UI Thread.
Michael Kolb8872c232013-01-29 10:33:22 -08001458 private void startPreview() {
Angus Kongdcccc512013-08-08 17:06:03 -07001459 if (mPaused) {
1460 return;
1461 }
1462 SurfaceTexture st = mUI.getSurfaceTexture();
1463 if (st == null) {
1464 Log.w(TAG, "startPreview: surfaceTexture is not ready.");
1465 return;
1466 }
1467 if (!mCameraPreviewParamsReady) {
1468 Log.w(TAG, "startPreview: parameters for preview is not ready.");
1469 return;
1470 }
Michael Kolb8872c232013-01-29 10:33:22 -08001471 mCameraDevice.setErrorCallback(mErrorCallback);
1472
1473 // ICS camera frameworks has a bug. Face detection state is not cleared
1474 // after taking a picture. Stop the preview to work around it. The bug
1475 // was fixed in JB.
1476 if (mCameraState != PREVIEW_STOPPED) stopPreview();
1477
1478 setDisplayOrientation();
1479
1480 if (!mSnapshotOnIdle) {
1481 // If the focus mode is continuous autofocus, call cancelAutoFocus to
1482 // resume it because it may have been paused by autoFocus call.
Angus Kongb50b5cb2013-08-09 14:55:20 -07001483 if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) {
Michael Kolb8872c232013-01-29 10:33:22 -08001484 mCameraDevice.cancelAutoFocus();
1485 }
1486 mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1487 }
1488 setCameraParameters(UPDATE_PARAM_ALL);
Doris Liu6432cd62013-06-13 17:20:31 -07001489 // Let UI set its expected aspect ratio
Angus Kongdcccc512013-08-08 17:06:03 -07001490 mCameraDevice.setPreviewTexture(st);
Michael Kolb8872c232013-01-29 10:33:22 -08001491
1492 Log.v(TAG, "startPreview");
Angus Kong9ef99252013-07-18 18:04:19 -07001493 mCameraDevice.startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001494 mFocusManager.onPreviewStarted();
Angus Kongdcccc512013-08-08 17:06:03 -07001495 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001496
1497 if (mSnapshotOnIdle) {
1498 mHandler.post(mDoSnapRunnable);
1499 }
1500 }
1501
Michael Kolbd6954f32013-03-08 20:43:01 -08001502 @Override
1503 public void stopPreview() {
Michael Kolb8872c232013-01-29 10:33:22 -08001504 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1505 Log.v(TAG, "stopPreview");
1506 mCameraDevice.stopPreview();
1507 mFaceDetectionStarted = false;
1508 }
1509 setCameraState(PREVIEW_STOPPED);
1510 if (mFocusManager != null) mFocusManager.onPreviewStopped();
1511 }
1512
1513 @SuppressWarnings("deprecation")
1514 private void updateCameraParametersInitialize() {
1515 // Reset preview frame rate to the maximum because it may be lowered by
1516 // video camera application.
ztenghui16a35202013-09-23 11:35:36 -07001517 int[] fpsRange = CameraUtil.getPhotoPreviewFpsRange(mParameters);
1518 if (fpsRange != null && fpsRange.length > 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001519 mParameters.setPreviewFpsRange(
1520 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1521 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
Michael Kolb8872c232013-01-29 10:33:22 -08001522 }
1523
Angus Kongb50b5cb2013-08-09 14:55:20 -07001524 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);
Michael Kolb8872c232013-01-29 10:33:22 -08001525
1526 // Disable video stabilization. Convenience methods not available in API
1527 // level <= 14
1528 String vstabSupported = mParameters.get("video-stabilization-supported");
1529 if ("true".equals(vstabSupported)) {
1530 mParameters.set("video-stabilization", "false");
1531 }
1532 }
1533
1534 private void updateCameraParametersZoom() {
1535 // Set zoom.
1536 if (mParameters.isZoomSupported()) {
1537 mParameters.setZoom(mZoomValue);
1538 }
1539 }
1540
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001541 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001542 private void setAutoExposureLockIfSupported() {
1543 if (mAeLockSupported) {
1544 mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1545 }
1546 }
1547
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001548 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001549 private void setAutoWhiteBalanceLockIfSupported() {
1550 if (mAwbLockSupported) {
1551 mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1552 }
1553 }
1554
Michael Kolb8872c232013-01-29 10:33:22 -08001555 private void setFocusAreasIfSupported() {
1556 if (mFocusAreaSupported) {
1557 mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1558 }
1559 }
1560
Michael Kolb8872c232013-01-29 10:33:22 -08001561 private void setMeteringAreasIfSupported() {
1562 if (mMeteringAreaSupported) {
Michael Kolb8872c232013-01-29 10:33:22 -08001563 mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1564 }
1565 }
1566
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001567 private boolean updateCameraParametersPreference() {
Michael Kolb8872c232013-01-29 10:33:22 -08001568 setAutoExposureLockIfSupported();
1569 setAutoWhiteBalanceLockIfSupported();
1570 setFocusAreasIfSupported();
1571 setMeteringAreasIfSupported();
1572
1573 // Set picture size.
1574 String pictureSize = mPreferences.getString(
1575 CameraSettings.KEY_PICTURE_SIZE, null);
1576 if (pictureSize == null) {
1577 CameraSettings.initialCameraPictureSize(mActivity, mParameters);
1578 } else {
1579 List<Size> supported = mParameters.getSupportedPictureSizes();
1580 CameraSettings.setCameraPictureSize(
1581 pictureSize, supported, mParameters);
1582 }
1583 Size size = mParameters.getPictureSize();
1584
1585 // Set a preview size that is closest to the viewfinder height and has
1586 // the right aspect ratio.
1587 List<Size> sizes = mParameters.getSupportedPreviewSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001588 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
Michael Kolb8872c232013-01-29 10:33:22 -08001589 (double) size.width / size.height);
1590 Size original = mParameters.getPreviewSize();
1591 if (!original.equals(optimalSize)) {
1592 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
Doris Liu6432cd62013-06-13 17:20:31 -07001593
Michael Kolb8872c232013-01-29 10:33:22 -08001594 // Zoom related settings will be changed for different preview
1595 // sizes, so set and read the parameters to get latest values
Michael Kolb4a4d4ef2013-05-30 08:35:26 -07001596 if (mHandler.getLooper() == Looper.myLooper()) {
1597 // On UI thread only, not when camera starts up
1598 setupPreview();
1599 } else {
1600 mCameraDevice.setParameters(mParameters);
1601 }
Michael Kolb8872c232013-01-29 10:33:22 -08001602 mParameters = mCameraDevice.getParameters();
1603 }
1604 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
1605
1606 // Since changing scene mode may change supported values, set scene mode
1607 // first. HDR is a scene mode. To promote it in UI, it is stored in a
1608 // separate preference.
Sascha Haeberling98f38bb2013-09-24 18:58:34 -07001609 String onValue = mActivity.getString(R.string.setting_on_value);
Michael Kolb8872c232013-01-29 10:33:22 -08001610 String hdr = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR,
1611 mActivity.getString(R.string.pref_camera_hdr_default));
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001612 String hdrPlus = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR_PLUS,
1613 mActivity.getString(R.string.pref_camera_hdr_plus_default));
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001614 boolean hdrOn = onValue.equals(hdr);
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001615 boolean hdrPlusOn = onValue.equals(hdrPlus);
Sascha Haeberling98f38bb2013-09-24 18:58:34 -07001616
1617 boolean doGcamModeSwitch = false;
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001618 if (hdrPlusOn && GcamHelper.hasGcamCapture()) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001619 // Kick off mode switch to gcam.
1620 doGcamModeSwitch = true;
Michael Kolb8872c232013-01-29 10:33:22 -08001621 } else {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001622 if (hdrOn) {
1623 mSceneMode = CameraUtil.SCENE_MODE_HDR;
1624 } else {
1625 mSceneMode = mPreferences.getString(
1626 CameraSettings.KEY_SCENE_MODE,
1627 mActivity.getString(R.string.pref_camera_scenemode_default));
1628 }
Michael Kolb8872c232013-01-29 10:33:22 -08001629 }
Angus Kongb50b5cb2013-08-09 14:55:20 -07001630 if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
Michael Kolb8872c232013-01-29 10:33:22 -08001631 if (!mParameters.getSceneMode().equals(mSceneMode)) {
1632 mParameters.setSceneMode(mSceneMode);
1633
1634 // Setting scene mode will change the settings of flash mode,
1635 // white balance, and focus mode. Here we read back the
1636 // parameters, so we can know those settings.
1637 mCameraDevice.setParameters(mParameters);
1638 mParameters = mCameraDevice.getParameters();
1639 }
1640 } else {
1641 mSceneMode = mParameters.getSceneMode();
1642 if (mSceneMode == null) {
1643 mSceneMode = Parameters.SCENE_MODE_AUTO;
1644 }
1645 }
1646
1647 // Set JPEG quality.
1648 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1649 CameraProfile.QUALITY_HIGH);
1650 mParameters.setJpegQuality(jpegQuality);
1651
1652 // For the following settings, we need to check if the settings are
1653 // still supported by latest driver, if not, ignore the settings.
1654
1655 // Set exposure compensation
1656 int value = CameraSettings.readExposure(mPreferences);
1657 int max = mParameters.getMaxExposureCompensation();
1658 int min = mParameters.getMinExposureCompensation();
1659 if (value >= min && value <= max) {
1660 mParameters.setExposureCompensation(value);
1661 } else {
1662 Log.w(TAG, "invalid exposure range: " + value);
1663 }
1664
1665 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1666 // Set flash mode.
1667 String flashMode = mPreferences.getString(
1668 CameraSettings.KEY_FLASH_MODE,
1669 mActivity.getString(R.string.pref_camera_flashmode_default));
1670 List<String> supportedFlash = mParameters.getSupportedFlashModes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001671 if (CameraUtil.isSupported(flashMode, supportedFlash)) {
Michael Kolb8872c232013-01-29 10:33:22 -08001672 mParameters.setFlashMode(flashMode);
1673 } else {
1674 flashMode = mParameters.getFlashMode();
1675 if (flashMode == null) {
1676 flashMode = mActivity.getString(
1677 R.string.pref_camera_flashmode_no_flash);
1678 }
1679 }
1680
1681 // Set white balance parameter.
1682 String whiteBalance = mPreferences.getString(
1683 CameraSettings.KEY_WHITE_BALANCE,
1684 mActivity.getString(R.string.pref_camera_whitebalance_default));
Angus Kongb50b5cb2013-08-09 14:55:20 -07001685 if (CameraUtil.isSupported(whiteBalance,
Michael Kolb8872c232013-01-29 10:33:22 -08001686 mParameters.getSupportedWhiteBalance())) {
1687 mParameters.setWhiteBalance(whiteBalance);
1688 } else {
1689 whiteBalance = mParameters.getWhiteBalance();
1690 if (whiteBalance == null) {
1691 whiteBalance = Parameters.WHITE_BALANCE_AUTO;
1692 }
1693 }
1694
1695 // Set focus mode.
1696 mFocusManager.overrideFocusMode(null);
1697 mParameters.setFocusMode(mFocusManager.getFocusMode());
1698 } else {
1699 mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1700 }
1701
Angus Kongdcccc512013-08-08 17:06:03 -07001702 if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
Michael Kolb8872c232013-01-29 10:33:22 -08001703 updateAutoFocusMoveCallback();
1704 }
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001705
1706 return doGcamModeSwitch;
Michael Kolb8872c232013-01-29 10:33:22 -08001707 }
1708
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001709 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001710 private void updateAutoFocusMoveCallback() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001711 if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Angus Kong9ef99252013-07-18 18:04:19 -07001712 mCameraDevice.setAutoFocusMoveCallback(mHandler,
Angus Kong4f795b82013-09-16 14:25:35 -07001713 (CameraAFMoveCallback) mAutoFocusMoveCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001714 } else {
Angus Kong9ef99252013-07-18 18:04:19 -07001715 mCameraDevice.setAutoFocusMoveCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001716 }
1717 }
1718
1719 // We separate the parameters into several subsets, so we can update only
1720 // the subsets actually need updating. The PREFERENCE set needs extra
1721 // locking because the preference can be changed from GLThread as well.
1722 private void setCameraParameters(int updateSet) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001723 boolean doModeSwitch = false;
1724
Michael Kolb8872c232013-01-29 10:33:22 -08001725 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1726 updateCameraParametersInitialize();
1727 }
1728
1729 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1730 updateCameraParametersZoom();
1731 }
1732
1733 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001734 doModeSwitch = updateCameraParametersPreference();
Michael Kolb8872c232013-01-29 10:33:22 -08001735 }
1736
1737 mCameraDevice.setParameters(mParameters);
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001738
Sascha Haeberling9bf0fd62013-10-03 12:10:48 -07001739 // Switch to gcam module if HDR+ was selected
Angus Kong0fb819b2013-10-08 13:44:19 -07001740 if (doModeSwitch && !mIsImageCaptureIntent) {
Ruben Brunk4601f5d2013-09-24 18:35:22 -07001741 mActivity.onModuleSelected(ModuleSwitcher.GCAM_MODULE_INDEX);
1742 }
Michael Kolb8872c232013-01-29 10:33:22 -08001743 }
1744
1745 // If the Camera is idle, update the parameters immediately, otherwise
1746 // accumulate them in mUpdateSet and update later.
1747 private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1748 mUpdateSet |= additionalUpdateSet;
1749 if (mCameraDevice == null) {
1750 // We will update all the parameters when we open the device, so
1751 // we don't need to do anything now.
1752 mUpdateSet = 0;
1753 return;
1754 } else if (isCameraIdle()) {
1755 setCameraParameters(mUpdateSet);
Michael Kolbd6954f32013-03-08 20:43:01 -08001756 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001757 mUpdateSet = 0;
1758 } else {
1759 if (!mHandler.hasMessages(SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1760 mHandler.sendEmptyMessageDelayed(
1761 SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
1762 }
1763 }
1764 }
1765
ztenghui7b265a62013-09-09 14:58:44 -07001766 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001767 public boolean isCameraIdle() {
Michael Kolb8872c232013-01-29 10:33:22 -08001768 return (mCameraState == IDLE) ||
1769 (mCameraState == PREVIEW_STOPPED) ||
1770 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
1771 && (mCameraState != SWITCHING_CAMERA));
1772 }
1773
ztenghui7b265a62013-09-09 14:58:44 -07001774 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001775 public boolean isImageCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001776 String action = mActivity.getIntent().getAction();
1777 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
Angus Kong6a8e8a12013-07-19 14:55:07 -07001778 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
Michael Kolb8872c232013-01-29 10:33:22 -08001779 }
1780
1781 private void setupCaptureParams() {
1782 Bundle myExtras = mActivity.getIntent().getExtras();
1783 if (myExtras != null) {
1784 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1785 mCropValue = myExtras.getString("crop");
1786 }
1787 }
1788
Michael Kolb8872c232013-01-29 10:33:22 -08001789 @Override
1790 public void onSharedPreferenceChanged() {
1791 // ignore the events after "onPause()"
1792 if (mPaused) return;
1793
1794 boolean recordLocation = RecordLocationPreference.get(
1795 mPreferences, mContentResolver);
1796 mLocationManager.recordLocation(recordLocation);
1797
1798 setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
Michael Kolbeb8adc12013-04-26 11:09:29 -07001799 mUI.updateOnScreenIndicators(mParameters, mPreferenceGroup, mPreferences);
Michael Kolb8872c232013-01-29 10:33:22 -08001800 }
1801
1802 @Override
1803 public void onCameraPickerClicked(int cameraId) {
1804 if (mPaused || mPendingSwitchCameraId != -1) return;
1805
1806 mPendingSwitchCameraId = cameraId;
Doris Liu6432cd62013-06-13 17:20:31 -07001807
1808 Log.v(TAG, "Start to switch camera. cameraId=" + cameraId);
1809 // We need to keep a preview frame for the animation before
1810 // releasing the camera. This will trigger onPreviewTextureCopied.
1811 //TODO: Need to animate the camera switch
1812 switchCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001813 }
1814
Michael Kolb8872c232013-01-29 10:33:22 -08001815 // Preview texture has been copied. Now camera can be released and the
1816 // animation can be started.
1817 @Override
1818 public void onPreviewTextureCopied() {
1819 mHandler.sendEmptyMessage(SWITCH_CAMERA);
1820 }
1821
1822 @Override
1823 public void onCaptureTextureCopied() {
1824 }
1825
1826 @Override
1827 public void onUserInteraction() {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001828 if (!mActivity.isFinishing()) keepScreenOnAwhile();
Michael Kolb8872c232013-01-29 10:33:22 -08001829 }
1830
1831 private void resetScreenOn() {
1832 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1833 mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1834 }
1835
1836 private void keepScreenOnAwhile() {
1837 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1838 mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1839 mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
1840 }
1841
Michael Kolb8872c232013-01-29 10:33:22 -08001842 @Override
1843 public void onOverriddenPreferencesClicked() {
1844 if (mPaused) return;
Michael Kolbd6954f32013-03-08 20:43:01 -08001845 mUI.showPreferencesToast();
Michael Kolb8872c232013-01-29 10:33:22 -08001846 }
1847
1848 private void showTapToFocusToast() {
1849 // TODO: Use a toast?
1850 new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
1851 // Clear the preference.
1852 Editor editor = mPreferences.edit();
1853 editor.putBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, false);
1854 editor.apply();
1855 }
1856
1857 private void initializeCapabilities() {
1858 mInitialParams = mCameraDevice.getParameters();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001859 mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
1860 mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
1861 mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
1862 mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
Angus Kongdcccc512013-08-08 17:06:03 -07001863 mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001864 CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
Michael Kolb8872c232013-01-29 10:33:22 -08001865 }
1866
Michael Kolb8872c232013-01-29 10:33:22 -08001867 @Override
1868 public void onCountDownFinished() {
1869 mSnapshotOnIdle = false;
1870 mFocusManager.doSnap();
Doris Liuda50e052013-02-07 14:36:32 -08001871 mFocusManager.onShutterUp();
Michael Kolb8872c232013-01-29 10:33:22 -08001872 }
1873
Michael Kolb8872c232013-01-29 10:33:22 -08001874 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001875 public void onShowSwitcherPopup() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001876 mUI.onShowSwitcherPopup();
Michael Kolb8872c232013-01-29 10:33:22 -08001877 }
1878
Angus Kongce5480e2013-01-29 17:43:48 -08001879 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001880 public int onZoomChanged(int index) {
1881 // Not useful to change zoom value when the activity is paused.
1882 if (mPaused) return index;
1883 mZoomValue = index;
1884 if (mParameters == null || mCameraDevice == null) return index;
1885 // Set zoom parameters asynchronously
1886 mParameters.setZoom(mZoomValue);
Angus Kong36ed8672013-04-15 12:11:15 -07001887 mCameraDevice.setParameters(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -08001888 Parameters p = mCameraDevice.getParameters();
1889 if (p != null) return p.getZoom();
1890 return index;
Angus Kongce5480e2013-01-29 17:43:48 -08001891 }
1892
1893 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001894 public int getCameraState() {
1895 return mCameraState;
1896 }
1897
1898 @Override
1899 public void onQueueStatus(boolean full) {
1900 mUI.enableShutter(!full);
Angus Kongce5480e2013-01-29 17:43:48 -08001901 }
Angus Kong86d36312013-01-31 18:22:44 -08001902
1903 @Override
1904 public void onMediaSaveServiceConnected(MediaSaveService s) {
1905 // We set the listener only when both service and shutterbutton
1906 // are initialized.
Michael Kolbd6954f32013-03-08 20:43:01 -08001907 if (mFirstTimeInitialized) {
1908 s.setListener(this);
1909 }
Angus Kong86d36312013-01-31 18:22:44 -08001910 }
Angus Kong0d00a892013-03-26 11:40:40 -07001911
1912 @Override
1913 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1914 }
1915
1916 @Override
1917 public void onSensorChanged(SensorEvent event) {
1918 int type = event.sensor.getType();
1919 float[] data;
1920 if (type == Sensor.TYPE_ACCELEROMETER) {
1921 data = mGData;
1922 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
1923 data = mMData;
1924 } else {
1925 // we should not be here.
1926 return;
1927 }
1928 for (int i = 0; i < 3 ; i++) {
1929 data[i] = event.values[i];
1930 }
1931 float[] orientation = new float[3];
1932 SensorManager.getRotationMatrix(mR, null, mGData, mMData);
1933 SensorManager.getOrientation(mR, orientation);
1934 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
1935 if (mHeading < 0) {
1936 mHeading += 360;
1937 }
Angus Kong0d00a892013-03-26 11:40:40 -07001938 }
Doris Liu6432cd62013-06-13 17:20:31 -07001939
1940 @Override
ztenghui7b265a62013-09-09 14:58:44 -07001941 public void onPreviewFocusChanged(boolean previewFocused) {
1942 mUI.onPreviewFocusChanged(previewFocused);
Doris Liu6432cd62013-06-13 17:20:31 -07001943 }
1944
Ruben Brunkd217ed02013-10-08 23:31:13 -07001945 // For debugging only.
1946 public void setDebugUri(Uri uri) {
1947 mDebugUri = uri;
1948 }
1949
1950 // For debugging only.
1951 private void saveToDebugUri(byte[] data) {
1952 if (mDebugUri != null) {
1953 OutputStream outputStream = null;
1954 try {
1955 outputStream = mContentResolver.openOutputStream(mDebugUri);
1956 outputStream.write(data);
1957 outputStream.close();
1958 } catch (IOException e) {
1959 Log.e(TAG, "Exception while writing debug jpeg file", e);
1960 } finally {
1961 CameraUtil.closeSilently(outputStream);
1962 }
1963 }
1964 }
1965
Doris Liu6432cd62013-06-13 17:20:31 -07001966/* Below is no longer needed, except to get rid of compile error
1967 * TODO: Remove these
1968 */
1969
1970 // TODO: Delete this function after old camera code is removed
1971 @Override
1972 public void onRestorePreferencesClicked() {}
1973
Michael Kolb8872c232013-01-29 10:33:22 -08001974}