diff options
author | Angus Kong <shkong@google.com> | 2013-08-08 17:06:03 -0700 |
---|---|---|
committer | Angus Kong <shkong@google.com> | 2013-08-13 17:49:11 -0700 |
commit | dcccc510652b835fdbd39310a07849af8203052a (patch) | |
tree | c7f7f9b3787b8213edbbae76bf1c83ba3a201c82 /src | |
parent | 5894ec256d231e5167239176cc90b96a49cb9148 (diff) | |
download | android_packages_apps_Snap-dcccc510652b835fdbd39310a07849af8203052a.tar.gz android_packages_apps_Snap-dcccc510652b835fdbd39310a07849af8203052a.tar.bz2 android_packages_apps_Snap-dcccc510652b835fdbd39310a07849af8203052a.zip |
Fix camera preview stopped after onResume().
This fix is for the blank camera preview blank after onPause() -> onResume().
1. Refined camera start up procedure by removing redundant camera startup
thread.
2. Cleanup unused calls after aparted from gallery.
bug:10189998
Change-Id: I13ffa24aff5069f0032cd4bc801548fccc63d0e7
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/camera/CameraActivity.java | 3 | ||||
-rw-r--r-- | src/com/android/camera/PhotoController.java | 15 | ||||
-rw-r--r-- | src/com/android/camera/PhotoModule.java | 223 | ||||
-rw-r--r-- | src/com/android/camera/PhotoUI.java | 50 | ||||
-rw-r--r-- | src/com/android/camera/VideoModule.java | 1 | ||||
-rw-r--r-- | src/com/android/camera/data/CameraDataAdapter.java | 8 | ||||
-rw-r--r-- | src/com/android/camera/data/FixedFirstDataAdapter.java | 4 | ||||
-rw-r--r-- | src/com/android/camera/ui/FilmStripView.java | 1 |
8 files changed, 133 insertions, 172 deletions
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java index 3e2065c28..099b5035f 100644 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -527,6 +527,7 @@ public class CameraActivity extends Activity if (!mSecureCamera) { mDataAdapter = mWrappedDataAdapter; + mFilmStripView.setDataAdapter(mDataAdapter); mDataAdapter.requestLoad(getContentResolver()); } else { // Put a lock placeholder as the last image by setting its date to 0. @@ -541,8 +542,8 @@ public class CameraActivity extends Activity 0, 0)); // Flush out all the original data. mDataAdapter.flush(); + mFilmStripView.setDataAdapter(mDataAdapter); } - mFilmStripView.setDataAdapter(mDataAdapter); } private void setRotationAnimation() { diff --git a/src/com/android/camera/PhotoController.java b/src/com/android/camera/PhotoController.java index ce932b04e..f32d2d967 100644 --- a/src/com/android/camera/PhotoController.java +++ b/src/com/android/camera/PhotoController.java @@ -59,4 +59,19 @@ public interface PhotoController extends OnShutterButtonListener { public void updateCameraOrientation(); public void enableRecordingLocation(boolean enable); + + /** + * This is the callback when the UI or buffer holder for camera preview, + * such as {@link android.graphics.SurfaceTexture}, is ready to be used. + * The controller can start the camera preview after or in this callback. + */ + public void onPreviewUIReady(); + + + /** + * This is the callback when the UI or buffer holder for camera preview, + * such as {@link android.graphics.SurfaceTexture}, is being destroyed. + * The controller should try to stop the preview in this callback. + */ + public void onPreviewUIDestroyed(); } diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java index 52125adab..1b0432f51 100644 --- a/src/com/android/camera/PhotoModule.java +++ b/src/com/android/camera/PhotoModule.java @@ -16,14 +16,6 @@ package com.android.camera; -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.List; - import android.annotation.TargetApi; import android.app.Activity; import android.content.ContentProviderClient; @@ -45,7 +37,6 @@ 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; @@ -63,10 +54,10 @@ import com.android.camera.CameraManager.CameraAFMoveCallback; import com.android.camera.CameraManager.CameraPictureCallback; import com.android.camera.CameraManager.CameraProxy; import com.android.camera.CameraManager.CameraShutterCallback; -import com.android.camera.util.ApiHelper; import com.android.camera.ui.CountDownView.OnCountDownFinishedListener; import com.android.camera.ui.PopupManager; import com.android.camera.ui.RotateTextToast; +import com.android.camera.util.ApiHelper; import com.android.camera.util.CameraUtil; import com.android.camera.util.UsageStatistics; import com.android.camera2.R; @@ -74,6 +65,14 @@ import com.android.gallery3d.exif.ExifInterface; import com.android.gallery3d.exif.ExifTag; import com.android.gallery3d.exif.Rational; +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.List; + public class PhotoModule implements CameraModule, PhotoController, @@ -93,14 +92,12 @@ public class PhotoModule 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; + private static final int SHOW_TAP_TO_FOCUS_TOAST = 5; + private static final int SWITCH_CAMERA = 6; + private static final int SWITCH_CAMERA_START_ANIMATION = 7; + private static final int CAMERA_OPEN_DONE = 8; + private static final int OPEN_CAMERA_FAIL = 9; + private static final int CAMERA_DISABLED = 10; // The subset of parameters we need to update in setCameraParameters(). private static final int UPDATE_PARAM_INITIALIZE = 1; @@ -141,7 +138,7 @@ public class PhotoModule private boolean mMeteringAreaSupported; private boolean mAeLockSupported; private boolean mAwbLockSupported; - private boolean mContinousFocusSupported; + private boolean mContinuousFocusSupported; // The degrees of the device rotated clockwise from its natural orientation. private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; @@ -167,8 +164,6 @@ public class PhotoModule } }; - private final StringBuilder mBuilder = new StringBuilder(); - /** * An unpublished intent flag requesting to return as soon as capturing * is completed. @@ -241,8 +236,8 @@ public class PhotoModule private float[] mR = new float[16]; private int mHeading = -1; - CameraStartUpThread mCameraStartUpThread; - ConditionVariable mStartPreviewPrerequisiteReady = new ConditionVariable(); + // True if all the parameters needed to start preview is ready. + private boolean mCameraPreviewParamsReady = false; private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener = new MediaSaveService.OnMediaSavedListener() { @@ -254,42 +249,22 @@ public class PhotoModule } }; - // 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(); + private void checkDisplayRotation() { + // 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 (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) { + setDisplayOrientation(); } - - @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 = CameraUtil.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); - } + if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) { + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + checkDisplayRotation(); + } + }, 100); } } @@ -322,21 +297,6 @@ public class PhotoModule 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 (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) { - setDisplayOrientation(); - } - if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) { - mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100); - } - break; - } - case SHOW_TAP_TO_FOCUS_TOAST: { showTapToFocusToast(); break; @@ -358,13 +318,7 @@ public class PhotoModule break; } - case START_PREVIEW_DONE: { - onPreviewStarted(); - break; - } - case OPEN_CAMERA_FAIL: { - mCameraStartUpThread = null; mOpenCameraFail = true; CameraUtil.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); @@ -372,7 +326,6 @@ public class PhotoModule } case CAMERA_DISABLED: { - mCameraStartUpThread = null; mCameraDisabled = true; CameraUtil.showErrorAndFinish(mActivity, R.string.camera_disabled); @@ -392,11 +345,6 @@ public class PhotoModule 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(); @@ -405,9 +353,6 @@ public class PhotoModule 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); @@ -423,7 +368,6 @@ public class PhotoModule } private void onPreviewStarted() { - mCameraStartUpThread = null; setCameraState(IDLE); startFaceDetection(); locationFirstRun(); @@ -450,6 +394,20 @@ public class PhotoModule : RecordLocationPreference.VALUE_OFF); } + @Override + public void onPreviewUIReady() { + startPreview(); + } + + @Override + public void onPreviewUIDestroyed() { + if (mCameraDevice == null) { + return; + } + mCameraDevice.setPreviewTexture(null); + stopPreview(); + } + private void setLocationPreference(String value) { mPreferences.edit() .putString(CameraSettings.KEY_RECORD_LOCATION, value) @@ -1185,18 +1143,37 @@ public class PhotoModule mPaused = false; } + private void prepareCamera() { + try { + // We need to check whether the activity is paused before long + // operations to ensure that onPause() can be done ASAP. + mCameraDevice = CameraUtil.openCamera(mActivity, mCameraId); + mParameters = mCameraDevice.getParameters(); + + initializeCapabilities(); + if (mFocusManager == null) initializeFocusManager(); + setCameraParameters(UPDATE_PARAM_ALL); + mHandler.sendEmptyMessage(CAMERA_OPEN_DONE); + mCameraPreviewParamsReady = true; + startPreview(); + mOnResumeTime = SystemClock.uptimeMillis(); + checkDisplayRotation(); + } catch (CameraHardwareException e) { + mHandler.sendEmptyMessage(OPEN_CAMERA_FAIL); + } catch (CameraDisabledException e) { + mHandler.sendEmptyMessage(CAMERA_DISABLED); + } + } + + @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(); - } + resetExposureCompensation(); + prepareCamera(); // If first time initialization is not finished, put it in the // message queue. @@ -1223,19 +1200,6 @@ public class PhotoModule } } - void waitCameraStartUpThread() { - try { - if (mCameraStartUpThread != null) { - mCameraStartUpThread.cancel(); - mCameraStartUpThread.join(); - mCameraStartUpThread = null; - setCameraState(IDLE); - } - } catch (InterruptedException e) { - // ignore - } - } - @Override public void onPauseBeforeSuper() { mPaused = true; @@ -1252,9 +1216,6 @@ public class PhotoModule @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 @@ -1279,16 +1240,8 @@ public class PhotoModule // 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); + // Remove the messages and runnables in the queue. + mHandler.removeCallbacksAndMessages(null); closeCamera(); @@ -1484,13 +1437,22 @@ public class PhotoModule 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. + // This can only be called by UI Thread. private void startPreview() { + if (mPaused) { + return; + } + SurfaceTexture st = mUI.getSurfaceTexture(); + if (st == null) { + Log.w(TAG, "startPreview: surfaceTexture is not ready."); + return; + } + if (!mCameraPreviewParamsReady) { + Log.w(TAG, "startPreview: parameters for preview is not ready."); + return; + } mCameraDevice.setErrorCallback(mErrorCallback); // ICS camera frameworks has a bug. Face detection state is not cleared @@ -1510,15 +1472,12 @@ public class PhotoModule } setCameraParameters(UPDATE_PARAM_ALL); // Let UI set its expected aspect ratio - mUI.setPreviewSize(mParameters.getPreviewSize()); - Object st = mUI.getSurfaceTexture(); - if (st != null) { - mCameraDevice.setPreviewTexture((SurfaceTexture) st); - } + mCameraDevice.setPreviewTexture(st); Log.v(TAG, "startPreview"); mCameraDevice.startPreview(); mFocusManager.onPreviewStarted(); + onPreviewStarted(); if (mSnapshotOnIdle) { mHandler.post(mDoSnapRunnable); @@ -1716,7 +1675,7 @@ public class PhotoModule mFocusManager.overrideFocusMode(mParameters.getFocusMode()); } - if (mContinousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) { + if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) { updateAutoFocusMoveCallback(); } } @@ -1866,7 +1825,7 @@ public class PhotoModule mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams); mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams); mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams); - mContinousFocusSupported = mInitialParams.getSupportedFocusModes().contains( + mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains( CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE); } diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java index f5748ba3d..4b353f1cf 100644 --- a/src/com/android/camera/PhotoUI.java +++ b/src/com/android/camera/PhotoUI.java @@ -79,7 +79,7 @@ public class PhotoUI implements PieListener, private PreviewGestures mGestures; private View mRootView; - private Object mSurfaceTexture; + private SurfaceTexture mSurfaceTexture; private PopupWindow mPopup; private ShutterButton mShutterButton; @@ -119,7 +119,6 @@ public class PhotoUI implements PieListener, private TextureView mTextureView; private Matrix mMatrix = null; private float mAspectRatio = 4f / 3f; - private final Object mLock = new Object(); private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { @@ -197,7 +196,7 @@ public class PhotoUI implements PieListener, mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button); mSwitcher = (CameraSwitcher) mRootView.findViewById(R.id.camera_switcher); mSwitcher.setCurrentIndex(CameraSwitcher.PHOTO_MODULE_INDEX); - mSwitcher.setSwitchListener((CameraSwitchListener) mActivity); + mSwitcher.setSwitchListener(mActivity); mMenuButton = mRootView.findViewById(R.id.menu); if (ApiHelper.HAS_FACE_DETECTION) { ViewStub faceViewStub = (ViewStub) mRootView @@ -205,8 +204,7 @@ public class PhotoUI implements PieListener, if (faceViewStub != null) { faceViewStub.inflate(); mFaceView = (FaceView) mRootView.findViewById(R.id.face_view); - setSurfaceTextureSizeChangedListener( - (SurfaceTextureSizeChangedListener) mFaceView); + setSurfaceTextureSizeChangedListener(mFaceView); } } mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls); @@ -222,21 +220,6 @@ public class PhotoUI implements PieListener, mSurfaceTextureSizeListener = listener; } - public void setPreviewSize(Size size) { - int width = size.width; - int height = size.height; - if (width == 0 || height == 0) { - Log.w(TAG, "Preview size should not be 0."); - return; - } - if (width > height) { - mAspectRatio = (float) width / height; - } else { - mAspectRatio = (float) height / width; - } - mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX); - } - private void setTransformMatrix(int width, int height) { mMatrix = mTextureView.getTransform(mMatrix); int orientation = CameraUtil.getDisplayRotation(mActivity); @@ -269,26 +252,28 @@ public class PhotoUI implements PieListener, mTextureView.setTransform(mMatrix); } + @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { - synchronized (mLock) { - mSurfaceTexture = surface; - mLock.notifyAll(); - } + Log.v(TAG, "SurfaceTexture ready."); + mSurfaceTexture = surface; + mController.onPreviewUIReady(); } + @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { // Ignored, Camera does all the work for us } + @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { mSurfaceTexture = null; - mController.stopPreview(); - Log.w(TAG, "surfaceTexture is destroyed"); + mController.onPreviewUIDestroyed(); + Log.w(TAG, "SurfaceTexture destroyed"); return true; } public void onSurfaceTextureUpdated(SurfaceTexture surface) { - // Invoked every time there's a new Camera preview frame + // Do nothing. } public View getRootView() { @@ -707,16 +692,7 @@ public class PhotoUI implements PieListener, mActivity.setSwipingEnabled(enable); } - public Object getSurfaceTexture() { - synchronized (mLock) { - if (mSurfaceTexture == null) { - try { - mLock.wait(); - } catch (InterruptedException e) { - Log.w(TAG, "Unexpected interruption when waiting to get surface texture"); - } - } - } + public SurfaceTexture getSurfaceTexture() { return mSurfaceTexture; } diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java index 76e1c5a31..0a6faba6a 100644 --- a/src/com/android/camera/VideoModule.java +++ b/src/com/android/camera/VideoModule.java @@ -840,7 +840,6 @@ public class VideoModule implements CameraModule, CameraUtil.showErrorAndFinish(mActivity, R.string.camera_disabled); } } - } private void onPreviewStarted() { diff --git a/src/com/android/camera/data/CameraDataAdapter.java b/src/com/android/camera/data/CameraDataAdapter.java index c265e397e..2cdb2c172 100644 --- a/src/com/android/camera/data/CameraDataAdapter.java +++ b/src/com/android/camera/data/CameraDataAdapter.java @@ -276,6 +276,14 @@ public class CameraDataAdapter implements LocalDataAdapter { } private class QueryTask extends AsyncTask<ContentResolver, Void, List<LocalData>> { + + /** + * Loads all the photo and video data in the camera folder in background + * and combine them into one single list. + * + * @param resolver {@link ContentResolver} to load all the data. + * @return An {@link ArrayList} of all loaded data. + */ @Override protected List<LocalData> doInBackground(ContentResolver... resolver) { List<LocalData> l = new ArrayList<LocalData>(); diff --git a/src/com/android/camera/data/FixedFirstDataAdapter.java b/src/com/android/camera/data/FixedFirstDataAdapter.java index ecb9c1402..9f3c4107b 100644 --- a/src/com/android/camera/data/FixedFirstDataAdapter.java +++ b/src/com/android/camera/data/FixedFirstDataAdapter.java @@ -20,7 +20,6 @@ import android.content.Context; import android.net.Uri; import android.view.View; -import com.android.camera.ui.FilmStripView; import com.android.camera.ui.FilmStripView.DataAdapter; import com.android.camera.ui.FilmStripView.ImageData; @@ -32,6 +31,9 @@ import com.android.camera.ui.FilmStripView.ImageData; public class FixedFirstDataAdapter extends AbstractLocalDataAdapterWrapper implements DataAdapter.Listener { + @SuppressWarnings("unused") + private static final String TAG = "CAM_FixedFirstDataAdapter"; + private LocalData mFirstData; private Listener mListener; diff --git a/src/com/android/camera/ui/FilmStripView.java b/src/com/android/camera/ui/FilmStripView.java index 5eceaa4f1..d99a4fcf5 100644 --- a/src/com/android/camera/ui/FilmStripView.java +++ b/src/com/android/camera/ui/FilmStripView.java @@ -516,6 +516,7 @@ public class FilmStripView extends ViewGroup { public void onDraw(Canvas c) { if (mViewInfo[mCurrentInfo] != null && mController.hasNewGeometry()) { layoutChildren(); + super.onDraw(c); } } |