diff options
Diffstat (limited to 'src/com/android/camera/NewPhotoModule.java')
-rw-r--r-- | src/com/android/camera/NewPhotoModule.java | 2005 |
1 files changed, 0 insertions, 2005 deletions
diff --git a/src/com/android/camera/NewPhotoModule.java b/src/com/android/camera/NewPhotoModule.java deleted file mode 100644 index 659e2be19..000000000 --- a/src/com/android/camera/NewPhotoModule.java +++ /dev/null @@ -1,2005 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.AlertDialog; -import android.content.ContentProviderClient; -import android.content.ContentResolver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences.Editor; -import android.content.res.Configuration; -import android.graphics.Bitmap; -import android.graphics.SurfaceTexture; -import android.hardware.Camera.CameraInfo; -import android.hardware.Camera.Parameters; -import android.hardware.Camera.PictureCallback; -import android.hardware.Camera.Size; -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; -import android.hardware.SensorManager; -import android.location.Location; -import android.media.CameraProfile; -import android.net.Uri; -import android.os.Bundle; -import android.os.ConditionVariable; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.MessageQueue; -import android.os.SystemClock; -import android.provider.MediaStore; -import android.util.Log; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.OrientationEventListener; -import android.view.SurfaceHolder; -import android.view.View; -import android.view.WindowManager; - -import com.android.camera.CameraManager.CameraProxy; -import com.android.camera.ui.CountDownView.OnCountDownFinishedListener; -import com.android.camera.ui.PopupManager; -import com.android.camera.ui.RotateTextToast; -import com.android.gallery3d.R; -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.exif.ExifInterface; -import com.android.gallery3d.exif.ExifTag; -import com.android.gallery3d.exif.Rational; -import com.android.gallery3d.filtershow.crop.CropExtras; -import com.android.gallery3d.filtershow.FilterShowActivity; -import com.android.gallery3d.util.UsageStatistics; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Formatter; -import java.util.List; - -public class NewPhotoModule - implements NewCameraModule, - PhotoController, - FocusOverlayManager.Listener, - CameraPreference.OnPreferenceChangedListener, - ShutterButton.OnShutterButtonListener, - MediaSaveService.Listener, - OnCountDownFinishedListener, - SensorEventListener { - - private static final String TAG = "CAM_PhotoModule"; - - // We number the request code from 1000 to avoid collision with Gallery. - private static final int REQUEST_CROP = 1000; - - private static final int SETUP_PREVIEW = 1; - private static final int FIRST_TIME_INIT = 2; - private static final int CLEAR_SCREEN_DELAY = 3; - private static final int SET_CAMERA_PARAMETERS_WHEN_IDLE = 4; - private static final int CHECK_DISPLAY_ROTATION = 5; - private static final int SHOW_TAP_TO_FOCUS_TOAST = 6; - private static final int SWITCH_CAMERA = 7; - private static final int SWITCH_CAMERA_START_ANIMATION = 8; - private static final int CAMERA_OPEN_DONE = 9; - private static final int START_PREVIEW_DONE = 10; - private static final int OPEN_CAMERA_FAIL = 11; - private static final int CAMERA_DISABLED = 12; - - // The subset of parameters we need to update in setCameraParameters(). - private static final int UPDATE_PARAM_INITIALIZE = 1; - private static final int UPDATE_PARAM_ZOOM = 2; - private static final int UPDATE_PARAM_PREFERENCE = 4; - private static final int UPDATE_PARAM_ALL = -1; - - // This is the timeout to keep the camera in onPause for the first time - // after screen on if the activity is started from secure lock screen. - private static final int KEEP_CAMERA_TIMEOUT = 1000; // ms - - // copied from Camera hierarchy - private NewCameraActivity mActivity; - private CameraProxy mCameraDevice; - private int mCameraId; - private Parameters mParameters; - private boolean mPaused; - - private NewPhotoUI mUI; - - // -1 means camera is not switching. - protected int mPendingSwitchCameraId = -1; - private boolean mOpenCameraFail; - private boolean mCameraDisabled; - - // When setCameraParametersWhenIdle() is called, we accumulate the subsets - // needed to be updated in mUpdateSet. - private int mUpdateSet; - - private static final int SCREEN_DELAY = 2 * 60 * 1000; - - private int mZoomValue; // The current zoom value. - - private Parameters mInitialParams; - private boolean mFocusAreaSupported; - private boolean mMeteringAreaSupported; - private boolean mAeLockSupported; - private boolean mAwbLockSupported; - private boolean mContinousFocusSupported; - - // The degrees of the device rotated clockwise from its natural orientation. - private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; - private ComboPreferences mPreferences; - - private static final String sTempCropFilename = "crop-temp"; - - private ContentProviderClient mMediaProviderClient; - private boolean mFaceDetectionStarted = false; - - // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true. - private String mCropValue; - private Uri mSaveUri; - - // We use a queue to generated names of the images to be used later - // when the image is ready to be saved. - private NamedImages mNamedImages; - - private Runnable mDoSnapRunnable = new Runnable() { - @Override - public void run() { - onShutterButtonClick(); - } - }; - - private final StringBuilder mBuilder = new StringBuilder(); - private final Formatter mFormatter = new Formatter(mBuilder); - private final Object[] mFormatterArgs = new Object[1]; - - /** - * An unpublished intent flag requesting to return as soon as capturing - * is completed. - * - * TODO: consider publishing by moving into MediaStore. - */ - private static final String EXTRA_QUICK_CAPTURE = - "android.intent.extra.quickCapture"; - - // The display rotation in degrees. This is only valid when mCameraState is - // not PREVIEW_STOPPED. - private int mDisplayRotation; - // The value for android.hardware.Camera.setDisplayOrientation. - private int mCameraDisplayOrientation; - // The value for UI components like indicators. - private int mDisplayOrientation; - // The value for android.hardware.Camera.Parameters.setRotation. - private int mJpegRotation; - private boolean mFirstTimeInitialized; - private boolean mIsImageCaptureIntent; - - private int mCameraState = PREVIEW_STOPPED; - private boolean mSnapshotOnIdle = false; - - private ContentResolver mContentResolver; - - private LocationManager mLocationManager; - - private final ShutterCallback mShutterCallback = new ShutterCallback(); - private final PostViewPictureCallback mPostViewPictureCallback = - new PostViewPictureCallback(); - private final RawPictureCallback mRawPictureCallback = - new RawPictureCallback(); - private final AutoFocusCallback mAutoFocusCallback = - new AutoFocusCallback(); - private final Object mAutoFocusMoveCallback = - ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK - ? new AutoFocusMoveCallback() - : null; - - private final CameraErrorCallback mErrorCallback = new CameraErrorCallback(); - - private long mFocusStartTime; - private long mShutterCallbackTime; - private long mPostViewPictureCallbackTime; - private long mRawPictureCallbackTime; - private long mJpegPictureCallbackTime; - private long mOnResumeTime; - private byte[] mJpegImageData; - - // These latency time are for the CameraLatency test. - public long mAutoFocusTime; - public long mShutterLag; - public long mShutterToPictureDisplayedTime; - public long mPictureDisplayedToJpegCallbackTime; - public long mJpegCallbackFinishTime; - public long mCaptureStartTime; - - // This handles everything about focus. - private FocusOverlayManager mFocusManager; - - private String mSceneMode; - - private final Handler mHandler = new MainHandler(); - private PreferenceGroup mPreferenceGroup; - - private boolean mQuickCapture; - private SensorManager mSensorManager; - private float[] mGData = new float[3]; - private float[] mMData = new float[3]; - private float[] mR = new float[16]; - private int mHeading = -1; - - CameraStartUpThread mCameraStartUpThread; - ConditionVariable mStartPreviewPrerequisiteReady = new ConditionVariable(); - - private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener = - new MediaSaveService.OnMediaSavedListener() { - @Override - public void onMediaSaved(Uri uri) { - if (uri != null) { - // TODO: Commenting out the line below for now. need to get it working - // mActivity.addSecureAlbumItemIfNeeded(false, uri); - Util.broadcastNewPicture(mActivity, uri); - } - } - }; - - // The purpose is not to block the main thread in onCreate and onResume. - private class CameraStartUpThread extends Thread { - private volatile boolean mCancelled; - - public void cancel() { - mCancelled = true; - interrupt(); - } - - public boolean isCanceled() { - return mCancelled; - } - - @Override - public void run() { - try { - // We need to check whether the activity is paused before long - // operations to ensure that onPause() can be done ASAP. - if (mCancelled) return; - mCameraDevice = Util.openCamera(mActivity, mCameraId); - mParameters = mCameraDevice.getParameters(); - // Wait until all the initialization needed by startPreview are - // done. - mStartPreviewPrerequisiteReady.block(); - - initializeCapabilities(); - if (mFocusManager == null) initializeFocusManager(); - if (mCancelled) return; - setCameraParameters(UPDATE_PARAM_ALL); - mHandler.sendEmptyMessage(CAMERA_OPEN_DONE); - if (mCancelled) return; - startPreview(); - mHandler.sendEmptyMessage(START_PREVIEW_DONE); - mOnResumeTime = SystemClock.uptimeMillis(); - mHandler.sendEmptyMessage(CHECK_DISPLAY_ROTATION); - } catch (CameraHardwareException e) { - mHandler.sendEmptyMessage(OPEN_CAMERA_FAIL); - } catch (CameraDisabledException e) { - mHandler.sendEmptyMessage(CAMERA_DISABLED); - } - } - } - - /** - * This Handler is used to post message back onto the main thread of the - * application - */ - private class MainHandler extends Handler { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case SETUP_PREVIEW: { - setupPreview(); - break; - } - - case CLEAR_SCREEN_DELAY: { - mActivity.getWindow().clearFlags( - WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - break; - } - - case FIRST_TIME_INIT: { - initializeFirstTime(); - break; - } - - case SET_CAMERA_PARAMETERS_WHEN_IDLE: { - setCameraParametersWhenIdle(0); - break; - } - - case CHECK_DISPLAY_ROTATION: { - // Set the display orientation if display rotation has changed. - // Sometimes this happens when the device is held upside - // down and camera app is opened. Rotation animation will - // take some time and the rotation value we have got may be - // wrong. Framework does not have a callback for this now. - if (Util.getDisplayRotation(mActivity) != mDisplayRotation) { - setDisplayOrientation(); - } - if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) { - mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100); - } - break; - } - - case SHOW_TAP_TO_FOCUS_TOAST: { - showTapToFocusToast(); - break; - } - - case SWITCH_CAMERA: { - switchCamera(); - break; - } - - case SWITCH_CAMERA_START_ANIMATION: { - // TODO: Need to revisit - // ((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera(); - break; - } - - case CAMERA_OPEN_DONE: { - onCameraOpened(); - break; - } - - case START_PREVIEW_DONE: { - onPreviewStarted(); - break; - } - - case OPEN_CAMERA_FAIL: { - mCameraStartUpThread = null; - mOpenCameraFail = true; - Util.showErrorAndFinish(mActivity, - R.string.cannot_connect_camera); - break; - } - - case CAMERA_DISABLED: { - mCameraStartUpThread = null; - mCameraDisabled = true; - Util.showErrorAndFinish(mActivity, - R.string.camera_disabled); - break; - } - } - } - } - - @Override - public void init(NewCameraActivity activity, View parent) { - mActivity = activity; - mUI = new NewPhotoUI(activity, this, parent); - mPreferences = new ComboPreferences(mActivity); - CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal()); - mCameraId = getPreferredCameraId(mPreferences); - - mContentResolver = mActivity.getContentResolver(); - - // To reduce startup time, open the camera and start the preview in - // another thread. - mCameraStartUpThread = new CameraStartUpThread(); - mCameraStartUpThread.start(); - - // Surface texture is from camera screen nail and startPreview needs it. - // This must be done before startPreview. - mIsImageCaptureIntent = isImageCaptureIntent(); - - mPreferences.setLocalId(mActivity, mCameraId); - CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); - // we need to reset exposure for the preview - resetExposureCompensation(); - // Starting the preview needs preferences, camera screen nail, and - // focus area indicator. - mStartPreviewPrerequisiteReady.open(); - - initializeControlByIntent(); - mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false); - mLocationManager = new LocationManager(mActivity, mUI); - mSensorManager = (SensorManager)(mActivity.getSystemService(Context.SENSOR_SERVICE)); - } - - private void initializeControlByIntent() { - mUI.initializeControlByIntent(); - if (mIsImageCaptureIntent) { - setupCaptureParams(); - } - } - - private void onPreviewStarted() { - mCameraStartUpThread = null; - setCameraState(IDLE); - startFaceDetection(); - locationFirstRun(); - } - - // Prompt the user to pick to record location for the very first run of - // camera only - private void locationFirstRun() { - if (RecordLocationPreference.isSet(mPreferences)) { - return; - } - if (mActivity.isSecureCamera()) return; - // Check if the back camera exists - int backCameraId = CameraHolder.instance().getBackCameraId(); - if (backCameraId == -1) { - // If there is no back camera, do not show the prompt. - return; - } - - new AlertDialog.Builder(mActivity) - .setTitle(R.string.remember_location_title) - .setMessage(R.string.remember_location_prompt) - .setPositiveButton(R.string.remember_location_yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int arg1) { - setLocationPreference(RecordLocationPreference.VALUE_ON); - } - }) - .setNegativeButton(R.string.remember_location_no, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int arg1) { - dialog.cancel(); - } - }) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - setLocationPreference(RecordLocationPreference.VALUE_OFF); - } - }) - .show(); - } - - private void setLocationPreference(String value) { - mPreferences.edit() - .putString(CameraSettings.KEY_RECORD_LOCATION, value) - .apply(); - // TODO: Fix this to use the actual onSharedPreferencesChanged listener - // instead of invoking manually - onSharedPreferenceChanged(); - } - - private void onCameraOpened() { - View root = mUI.getRootView(); - // These depend on camera parameters. - - int width = root.getWidth(); - int height = root.getHeight(); - mFocusManager.setPreviewSize(width, height); - openCameraCommon(); - } - - private void switchCamera() { - if (mPaused) return; - - Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId); - mCameraId = mPendingSwitchCameraId; - mPendingSwitchCameraId = -1; - setCameraId(mCameraId); - - // from onPause - closeCamera(); - mUI.collapseCameraControls(); - mUI.clearFaces(); - if (mFocusManager != null) mFocusManager.removeMessages(); - - // Restart the camera and initialize the UI. From onCreate. - mPreferences.setLocalId(mActivity, mCameraId); - CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); - try { - mCameraDevice = Util.openCamera(mActivity, mCameraId); - mParameters = mCameraDevice.getParameters(); - } catch (CameraHardwareException e) { - Util.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); - return; - } catch (CameraDisabledException e) { - Util.showErrorAndFinish(mActivity, R.string.camera_disabled); - return; - } - initializeCapabilities(); - CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; - boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT); - mFocusManager.setMirror(mirror); - mFocusManager.setParameters(mInitialParams); - setupPreview(); - - openCameraCommon(); - - if (ApiHelper.HAS_SURFACE_TEXTURE) { - // Start switch camera animation. Post a message because - // onFrameAvailable from the old camera may already exist. - mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION); - } - } - - protected void setCameraId(int cameraId) { - ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID); - pref.setValue("" + cameraId); - } - - // either open a new camera or switch cameras - private void openCameraCommon() { - loadCameraPreferences(); - - mUI.onCameraOpened(mPreferenceGroup, mPreferences, mParameters, this); - updateSceneMode(); - showTapToFocusToastIfNeeded(); - - - } - - public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) { - if (mFocusManager != null) mFocusManager.setPreviewSize(width, height); - } - - private void resetExposureCompensation() { - String value = mPreferences.getString(CameraSettings.KEY_EXPOSURE, - CameraSettings.EXPOSURE_DEFAULT_VALUE); - if (!CameraSettings.EXPOSURE_DEFAULT_VALUE.equals(value)) { - Editor editor = mPreferences.edit(); - editor.putString(CameraSettings.KEY_EXPOSURE, "0"); - editor.apply(); - } - } - - private void keepMediaProviderInstance() { - // We want to keep a reference to MediaProvider in camera's lifecycle. - // TODO: Utilize mMediaProviderClient instance to replace - // ContentResolver calls. - if (mMediaProviderClient == null) { - mMediaProviderClient = mContentResolver - .acquireContentProviderClient(MediaStore.AUTHORITY); - } - } - - // Snapshots can only be taken after this is called. It should be called - // once only. We could have done these things in onCreate() but we want to - // make preview screen appear as soon as possible. - private void initializeFirstTime() { - if (mFirstTimeInitialized) return; - - // Initialize location service. - boolean recordLocation = RecordLocationPreference.get( - mPreferences, mContentResolver); - mLocationManager.recordLocation(recordLocation); - - keepMediaProviderInstance(); - - mUI.initializeFirstTime(); - MediaSaveService s = mActivity.getMediaSaveService(); - // We set the listener only when both service and shutterbutton - // are initialized. - if (s != null) { - s.setListener(this); - } - - mNamedImages = new NamedImages(); - - mFirstTimeInitialized = true; - addIdleHandler(); - - mActivity.updateStorageSpaceAndHint(); - } - - // If the activity is paused and resumed, this method will be called in - // onResume. - private void initializeSecondTime() { - // Start location update if needed. - boolean recordLocation = RecordLocationPreference.get( - mPreferences, mContentResolver); - mLocationManager.recordLocation(recordLocation); - MediaSaveService s = mActivity.getMediaSaveService(); - if (s != null) { - s.setListener(this); - } - mNamedImages = new NamedImages(); - mUI.initializeSecondTime(mParameters); - keepMediaProviderInstance(); - } - - @Override - public void onSurfaceCreated(SurfaceHolder holder) { - // Do not access the camera if camera start up thread is not finished. - if (mCameraDevice == null || mCameraStartUpThread != null) - return; - - mCameraDevice.setPreviewDisplayAsync(holder); - // This happens when onConfigurationChanged arrives, surface has been - // destroyed, and there is no onFullScreenChanged. - if (mCameraState == PREVIEW_STOPPED) { - setupPreview(); - } - } - - private void showTapToFocusToastIfNeeded() { - // Show the tap to focus toast if this is the first start. - if (mFocusAreaSupported && - mPreferences.getBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, true)) { - // Delay the toast for one second to wait for orientation. - mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_FOCUS_TOAST, 1000); - } - } - - private void addIdleHandler() { - MessageQueue queue = Looper.myQueue(); - queue.addIdleHandler(new MessageQueue.IdleHandler() { - @Override - public boolean queueIdle() { - Storage.ensureOSXCompatible(); - return false; - } - }); - } - - @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) - @Override - public void startFaceDetection() { - if (!ApiHelper.HAS_FACE_DETECTION) return; - if (mFaceDetectionStarted) return; - if (mParameters.getMaxNumDetectedFaces() > 0) { - mFaceDetectionStarted = true; - CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; - mUI.onStartFaceDetection(mDisplayOrientation, - (info.facing == CameraInfo.CAMERA_FACING_FRONT)); - mCameraDevice.setFaceDetectionListener(mUI); - mCameraDevice.startFaceDetection(); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) - @Override - public void stopFaceDetection() { - if (!ApiHelper.HAS_FACE_DETECTION) return; - if (!mFaceDetectionStarted) return; - if (mParameters.getMaxNumDetectedFaces() > 0) { - mFaceDetectionStarted = false; - mCameraDevice.setFaceDetectionListener(null); - mCameraDevice.stopFaceDetection(); - mUI.clearFaces(); - } - } - - @Override - public boolean dispatchTouchEvent(MotionEvent m) { - if (mCameraState == SWITCHING_CAMERA) return true; - return mUI.dispatchTouchEvent(m); - } - - private final class ShutterCallback - implements android.hardware.Camera.ShutterCallback { - @Override - public void onShutter() { - mShutterCallbackTime = System.currentTimeMillis(); - mShutterLag = mShutterCallbackTime - mCaptureStartTime; - Log.v(TAG, "mShutterLag = " + mShutterLag + "ms"); - } - } - - private final class PostViewPictureCallback implements PictureCallback { - @Override - public void onPictureTaken( - byte [] data, android.hardware.Camera camera) { - mPostViewPictureCallbackTime = System.currentTimeMillis(); - Log.v(TAG, "mShutterToPostViewCallbackTime = " - + (mPostViewPictureCallbackTime - mShutterCallbackTime) - + "ms"); - } - } - - private final class RawPictureCallback implements PictureCallback { - @Override - public void onPictureTaken( - byte [] rawData, android.hardware.Camera camera) { - mRawPictureCallbackTime = System.currentTimeMillis(); - Log.v(TAG, "mShutterToRawCallbackTime = " - + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms"); - } - } - - private final class JpegPictureCallback implements PictureCallback { - Location mLocation; - - public JpegPictureCallback(Location loc) { - mLocation = loc; - } - - @Override - public void onPictureTaken( - final byte [] jpegData, final android.hardware.Camera camera) { - if (mPaused) { - return; - } - if (mSceneMode == Util.SCENE_MODE_HDR) { - mUI.showSwitcher(); - //TODO: mActivity.setSwipingEnabled(true); - } - - mJpegPictureCallbackTime = System.currentTimeMillis(); - // If postview callback has arrived, the captured image is displayed - // in postview callback. If not, the captured image is displayed in - // raw picture callback. - if (mPostViewPictureCallbackTime != 0) { - mShutterToPictureDisplayedTime = - mPostViewPictureCallbackTime - mShutterCallbackTime; - mPictureDisplayedToJpegCallbackTime = - mJpegPictureCallbackTime - mPostViewPictureCallbackTime; - } else { - mShutterToPictureDisplayedTime = - mRawPictureCallbackTime - mShutterCallbackTime; - mPictureDisplayedToJpegCallbackTime = - mJpegPictureCallbackTime - mRawPictureCallbackTime; - } - Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = " - + mPictureDisplayedToJpegCallbackTime + "ms"); - - /*TODO: - // Only animate when in full screen capture mode - // i.e. If monkey/a user swipes to the gallery during picture taking, - // don't show animation - if (ApiHelper.HAS_SURFACE_TEXTURE && !mIsImageCaptureIntent - && mActivity.mShowCameraAppView) { - // Finish capture animation - ((CameraScreenNail) mActivity.mCameraScreenNail).animateSlide(); - } */ - mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden. - if (!mIsImageCaptureIntent) { - if (ApiHelper.CAN_START_PREVIEW_IN_JPEG_CALLBACK) { - setupPreview(); - } else { - // Camera HAL of some devices have a bug. Starting preview - // immediately after taking a picture will fail. Wait some - // time before starting the preview. - mHandler.sendEmptyMessageDelayed(SETUP_PREVIEW, 300); - } - } - - if (!mIsImageCaptureIntent) { - // Calculate the width and the height of the jpeg. - Size s = mParameters.getPictureSize(); - ExifInterface exif = Exif.getExif(jpegData); - int orientation = Exif.getOrientation(exif); - int width, height; - if ((mJpegRotation + orientation) % 180 == 0) { - width = s.width; - height = s.height; - } else { - width = s.height; - height = s.width; - } - String title = mNamedImages.getTitle(); - long date = mNamedImages.getDate(); - if (title == null) { - Log.e(TAG, "Unbalanced name/data pair"); - } else { - if (date == -1) date = mCaptureStartTime; - if (mHeading >= 0) { - // heading direction has been updated by the sensor. - ExifTag directionRefTag = exif.buildTag( - ExifInterface.TAG_GPS_IMG_DIRECTION_REF, - ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION); - ExifTag directionTag = exif.buildTag( - ExifInterface.TAG_GPS_IMG_DIRECTION, - new Rational(mHeading, 1)); - exif.setTag(directionRefTag); - exif.setTag(directionTag); - } - mActivity.getMediaSaveService().addImage( - jpegData, title, date, mLocation, width, height, - orientation, exif, mOnMediaSavedListener, mContentResolver); - } - } else { - mJpegImageData = jpegData; - if (!mQuickCapture) { - mUI.showPostCaptureAlert(); - } else { - onCaptureDone(); - } - } - - // Check this in advance of each shot so we don't add to shutter - // latency. It's true that someone else could write to the SD card in - // the mean time and fill it, but that could have happened between the - // shutter press and saving the JPEG too. - mActivity.updateStorageSpaceAndHint(); - - long now = System.currentTimeMillis(); - mJpegCallbackFinishTime = now - mJpegPictureCallbackTime; - Log.v(TAG, "mJpegCallbackFinishTime = " - + mJpegCallbackFinishTime + "ms"); - mJpegPictureCallbackTime = 0; - } - } - - private final class AutoFocusCallback - implements android.hardware.Camera.AutoFocusCallback { - @Override - public void onAutoFocus( - boolean focused, android.hardware.Camera camera) { - if (mPaused) return; - - mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime; - Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms"); - setCameraState(IDLE); - mFocusManager.onAutoFocus(focused, mUI.isShutterPressed()); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN) - private final class AutoFocusMoveCallback - implements android.hardware.Camera.AutoFocusMoveCallback { - @Override - public void onAutoFocusMoving( - boolean moving, android.hardware.Camera camera) { - mFocusManager.onAutoFocusMoving(moving); - } - } - - private static class NamedImages { - private ArrayList<NamedEntity> mQueue; - private boolean mStop; - private NamedEntity mNamedEntity; - - public NamedImages() { - mQueue = new ArrayList<NamedEntity>(); - } - - public void nameNewImage(ContentResolver resolver, long date) { - NamedEntity r = new NamedEntity(); - r.title = Util.createJpegName(date); - r.date = date; - mQueue.add(r); - } - - public String getTitle() { - if (mQueue.isEmpty()) { - mNamedEntity = null; - return null; - } - mNamedEntity = mQueue.get(0); - mQueue.remove(0); - - return mNamedEntity.title; - } - - // Must be called after getTitle(). - public long getDate() { - if (mNamedEntity == null) return -1; - return mNamedEntity.date; - } - - private static class NamedEntity { - String title; - long date; - } - } - - private void setCameraState(int state) { - mCameraState = state; - switch (state) { - case PhotoController.PREVIEW_STOPPED: - case PhotoController.SNAPSHOT_IN_PROGRESS: - case PhotoController.FOCUSING: - case PhotoController.SWITCHING_CAMERA: - mUI.enableGestures(false); - break; - case PhotoController.IDLE: - mUI.enableGestures(true); - break; - } - } - - private void animateFlash() { - /* //TODO: - // Only animate when in full screen capture mode - // i.e. If monkey/a user swipes to the gallery during picture taking, - // don't show animation - if (ApiHelper.HAS_SURFACE_TEXTURE && !mIsImageCaptureIntent - && mActivity.mShowCameraAppView) { - // Start capture animation. - ((CameraScreenNail) mActivity.mCameraScreenNail).animateFlash(mDisplayRotation); - } */ - } - - @Override - public boolean capture() { - // If we are already in the middle of taking a snapshot or the image save request - // is full then ignore. - if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS - || mCameraState == SWITCHING_CAMERA - || mActivity.getMediaSaveService().isQueueFull()) { - return false; - } - mCaptureStartTime = System.currentTimeMillis(); - mPostViewPictureCallbackTime = 0; - mJpegImageData = null; - - final boolean animateBefore = (mSceneMode == Util.SCENE_MODE_HDR); - - if (animateBefore) { - animateFlash(); - } - - // Set rotation and gps data. - int orientation = (360 - mDisplayRotation) % 360; - // We need to be consistent with the framework orientation (i.e. the - // orientation of the UI.) when the auto-rotate screen setting is on. - if (mActivity.isAutoRotateScreen()) { - orientation = (360 - mDisplayRotation) % 360; - } else { - orientation = mOrientation; - } - mJpegRotation = Util.getJpegRotation(mCameraId, orientation); - mParameters.setRotation(mJpegRotation); - Location loc = mLocationManager.getCurrentLocation(); - Util.setGpsParameters(mParameters, loc); - mCameraDevice.setParameters(mParameters); - - mCameraDevice.takePicture2(mShutterCallback, mRawPictureCallback, - mPostViewPictureCallback, new JpegPictureCallback(loc), - mCameraState, mFocusManager.getFocusState()); - - if (!animateBefore) { - animateFlash(); - } - - mNamedImages.nameNewImage(mContentResolver, mCaptureStartTime); - - mFaceDetectionStarted = false; - setCameraState(SNAPSHOT_IN_PROGRESS); - return true; - } - - @Override - public void setFocusParameters() { - setCameraParameters(UPDATE_PARAM_PREFERENCE); - } - - private int getPreferredCameraId(ComboPreferences preferences) { - int intentCameraId = Util.getCameraFacingIntentExtras(mActivity); - if (intentCameraId != -1) { - // Testing purpose. Launch a specific camera through the intent - // extras. - return intentCameraId; - } else { - return CameraSettings.readPreferredCameraId(preferences); - } - } - - private void updateSceneMode() { - // If scene mode is set, we cannot set flash mode, white balance, and - // focus mode, instead, we read it from driver - if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) { - overrideCameraSettings(mParameters.getFlashMode(), - mParameters.getWhiteBalance(), mParameters.getFocusMode()); - } else { - overrideCameraSettings(null, null, null); - } - } - - private void overrideCameraSettings(final String flashMode, - final String whiteBalance, final String focusMode) { - mUI.overrideSettings( - CameraSettings.KEY_FLASH_MODE, flashMode, - CameraSettings.KEY_WHITE_BALANCE, whiteBalance, - CameraSettings.KEY_FOCUS_MODE, focusMode); - } - - private void loadCameraPreferences() { - CameraSettings settings = new CameraSettings(mActivity, mInitialParams, - mCameraId, CameraHolder.instance().getCameraInfo()); - mPreferenceGroup = settings.getPreferenceGroup(R.xml.camera_preferences); - } - - @Override - public void onOrientationChanged(int orientation) { - // We keep the last known orientation. So if the user first orient - // the camera then point the camera to floor or sky, we still have - // the correct orientation. - if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return; - mOrientation = Util.roundOrientation(orientation, mOrientation); - - // Show the toast after getting the first orientation changed. - if (mHandler.hasMessages(SHOW_TAP_TO_FOCUS_TOAST)) { - mHandler.removeMessages(SHOW_TAP_TO_FOCUS_TOAST); - showTapToFocusToast(); - } - } - - @Override - public void onStop() { - if (mMediaProviderClient != null) { - mMediaProviderClient.release(); - mMediaProviderClient = null; - } - } - - @Override - public void onCaptureCancelled() { - mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent()); - mActivity.finish(); - } - - @Override - public void onCaptureRetake() { - if (mPaused) - return; - mUI.hidePostCaptureAlert(); - setupPreview(); - } - - @Override - public void onCaptureDone() { - if (mPaused) { - return; - } - - byte[] data = mJpegImageData; - - if (mCropValue == null) { - // First handle the no crop case -- just return the value. If the - // caller specifies a "save uri" then write the data to its - // stream. Otherwise, pass back a scaled down version of the bitmap - // directly in the extras. - if (mSaveUri != null) { - OutputStream outputStream = null; - try { - outputStream = mContentResolver.openOutputStream(mSaveUri); - outputStream.write(data); - outputStream.close(); - - mActivity.setResultEx(Activity.RESULT_OK); - mActivity.finish(); - } catch (IOException ex) { - // ignore exception - } finally { - Util.closeSilently(outputStream); - } - } else { - ExifInterface exif = Exif.getExif(data); - int orientation = Exif.getOrientation(exif); - Bitmap bitmap = Util.makeBitmap(data, 50 * 1024); - bitmap = Util.rotate(bitmap, orientation); - mActivity.setResultEx(Activity.RESULT_OK, - new Intent("inline-data").putExtra("data", bitmap)); - mActivity.finish(); - } - } else { - // Save the image to a temp file and invoke the cropper - Uri tempUri = null; - FileOutputStream tempStream = null; - try { - File path = mActivity.getFileStreamPath(sTempCropFilename); - path.delete(); - tempStream = mActivity.openFileOutput(sTempCropFilename, 0); - tempStream.write(data); - tempStream.close(); - tempUri = Uri.fromFile(path); - } catch (FileNotFoundException ex) { - mActivity.setResultEx(Activity.RESULT_CANCELED); - mActivity.finish(); - return; - } catch (IOException ex) { - mActivity.setResultEx(Activity.RESULT_CANCELED); - mActivity.finish(); - return; - } finally { - Util.closeSilently(tempStream); - } - - Bundle newExtras = new Bundle(); - if (mCropValue.equals("circle")) { - newExtras.putString("circleCrop", "true"); - } - if (mSaveUri != null) { - newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri); - } else { - newExtras.putBoolean(CropExtras.KEY_RETURN_DATA, true); - } - if (mActivity.isSecureCamera()) { - newExtras.putBoolean(CropExtras.KEY_SHOW_WHEN_LOCKED, true); - } - - Intent cropIntent = new Intent(FilterShowActivity.CROP_ACTION); - - cropIntent.setData(tempUri); - cropIntent.putExtras(newExtras); - - mActivity.startActivityForResult(cropIntent, REQUEST_CROP); - } - } - - @Override - public void onShutterButtonFocus(boolean pressed) { - if (mPaused || mUI.collapseCameraControls() - || (mCameraState == SNAPSHOT_IN_PROGRESS) - || (mCameraState == PREVIEW_STOPPED)) return; - - // Do not do focus if there is not enough storage. - if (pressed && !canTakePicture()) return; - - if (pressed) { - if (mSceneMode == Util.SCENE_MODE_HDR) { - mUI.hideSwitcher(); - //TODO: mActivity.setSwipingEnabled(false); - } - mFocusManager.onShutterDown(); - } else { - // for countdown mode, we need to postpone the shutter release - // i.e. lock the focus during countdown. - if (!mUI.isCountingDown()) { - mFocusManager.onShutterUp(); - } - } - } - - @Override - public void onShutterButtonClick() { - if (mPaused || mUI.collapseCameraControls() - || (mCameraState == SWITCHING_CAMERA) - || (mCameraState == PREVIEW_STOPPED)) return; - - // Do not take the picture if there is not enough storage. - if (mActivity.getStorageSpace() <= Storage.LOW_STORAGE_THRESHOLD) { - Log.i(TAG, "Not enough space or storage not ready. remaining=" - + mActivity.getStorageSpace()); - return; - } - Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState); - - // If the user wants to do a snapshot while the previous one is still - // in progress, remember the fact and do it after we finish the previous - // one and re-start the preview. Snapshot in progress also includes the - // state that autofocus is focusing and a picture will be taken when - // focus callback arrives. - if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS) - && !mIsImageCaptureIntent) { - mSnapshotOnIdle = true; - return; - } - - String timer = mPreferences.getString( - CameraSettings.KEY_TIMER, - mActivity.getString(R.string.pref_camera_timer_default)); - boolean playSound = mPreferences.getString(CameraSettings.KEY_TIMER_SOUND_EFFECTS, - mActivity.getString(R.string.pref_camera_timer_sound_default)) - .equals(mActivity.getString(R.string.setting_on_value)); - - int seconds = Integer.parseInt(timer); - // When shutter button is pressed, check whether the previous countdown is - // finished. If not, cancel the previous countdown and start a new one. - if (mUI.isCountingDown()) { - mUI.cancelCountDown(); - } - if (seconds > 0) { - mUI.startCountDown(seconds, playSound); - } else { - mSnapshotOnIdle = false; - mFocusManager.doSnap(); - } - } - - @Override - public void installIntentFilter() { - } - - @Override - public boolean updateStorageHintOnResume() { - return mFirstTimeInitialized; - } - - @Override - public void updateCameraAppView() { - } - - @Override - public void onResumeBeforeSuper() { - mPaused = false; - } - - @Override - public void onResumeAfterSuper() { - if (mOpenCameraFail || mCameraDisabled) return; - - mJpegPictureCallbackTime = 0; - mZoomValue = 0; - // Start the preview if it is not started. - if (mCameraState == PREVIEW_STOPPED && mCameraStartUpThread == null) { - resetExposureCompensation(); - mCameraStartUpThread = new CameraStartUpThread(); - mCameraStartUpThread.start(); - } - - // If first time initialization is not finished, put it in the - // message queue. - if (!mFirstTimeInitialized) { - mHandler.sendEmptyMessage(FIRST_TIME_INIT); - } else { - initializeSecondTime(); - } - keepScreenOnAwhile(); - - // Dismiss open menu if exists. - PopupManager.getInstance(mActivity).notifyShowPopup(null); - UsageStatistics.onContentViewChanged( - UsageStatistics.COMPONENT_CAMERA, "PhotoModule"); - - Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); - if (gsensor != null) { - mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL); - } - - Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); - if (msensor != null) { - mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL); - } - } - - void waitCameraStartUpThread() { - try { - if (mCameraStartUpThread != null) { - mCameraStartUpThread.cancel(); - mCameraStartUpThread.join(); - mCameraStartUpThread = null; - setCameraState(IDLE); - } - } catch (InterruptedException e) { - // ignore - } - } - - @Override - public void onPauseBeforeSuper() { - mPaused = true; - Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); - if (gsensor != null) { - mSensorManager.unregisterListener(this, gsensor); - } - - Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); - if (msensor != null) { - mSensorManager.unregisterListener(this, msensor); - } - } - - @Override - public void onPauseAfterSuper() { - // Wait the camera start up thread to finish. - waitCameraStartUpThread(); - - // When camera is started from secure lock screen for the first time - // after screen on, the activity gets onCreate->onResume->onPause->onResume. - // To reduce the latency, keep the camera for a short time so it does - // not need to be opened again. - if (mCameraDevice != null && mActivity.isSecureCamera() - && ActivityBase.isFirstStartAfterScreenOn()) { - ActivityBase.resetFirstStartAfterScreenOn(); - CameraHolder.instance().keep(KEEP_CAMERA_TIMEOUT); - } - // Reset the focus first. Camera CTS does not guarantee that - // cancelAutoFocus is allowed after preview stops. - if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { - mCameraDevice.cancelAutoFocus(); - } - stopPreview(); - - mNamedImages = null; - - if (mLocationManager != null) mLocationManager.recordLocation(false); - - // If we are in an image capture intent and has taken - // a picture, we just clear it in onPause. - mJpegImageData = null; - - // Remove the messages in the event queue. - mHandler.removeMessages(SETUP_PREVIEW); - mHandler.removeMessages(FIRST_TIME_INIT); - mHandler.removeMessages(CHECK_DISPLAY_ROTATION); - mHandler.removeMessages(SWITCH_CAMERA); - mHandler.removeMessages(SWITCH_CAMERA_START_ANIMATION); - mHandler.removeMessages(CAMERA_OPEN_DONE); - mHandler.removeMessages(START_PREVIEW_DONE); - mHandler.removeMessages(OPEN_CAMERA_FAIL); - mHandler.removeMessages(CAMERA_DISABLED); - - closeCamera(); - - resetScreenOn(); - mUI.onPause(); - - mPendingSwitchCameraId = -1; - if (mFocusManager != null) mFocusManager.removeMessages(); - MediaSaveService s = mActivity.getMediaSaveService(); - if (s != null) { - s.setListener(null); - } - } - - /** - * The focus manager is the first UI related element to get initialized, - * and it requires the RenderOverlay, so initialize it here - */ - private void initializeFocusManager() { - // Create FocusManager object. startPreview needs it. - // if mFocusManager not null, reuse it - // otherwise create a new instance - if (mFocusManager != null) { - mFocusManager.removeMessages(); - } else { - CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; - boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT); - String[] defaultFocusModes = mActivity.getResources().getStringArray( - R.array.pref_camera_focusmode_default_array); - mFocusManager = new FocusOverlayManager(mPreferences, defaultFocusModes, - mInitialParams, this, mirror, - mActivity.getMainLooper(), mUI); - } - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - Log.v(TAG, "onConfigurationChanged"); - setDisplayOrientation(); - } - - @Override - public void onActivityResult( - int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_CROP: { - Intent intent = new Intent(); - if (data != null) { - Bundle extras = data.getExtras(); - if (extras != null) { - intent.putExtras(extras); - } - } - mActivity.setResultEx(resultCode, intent); - mActivity.finish(); - - File path = mActivity.getFileStreamPath(sTempCropFilename); - path.delete(); - - break; - } - } - } - - private boolean canTakePicture() { - return isCameraIdle() && (mActivity.getStorageSpace() > Storage.LOW_STORAGE_THRESHOLD); - } - - @Override - public void autoFocus() { - mFocusStartTime = System.currentTimeMillis(); - mCameraDevice.autoFocus(mAutoFocusCallback); - setCameraState(FOCUSING); - } - - @Override - public void cancelAutoFocus() { - mCameraDevice.cancelAutoFocus(); - setCameraState(IDLE); - setCameraParameters(UPDATE_PARAM_PREFERENCE); - } - - // Preview area is touched. Handle touch focus. - @Override - public void onSingleTapUp(View view, int x, int y) { - if (mPaused || mCameraDevice == null || !mFirstTimeInitialized - || mCameraState == SNAPSHOT_IN_PROGRESS - || mCameraState == SWITCHING_CAMERA - || mCameraState == PREVIEW_STOPPED) { - return; - } - - // Do not trigger touch focus if popup window is opened. - if (mUI.removeTopLevelPopup()) return; - - // Check if metering area or focus area is supported. - if (!mFocusAreaSupported && !mMeteringAreaSupported) return; - mFocusManager.onSingleTapUp(x, y); - } - - @Override - public boolean onBackPressed() { - return mUI.onBackPressed(); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: - case KeyEvent.KEYCODE_FOCUS: - if (/*TODO: mActivity.isInCameraApp() &&*/ mFirstTimeInitialized) { - if (event.getRepeatCount() == 0) { - onShutterButtonFocus(true); - } - return true; - } - return false; - case KeyEvent.KEYCODE_CAMERA: - if (mFirstTimeInitialized && event.getRepeatCount() == 0) { - onShutterButtonClick(); - } - return true; - case KeyEvent.KEYCODE_DPAD_CENTER: - // If we get a dpad center event without any focused view, move - // the focus to the shutter button and press it. - if (mFirstTimeInitialized && event.getRepeatCount() == 0) { - // Start auto-focus immediately to reduce shutter lag. After - // the shutter button gets the focus, onShutterButtonFocus() - // will be called again but it is fine. - if (mUI.removeTopLevelPopup()) return true; - onShutterButtonFocus(true); - mUI.pressShutterButton(); - } - return true; - } - return false; - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: - if (/*mActivity.isInCameraApp() && */ mFirstTimeInitialized) { - onShutterButtonClick(); - return true; - } - return false; - case KeyEvent.KEYCODE_FOCUS: - if (mFirstTimeInitialized) { - onShutterButtonFocus(false); - } - return true; - } - return false; - } - - @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) - private void closeCamera() { - if (mCameraDevice != null) { - mCameraDevice.setZoomChangeListener(null); - if(ApiHelper.HAS_FACE_DETECTION) { - mCameraDevice.setFaceDetectionListener(null); - } - mCameraDevice.setErrorCallback(null); - CameraHolder.instance().release(); - mFaceDetectionStarted = false; - mCameraDevice = null; - setCameraState(PREVIEW_STOPPED); - mFocusManager.onCameraReleased(); - } - } - - private void setDisplayOrientation() { - mDisplayRotation = Util.getDisplayRotation(mActivity); - mDisplayOrientation = Util.getDisplayOrientation(mDisplayRotation, mCameraId); - mCameraDisplayOrientation = mDisplayOrientation; - mUI.setDisplayOrientation(mDisplayOrientation); - if (mFocusManager != null) { - mFocusManager.setDisplayOrientation(mDisplayOrientation); - } - // Change the camera display orientation - if (mCameraDevice != null) { - mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation); - } - } - - // Only called by UI thread. - private void setupPreview() { - mFocusManager.resetTouchFocus(); - startPreview(); - setCameraState(IDLE); - startFaceDetection(); - } - - // This can be called by UI Thread or CameraStartUpThread. So this should - // not modify the views. - private void startPreview() { - mCameraDevice.setErrorCallback(mErrorCallback); - - // ICS camera frameworks has a bug. Face detection state is not cleared - // after taking a picture. Stop the preview to work around it. The bug - // was fixed in JB. - if (mCameraState != PREVIEW_STOPPED) stopPreview(); - - setDisplayOrientation(); - - if (!mSnapshotOnIdle) { - // If the focus mode is continuous autofocus, call cancelAutoFocus to - // resume it because it may have been paused by autoFocus call. - if (Util.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) { - mCameraDevice.cancelAutoFocus(); - } - mFocusManager.setAeAwbLock(false); // Unlock AE and AWB. - } - setCameraParameters(UPDATE_PARAM_ALL); - // Let UI set its expected aspect ratio - mUI.setPreviewSize(mParameters.getPreviewSize()); - Object st = mUI.getSurfaceTexture(); - if (st != null) { - mCameraDevice.setPreviewTextureAsync((SurfaceTexture) st); - } - - Log.v(TAG, "startPreview"); - mCameraDevice.startPreviewAsync(); - mFocusManager.onPreviewStarted(); - - if (mSnapshotOnIdle) { - mHandler.post(mDoSnapRunnable); - } - } - - @Override - public void stopPreview() { - if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { - Log.v(TAG, "stopPreview"); - mCameraDevice.stopPreview(); - mFaceDetectionStarted = false; - } - setCameraState(PREVIEW_STOPPED); - if (mFocusManager != null) mFocusManager.onPreviewStopped(); - } - - @SuppressWarnings("deprecation") - private void updateCameraParametersInitialize() { - // Reset preview frame rate to the maximum because it may be lowered by - // video camera application. - List<Integer> frameRates = mParameters.getSupportedPreviewFrameRates(); - if (frameRates != null) { - Integer max = Collections.max(frameRates); - mParameters.setPreviewFrameRate(max); - } - - mParameters.set(Util.RECORDING_HINT, Util.FALSE); - - // Disable video stabilization. Convenience methods not available in API - // level <= 14 - String vstabSupported = mParameters.get("video-stabilization-supported"); - if ("true".equals(vstabSupported)) { - mParameters.set("video-stabilization", "false"); - } - } - - private void updateCameraParametersZoom() { - // Set zoom. - if (mParameters.isZoomSupported()) { - mParameters.setZoom(mZoomValue); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN) - private void setAutoExposureLockIfSupported() { - if (mAeLockSupported) { - mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock()); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN) - private void setAutoWhiteBalanceLockIfSupported() { - if (mAwbLockSupported) { - mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock()); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) - private void setFocusAreasIfSupported() { - if (mFocusAreaSupported) { - mParameters.setFocusAreas(mFocusManager.getFocusAreas()); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) - private void setMeteringAreasIfSupported() { - if (mMeteringAreaSupported) { - // Use the same area for focus and metering. - mParameters.setMeteringAreas(mFocusManager.getMeteringAreas()); - } - } - - private void updateCameraParametersPreference() { - setAutoExposureLockIfSupported(); - setAutoWhiteBalanceLockIfSupported(); - setFocusAreasIfSupported(); - setMeteringAreasIfSupported(); - - // Set picture size. - String pictureSize = mPreferences.getString( - CameraSettings.KEY_PICTURE_SIZE, null); - if (pictureSize == null) { - CameraSettings.initialCameraPictureSize(mActivity, mParameters); - } else { - List<Size> supported = mParameters.getSupportedPictureSizes(); - CameraSettings.setCameraPictureSize( - pictureSize, supported, mParameters); - } - Size size = mParameters.getPictureSize(); - - // Set a preview size that is closest to the viewfinder height and has - // the right aspect ratio. - List<Size> sizes = mParameters.getSupportedPreviewSizes(); - Size optimalSize = Util.getOptimalPreviewSize(mActivity, sizes, - (double) size.width / size.height); - Size original = mParameters.getPreviewSize(); - if (!original.equals(optimalSize)) { - mParameters.setPreviewSize(optimalSize.width, optimalSize.height); - - // Zoom related settings will be changed for different preview - // sizes, so set and read the parameters to get latest values - mCameraDevice.setParameters(mParameters); - mParameters = mCameraDevice.getParameters(); - } - Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height); - - // Since changing scene mode may change supported values, set scene mode - // first. HDR is a scene mode. To promote it in UI, it is stored in a - // separate preference. - String hdr = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR, - mActivity.getString(R.string.pref_camera_hdr_default)); - if (mActivity.getString(R.string.setting_on_value).equals(hdr)) { - mSceneMode = Util.SCENE_MODE_HDR; - } else { - mSceneMode = mPreferences.getString( - CameraSettings.KEY_SCENE_MODE, - mActivity.getString(R.string.pref_camera_scenemode_default)); - } - if (Util.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) { - if (!mParameters.getSceneMode().equals(mSceneMode)) { - mParameters.setSceneMode(mSceneMode); - - // Setting scene mode will change the settings of flash mode, - // white balance, and focus mode. Here we read back the - // parameters, so we can know those settings. - mCameraDevice.setParameters(mParameters); - mParameters = mCameraDevice.getParameters(); - } - } else { - mSceneMode = mParameters.getSceneMode(); - if (mSceneMode == null) { - mSceneMode = Parameters.SCENE_MODE_AUTO; - } - } - - // Set JPEG quality. - int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId, - CameraProfile.QUALITY_HIGH); - mParameters.setJpegQuality(jpegQuality); - - // For the following settings, we need to check if the settings are - // still supported by latest driver, if not, ignore the settings. - - // Set exposure compensation - int value = CameraSettings.readExposure(mPreferences); - int max = mParameters.getMaxExposureCompensation(); - int min = mParameters.getMinExposureCompensation(); - if (value >= min && value <= max) { - mParameters.setExposureCompensation(value); - } else { - Log.w(TAG, "invalid exposure range: " + value); - } - - if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) { - // Set flash mode. - String flashMode = mPreferences.getString( - CameraSettings.KEY_FLASH_MODE, - mActivity.getString(R.string.pref_camera_flashmode_default)); - List<String> supportedFlash = mParameters.getSupportedFlashModes(); - if (Util.isSupported(flashMode, supportedFlash)) { - mParameters.setFlashMode(flashMode); - } else { - flashMode = mParameters.getFlashMode(); - if (flashMode == null) { - flashMode = mActivity.getString( - R.string.pref_camera_flashmode_no_flash); - } - } - - // Set white balance parameter. - String whiteBalance = mPreferences.getString( - CameraSettings.KEY_WHITE_BALANCE, - mActivity.getString(R.string.pref_camera_whitebalance_default)); - if (Util.isSupported(whiteBalance, - mParameters.getSupportedWhiteBalance())) { - mParameters.setWhiteBalance(whiteBalance); - } else { - whiteBalance = mParameters.getWhiteBalance(); - if (whiteBalance == null) { - whiteBalance = Parameters.WHITE_BALANCE_AUTO; - } - } - - // Set focus mode. - mFocusManager.overrideFocusMode(null); - mParameters.setFocusMode(mFocusManager.getFocusMode()); - } else { - mFocusManager.overrideFocusMode(mParameters.getFocusMode()); - } - - if (mContinousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) { - updateAutoFocusMoveCallback(); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN) - private void updateAutoFocusMoveCallback() { - if (mParameters.getFocusMode().equals(Util.FOCUS_MODE_CONTINUOUS_PICTURE)) { - mCameraDevice.setAutoFocusMoveCallback( - (AutoFocusMoveCallback) mAutoFocusMoveCallback); - } else { - mCameraDevice.setAutoFocusMoveCallback(null); - } - } - - // We separate the parameters into several subsets, so we can update only - // the subsets actually need updating. The PREFERENCE set needs extra - // locking because the preference can be changed from GLThread as well. - private void setCameraParameters(int updateSet) { - if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) { - updateCameraParametersInitialize(); - } - - if ((updateSet & UPDATE_PARAM_ZOOM) != 0) { - updateCameraParametersZoom(); - } - - if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) { - updateCameraParametersPreference(); - } - - mCameraDevice.setParameters(mParameters); - } - - // If the Camera is idle, update the parameters immediately, otherwise - // accumulate them in mUpdateSet and update later. - private void setCameraParametersWhenIdle(int additionalUpdateSet) { - mUpdateSet |= additionalUpdateSet; - if (mCameraDevice == null) { - // We will update all the parameters when we open the device, so - // we don't need to do anything now. - mUpdateSet = 0; - return; - } else if (isCameraIdle()) { - setCameraParameters(mUpdateSet); - updateSceneMode(); - mUpdateSet = 0; - } else { - if (!mHandler.hasMessages(SET_CAMERA_PARAMETERS_WHEN_IDLE)) { - mHandler.sendEmptyMessageDelayed( - SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000); - } - } - } - - public boolean isCameraIdle() { - return (mCameraState == IDLE) || - (mCameraState == PREVIEW_STOPPED) || - ((mFocusManager != null) && mFocusManager.isFocusCompleted() - && (mCameraState != SWITCHING_CAMERA)); - } - - public boolean isImageCaptureIntent() { - String action = mActivity.getIntent().getAction(); - return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action) - || ActivityBase.ACTION_IMAGE_CAPTURE_SECURE.equals(action)); - } - - private void setupCaptureParams() { - Bundle myExtras = mActivity.getIntent().getExtras(); - if (myExtras != null) { - mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT); - mCropValue = myExtras.getString("crop"); - } - } - - @Override - public void onSharedPreferenceChanged() { - // ignore the events after "onPause()" - if (mPaused) return; - - boolean recordLocation = RecordLocationPreference.get( - mPreferences, mContentResolver); - mLocationManager.recordLocation(recordLocation); - - setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE); - mUI.updateOnScreenIndicators(mParameters, mPreferences); - } - - @Override - public void onCameraPickerClicked(int cameraId) { - if (mPaused || mPendingSwitchCameraId != -1) return; - - mPendingSwitchCameraId = cameraId; - - Log.v(TAG, "Start to switch camera. cameraId=" + cameraId); - // We need to keep a preview frame for the animation before - // releasing the camera. This will trigger onPreviewTextureCopied. - //TODO: Need to animate the camera switch - switchCamera(); - } - - // Preview texture has been copied. Now camera can be released and the - // animation can be started. - @Override - public void onPreviewTextureCopied() { - mHandler.sendEmptyMessage(SWITCH_CAMERA); - } - - @Override - public void onCaptureTextureCopied() { - } - - @Override - public void onUserInteraction() { - if (!mActivity.isFinishing()) keepScreenOnAwhile(); - } - - private void resetScreenOn() { - mHandler.removeMessages(CLEAR_SCREEN_DELAY); - mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - private void keepScreenOnAwhile() { - mHandler.removeMessages(CLEAR_SCREEN_DELAY); - mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY); - } - - @Override - public void onOverriddenPreferencesClicked() { - if (mPaused) return; - mUI.showPreferencesToast(); - } - - private void showTapToFocusToast() { - // TODO: Use a toast? - new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show(); - // Clear the preference. - Editor editor = mPreferences.edit(); - editor.putBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, false); - editor.apply(); - } - - private void initializeCapabilities() { - mInitialParams = mCameraDevice.getParameters(); - mFocusAreaSupported = Util.isFocusAreaSupported(mInitialParams); - mMeteringAreaSupported = Util.isMeteringAreaSupported(mInitialParams); - mAeLockSupported = Util.isAutoExposureLockSupported(mInitialParams); - mAwbLockSupported = Util.isAutoWhiteBalanceLockSupported(mInitialParams); - mContinousFocusSupported = mInitialParams.getSupportedFocusModes().contains( - Util.FOCUS_MODE_CONTINUOUS_PICTURE); - } - - @Override - public void onCountDownFinished() { - mSnapshotOnIdle = false; - mFocusManager.doSnap(); - mFocusManager.onShutterUp(); - } - - @Override - public boolean needsSwitcher() { - return !mIsImageCaptureIntent; - } - - @Override - public boolean needsPieMenu() { - return true; - } - - @Override - public void onShowSwitcherPopup() { - mUI.onShowSwitcherPopup(); - } - - @Override - public int onZoomChanged(int index) { - // Not useful to change zoom value when the activity is paused. - if (mPaused) return index; - mZoomValue = index; - if (mParameters == null || mCameraDevice == null) return index; - // Set zoom parameters asynchronously - mParameters.setZoom(mZoomValue); - mCameraDevice.setParameters(mParameters); - Parameters p = mCameraDevice.getParameters(); - if (p != null) return p.getZoom(); - return index; - } - - @Override - public int getCameraState() { - return mCameraState; - } - - @Override - public void onQueueStatus(boolean full) { - mUI.enableShutter(!full); - } - - @Override - public void onMediaSaveServiceConnected(MediaSaveService s) { - // We set the listener only when both service and shutterbutton - // are initialized. - if (mFirstTimeInitialized) { - s.setListener(this); - } - } - - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) { - } - - @Override - public void onSensorChanged(SensorEvent event) { - int type = event.sensor.getType(); - float[] data; - if (type == Sensor.TYPE_ACCELEROMETER) { - data = mGData; - } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { - data = mMData; - } else { - // we should not be here. - return; - } - for (int i = 0; i < 3 ; i++) { - data[i] = event.values[i]; - } - float[] orientation = new float[3]; - SensorManager.getRotationMatrix(mR, null, mGData, mMData); - SensorManager.getOrientation(mR, orientation); - mHeading = (int) (orientation[0] * 180f / Math.PI) % 360; - if (mHeading < 0) { - mHeading += 360; - } - } -/* Below is no longer needed, except to get rid of compile error - * TODO: Remove these - */ - - // TODO: Delete this function after old camera code is removed - @Override - public void onRestorePreferencesClicked() {} - - @Override - public void onFullScreenChanged(boolean full) { - /* //TODO: - mUI.onFullScreenChanged(full); - if (ApiHelper.HAS_SURFACE_TEXTURE) { - if (mActivity.mCameraScreenNail != null) { - ((CameraScreenNail) mActivity.mCameraScreenNail).setFullScreen(full); - } - return; - } */ - } - -} |