blob: abef9d0795dbf29a5d7badc6bbac385d1ecd3200 [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;
Doris Liu773e1c92013-12-02 17:35:03 -080048import android.view.ViewGroup;
Michael Kolb8872c232013-01-29 10:33:22 -080049
Sameer Padala2c8cc452013-11-05 18:49:12 -080050import com.android.camera.PhotoModule.NamedImages.NamedEntity;
51import com.android.camera.app.AppController;
Erin Dahlgrenb1641f52014-01-14 15:58:52 -080052import com.android.camera.app.CameraAppUI;
Angus Kong20fad242013-11-11 18:23:46 -080053import com.android.camera.app.CameraManager.CameraAFCallback;
54import com.android.camera.app.CameraManager.CameraAFMoveCallback;
55import com.android.camera.app.CameraManager.CameraPictureCallback;
56import com.android.camera.app.CameraManager.CameraProxy;
57import com.android.camera.app.CameraManager.CameraShutterCallback;
Kevin Gabayanffbc43c2013-12-09 11:41:50 -080058import com.android.camera.app.LocationManager;
Angus Kongfd4fc0e2013-11-07 15:38:09 -080059import com.android.camera.app.MediaSaver;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080060import com.android.camera.app.MemoryManager;
61import com.android.camera.app.MemoryManager.MemoryListener;
ztenghuia16e7b52013-08-23 11:47:56 -070062import com.android.camera.exif.ExifInterface;
63import com.android.camera.exif.ExifTag;
64import com.android.camera.exif.Rational;
Erin Dahlgrenb1641f52014-01-14 15:58:52 -080065import com.android.camera.hardware.HardwareSpec;
66import com.android.camera.hardware.HardwareSpecImpl;
Angus Kong20fad242013-11-11 18:23:46 -080067import com.android.camera.module.ModuleController;
Sascha Haeberlingf2994f02014-01-23 19:55:01 -080068import com.android.camera.remote.RemoteCameraModule;
Erin Dahlgren357b7672013-11-20 17:38:14 -080069import com.android.camera.settings.SettingsManager;
Michael Kolb8872c232013-01-29 10:33:22 -080070import com.android.camera.ui.RotateTextToast;
Angus Kongdcccc512013-08-08 17:06:03 -070071import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -070072import com.android.camera.util.CameraUtil;
Ruben Brunk4601f5d2013-09-24 18:35:22 -070073import com.android.camera.util.GcamHelper;
Sameer Padala2c8cc452013-11-05 18:49:12 -080074import com.android.camera.util.SmartCameraHelper;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070075import com.android.camera.util.UsageStatistics;
76import com.android.camera2.R;
Michael Kolb8872c232013-01-29 10:33:22 -080077
Angus Kongdcccc512013-08-08 17:06:03 -070078import java.io.File;
79import java.io.FileNotFoundException;
80import java.io.FileOutputStream;
81import java.io.IOException;
82import java.io.OutputStream;
Angus Kongdcccc512013-08-08 17:06:03 -070083import java.util.List;
Ruben Brunka9d66bd2013-09-06 11:56:32 -070084import java.util.Vector;
Angus Kongdcccc512013-08-08 17:06:03 -070085
Michael Kolb8872c232013-01-29 10:33:22 -080086public class PhotoModule
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080087 extends CameraModule
88 implements PhotoController,
89 ModuleController,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080090 MemoryListener,
Sascha Haeberling280fd3e2013-11-21 13:52:15 -080091 FocusOverlayManager.Listener,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080092 ShutterButton.OnShutterButtonListener,
Erin Dahlgren7f0151d2014-01-02 16:08:12 -080093 SensorEventListener,
Sascha Haeberlingf2994f02014-01-23 19:55:01 -080094 SettingsManager.OnSettingChangedListener,
95 RemoteCameraModule {
Michael Kolb8872c232013-01-29 10:33:22 -080096
Sascha Haeberling58501152014-01-06 11:02:35 -080097 private static final String TAG = "PhotoModule";
Michael Kolb8872c232013-01-29 10:33:22 -080098
99 // We number the request code from 1000 to avoid collision with Gallery.
100 private static final int REQUEST_CROP = 1000;
101
Angus Kong13e87c42013-11-25 10:02:47 -0800102 // Messages defined for the UI thread handler.
Angus Kong1587b042014-01-02 18:09:27 -0800103 private static final int MSG_FIRST_TIME_INIT = 1;
104 private static final int MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE = 2;
105 private static final int MSG_SHOW_TAP_TO_FOCUS_TOAST = 3;
106 private static final int MSG_SWITCH_TO_GCAM_MODULE = 4;
Michael Kolb8872c232013-01-29 10:33:22 -0800107
108 // The subset of parameters we need to update in setCameraParameters().
109 private static final int UPDATE_PARAM_INITIALIZE = 1;
110 private static final int UPDATE_PARAM_ZOOM = 2;
111 private static final int UPDATE_PARAM_PREFERENCE = 4;
112 private static final int UPDATE_PARAM_ALL = -1;
113
Andy Huibersdef975d2013-11-22 09:13:39 -0800114 // This is the delay before we execute onResume tasks when coming
115 // from the lock screen, to allow time for onPause to execute.
116 private static final int ON_RESUME_TASKS_DELAY_MSEC = 20;
Michael Kolb8872c232013-01-29 10:33:22 -0800117
Ruben Brunkd7488272013-10-10 18:45:53 -0700118 private static final String DEBUG_IMAGE_PREFIX = "DEBUG_";
119
Michael Kolb8872c232013-01-29 10:33:22 -0800120 // copied from Camera hierarchy
121 private CameraActivity mActivity;
Michael Kolb8872c232013-01-29 10:33:22 -0800122 private CameraProxy mCameraDevice;
123 private int mCameraId;
124 private Parameters mParameters;
125 private boolean mPaused;
Michael Kolbd6954f32013-03-08 20:43:01 -0800126
127 private PhotoUI mUI;
Michael Kolb8872c232013-01-29 10:33:22 -0800128
Michael Kolb8872c232013-01-29 10:33:22 -0800129 // The activity is going to switch to the specified camera id. This is
130 // needed because texture copy is done in GL thread. -1 means camera is not
131 // switching.
132 protected int mPendingSwitchCameraId = -1;
Michael Kolb8872c232013-01-29 10:33:22 -0800133
134 // When setCameraParametersWhenIdle() is called, we accumulate the subsets
135 // needed to be updated in mUpdateSet.
136 private int mUpdateSet;
137
138 private static final int SCREEN_DELAY = 2 * 60 * 1000;
139
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800140 private int mZoomValue; // The current zoom value.
Michael Kolb8872c232013-01-29 10:33:22 -0800141
142 private Parameters mInitialParams;
143 private boolean mFocusAreaSupported;
144 private boolean mMeteringAreaSupported;
145 private boolean mAeLockSupported;
146 private boolean mAwbLockSupported;
Angus Kongdcccc512013-08-08 17:06:03 -0700147 private boolean mContinuousFocusSupported;
Michael Kolb8872c232013-01-29 10:33:22 -0800148
149 // The degrees of the device rotated clockwise from its natural orientation.
150 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
Michael Kolb8872c232013-01-29 10:33:22 -0800151
152 private static final String sTempCropFilename = "crop-temp";
153
Michael Kolb8872c232013-01-29 10:33:22 -0800154 private boolean mFaceDetectionStarted = false;
155
Michael Kolb8872c232013-01-29 10:33:22 -0800156 // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
157 private String mCropValue;
158 private Uri mSaveUri;
159
Ruben Brunkd217ed02013-10-08 23:31:13 -0700160 private Uri mDebugUri;
161
Angus Kongce5480e2013-01-29 17:43:48 -0800162 // We use a queue to generated names of the images to be used later
163 // when the image is ready to be saved.
Michael Kolb8872c232013-01-29 10:33:22 -0800164 private NamedImages mNamedImages;
165
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800166 private final Runnable mDoSnapRunnable = new Runnable() {
Michael Kolb8872c232013-01-29 10:33:22 -0800167 @Override
168 public void run() {
169 onShutterButtonClick();
170 }
171 };
172
Michael Kolb8872c232013-01-29 10:33:22 -0800173 /**
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800174 * An unpublished intent flag requesting to return as soon as capturing is
175 * completed. TODO: consider publishing by moving into MediaStore.
Michael Kolb8872c232013-01-29 10:33:22 -0800176 */
177 private static final String EXTRA_QUICK_CAPTURE =
178 "android.intent.extra.quickCapture";
179
180 // The display rotation in degrees. This is only valid when mCameraState is
181 // not PREVIEW_STOPPED.
182 private int mDisplayRotation;
183 // The value for android.hardware.Camera.setDisplayOrientation.
184 private int mCameraDisplayOrientation;
185 // The value for UI components like indicators.
186 private int mDisplayOrientation;
187 // The value for android.hardware.Camera.Parameters.setRotation.
188 private int mJpegRotation;
Doris Liu29da2db2013-08-28 14:28:45 -0700189 // Indicates whether we are using front camera
190 private boolean mMirror;
Michael Kolb8872c232013-01-29 10:33:22 -0800191 private boolean mFirstTimeInitialized;
192 private boolean mIsImageCaptureIntent;
193
Michael Kolb8872c232013-01-29 10:33:22 -0800194 private int mCameraState = PREVIEW_STOPPED;
195 private boolean mSnapshotOnIdle = false;
196
197 private ContentResolver mContentResolver;
198
199 private LocationManager mLocationManager;
Doris Liu2b906b82013-12-10 16:34:08 -0800200 private AppController mAppController;
Michael Kolb8872c232013-01-29 10:33:22 -0800201
Michael Kolb8872c232013-01-29 10:33:22 -0800202 private final PostViewPictureCallback mPostViewPictureCallback =
203 new PostViewPictureCallback();
204 private final RawPictureCallback mRawPictureCallback =
205 new RawPictureCallback();
206 private final AutoFocusCallback mAutoFocusCallback =
207 new AutoFocusCallback();
208 private final Object mAutoFocusMoveCallback =
209 ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700210 ? new AutoFocusMoveCallback()
211 : null;
Michael Kolb8872c232013-01-29 10:33:22 -0800212
213 private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
214
215 private long mFocusStartTime;
216 private long mShutterCallbackTime;
217 private long mPostViewPictureCallbackTime;
218 private long mRawPictureCallbackTime;
219 private long mJpegPictureCallbackTime;
220 private long mOnResumeTime;
221 private byte[] mJpegImageData;
222
223 // These latency time are for the CameraLatency test.
224 public long mAutoFocusTime;
225 public long mShutterLag;
226 public long mShutterToPictureDisplayedTime;
227 public long mPictureDisplayedToJpegCallbackTime;
228 public long mJpegCallbackFinishTime;
229 public long mCaptureStartTime;
230
231 // This handles everything about focus.
232 private FocusOverlayManager mFocusManager;
233
Doris Liubd1b8f92014-01-03 17:59:51 -0800234 private final int mGcamModeIndex;
235 private final int mRefocusModeIndex;
236
Michael Kolb8872c232013-01-29 10:33:22 -0800237 private String mSceneMode;
Michael Kolb8872c232013-01-29 10:33:22 -0800238
239 private final Handler mHandler = new MainHandler();
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800240
Michael Kolb8872c232013-01-29 10:33:22 -0800241 private boolean mQuickCapture;
Angus Kong0d00a892013-03-26 11:40:40 -0700242 private SensorManager mSensorManager;
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800243 private final float[] mGData = new float[3];
244 private final float[] mMData = new float[3];
245 private final float[] mR = new float[16];
Angus Kong0d00a892013-03-26 11:40:40 -0700246 private int mHeading = -1;
247
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800248 /** Whether shutter is enabled. */
Spike Sprague215f6b02013-12-12 11:53:49 -0800249 private boolean mShutterEnabled = true;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800250
251 /** True if all the parameters needed to start preview is ready. */
Angus Kongdcccc512013-08-08 17:06:03 -0700252 private boolean mCameraPreviewParamsReady = false;
Doris Liu6432cd62013-06-13 17:20:31 -0700253
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800254 private final MediaSaver.OnMediaSavedListener mOnMediaSavedListener =
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800255 new MediaSaver.OnMediaSavedListener() {
Angus Kongce5480e2013-01-29 17:43:48 -0800256 @Override
257 public void onMediaSaved(Uri uri) {
258 if (uri != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700259 mActivity.notifyNewMedia(uri);
Angus Kongce5480e2013-01-29 17:43:48 -0800260 }
261 }
262 };
Michael Kolb8872c232013-01-29 10:33:22 -0800263
Angus Kongdcccc512013-08-08 17:06:03 -0700264 private void checkDisplayRotation() {
265 // Set the display orientation if display rotation has changed.
266 // Sometimes this happens when the device is held upside
267 // down and camera app is opened. Rotation animation will
268 // take some time and the rotation value we have got may be
269 // wrong. Framework does not have a callback for this now.
270 if (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) {
271 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -0800272 }
Angus Kongdcccc512013-08-08 17:06:03 -0700273 if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
274 mHandler.postDelayed(new Runnable() {
275 @Override
276 public void run() {
277 checkDisplayRotation();
278 }
279 }, 100);
Michael Kolb8872c232013-01-29 10:33:22 -0800280 }
281 }
282
283 /**
284 * This Handler is used to post message back onto the main thread of the
285 * application
286 */
287 private class MainHandler extends Handler {
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -0800288 public MainHandler() {
289 super(Looper.getMainLooper());
290 }
291
Michael Kolb8872c232013-01-29 10:33:22 -0800292 @Override
293 public void handleMessage(Message msg) {
294 switch (msg.what) {
Angus Kong13e87c42013-11-25 10:02:47 -0800295 case MSG_FIRST_TIME_INIT: {
Michael Kolb8872c232013-01-29 10:33:22 -0800296 initializeFirstTime();
297 break;
298 }
299
Angus Kong13e87c42013-11-25 10:02:47 -0800300 case MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE: {
Michael Kolb8872c232013-01-29 10:33:22 -0800301 setCameraParametersWhenIdle(0);
302 break;
303 }
304
Angus Kong13e87c42013-11-25 10:02:47 -0800305 case MSG_SHOW_TAP_TO_FOCUS_TOAST: {
Michael Kolb8872c232013-01-29 10:33:22 -0800306 showTapToFocusToast();
307 break;
308 }
309
Angus Kong13e87c42013-11-25 10:02:47 -0800310 case MSG_SWITCH_TO_GCAM_MODULE: {
Doris Liubd1b8f92014-01-03 17:59:51 -0800311 mActivity.onModeSelected(mGcamModeIndex);
ztenghui367c7c82013-10-16 14:43:26 -0700312 }
Michael Kolb8872c232013-01-29 10:33:22 -0800313 }
314 }
315 }
316
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800317 /**
318 * Constructs a new photo module.
319 */
Angus Kongc4e66562013-11-22 23:03:21 -0800320 public PhotoModule(AppController app) {
321 super(app);
Doris Liubd1b8f92014-01-03 17:59:51 -0800322 mGcamModeIndex = app.getAndroidContext().getResources()
323 .getInteger(R.integer.camera_mode_gcam);
324 mRefocusModeIndex = app.getAndroidContext().getResources()
325 .getInteger(R.integer.camera_mode_refocus);
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800326 }
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700327
Angus Kong13e87c42013-11-25 10:02:47 -0800328
Michael Kolb8872c232013-01-29 10:33:22 -0800329 @Override
Angus Kong13e87c42013-11-25 10:02:47 -0800330 public void init(AppController app, boolean isSecureCamera, boolean isCaptureIntent) {
331 mActivity = (CameraActivity) app.getAndroidContext();
332 mUI = new PhotoUI(mActivity, this, app.getModuleLayoutRoot());
Doris Liu06db7422013-12-09 19:36:25 -0800333 app.setPreviewStatusListener(mUI);
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800334 app.getCameraAppUI().setBottomBarShutterListener(this);
Erin Dahlgren357b7672013-11-20 17:38:14 -0800335
336 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800337 mCameraId = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_CAMERA_ID));
Michael Kolb8872c232013-01-29 10:33:22 -0800338
339 mContentResolver = mActivity.getContentResolver();
340
Michael Kolb8872c232013-01-29 10:33:22 -0800341 // Surface texture is from camera screen nail and startPreview needs it.
342 // This must be done before startPreview.
343 mIsImageCaptureIntent = isImageCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800344
Angus Kong20fad242013-11-11 18:23:46 -0800345 mActivity.getCameraProvider().requestCamera(mCameraId);
346
Michael Kolb8872c232013-01-29 10:33:22 -0800347 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800348 mLocationManager = mActivity.getLocationManager();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800349 mSensorManager = (SensorManager) (mActivity.getSystemService(Context.SENSOR_SERVICE));
Doris Liu2b906b82013-12-10 16:34:08 -0800350 mAppController = app;
Michael Kolbd6954f32013-03-08 20:43:01 -0800351 }
352
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800353 @Override
354 public boolean isUsingBottomBar() {
355 return true;
356 }
357
Michael Kolbd6954f32013-03-08 20:43:01 -0800358 private void initializeControlByIntent() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800359 if (mIsImageCaptureIntent) {
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800360 mActivity.getCameraAppUI().transitionToIntentLayout();
Michael Kolbd6954f32013-03-08 20:43:01 -0800361 setupCaptureParams();
362 }
363 }
364
365 private void onPreviewStarted() {
Doris Liu2b906b82013-12-10 16:34:08 -0800366 mAppController.onPreviewStarted();
Michael Kolbd6954f32013-03-08 20:43:01 -0800367 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800368 startFaceDetection();
Sameer Padala2c8cc452013-11-05 18:49:12 -0800369 startSmartCamera();
Michael Kolbd6954f32013-03-08 20:43:01 -0800370 locationFirstRun();
Michael Kolb8872c232013-01-29 10:33:22 -0800371 }
372
373 // Prompt the user to pick to record location for the very first run of
374 // camera only
375 private void locationFirstRun() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800376 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800377 if (settingsManager.isSet(SettingsManager.SETTING_RECORD_LOCATION)) {
Michael Kolb8872c232013-01-29 10:33:22 -0800378 return;
379 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800380 if (mActivity.isSecureCamera()) {
381 return;
382 }
Michael Kolb8872c232013-01-29 10:33:22 -0800383 // Check if the back camera exists
Angus Kongd74e6a12014-01-07 11:29:44 -0800384 int backCameraId = mAppController.getCameraProvider().getFirstBackCameraId();
Michael Kolb8872c232013-01-29 10:33:22 -0800385 if (backCameraId == -1) {
386 // If there is no back camera, do not show the prompt.
387 return;
388 }
Doris Liu6a83d522013-07-02 12:03:32 -0700389 mUI.showLocationDialog();
390 }
Michael Kolb8872c232013-01-29 10:33:22 -0800391
ztenghui7b265a62013-09-09 14:58:44 -0700392 @Override
Angus Kongdcccc512013-08-08 17:06:03 -0700393 public void onPreviewUIReady() {
Erin Dahlgrendc282e12013-11-12 09:39:08 -0800394 startPreview();
Angus Kongdcccc512013-08-08 17:06:03 -0700395 }
396
397 @Override
398 public void onPreviewUIDestroyed() {
399 if (mCameraDevice == null) {
400 return;
401 }
402 mCameraDevice.setPreviewTexture(null);
403 stopPreview();
404 }
405
Doris Liu1dfe7822013-12-12 00:02:08 -0800406 @Override
407 public void startPreCaptureAnimation() {
408 mAppController.startPreCaptureAnimation();
409 }
410
Michael Kolbd6954f32013-03-08 20:43:01 -0800411 private void onCameraOpened() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800412 openCameraCommon();
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800413 initializeControlByIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800414 }
415
Michael Kolbd6954f32013-03-08 20:43:01 -0800416 private void switchCamera() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800417 if (mPaused) {
418 return;
419 }
Erin Dahlgren357b7672013-11-20 17:38:14 -0800420 SettingsManager settingsManager = mActivity.getSettingsManager();
Michael Kolbd6954f32013-03-08 20:43:01 -0800421
422 Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
Angus Kongd4109bc2014-01-08 18:38:03 -0800423 closeCamera();
Michael Kolbd6954f32013-03-08 20:43:01 -0800424 mCameraId = mPendingSwitchCameraId;
425 mPendingSwitchCameraId = -1;
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800426 settingsManager.set(SettingsManager.SETTING_CAMERA_ID, "" + mCameraId);
Angus Kong20fad242013-11-11 18:23:46 -0800427 mActivity.getCameraProvider().requestCamera(mCameraId);
Michael Kolbd6954f32013-03-08 20:43:01 -0800428 mUI.clearFaces();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800429 if (mFocusManager != null) {
430 mFocusManager.removeMessages();
431 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800432
Erin Dahlgren357b7672013-11-20 17:38:14 -0800433 // TODO: this needs to be brought into onCameraAvailable();
Angus Kong20fad242013-11-11 18:23:46 -0800434 CameraInfo info = mActivity.getCameraProvider().getCameraInfo()[mCameraId];
Doris Liu29da2db2013-08-28 14:28:45 -0700435 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
436 mFocusManager.setMirror(mMirror);
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700437 // Start switch camera animation. Post a message because
438 // onFrameAvailable from the old camera may already exist.
Doris Liu48239f42013-03-04 22:19:10 -0800439 }
440
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800441 private final ButtonManager.ButtonCallback mCameraCallback =
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800442 new ButtonManager.ButtonCallback() {
443 @Override
444 public void onStateChanged(int state) {
445 if (mPaused || mPendingSwitchCameraId != -1) {
446 return;
447 }
448 mPendingSwitchCameraId = state;
449
450 Log.v(TAG, "Start to switch camera. cameraId=" + state);
451 // We need to keep a preview frame for the animation before
452 // releasing the camera. This will trigger onPreviewTextureCopied.
453 //TODO: Need to animate the camera switch
454 switchCamera();
455 }
456 };
457
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800458 private final ButtonManager.ButtonCallback mHdrPlusCallback =
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800459 new ButtonManager.ButtonCallback() {
460 @Override
461 public void onStateChanged(int state) {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -0800462 if (GcamHelper.hasGcamCapture()) {
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800463 // Set the camera setting to default backfacing.
464 SettingsManager settingsManager = mActivity.getSettingsManager();
465 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_ID);
Erin Dahlgrenba6994d2013-12-12 16:04:38 -0800466 mHandler.sendEmptyMessage(MSG_SWITCH_TO_GCAM_MODULE);
467 } else {
468 mSceneMode = CameraUtil.SCENE_MODE_HDR;
469 updateParametersSceneMode();
470 }
Erin Dahlgren18e2ef62013-12-05 14:53:38 -0800471 }
472 };
473
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800474 private final ButtonManager.ButtonCallback mRefocusCallback =
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800475 new ButtonManager.ButtonCallback() {
476 @Override
477 public void onStateChanged(int state) {
478 if (state == ButtonManager.OFF) {
479 throw new IllegalStateException(
480 "Can't switch refocus off because it should already be off.");
481 }
Doris Liubd1b8f92014-01-03 17:59:51 -0800482 mActivity.onModeSelected(mRefocusModeIndex);
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800483 }
484 };
485
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800486 private final View.OnClickListener mCancelCallback = new View.OnClickListener() {
487 @Override
488 public void onClick(View v) {
489 onCaptureCancelled();
490 }
491 };
492
493 private final View.OnClickListener mDoneCallback = new View.OnClickListener() {
494 @Override
495 public void onClick(View v) {
496 onCaptureDone();
497 }
498 };
499
500 private final View.OnClickListener mRetakeCallback = new View.OnClickListener() {
501 @Override
502 public void onClick(View v) {
503 mActivity.getCameraAppUI().transitionToIntentLayout();
504 onCaptureRetake();
505 }
506 };
507
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800508 @Override
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800509 public HardwareSpec getHardwareSpec() {
510 return new HardwareSpecImpl(mParameters);
511 }
512
513 @Override
514 public CameraAppUI.BottomBarUISpec getBottomBarSpec() {
515 CameraAppUI.BottomBarUISpec bottomBarSpec = new CameraAppUI.BottomBarUISpec();
516
517 bottomBarSpec.enableCamera = true;
518 bottomBarSpec.cameraCallback = mCameraCallback;
519 bottomBarSpec.enableFlash = true;
520
521 if (mActivity.getCurrentModuleIndex() ==
522 mActivity.getResources().getInteger(R.integer.camera_mode_photo)) {
523 bottomBarSpec.hideHdr= true;
524 bottomBarSpec.hideRefocus = true;
525 } else {
526 bottomBarSpec.enableHdr = true;
527 bottomBarSpec.hdrCallback = mHdrPlusCallback;
528 bottomBarSpec.enableRefocus = true;
529 bottomBarSpec.refocusCallback = mRefocusCallback;
530 }
531
532 if (isImageCaptureIntent()) {
533 bottomBarSpec.showCancel = true;
534 bottomBarSpec.cancelCallback = mCancelCallback;
535 bottomBarSpec.showDone = true;
536 bottomBarSpec.doneCallback = mDoneCallback;
537 bottomBarSpec.showRetake = true;
538 bottomBarSpec.retakeCallback = mRetakeCallback;
539 }
540
541 return bottomBarSpec;
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800542 }
543
Michael Kolbd6954f32013-03-08 20:43:01 -0800544 // either open a new camera or switch cameras
545 private void openCameraCommon() {
Erin Dahlgrenb1641f52014-01-14 15:58:52 -0800546 mUI.onCameraOpened(mParameters);
Angus Kong0fb819b2013-10-08 13:44:19 -0700547 if (mIsImageCaptureIntent) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800548 // Set hdr plus to default: off.
549 SettingsManager settingsManager = mActivity.getSettingsManager();
550 settingsManager.setDefault(SettingsManager.SETTING_CAMERA_HDR_PLUS);
Angus Kong0fb819b2013-10-08 13:44:19 -0700551 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800552 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -0800553 }
554
ztenghui7b265a62013-09-09 14:58:44 -0700555 @Override
Doris Liu70da9182013-12-17 18:41:15 -0800556 public void updatePreviewAspectRatio(float aspectRatio) {
557 mAppController.updatePreviewAspectRatio(aspectRatio);
558 }
559
Michael Kolb8872c232013-01-29 10:33:22 -0800560 private void resetExposureCompensation() {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800561 SettingsManager settingsManager = mActivity.getSettingsManager();
562 if (settingsManager == null) {
563 Log.e(TAG, "Settings manager is null!");
564 return;
Michael Kolb8872c232013-01-29 10:33:22 -0800565 }
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800566 settingsManager.setDefault(SettingsManager.SETTING_EXPOSURE);
Michael Kolb8872c232013-01-29 10:33:22 -0800567 }
568
Michael Kolb8872c232013-01-29 10:33:22 -0800569 // Snapshots can only be taken after this is called. It should be called
570 // once only. We could have done these things in onCreate() but we want to
571 // make preview screen appear as soon as possible.
572 private void initializeFirstTime() {
Sascha Haeberling330dafb2013-10-10 19:00:41 -0700573 if (mFirstTimeInitialized || mPaused) {
574 return;
575 }
Michael Kolb8872c232013-01-29 10:33:22 -0800576
577 // Initialize location service.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800578 SettingsController settingsController = mActivity.getSettingsController();
579 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -0800580
Michael Kolbd6954f32013-03-08 20:43:01 -0800581 mUI.initializeFirstTime();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800582
Angus Kong86d36312013-01-31 18:22:44 -0800583 // We set the listener only when both service and shutterbutton
584 // are initialized.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800585 getServices().getMemoryManager().addListener(this);
Michael Kolb8872c232013-01-29 10:33:22 -0800586
Michael Kolb8872c232013-01-29 10:33:22 -0800587 mNamedImages = new NamedImages();
588
589 mFirstTimeInitialized = true;
590 addIdleHandler();
591
592 mActivity.updateStorageSpaceAndHint();
593 }
594
Michael Kolbd6954f32013-03-08 20:43:01 -0800595 // If the activity is paused and resumed, this method will be called in
596 // onResume.
597 private void initializeSecondTime() {
598 // Start location update if needed.
Erin Dahlgren357b7672013-11-20 17:38:14 -0800599 SettingsController settingsController = mActivity.getSettingsController();
600 settingsController.syncLocationManager();
601
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800602 getServices().getMemoryManager().addListener(this);
Michael Kolbd6954f32013-03-08 20:43:01 -0800603 mNamedImages = new NamedImages();
604 mUI.initializeSecondTime(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -0800605 }
606
Michael Kolb8872c232013-01-29 10:33:22 -0800607 private void addIdleHandler() {
608 MessageQueue queue = Looper.myQueue();
609 queue.addIdleHandler(new MessageQueue.IdleHandler() {
610 @Override
611 public boolean queueIdle() {
612 Storage.ensureOSXCompatible();
613 return false;
614 }
615 });
616 }
617
Sameer Padala2c8cc452013-11-05 18:49:12 -0800618 private void startSmartCamera() {
619 SmartCameraHelper.register(mCameraDevice, mParameters.getPreviewSize(), mActivity,
Doris Liu773e1c92013-12-02 17:35:03 -0800620 (ViewGroup) mActivity.findViewById(R.id.camera_app_root));
Sameer Padala2c8cc452013-11-05 18:49:12 -0800621 }
622
623 private void stopSmartCamera() {
624 SmartCameraHelper.tearDown();
625 }
626
Michael Kolb8872c232013-01-29 10:33:22 -0800627 @Override
628 public void startFaceDetection() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800629 if (mFaceDetectionStarted) {
630 return;
631 }
Michael Kolb8872c232013-01-29 10:33:22 -0800632 if (mParameters.getMaxNumDetectedFaces() > 0) {
633 mFaceDetectionStarted = true;
Angus Kongd74e6a12014-01-07 11:29:44 -0800634 CameraInfo info = mAppController.getCameraProvider().getCameraInfo()[mCameraId];
Michael Kolbd6954f32013-03-08 20:43:01 -0800635 mUI.onStartFaceDetection(mDisplayOrientation,
636 (info.facing == CameraInfo.CAMERA_FACING_FRONT));
Angus Kong9e765522013-07-31 14:05:20 -0700637 mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Michael Kolb8872c232013-01-29 10:33:22 -0800638 mCameraDevice.startFaceDetection();
639 }
640 }
641
Michael Kolb8872c232013-01-29 10:33:22 -0800642 @Override
643 public void stopFaceDetection() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800644 if (!mFaceDetectionStarted) {
645 return;
646 }
Michael Kolb8872c232013-01-29 10:33:22 -0800647 if (mParameters.getMaxNumDetectedFaces() > 0) {
648 mFaceDetectionStarted = false;
Angus Kong9e765522013-07-31 14:05:20 -0700649 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -0800650 mCameraDevice.stopFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800651 mUI.clearFaces();
Michael Kolb8872c232013-01-29 10:33:22 -0800652 }
653 }
654
Michael Kolb8872c232013-01-29 10:33:22 -0800655 private final class ShutterCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700656 implements CameraShutterCallback {
Angus Kongdcb0ef12013-03-25 23:11:43 -0700657
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800658 private final boolean mNeedsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700659
Sascha Haeberling37f36112013-08-06 14:31:52 -0700660 public ShutterCallback(boolean needsAnimation) {
661 mNeedsAnimation = needsAnimation;
Angus Kongdcb0ef12013-03-25 23:11:43 -0700662 }
663
Michael Kolb8872c232013-01-29 10:33:22 -0800664 @Override
Angus Kong9ef99252013-07-18 18:04:19 -0700665 public void onShutter(CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800666 mShutterCallbackTime = System.currentTimeMillis();
667 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
668 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Sascha Haeberling37f36112013-08-06 14:31:52 -0700669 if (mNeedsAnimation) {
670 mActivity.runOnUiThread(new Runnable() {
671 @Override
672 public void run() {
673 animateAfterShutter();
674 }
675 });
Angus Kongdcb0ef12013-03-25 23:11:43 -0700676 }
Michael Kolb8872c232013-01-29 10:33:22 -0800677 }
678 }
679
Angus Kong9ef99252013-07-18 18:04:19 -0700680 private final class PostViewPictureCallback
681 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800682 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800683 public void onPictureTaken(byte[] data, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800684 mPostViewPictureCallbackTime = System.currentTimeMillis();
685 Log.v(TAG, "mShutterToPostViewCallbackTime = "
686 + (mPostViewPictureCallbackTime - mShutterCallbackTime)
687 + "ms");
688 }
689 }
690
Angus Kong9ef99252013-07-18 18:04:19 -0700691 private final class RawPictureCallback
692 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800693 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800694 public void onPictureTaken(byte[] rawData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -0800695 mRawPictureCallbackTime = System.currentTimeMillis();
696 Log.v(TAG, "mShutterToRawCallbackTime = "
697 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
698 }
699 }
700
Angus Kong9ef99252013-07-18 18:04:19 -0700701 private final class JpegPictureCallback
702 implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800703 Location mLocation;
704
705 public JpegPictureCallback(Location loc) {
706 mLocation = loc;
707 }
708
709 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800710 public void onPictureTaken(final byte[] jpegData, CameraProxy camera) {
711 setShutterEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800712 if (mPaused) {
713 return;
714 }
Doris Liu6432cd62013-06-13 17:20:31 -0700715 if (mIsImageCaptureIntent) {
716 stopPreview();
717 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700718 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -0700719 mUI.setSwipingEnabled(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800720 }
721
722 mJpegPictureCallbackTime = System.currentTimeMillis();
723 // If postview callback has arrived, the captured image is displayed
724 // in postview callback. If not, the captured image is displayed in
725 // raw picture callback.
726 if (mPostViewPictureCallbackTime != 0) {
727 mShutterToPictureDisplayedTime =
728 mPostViewPictureCallbackTime - mShutterCallbackTime;
729 mPictureDisplayedToJpegCallbackTime =
730 mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
731 } else {
732 mShutterToPictureDisplayedTime =
733 mRawPictureCallbackTime - mShutterCallbackTime;
734 mPictureDisplayedToJpegCallbackTime =
735 mJpegPictureCallbackTime - mRawPictureCallbackTime;
736 }
737 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
738 + mPictureDisplayedToJpegCallbackTime + "ms");
739
Michael Kolb8872c232013-01-29 10:33:22 -0800740 mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
741 if (!mIsImageCaptureIntent) {
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700742 setupPreview();
Michael Kolb8872c232013-01-29 10:33:22 -0800743 }
744
Doris Liu36e56fb2013-09-11 17:38:08 -0700745 ExifInterface exif = Exif.getExif(jpegData);
746 int orientation = Exif.getOrientation(exif);
Ruben Brunkd217ed02013-10-08 23:31:13 -0700747
Ruben Brunkd7488272013-10-10 18:45:53 -0700748 if (!mIsImageCaptureIntent) {
Michael Kolb8872c232013-01-29 10:33:22 -0800749 // Calculate the width and the height of the jpeg.
750 Size s = mParameters.getPictureSize();
Michael Kolb8872c232013-01-29 10:33:22 -0800751 int width, height;
752 if ((mJpegRotation + orientation) % 180 == 0) {
753 width = s.width;
754 height = s.height;
755 } else {
756 width = s.height;
757 height = s.width;
758 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700759 NamedEntity name = mNamedImages.getNextNameEntity();
760 String title = (name == null) ? null : name.title;
761 long date = (name == null) ? -1 : name.date;
Ruben Brunkd7488272013-10-10 18:45:53 -0700762
763 // Handle debug mode outputs
764 if (mDebugUri != null) {
765 // If using a debug uri, save jpeg there.
766 saveToDebugUri(jpegData);
767
768 // Adjust the title of the debug image shown in mediastore.
769 if (title != null) {
770 title = DEBUG_IMAGE_PREFIX + title;
771 }
772 }
773
Michael Kolb8872c232013-01-29 10:33:22 -0800774 if (title == null) {
775 Log.e(TAG, "Unbalanced name/data pair");
776 } else {
Sascha Haeberlingf2994f02014-01-23 19:55:01 -0800777 if (date == -1) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800778 date = mCaptureStartTime;
Sascha Haeberlingf2994f02014-01-23 19:55:01 -0800779 }
780 if (mHeading >= 0) {
Angus Kong0d00a892013-03-26 11:40:40 -0700781 // heading direction has been updated by the sensor.
782 ExifTag directionRefTag = exif.buildTag(
783 ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
784 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
785 ExifTag directionTag = exif.buildTag(
786 ExifInterface.TAG_GPS_IMG_DIRECTION,
787 new Rational(mHeading, 1));
788 exif.setTag(directionRefTag);
789 exif.setTag(directionTag);
790 }
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800791 getServices().getMediaSaver().addImage(
Angus Kong86d36312013-01-31 18:22:44 -0800792 jpegData, title, date, mLocation, width, height,
Angus Kong0d00a892013-03-26 11:40:40 -0700793 orientation, exif, mOnMediaSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -0800794 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800795 // Animate capture with real jpeg data instead of a preview
796 // frame.
Doris Liu29da2db2013-08-28 14:28:45 -0700797 mUI.animateCapture(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800798 } else {
799 mJpegImageData = jpegData;
800 if (!mQuickCapture) {
Doris Liu36e56fb2013-09-11 17:38:08 -0700801 mUI.showCapturedImageForReview(jpegData, orientation, mMirror);
Michael Kolb8872c232013-01-29 10:33:22 -0800802 } else {
Michael Kolbd6954f32013-03-08 20:43:01 -0800803 onCaptureDone();
Michael Kolb8872c232013-01-29 10:33:22 -0800804 }
805 }
806
Sascha Haeberlingf2994f02014-01-23 19:55:01 -0800807 // Send the taken photo to remote shutter listeners, if any are registered.
808 getServices().getRemoteShutterListener().onPictureTaken(jpegData);
809
Michael Kolb8872c232013-01-29 10:33:22 -0800810 // Check this in advance of each shot so we don't add to shutter
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800811 // latency. It's true that someone else could write to the SD card
812 // in the mean time and fill it, but that could have happened
813 // between the shutter press and saving the JPEG too.
Michael Kolb8872c232013-01-29 10:33:22 -0800814 mActivity.updateStorageSpaceAndHint();
815
816 long now = System.currentTimeMillis();
817 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
818 Log.v(TAG, "mJpegCallbackFinishTime = "
819 + mJpegCallbackFinishTime + "ms");
820 mJpegPictureCallbackTime = 0;
821 }
822 }
823
Angus Kong9ef99252013-07-18 18:04:19 -0700824 private final class AutoFocusCallback implements CameraAFCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800825 @Override
826 public void onAutoFocus(
Angus Kong9ef99252013-07-18 18:04:19 -0700827 boolean focused, CameraProxy camera) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800828 if (mPaused) {
829 return;
830 }
Michael Kolb8872c232013-01-29 10:33:22 -0800831
832 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
833 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
834 setCameraState(IDLE);
Michael Kolbd6954f32013-03-08 20:43:01 -0800835 mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
Michael Kolb8872c232013-01-29 10:33:22 -0800836 }
837 }
838
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700839 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -0800840 private final class AutoFocusMoveCallback
Angus Kong9ef99252013-07-18 18:04:19 -0700841 implements CameraAFMoveCallback {
Michael Kolb8872c232013-01-29 10:33:22 -0800842 @Override
843 public void onAutoFocusMoving(
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700844 boolean moving, CameraProxy camera) {
845 mFocusManager.onAutoFocusMoving(moving);
Michael Kolb8872c232013-01-29 10:33:22 -0800846 }
847 }
848
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700849 /**
850 * This class is just a thread-safe queue for name,date holder objects.
851 */
852 public static class NamedImages {
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800853 private final Vector<NamedEntity> mQueue;
Michael Kolb8872c232013-01-29 10:33:22 -0800854
855 public NamedImages() {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700856 mQueue = new Vector<NamedEntity>();
Michael Kolb8872c232013-01-29 10:33:22 -0800857 }
858
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700859 public void nameNewImage(long date) {
Michael Kolb8872c232013-01-29 10:33:22 -0800860 NamedEntity r = new NamedEntity();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700861 r.title = CameraUtil.createJpegName(date);
Michael Kolb8872c232013-01-29 10:33:22 -0800862 r.date = date;
863 mQueue.add(r);
864 }
865
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700866 public NamedEntity getNextNameEntity() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800867 synchronized (mQueue) {
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700868 if (!mQueue.isEmpty()) {
869 return mQueue.remove(0);
870 }
Michael Kolb8872c232013-01-29 10:33:22 -0800871 }
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700872 return null;
Michael Kolb8872c232013-01-29 10:33:22 -0800873 }
874
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700875 public static class NamedEntity {
876 public String title;
877 public long date;
Michael Kolb8872c232013-01-29 10:33:22 -0800878 }
879 }
880
881 private void setCameraState(int state) {
882 mCameraState = state;
883 switch (state) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700884 case PhotoController.PREVIEW_STOPPED:
885 case PhotoController.SNAPSHOT_IN_PROGRESS:
886 case PhotoController.SWITCHING_CAMERA:
Doris Liuf55f3c42013-11-20 00:24:46 -0800887 // TODO: Tell app UI to disable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700888 break;
889 case PhotoController.IDLE:
Doris Liuf55f3c42013-11-20 00:24:46 -0800890 // TODO: Tell app UI to enable swipe
Dan Aminzade92ae10e2013-08-13 14:44:25 -0700891 break;
Michael Kolb8872c232013-01-29 10:33:22 -0800892 }
893 }
894
Sascha Haeberling37f36112013-08-06 14:31:52 -0700895 private void animateAfterShutter() {
Michael Kolb8872c232013-01-29 10:33:22 -0800896 // Only animate when in full screen capture mode
897 // i.e. If monkey/a user swipes to the gallery during picture taking,
898 // don't show animation
Doris Liuc2e9abd2013-06-19 14:20:51 -0700899 if (!mIsImageCaptureIntent) {
900 mUI.animateFlash();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700901 }
Michael Kolb8872c232013-01-29 10:33:22 -0800902 }
903
904 @Override
905 public boolean capture() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800906 // If we are already in the middle of taking a snapshot or the image
907 // save request is full then ignore.
Michael Kolb8872c232013-01-29 10:33:22 -0800908 if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800909 || mCameraState == SWITCHING_CAMERA || !mShutterEnabled) {
Michael Kolb8872c232013-01-29 10:33:22 -0800910 return false;
911 }
912 mCaptureStartTime = System.currentTimeMillis();
913 mPostViewPictureCallbackTime = 0;
914 mJpegImageData = null;
915
Angus Kongb50b5cb2013-08-09 14:55:20 -0700916 final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
Michael Kolb8872c232013-01-29 10:33:22 -0800917
918 if (animateBefore) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700919 animateAfterShutter();
Michael Kolb8872c232013-01-29 10:33:22 -0800920 }
921
922 // Set rotation and gps data.
Doris Liu3cf565c2013-02-15 10:55:37 -0800923 int orientation;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800924
Doris Liu3cf565c2013-02-15 10:55:37 -0800925 // We need to be consistent with the framework orientation (i.e. the
926 // orientation of the UI.) when the auto-rotate screen setting is on.
927 if (mActivity.isAutoRotateScreen()) {
928 orientation = (360 - mDisplayRotation) % 360;
929 } else {
930 orientation = mOrientation;
931 }
Angus Kong20fad242013-11-11 18:23:46 -0800932 mJpegRotation = CameraUtil.getJpegRotation(mActivity, mCameraId, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800933 mParameters.setRotation(mJpegRotation);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800934 Location loc = mActivity.getLocationManager().getCurrentLocation();
Angus Kongb50b5cb2013-08-09 14:55:20 -0700935 CameraUtil.setGpsParameters(mParameters, loc);
Michael Kolb8872c232013-01-29 10:33:22 -0800936 mCameraDevice.setParameters(mParameters);
937
Sascha Haeberling88901942013-08-28 17:49:00 -0700938 // We don't want user to press the button again while taking a
939 // multi-second HDR photo.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800940 setShutterEnabled(false);
Angus Kong9ef99252013-07-18 18:04:19 -0700941 mCameraDevice.takePicture(mHandler,
942 new ShutterCallback(!animateBefore),
Angus Kongdcb0ef12013-03-25 23:11:43 -0700943 mRawPictureCallback, mPostViewPictureCallback,
Angus Kong9ef99252013-07-18 18:04:19 -0700944 new JpegPictureCallback(loc));
Michael Kolb8872c232013-01-29 10:33:22 -0800945
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700946 mNamedImages.nameNewImage(mCaptureStartTime);
Michael Kolb8872c232013-01-29 10:33:22 -0800947
948 mFaceDetectionStarted = false;
949 setCameraState(SNAPSHOT_IN_PROGRESS);
Bobby Georgescu301b6462013-04-01 15:33:17 -0700950 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
Seth Raphaelcbd82672013-11-05 10:12:36 -0800951 UsageStatistics.ACTION_CAPTURE_DONE, "Photo", 0,
Seth Raphael44973262013-11-27 14:29:24 -0800952 UsageStatistics.hashFileName(mNamedImages.mQueue.lastElement().title + ".jpg"));
Michael Kolb8872c232013-01-29 10:33:22 -0800953 return true;
954 }
955
956 @Override
957 public void setFocusParameters() {
958 setCameraParameters(UPDATE_PARAM_PREFERENCE);
959 }
960
Michael Kolbd6954f32013-03-08 20:43:01 -0800961 private void updateSceneMode() {
Michael Kolb8872c232013-01-29 10:33:22 -0800962 // If scene mode is set, we cannot set flash mode, white balance, and
963 // focus mode, instead, we read it from driver
964 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
965 overrideCameraSettings(mParameters.getFlashMode(),
966 mParameters.getWhiteBalance(), mParameters.getFocusMode());
Michael Kolb8872c232013-01-29 10:33:22 -0800967 }
968 }
969
970 private void overrideCameraSettings(final String flashMode,
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800971 final String whiteBalance, final String focusMode) {
Erin Dahlgrene419b192013-12-03 13:10:27 -0800972 SettingsManager settingsManager = mActivity.getSettingsManager();
973 settingsManager.set(SettingsManager.SETTING_FLASH_MODE, flashMode);
974 settingsManager.set(SettingsManager.SETTING_WHITE_BALANCE, whiteBalance);
975 settingsManager.set(SettingsManager.SETTING_FOCUS_MODE, focusMode);
Michael Kolb8872c232013-01-29 10:33:22 -0800976 }
977
978 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800979 public void onOrientationChanged(int orientation) {
980 // We keep the last known orientation. So if the user first orient
981 // the camera then point the camera to floor or sky, we still have
982 // the correct orientation.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800983 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
984 return;
985 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700986 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800987
988 // Show the toast after getting the first orientation changed.
Angus Kong13e87c42013-11-25 10:02:47 -0800989 if (mHandler.hasMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST)) {
990 mHandler.removeMessages(MSG_SHOW_TAP_TO_FOCUS_TOAST);
Michael Kolb8872c232013-01-29 10:33:22 -0800991 showTapToFocusToast();
992 }
993 }
994
995 @Override
Angus Kong20fad242013-11-11 18:23:46 -0800996 public void onCameraAvailable(CameraProxy cameraProxy) {
997 if (mPaused) {
998 return;
999 }
1000 mCameraDevice = cameraProxy;
1001
Erin Dahlgren357b7672013-11-20 17:38:14 -08001002 resetExposureCompensation();
Angus Kong20fad242013-11-11 18:23:46 -08001003 initializeCapabilities();
1004
1005 // Reset zoom value index.
1006 mZoomValue = 0;
1007 if (mFocusManager == null) {
1008 initializeFocusManager();
1009 }
1010 mFocusManager.setParameters(mInitialParams);
1011
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001012 // Do camera parameter dependent initialization.
Angus Kong20fad242013-11-11 18:23:46 -08001013 mParameters = mCameraDevice.getParameters();
1014 setCameraParameters(UPDATE_PARAM_ALL);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001015 // Set a listener which updates camera parameters based
1016 // on changed settings.
1017 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren1648c362014-01-06 15:06:04 -08001018 settingsManager.addListener(this);
Angus Kong20fad242013-11-11 18:23:46 -08001019 mCameraPreviewParamsReady = true;
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001020
Angus Kong20fad242013-11-11 18:23:46 -08001021 startPreview();
1022
1023 onCameraOpened();
1024 }
1025
1026 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001027 public void onCaptureCancelled() {
1028 mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
1029 mActivity.finish();
Michael Kolb8872c232013-01-29 10:33:22 -08001030 }
1031
Michael Kolbd6954f32013-03-08 20:43:01 -08001032 @Override
1033 public void onCaptureRetake() {
Sascha Haeberlingf2994f02014-01-23 19:55:01 -08001034 if (mPaused) {
1035 return;
1036 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001037 mUI.hidePostCaptureAlert();
Michael Kolb8872c232013-01-29 10:33:22 -08001038 setupPreview();
1039 }
1040
Michael Kolbd6954f32013-03-08 20:43:01 -08001041 @Override
1042 public void onCaptureDone() {
Michael Kolb8872c232013-01-29 10:33:22 -08001043 if (mPaused) {
1044 return;
1045 }
1046
1047 byte[] data = mJpegImageData;
1048
1049 if (mCropValue == null) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001050 // First handle the no crop case -- just return the value. If the
Michael Kolb8872c232013-01-29 10:33:22 -08001051 // caller specifies a "save uri" then write the data to its
1052 // stream. Otherwise, pass back a scaled down version of the bitmap
1053 // directly in the extras.
1054 if (mSaveUri != null) {
1055 OutputStream outputStream = null;
1056 try {
1057 outputStream = mContentResolver.openOutputStream(mSaveUri);
1058 outputStream.write(data);
1059 outputStream.close();
1060
1061 mActivity.setResultEx(Activity.RESULT_OK);
1062 mActivity.finish();
1063 } catch (IOException ex) {
1064 // ignore exception
1065 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001066 CameraUtil.closeSilently(outputStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001067 }
1068 } else {
Angus Kong0d00a892013-03-26 11:40:40 -07001069 ExifInterface exif = Exif.getExif(data);
1070 int orientation = Exif.getOrientation(exif);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001071 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
1072 bitmap = CameraUtil.rotate(bitmap, orientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001073 mActivity.setResultEx(Activity.RESULT_OK,
1074 new Intent("inline-data").putExtra("data", bitmap));
1075 mActivity.finish();
1076 }
1077 } else {
1078 // Save the image to a temp file and invoke the cropper
1079 Uri tempUri = null;
1080 FileOutputStream tempStream = null;
1081 try {
1082 File path = mActivity.getFileStreamPath(sTempCropFilename);
1083 path.delete();
1084 tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1085 tempStream.write(data);
1086 tempStream.close();
1087 tempUri = Uri.fromFile(path);
1088 } catch (FileNotFoundException ex) {
1089 mActivity.setResultEx(Activity.RESULT_CANCELED);
1090 mActivity.finish();
1091 return;
1092 } catch (IOException ex) {
1093 mActivity.setResultEx(Activity.RESULT_CANCELED);
1094 mActivity.finish();
1095 return;
1096 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001097 CameraUtil.closeSilently(tempStream);
Michael Kolb8872c232013-01-29 10:33:22 -08001098 }
1099
1100 Bundle newExtras = new Bundle();
1101 if (mCropValue.equals("circle")) {
1102 newExtras.putString("circleCrop", "true");
1103 }
1104 if (mSaveUri != null) {
1105 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1106 } else {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001107 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001108 }
1109 if (mActivity.isSecureCamera()) {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001110 newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001111 }
1112
Sascha Haeberling37f36112013-08-06 14:31:52 -07001113 // TODO: Share this constant.
Sascha Haeberling8e963a52013-08-06 11:43:02 -07001114 final String CROP_ACTION = "com.android.camera.action.CROP";
1115 Intent cropIntent = new Intent(CROP_ACTION);
Michael Kolb8872c232013-01-29 10:33:22 -08001116
1117 cropIntent.setData(tempUri);
1118 cropIntent.putExtras(newExtras);
1119
1120 mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1121 }
1122 }
1123
Michael Kolb8872c232013-01-29 10:33:22 -08001124 @Override
1125 public void onShutterButtonFocus(boolean pressed) {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001126 if (mPaused || (mCameraState == SNAPSHOT_IN_PROGRESS)
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001127 || (mCameraState == PREVIEW_STOPPED)) {
1128 return;
1129 }
Michael Kolb8872c232013-01-29 10:33:22 -08001130
1131 // Do not do focus if there is not enough storage.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001132 if (pressed && !canTakePicture()) {
1133 return;
1134 }
Michael Kolb8872c232013-01-29 10:33:22 -08001135
1136 if (pressed) {
Michael Kolb8872c232013-01-29 10:33:22 -08001137 mFocusManager.onShutterDown();
1138 } else {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001139 mFocusManager.onShutterUp();
Michael Kolb8872c232013-01-29 10:33:22 -08001140 }
1141 }
1142
1143 @Override
1144 public void onShutterButtonClick() {
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001145 if (mPaused || (mCameraState == SWITCHING_CAMERA)
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001146 || (mCameraState == PREVIEW_STOPPED)) {
1147 return;
1148 }
Michael Kolb8872c232013-01-29 10:33:22 -08001149
1150 // Do not take the picture if there is not enough storage.
Angus Kong2dcc0a92013-09-25 13:00:08 -07001151 if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Michael Kolb8872c232013-01-29 10:33:22 -08001152 Log.i(TAG, "Not enough space or storage not ready. remaining="
Angus Kong2dcc0a92013-09-25 13:00:08 -07001153 + mActivity.getStorageSpaceBytes());
Michael Kolb8872c232013-01-29 10:33:22 -08001154 return;
1155 }
1156 Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1157
Angus Kongb50b5cb2013-08-09 14:55:20 -07001158 if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
Doris Liu6432cd62013-06-13 17:20:31 -07001159 mUI.setSwipingEnabled(false);
Doris Liu9cdfe002013-04-16 09:50:56 -07001160 }
Michael Kolb8872c232013-01-29 10:33:22 -08001161 // If the user wants to do a snapshot while the previous one is still
1162 // in progress, remember the fact and do it after we finish the previous
1163 // one and re-start the preview. Snapshot in progress also includes the
1164 // state that autofocus is focusing and a picture will be taken when
1165 // focus callback arrives.
1166 if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1167 && !mIsImageCaptureIntent) {
1168 mSnapshotOnIdle = true;
1169 return;
1170 }
1171
Doris Liuf9e4f8f2013-12-04 18:04:22 -08001172 mSnapshotOnIdle = false;
1173 mFocusManager.doSnap();
Michael Kolb8872c232013-01-29 10:33:22 -08001174 }
1175
Andy Huibersdef975d2013-11-22 09:13:39 -08001176 private void onResumeTasks() {
1177 Log.v(TAG, "Executing onResumeTasks.");
Angus Kong20fad242013-11-11 18:23:46 -08001178 mActivity.getCameraProvider().requestCamera(mCameraId);
1179
Michael Kolb8872c232013-01-29 10:33:22 -08001180 mJpegPictureCallbackTime = 0;
1181 mZoomValue = 0;
Angus Kong20fad242013-11-11 18:23:46 -08001182
1183 mOnResumeTime = SystemClock.uptimeMillis();
1184 checkDisplayRotation();
Michael Kolb8872c232013-01-29 10:33:22 -08001185
1186 // If first time initialization is not finished, put it in the
1187 // message queue.
1188 if (!mFirstTimeInitialized) {
Angus Kong13e87c42013-11-25 10:02:47 -08001189 mHandler.sendEmptyMessage(MSG_FIRST_TIME_INIT);
Michael Kolb8872c232013-01-29 10:33:22 -08001190 } else {
1191 initializeSecondTime();
1192 }
Michael Kolb8872c232013-01-29 10:33:22 -08001193
Bobby Georgescu0a7dd572013-03-12 22:45:17 -07001194 UsageStatistics.onContentViewChanged(
1195 UsageStatistics.COMPONENT_CAMERA, "PhotoModule");
Angus Kong0d00a892013-03-26 11:40:40 -07001196
1197 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1198 if (gsensor != null) {
1199 mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
1200 }
1201
1202 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1203 if (msensor != null) {
1204 mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
1205 }
Michael Kolb8872c232013-01-29 10:33:22 -08001206 }
1207
Angus Kongc4e66562013-11-22 23:03:21 -08001208 /**
1209 * The focus manager is the first UI related element to get initialized,
1210 * and it requires the RenderOverlay, so initialize it here
1211 */
1212 private void initializeFocusManager() {
1213 // Create FocusManager object. startPreview needs it.
1214 // if mFocusManager not null, reuse it
1215 // otherwise create a new instance
1216 if (mFocusManager != null) {
1217 mFocusManager.removeMessages();
1218 } else {
Angus Kongd74e6a12014-01-07 11:29:44 -08001219 CameraInfo info = mAppController.getCameraProvider().getCameraInfo()[mCameraId];
Angus Kongc4e66562013-11-22 23:03:21 -08001220 mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
1221 String[] defaultFocusModes = mActivity.getResources().getStringArray(
1222 R.array.pref_camera_focusmode_default_array);
Erin Dahlgren357b7672013-11-20 17:38:14 -08001223 mFocusManager = new FocusOverlayManager(mActivity.getSettingsManager(),
1224 defaultFocusModes,
Angus Kongc4e66562013-11-22 23:03:21 -08001225 mInitialParams, this, mMirror,
Doris Liu482de022013-12-18 19:18:16 -08001226 mActivity.getMainLooper(), mUI.getFocusUI());
Angus Kongc4e66562013-11-22 23:03:21 -08001227 }
Doris Liu482de022013-12-18 19:18:16 -08001228 mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
Angus Kong20fad242013-11-11 18:23:46 -08001229 }
1230
1231 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001232 public void resume() {
1233 mPaused = false;
Doris Liu482de022013-12-18 19:18:16 -08001234 if (mFocusManager != null) {
Doris Liu15b99612013-12-21 11:32:28 -08001235 // If camera is not open when resume is called, focus manager will not
1236 // be initialized yet, in which case it will start listening to
1237 // preview area size change later in the initialization.
Doris Liu482de022013-12-18 19:18:16 -08001238 mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
1239 }
Doris Liu59401042014-01-14 17:51:32 -08001240
1241 if (mUI.getPreviewAreaSizeChangedListener() != null) {
1242 mAppController.addPreviewAreaSizeChangedListener(
1243 mUI.getPreviewAreaSizeChangedListener());
1244 }
1245
Angus Kongc4e66562013-11-22 23:03:21 -08001246 // Add delay on resume from lock screen only, in order to to speed up
1247 // the onResume --> onPause --> onResume cycle from lock screen.
1248 // Don't do always because letting go of thread can cause delay.
1249 String action = mActivity.getIntent().getAction();
1250 if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
1251 || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
1252 Log.v(TAG, "On resume, from lock screen.");
1253 // Note: onPauseAfterSuper() will delete this runnable, so we will
1254 // at most have 1 copy queued up.
1255 mHandler.postDelayed(new Runnable() {
Sameer Padala2c8cc452013-11-05 18:49:12 -08001256 @Override
Angus Kongc4e66562013-11-22 23:03:21 -08001257 public void run() {
1258 onResumeTasks();
1259 }
1260 }, ON_RESUME_TASKS_DELAY_MSEC);
1261 } else {
1262 Log.v(TAG, "On resume.");
1263 onResumeTasks();
1264 }
Sascha Haeberlingf2994f02014-01-23 19:55:01 -08001265 getServices().getRemoteShutterListener().onModuleReady(this);
Angus Kongc4e66562013-11-22 23:03:21 -08001266 }
1267
1268 @Override
1269 public void pause() {
Sascha Haeberlingf2994f02014-01-23 19:55:01 -08001270 getServices().getRemoteShutterListener().onModuleExit();
Michael Kolb8872c232013-01-29 10:33:22 -08001271 mPaused = true;
Angus Kong0d00a892013-03-26 11:40:40 -07001272 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
1273 if (gsensor != null) {
1274 mSensorManager.unregisterListener(this, gsensor);
1275 }
1276
1277 Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
1278 if (msensor != null) {
1279 mSensorManager.unregisterListener(this, msensor);
1280 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001281
Michael Kolb8872c232013-01-29 10:33:22 -08001282 // Reset the focus first. Camera CTS does not guarantee that
1283 // cancelAutoFocus is allowed after preview stops.
1284 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1285 mCameraDevice.cancelAutoFocus();
1286 }
Andy Huibersdef975d2013-11-22 09:13:39 -08001287
Erin Dahlgrenb09b53e2013-11-06 11:57:51 -08001288 // If the camera has not been opened asynchronously yet,
1289 // and startPreview hasn't been called, then this is a no-op.
1290 // (e.g. onResume -> onPause -> onResume).
Michael Kolb8872c232013-01-29 10:33:22 -08001291 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001292
Angus Kongce5480e2013-01-29 17:43:48 -08001293 mNamedImages = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001294
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001295 if (mLocationManager != null) {
1296 mLocationManager.recordLocation(false);
1297 }
Michael Kolb8872c232013-01-29 10:33:22 -08001298
1299 // If we are in an image capture intent and has taken
1300 // a picture, we just clear it in onPause.
1301 mJpegImageData = null;
1302
Angus Kongdcccc512013-08-08 17:06:03 -07001303 // Remove the messages and runnables in the queue.
1304 mHandler.removeCallbacksAndMessages(null);
Michael Kolb8872c232013-01-29 10:33:22 -08001305
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001306 closeCamera();
Angus Kong13e87c42013-11-25 10:02:47 -08001307 mActivity.enableKeepScreenOn(false);
Michael Kolbd6954f32013-03-08 20:43:01 -08001308 mUI.onPause();
1309
Michael Kolb8872c232013-01-29 10:33:22 -08001310 mPendingSwitchCameraId = -1;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001311 if (mFocusManager != null) {
1312 mFocusManager.removeMessages();
Angus Kong86d36312013-01-31 18:22:44 -08001313 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001314 getServices().getMemoryManager().removeListener(this);
Doris Liu482de022013-12-18 19:18:16 -08001315 mAppController.removePreviewAreaSizeChangedListener(mFocusManager);
Doris Liu59401042014-01-14 17:51:32 -08001316 if (mUI.getPreviewAreaSizeChangedListener() != null) {
1317 mAppController.removePreviewAreaSizeChangedListener(
1318 mUI.getPreviewAreaSizeChangedListener());
1319 }
Erin Dahlgren1648c362014-01-06 15:06:04 -08001320
1321 SettingsManager settingsManager = mActivity.getSettingsManager();
1322 settingsManager.removeListener(this);
Michael Kolb8872c232013-01-29 10:33:22 -08001323 }
1324
Angus Kong20fad242013-11-11 18:23:46 -08001325 @Override
1326 public void destroy() {
1327 // TODO: implement this.
1328 }
1329
1330 @Override
1331 public void onPreviewSizeChanged(int width, int height) {
1332 // TODO: implement this.
1333 }
1334
1335 @Override
Angus Kong2f0e4a32013-12-03 10:02:35 -08001336 public void onLayoutOrientationChanged(boolean isLandscape) {
Michael Kolb8872c232013-01-29 10:33:22 -08001337 setDisplayOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001338 }
1339
1340 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001341 public void updateCameraOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001342 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001343 setDisplayOrientation();
1344 }
1345 }
1346
Michael Kolb8872c232013-01-29 10:33:22 -08001347 private boolean canTakePicture() {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001348 return isCameraIdle()
1349 && (mActivity.getStorageSpaceBytes() > Storage.LOW_STORAGE_THRESHOLD_BYTES);
Michael Kolb8872c232013-01-29 10:33:22 -08001350 }
1351
1352 @Override
1353 public void autoFocus() {
1354 mFocusStartTime = System.currentTimeMillis();
Angus Kong9ef99252013-07-18 18:04:19 -07001355 mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001356 setCameraState(FOCUSING);
1357 }
1358
1359 @Override
1360 public void cancelAutoFocus() {
1361 mCameraDevice.cancelAutoFocus();
1362 setCameraState(IDLE);
1363 setCameraParameters(UPDATE_PARAM_PREFERENCE);
1364 }
1365
Michael Kolb8872c232013-01-29 10:33:22 -08001366 @Override
1367 public void onSingleTapUp(View view, int x, int y) {
Doris Liu482de022013-12-18 19:18:16 -08001368 if (mPaused || mCameraDevice == null || !mFirstTimeInitialized
1369 || mCameraState == SNAPSHOT_IN_PROGRESS
1370 || mCameraState == SWITCHING_CAMERA
1371 || mCameraState == PREVIEW_STOPPED) {
1372 return;
1373 }
1374
1375 // Check if metering area or focus area is supported.
Doris Liu15b99612013-12-21 11:32:28 -08001376 if (!mFocusAreaSupported && !mMeteringAreaSupported) {
1377 return;
1378 }
Doris Liu482de022013-12-18 19:18:16 -08001379 mFocusManager.onSingleTapUp(x, y);
Michael Kolb8872c232013-01-29 10:33:22 -08001380 }
1381
1382 @Override
1383 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -08001384 return mUI.onBackPressed();
Michael Kolb8872c232013-01-29 10:33:22 -08001385 }
1386
1387 @Override
1388 public boolean onKeyDown(int keyCode, KeyEvent event) {
1389 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001390 case KeyEvent.KEYCODE_VOLUME_UP:
1391 case KeyEvent.KEYCODE_VOLUME_DOWN:
1392 case KeyEvent.KEYCODE_FOCUS:
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001393 if (/* TODO: mActivity.isInCameraApp() && */mFirstTimeInitialized) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001394 if (event.getRepeatCount() == 0) {
1395 onShutterButtonFocus(true);
1396 }
1397 return true;
1398 }
1399 return false;
1400 case KeyEvent.KEYCODE_CAMERA:
1401 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1402 onShutterButtonClick();
Michael Kolb8872c232013-01-29 10:33:22 -08001403 }
1404 return true;
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001405 case KeyEvent.KEYCODE_DPAD_CENTER:
1406 // If we get a dpad center event without any focused view, move
1407 // the focus to the shutter button and press it.
1408 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1409 // Start auto-focus immediately to reduce shutter lag. After
1410 // the shutter button gets the focus, onShutterButtonFocus()
1411 // will be called again but it is fine.
1412 onShutterButtonFocus(true);
1413 mUI.pressShutterButton();
1414 }
1415 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001416 }
1417 return false;
1418 }
1419
1420 @Override
1421 public boolean onKeyUp(int keyCode, KeyEvent event) {
1422 switch (keyCode) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001423 case KeyEvent.KEYCODE_VOLUME_UP:
1424 case KeyEvent.KEYCODE_VOLUME_DOWN:
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001425 if (/* mActivity.isInCameraApp() && */mFirstTimeInitialized) {
Dan Aminzade92ae10e2013-08-13 14:44:25 -07001426 onShutterButtonClick();
1427 return true;
1428 }
1429 return false;
1430 case KeyEvent.KEYCODE_FOCUS:
1431 if (mFirstTimeInitialized) {
1432 onShutterButtonFocus(false);
1433 }
Michael Kolb8872c232013-01-29 10:33:22 -08001434 return true;
Michael Kolb8872c232013-01-29 10:33:22 -08001435 }
1436 return false;
1437 }
1438
Michael Kolb8872c232013-01-29 10:33:22 -08001439 private void closeCamera() {
1440 if (mCameraDevice != null) {
1441 mCameraDevice.setZoomChangeListener(null);
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001442 mCameraDevice.setFaceDetectionCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001443 mCameraDevice.setErrorCallback(null);
Ruben Brunk59147832013-11-05 15:53:28 -08001444
Michael Kolb8872c232013-01-29 10:33:22 -08001445 mFaceDetectionStarted = false;
Angus Kong20fad242013-11-11 18:23:46 -08001446 mActivity.getCameraProvider().releaseCamera(mCameraDevice.getCameraId());
Michael Kolb8872c232013-01-29 10:33:22 -08001447 mCameraDevice = null;
1448 setCameraState(PREVIEW_STOPPED);
1449 mFocusManager.onCameraReleased();
1450 }
1451 }
1452
1453 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001454 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1455 mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001456 mCameraDisplayOrientation = mDisplayOrientation;
Michael Kolbd6954f32013-03-08 20:43:01 -08001457 mUI.setDisplayOrientation(mDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001458 if (mFocusManager != null) {
1459 mFocusManager.setDisplayOrientation(mDisplayOrientation);
1460 }
Doris Liu6432cd62013-06-13 17:20:31 -07001461 // Change the camera display orientation
1462 if (mCameraDevice != null) {
1463 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1464 }
Michael Kolb8872c232013-01-29 10:33:22 -08001465 }
1466
Sascha Haeberlingddef7792013-08-13 14:41:10 -07001467 /** Only called by UI thread. */
Michael Kolb8872c232013-01-29 10:33:22 -08001468 private void setupPreview() {
1469 mFocusManager.resetTouchFocus();
1470 startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001471 }
1472
Angus Kong20fad242013-11-11 18:23:46 -08001473 /**
1474 * Returns whether we can/should start the preview or not.
1475 */
1476 private boolean checkPreviewPreconditions() {
1477 if (mPaused) {
1478 return false;
Angus Kongdcccc512013-08-08 17:06:03 -07001479 }
Michael Kolb8872c232013-01-29 10:33:22 -08001480
Angus Kong20fad242013-11-11 18:23:46 -08001481 if (mCameraDevice == null) {
1482 Log.w(TAG, "startPreview: camera device not ready yet.");
1483 return false;
1484 }
1485
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001486 SurfaceTexture st = mUI.getSurfaceTexture();
1487 if (st == null) {
1488 Log.w(TAG, "startPreview: surfaceTexture is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001489 return false;
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001490 }
1491
1492 if (!mCameraPreviewParamsReady) {
1493 Log.w(TAG, "startPreview: parameters for preview is not ready.");
Angus Kong20fad242013-11-11 18:23:46 -08001494 return false;
1495 }
1496 return true;
1497 }
1498
1499 /**
1500 * The start/stop preview should only run on the UI thread.
1501 */
1502 private void startPreview() {
1503 if (!checkPreviewPreconditions()) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001504 return;
1505 }
Angus Kong20fad242013-11-11 18:23:46 -08001506
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001507 mCameraDevice.setErrorCallback(mErrorCallback);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001508 // ICS camera frameworks has a bug. Face detection state is not cleared
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001509 // after taking a picture. Stop the preview to work around it. The bug
1510 // was fixed in JB.
1511 if (mCameraState != PREVIEW_STOPPED) {
1512 stopPreview();
1513 }
1514
1515 setDisplayOrientation();
1516
1517 if (!mSnapshotOnIdle) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001518 // If the focus mode is continuous autofocus, call cancelAutoFocus
1519 // to resume it because it may have been paused by autoFocus call.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001520 String focusMode = mFocusManager.getFocusMode();
1521 if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(focusMode)) {
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001522 mCameraDevice.cancelAutoFocus();
Michael Kolb8872c232013-01-29 10:33:22 -08001523 }
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001524 mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1525 }
1526 setCameraParameters(UPDATE_PARAM_ALL);
1527 // Let UI set its expected aspect ratio
Angus Kong20fad242013-11-11 18:23:46 -08001528 mCameraDevice.setPreviewTexture(mUI.getSurfaceTexture());
Michael Kolb8872c232013-01-29 10:33:22 -08001529
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001530 Log.v(TAG, "startPreview");
1531 mCameraDevice.startPreview();
Angus Kong20fad242013-11-11 18:23:46 -08001532
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001533 mFocusManager.onPreviewStarted();
1534 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001535
Erin Dahlgrendc282e12013-11-12 09:39:08 -08001536 if (mSnapshotOnIdle) {
1537 mHandler.post(mDoSnapRunnable);
Michael Kolb8872c232013-01-29 10:33:22 -08001538 }
1539 }
1540
Michael Kolbd6954f32013-03-08 20:43:01 -08001541 @Override
1542 public void stopPreview() {
Michael Kolb8872c232013-01-29 10:33:22 -08001543 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
1544 Log.v(TAG, "stopPreview");
1545 mCameraDevice.stopPreview();
1546 mFaceDetectionStarted = false;
1547 }
1548 setCameraState(PREVIEW_STOPPED);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001549 if (mFocusManager != null) {
1550 mFocusManager.onPreviewStopped();
1551 }
Sameer Padala2c8cc452013-11-05 18:49:12 -08001552 stopSmartCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001553 }
1554
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001555 @Override
Erin Dahlgren1648c362014-01-06 15:06:04 -08001556 public void onSettingChanged(SettingsManager settingsManager, int id) {
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001557 switch (id) {
1558 case SettingsManager.SETTING_FLASH_MODE: {
1559 updateParametersFlashMode();
1560 break;
1561 }
1562 case SettingsManager.SETTING_PICTURE_SIZE: {
1563 updateParametersPictureSize();
1564 break;
1565 }
1566 case SettingsManager.SETTING_RECORD_LOCATION: {
1567 SettingsController settingsController = mActivity.getSettingsController();
1568 settingsController.syncLocationManager();
1569 break;
1570 }
1571 default: {
1572 // Do nothing.
1573 }
1574 }
Erin Dahlgren1648c362014-01-06 15:06:04 -08001575
1576 if (mCameraDevice != null) {
1577 mCameraDevice.setParameters(mParameters);
1578 }
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001579 }
1580
Michael Kolb8872c232013-01-29 10:33:22 -08001581 private void updateCameraParametersInitialize() {
1582 // Reset preview frame rate to the maximum because it may be lowered by
1583 // video camera application.
ztenghui16a35202013-09-23 11:35:36 -07001584 int[] fpsRange = CameraUtil.getPhotoPreviewFpsRange(mParameters);
1585 if (fpsRange != null && fpsRange.length > 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001586 mParameters.setPreviewFpsRange(
1587 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1588 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
Michael Kolb8872c232013-01-29 10:33:22 -08001589 }
1590
Angus Kongb50b5cb2013-08-09 14:55:20 -07001591 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);
Michael Kolb8872c232013-01-29 10:33:22 -08001592
1593 // Disable video stabilization. Convenience methods not available in API
1594 // level <= 14
1595 String vstabSupported = mParameters.get("video-stabilization-supported");
1596 if ("true".equals(vstabSupported)) {
1597 mParameters.set("video-stabilization", "false");
1598 }
1599 }
1600
1601 private void updateCameraParametersZoom() {
1602 // Set zoom.
1603 if (mParameters.isZoomSupported()) {
1604 mParameters.setZoom(mZoomValue);
1605 }
1606 }
1607
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001608 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001609 private void setAutoExposureLockIfSupported() {
1610 if (mAeLockSupported) {
1611 mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
1612 }
1613 }
1614
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001615 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001616 private void setAutoWhiteBalanceLockIfSupported() {
1617 if (mAwbLockSupported) {
1618 mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
1619 }
1620 }
1621
Michael Kolb8872c232013-01-29 10:33:22 -08001622 private void setFocusAreasIfSupported() {
1623 if (mFocusAreaSupported) {
1624 mParameters.setFocusAreas(mFocusManager.getFocusAreas());
1625 }
1626 }
1627
Michael Kolb8872c232013-01-29 10:33:22 -08001628 private void setMeteringAreasIfSupported() {
1629 if (mMeteringAreaSupported) {
Michael Kolb8872c232013-01-29 10:33:22 -08001630 mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
1631 }
1632 }
1633
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001634 private void updateCameraParametersPreference() {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001635 SettingsManager settingsManager = mActivity.getSettingsManager();
1636
Michael Kolb8872c232013-01-29 10:33:22 -08001637 setAutoExposureLockIfSupported();
1638 setAutoWhiteBalanceLockIfSupported();
1639 setFocusAreasIfSupported();
1640 setMeteringAreasIfSupported();
1641
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001642 // Initialize focus mode.
Michael Kolbd3253f22013-07-12 11:36:47 -07001643 mFocusManager.overrideFocusMode(null);
1644 mParameters.setFocusMode(mFocusManager.getFocusMode());
1645
Michael Kolb8872c232013-01-29 10:33:22 -08001646 // Set picture size.
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001647 updateParametersPictureSize();
1648
1649 // Set JPEG quality.
1650 updateParametersPictureQuality();
1651
1652 // For the following settings, we need to check if the settings are
1653 // still supported by latest driver, if not, ignore the settings.
1654
1655 // Set exposure compensation
1656 updateParametersExposureCompensation();
1657
1658 // Set the scene mode: also sets flash and white balance.
1659 updateParametersSceneMode();
1660
1661 if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
1662 updateAutoFocusMoveCallback();
1663 }
1664 }
1665
1666 private void updateParametersPictureSize() {
1667 SettingsManager settingsManager = mActivity.getSettingsManager();
1668
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001669 String pictureSize = settingsManager.get(SettingsManager.SETTING_PICTURE_SIZE);
Michael Kolb8872c232013-01-29 10:33:22 -08001670 if (pictureSize == null) {
Erin Dahlgren357b7672013-11-20 17:38:14 -08001671 //TODO: deprecate CameraSettings.
1672 CameraSettings.initialCameraPictureSize(
1673 mActivity, mParameters, settingsManager);
Michael Kolb8872c232013-01-29 10:33:22 -08001674 } else {
1675 List<Size> supported = mParameters.getSupportedPictureSizes();
1676 CameraSettings.setCameraPictureSize(
1677 pictureSize, supported, mParameters);
1678 }
1679 Size size = mParameters.getPictureSize();
1680
1681 // Set a preview size that is closest to the viewfinder height and has
1682 // the right aspect ratio.
1683 List<Size> sizes = mParameters.getSupportedPreviewSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001684 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
Michael Kolb8872c232013-01-29 10:33:22 -08001685 (double) size.width / size.height);
1686 Size original = mParameters.getPreviewSize();
1687 if (!original.equals(optimalSize)) {
1688 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
Doris Liu6432cd62013-06-13 17:20:31 -07001689
Michael Kolb8872c232013-01-29 10:33:22 -08001690 // Zoom related settings will be changed for different preview
1691 // sizes, so set and read the parameters to get latest values
Michael Kolb4a4d4ef2013-05-30 08:35:26 -07001692 if (mHandler.getLooper() == Looper.myLooper()) {
1693 // On UI thread only, not when camera starts up
1694 setupPreview();
1695 } else {
1696 mCameraDevice.setParameters(mParameters);
1697 }
Michael Kolb8872c232013-01-29 10:33:22 -08001698 mParameters = mCameraDevice.getParameters();
1699 }
Doris Liu95405742013-11-05 15:25:26 -08001700
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001701 if (optimalSize.width != 0 && optimalSize.height != 0) {
Doris Liu95405742013-11-05 15:25:26 -08001702 mUI.updatePreviewAspectRatio((float) optimalSize.width
1703 / (float) optimalSize.height);
1704 }
Michael Kolb8872c232013-01-29 10:33:22 -08001705 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001706 }
Michael Kolb8872c232013-01-29 10:33:22 -08001707
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001708 private void updateParametersPictureQuality() {
Michael Kolb8872c232013-01-29 10:33:22 -08001709 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
1710 CameraProfile.QUALITY_HIGH);
1711 mParameters.setJpegQuality(jpegQuality);
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001712 }
Michael Kolb8872c232013-01-29 10:33:22 -08001713
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001714 private void updateParametersExposureCompensation() {
1715 SettingsManager settingsManager = mActivity.getSettingsManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001716
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001717 int value = Integer.parseInt(settingsManager.get(SettingsManager.SETTING_EXPOSURE));
Michael Kolb8872c232013-01-29 10:33:22 -08001718 int max = mParameters.getMaxExposureCompensation();
1719 int min = mParameters.getMinExposureCompensation();
1720 if (value >= min && value <= max) {
1721 mParameters.setExposureCompensation(value);
1722 } else {
1723 Log.w(TAG, "invalid exposure range: " + value);
1724 }
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001725 }
1726
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001727 private void updateParametersSceneMode() {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001728 SettingsManager settingsManager = mActivity.getSettingsManager();
1729
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001730 mSceneMode = settingsManager.get(SettingsManager.SETTING_SCENE_MODE);
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001731 if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
1732 if (!mParameters.getSceneMode().equals(mSceneMode)) {
1733 mParameters.setSceneMode(mSceneMode);
1734
1735 // Setting scene mode will change the settings of flash mode,
1736 // white balance, and focus mode. Here we read back the
1737 // parameters, so we can know those settings.
1738 mCameraDevice.setParameters(mParameters);
1739 mParameters = mCameraDevice.getParameters();
1740 }
1741 } else {
1742 mSceneMode = mParameters.getSceneMode();
1743 if (mSceneMode == null) {
1744 mSceneMode = Parameters.SCENE_MODE_AUTO;
1745 }
1746 }
1747
Michael Kolb8872c232013-01-29 10:33:22 -08001748 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1749 // Set flash mode.
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001750 updateParametersFlashMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001751
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001752 // Set white balance mode.
1753 updateParametersWhiteBalanceMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001754
1755 // Set focus mode.
1756 mFocusManager.overrideFocusMode(null);
1757 mParameters.setFocusMode(mFocusManager.getFocusMode());
1758 } else {
1759 mFocusManager.overrideFocusMode(mParameters.getFocusMode());
1760 }
Michael Kolb8872c232013-01-29 10:33:22 -08001761 }
1762
Erin Dahlgren7f0151d2014-01-02 16:08:12 -08001763 private void updateParametersFlashMode() {
1764 SettingsManager settingsManager = mActivity.getSettingsManager();
1765
1766 String flashMode = settingsManager.get(SettingsManager.SETTING_FLASH_MODE);
1767 List<String> supportedFlash = mParameters.getSupportedFlashModes();
1768 if (CameraUtil.isSupported(flashMode, supportedFlash)) {
1769 mParameters.setFlashMode(flashMode);
1770 }
1771 }
1772
1773 private void updateParametersWhiteBalanceMode() {
1774 SettingsManager settingsManager = mActivity.getSettingsManager();
1775
1776 // Set white balance parameter.
1777 String whiteBalance = settingsManager.get(SettingsManager.SETTING_WHITE_BALANCE);
1778 if (CameraUtil.isSupported(whiteBalance,
1779 mParameters.getSupportedWhiteBalance())) {
1780 mParameters.setWhiteBalance(whiteBalance);
1781 }
1782 }
1783
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001784 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Michael Kolb8872c232013-01-29 10:33:22 -08001785 private void updateAutoFocusMoveCallback() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001786 if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
Angus Kong9ef99252013-07-18 18:04:19 -07001787 mCameraDevice.setAutoFocusMoveCallback(mHandler,
Angus Kong4f795b82013-09-16 14:25:35 -07001788 (CameraAFMoveCallback) mAutoFocusMoveCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001789 } else {
Angus Kong9ef99252013-07-18 18:04:19 -07001790 mCameraDevice.setAutoFocusMoveCallback(null, null);
Michael Kolb8872c232013-01-29 10:33:22 -08001791 }
1792 }
1793
1794 // We separate the parameters into several subsets, so we can update only
1795 // the subsets actually need updating. The PREFERENCE set needs extra
1796 // locking because the preference can be changed from GLThread as well.
1797 private void setCameraParameters(int updateSet) {
1798 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
1799 updateCameraParametersInitialize();
1800 }
1801
1802 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
1803 updateCameraParametersZoom();
1804 }
1805
1806 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
Erin Dahlgrenba6994d2013-12-12 16:04:38 -08001807 updateCameraParametersPreference();
Michael Kolb8872c232013-01-29 10:33:22 -08001808 }
1809
1810 mCameraDevice.setParameters(mParameters);
1811 }
1812
1813 // If the Camera is idle, update the parameters immediately, otherwise
1814 // accumulate them in mUpdateSet and update later.
1815 private void setCameraParametersWhenIdle(int additionalUpdateSet) {
1816 mUpdateSet |= additionalUpdateSet;
1817 if (mCameraDevice == null) {
1818 // We will update all the parameters when we open the device, so
1819 // we don't need to do anything now.
1820 mUpdateSet = 0;
1821 return;
1822 } else if (isCameraIdle()) {
1823 setCameraParameters(mUpdateSet);
Michael Kolbd6954f32013-03-08 20:43:01 -08001824 updateSceneMode();
Michael Kolb8872c232013-01-29 10:33:22 -08001825 mUpdateSet = 0;
1826 } else {
Angus Kong13e87c42013-11-25 10:02:47 -08001827 if (!mHandler.hasMessages(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
1828 mHandler.sendEmptyMessageDelayed(MSG_SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
Michael Kolb8872c232013-01-29 10:33:22 -08001829 }
1830 }
1831 }
1832
ztenghui7b265a62013-09-09 14:58:44 -07001833 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001834 public boolean isCameraIdle() {
Michael Kolb8872c232013-01-29 10:33:22 -08001835 return (mCameraState == IDLE) ||
1836 (mCameraState == PREVIEW_STOPPED) ||
1837 ((mFocusManager != null) && mFocusManager.isFocusCompleted()
1838 && (mCameraState != SWITCHING_CAMERA));
1839 }
1840
ztenghui7b265a62013-09-09 14:58:44 -07001841 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001842 public boolean isImageCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001843 String action = mActivity.getIntent().getAction();
1844 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
Angus Kong6a8e8a12013-07-19 14:55:07 -07001845 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
Michael Kolb8872c232013-01-29 10:33:22 -08001846 }
1847
1848 private void setupCaptureParams() {
1849 Bundle myExtras = mActivity.getIntent().getExtras();
1850 if (myExtras != null) {
1851 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1852 mCropValue = myExtras.getString("crop");
1853 }
1854 }
1855
Michael Kolb8872c232013-01-29 10:33:22 -08001856 public void onSharedPreferenceChanged() {
1857 // ignore the events after "onPause()"
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001858 if (mPaused) {
1859 return;
1860 }
Michael Kolb8872c232013-01-29 10:33:22 -08001861
Erin Dahlgren357b7672013-11-20 17:38:14 -08001862 SettingsController settingsController = mActivity.getSettingsController();
1863 settingsController.syncLocationManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001864
1865 setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
Michael Kolb8872c232013-01-29 10:33:22 -08001866 }
1867
Michael Kolb8872c232013-01-29 10:33:22 -08001868 private void showTapToFocusToast() {
1869 // TODO: Use a toast?
1870 new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
1871 // Clear the preference.
Erin Dahlgren357b7672013-11-20 17:38:14 -08001872 SettingsManager settingsManager = mActivity.getSettingsManager();
Erin Dahlgren635a4b82013-11-25 15:21:18 -08001873 settingsManager.setBoolean(
1874 SettingsManager.SETTING_CAMERA_FIRST_USE_HINT_SHOWN, false);
Michael Kolb8872c232013-01-29 10:33:22 -08001875 }
1876
1877 private void initializeCapabilities() {
1878 mInitialParams = mCameraDevice.getParameters();
Angus Kongb50b5cb2013-08-09 14:55:20 -07001879 mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
1880 mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
1881 mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
1882 mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
Angus Kongdcccc512013-08-08 17:06:03 -07001883 mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001884 CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
Michael Kolb8872c232013-01-29 10:33:22 -08001885 }
1886
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001887 private void setShutterEnabled(boolean enabled) {
1888 mShutterEnabled = enabled;
1889 mUI.enableShutter(enabled);
1890 }
1891
Marco Nelissen0744e4a2013-11-22 01:47:37 +00001892 // TODO: Remove this
Michael Kolb8872c232013-01-29 10:33:22 -08001893 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001894 public int onZoomChanged(int index) {
1895 // Not useful to change zoom value when the activity is paused.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001896 if (mPaused) {
1897 return index;
1898 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001899 mZoomValue = index;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001900 if (mParameters == null || mCameraDevice == null) {
1901 return index;
1902 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001903 // Set zoom parameters asynchronously
1904 mParameters.setZoom(mZoomValue);
Angus Kong36ed8672013-04-15 12:11:15 -07001905 mCameraDevice.setParameters(mParameters);
Michael Kolbd6954f32013-03-08 20:43:01 -08001906 Parameters p = mCameraDevice.getParameters();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001907 if (p != null) {
1908 return p.getZoom();
1909 }
Michael Kolbd6954f32013-03-08 20:43:01 -08001910 return index;
Angus Kongce5480e2013-01-29 17:43:48 -08001911 }
1912
1913 @Override
Michael Kolbd6954f32013-03-08 20:43:01 -08001914 public int getCameraState() {
1915 return mCameraState;
1916 }
1917
1918 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001919 public void onMemoryStateChanged(int state) {
1920 setShutterEnabled(state == MemoryManager.STATE_OK);
Angus Kongce5480e2013-01-29 17:43:48 -08001921 }
Angus Kong86d36312013-01-31 18:22:44 -08001922
1923 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001924 public void onLowMemory() {
1925 // Not much we can do in the photo module.
Angus Kong86d36312013-01-31 18:22:44 -08001926 }
Angus Kong0d00a892013-03-26 11:40:40 -07001927
1928 @Override
1929 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1930 }
1931
1932 @Override
1933 public void onSensorChanged(SensorEvent event) {
1934 int type = event.sensor.getType();
1935 float[] data;
1936 if (type == Sensor.TYPE_ACCELEROMETER) {
1937 data = mGData;
1938 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
1939 data = mMData;
1940 } else {
1941 // we should not be here.
1942 return;
1943 }
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001944 for (int i = 0; i < 3; i++) {
Angus Kong0d00a892013-03-26 11:40:40 -07001945 data[i] = event.values[i];
1946 }
1947 float[] orientation = new float[3];
1948 SensorManager.getRotationMatrix(mR, null, mGData, mMData);
1949 SensorManager.getOrientation(mR, orientation);
1950 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
1951 if (mHeading < 0) {
1952 mHeading += 360;
1953 }
Angus Kong0d00a892013-03-26 11:40:40 -07001954 }
Doris Liu6432cd62013-06-13 17:20:31 -07001955
Ruben Brunkd217ed02013-10-08 23:31:13 -07001956 // For debugging only.
1957 public void setDebugUri(Uri uri) {
1958 mDebugUri = uri;
1959 }
1960
1961 // For debugging only.
1962 private void saveToDebugUri(byte[] data) {
1963 if (mDebugUri != null) {
1964 OutputStream outputStream = null;
1965 try {
1966 outputStream = mContentResolver.openOutputStream(mDebugUri);
1967 outputStream.write(data);
1968 outputStream.close();
1969 } catch (IOException e) {
1970 Log.e(TAG, "Exception while writing debug jpeg file", e);
1971 } finally {
1972 CameraUtil.closeSilently(outputStream);
1973 }
1974 }
1975 }
Sascha Haeberlingf2994f02014-01-23 19:55:01 -08001976
1977 @Override
1978 public void onRemoteShutterPress() {
1979 capture();
1980 }
Michael Kolb8872c232013-01-29 10:33:22 -08001981}