blob: d00da1935f3bbccafaeb3c65d75f22b74150163c [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;
41import android.os.Bundle;
Michael Kolb8872c232013-01-29 10:33:22 -080042import android.os.Handler;
43import android.os.Looper;
44import android.os.Message;
45import android.os.MessageQueue;
46import android.os.SystemClock;
47import android.provider.MediaStore;
48import android.util.Log;
Michael Kolb8872c232013-01-29 10:33:22 -080049import android.view.KeyEvent;
Michael Kolb8872c232013-01-29 10:33:22 -080050import android.view.OrientationEventListener;
Michael Kolb8872c232013-01-29 10:33:22 -080051import android.view.View;
Michael Kolb8872c232013-01-29 10:33:22 -080052import android.view.WindowManager;
Michael Kolb8872c232013-01-29 10:33:22 -080053
Angus Kong9ef99252013-07-18 18:04:19 -070054import com.android.camera.CameraManager.CameraAFCallback;
55import com.android.camera.CameraManager.CameraAFMoveCallback;
56import com.android.camera.CameraManager.CameraPictureCallback;
Michael Kolb8872c232013-01-29 10:33:22 -080057import com.android.camera.CameraManager.CameraProxy;
Angus Kong9ef99252013-07-18 18:04:19 -070058import com.android.camera.CameraManager.CameraShutterCallback;
ztenghuia16e7b52013-08-23 11:47:56 -070059import com.android.camera.exif.ExifInterface;
60import com.android.camera.exif.ExifTag;
61import com.android.camera.exif.Rational;
Michael Kolbd6954f32013-03-08 20:43:01 -080062import com.android.camera.ui.CountDownView.OnCountDownFinishedListener;
Michael Kolb8872c232013-01-29 10:33:22 -080063import com.android.camera.ui.PopupManager;
Michael Kolb8872c232013-01-29 10:33:22 -080064import com.android.camera.ui.RotateTextToast;
Angus Kongdcccc512013-08-08 17:06:03 -070065import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -070066import com.android.camera.util.CameraUtil;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070067import com.android.camera.util.UsageStatistics;
68import com.android.camera2.R;
Michael Kolb8872c232013-01-29 10:33:22 -080069
Angus Kongdcccc512013-08-08 17:06:03 -070070import java.io.File;
71import java.io.FileNotFoundException;
72import java.io.FileOutputStream;
73import java.io.IOException;
74import java.io.OutputStream;
75import java.util.ArrayList;
76import java.util.List;
77
Michael Kolb8872c232013-01-29 10:33:22 -080078public class PhotoModule
Dan Aminzade92ae10e2013-08-13 14:44:25 -070079 implements CameraModule,
80 PhotoController,
81 FocusOverlayManager.Listener,
82 CameraPreference.OnPreferenceChangedListener,
83 ShutterButton.OnShutterButtonListener,
84 MediaSaveService.Listener,
85 OnCountDownFinishedListener,
86 SensorEventListener {
Michael Kolb8872c232013-01-29 10:33:22 -080087
88 private static final String TAG = "CAM_PhotoModule";
89
90 // We number the request code from 1000 to avoid collision with Gallery.
91 private static final int REQUEST_CROP = 1000;
92
93 private static final int SETUP_PREVIEW = 1;
94 private static final int FIRST_TIME_INIT = 2;
95 private static final int CLEAR_SCREEN_DELAY = 3;
96 private static final int SET_CAMERA_PARAMETERS_WHEN_IDLE = 4;
Angus Kongdcccc512013-08-08 17:06:03 -070097 private static final int SHOW_TAP_TO_FOCUS_TOAST = 5;
98 private static final int SWITCH_CAMERA = 6;
99 private static final int SWITCH_CAMERA_START_ANIMATION = 7;
100 private static final int CAMERA_OPEN_DONE = 8;
101 private static final int OPEN_CAMERA_FAIL = 9;
102 private static final int CAMERA_DISABLED = 10;
Michael Kolb8872c232013-01-29 10:33:22 -0800103
104 // The subset of parameters we need to update in setCameraParameters().
105 private static final int UPDATE_PARAM_INITIALIZE = 1;
106 private static final int UPDATE_PARAM_ZOOM = 2;
107 private static final int UPDATE_PARAM_PREFERENCE = 4;
108 private static final int UPDATE_PARAM_ALL = -1;
109
110 // This is the timeout to keep the camera in onPause for the first time
111 // after screen on if the activity is started from secure lock screen.
112 private static final int KEEP_CAMERA_TIMEOUT = 1000; // ms
113
114 // copied from Camera hierarchy
115 private CameraActivity mActivity;
Michael Kolb8872c232013-01-29 10:33:22 -0800116 private CameraProxy mCameraDevice;
117 private int mCameraId;
118 private Parameters mParameters;
119 private boolean mPaused;
Michael Kolbd6954f32013-03-08 20:43:01 -0800120
121 private PhotoUI mUI;
Michael Kolb8872c232013-01-29 10:33:22 -0800122
Michael Kolb8872c232013-01-29 10:33:22 -0800123 // The activity is going to switch to the specified camera id. This is
124 // needed because texture copy is done in GL thread. -1 means camera is not
125 // switching.
126 protected int mPendingSwitchCameraId = -1;
127 private boolean mOpenCameraFail;
128 private boolean mCameraDisabled;
129
130 // When setCameraParametersWhenIdle() is called, we accumulate the subsets
131 // needed to be updated in mUpdateSet.
132 private int mUpdateSet;
133
134 private static final int SCREEN_DELAY = 2 * 60 * 1000;
135
136 private int mZoomValue; // The current zoom value.
Michael Kolb8872c232013-01-29 10:33:22 -0800137
138 private Parameters mInitialParams;
139 private boolean mFocusAreaSupported;
140 private boolean mMeteringAreaSupported;
141 private boolean mAeLockSupported;
142 private boolean mAwbLockSupported;
Angus Kongdcccc512013-08-08 17:06:03 -0700143 private boolean mContinuousFocusSupported;
Michael Kolb8872c232013-01-29 10:33:22 -0800144
145 // The degrees of the device rotated clockwise from its natural orientation.
146 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
147 private ComboPreferences mPreferences;
148
149 private static final String sTempCropFilename = "crop-temp";
150
151 private ContentProviderClient mMediaProviderClient;
Michael Kolb8872c232013-01-29 10:33:22 -0800152 private boolean mFaceDetectionStarted = false;
153
Michael Kolb8872c232013-01-29 10:33:22 -0800154 // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
155 private String mCropValue;
156 private Uri mSaveUri;
157
Angus Kongce5480e2013-01-29 17:43:48 -0800158 // We use a queue to generated names of the images to be used later
159 // when the image is ready to be saved.
Michael Kolb8872c232013-01-29 10:33:22 -0800160 private NamedImages mNamedImages;
161
162 private Runnable mDoSnapRunnable = new Runnable() {
163 @Override
164 public void run() {
165 onShutterButtonClick();
166 }
167 };
168
Michael Kolb8872c232013-01-29 10:33:22 -0800169 /**
170 * An unpublished intent flag requesting to return as soon as capturing
171 * is completed.
172 *
173 * TODO: consider publishing by moving into MediaStore.
174 */
175 private static final String EXTRA_QUICK_CAPTURE =
176 "android.intent.extra.quickCapture";
177
178 // The display rotation in degrees. This is only valid when mCameraState is
179 // not PREVIEW_STOPPED.
180 private int mDisplayRotation;
181 // The value for android.hardware.Camera.setDisplayOrientation.
182 private int mCameraDisplayOrientation;
183 // The value for UI components like indicators.
184 private int mDisplayOrientation;
185 // The value for android.hardware.Camera.Parameters.setRotation.
186 private int mJpegRotation;
Doris Liu29da2db2013-08-28 14:28:45 -0700187 // Indicates whether we are using front camera
188 private boolean mMirror;
Michael Kolb8872c232013-01-29 10:33:22 -0800189 private boolean mFirstTimeInitialized;
190 private boolean mIsImageCaptureIntent;
191
Michael Kolb8872c232013-01-29 10:33:22 -0800192 private int mCameraState = PREVIEW_STOPPED;
193 private boolean mSnapshotOnIdle = false;
194
195 private ContentResolver mContentResolver;
196
197 private LocationManager mLocationManager;
198
Michael Kolb8872c232013-01-29 10:33:22 -0800199 private final PostViewPictureCallback mPostViewPictureCallback =
200 new PostViewPictureCallback();
201 private final RawPictureCallback mRawPictureCallback =
202 new RawPictureCallback();
203 private final AutoFocusCallback mAutoFocusCallback =
204 new AutoFocusCallback();
205 private final Object mAutoFocusMoveCallback =
206 ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700207 ? new AutoFocusMoveCallback()
208 : null;
Michael Kolb8872c232013-01-29 10:33:22 -0800209
210 private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
211
212 private long mFocusStartTime;
213 private long mShutterCallbackTime;
214 private long mPostViewPictureCallbackTime;
215 private long mRawPictureCallbackTime;
216 private long mJpegPictureCallbackTime;
217 private long mOnResumeTime;
218 private byte[] mJpegImageData;
219
220 // These latency time are for the CameraLatency test.
221 public long mAutoFocusTime;
222 public long mShutterLag;
223 public long mShutterToPictureDisplayedTime;
224 public long mPictureDisplayedToJpegCallbackTime;
225 public long mJpegCallbackFinishTime;
226 public long mCaptureStartTime;
227
228 // This handles everything about focus.
229 private FocusOverlayManager mFocusManager;
230
Michael Kolb8872c232013-01-29 10:33:22 -0800231 private String mSceneMode;
Michael Kolb8872c232013-01-29 10:33:22 -0800232
233 private final Handler mHandler = new MainHandler();
234 private PreferenceGroup mPreferenceGroup;
235
236 private boolean mQuickCapture;
Angus Kong0d00a892013-03-26 11:40:40 -0700237 private SensorManager mSensorManager;
238 private float[] mGData = new float[3];
239 private float[] mMData = new float[3];
240 private float[] mR = new float[16];
241 private int mHeading = -1;
242
Angus Kongdcccc512013-08-08 17:06:03 -0700243 // True if all the parameters needed to start preview is ready.
244 private boolean mCameraPreviewParamsReady = false;
Doris Liu6432cd62013-06-13 17:20:31 -0700245
Angus Kongce5480e2013-01-29 17:43:48 -0800246 private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener =
247 new MediaSaveService.OnMediaSavedListener() {
248 @Override
249 public void onMediaSaved(Uri uri) {
250 if (uri != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700251 mActivity.notifyNewMedia(uri);
Angus Kongce5480e2013-01-29 17:43:48 -0800252 }
253 }
254 };
Michael Kolb8872c232013-01-29 10:33:22 -0800255
Angus Kongdcccc512013-08-08 17:06:03 -0700256 private void checkDisplayRotation() {
257 // Set the display orientation if display rotation has changed.
258 // Sometimes this happens when the device is held upside
259 // down and camera app is opened. Rotation animation will
260 // take some time and the rotation value we have got may be
261 // wrong. Framework does not have a callback for this now.
262 if (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) {
263 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -0800264 }
Angus Kongdcccc512013-08-08 17:06:03 -0700265 if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
266 mHandler.postDelayed(new Runnable() {
267 @Override
268 public void run() {
269 checkDisplayRotation();
270 }
271 }, 100);
Michael Kolb8872c232013-01-29 10:33:22 -0800272 }
273 }
274
275 /**
276 * This Handler is used to post message back onto the main thread of the
277 * application
278 */
279 private class MainHandler extends Handler {
280 @Override
281 public void handleMessage(Message msg) {
282 switch (msg.what) {
283 case SETUP_PREVIEW: {
284 setupPreview();
285 break;
286 }
287
288 case CLEAR_SCREEN_DELAY: {
289 mActivity.getWindow().clearFlags(
290 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
291 break;
292 }
293
294 case FIRST_TIME_INIT: {
295 initializeFirstTime();
296 break;
297 }
298
299 case SET_CAMERA_PARAMETERS_WHEN_IDLE: {
300 setCameraParametersWhenIdle(0);
301 break;
302 }
303
Michael Kolb8872c232013-01-29 10:33:22 -0800304 case SHOW_TAP_TO_FOCUS_TOAST: {
305 showTapToFocusToast();
306 break;
307 }
308
309 case SWITCH_CAMERA: {
310 switchCamera();
311 break;
312 }
313
314 case SWITCH_CAMERA_START_ANIMATION: {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700315 // TODO: Need to revisit
316 // ((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera();
Michael Kolb8872c232013-01-29 10:33:22 -0800317 break;
318 }
319
320 case CAMERA_OPEN_DONE: {
Michael Kolbd6954f32013-03-08 20:43:01 -0800321 onCameraOpened();
Michael Kolb8872c232013-01-29 10:33:22 -0800322 break;
323 }
324
Michael Kolb8872c232013-01-29 10:33:22 -0800325 case OPEN_CAMERA_FAIL: {
Michael Kolb8872c232013-01-29 10:33:22 -0800326 mOpenCameraFail = true;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700327 CameraUtil.showErrorAndFinish(mActivity,
Michael Kolb8872c232013-01-29 10:33:22 -0800328 R.string.cannot_connect_camera);
329 break;
330 }
331
332 case CAMERA_DISABLED: {
Michael Kolb8872c232013-01-29 10:33:22 -0800333 mCameraDisabled = true;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700334 CameraUtil.showErrorAndFinish(mActivity,
Michael Kolb8872c232013-01-29 10:33:22 -0800335 R.string.camera_disabled);
336 break;
337 }
Michael Kolb8872c232013-01-29 10:33:22 -0800338 }
339 }
340 }
341
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700342 private BroadcastReceiver mReceiver = null;
343
344 private class ShutterBroadcastReceiver extends BroadcastReceiver {
345 @Override
346 public void onReceive(Context context, Intent intent) {
347 String action = intent.getAction();
Dan Aminzadefca1c5e2013-08-14 17:36:56 -0700348 if (action.equals(CameraUtil.ACTION_CAMERA_SHUTTER_CLICK)) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700349 onShutterButtonFocus(true);
350 onShutterButtonClick();
351 }
352 }
353 }
354
Michael Kolb8872c232013-01-29 10:33:22 -0800355 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700356 public void init(CameraActivity activity, View parent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800357 mActivity = activity;
Michael Kolbd6954f32013-03-08 20:43:01 -0800358 mUI = new PhotoUI(activity, this, parent);
Michael Kolb8872c232013-01-29 10:33:22 -0800359 mPreferences = new ComboPreferences(mActivity);
360 CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal());
361 mCameraId = getPreferredCameraId(mPreferences);
362
363 mContentResolver = mActivity.getContentResolver();
364
Michael Kolb8872c232013-01-29 10:33:22 -0800365 // Surface texture is from camera screen nail and startPreview needs it.
366 // This must be done before startPreview.
367 mIsImageCaptureIntent = isImageCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800368
369 mPreferences.setLocalId(mActivity, mCameraId);
370 CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
371 // we need to reset exposure for the preview
372 resetExposureCompensation();
Michael Kolb8872c232013-01-29 10:33:22 -0800373
374 initializeControlByIntent();
375 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
Michael Kolbd6954f32013-03-08 20:43:01 -0800376 mLocationManager = new LocationManager(mActivity, mUI);
Angus Kong0d00a892013-03-26 11:40:40 -0700377 mSensorManager = (SensorManager)(mActivity.getSystemService(Context.SENSOR_SERVICE));
Michael Kolbd6954f32013-03-08 20:43:01 -0800378 }
379
380 private void initializeControlByIntent() {
381 mUI.initializeControlByIntent();
382 if (mIsImageCaptureIntent) {
383 setupCaptureParams();
384 }
385 }
386
387 private void onPreviewStarted() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800388 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800389 startFaceDetection();
390 locationFirstRun();
Michael Kolb8872c232013-01-29 10:33:22 -0800391 }
392
393 // Prompt the user to pick to record location for the very first run of
394 // camera only
395 private void locationFirstRun() {
396 if (RecordLocationPreference.isSet(mPreferences)) {
397 return;
398 }
399 if (mActivity.isSecureCamera()) return;
400 // Check if the back camera exists
401 int backCameraId = CameraHolder.instance().getBackCameraId();
402 if (backCameraId == -1) {
403 // If there is no back camera, do not show the prompt.
404 return;
405 }
Doris Liu6a83d522013-07-02 12:03:32 -0700406 mUI.showLocationDialog();
407 }
Michael Kolb8872c232013-01-29 10:33:22 -0800408
ztenghui7b265a62013-09-09 14:58:44 -0700409 @Override
Doris Liu6a83d522013-07-02 12:03:32 -0700410 public void enableRecordingLocation(boolean enable) {
411 setLocationPreference(enable ? RecordLocationPreference.VALUE_ON
412 : RecordLocationPreference.VALUE_OFF);
Michael Kolb8872c232013-01-29 10:33:22 -0800413 }
414
Angus Kongdcccc512013-08-08 17:06:03 -0700415 @Override
416 public void onPreviewUIReady() {
417 startPreview();
418 }
419
420 @Override
421 public void onPreviewUIDestroyed() {
422 if (mCameraDevice == null) {
423 return;
424 }
425 mCameraDevice.setPreviewTexture(null);
426 stopPreview();
427 }
428
Michael Kolb8872c232013-01-29 10:33:22 -0800429 private void setLocationPreference(String value) {
430 mPreferences.edit()
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700431 .putString(CameraSettings.KEY_RECORD_LOCATION, value)
432 .apply();
Michael Kolb8872c232013-01-29 10:33:22 -0800433 // TODO: Fix this to use the actual onSharedPreferencesChanged listener
434 // instead of invoking manually
435 onSharedPreferenceChanged();
436 }
437
Michael Kolbd6954f32013-03-08 20:43:01 -0800438 private void onCameraOpened() {
439 View root = mUI.getRootView();
Michael Kolb8872c232013-01-29 10:33:22 -0800440 // These depend on camera parameters.
Michael Kolbd6954f32013-03-08 20:43:01 -0800441
442 int width = root.getWidth();
443 int height = root.getHeight();
Doris Liu6a0de792013-02-26 10:54:25 -0800444 mFocusManager.setPreviewSize(width, height);
Michael Kolbd6954f32013-03-08 20:43:01 -0800445 openCameraCommon();
Michael Kolb8872c232013-01-29 10:33:22 -0800446 }
447
Michael Kolbd6954f32013-03-08 20:43:01 -0800448 private void switchCamera() {
449 if (mPaused) return;
450
451 Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
452 mCameraId = mPendingSwitchCameraId;
453 mPendingSwitchCameraId = -1;
454 setCameraId(mCameraId);
455
456 // from onPause
457 closeCamera();
458 mUI.collapseCameraControls();
459 mUI.clearFaces();
460 if (mFocusManager != null) mFocusManager.removeMessages();
461
462 // Restart the camera and initialize the UI. From onCreate.
463 mPreferences.setLocalId(mActivity, mCameraId);
464 CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
465 try {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700466 mCameraDevice = CameraUtil.openCamera(mActivity, mCameraId);
Michael Kolbd6954f32013-03-08 20:43:01 -0800467 mParameters = mCameraDevice.getParameters();
468 } catch (CameraHardwareException e) {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700469 CameraUtil.showErrorAndFinish(mActivity, R.string.cannot_connect_camera);
Michael Kolbd6954f32013-03-08 20:43:01 -0800470 return;
471 } catch (CameraDisabledException e) {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700472 CameraUtil.showErrorAndFinish(mActivity, R.string.camera_disabled);
Michael Kolbd6954f32013-03-08 20:43:01 -0800473 return;
Doris Liu09106a42013-03-05 09:54:25 -0800474 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800475 initializeCapabilities();
476 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -0700477 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
478 mFocusManager.setMirror(mMirror);
Michael Kolbd6954f32013-03-08 20:43:01 -0800479 mFocusManager.setParameters(mInitialParams);
480 setupPreview();
481
Doris Liu6432cd62013-06-13 17:20:31 -0700482 // reset zoom value index
483 mZoomValue = 0;
Michael Kolbd6954f32013-03-08 20:43:01 -0800484 openCameraCommon();
485
486 if (ApiHelper.HAS_SURFACE_TEXTURE) {
487 // Start switch camera animation. Post a message because
488 // onFrameAvailable from the old camera may already exist.
489 mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION);
Doris Liu48239f42013-03-04 22:19:10 -0800490 }
491 }
492
Michael Kolbd6954f32013-03-08 20:43:01 -0800493 protected void setCameraId(int cameraId) {
494 ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID);
495 pref.setValue("" + cameraId);
496 }
497
498 // either open a new camera or switch cameras
499 private void openCameraCommon() {
Michael Kolb8872c232013-01-29 10:33:22 -0800500 loadCameraPreferences();
Michael Kolbd6954f32013-03-08 20:43:01 -0800501
502 mUI.onCameraOpened(mPreferenceGroup, mPreferences, mParameters, this);
503 updateSceneMode();
504 showTapToFocusToastIfNeeded();
505
506
Michael Kolb8872c232013-01-29 10:33:22 -0800507 }
508
ztenghui7b265a62013-09-09 14:58:44 -0700509 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -0800510 public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) {
Michael Kolbd6954f32013-03-08 20:43:01 -0800511 if (mFocusManager != null) mFocusManager.setPreviewSize(width, height);
Michael Kolbd6954f32013-03-08 20:43:01 -0800512 }
Michael Kolb8872c232013-01-29 10:33:22 -0800513
514 private void resetExposureCompensation() {
515 String value = mPreferences.getString(CameraSettings.KEY_EXPOSURE,
516 CameraSettings.EXPOSURE_DEFAULT_VALUE);
517 if (!CameraSettings.EXPOSURE_DEFAULT_VALUE.equals(value)) {
518 Editor editor = mPreferences.edit();
519 editor.putString(CameraSettings.KEY_EXPOSURE, "0");
520 editor.apply();
521 }
522 }
523
524 private void keepMediaProviderInstance() {
525 // We want to keep a reference to MediaProvider in camera's lifecycle.
526 // TODO: Utilize mMediaProviderClient instance to replace
527 // ContentResolver calls.
528 if (mMediaProviderClient == null) {
529 mMediaProviderClient = mContentResolver
530 .acquireContentProviderClient(MediaStore.AUTHORITY);
531 }
532 }
533
534 // Snapshots can only be taken after this is called. It should be called
535 // once only. We could have done these things in onCreate() but we want to
536 // make preview screen appear as soon as possible.
537 private void initializeFirstTime() {
538 if (mFirstTimeInitialized) return;
539
540 // Initialize location service.
541 boolean recordLocation = RecordLocationPreference.get(
542 mPreferences, mContentResolver);
543 mLocationManager.recordLocation(recordLocation);
544
545 keepMediaProviderInstance();
546
Michael Kolbd6954f32013-03-08 20:43:01 -0800547 mUI.initializeFirstTime();
Angus Kong86d36312013-01-31 18:22:44 -0800548 MediaSaveService s = mActivity.getMediaSaveService();
549 // We set the listener only when both service and shutterbutton
550 // are initialized.
551 if (s != null) {
552 s.setListener(this);
553 }
Michael Kolb8872c232013-01-29 10:33:22 -0800554
Michael Kolb8872c232013-01-29 10:33:22 -0800555 mNamedImages = new NamedImages();
556
557 mFirstTimeInitialized = true;
558 addIdleHandler();
559
560 mActivity.updateStorageSpaceAndHint();
561 }
562
Michael Kolbd6954f32013-03-08 20:43:01 -0800563 // If the activity is paused and resumed, this method will be called in
564 // onResume.
565 private void initializeSecondTime() {
566 // Start location update if needed.
567 boolean recordLocation = RecordLocationPreference.get(
568 mPreferences, mContentResolver);
569 mLocationManager.recordLocation(recordLocation);
570 MediaSaveService s = mActivity.getMediaSaveService();
571 if (s != null) {
572 s.setListener(this);
573 }
574 mNamedImages = new NamedImages();
575 mUI.initializeSecondTime(mParameters);
576 keepMediaProviderInstance();
577 }
578
Michael Kolb8872c232013-01-29 10:33:22 -0800579 private void showTapToFocusToastIfNeeded() {
580 // Show the tap to focus toast if this is the first start.
581 if (mFocusAreaSupported &&
582 mPreferences.getBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, true)) {
583 // Delay the toast for one second to wait for orientation.
584 mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_FOCUS_TOAST, 1000);
585 }
586 }
587
588 private void addIdleHandler() {
589 MessageQueue queue = Looper.myQueue();
590 queue.addIdleHandler(new MessageQueue.IdleHandler() {
591 @Override
592 public boolean queueIdle() {
593 Storage.ensureOSXCompatible();
594 return false;
595 }
596 });
597 }
598
Michael Kolb8872c232013-01-29 10:33:22 -0800599 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
600 @Override
601 public void startFaceDetection() {
602 if (!ApiHelper.HAS_FACE_DETECTION) return;
603 if (mFaceDetectionStarted) return;
604 if (mParameters.getMaxNumDetectedFaces() > 0) {
605 mFaceDetectionStarted = true;
Michael Kolb8872c232013-01-29 10:33:22 -0800606 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Michael Kolbd6954f32013-03-08 20:43:01 -0800607 mUI.onStartFaceDetection(mDisplayOrientation,
608 (info.facing == CameraInfo.CAMERA_FACING_FRONT));
Angus Kong9e765522013-07-31 14:05:20 -0700609 mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Michael Kolb8872c232013-01-29 10:33:22 -0800610 mCameraDevice.startFaceDetection();
611 }
612 }
613
614 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
615 @Override
616 public void stopFaceDetection() {
617 if (!ApiHelper.HAS_FACE_DETECTION) return;
618 if (!mFaceDetectionStarted) return;
619 if (mParameters.getMaxNumDetectedFaces() > 0) {
620 mFaceDetectionStarted = false;
Angus Kong9e765522013-07-31 14:05:20 -0700621 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -0800622 mCameraDevice.stopFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800623 mUI.clearFaces();
Michael Kolb8872c232013-01-29 10:33:22 -0800624 }
625 }
626
Michael Kolb8872c232013-01-29 10:33:22 -0800627 private final class ShutterCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700628 implements CameraShutterCallback {
Angus Kongdcb0ef12013-03-25 23:11:43 -0700629
Sascha Haeberling37f36112013-08-06 14:31:52 -0700630 private boolean mNeedsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700631
Sascha Haeberling37f36112013-08-06 14:31:52 -0700632 public ShutterCallback(boolean needsAnimation) {
633 mNeedsAnimation = needsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700634 }
635
Michael Kolb8872c232013-01-29 10:33:22 -0800636 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700637 public void onShutter(CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800638 mShutterCallbackTime = System.currentTimeMillis();
639 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
640 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Sascha Haeberling37f36112013-08-06 14:31:52 -0700641 if (mNeedsAnimation) {
642 mActivity.runOnUiThread(new Runnable() {
643 @Override
644 public void run() {
645 animateAfterShutter();
646 }
647 });
Angus Kongdcb0ef12013-03-25 23:11:43 -0700648 }
Michael Kolb8872c232013-01-29 10:33:22 -0800649 }
650 }
651
Angus Kong9ef99252013-07-18 18:04:19 -0700652 private final class PostViewPictureCallback
653 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800654 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700655 public void onPictureTaken(byte [] data, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800656 mPostViewPictureCallbackTime = System.currentTimeMillis();
657 Log.v(TAG, "mShutterToPostViewCallbackTime = "
658 + (mPostViewPictureCallbackTime - mShutterCallbackTime)
659 + "ms");
660 }
661 }
662
Angus Kong9ef99252013-07-18 18:04:19 -0700663 private final class RawPictureCallback
664 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800665 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700666 public void onPictureTaken(byte [] rawData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800667 mRawPictureCallbackTime = System.currentTimeMillis();
668 Log.v(TAG, "mShutterToRawCallbackTime = "
669 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
670 }
671 }
672
Angus Kong9ef99252013-07-18 18:04:19 -0700673 private final class JpegPictureCallback
674 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800675 Location mLocation;
676
677 public JpegPictureCallback(Location loc) {
678 mLocation = loc;
679 }
680
681 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700682 public void onPictureTaken(final byte [] jpegData, CameraProxy camera) {
Sascha Haeberling88901942013-08-28 17:49:00 -0700683 mUI.enableShutter(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800684 if (mPaused) {
685 return;
686 }
Doris Liu6432cd62013-06-13 17:20:31 -0700687 if (mIsImageCaptureIntent) {
688 stopPreview();
689 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700690 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -0700691 mUI.showSwitcher();
692 mUI.setSwipingEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800693 }
694
695 mJpegPictureCallbackTime = System.currentTimeMillis();
696 // If postview callback has arrived, the captured image is displayed
697 // in postview callback. If not, the captured image is displayed in
698 // raw picture callback.
699 if (mPostViewPictureCallbackTime != 0) {
700 mShutterToPictureDisplayedTime =
701 mPostViewPictureCallbackTime - mShutterCallbackTime;
702 mPictureDisplayedToJpegCallbackTime =
703 mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
704 } else {
705 mShutterToPictureDisplayedTime =
706 mRawPictureCallbackTime - mShutterCallbackTime;
707 mPictureDisplayedToJpegCallbackTime =
708 mJpegPictureCallbackTime - mRawPictureCallbackTime;
709 }
710 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
711 + mPictureDisplayedToJpegCallbackTime + "ms");
712
Michael Kolb8872c232013-01-29 10:33:22 -0800713 mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
714 if (!mIsImageCaptureIntent) {
715 if (ApiHelper.CAN_START_PREVIEW_IN_JPEG_CALLBACK) {
716 setupPreview();
717 } else {
718 // Camera HAL of some devices have a bug. Starting preview
719 // immediately after taking a picture will fail. Wait some
720 // time before starting the preview.
721 mHandler.sendEmptyMessageDelayed(SETUP_PREVIEW, 300);
722 }
723 }
724
Doris Liu36e56fb2013-09-11 17:38:08 -0700725 ExifInterface exif = Exif.getExif(jpegData);
726 int orientation = Exif.getOrientation(exif);
Michael Kolb8872c232013-01-29 10:33:22 -0800727 if (!mIsImageCaptureIntent) {
728 // Calculate the width and the height of the jpeg.
729 Size s = mParameters.getPictureSize();
Michael Kolb8872c232013-01-29 10:33:22 -0800730 int width, height;
731 if ((mJpegRotation + orientation) % 180 == 0) {
732 width = s.width;
733 height = s.height;
734 } else {
735 width = s.height;
736 height = s.width;
737 }
738 String title = mNamedImages.getTitle();
739 long date = mNamedImages.getDate();
740 if (title == null) {
741 Log.e(TAG, "Unbalanced name/data pair");
742 } else {
743 if (date == -1) date = mCaptureStartTime;
Angus Kong0d00a892013-03-26 11:40:40 -0700744 if (mHeading >= 0) {
745 // heading direction has been updated by the sensor.
746 ExifTag directionRefTag = exif.buildTag(
747 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
748 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
749 ExifTag directionTag = exif.buildTag(
750 ExifInterface.TAG_GPS_IMG_DIRECTION,
751 new Rational(mHeading, 1));
752 exif.setTag(directionRefTag);
753 exif.setTag(directionTag);
754 }
Angus Kong86d36312013-01-31 18:22:44 -0800755 mActivity.getMediaSaveService().addImage(
756 jpegData, title, date, mLocation, width, height,
Angus Kong0d00a892013-03-26 11:40:40 -0700757 orientation, exif, mOnMediaSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -0800758 }
Doris Liuce2acbc2013-08-21 18:45:29 -0700759 // Animate capture with real jpeg data instead of a preview frame.
Doris Liu29da2db2013-08-28 14:28:45 -0700760 mUI.animateCapture(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800761 } else {
762 mJpegImageData = jpegData;
763 if (!mQuickCapture) {
Doris Liu36e56fb2013-09-11 17:38:08 -0700764 mUI.showCapturedImageForReview(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800765 } else {
Michael Kolbd6954f32013-03-08 20:43:01 -0800766 onCaptureDone();
Michael Kolb8872c232013-01-29 10:33:22 -0800767 }
768 }
769
770 // Check this in advance of each shot so we don't add to shutter
771 // latency. It's true that someone else could write to the SD card in
772 // the mean time and fill it, but that could have happened between the
773 // shutter press and saving the JPEG too.
774 mActivity.updateStorageSpaceAndHint();
775
776 long now = System.currentTimeMillis();
777 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
778 Log.v(TAG, "mJpegCallbackFinishTime = "
779 + mJpegCallbackFinishTime + "ms");
780 mJpegPictureCallbackTime = 0;
781 }
782 }
783
Angus Kong9ef99252013-07-18 18:04:19 -0700784 private final class AutoFocusCallback implements CameraAFCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800785 @Override
786 public void onAutoFocus(
Angus Kong9ef99252013-07-18 18:04:19 -0700787 boolean focused, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800788 if (mPaused) return;
789
790 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
791 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
792 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800793 mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
Michael Kolb8872c232013-01-29 10:33:22 -0800794 }
795 }
796
797 @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
798 private final class AutoFocusMoveCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700799 implements CameraAFMoveCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800800 @Override
801 public void onAutoFocusMoving(
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700802 boolean moving, CameraProxy camera) {
803 mFocusManager.onAutoFocusMoving(moving);
Michael Kolb8872c232013-01-29 10:33:22 -0800804 }
805 }
806
807 private static class NamedImages {
808 private ArrayList<NamedEntity> mQueue;
Michael Kolb8872c232013-01-29 10:33:22 -0800809 private NamedEntity mNamedEntity;
810
811 public NamedImages() {
812 mQueue = new ArrayList<NamedEntity>();
813 }
814
815 public void nameNewImage(ContentResolver resolver, long date) {
816 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
822 public String getTitle() {
823 if (mQueue.isEmpty()) {
824 mNamedEntity = null;
825 return null;
826 }
827 mNamedEntity = mQueue.get(0);
828 mQueue.remove(0);
829
830 return mNamedEntity.title;
831 }
832
833 // Must be called after getTitle().
834 public long getDate() {
835 if (mNamedEntity == null) return -1;
836 return mNamedEntity.date;
837 }
838
839 private static class NamedEntity {
840 String title;
841 long date;
842 }
843 }
844
845 private void setCameraState(int state) {
846 mCameraState = state;
847 switch (state) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700848 case PhotoController.PREVIEW_STOPPED:
849 case PhotoController.SNAPSHOT_IN_PROGRESS:
850 case PhotoController.SWITCHING_CAMERA:
851 mUI.enableGestures(false);
852 break;
853 case PhotoController.IDLE:
854 mUI.enableGestures(true);
855 break;
Michael Kolb8872c232013-01-29 10:33:22 -0800856 }
857 }
858
Sascha Haeberling37f36112013-08-06 14:31:52 -0700859 private void animateAfterShutter() {
Michael Kolb8872c232013-01-29 10:33:22 -0800860 // Only animate when in full screen capture mode
861 // i.e. If monkey/a user swipes to the gallery during picture taking,
862 // don't show animation
Doris Liuc2e9abd2013-06-19 14:20:51 -0700863 if (!mIsImageCaptureIntent) {
864 mUI.animateFlash();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700865 }
Michael Kolb8872c232013-01-29 10:33:22 -0800866 }
867
868 @Override
869 public boolean capture() {
870 // If we are already in the middle of taking a snapshot or the image save request
871 // is full then ignore.
872 if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
Angus Kong86d36312013-01-31 18:22:44 -0800873 || mCameraState == SWITCHING_CAMERA
874 || mActivity.getMediaSaveService().isQueueFull()) {
Michael Kolb8872c232013-01-29 10:33:22 -0800875 return false;
876 }
877 mCaptureStartTime = System.currentTimeMillis();
878 mPostViewPictureCallbackTime = 0;
879 mJpegImageData = null;
880
Angus Kongb50b5cb2013-08-09 14:55:20 -0700881 final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
Michael Kolb8872c232013-01-29 10:33:22 -0800882
883 if (animateBefore) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700884 animateAfterShutter();
Michael Kolb8872c232013-01-29 10:33:22 -0800885 }
886
887 // Set rotation and gps data.
Doris Liu3cf565c2013-02-15 10:55:37 -0800888 int orientation;
889 // We need to be consistent with the framework orientation (i.e. the
890 // orientation of the UI.) when the auto-rotate screen setting is on.
891 if (mActivity.isAutoRotateScreen()) {
892 orientation = (360 - mDisplayRotation) % 360;
893 } else {
894 orientation = mOrientation;
895 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700896 mJpegRotation = CameraUtil.getJpegRotation(mCameraId, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800897 mParameters.setRotation(mJpegRotation);
898 Location loc = mLocationManager.getCurrentLocation();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700899 CameraUtil.setGpsParameters(mParameters, loc);
Michael Kolb8872c232013-01-29 10:33:22 -0800900 mCameraDevice.setParameters(mParameters);
901
Sascha Haeberling88901942013-08-28 17:49:00 -0700902 // We don't want user to press the button again while taking a
903 // multi-second HDR photo.
904 mUI.enableShutter(false);
Angus Kong9ef99252013-07-18 18:04:19 -0700905 mCameraDevice.takePicture(mHandler,
906 new ShutterCallback(!animateBefore),
Angus Kongdcb0ef12013-03-25 23:11:43 -0700907 mRawPictureCallback, mPostViewPictureCallback,
Angus Kong9ef99252013-07-18 18:04:19 -0700908 new JpegPictureCallback(loc));
Michael Kolb8872c232013-01-29 10:33:22 -0800909
910 mNamedImages.nameNewImage(mContentResolver, mCaptureStartTime);
911
912 mFaceDetectionStarted = false;
913 setCameraState(SNAPSHOT_IN_PROGRESS);
Bobby Georgescu301b6462013-04-01 15:33:17 -0700914 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
915 UsageStatistics.ACTION_CAPTURE_DONE, "Photo");
Michael Kolb8872c232013-01-29 10:33:22 -0800916 return true;
917 }
918
919 @Override
920 public void setFocusParameters() {
921 setCameraParameters(UPDATE_PARAM_PREFERENCE);
922 }
923
924 private int getPreferredCameraId(ComboPreferences preferences) {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700925 int intentCameraId = CameraUtil.getCameraFacingIntentExtras(mActivity);
Michael Kolb8872c232013-01-29 10:33:22 -0800926 if (intentCameraId != -1) {
927 // Testing purpose. Launch a specific camera through the intent
928 // extras.
929 return intentCameraId;
930 } else {
931 return CameraSettings.readPreferredCameraId(preferences);
932 }
933 }
934
Michael Kolbd6954f32013-03-08 20:43:01 -0800935 private void updateSceneMode() {
Michael Kolb8872c232013-01-29 10:33:22 -0800936 // If scene mode is set, we cannot set flash mode, white balance, and
937 // focus mode, instead, we read it from driver
938 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
939 overrideCameraSettings(mParameters.getFlashMode(),
940 mParameters.getWhiteBalance(), mParameters.getFocusMode());
941 } else {
942 overrideCameraSettings(null, null, null);
943 }
944 }
945
946 private void overrideCameraSettings(final String flashMode,
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700947 final String whiteBalance, final String focusMode) {
Michael Kolbd6954f32013-03-08 20:43:01 -0800948 mUI.overrideSettings(
949 CameraSettings.KEY_FLASH_MODE, flashMode,
950 CameraSettings.KEY_WHITE_BALANCE, whiteBalance,
951 CameraSettings.KEY_FOCUS_MODE, focusMode);
Michael Kolb8872c232013-01-29 10:33:22 -0800952 }
953
954 private void loadCameraPreferences() {
955 CameraSettings settings = new CameraSettings(mActivity, mInitialParams,
956 mCameraId, CameraHolder.instance().getCameraInfo());
957 mPreferenceGroup = settings.getPreferenceGroup(R.xml.camera_preferences);
958 }
959
960 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800961 public void onOrientationChanged(int orientation) {
962 // We keep the last known orientation. So if the user first orient
963 // the camera then point the camera to floor or sky, we still have
964 // the correct orientation.
965 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700966 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800967
968 // Show the toast after getting the first orientation changed.
969 if (mHandler.hasMessages(SHOW_TAP_TO_FOCUS_TOAST)) {
970 mHandler.removeMessages(SHOW_TAP_TO_FOCUS_TOAST);
971 showTapToFocusToast();
972 }
973 }
974
975 @Override
976 public void onStop() {
977 if (mMediaProviderClient != null) {
978 mMediaProviderClient.release();
979 mMediaProviderClient = null;
980 }
981 }
982
Michael Kolbd6954f32013-03-08 20:43:01 -0800983 @Override
984 public void onCaptureCancelled() {
985 mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
986 mActivity.finish();
Michael Kolb8872c232013-01-29 10:33:22 -0800987 }
988
Michael Kolbd6954f32013-03-08 20:43:01 -0800989 @Override
990 public void onCaptureRetake() {
Michael Kolb8872c232013-01-29 10:33:22 -0800991 if (mPaused)
992 return;
Michael Kolbd6954f32013-03-08 20:43:01 -0800993 mUI.hidePostCaptureAlert();
Michael Kolb8872c232013-01-29 10:33:22 -0800994 setupPreview();
995 }
996
Michael Kolbd6954f32013-03-08 20:43:01 -0800997 @Override
998 public void onCaptureDone() {
Michael Kolb8872c232013-01-29 10:33:22 -0800999 if (mPaused) {
1000 return;
1001 }
1002
1003 byte[] data = mJpegImageData;
1004
1005 if (mCropValue == null) {
1006 // First handle the no crop case -- just return the value. If the
1007 // caller specifies a "save uri" then write the data to its
1008 // stream. Otherwise, pass back a scaled down version of the bitmap
1009 // directly in the extras.
1010 if (mSaveUri != null) {
1011 OutputStream outputStream = null;
1012 try {
1013 outputStream = mContentResolver.openOutputStream(mSaveUri);
1014 outputStream.write(data);
1015 outputStream.close();
1016
1017 mActivity.setResultEx(Activity.RESULT_OK);
1018 mActivity.finish();
1019 } catch (IOException ex) {
1020 // ignore exception
1021 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001022 CameraUtil.closeSilently(outputStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001023 }
1024 } else {
Angus Kong0d00a892013-03-26 11:40:40 -07001025 ExifInterface exif = Exif.getExif(data);
1026 int orientation = Exif.getOrientation(exif);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001027 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
1028 bitmap = CameraUtil.rotate(bitmap, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001029 mActivity.setResultEx(Activity.RESULT_OK,
1030 new Intent("inline-data").putExtra("data", bitmap));
1031 mActivity.finish();
1032 }
1033 } else {
1034 // Save the image to a temp file and invoke the cropper
1035 Uri tempUri = null;
1036 FileOutputStream tempStream = null;
1037 try {
1038 File path = mActivity.getFileStreamPath(sTempCropFilename);
1039 path.delete();
1040 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1041 tempStream.write(data);
1042 tempStream.close();
1043 tempUri = Uri.fromFile(path);
1044 } catch (FileNotFoundException ex) {
1045 mActivity.setResultEx(Activity.RESULT_CANCELED);
1046 mActivity.finish();
1047 return;
1048 } catch (IOException ex) {
1049 mActivity.setResultEx(Activity.RESULT_CANCELED);
1050 mActivity.finish();
1051 return;
1052 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001053 CameraUtil.closeSilently(tempStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001054 }
1055
1056 Bundle newExtras = new Bundle();
1057 if (mCropValue.equals("circle")) {
1058 newExtras.putString("circleCrop", "true");
1059 }
1060 if (mSaveUri != null) {
1061 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1062 } else {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001063 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001064 }
1065 if (mActivity.isSecureCamera()) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001066 newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001067 }
1068
Sascha Haeberling37f36112013-08-06 14:31:52 -07001069 // TODO: Share this constant.
Sascha Haeberling8e963a52013-08-06 11:43:02 -07001070 final String CROP_ACTION = "com.android.camera.action.CROP";
1071 Intent cropIntent = new Intent(CROP_ACTION);
Michael Kolb8872c232013-01-29 10:33:22 -08001072
1073 cropIntent.setData(tempUri);
1074 cropIntent.putExtras(newExtras);
1075
1076 mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1077 }
1078 }
1079
Michael Kolb8872c232013-01-29 10:33:22 -08001080 @Override
1081 public void onShutterButtonFocus(boolean pressed) {
Michael Kolbd6954f32013-03-08 20:43:01 -08001082 if (mPaused || mUI.collapseCameraControls()
Michael Kolb8872c232013-01-29 10:33:22 -08001083 || (mCameraState == SNAPSHOT_IN_PROGRESS)
1084 || (mCameraState == PREVIEW_STOPPED)) return;
1085
1086 // Do not do focus if there is not enough storage.
1087 if (pressed && !canTakePicture()) return;
1088
1089 if (pressed) {
Michael Kolb8872c232013-01-29 10:33:22 -08001090 mFocusManager.onShutterDown();
1091 } else {
Doris Liuda50e052013-02-07 14:36:32 -08001092 // for countdown mode, we need to postpone the shutter release
1093 // i.e. lock the focus during countdown.
Michael Kolbd6954f32013-03-08 20:43:01 -08001094 if (!mUI.isCountingDown()) {
Doris Liuda50e052013-02-07 14:36:32 -08001095 mFocusManager.onShutterUp();
1096 }
Michael Kolb8872c232013-01-29 10:33:22 -08001097 }
1098 }
1099
1100 @Override
1101 public void onShutterButtonClick() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001102 if (mPaused || mUI.collapseCameraControls()
Michael Kolb8872c232013-01-29 10:33:22 -08001103 || (mCameraState == SWITCHING_CAMERA)
1104 || (mCameraState == PREVIEW_STOPPED)) return;
1105
1106 // Do not take the picture if there is not enough storage.
1107 if (mActivity.getStorageSpace() <= Storage.LOW_STORAGE_THRESHOLD) {
1108 Log.i(TAG, "Not enough space or storage not ready. remaining="
1109 + mActivity.getStorageSpace());
1110 return;
1111 }
1112 Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1113
Angus Kongb50b5cb2013-08-09 14:55:20 -07001114 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -07001115 mUI.hideSwitcher();
1116 mUI.setSwipingEnabled(false);
Doris Liu9cdfe002013-04-16 09:50:56 -07001117 }
Michael Kolb8872c232013-01-29 10:33:22 -08001118 // If the user wants to do a snapshot while the previous one is still
1119 // in progress, remember the fact and do it after we finish the previous
1120 // one and re-start the preview. Snapshot in progress also includes the
1121 // state that autofocus is focusing and a picture will be taken when
1122 // focus callback arrives.
1123 if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1124 && !mIsImageCaptureIntent) {
1125 mSnapshotOnIdle = true;
1126 return;
1127 }
1128
1129 String timer = mPreferences.getString(
1130 CameraSettings.KEY_TIMER,
1131 mActivity.getString(R.string.pref_camera_timer_default));
1132 boolean playSound = mPreferences.getString(CameraSettings.KEY_TIMER_SOUND_EFFECTS,
1133 mActivity.getString(R.string.pref_camera_timer_sound_default))
1134 .equals(mActivity.getString(R.string.setting_on_value));
1135
1136 int seconds = Integer.parseInt(timer);
1137 // When shutter button is pressed, check whether the previous countdown is
1138 // finished. If not, cancel the previous countdown and start a new one.
Michael Kolbd6954f32013-03-08 20:43:01 -08001139 if (mUI.isCountingDown()) {
1140 mUI.cancelCountDown();
1141 }
1142 if (seconds > 0) {
1143 mUI.startCountDown(seconds, playSound);
Michael Kolb8872c232013-01-29 10:33:22 -08001144 } else {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001145 mSnapshotOnIdle = false;
1146 mFocusManager.doSnap();
Michael Kolb8872c232013-01-29 10:33:22 -08001147 }
1148 }
1149
1150 @Override
1151 public void installIntentFilter() {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001152 // Install an intent filter to receive remote shutter events.
1153 IntentFilter intentFilter =
Dan Aminzadefca1c5e2013-08-14 17:36:56 -07001154 new IntentFilter(CameraUtil.ACTION_CAMERA_SHUTTER_CLICK);
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001155 mReceiver = new ShutterBroadcastReceiver();
1156 mActivity.registerReceiver(mReceiver, intentFilter);
Michael Kolb8872c232013-01-29 10:33:22 -08001157 }
1158
1159 @Override
1160 public boolean updateStorageHintOnResume() {
1161 return mFirstTimeInitialized;
1162 }
1163
1164 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001165 public void onResumeBeforeSuper() {
1166 mPaused = false;
1167 }
1168
Angus Kongdcccc512013-08-08 17:06:03 -07001169 private void prepareCamera() {
1170 try {
1171 // We need to check whether the activity is paused before long
1172 // operations to ensure that onPause() can be done ASAP.
1173 mCameraDevice = CameraUtil.openCamera(mActivity, mCameraId);
1174 mParameters = mCameraDevice.getParameters();
1175
1176 initializeCapabilities();
1177 if (mFocusManager == null) initializeFocusManager();
1178 setCameraParameters(UPDATE_PARAM_ALL);
1179 mHandler.sendEmptyMessage(CAMERA_OPEN_DONE);
1180 mCameraPreviewParamsReady = true;
1181 startPreview();
1182 mOnResumeTime = SystemClock.uptimeMillis();
1183 checkDisplayRotation();
1184 } catch (CameraHardwareException e) {
1185 mHandler.sendEmptyMessage(OPEN_CAMERA_FAIL);
1186 } catch (CameraDisabledException e) {
1187 mHandler.sendEmptyMessage(CAMERA_DISABLED);
1188 }
1189 }
1190
1191
Michael Kolb8872c232013-01-29 10:33:22 -08001192 @Override
1193 public void onResumeAfterSuper() {
1194 if (mOpenCameraFail || mCameraDisabled) return;
1195
1196 mJpegPictureCallbackTime = 0;
1197 mZoomValue = 0;
Angus Kongdcccc512013-08-08 17:06:03 -07001198 resetExposureCompensation();
1199 prepareCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001200
1201 // If first time initialization is not finished, put it in the
1202 // message queue.
1203 if (!mFirstTimeInitialized) {
1204 mHandler.sendEmptyMessage(FIRST_TIME_INIT);
1205 } else {
1206 initializeSecondTime();
1207 }
1208 keepScreenOnAwhile();
1209
1210 // Dismiss open menu if exists.
1211 PopupManager.getInstance(mActivity).notifyShowPopup(null);
Bobby Georgescu0a7dd572013-03-12 22:45:17 -07001212 UsageStatistics.onContentViewChanged(
1213 UsageStatistics.COMPONENT_CAMERA, "PhotoModule");
Angus Kong0d00a892013-03-26 11:40:40 -07001214
1215 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1216 if (gsensor != null) {
1217 mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1218 }
1219
1220 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1221 if (msensor != null) {
1222 mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1223 }
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001224
1225 installIntentFilter();
Dan Aminzadefca1c5e2013-08-14 17:36:56 -07001226 Intent intent = new Intent(CameraUtil.ACTION_CAMERA_STARTED);
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001227 mActivity.sendBroadcast(intent);
Michael Kolb8872c232013-01-29 10:33:22 -08001228 }
1229
Michael Kolb8872c232013-01-29 10:33:22 -08001230 @Override
1231 public void onPauseBeforeSuper() {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001232
Dan Aminzadefca1c5e2013-08-14 17:36:56 -07001233 Intent intent = new Intent(CameraUtil.ACTION_CAMERA_STOPPED);
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001234 mActivity.sendBroadcast(intent);
1235
1236 if (mReceiver != null) {
1237 mActivity.unregisterReceiver(mReceiver);
1238 mReceiver = null;
1239 }
1240
Michael Kolb8872c232013-01-29 10:33:22 -08001241 mPaused = true;
Angus Kong0d00a892013-03-26 11:40:40 -07001242 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1243 if (gsensor != null) {
1244 mSensorManager.unregisterListener(this, gsensor);
1245 }
1246
1247 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1248 if (msensor != null) {
1249 mSensorManager.unregisterListener(this, msensor);
1250 }
Michael Kolb8872c232013-01-29 10:33:22 -08001251 }
1252
1253 @Override
1254 public void onPauseAfterSuper() {
Michael Kolb8872c232013-01-29 10:33:22 -08001255 // When camera is started from secure lock screen for the first time
1256 // after screen on, the activity gets onCreate->onResume->onPause->onResume.
1257 // To reduce the latency, keep the camera for a short time so it does
1258 // not need to be opened again.
1259 if (mCameraDevice != null && mActivity.isSecureCamera()
Angus Kong6a8e8a12013-07-19 14:55:07 -07001260 && CameraActivity.isFirstStartAfterScreenOn()) {
1261 CameraActivity.resetFirstStartAfterScreenOn();
Michael Kolb8872c232013-01-29 10:33:22 -08001262 CameraHolder.instance().keep(KEEP_CAMERA_TIMEOUT);
1263 }
1264 // Reset the focus first. Camera CTS does not guarantee that
1265 // cancelAutoFocus is allowed after preview stops.
1266 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1267 mCameraDevice.cancelAutoFocus();
1268 }
1269 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001270
Angus Kongce5480e2013-01-29 17:43:48 -08001271 mNamedImages = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001272
1273 if (mLocationManager != null) mLocationManager.recordLocation(false);
1274
1275 // If we are in an image capture intent and has taken
1276 // a picture, we just clear it in onPause.
1277 mJpegImageData = null;
1278
Angus Kongdcccc512013-08-08 17:06:03 -07001279 // Remove the messages and runnables in the queue.
1280 mHandler.removeCallbacksAndMessages(null);
Michael Kolb8872c232013-01-29 10:33:22 -08001281
Michael Kolbd6954f32013-03-08 20:43:01 -08001282 closeCamera();
1283
1284 resetScreenOn();
1285 mUI.onPause();
1286
Michael Kolb8872c232013-01-29 10:33:22 -08001287 mPendingSwitchCameraId = -1;
1288 if (mFocusManager != null) mFocusManager.removeMessages();
Angus Kong86d36312013-01-31 18:22:44 -08001289 MediaSaveService s = mActivity.getMediaSaveService();
1290 if (s != null) {
1291 s.setListener(null);
1292 }
Michael Kolb8872c232013-01-29 10:33:22 -08001293 }
1294
Michael Kolb8872c232013-01-29 10:33:22 -08001295 /**
1296 * The focus manager is the first UI related element to get initialized,
1297 * and it requires the RenderOverlay, so initialize it here
1298 */
1299 private void initializeFocusManager() {
1300 // Create FocusManager object. startPreview needs it.
Michael Kolb8872c232013-01-29 10:33:22 -08001301 // if mFocusManager not null, reuse it
1302 // otherwise create a new instance
1303 if (mFocusManager != null) {
1304 mFocusManager.removeMessages();
1305 } else {
1306 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -07001307 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
Michael Kolb8872c232013-01-29 10:33:22 -08001308 String[] defaultFocusModes = mActivity.getResources().getStringArray(
1309 R.array.pref_camera_focusmode_default_array);
1310 mFocusManager = new FocusOverlayManager(mPreferences, defaultFocusModes,
Doris Liu29da2db2013-08-28 14:28:45 -07001311 mInitialParams, this, mMirror,
Michael Kolbd6954f32013-03-08 20:43:01 -08001312 mActivity.getMainLooper(), mUI);
Michael Kolb8872c232013-01-29 10:33:22 -08001313 }
1314 }
1315
Michael Kolb8872c232013-01-29 10:33:22 -08001316 @Override
1317 public void onConfigurationChanged(Configuration newConfig) {
1318 Log.v(TAG, "onConfigurationChanged");
1319 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001320 }
1321
1322 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001323 public void updateCameraOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001324 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001325 setDisplayOrientation();
1326 }
1327 }
1328
1329 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001330 public void onActivityResult(
1331 int requestCode, int resultCode, Intent data) {
1332 switch (requestCode) {
1333 case REQUEST_CROP: {
1334 Intent intent = new Intent();
1335 if (data != null) {
1336 Bundle extras = data.getExtras();
1337 if (extras != null) {
1338 intent.putExtras(extras);
1339 }
1340 }
1341 mActivity.setResultEx(resultCode, intent);
1342 mActivity.finish();
1343
1344 File path = mActivity.getFileStreamPath(sTempCropFilename);
1345 path.delete();
1346
1347 break;
1348 }
1349 }
1350 }
1351
1352 private boolean canTakePicture() {
1353 return isCameraIdle() && (mActivity.getStorageSpace() > Storage.LOW_STORAGE_THRESHOLD);
1354 }
1355
1356 @Override
1357 public void autoFocus() {
1358 mFocusStartTime = System.currentTimeMillis();
Angus Kong9ef99252013-07-18 18:04:19 -07001359 mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001360 setCameraState(FOCUSING);
1361 }
1362
1363 @Override
1364 public void cancelAutoFocus() {
1365 mCameraDevice.cancelAutoFocus();
1366 setCameraState(IDLE);
1367 setCameraParameters(UPDATE_PARAM_PREFERENCE);
1368 }
1369
1370 // Preview area is touched. Handle touch focus.
1371 @Override
1372 public void onSingleTapUp(View view, int x, int y) {
1373 if (mPaused || mCameraDevice == null || !mFirstTimeInitialized
1374 || mCameraState == SNAPSHOT_IN_PROGRESS
1375 || mCameraState == SWITCHING_CAMERA
1376 || mCameraState == PREVIEW_STOPPED) {
1377 return;
1378 }
1379
Michael Kolb8872c232013-01-29 10:33:22 -08001380 // Check if metering area or focus area is supported.
1381 if (!mFocusAreaSupported && !mMeteringAreaSupported) return;
1382 mFocusManager.onSingleTapUp(x, y);
1383 }
1384
1385 @Override
1386 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001387 return mUI.onBackPressed();
Michael Kolb8872c232013-01-29 10:33:22 -08001388 }
1389
1390 @Override
1391 public boolean onKeyDown(int keyCode, KeyEvent event) {
1392 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001393 case KeyEvent.KEYCODE_VOLUME_UP:
1394 case KeyEvent.KEYCODE_VOLUME_DOWN:
1395 case KeyEvent.KEYCODE_FOCUS:
1396 if (/*TODO: mActivity.isInCameraApp() &&*/ mFirstTimeInitialized) {
1397 if (event.getRepeatCount() == 0) {
1398 onShutterButtonFocus(true);
1399 }
1400 return true;
1401 }
1402 return false;
1403 case KeyEvent.KEYCODE_CAMERA:
1404 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1405 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001406 }
1407 return true;
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001408 case KeyEvent.KEYCODE_DPAD_CENTER:
1409 // If we get a dpad center event without any focused view, move
1410 // the focus to the shutter button and press it.
1411 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1412 // Start auto-focus immediately to reduce shutter lag. After
1413 // the shutter button gets the focus, onShutterButtonFocus()
1414 // will be called again but it is fine.
1415 onShutterButtonFocus(true);
1416 mUI.pressShutterButton();
1417 }
1418 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001419 }
1420 return false;
1421 }
1422
1423 @Override
1424 public boolean onKeyUp(int keyCode, KeyEvent event) {
1425 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001426 case KeyEvent.KEYCODE_VOLUME_UP:
1427 case KeyEvent.KEYCODE_VOLUME_DOWN:
1428 if (/*mActivity.isInCameraApp() && */ mFirstTimeInitialized) {
1429 onShutterButtonClick();
1430 return true;
1431 }
1432 return false;
1433 case KeyEvent.KEYCODE_FOCUS:
1434 if (mFirstTimeInitialized) {
1435 onShutterButtonFocus(false);
1436 }
Michael Kolb8872c232013-01-29 10:33:22 -08001437 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001438 }
1439 return false;
1440 }
1441
1442 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
1443 private void closeCamera() {
1444 if (mCameraDevice != null) {
1445 mCameraDevice.setZoomChangeListener(null);
1446 if(ApiHelper.HAS_FACE_DETECTION) {
Angus Kong9e765522013-07-31 14:05:20 -07001447 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001448 }
1449 mCameraDevice.setErrorCallback(null);
1450 CameraHolder.instance().release();
1451 mFaceDetectionStarted = false;
1452 mCameraDevice = null;
1453 setCameraState(PREVIEW_STOPPED);
1454 mFocusManager.onCameraReleased();
1455 }
1456 }
1457
1458 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001459 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1460 mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001461 mCameraDisplayOrientation = mDisplayOrientation;
Michael Kolbd6954f32013-03-08 20:43:01 -08001462 mUI.setDisplayOrientation(mDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001463 if (mFocusManager != null) {
1464 mFocusManager.setDisplayOrientation(mDisplayOrientation);
1465 }
Doris Liu6432cd62013-06-13 17:20:31 -07001466 // Change the camera display orientation
1467 if (mCameraDevice != null) {
1468 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1469 }
Michael Kolb8872c232013-01-29 10:33:22 -08001470 }
1471
Sascha Haeberlingddef7792013-08-13 14:41:10 -07001472 /** Only called by UI thread. */
Michael Kolb8872c232013-01-29 10:33:22 -08001473 private void setupPreview() {
1474 mFocusManager.resetTouchFocus();
1475 startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001476 }
1477
Angus Kongdcccc512013-08-08 17:06:03 -07001478 // This can only be called by UI Thread.
Michael Kolb8872c232013-01-29 10:33:22 -08001479 private void startPreview() {
Angus Kongdcccc512013-08-08 17:06:03 -07001480 if (mPaused) {
1481 return;
1482 }
1483 SurfaceTexture st = mUI.getSurfaceTexture();
1484 if (st == null) {
1485 Log.w(TAG, "startPreview: surfaceTexture is not ready.");
1486 return;
1487 }
1488 if (!mCameraPreviewParamsReady) {
1489 Log.w(TAG, "startPreview: parameters for preview is not ready.");
1490 return;
1491 }
Michael Kolb8872c232013-01-29 10:33:22 -08001492 mCameraDevice.setErrorCallback(mErrorCallback);
1493
1494 // ICS camera frameworks has a bug. Face detection state is not cleared
1495 // after taking a picture. Stop the preview to work around it. The bug
1496 // was fixed in JB.
1497 if (mCameraState != PREVIEW_STOPPED) stopPreview();
1498
1499 setDisplayOrientation();
1500
1501 if (!mSnapshotOnIdle) {
1502 // If the focus mode is continuous autofocus, call cancelAutoFocus to
1503 // resume it because it may have been paused by autoFocus call.
Angus Kongb50b5cb2013-08-09 14:55:20 -07001504 if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) {
Michael Kolb8872c232013-01-29 10:33:22 -08001505 mCameraDevice.cancelAutoFocus();
1506 }
1507 mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1508 }
1509 setCameraParameters(UPDATE_PARAM_ALL);
Doris Liu6432cd62013-06-13 17:20:31 -07001510 // Let UI set its expected aspect ratio
Angus Kongdcccc512013-08-08 17:06:03 -07001511 mCameraDevice.setPreviewTexture(st);
Michael Kolb8872c232013-01-29 10:33:22 -08001512
1513 Log.v(TAG, "startPreview");
Angus Kong9ef99252013-07-18 18:04:19 -07001514 mCameraDevice.startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001515 mFocusManager.onPreviewStarted();
Angus Kongdcccc512013-08-08 17:06:03 -07001516 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001517
1518 if (mSnapshotOnIdle) {
1519 mHandler.post(mDoSnapRunnable);
1520 }
1521 }
1522
Michael Kolbd6954f32013-03-08 20:43:01 -08001523 @Override
1524 public void stopPreview() {
Michael Kolb8872c232013-01-29 10:33:22 -08001525 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1526 Log.v(TAG, "stopPreview");
1527 mCameraDevice.stopPreview();
1528 mFaceDetectionStarted = false;
1529 }
1530 setCameraState(PREVIEW_STOPPED);
1531 if (mFocusManager != null) mFocusManager.onPreviewStopped();
1532 }
1533
1534 @SuppressWarnings("deprecation")
1535 private void updateCameraParametersInitialize() {
1536 // Reset preview frame rate to the maximum because it may be lowered by
1537 // video camera application.
Angus Kongb50b5cb2013-08-09 14:55:20 -07001538 int[] fpsRange = CameraUtil.getMaxPreviewFpsRange(mParameters);
Doris Liu6432cd62013-06-13 17:20:31 -07001539 if (fpsRange.length > 0) {
1540 mParameters.setPreviewFpsRange(
1541 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1542 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
Michael Kolb8872c232013-01-29 10:33:22 -08001543 }
1544
Angus Kongb50b5cb2013-08-09 14:55:20 -07001545 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);
Michael Kolb8872c232013-01-29 10:33:22 -08001546
1547 // Disable video stabilization. Convenience methods not available in API
1548 // level <= 14
1549 String vstabSupported = mParameters.get("video-stabilization-supported");
1550 if ("true".equals(vstabSupported)) {
1551 mParameters.set("video-stabilization", "false");
1552 }
1553 }
1554
1555 private void updateCameraParametersZoom() {
1556 // Set zoom.
1557 if (mParameters.isZoomSupported()) {
1558 mParameters.setZoom(mZoomValue);
1559 }
1560 }
1561
1562 @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
1563 private void setAutoExposureLockIfSupported() {
1564 if (mAeLockSupported) {
1565 mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1566 }
1567 }
1568
1569 @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
1570 private void setAutoWhiteBalanceLockIfSupported() {
1571 if (mAwbLockSupported) {
1572 mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1573 }
1574 }
1575
1576 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
1577 private void setFocusAreasIfSupported() {
1578 if (mFocusAreaSupported) {
1579 mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1580 }
1581 }
1582
1583 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
1584 private void setMeteringAreasIfSupported() {
1585 if (mMeteringAreaSupported) {
1586 // Use the same area for focus and metering.
1587 mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1588 }
1589 }
1590
1591 private void updateCameraParametersPreference() {
1592 setAutoExposureLockIfSupported();
1593 setAutoWhiteBalanceLockIfSupported();
1594 setFocusAreasIfSupported();
1595 setMeteringAreasIfSupported();
1596
1597 // Set picture size.
1598 String pictureSize = mPreferences.getString(
1599 CameraSettings.KEY_PICTURE_SIZE, null);
1600 if (pictureSize == null) {
1601 CameraSettings.initialCameraPictureSize(mActivity, mParameters);
1602 } else {
1603 List<Size> supported = mParameters.getSupportedPictureSizes();
1604 CameraSettings.setCameraPictureSize(
1605 pictureSize, supported, mParameters);
1606 }
1607 Size size = mParameters.getPictureSize();
1608
1609 // Set a preview size that is closest to the viewfinder height and has
1610 // the right aspect ratio.
1611 List<Size> sizes = mParameters.getSupportedPreviewSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001612 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
Michael Kolb8872c232013-01-29 10:33:22 -08001613 (double) size.width / size.height);
1614 Size original = mParameters.getPreviewSize();
1615 if (!original.equals(optimalSize)) {
1616 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
Doris Liu6432cd62013-06-13 17:20:31 -07001617
Michael Kolb8872c232013-01-29 10:33:22 -08001618 // Zoom related settings will be changed for different preview
1619 // sizes, so set and read the parameters to get latest values
Michael Kolb4a4d4ef2013-05-30 08:35:26 -07001620 if (mHandler.getLooper() == Looper.myLooper()) {
1621 // On UI thread only, not when camera starts up
1622 setupPreview();
1623 } else {
1624 mCameraDevice.setParameters(mParameters);
1625 }
Michael Kolb8872c232013-01-29 10:33:22 -08001626 mParameters = mCameraDevice.getParameters();
1627 }
1628 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
1629
1630 // Since changing scene mode may change supported values, set scene mode
1631 // first. HDR is a scene mode. To promote it in UI, it is stored in a
1632 // separate preference.
1633 String hdr = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR,
1634 mActivity.getString(R.string.pref_camera_hdr_default));
1635 if (mActivity.getString(R.string.setting_on_value).equals(hdr)) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001636 mSceneMode = CameraUtil.SCENE_MODE_HDR;
Michael Kolb8872c232013-01-29 10:33:22 -08001637 } else {
1638 mSceneMode = mPreferences.getString(
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001639 CameraSettings.KEY_SCENE_MODE,
1640 mActivity.getString(R.string.pref_camera_scenemode_default));
Michael Kolb8872c232013-01-29 10:33:22 -08001641 }
Angus Kongb50b5cb2013-08-09 14:55:20 -07001642 if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
Michael Kolb8872c232013-01-29 10:33:22 -08001643 if (!mParameters.getSceneMode().equals(mSceneMode)) {
1644 mParameters.setSceneMode(mSceneMode);
1645
1646 // Setting scene mode will change the settings of flash mode,
1647 // white balance, and focus mode. Here we read back the
1648 // parameters, so we can know those settings.
1649 mCameraDevice.setParameters(mParameters);
1650 mParameters = mCameraDevice.getParameters();
1651 }
1652 } else {
1653 mSceneMode = mParameters.getSceneMode();
1654 if (mSceneMode == null) {
1655 mSceneMode = Parameters.SCENE_MODE_AUTO;
1656 }
1657 }
1658
1659 // Set JPEG quality.
1660 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1661 CameraProfile.QUALITY_HIGH);
1662 mParameters.setJpegQuality(jpegQuality);
1663
1664 // For the following settings, we need to check if the settings are
1665 // still supported by latest driver, if not, ignore the settings.
1666
1667 // Set exposure compensation
1668 int value = CameraSettings.readExposure(mPreferences);
1669 int max = mParameters.getMaxExposureCompensation();
1670 int min = mParameters.getMinExposureCompensation();
1671 if (value >= min && value <= max) {
1672 mParameters.setExposureCompensation(value);
1673 } else {
1674 Log.w(TAG, "invalid exposure range: " + value);
1675 }
1676
1677 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1678 // Set flash mode.
1679 String flashMode = mPreferences.getString(
1680 CameraSettings.KEY_FLASH_MODE,
1681 mActivity.getString(R.string.pref_camera_flashmode_default));
1682 List<String> supportedFlash = mParameters.getSupportedFlashModes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001683 if (CameraUtil.isSupported(flashMode, supportedFlash)) {
Michael Kolb8872c232013-01-29 10:33:22 -08001684 mParameters.setFlashMode(flashMode);
1685 } else {
1686 flashMode = mParameters.getFlashMode();
1687 if (flashMode == null) {
1688 flashMode = mActivity.getString(
1689 R.string.pref_camera_flashmode_no_flash);
1690 }
1691 }
1692
1693 // Set white balance parameter.
1694 String whiteBalance = mPreferences.getString(
1695 CameraSettings.KEY_WHITE_BALANCE,
1696 mActivity.getString(R.string.pref_camera_whitebalance_default));
Angus Kongb50b5cb2013-08-09 14:55:20 -07001697 if (CameraUtil.isSupported(whiteBalance,
Michael Kolb8872c232013-01-29 10:33:22 -08001698 mParameters.getSupportedWhiteBalance())) {
1699 mParameters.setWhiteBalance(whiteBalance);
1700 } else {
1701 whiteBalance = mParameters.getWhiteBalance();
1702 if (whiteBalance == null) {
1703 whiteBalance = Parameters.WHITE_BALANCE_AUTO;
1704 }
1705 }
1706
1707 // Set focus mode.
1708 mFocusManager.overrideFocusMode(null);
1709 mParameters.setFocusMode(mFocusManager.getFocusMode());
1710 } else {
1711 mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1712 }
1713
Angus Kongdcccc512013-08-08 17:06:03 -07001714 if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
Michael Kolb8872c232013-01-29 10:33:22 -08001715 updateAutoFocusMoveCallback();
1716 }
1717 }
1718
1719 @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
1720 private void updateAutoFocusMoveCallback() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001721 if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Angus Kong9ef99252013-07-18 18:04:19 -07001722 mCameraDevice.setAutoFocusMoveCallback(mHandler,
1723 (CameraManager.CameraAFMoveCallback) mAutoFocusMoveCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001724 } else {
Angus Kong9ef99252013-07-18 18:04:19 -07001725 mCameraDevice.setAutoFocusMoveCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001726 }
1727 }
1728
1729 // We separate the parameters into several subsets, so we can update only
1730 // the subsets actually need updating. The PREFERENCE set needs extra
1731 // locking because the preference can be changed from GLThread as well.
1732 private void setCameraParameters(int updateSet) {
1733 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1734 updateCameraParametersInitialize();
1735 }
1736
1737 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1738 updateCameraParametersZoom();
1739 }
1740
1741 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
1742 updateCameraParametersPreference();
1743 }
1744
1745 mCameraDevice.setParameters(mParameters);
1746 }
1747
1748 // If the Camera is idle, update the parameters immediately, otherwise
1749 // accumulate them in mUpdateSet and update later.
1750 private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1751 mUpdateSet |= additionalUpdateSet;
1752 if (mCameraDevice == null) {
1753 // We will update all the parameters when we open the device, so
1754 // we don't need to do anything now.
1755 mUpdateSet = 0;
1756 return;
1757 } else if (isCameraIdle()) {
1758 setCameraParameters(mUpdateSet);
Michael Kolbd6954f32013-03-08 20:43:01 -08001759 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001760 mUpdateSet = 0;
1761 } else {
1762 if (!mHandler.hasMessages(SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1763 mHandler.sendEmptyMessageDelayed(
1764 SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
1765 }
1766 }
1767 }
1768
ztenghui7b265a62013-09-09 14:58:44 -07001769 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001770 public boolean isCameraIdle() {
Michael Kolb8872c232013-01-29 10:33:22 -08001771 return (mCameraState == IDLE) ||
1772 (mCameraState == PREVIEW_STOPPED) ||
1773 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
1774 && (mCameraState != SWITCHING_CAMERA));
1775 }
1776
ztenghui7b265a62013-09-09 14:58:44 -07001777 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001778 public boolean isImageCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001779 String action = mActivity.getIntent().getAction();
1780 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
Angus Kong6a8e8a12013-07-19 14:55:07 -07001781 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
Michael Kolb8872c232013-01-29 10:33:22 -08001782 }
1783
1784 private void setupCaptureParams() {
1785 Bundle myExtras = mActivity.getIntent().getExtras();
1786 if (myExtras != null) {
1787 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1788 mCropValue = myExtras.getString("crop");
1789 }
1790 }
1791
Michael Kolb8872c232013-01-29 10:33:22 -08001792 @Override
1793 public void onSharedPreferenceChanged() {
1794 // ignore the events after "onPause()"
1795 if (mPaused) return;
1796
1797 boolean recordLocation = RecordLocationPreference.get(
1798 mPreferences, mContentResolver);
1799 mLocationManager.recordLocation(recordLocation);
1800
1801 setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
Michael Kolbeb8adc12013-04-26 11:09:29 -07001802 mUI.updateOnScreenIndicators(mParameters, mPreferenceGroup, mPreferences);
Michael Kolb8872c232013-01-29 10:33:22 -08001803 }
1804
1805 @Override
1806 public void onCameraPickerClicked(int cameraId) {
1807 if (mPaused || mPendingSwitchCameraId != -1) return;
1808
1809 mPendingSwitchCameraId = cameraId;
Doris Liu6432cd62013-06-13 17:20:31 -07001810
1811 Log.v(TAG, "Start to switch camera. cameraId=" + cameraId);
1812 // We need to keep a preview frame for the animation before
1813 // releasing the camera. This will trigger onPreviewTextureCopied.
1814 //TODO: Need to animate the camera switch
1815 switchCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001816 }
1817
Michael Kolb8872c232013-01-29 10:33:22 -08001818 // Preview texture has been copied. Now camera can be released and the
1819 // animation can be started.
1820 @Override
1821 public void onPreviewTextureCopied() {
1822 mHandler.sendEmptyMessage(SWITCH_CAMERA);
1823 }
1824
1825 @Override
1826 public void onCaptureTextureCopied() {
1827 }
1828
1829 @Override
1830 public void onUserInteraction() {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001831 if (!mActivity.isFinishing()) keepScreenOnAwhile();
Michael Kolb8872c232013-01-29 10:33:22 -08001832 }
1833
1834 private void resetScreenOn() {
1835 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1836 mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1837 }
1838
1839 private void keepScreenOnAwhile() {
1840 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1841 mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1842 mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
1843 }
1844
Michael Kolb8872c232013-01-29 10:33:22 -08001845 @Override
1846 public void onOverriddenPreferencesClicked() {
1847 if (mPaused) return;
Michael Kolbd6954f32013-03-08 20:43:01 -08001848 mUI.showPreferencesToast();
Michael Kolb8872c232013-01-29 10:33:22 -08001849 }
1850
1851 private void showTapToFocusToast() {
1852 // TODO: Use a toast?
1853 new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
1854 // Clear the preference.
1855 Editor editor = mPreferences.edit();
1856 editor.putBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, false);
1857 editor.apply();
1858 }
1859
1860 private void initializeCapabilities() {
1861 mInitialParams = mCameraDevice.getParameters();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001862 mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
1863 mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
1864 mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
1865 mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
Angus Kongdcccc512013-08-08 17:06:03 -07001866 mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001867 CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
Michael Kolb8872c232013-01-29 10:33:22 -08001868 }
1869
Michael Kolb8872c232013-01-29 10:33:22 -08001870 @Override
1871 public void onCountDownFinished() {
1872 mSnapshotOnIdle = false;
1873 mFocusManager.doSnap();
Doris Liuda50e052013-02-07 14:36:32 -08001874 mFocusManager.onShutterUp();
Michael Kolb8872c232013-01-29 10:33:22 -08001875 }
1876
Michael Kolb8872c232013-01-29 10:33:22 -08001877 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001878 public void onShowSwitcherPopup() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001879 mUI.onShowSwitcherPopup();
Michael Kolb8872c232013-01-29 10:33:22 -08001880 }
1881
Angus Kongce5480e2013-01-29 17:43:48 -08001882 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001883 public int onZoomChanged(int index) {
1884 // Not useful to change zoom value when the activity is paused.
1885 if (mPaused) return index;
1886 mZoomValue = index;
1887 if (mParameters == null || mCameraDevice == null) return index;
1888 // Set zoom parameters asynchronously
1889 mParameters.setZoom(mZoomValue);
Angus Kong36ed8672013-04-15 12:11:15 -07001890 mCameraDevice.setParameters(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -08001891 Parameters p = mCameraDevice.getParameters();
1892 if (p != null) return p.getZoom();
1893 return index;
Angus Kongce5480e2013-01-29 17:43:48 -08001894 }
1895
1896 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001897 public int getCameraState() {
1898 return mCameraState;
1899 }
1900
1901 @Override
1902 public void onQueueStatus(boolean full) {
1903 mUI.enableShutter(!full);
Angus Kongce5480e2013-01-29 17:43:48 -08001904 }
Angus Kong86d36312013-01-31 18:22:44 -08001905
1906 @Override
1907 public void onMediaSaveServiceConnected(MediaSaveService s) {
1908 // We set the listener only when both service and shutterbutton
1909 // are initialized.
Michael Kolbd6954f32013-03-08 20:43:01 -08001910 if (mFirstTimeInitialized) {
1911 s.setListener(this);
1912 }
Angus Kong86d36312013-01-31 18:22:44 -08001913 }
Angus Kong0d00a892013-03-26 11:40:40 -07001914
1915 @Override
1916 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1917 }
1918
1919 @Override
1920 public void onSensorChanged(SensorEvent event) {
1921 int type = event.sensor.getType();
1922 float[] data;
1923 if (type == Sensor.TYPE_ACCELEROMETER) {
1924 data = mGData;
1925 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
1926 data = mMData;
1927 } else {
1928 // we should not be here.
1929 return;
1930 }
1931 for (int i = 0; i < 3 ; i++) {
1932 data[i] = event.values[i];
1933 }
1934 float[] orientation = new float[3];
1935 SensorManager.getRotationMatrix(mR, null, mGData, mMData);
1936 SensorManager.getOrientation(mR, orientation);
1937 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
1938 if (mHeading < 0) {
1939 mHeading += 360;
1940 }
Angus Kong0d00a892013-03-26 11:40:40 -07001941 }
Doris Liu6432cd62013-06-13 17:20:31 -07001942
1943 @Override
ztenghui7b265a62013-09-09 14:58:44 -07001944 public void onPreviewFocusChanged(boolean previewFocused) {
1945 mUI.onPreviewFocusChanged(previewFocused);
Doris Liu6432cd62013-06-13 17:20:31 -07001946 }
1947
1948/* Below is no longer needed, except to get rid of compile error
1949 * TODO: Remove these
1950 */
1951
1952 // TODO: Delete this function after old camera code is removed
1953 @Override
1954 public void onRestorePreferencesClicked() {}
1955
Michael Kolb8872c232013-01-29 10:33:22 -08001956}