blob: 31fde2a3ae838169ebdccfdab44faefd4b5306c0 [file] [log] [blame]
Michael Kolb8872c232013-01-29 10:33:22 -08001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera;
18
19import android.annotation.TargetApi;
20import android.app.Activity;
Michael Kolb8872c232013-01-29 10:33:22 -080021import android.content.ContentResolver;
Angus Kong0d00a892013-03-26 11:40:40 -070022import android.content.Context;
Michael Kolb8872c232013-01-29 10:33:22 -080023import android.content.Intent;
Michael Kolb8872c232013-01-29 10:33:22 -080024import android.graphics.Bitmap;
25import android.graphics.SurfaceTexture;
26import android.hardware.Camera.CameraInfo;
Michael Kolb8872c232013-01-29 10:33:22 -080027import android.hardware.Camera.Parameters;
Michael Kolb8872c232013-01-29 10:33:22 -080028import android.hardware.Camera.Size;
Angus Kong0d00a892013-03-26 11:40:40 -070029import android.hardware.Sensor;
30import android.hardware.SensorEvent;
31import android.hardware.SensorEventListener;
32import android.hardware.SensorManager;
Michael Kolb8872c232013-01-29 10:33:22 -080033import android.location.Location;
34import android.media.CameraProfile;
35import android.net.Uri;
Sascha Haeberling638e6f02013-09-18 14:28:51 -070036import android.os.Build;
Michael Kolb8872c232013-01-29 10:33:22 -080037import android.os.Bundle;
Michael Kolb8872c232013-01-29 10:33:22 -080038import android.os.Handler;
39import android.os.Looper;
40import android.os.Message;
41import android.os.MessageQueue;
42import android.os.SystemClock;
43import android.provider.MediaStore;
44import android.util.Log;
Michael Kolb8872c232013-01-29 10:33:22 -080045import android.view.KeyEvent;
Michael Kolb8872c232013-01-29 10:33:22 -080046import android.view.OrientationEventListener;
Michael Kolb8872c232013-01-29 10:33:22 -080047import android.view.View;
Sameer Padala2c8cc452013-11-05 18:49:12 -080048import com.android.camera.PhotoModule.NamedImages.NamedEntity;
49import com.android.camera.app.AppController;
Erin Dahlgrenb1641f52014-01-14 15:58:52 -080050import com.android.camera.app.CameraAppUI;
Angus Kong20fad242013-11-11 18:23:46 -080051import com.android.camera.app.CameraManager.CameraAFCallback;
52import com.android.camera.app.CameraManager.CameraAFMoveCallback;
53import com.android.camera.app.CameraManager.CameraPictureCallback;
54import com.android.camera.app.CameraManager.CameraProxy;
55import com.android.camera.app.CameraManager.CameraShutterCallback;
Kevin Gabayanffbc43c2013-12-09 11:41:50 -080056import com.android.camera.app.LocationManager;
Angus Kongfd4fc0e2013-11-07 15:38:09 -080057import com.android.camera.app.MediaSaver;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080058import com.android.camera.app.MemoryManager;
59import com.android.camera.app.MemoryManager.MemoryListener;
ztenghuia16e7b52013-08-23 11:47:56 -070060import com.android.camera.exif.ExifInterface;
61import com.android.camera.exif.ExifTag;
62import com.android.camera.exif.Rational;
Erin Dahlgrenb1641f52014-01-14 15:58:52 -080063import com.android.camera.hardware.HardwareSpec;
64import com.android.camera.hardware.HardwareSpecImpl;
Angus Kong20fad242013-11-11 18:23:46 -080065import com.android.camera.module.ModuleController;
Erin Dahlgren357b7672013-11-20 17:38:14 -080066import com.android.camera.settings.SettingsManager;
Sascha Haeberling3b0ab892014-01-29 20:54:39 +010067import com.android.camera.settings.SettingsUtil;
Michael Kolb8872c232013-01-29 10:33:22 -080068import com.android.camera.ui.RotateTextToast;
Angus Kongdcccc512013-08-08 17:06:03 -070069import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -070070import com.android.camera.util.CameraUtil;
Ruben Brunk4601f5d2013-09-24 18:35:22 -070071import com.android.camera.util.GcamHelper;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070072import com.android.camera.util.UsageStatistics;
73import com.android.camera2.R;
Seth Raphael5e09d012013-12-18 13:45:03 -080074import com.google.common.logging.eventprotos;
Michael Kolb8872c232013-01-29 10:33:22 -080075
Angus Kongdcccc512013-08-08 17:06:03 -070076import java.io.File;
77import java.io.FileNotFoundException;
78import java.io.FileOutputStream;
79import java.io.IOException;
80import java.io.OutputStream;
Sascha Haeberling846d3ab2014-02-04 12:48:55 +010081import java.lang.ref.WeakReference;
Angus Kongdcccc512013-08-08 17:06:03 -070082import java.util.List;
Ruben Brunka9d66bd2013-09-06 11:56:32 -070083import java.util.Vector;
Angus Kongdcccc512013-08-08 17:06:03 -070084
Michael Kolb8872c232013-01-29 10:33:22 -080085public class PhotoModule
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080086 extends CameraModule
87 implements PhotoController,
88 ModuleController,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080089 MemoryListener,
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080090 FocusOverlayManager.Listener,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080091 ShutterButton.OnShutterButtonListener,
Erin Dahlgren7f0151d2014-01-02 16:08:12 -080092 SensorEventListener,
93 SettingsManager.OnSettingChangedListener {
Michael Kolb8872c232013-01-29 10:33:22 -080094
Sascha Haeberling58501152014-01-06 11:02:35 -080095 private static final String TAG = "PhotoModule";
Michael Kolb8872c232013-01-29 10:33:22 -080096
97 // We number the request code from 1000 to avoid collision with Gallery.
98 private static final int REQUEST_CROP = 1000;
99
Angus Kong13e87c42013-11-25 10:02:47 -0800100 // Messages defined for the UI thread handler.
Angus Kong1587b042014-01-02 18:09:27 -0800101 private static final int MSG_FIRST_TIME_INIT = 1;
102 private static final int MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE = 2;
103 private static final int MSG_SHOW_TAP_TO_FOCUS_TOAST = 3;
104 private static final int MSG_SWITCH_TO_GCAM_MODULE = 4;
Michael Kolb8872c232013-01-29 10:33:22 -0800105
106 // The subset of parameters we need to update in setCameraParameters().
107 private static final int UPDATE_PARAM_INITIALIZE = 1;
108 private static final int UPDATE_PARAM_ZOOM = 2;
109 private static final int UPDATE_PARAM_PREFERENCE = 4;
110 private static final int UPDATE_PARAM_ALL = -1;
111
Andy Huibersdef975d2013-11-22 09:13:39 -0800112 // This is the delay before we execute onResume tasks when coming
113 // from the lock screen, to allow time for onPause to execute.
114 private static final int ON_RESUME_TASKS_DELAY_MSEC = 20;
Michael Kolb8872c232013-01-29 10:33:22 -0800115
Ruben Brunkd7488272013-10-10 18:45:53 -0700116 private static final String DEBUG_IMAGE_PREFIX = "DEBUG_";
117
Michael Kolb8872c232013-01-29 10:33:22 -0800118 private CameraActivity mActivity;
Michael Kolb8872c232013-01-29 10:33:22 -0800119 private CameraProxy mCameraDevice;
120 private int mCameraId;
121 private Parameters mParameters;
122 private boolean mPaused;
Michael Kolbd6954f32013-03-08 20:43:01 -0800123
124 private PhotoUI mUI;
Michael Kolb8872c232013-01-29 10:33:22 -0800125
Michael Kolb8872c232013-01-29 10:33:22 -0800126 // The activity is going to switch to the specified camera id. This is
127 // needed because texture copy is done in GL thread. -1 means camera is not
128 // switching.
129 protected int mPendingSwitchCameraId = -1;
Michael Kolb8872c232013-01-29 10:33:22 -0800130
131 // When setCameraParametersWhenIdle() is called, we accumulate the subsets
132 // needed to be updated in mUpdateSet.
133 private int mUpdateSet;
134
135 private static final int SCREEN_DELAY = 2 * 60 * 1000;
136
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800137 private int mZoomValue; // The current zoom value.
Michael Kolb8872c232013-01-29 10:33:22 -0800138
139 private Parameters mInitialParams;
140 private boolean mFocusAreaSupported;
141 private boolean mMeteringAreaSupported;
142 private boolean mAeLockSupported;
143 private boolean mAwbLockSupported;
Angus Kongdcccc512013-08-08 17:06:03 -0700144 private boolean mContinuousFocusSupported;
Michael Kolb8872c232013-01-29 10:33:22 -0800145
146 // The degrees of the device rotated clockwise from its natural orientation.
147 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
Michael Kolb8872c232013-01-29 10:33:22 -0800148
149 private static final String sTempCropFilename = "crop-temp";
150
Michael Kolb8872c232013-01-29 10:33:22 -0800151 private boolean mFaceDetectionStarted = false;
152
Michael Kolb8872c232013-01-29 10:33:22 -0800153 // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
154 private String mCropValue;
155 private Uri mSaveUri;
156
Ruben Brunkd217ed02013-10-08 23:31:13 -0700157 private Uri mDebugUri;
158
Angus Kongce5480e2013-01-29 17:43:48 -0800159 // We use a queue to generated names of the images to be used later
160 // when the image is ready to be saved.
Michael Kolb8872c232013-01-29 10:33:22 -0800161 private NamedImages mNamedImages;
162
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800163 private final Runnable mDoSnapRunnable = new Runnable() {
Michael Kolb8872c232013-01-29 10:33:22 -0800164 @Override
165 public void run() {
166 onShutterButtonClick();
167 }
168 };
169
Michael Kolb8872c232013-01-29 10:33:22 -0800170 /**
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800171 * An unpublished intent flag requesting to return as soon as capturing is
172 * completed. TODO: consider publishing by moving into MediaStore.
Michael Kolb8872c232013-01-29 10:33:22 -0800173 */
174 private static final String EXTRA_QUICK_CAPTURE =
175 "android.intent.extra.quickCapture";
176
177 // The display rotation in degrees. This is only valid when mCameraState is
178 // not PREVIEW_STOPPED.
179 private int mDisplayRotation;
180 // The value for android.hardware.Camera.setDisplayOrientation.
181 private int mCameraDisplayOrientation;
182 // The value for UI components like indicators.
183 private int mDisplayOrientation;
184 // The value for android.hardware.Camera.Parameters.setRotation.
185 private int mJpegRotation;
Doris Liu29da2db2013-08-28 14:28:45 -0700186 // Indicates whether we are using front camera
187 private boolean mMirror;
Michael Kolb8872c232013-01-29 10:33:22 -0800188 private boolean mFirstTimeInitialized;
189 private boolean mIsImageCaptureIntent;
190
Michael Kolb8872c232013-01-29 10:33:22 -0800191 private int mCameraState = PREVIEW_STOPPED;
192 private boolean mSnapshotOnIdle = false;
193
194 private ContentResolver mContentResolver;
195
196 private LocationManager mLocationManager;
Doris Liu2b906b82013-12-10 16:34:08 -0800197 private AppController mAppController;
Michael Kolb8872c232013-01-29 10:33:22 -0800198
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
Doris Liubd1b8f92014-01-03 17:59:51 -0800231 private final int mGcamModeIndex;
Doris Liubd1b8f92014-01-03 17:59:51 -0800232
Michael Kolb8872c232013-01-29 10:33:22 -0800233 private String mSceneMode;
Michael Kolb8872c232013-01-29 10:33:22 -0800234
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100235 private final Handler mHandler = new MainHandler(this);
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800236
Michael Kolb8872c232013-01-29 10:33:22 -0800237 private boolean mQuickCapture;
Angus Kong0d00a892013-03-26 11:40:40 -0700238 private SensorManager mSensorManager;
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800239 private final float[] mGData = new float[3];
240 private final float[] mMData = new float[3];
241 private final float[] mR = new float[16];
Angus Kong0d00a892013-03-26 11:40:40 -0700242 private int mHeading = -1;
243
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800244 /** Whether shutter is enabled. */
Spike Sprague215f6b02013-12-12 11:53:49 -0800245 private boolean mShutterEnabled = true;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800246
247 /** True if all the parameters needed to start preview is ready. */
Angus Kongdcccc512013-08-08 17:06:03 -0700248 private boolean mCameraPreviewParamsReady = false;
Doris Liu6432cd62013-06-13 17:20:31 -0700249
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800250 private final MediaSaver.OnMediaSavedListener mOnMediaSavedListener =
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800251 new MediaSaver.OnMediaSavedListener() {
Angus Kongce5480e2013-01-29 17:43:48 -0800252 @Override
253 public void onMediaSaved(Uri uri) {
254 if (uri != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700255 mActivity.notifyNewMedia(uri);
Angus Kongce5480e2013-01-29 17:43:48 -0800256 }
257 }
258 };
Michael Kolb8872c232013-01-29 10:33:22 -0800259
Angus Kongdcccc512013-08-08 17:06:03 -0700260 private void checkDisplayRotation() {
261 // Set the display orientation if display rotation has changed.
262 // Sometimes this happens when the device is held upside
263 // down and camera app is opened. Rotation animation will
264 // take some time and the rotation value we have got may be
265 // wrong. Framework does not have a callback for this now.
266 if (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) {
267 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -0800268 }
Angus Kongdcccc512013-08-08 17:06:03 -0700269 if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
270 mHandler.postDelayed(new Runnable() {
271 @Override
272 public void run() {
273 checkDisplayRotation();
274 }
275 }, 100);
Michael Kolb8872c232013-01-29 10:33:22 -0800276 }
277 }
278
279 /**
280 * This Handler is used to post message back onto the main thread of the
281 * application
282 */
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100283 private static class MainHandler extends Handler {
284 private final WeakReference<PhotoModule> mModule;
285
286 public MainHandler(PhotoModule module) {
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800287 super(Looper.getMainLooper());
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100288 mModule = new WeakReference<PhotoModule>(module);
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800289 }
290
Michael Kolb8872c232013-01-29 10:33:22 -0800291 @Override
292 public void handleMessage(Message msg) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100293 PhotoModule module = mModule.get();
294 if (module == null) {
295 return;
296 }
Michael Kolb8872c232013-01-29 10:33:22 -0800297 switch (msg.what) {
Angus Kong13e87c42013-11-25 10:02:47 -0800298 case MSG_FIRST_TIME_INIT: {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100299 module.initializeFirstTime();
Michael Kolb8872c232013-01-29 10:33:22 -0800300 break;
301 }
302
Angus Kong13e87c42013-11-25 10:02:47 -0800303 case MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE: {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100304 module.setCameraParametersWhenIdle(0);
Michael Kolb8872c232013-01-29 10:33:22 -0800305 break;
306 }
307
Angus Kong13e87c42013-11-25 10:02:47 -0800308 case MSG_SHOW_TAP_TO_FOCUS_TOAST: {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100309 module.showTapToFocusToast();
Michael Kolb8872c232013-01-29 10:33:22 -0800310 break;
311 }
312
Angus Kong13e87c42013-11-25 10:02:47 -0800313 case MSG_SWITCH_TO_GCAM_MODULE: {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100314 module.mActivity.onModeSelected(module.mGcamModeIndex);
ztenghui367c7c82013-10-16 14:43:26 -0700315 }
Michael Kolb8872c232013-01-29 10:33:22 -0800316 }
317 }
318 }
319
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800320 /**
321 * Constructs a new photo module.
322 */
Angus Kongc4e66562013-11-22 23:03:21 -0800323 public PhotoModule(AppController app) {
324 super(app);
Doris Liubd1b8f92014-01-03 17:59:51 -0800325 mGcamModeIndex = app.getAndroidContext().getResources()
326 .getInteger(R.integer.camera_mode_gcam);
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800327 }
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700328
Michael Kolb8872c232013-01-29 10:33:22 -0800329 @Override
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100330 public void init(CameraActivity activity, boolean isSecureCamera, boolean isCaptureIntent) {
331 mActivity = activity;
332 // TODO: Need to look at the controller interface to see if we can get
333 // rid of passing in the activity directly.
334 mAppController = mActivity;
335
336 mUI = new PhotoUI(mActivity, this, mActivity.getModuleLayoutRoot());
337 mActivity.setPreviewStatusListener(mUI);
338 mActivity.getCameraAppUI().setBottomBarShutterListener(this);
Erin Dahlgren357b7672013-11-20 17:38:14 -0800339
340 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800341 mCameraId = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_CAMERA_ID));
Michael Kolb8872c232013-01-29 10:33:22 -0800342
343 mContentResolver = mActivity.getContentResolver();
344
Michael Kolb8872c232013-01-29 10:33:22 -0800345 // Surface texture is from camera screen nail and startPreview needs it.
346 // This must be done before startPreview.
347 mIsImageCaptureIntent = isImageCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800348
Angus Kong20fad242013-11-11 18:23:46 -0800349 mActivity.getCameraProvider().requestCamera(mCameraId);
350
Michael Kolb8872c232013-01-29 10:33:22 -0800351 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800352 mLocationManager = mActivity.getLocationManager();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800353 mSensorManager = (SensorManager) (mActivity.getSystemService(Context.SENSOR_SERVICE));
Michael Kolbd6954f32013-03-08 20:43:01 -0800354 }
355
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800356 @Override
357 public boolean isUsingBottomBar() {
358 return true;
359 }
360
Michael Kolbd6954f32013-03-08 20:43:01 -0800361 private void initializeControlByIntent() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800362 if (mIsImageCaptureIntent) {
Spike Sprague15690d02014-02-10 12:11:20 -0800363 mActivity.getCameraAppUI().transitionToIntentCaptureLayout();
Michael Kolbd6954f32013-03-08 20:43:01 -0800364 setupCaptureParams();
365 }
366 }
367
368 private void onPreviewStarted() {
Doris Liu2b906b82013-12-10 16:34:08 -0800369 mAppController.onPreviewStarted();
Michael Kolbd6954f32013-03-08 20:43:01 -0800370 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800371 startFaceDetection();
372 locationFirstRun();
Michael Kolb8872c232013-01-29 10:33:22 -0800373 }
374
Sascha Haeberlinga7cbfc02014-02-14 11:06:03 +0100375 @Override
Seth Raphael30836422014-02-06 14:49:47 -0800376 public void onPreviewInitialDataReceived() {
Seth Raphael30836422014-02-06 14:49:47 -0800377 }
378
Michael Kolb8872c232013-01-29 10:33:22 -0800379 // Prompt the user to pick to record location for the very first run of
380 // camera only
381 private void locationFirstRun() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800382 SettingsManager settingsManager = mActivity.getSettingsManager();
Sascha Haeberlingde303232014-02-07 02:30:53 +0100383
Erin Dahlgren4569b702014-02-24 14:21:11 -0800384 if (settingsManager.isSet(SettingsManager.SETTING_RECORD_LOCATION)) {
385 return;
Michael Kolb8872c232013-01-29 10:33:22 -0800386 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800387 if (mActivity.isSecureCamera()) {
388 return;
389 }
Michael Kolb8872c232013-01-29 10:33:22 -0800390 // Check if the back camera exists
Angus Kongd74e6a12014-01-07 11:29:44 -0800391 int backCameraId = mAppController.getCameraProvider().getFirstBackCameraId();
Michael Kolb8872c232013-01-29 10:33:22 -0800392 if (backCameraId == -1) {
393 // If there is no back camera, do not show the prompt.
394 return;
395 }
Doris Liu6a83d522013-07-02 12:03:32 -0700396 mUI.showLocationDialog();
397 }
Michael Kolb8872c232013-01-29 10:33:22 -0800398
ztenghui7b265a62013-09-09 14:58:44 -0700399 @Override
Angus Kongdcccc512013-08-08 17:06:03 -0700400 public void onPreviewUIReady() {
Erin Dahlgrendc282e12013-11-12 09:39:08 -0800401 startPreview();
Angus Kongdcccc512013-08-08 17:06:03 -0700402 }
403
404 @Override
405 public void onPreviewUIDestroyed() {
406 if (mCameraDevice == null) {
407 return;
408 }
409 mCameraDevice.setPreviewTexture(null);
410 stopPreview();
411 }
412
Doris Liu1dfe7822013-12-12 00:02:08 -0800413 @Override
414 public void startPreCaptureAnimation() {
415 mAppController.startPreCaptureAnimation();
416 }
417
Michael Kolbd6954f32013-03-08 20:43:01 -0800418 private void onCameraOpened() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800419 openCameraCommon();
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800420 initializeControlByIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800421 }
422
Michael Kolbd6954f32013-03-08 20:43:01 -0800423 private void switchCamera() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800424 if (mPaused) {
425 return;
426 }
Erin Dahlgren357b7672013-11-20 17:38:14 -0800427 SettingsManager settingsManager = mActivity.getSettingsManager();
Michael Kolbd6954f32013-03-08 20:43:01 -0800428
429 Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
Angus Kongd4109bc2014-01-08 18:38:03 -0800430 closeCamera();
Michael Kolbd6954f32013-03-08 20:43:01 -0800431 mCameraId = mPendingSwitchCameraId;
432 mPendingSwitchCameraId = -1;
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800433 settingsManager.set(SettingsManager.SETTING_CAMERA_ID, "" + mCameraId);
Angus Kong20fad242013-11-11 18:23:46 -0800434 mActivity.getCameraProvider().requestCamera(mCameraId);
Michael Kolbd6954f32013-03-08 20:43:01 -0800435 mUI.clearFaces();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800436 if (mFocusManager != null) {
437 mFocusManager.removeMessages();
438 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800439
Erin Dahlgren357b7672013-11-20 17:38:14 -0800440 // TODO: this needs to be brought into onCameraAvailable();
Angus Kong20fad242013-11-11 18:23:46 -0800441 CameraInfo info = mActivity.getCameraProvider().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -0700442 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
443 mFocusManager.setMirror(mMirror);
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700444 // Start switch camera animation. Post a message because
445 // onFrameAvailable from the old camera may already exist.
Doris Liu48239f42013-03-04 22:19:10 -0800446 }
447
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800448 private final ButtonManager.ButtonCallback mCameraCallback =
Sascha Haeberlingde303232014-02-07 02:30:53 +0100449 new ButtonManager.ButtonCallback() {
450 @Override
451 public void onStateChanged(int state) {
452 if (mPaused || mPendingSwitchCameraId != -1) {
453 return;
454 }
455 mPendingSwitchCameraId = state;
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800456
Sascha Haeberlingde303232014-02-07 02:30:53 +0100457 Log.v(TAG, "Start to switch camera. cameraId=" + state);
458 // We need to keep a preview frame for the animation before
459 // releasing the camera. This will trigger
460 // onPreviewTextureCopied.
461 // TODO: Need to animate the camera switch
462 switchCamera();
463 }
464 };
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800465
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800466 private final ButtonManager.ButtonCallback mHdrPlusCallback =
Sascha Haeberlingde303232014-02-07 02:30:53 +0100467 new ButtonManager.ButtonCallback() {
468 @Override
469 public void onStateChanged(int state) {
470 if (GcamHelper.hasGcamCapture()) {
471 // Set the camera setting to default backfacing.
472 SettingsManager settingsManager = mActivity.getSettingsManager();
473 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_ID);
474 mHandler.sendEmptyMessage(MSG_SWITCH_TO_GCAM_MODULE);
475 } else {
476 mSceneMode = CameraUtil.SCENE_MODE_HDR;
477 updateParametersSceneMode();
478 }
Erin Dahlgrenba6994d2013-12-12 16:04:38 -0800479 }
Sascha Haeberlingde303232014-02-07 02:30:53 +0100480 };
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800481
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800482 private final View.OnClickListener mCancelCallback = new View.OnClickListener() {
483 @Override
484 public void onClick(View v) {
485 onCaptureCancelled();
486 }
487 };
488
489 private final View.OnClickListener mDoneCallback = new View.OnClickListener() {
490 @Override
491 public void onClick(View v) {
492 onCaptureDone();
493 }
494 };
495
496 private final View.OnClickListener mRetakeCallback = new View.OnClickListener() {
497 @Override
498 public void onClick(View v) {
Spike Sprague15690d02014-02-10 12:11:20 -0800499 mActivity.getCameraAppUI().transitionToIntentCaptureLayout();
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800500 onCaptureRetake();
501 }
502 };
503
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800504 @Override
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800505 public HardwareSpec getHardwareSpec() {
Erin Dahlgren49ab9222014-01-28 17:40:28 -0800506 return (mParameters != null ? new HardwareSpecImpl(mParameters) : null);
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800507 }
508
509 @Override
510 public CameraAppUI.BottomBarUISpec getBottomBarSpec() {
511 CameraAppUI.BottomBarUISpec bottomBarSpec = new CameraAppUI.BottomBarUISpec();
512
513 bottomBarSpec.enableCamera = true;
514 bottomBarSpec.cameraCallback = mCameraCallback;
515 bottomBarSpec.enableFlash = true;
Erin Dahlgrena6587a12014-02-03 13:24:55 -0800516 bottomBarSpec.enableHdr = true;
517 bottomBarSpec.hdrCallback = mHdrPlusCallback;
Erin Dahlgrend5e51462014-02-07 12:38:57 -0800518 bottomBarSpec.enableGridLines = true;
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800519
520 if (isImageCaptureIntent()) {
521 bottomBarSpec.showCancel = true;
522 bottomBarSpec.cancelCallback = mCancelCallback;
523 bottomBarSpec.showDone = true;
524 bottomBarSpec.doneCallback = mDoneCallback;
525 bottomBarSpec.showRetake = true;
526 bottomBarSpec.retakeCallback = mRetakeCallback;
527 }
528
529 return bottomBarSpec;
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800530 }
531
Michael Kolbd6954f32013-03-08 20:43:01 -0800532 // either open a new camera or switch cameras
533 private void openCameraCommon() {
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800534 mUI.onCameraOpened(mParameters);
Angus Kong0fb819b2013-10-08 13:44:19 -0700535 if (mIsImageCaptureIntent) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800536 // Set hdr plus to default: off.
537 SettingsManager settingsManager = mActivity.getSettingsManager();
538 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_HDR_PLUS);
Angus Kong0fb819b2013-10-08 13:44:19 -0700539 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800540 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -0800541 }
542
ztenghui7b265a62013-09-09 14:58:44 -0700543 @Override
Doris Liu70da9182013-12-17 18:41:15 -0800544 public void updatePreviewAspectRatio(float aspectRatio) {
545 mAppController.updatePreviewAspectRatio(aspectRatio);
546 }
547
Michael Kolb8872c232013-01-29 10:33:22 -0800548 private void resetExposureCompensation() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800549 SettingsManager settingsManager = mActivity.getSettingsManager();
550 if (settingsManager == null) {
551 Log.e(TAG, "Settings manager is null!");
552 return;
Michael Kolb8872c232013-01-29 10:33:22 -0800553 }
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800554 settingsManager.setDefault(SettingsManager.SETTING_EXPOSURE);
Michael Kolb8872c232013-01-29 10:33:22 -0800555 }
556
Michael Kolb8872c232013-01-29 10:33:22 -0800557 // Snapshots can only be taken after this is called. It should be called
558 // once only. We could have done these things in onCreate() but we want to
559 // make preview screen appear as soon as possible.
560 private void initializeFirstTime() {
Sascha Haeberling330dafb2013-10-10 19:00:41 -0700561 if (mFirstTimeInitialized || mPaused) {
562 return;
563 }
Michael Kolb8872c232013-01-29 10:33:22 -0800564
565 // Initialize location service.
Sascha Haeberlingde303232014-02-07 02:30:53 +0100566 mActivity.syncLocationManagerSetting();
Michael Kolb8872c232013-01-29 10:33:22 -0800567
Michael Kolbd6954f32013-03-08 20:43:01 -0800568 mUI.initializeFirstTime();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800569
Angus Kong86d36312013-01-31 18:22:44 -0800570 // We set the listener only when both service and shutterbutton
571 // are initialized.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800572 getServices().getMemoryManager().addListener(this);
Michael Kolb8872c232013-01-29 10:33:22 -0800573
Michael Kolb8872c232013-01-29 10:33:22 -0800574 mNamedImages = new NamedImages();
575
576 mFirstTimeInitialized = true;
577 addIdleHandler();
578
579 mActivity.updateStorageSpaceAndHint();
580 }
581
Michael Kolbd6954f32013-03-08 20:43:01 -0800582 // If the activity is paused and resumed, this method will be called in
583 // onResume.
584 private void initializeSecondTime() {
585 // Start location update if needed.
Sascha Haeberlingde303232014-02-07 02:30:53 +0100586 mActivity.syncLocationManagerSetting();
Erin Dahlgren357b7672013-11-20 17:38:14 -0800587
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800588 getServices().getMemoryManager().addListener(this);
Michael Kolbd6954f32013-03-08 20:43:01 -0800589 mNamedImages = new NamedImages();
590 mUI.initializeSecondTime(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -0800591 }
592
Michael Kolb8872c232013-01-29 10:33:22 -0800593 private void addIdleHandler() {
594 MessageQueue queue = Looper.myQueue();
595 queue.addIdleHandler(new MessageQueue.IdleHandler() {
596 @Override
597 public boolean queueIdle() {
598 Storage.ensureOSXCompatible();
599 return false;
600 }
601 });
602 }
603
Michael Kolb8872c232013-01-29 10:33:22 -0800604 @Override
605 public void startFaceDetection() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800606 if (mFaceDetectionStarted) {
607 return;
608 }
Michael Kolb8872c232013-01-29 10:33:22 -0800609 if (mParameters.getMaxNumDetectedFaces() > 0) {
610 mFaceDetectionStarted = true;
Angus Kongd74e6a12014-01-07 11:29:44 -0800611 CameraInfo info = mAppController.getCameraProvider().getCameraInfo()[mCameraId];
Michael Kolbd6954f32013-03-08 20:43:01 -0800612 mUI.onStartFaceDetection(mDisplayOrientation,
613 (info.facing == CameraInfo.CAMERA_FACING_FRONT));
Angus Kong9e765522013-07-31 14:05:20 -0700614 mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Michael Kolb8872c232013-01-29 10:33:22 -0800615 mCameraDevice.startFaceDetection();
616 }
617 }
618
Michael Kolb8872c232013-01-29 10:33:22 -0800619 @Override
620 public void stopFaceDetection() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800621 if (!mFaceDetectionStarted) {
622 return;
623 }
Michael Kolb8872c232013-01-29 10:33:22 -0800624 if (mParameters.getMaxNumDetectedFaces() > 0) {
625 mFaceDetectionStarted = false;
Angus Kong9e765522013-07-31 14:05:20 -0700626 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -0800627 mCameraDevice.stopFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800628 mUI.clearFaces();
Michael Kolb8872c232013-01-29 10:33:22 -0800629 }
630 }
631
Michael Kolb8872c232013-01-29 10:33:22 -0800632 private final class ShutterCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700633 implements CameraShutterCallback {
Angus Kongdcb0ef12013-03-25 23:11:43 -0700634
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800635 private final boolean mNeedsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700636
Sascha Haeberling37f36112013-08-06 14:31:52 -0700637 public ShutterCallback(boolean needsAnimation) {
638 mNeedsAnimation = needsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700639 }
640
Michael Kolb8872c232013-01-29 10:33:22 -0800641 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700642 public void onShutter(CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800643 mShutterCallbackTime = System.currentTimeMillis();
644 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
645 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Sascha Haeberling37f36112013-08-06 14:31:52 -0700646 if (mNeedsAnimation) {
647 mActivity.runOnUiThread(new Runnable() {
648 @Override
649 public void run() {
650 animateAfterShutter();
651 }
652 });
Angus Kongdcb0ef12013-03-25 23:11:43 -0700653 }
Michael Kolb8872c232013-01-29 10:33:22 -0800654 }
655 }
656
Angus Kong9ef99252013-07-18 18:04:19 -0700657 private final class PostViewPictureCallback
658 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800659 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800660 public void onPictureTaken(byte[] data, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800661 mPostViewPictureCallbackTime = System.currentTimeMillis();
662 Log.v(TAG, "mShutterToPostViewCallbackTime = "
663 + (mPostViewPictureCallbackTime - mShutterCallbackTime)
664 + "ms");
665 }
666 }
667
Angus Kong9ef99252013-07-18 18:04:19 -0700668 private final class RawPictureCallback
669 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800670 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800671 public void onPictureTaken(byte[] rawData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800672 mRawPictureCallbackTime = System.currentTimeMillis();
673 Log.v(TAG, "mShutterToRawCallbackTime = "
674 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
675 }
676 }
677
Angus Kong9ef99252013-07-18 18:04:19 -0700678 private final class JpegPictureCallback
679 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800680 Location mLocation;
681
682 public JpegPictureCallback(Location loc) {
683 mLocation = loc;
684 }
685
686 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800687 public void onPictureTaken(final byte[] jpegData, CameraProxy camera) {
688 setShutterEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800689 if (mPaused) {
690 return;
691 }
Doris Liu6432cd62013-06-13 17:20:31 -0700692 if (mIsImageCaptureIntent) {
693 stopPreview();
694 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700695 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -0700696 mUI.setSwipingEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800697 }
698
699 mJpegPictureCallbackTime = System.currentTimeMillis();
700 // If postview callback has arrived, the captured image is displayed
701 // in postview callback. If not, the captured image is displayed in
702 // raw picture callback.
703 if (mPostViewPictureCallbackTime != 0) {
704 mShutterToPictureDisplayedTime =
705 mPostViewPictureCallbackTime - mShutterCallbackTime;
706 mPictureDisplayedToJpegCallbackTime =
707 mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
708 } else {
709 mShutterToPictureDisplayedTime =
710 mRawPictureCallbackTime - mShutterCallbackTime;
711 mPictureDisplayedToJpegCallbackTime =
712 mJpegPictureCallbackTime - mRawPictureCallbackTime;
713 }
714 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
715 + mPictureDisplayedToJpegCallbackTime + "ms");
716
Michael Kolb8872c232013-01-29 10:33:22 -0800717 mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
718 if (!mIsImageCaptureIntent) {
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700719 setupPreview();
Michael Kolb8872c232013-01-29 10:33:22 -0800720 }
721
Doris Liu36e56fb2013-09-11 17:38:08 -0700722 ExifInterface exif = Exif.getExif(jpegData);
723 int orientation = Exif.getOrientation(exif);
Ruben Brunkd217ed02013-10-08 23:31:13 -0700724
Ruben Brunkd7488272013-10-10 18:45:53 -0700725 if (!mIsImageCaptureIntent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800726 // Calculate the width and the height of the jpeg.
727 Size s = mParameters.getPictureSize();
Michael Kolb8872c232013-01-29 10:33:22 -0800728 int width, height;
729 if ((mJpegRotation + orientation) % 180 == 0) {
730 width = s.width;
731 height = s.height;
732 } else {
733 width = s.height;
734 height = s.width;
735 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700736 NamedEntity name = mNamedImages.getNextNameEntity();
737 String title = (name == null) ? null : name.title;
738 long date = (name == null) ? -1 : name.date;
Ruben Brunkd7488272013-10-10 18:45:53 -0700739
740 // Handle debug mode outputs
741 if (mDebugUri != null) {
742 // If using a debug uri, save jpeg there.
743 saveToDebugUri(jpegData);
744
745 // Adjust the title of the debug image shown in mediastore.
746 if (title != null) {
747 title = DEBUG_IMAGE_PREFIX + title;
748 }
749 }
750
Michael Kolb8872c232013-01-29 10:33:22 -0800751 if (title == null) {
752 Log.e(TAG, "Unbalanced name/data pair");
753 } else {
Sascha Haeberling3b0ab892014-01-29 20:54:39 +0100754 if (date == -1) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800755 date = mCaptureStartTime;
Sascha Haeberling3b0ab892014-01-29 20:54:39 +0100756 }
Angus Kong0d00a892013-03-26 11:40:40 -0700757 if (mHeading >= 0) {
758 // heading direction has been updated by the sensor.
759 ExifTag directionRefTag = exif.buildTag(
760 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
761 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
762 ExifTag directionTag = exif.buildTag(
763 ExifInterface.TAG_GPS_IMG_DIRECTION,
764 new Rational(mHeading, 1));
765 exif.setTag(directionRefTag);
766 exif.setTag(directionTag);
767 }
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800768 getServices().getMediaSaver().addImage(
Angus Kong86d36312013-01-31 18:22:44 -0800769 jpegData, title, date, mLocation, width, height,
Angus Kong0d00a892013-03-26 11:40:40 -0700770 orientation, exif, mOnMediaSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -0800771 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800772 // Animate capture with real jpeg data instead of a preview
773 // frame.
Doris Liu29da2db2013-08-28 14:28:45 -0700774 mUI.animateCapture(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800775 } else {
776 mJpegImageData = jpegData;
777 if (!mQuickCapture) {
Doris Liu36e56fb2013-09-11 17:38:08 -0700778 mUI.showCapturedImageForReview(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800779 } else {
Michael Kolbd6954f32013-03-08 20:43:01 -0800780 onCaptureDone();
Michael Kolb8872c232013-01-29 10:33:22 -0800781 }
782 }
783
784 // Check this in advance of each shot so we don't add to shutter
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800785 // latency. It's true that someone else could write to the SD card
786 // in the mean time and fill it, but that could have happened
787 // between the shutter press and saving the JPEG too.
Michael Kolb8872c232013-01-29 10:33:22 -0800788 mActivity.updateStorageSpaceAndHint();
789
790 long now = System.currentTimeMillis();
791 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
792 Log.v(TAG, "mJpegCallbackFinishTime = "
793 + mJpegCallbackFinishTime + "ms");
794 mJpegPictureCallbackTime = 0;
795 }
796 }
797
Angus Kong9ef99252013-07-18 18:04:19 -0700798 private final class AutoFocusCallback implements CameraAFCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800799 @Override
800 public void onAutoFocus(
Angus Kong9ef99252013-07-18 18:04:19 -0700801 boolean focused, CameraProxy camera) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800802 if (mPaused) {
803 return;
804 }
Michael Kolb8872c232013-01-29 10:33:22 -0800805
806 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
807 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
808 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800809 mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
Michael Kolb8872c232013-01-29 10:33:22 -0800810 }
811 }
812
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700813 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -0800814 private final class AutoFocusMoveCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700815 implements CameraAFMoveCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800816 @Override
817 public void onAutoFocusMoving(
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700818 boolean moving, CameraProxy camera) {
819 mFocusManager.onAutoFocusMoving(moving);
Michael Kolb8872c232013-01-29 10:33:22 -0800820 }
821 }
822
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700823 /**
824 * This class is just a thread-safe queue for name,date holder objects.
825 */
826 public static class NamedImages {
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800827 private final Vector<NamedEntity> mQueue;
Michael Kolb8872c232013-01-29 10:33:22 -0800828
829 public NamedImages() {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700830 mQueue = new Vector<NamedEntity>();
Michael Kolb8872c232013-01-29 10:33:22 -0800831 }
832
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700833 public void nameNewImage(long date) {
Michael Kolb8872c232013-01-29 10:33:22 -0800834 NamedEntity r = new NamedEntity();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700835 r.title = CameraUtil.createJpegName(date);
Michael Kolb8872c232013-01-29 10:33:22 -0800836 r.date = date;
837 mQueue.add(r);
838 }
839
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700840 public NamedEntity getNextNameEntity() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800841 synchronized (mQueue) {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700842 if (!mQueue.isEmpty()) {
843 return mQueue.remove(0);
844 }
Michael Kolb8872c232013-01-29 10:33:22 -0800845 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700846 return null;
Michael Kolb8872c232013-01-29 10:33:22 -0800847 }
848
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700849 public static class NamedEntity {
850 public String title;
851 public long date;
Michael Kolb8872c232013-01-29 10:33:22 -0800852 }
853 }
854
855 private void setCameraState(int state) {
856 mCameraState = state;
857 switch (state) {
Angus Kong62753ae2014-02-10 10:53:54 -0800858 case PREVIEW_STOPPED:
859 case SNAPSHOT_IN_PROGRESS:
860 case SWITCHING_CAMERA:
Doris Liuf55f3c42013-11-20 00:24:46 -0800861 // TODO: Tell app UI to disable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700862 break;
863 case PhotoController.IDLE:
Doris Liuf55f3c42013-11-20 00:24:46 -0800864 // TODO: Tell app UI to enable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700865 break;
Michael Kolb8872c232013-01-29 10:33:22 -0800866 }
867 }
868
Sascha Haeberling37f36112013-08-06 14:31:52 -0700869 private void animateAfterShutter() {
Michael Kolb8872c232013-01-29 10:33:22 -0800870 // Only animate when in full screen capture mode
871 // i.e. If monkey/a user swipes to the gallery during picture taking,
872 // don't show animation
Doris Liuc2e9abd2013-06-19 14:20:51 -0700873 if (!mIsImageCaptureIntent) {
874 mUI.animateFlash();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700875 }
Michael Kolb8872c232013-01-29 10:33:22 -0800876 }
877
878 @Override
879 public boolean capture() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800880 // If we are already in the middle of taking a snapshot or the image
881 // save request is full then ignore.
Michael Kolb8872c232013-01-29 10:33:22 -0800882 if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800883 || mCameraState == SWITCHING_CAMERA || !mShutterEnabled) {
Michael Kolb8872c232013-01-29 10:33:22 -0800884 return false;
885 }
886 mCaptureStartTime = System.currentTimeMillis();
887 mPostViewPictureCallbackTime = 0;
888 mJpegImageData = null;
889
Angus Kongb50b5cb2013-08-09 14:55:20 -0700890 final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
Michael Kolb8872c232013-01-29 10:33:22 -0800891
892 if (animateBefore) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700893 animateAfterShutter();
Michael Kolb8872c232013-01-29 10:33:22 -0800894 }
895
896 // Set rotation and gps data.
Doris Liu3cf565c2013-02-15 10:55:37 -0800897 int orientation;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800898
Doris Liu3cf565c2013-02-15 10:55:37 -0800899 // We need to be consistent with the framework orientation (i.e. the
900 // orientation of the UI.) when the auto-rotate screen setting is on.
901 if (mActivity.isAutoRotateScreen()) {
902 orientation = (360 - mDisplayRotation) % 360;
903 } else {
904 orientation = mOrientation;
905 }
Sascha Haeberlinga7cbfc02014-02-14 11:06:03 +0100906 CameraInfo info = mActivity.getCameraProvider().getCameraInfo()[mCameraId];
907 mJpegRotation = CameraUtil.getJpegRotation(info, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800908 mParameters.setRotation(mJpegRotation);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800909 Location loc = mActivity.getLocationManager().getCurrentLocation();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700910 CameraUtil.setGpsParameters(mParameters, loc);
Michael Kolb8872c232013-01-29 10:33:22 -0800911 mCameraDevice.setParameters(mParameters);
912
Sascha Haeberling88901942013-08-28 17:49:00 -0700913 // We don't want user to press the button again while taking a
914 // multi-second HDR photo.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800915 setShutterEnabled(false);
Angus Kong9ef99252013-07-18 18:04:19 -0700916 mCameraDevice.takePicture(mHandler,
917 new ShutterCallback(!animateBefore),
Angus Kongdcb0ef12013-03-25 23:11:43 -0700918 mRawPictureCallback, mPostViewPictureCallback,
Angus Kong9ef99252013-07-18 18:04:19 -0700919 new JpegPictureCallback(loc));
Michael Kolb8872c232013-01-29 10:33:22 -0800920
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700921 mNamedImages.nameNewImage(mCaptureStartTime);
Michael Kolb8872c232013-01-29 10:33:22 -0800922
923 mFaceDetectionStarted = false;
924 setCameraState(SNAPSHOT_IN_PROGRESS);
Seth Raphael5e09d012013-12-18 13:45:03 -0800925 UsageStatistics.captureEvent(eventprotos.NavigationChange.Mode.PHOTO_CAPTURE,
926 UsageStatistics.hashFileName(mNamedImages.mQueue.lastElement().title + ".jpg"),
927 mParameters);
Michael Kolb8872c232013-01-29 10:33:22 -0800928 return true;
929 }
930
931 @Override
932 public void setFocusParameters() {
933 setCameraParameters(UPDATE_PARAM_PREFERENCE);
934 }
935
Michael Kolbd6954f32013-03-08 20:43:01 -0800936 private void updateSceneMode() {
Michael Kolb8872c232013-01-29 10:33:22 -0800937 // If scene mode is set, we cannot set flash mode, white balance, and
938 // focus mode, instead, we read it from driver
939 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
940 overrideCameraSettings(mParameters.getFlashMode(),
941 mParameters.getWhiteBalance(), mParameters.getFocusMode());
Michael Kolb8872c232013-01-29 10:33:22 -0800942 }
943 }
944
945 private void overrideCameraSettings(final String flashMode,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800946 final String whiteBalance, final String focusMode) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800947 SettingsManager settingsManager = mActivity.getSettingsManager();
948 settingsManager.set(SettingsManager.SETTING_FLASH_MODE, flashMode);
949 settingsManager.set(SettingsManager.SETTING_WHITE_BALANCE, whiteBalance);
950 settingsManager.set(SettingsManager.SETTING_FOCUS_MODE, focusMode);
Michael Kolb8872c232013-01-29 10:33:22 -0800951 }
952
953 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800954 public void onOrientationChanged(int orientation) {
955 // We keep the last known orientation. So if the user first orient
956 // the camera then point the camera to floor or sky, we still have
957 // the correct orientation.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800958 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
959 return;
960 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700961 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800962
963 // Show the toast after getting the first orientation changed.
Angus Kong13e87c42013-11-25 10:02:47 -0800964 if (mHandler.hasMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST)) {
965 mHandler.removeMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST);
Michael Kolb8872c232013-01-29 10:33:22 -0800966 showTapToFocusToast();
967 }
968 }
969
970 @Override
Angus Kong20fad242013-11-11 18:23:46 -0800971 public void onCameraAvailable(CameraProxy cameraProxy) {
972 if (mPaused) {
973 return;
974 }
975 mCameraDevice = cameraProxy;
976
Erin Dahlgren357b7672013-11-20 17:38:14 -0800977 resetExposureCompensation();
Angus Kong20fad242013-11-11 18:23:46 -0800978 initializeCapabilities();
979
980 // Reset zoom value index.
981 mZoomValue = 0;
982 if (mFocusManager == null) {
983 initializeFocusManager();
984 }
985 mFocusManager.setParameters(mInitialParams);
986
Erin Dahlgren7f0151d2014-01-02 16:08:12 -0800987 // Do camera parameter dependent initialization.
Angus Kong20fad242013-11-11 18:23:46 -0800988 mParameters = mCameraDevice.getParameters();
989 setCameraParameters(UPDATE_PARAM_ALL);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -0800990 // Set a listener which updates camera parameters based
991 // on changed settings.
992 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren1648c362014-01-06 15:06:04 -0800993 settingsManager.addListener(this);
Angus Kong20fad242013-11-11 18:23:46 -0800994 mCameraPreviewParamsReady = true;
Erin Dahlgren7f0151d2014-01-02 16:08:12 -0800995
Angus Kong20fad242013-11-11 18:23:46 -0800996 startPreview();
997
998 onCameraOpened();
999 }
1000
1001 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001002 public void onCaptureCancelled() {
1003 mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
1004 mActivity.finish();
Michael Kolb8872c232013-01-29 10:33:22 -08001005 }
1006
Michael Kolbd6954f32013-03-08 20:43:01 -08001007 @Override
1008 public void onCaptureRetake() {
Sascha Haeberling3b0ab892014-01-29 20:54:39 +01001009 if (mPaused) {
Michael Kolb8872c232013-01-29 10:33:22 -08001010 return;
Sascha Haeberling3b0ab892014-01-29 20:54:39 +01001011 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001012 mUI.hidePostCaptureAlert();
Michael Kolb8872c232013-01-29 10:33:22 -08001013 setupPreview();
1014 }
1015
Michael Kolbd6954f32013-03-08 20:43:01 -08001016 @Override
1017 public void onCaptureDone() {
Michael Kolb8872c232013-01-29 10:33:22 -08001018 if (mPaused) {
1019 return;
1020 }
1021
1022 byte[] data = mJpegImageData;
1023
1024 if (mCropValue == null) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001025 // First handle the no crop case -- just return the value. If the
Michael Kolb8872c232013-01-29 10:33:22 -08001026 // caller specifies a "save uri" then write the data to its
1027 // stream. Otherwise, pass back a scaled down version of the bitmap
1028 // directly in the extras.
1029 if (mSaveUri != null) {
1030 OutputStream outputStream = null;
1031 try {
1032 outputStream = mContentResolver.openOutputStream(mSaveUri);
1033 outputStream.write(data);
1034 outputStream.close();
1035
1036 mActivity.setResultEx(Activity.RESULT_OK);
1037 mActivity.finish();
1038 } catch (IOException ex) {
1039 // ignore exception
1040 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001041 CameraUtil.closeSilently(outputStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001042 }
1043 } else {
Angus Kong0d00a892013-03-26 11:40:40 -07001044 ExifInterface exif = Exif.getExif(data);
1045 int orientation = Exif.getOrientation(exif);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001046 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
1047 bitmap = CameraUtil.rotate(bitmap, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001048 mActivity.setResultEx(Activity.RESULT_OK,
1049 new Intent("inline-data").putExtra("data", bitmap));
1050 mActivity.finish();
1051 }
1052 } else {
1053 // Save the image to a temp file and invoke the cropper
1054 Uri tempUri = null;
1055 FileOutputStream tempStream = null;
1056 try {
1057 File path = mActivity.getFileStreamPath(sTempCropFilename);
1058 path.delete();
1059 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1060 tempStream.write(data);
1061 tempStream.close();
1062 tempUri = Uri.fromFile(path);
1063 } catch (FileNotFoundException ex) {
1064 mActivity.setResultEx(Activity.RESULT_CANCELED);
1065 mActivity.finish();
1066 return;
1067 } catch (IOException ex) {
1068 mActivity.setResultEx(Activity.RESULT_CANCELED);
1069 mActivity.finish();
1070 return;
1071 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001072 CameraUtil.closeSilently(tempStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001073 }
1074
1075 Bundle newExtras = new Bundle();
1076 if (mCropValue.equals("circle")) {
1077 newExtras.putString("circleCrop", "true");
1078 }
1079 if (mSaveUri != null) {
1080 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1081 } else {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001082 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001083 }
1084 if (mActivity.isSecureCamera()) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001085 newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001086 }
1087
Sascha Haeberling37f36112013-08-06 14:31:52 -07001088 // TODO: Share this constant.
Sascha Haeberling8e963a52013-08-06 11:43:02 -07001089 final String CROP_ACTION = "com.android.camera.action.CROP";
1090 Intent cropIntent = new Intent(CROP_ACTION);
Michael Kolb8872c232013-01-29 10:33:22 -08001091
1092 cropIntent.setData(tempUri);
1093 cropIntent.putExtras(newExtras);
1094
1095 mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1096 }
1097 }
1098
Michael Kolb8872c232013-01-29 10:33:22 -08001099 @Override
1100 public void onShutterButtonFocus(boolean pressed) {
Angus Kongeaaf56d2014-02-20 11:59:10 -08001101 // Do nothing. We don't support half-press to focus anymore.
Michael Kolb8872c232013-01-29 10:33:22 -08001102 }
1103
1104 @Override
1105 public void onShutterButtonClick() {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001106 if (mPaused || (mCameraState == SWITCHING_CAMERA)
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001107 || (mCameraState == PREVIEW_STOPPED)) {
1108 return;
1109 }
Michael Kolb8872c232013-01-29 10:33:22 -08001110
1111 // Do not take the picture if there is not enough storage.
Angus Kong2dcc0a92013-09-25 13:00:08 -07001112 if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Michael Kolb8872c232013-01-29 10:33:22 -08001113 Log.i(TAG, "Not enough space or storage not ready. remaining="
Angus Kong2dcc0a92013-09-25 13:00:08 -07001114 + mActivity.getStorageSpaceBytes());
Michael Kolb8872c232013-01-29 10:33:22 -08001115 return;
1116 }
1117 Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1118
Angus Kongb50b5cb2013-08-09 14:55:20 -07001119 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -07001120 mUI.setSwipingEnabled(false);
Doris Liu9cdfe002013-04-16 09:50:56 -07001121 }
Michael Kolb8872c232013-01-29 10:33:22 -08001122 // If the user wants to do a snapshot while the previous one is still
1123 // in progress, remember the fact and do it after we finish the previous
1124 // one and re-start the preview. Snapshot in progress also includes the
1125 // state that autofocus is focusing and a picture will be taken when
1126 // focus callback arrives.
Angus Kongeaaf56d2014-02-20 11:59:10 -08001127 if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)) {
1128 if (!mIsImageCaptureIntent) {
1129 mSnapshotOnIdle = true;
1130 }
Michael Kolb8872c232013-01-29 10:33:22 -08001131 return;
1132 }
1133
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001134 mSnapshotOnIdle = false;
Angus Kongeaaf56d2014-02-20 11:59:10 -08001135 mFocusManager.focusAndCapture();
Michael Kolb8872c232013-01-29 10:33:22 -08001136 }
1137
Andy Huibersdef975d2013-11-22 09:13:39 -08001138 private void onResumeTasks() {
1139 Log.v(TAG, "Executing onResumeTasks.");
Angus Kong20fad242013-11-11 18:23:46 -08001140 mActivity.getCameraProvider().requestCamera(mCameraId);
1141
Michael Kolb8872c232013-01-29 10:33:22 -08001142 mJpegPictureCallbackTime = 0;
1143 mZoomValue = 0;
Angus Kong20fad242013-11-11 18:23:46 -08001144
1145 mOnResumeTime = SystemClock.uptimeMillis();
1146 checkDisplayRotation();
Michael Kolb8872c232013-01-29 10:33:22 -08001147
1148 // If first time initialization is not finished, put it in the
1149 // message queue.
1150 if (!mFirstTimeInitialized) {
Angus Kong13e87c42013-11-25 10:02:47 -08001151 mHandler.sendEmptyMessage(MSG_FIRST_TIME_INIT);
Michael Kolb8872c232013-01-29 10:33:22 -08001152 } else {
1153 initializeSecondTime();
1154 }
Michael Kolb8872c232013-01-29 10:33:22 -08001155
Seth Raphael5e09d012013-12-18 13:45:03 -08001156 UsageStatistics.changeScreen(eventprotos.NavigationChange.Mode.PHOTO_CAPTURE,
1157 eventprotos.CameraEvent.InteractionCause.BUTTON);
Angus Kong0d00a892013-03-26 11:40:40 -07001158
1159 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1160 if (gsensor != null) {
1161 mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1162 }
1163
1164 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1165 if (msensor != null) {
1166 mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1167 }
Michael Kolb8872c232013-01-29 10:33:22 -08001168 }
1169
Angus Kongc4e66562013-11-22 23:03:21 -08001170 /**
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001171 * The focus manager is the first UI related element to get initialized, and
1172 * it requires the RenderOverlay, so initialize it here
Angus Kongc4e66562013-11-22 23:03:21 -08001173 */
1174 private void initializeFocusManager() {
1175 // Create FocusManager object. startPreview needs it.
1176 // if mFocusManager not null, reuse it
1177 // otherwise create a new instance
1178 if (mFocusManager != null) {
1179 mFocusManager.removeMessages();
1180 } else {
Angus Kongd74e6a12014-01-07 11:29:44 -08001181 CameraInfo info = mAppController.getCameraProvider().getCameraInfo()[mCameraId];
Angus Kongc4e66562013-11-22 23:03:21 -08001182 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
1183 String[] defaultFocusModes = mActivity.getResources().getStringArray(
1184 R.array.pref_camera_focusmode_default_array);
Erin Dahlgren357b7672013-11-20 17:38:14 -08001185 mFocusManager = new FocusOverlayManager(mActivity.getSettingsManager(),
1186 defaultFocusModes,
Angus Kongc4e66562013-11-22 23:03:21 -08001187 mInitialParams, this, mMirror,
Doris Liu482de022013-12-18 19:18:16 -08001188 mActivity.getMainLooper(), mUI.getFocusUI());
Angus Kongc4e66562013-11-22 23:03:21 -08001189 }
Doris Liu482de022013-12-18 19:18:16 -08001190 mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
Angus Kong20fad242013-11-11 18:23:46 -08001191 }
1192
1193 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001194 public void resume() {
1195 mPaused = false;
Doris Liu482de022013-12-18 19:18:16 -08001196 if (mFocusManager != null) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001197 // If camera is not open when resume is called, focus manager will
1198 // not
Doris Liu15b99612013-12-21 11:32:28 -08001199 // be initialized yet, in which case it will start listening to
1200 // preview area size change later in the initialization.
Doris Liu482de022013-12-18 19:18:16 -08001201 mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
1202 }
Doris Liu59401042014-01-14 17:51:32 -08001203
1204 if (mUI.getPreviewAreaSizeChangedListener() != null) {
1205 mAppController.addPreviewAreaSizeChangedListener(
1206 mUI.getPreviewAreaSizeChangedListener());
1207 }
1208
Angus Kongc4e66562013-11-22 23:03:21 -08001209 // Add delay on resume from lock screen only, in order to to speed up
1210 // the onResume --> onPause --> onResume cycle from lock screen.
1211 // Don't do always because letting go of thread can cause delay.
1212 String action = mActivity.getIntent().getAction();
1213 if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
1214 || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
1215 Log.v(TAG, "On resume, from lock screen.");
1216 // Note: onPauseAfterSuper() will delete this runnable, so we will
1217 // at most have 1 copy queued up.
1218 mHandler.postDelayed(new Runnable() {
Sameer Padala2c8cc452013-11-05 18:49:12 -08001219 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001220 public void run() {
1221 onResumeTasks();
1222 }
1223 }, ON_RESUME_TASKS_DELAY_MSEC);
1224 } else {
1225 Log.v(TAG, "On resume.");
1226 onResumeTasks();
1227 }
1228 }
1229
1230 @Override
1231 public void pause() {
Michael Kolb8872c232013-01-29 10:33:22 -08001232 mPaused = true;
Angus Kong0d00a892013-03-26 11:40:40 -07001233 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1234 if (gsensor != null) {
1235 mSensorManager.unregisterListener(this, gsensor);
1236 }
1237
1238 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1239 if (msensor != null) {
1240 mSensorManager.unregisterListener(this, msensor);
1241 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001242
Michael Kolb8872c232013-01-29 10:33:22 -08001243 // Reset the focus first. Camera CTS does not guarantee that
1244 // cancelAutoFocus is allowed after preview stops.
1245 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1246 mCameraDevice.cancelAutoFocus();
1247 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001248
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -08001249 // If the camera has not been opened asynchronously yet,
1250 // and startPreview hasn't been called, then this is a no-op.
1251 // (e.g. onResume -> onPause -> onResume).
Michael Kolb8872c232013-01-29 10:33:22 -08001252 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001253
Angus Kongce5480e2013-01-29 17:43:48 -08001254 mNamedImages = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001255
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001256 if (mLocationManager != null) {
1257 mLocationManager.recordLocation(false);
1258 }
Michael Kolb8872c232013-01-29 10:33:22 -08001259
1260 // If we are in an image capture intent and has taken
1261 // a picture, we just clear it in onPause.
1262 mJpegImageData = null;
1263
Angus Kongdcccc512013-08-08 17:06:03 -07001264 // Remove the messages and runnables in the queue.
1265 mHandler.removeCallbacksAndMessages(null);
Michael Kolb8872c232013-01-29 10:33:22 -08001266
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001267 closeCamera();
Angus Kong13e87c42013-11-25 10:02:47 -08001268 mActivity.enableKeepScreenOn(false);
Michael Kolbd6954f32013-03-08 20:43:01 -08001269 mUI.onPause();
1270
Michael Kolb8872c232013-01-29 10:33:22 -08001271 mPendingSwitchCameraId = -1;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001272 if (mFocusManager != null) {
1273 mFocusManager.removeMessages();
Angus Kong86d36312013-01-31 18:22:44 -08001274 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001275 getServices().getMemoryManager().removeListener(this);
Doris Liu482de022013-12-18 19:18:16 -08001276 mAppController.removePreviewAreaSizeChangedListener(mFocusManager);
Doris Liu59401042014-01-14 17:51:32 -08001277 if (mUI.getPreviewAreaSizeChangedListener() != null) {
1278 mAppController.removePreviewAreaSizeChangedListener(
1279 mUI.getPreviewAreaSizeChangedListener());
1280 }
Erin Dahlgren1648c362014-01-06 15:06:04 -08001281
1282 SettingsManager settingsManager = mActivity.getSettingsManager();
1283 settingsManager.removeListener(this);
Michael Kolb8872c232013-01-29 10:33:22 -08001284 }
1285
Angus Kong20fad242013-11-11 18:23:46 -08001286 @Override
1287 public void destroy() {
1288 // TODO: implement this.
1289 }
1290
1291 @Override
Angus Kong2f0e4a32013-12-03 10:02:35 -08001292 public void onLayoutOrientationChanged(boolean isLandscape) {
Michael Kolb8872c232013-01-29 10:33:22 -08001293 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001294 }
1295
1296 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001297 public void updateCameraOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001298 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001299 setDisplayOrientation();
1300 }
1301 }
1302
Michael Kolb8872c232013-01-29 10:33:22 -08001303 private boolean canTakePicture() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001304 return isCameraIdle()
1305 && (mActivity.getStorageSpaceBytes() > Storage.LOW_STORAGE_THRESHOLD_BYTES);
Michael Kolb8872c232013-01-29 10:33:22 -08001306 }
1307
1308 @Override
1309 public void autoFocus() {
1310 mFocusStartTime = System.currentTimeMillis();
Angus Kong9ef99252013-07-18 18:04:19 -07001311 mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001312 setCameraState(FOCUSING);
1313 }
1314
1315 @Override
1316 public void cancelAutoFocus() {
1317 mCameraDevice.cancelAutoFocus();
1318 setCameraState(IDLE);
1319 setCameraParameters(UPDATE_PARAM_PREFERENCE);
1320 }
1321
Michael Kolb8872c232013-01-29 10:33:22 -08001322 @Override
1323 public void onSingleTapUp(View view, int x, int y) {
Doris Liu482de022013-12-18 19:18:16 -08001324 if (mPaused || mCameraDevice == null || !mFirstTimeInitialized
1325 || mCameraState == SNAPSHOT_IN_PROGRESS
1326 || mCameraState == SWITCHING_CAMERA
1327 || mCameraState == PREVIEW_STOPPED) {
1328 return;
1329 }
1330
1331 // Check if metering area or focus area is supported.
Doris Liu15b99612013-12-21 11:32:28 -08001332 if (!mFocusAreaSupported && !mMeteringAreaSupported) {
1333 return;
1334 }
Doris Liu482de022013-12-18 19:18:16 -08001335 mFocusManager.onSingleTapUp(x, y);
Michael Kolb8872c232013-01-29 10:33:22 -08001336 }
1337
1338 @Override
1339 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001340 return mUI.onBackPressed();
Michael Kolb8872c232013-01-29 10:33:22 -08001341 }
1342
1343 @Override
1344 public boolean onKeyDown(int keyCode, KeyEvent event) {
1345 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001346 case KeyEvent.KEYCODE_VOLUME_UP:
1347 case KeyEvent.KEYCODE_VOLUME_DOWN:
1348 case KeyEvent.KEYCODE_FOCUS:
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001349 if (/* TODO: mActivity.isInCameraApp() && */mFirstTimeInitialized) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001350 if (event.getRepeatCount() == 0) {
1351 onShutterButtonFocus(true);
1352 }
1353 return true;
1354 }
1355 return false;
1356 case KeyEvent.KEYCODE_CAMERA:
1357 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1358 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001359 }
1360 return true;
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001361 case KeyEvent.KEYCODE_DPAD_CENTER:
1362 // If we get a dpad center event without any focused view, move
1363 // the focus to the shutter button and press it.
1364 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1365 // Start auto-focus immediately to reduce shutter lag. After
1366 // the shutter button gets the focus, onShutterButtonFocus()
1367 // will be called again but it is fine.
1368 onShutterButtonFocus(true);
1369 mUI.pressShutterButton();
1370 }
1371 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001372 }
1373 return false;
1374 }
1375
1376 @Override
1377 public boolean onKeyUp(int keyCode, KeyEvent event) {
1378 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001379 case KeyEvent.KEYCODE_VOLUME_UP:
1380 case KeyEvent.KEYCODE_VOLUME_DOWN:
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001381 if (/* mActivity.isInCameraApp() && */mFirstTimeInitialized) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001382 onShutterButtonClick();
1383 return true;
1384 }
1385 return false;
1386 case KeyEvent.KEYCODE_FOCUS:
1387 if (mFirstTimeInitialized) {
1388 onShutterButtonFocus(false);
1389 }
Michael Kolb8872c232013-01-29 10:33:22 -08001390 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001391 }
1392 return false;
1393 }
1394
Michael Kolb8872c232013-01-29 10:33:22 -08001395 private void closeCamera() {
1396 if (mCameraDevice != null) {
1397 mCameraDevice.setZoomChangeListener(null);
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001398 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001399 mCameraDevice.setErrorCallback(null);
Ruben Brunk59147832013-11-05 15:53:28 -08001400
Michael Kolb8872c232013-01-29 10:33:22 -08001401 mFaceDetectionStarted = false;
Angus Kong20fad242013-11-11 18:23:46 -08001402 mActivity.getCameraProvider().releaseCamera(mCameraDevice.getCameraId());
Michael Kolb8872c232013-01-29 10:33:22 -08001403 mCameraDevice = null;
1404 setCameraState(PREVIEW_STOPPED);
1405 mFocusManager.onCameraReleased();
1406 }
1407 }
1408
1409 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001410 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1411 mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001412 mCameraDisplayOrientation = mDisplayOrientation;
Michael Kolbd6954f32013-03-08 20:43:01 -08001413 mUI.setDisplayOrientation(mDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001414 if (mFocusManager != null) {
1415 mFocusManager.setDisplayOrientation(mDisplayOrientation);
1416 }
Doris Liu6432cd62013-06-13 17:20:31 -07001417 // Change the camera display orientation
1418 if (mCameraDevice != null) {
1419 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1420 }
Michael Kolb8872c232013-01-29 10:33:22 -08001421 }
1422
Sascha Haeberlingddef7792013-08-13 14:41:10 -07001423 /** Only called by UI thread. */
Michael Kolb8872c232013-01-29 10:33:22 -08001424 private void setupPreview() {
1425 mFocusManager.resetTouchFocus();
1426 startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001427 }
1428
Angus Kong20fad242013-11-11 18:23:46 -08001429 /**
1430 * Returns whether we can/should start the preview or not.
1431 */
1432 private boolean checkPreviewPreconditions() {
1433 if (mPaused) {
1434 return false;
Angus Kongdcccc512013-08-08 17:06:03 -07001435 }
Michael Kolb8872c232013-01-29 10:33:22 -08001436
Angus Kong20fad242013-11-11 18:23:46 -08001437 if (mCameraDevice == null) {
1438 Log.w(TAG, "startPreview: camera device not ready yet.");
1439 return false;
1440 }
1441
Erin Dahlgrend8de0772014-02-03 10:12:27 -08001442 SurfaceTexture st = mActivity.getCameraAppUI().getSurfaceTexture();
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001443 if (st == null) {
1444 Log.w(TAG, "startPreview: surfaceTexture is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001445 return false;
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001446 }
1447
1448 if (!mCameraPreviewParamsReady) {
1449 Log.w(TAG, "startPreview: parameters for preview is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001450 return false;
1451 }
1452 return true;
1453 }
1454
1455 /**
1456 * The start/stop preview should only run on the UI thread.
1457 */
1458 private void startPreview() {
1459 if (!checkPreviewPreconditions()) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001460 return;
1461 }
Angus Kong20fad242013-11-11 18:23:46 -08001462
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001463 mCameraDevice.setErrorCallback(mErrorCallback);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001464 // ICS camera frameworks has a bug. Face detection state is not cleared
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001465 // after taking a picture. Stop the preview to work around it. The bug
1466 // was fixed in JB.
1467 if (mCameraState != PREVIEW_STOPPED) {
1468 stopPreview();
1469 }
1470
1471 setDisplayOrientation();
1472
1473 if (!mSnapshotOnIdle) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001474 // If the focus mode is continuous autofocus, call cancelAutoFocus
1475 // to resume it because it may have been paused by autoFocus call.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001476 String focusMode = mFocusManager.getFocusMode();
1477 if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(focusMode)) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001478 mCameraDevice.cancelAutoFocus();
Michael Kolb8872c232013-01-29 10:33:22 -08001479 }
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001480 mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1481 }
1482 setCameraParameters(UPDATE_PARAM_ALL);
1483 // Let UI set its expected aspect ratio
Erin Dahlgrend8de0772014-02-03 10:12:27 -08001484 mCameraDevice.setPreviewTexture(mActivity.getCameraAppUI().getSurfaceTexture());
Michael Kolb8872c232013-01-29 10:33:22 -08001485
Doris Liu5a367542014-01-17 17:21:42 -08001486 // This is to notify app controller that preview will start next, so app
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001487 // controller can set preview callbacks if needed. This has to happen
Sascha Haeberlingde303232014-02-07 02:30:53 +01001488 // before preview is started as a workaround of the framework bug
1489 // related to
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001490 // preview callbacks at b/12591410.
Doris Liu5a367542014-01-17 17:21:42 -08001491 mAppController.onPreviewReadyToStart();
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001492 Log.v(TAG, "startPreview");
1493 mCameraDevice.startPreview();
Angus Kong20fad242013-11-11 18:23:46 -08001494
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001495 mFocusManager.onPreviewStarted();
1496 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001497
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001498 if (mSnapshotOnIdle) {
1499 mHandler.post(mDoSnapRunnable);
Michael Kolb8872c232013-01-29 10:33:22 -08001500 }
1501 }
1502
Michael Kolbd6954f32013-03-08 20:43:01 -08001503 @Override
1504 public void stopPreview() {
Michael Kolb8872c232013-01-29 10:33:22 -08001505 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1506 Log.v(TAG, "stopPreview");
1507 mCameraDevice.stopPreview();
1508 mFaceDetectionStarted = false;
1509 }
1510 setCameraState(PREVIEW_STOPPED);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001511 if (mFocusManager != null) {
1512 mFocusManager.onPreviewStopped();
1513 }
Michael Kolb8872c232013-01-29 10:33:22 -08001514 }
1515
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001516 @Override
Erin Dahlgren1648c362014-01-06 15:06:04 -08001517 public void onSettingChanged(SettingsManager settingsManager, int id) {
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001518 switch (id) {
1519 case SettingsManager.SETTING_FLASH_MODE: {
1520 updateParametersFlashMode();
1521 break;
1522 }
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001523 default: {
1524 // Do nothing.
1525 }
1526 }
Erin Dahlgren1648c362014-01-06 15:06:04 -08001527
1528 if (mCameraDevice != null) {
1529 mCameraDevice.setParameters(mParameters);
1530 }
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001531 }
1532
Michael Kolb8872c232013-01-29 10:33:22 -08001533 private void updateCameraParametersInitialize() {
1534 // Reset preview frame rate to the maximum because it may be lowered by
1535 // video camera application.
ztenghui16a35202013-09-23 11:35:36 -07001536 int[] fpsRange = CameraUtil.getPhotoPreviewFpsRange(mParameters);
1537 if (fpsRange != null && fpsRange.length > 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001538 mParameters.setPreviewFpsRange(
1539 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1540 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
Michael Kolb8872c232013-01-29 10:33:22 -08001541 }
1542
Angus Kongb50b5cb2013-08-09 14:55:20 -07001543 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);
Michael Kolb8872c232013-01-29 10:33:22 -08001544
1545 // Disable video stabilization. Convenience methods not available in API
1546 // level <= 14
1547 String vstabSupported = mParameters.get("video-stabilization-supported");
1548 if ("true".equals(vstabSupported)) {
1549 mParameters.set("video-stabilization", "false");
1550 }
1551 }
1552
1553 private void updateCameraParametersZoom() {
1554 // Set zoom.
1555 if (mParameters.isZoomSupported()) {
1556 mParameters.setZoom(mZoomValue);
1557 }
1558 }
1559
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001560 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001561 private void setAutoExposureLockIfSupported() {
1562 if (mAeLockSupported) {
1563 mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1564 }
1565 }
1566
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001567 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001568 private void setAutoWhiteBalanceLockIfSupported() {
1569 if (mAwbLockSupported) {
1570 mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1571 }
1572 }
1573
Michael Kolb8872c232013-01-29 10:33:22 -08001574 private void setFocusAreasIfSupported() {
1575 if (mFocusAreaSupported) {
1576 mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1577 }
1578 }
1579
Michael Kolb8872c232013-01-29 10:33:22 -08001580 private void setMeteringAreasIfSupported() {
1581 if (mMeteringAreaSupported) {
Michael Kolb8872c232013-01-29 10:33:22 -08001582 mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1583 }
1584 }
1585
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001586 private void updateCameraParametersPreference() {
Michael Kolb8872c232013-01-29 10:33:22 -08001587 setAutoExposureLockIfSupported();
1588 setAutoWhiteBalanceLockIfSupported();
1589 setFocusAreasIfSupported();
1590 setMeteringAreasIfSupported();
1591
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001592 // Initialize focus mode.
Michael Kolbd3253f22013-07-12 11:36:47 -07001593 mFocusManager.overrideFocusMode(null);
1594 mParameters.setFocusMode(mFocusManager.getFocusMode());
1595
Michael Kolb8872c232013-01-29 10:33:22 -08001596 // Set picture size.
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001597 updateParametersPictureSize();
1598
1599 // Set JPEG quality.
1600 updateParametersPictureQuality();
1601
1602 // For the following settings, we need to check if the settings are
1603 // still supported by latest driver, if not, ignore the settings.
1604
1605 // Set exposure compensation
1606 updateParametersExposureCompensation();
1607
1608 // Set the scene mode: also sets flash and white balance.
1609 updateParametersSceneMode();
1610
1611 if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
1612 updateAutoFocusMoveCallback();
1613 }
1614 }
1615
1616 private void updateParametersPictureSize() {
1617 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001618 String pictureSize = settingsManager.get(SettingsManager.SETTING_PICTURE_SIZE);
Sascha Haeberling3b0ab892014-01-29 20:54:39 +01001619
1620 List<Size> supported = mParameters.getSupportedPictureSizes();
1621 SettingsUtil.setCameraPictureSize(pictureSize, supported, mParameters);
Michael Kolb8872c232013-01-29 10:33:22 -08001622 Size size = mParameters.getPictureSize();
1623
1624 // Set a preview size that is closest to the viewfinder height and has
1625 // the right aspect ratio.
1626 List<Size> sizes = mParameters.getSupportedPreviewSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001627 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
Michael Kolb8872c232013-01-29 10:33:22 -08001628 (double) size.width / size.height);
1629 Size original = mParameters.getPreviewSize();
1630 if (!original.equals(optimalSize)) {
1631 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
Doris Liu6432cd62013-06-13 17:20:31 -07001632
Michael Kolb8872c232013-01-29 10:33:22 -08001633 // Zoom related settings will be changed for different preview
1634 // sizes, so set and read the parameters to get latest values
Michael Kolb4a4d4ef2013-05-30 08:35:26 -07001635 if (mHandler.getLooper() == Looper.myLooper()) {
1636 // On UI thread only, not when camera starts up
1637 setupPreview();
1638 } else {
1639 mCameraDevice.setParameters(mParameters);
1640 }
Michael Kolb8872c232013-01-29 10:33:22 -08001641 mParameters = mCameraDevice.getParameters();
1642 }
Doris Liu95405742013-11-05 15:25:26 -08001643
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001644 if (optimalSize.width != 0 && optimalSize.height != 0) {
Doris Liu95405742013-11-05 15:25:26 -08001645 mUI.updatePreviewAspectRatio((float) optimalSize.width
1646 / (float) optimalSize.height);
1647 }
Michael Kolb8872c232013-01-29 10:33:22 -08001648 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001649 }
Michael Kolb8872c232013-01-29 10:33:22 -08001650
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001651 private void updateParametersPictureQuality() {
Michael Kolb8872c232013-01-29 10:33:22 -08001652 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1653 CameraProfile.QUALITY_HIGH);
1654 mParameters.setJpegQuality(jpegQuality);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001655 }
Michael Kolb8872c232013-01-29 10:33:22 -08001656
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001657 private void updateParametersExposureCompensation() {
1658 SettingsManager settingsManager = mActivity.getSettingsManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001659
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001660 int value = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_EXPOSURE));
Michael Kolb8872c232013-01-29 10:33:22 -08001661 int max = mParameters.getMaxExposureCompensation();
1662 int min = mParameters.getMinExposureCompensation();
1663 if (value >= min && value <= max) {
1664 mParameters.setExposureCompensation(value);
1665 } else {
1666 Log.w(TAG, "invalid exposure range: " + value);
1667 }
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001668 }
1669
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001670 private void updateParametersSceneMode() {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001671 SettingsManager settingsManager = mActivity.getSettingsManager();
1672
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001673 mSceneMode = settingsManager.get(SettingsManager.SETTING_SCENE_MODE);
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001674 if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
1675 if (!mParameters.getSceneMode().equals(mSceneMode)) {
1676 mParameters.setSceneMode(mSceneMode);
1677
1678 // Setting scene mode will change the settings of flash mode,
1679 // white balance, and focus mode. Here we read back the
1680 // parameters, so we can know those settings.
1681 mCameraDevice.setParameters(mParameters);
1682 mParameters = mCameraDevice.getParameters();
1683 }
1684 } else {
1685 mSceneMode = mParameters.getSceneMode();
1686 if (mSceneMode == null) {
1687 mSceneMode = Parameters.SCENE_MODE_AUTO;
1688 }
1689 }
1690
Michael Kolb8872c232013-01-29 10:33:22 -08001691 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1692 // Set flash mode.
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001693 updateParametersFlashMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001694
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001695 // Set white balance mode.
1696 updateParametersWhiteBalanceMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001697
1698 // Set focus mode.
1699 mFocusManager.overrideFocusMode(null);
1700 mParameters.setFocusMode(mFocusManager.getFocusMode());
1701 } else {
1702 mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1703 }
Michael Kolb8872c232013-01-29 10:33:22 -08001704 }
1705
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001706 private void updateParametersFlashMode() {
1707 SettingsManager settingsManager = mActivity.getSettingsManager();
1708
1709 String flashMode = settingsManager.get(SettingsManager.SETTING_FLASH_MODE);
1710 List<String> supportedFlash = mParameters.getSupportedFlashModes();
1711 if (CameraUtil.isSupported(flashMode, supportedFlash)) {
1712 mParameters.setFlashMode(flashMode);
1713 }
1714 }
1715
1716 private void updateParametersWhiteBalanceMode() {
1717 SettingsManager settingsManager = mActivity.getSettingsManager();
1718
1719 // Set white balance parameter.
1720 String whiteBalance = settingsManager.get(SettingsManager.SETTING_WHITE_BALANCE);
1721 if (CameraUtil.isSupported(whiteBalance,
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001722 mParameters.getSupportedWhiteBalance())) {
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001723 mParameters.setWhiteBalance(whiteBalance);
1724 }
1725 }
1726
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001727 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001728 private void updateAutoFocusMoveCallback() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001729 if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Angus Kong9ef99252013-07-18 18:04:19 -07001730 mCameraDevice.setAutoFocusMoveCallback(mHandler,
Angus Kong4f795b82013-09-16 14:25:35 -07001731 (CameraAFMoveCallback) mAutoFocusMoveCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001732 } else {
Angus Kong9ef99252013-07-18 18:04:19 -07001733 mCameraDevice.setAutoFocusMoveCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001734 }
1735 }
1736
1737 // We separate the parameters into several subsets, so we can update only
1738 // the subsets actually need updating. The PREFERENCE set needs extra
1739 // locking because the preference can be changed from GLThread as well.
1740 private void setCameraParameters(int updateSet) {
1741 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1742 updateCameraParametersInitialize();
1743 }
1744
1745 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1746 updateCameraParametersZoom();
1747 }
1748
1749 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001750 updateCameraParametersPreference();
Michael Kolb8872c232013-01-29 10:33:22 -08001751 }
1752
1753 mCameraDevice.setParameters(mParameters);
1754 }
1755
1756 // If the Camera is idle, update the parameters immediately, otherwise
1757 // accumulate them in mUpdateSet and update later.
1758 private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1759 mUpdateSet |= additionalUpdateSet;
1760 if (mCameraDevice == null) {
1761 // We will update all the parameters when we open the device, so
1762 // we don't need to do anything now.
1763 mUpdateSet = 0;
1764 return;
1765 } else if (isCameraIdle()) {
1766 setCameraParameters(mUpdateSet);
Michael Kolbd6954f32013-03-08 20:43:01 -08001767 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001768 mUpdateSet = 0;
1769 } else {
Angus Kong13e87c42013-11-25 10:02:47 -08001770 if (!mHandler.hasMessages(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1771 mHandler.sendEmptyMessageDelayed(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
Michael Kolb8872c232013-01-29 10:33:22 -08001772 }
1773 }
1774 }
1775
ztenghui7b265a62013-09-09 14:58:44 -07001776 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001777 public boolean isCameraIdle() {
Michael Kolb8872c232013-01-29 10:33:22 -08001778 return (mCameraState == IDLE) ||
1779 (mCameraState == PREVIEW_STOPPED) ||
1780 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001781 && (mCameraState != SWITCHING_CAMERA));
Michael Kolb8872c232013-01-29 10:33:22 -08001782 }
1783
ztenghui7b265a62013-09-09 14:58:44 -07001784 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001785 public boolean isImageCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001786 String action = mActivity.getIntent().getAction();
1787 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001788 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
Michael Kolb8872c232013-01-29 10:33:22 -08001789 }
1790
1791 private void setupCaptureParams() {
1792 Bundle myExtras = mActivity.getIntent().getExtras();
1793 if (myExtras != null) {
1794 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1795 mCropValue = myExtras.getString("crop");
1796 }
1797 }
1798
Michael Kolb8872c232013-01-29 10:33:22 -08001799 private void showTapToFocusToast() {
1800 // TODO: Use a toast?
1801 new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
1802 // Clear the preference.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001803 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001804 settingsManager.setBoolean(
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001805 SettingsManager.SETTING_CAMERA_FIRST_USE_HINT_SHOWN, false);
Michael Kolb8872c232013-01-29 10:33:22 -08001806 }
1807
1808 private void initializeCapabilities() {
1809 mInitialParams = mCameraDevice.getParameters();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001810 mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
1811 mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
1812 mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
1813 mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
Angus Kongdcccc512013-08-08 17:06:03 -07001814 mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001815 CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
Michael Kolb8872c232013-01-29 10:33:22 -08001816 }
1817
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001818 private void setShutterEnabled(boolean enabled) {
1819 mShutterEnabled = enabled;
1820 mUI.enableShutter(enabled);
1821 }
1822
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001823 // TODO: Remove this
Michael Kolb8872c232013-01-29 10:33:22 -08001824 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001825 public int onZoomChanged(int index) {
1826 // Not useful to change zoom value when the activity is paused.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001827 if (mPaused) {
1828 return index;
1829 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001830 mZoomValue = index;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001831 if (mParameters == null || mCameraDevice == null) {
1832 return index;
1833 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001834 // Set zoom parameters asynchronously
1835 mParameters.setZoom(mZoomValue);
Angus Kong36ed8672013-04-15 12:11:15 -07001836 mCameraDevice.setParameters(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -08001837 Parameters p = mCameraDevice.getParameters();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001838 if (p != null) {
1839 return p.getZoom();
1840 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001841 return index;
Angus Kongce5480e2013-01-29 17:43:48 -08001842 }
1843
1844 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001845 public int getCameraState() {
1846 return mCameraState;
1847 }
1848
1849 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001850 public void onMemoryStateChanged(int state) {
1851 setShutterEnabled(state == MemoryManager.STATE_OK);
Angus Kongce5480e2013-01-29 17:43:48 -08001852 }
Angus Kong86d36312013-01-31 18:22:44 -08001853
1854 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001855 public void onLowMemory() {
1856 // Not much we can do in the photo module.
Angus Kong86d36312013-01-31 18:22:44 -08001857 }
Angus Kong0d00a892013-03-26 11:40:40 -07001858
1859 @Override
1860 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1861 }
1862
1863 @Override
1864 public void onSensorChanged(SensorEvent event) {
1865 int type = event.sensor.getType();
1866 float[] data;
1867 if (type == Sensor.TYPE_ACCELEROMETER) {
1868 data = mGData;
1869 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
1870 data = mMData;
1871 } else {
1872 // we should not be here.
1873 return;
1874 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001875 for (int i = 0; i < 3; i++) {
Angus Kong0d00a892013-03-26 11:40:40 -07001876 data[i] = event.values[i];
1877 }
1878 float[] orientation = new float[3];
1879 SensorManager.getRotationMatrix(mR, null, mGData, mMData);
1880 SensorManager.getOrientation(mR, orientation);
1881 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
1882 if (mHeading < 0) {
1883 mHeading += 360;
1884 }
Angus Kong0d00a892013-03-26 11:40:40 -07001885 }
Doris Liu6432cd62013-06-13 17:20:31 -07001886
Ruben Brunkd217ed02013-10-08 23:31:13 -07001887 // For debugging only.
1888 public void setDebugUri(Uri uri) {
1889 mDebugUri = uri;
1890 }
1891
1892 // For debugging only.
1893 private void saveToDebugUri(byte[] data) {
1894 if (mDebugUri != null) {
1895 OutputStream outputStream = null;
1896 try {
1897 outputStream = mContentResolver.openOutputStream(mDebugUri);
1898 outputStream.write(data);
1899 outputStream.close();
1900 } catch (IOException e) {
1901 Log.e(TAG, "Exception while writing debug jpeg file", e);
1902 } finally {
1903 CameraUtil.closeSilently(outputStream);
1904 }
1905 }
1906 }
Michael Kolb8872c232013-01-29 10:33:22 -08001907}