diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/camera/AndroidCameraManagerImpl.java | 86 | ||||
-rw-r--r-- | src/com/android/camera/CameraActivity.java | 29 | ||||
-rw-r--r-- | src/com/android/camera/CameraButtonIntentReceiver.java | 4 | ||||
-rw-r--r-- | src/com/android/camera/CameraHolder.java | 53 | ||||
-rw-r--r-- | src/com/android/camera/CameraManager.java | 51 | ||||
-rw-r--r-- | src/com/android/camera/PhotoModule.java | 65 | ||||
-rw-r--r-- | src/com/android/camera/VideoModule.java | 18 | ||||
-rw-r--r-- | src/com/android/camera/WideAnglePanoramaModule.java | 36 | ||||
-rw-r--r-- | src/com/android/camera/util/CameraUtil.java | 26 |
9 files changed, 265 insertions, 103 deletions
diff --git a/src/com/android/camera/AndroidCameraManagerImpl.java b/src/com/android/camera/AndroidCameraManagerImpl.java index 00fe905a9..bed7ba72e 100644 --- a/src/com/android/camera/AndroidCameraManagerImpl.java +++ b/src/com/android/camera/AndroidCameraManagerImpl.java @@ -202,6 +202,10 @@ class AndroidCameraManagerImpl implements CameraManager { if (mParamsToSet == null) { mParamsToSet = mCamera.getParameters(); } + } else { + if (msg.obj != null) { + ((CameraOpenErrorCallback) msg.obj).onDeviceOpenFailure(msg.arg1); + } } return; @@ -336,8 +340,11 @@ class AndroidCameraManagerImpl implements CameraManager { } @Override - public CameraManager.CameraProxy cameraOpen(int cameraId) { - mCameraHandler.obtainMessage(OPEN_CAMERA, cameraId, 0).sendToTarget(); + public CameraManager.CameraProxy cameraOpen( + Handler handler, int cameraId, CameraOpenErrorCallback callback) { + mCameraHandler.obtainMessage(OPEN_CAMERA, cameraId, 0, + CameraOpenErrorCallbackForward.getNewInstance( + handler, callback)).sendToTarget(); mCameraHandler.waitDone(); if (mCamera != null) { return new AndroidCameraProxyImpl(); @@ -347,8 +354,10 @@ class AndroidCameraManagerImpl implements CameraManager { } /** - * A class which implements {@link CameraManager.CameraProxy} and + * A class which implements {@link CameraManager.CameraProxy} and * camera handler thread. + * TODO: Save the handler for the callback here to avoid passing the same + * handler multiple times. */ public class AndroidCameraProxyImpl implements CameraManager.CameraProxy { @@ -370,12 +379,18 @@ class AndroidCameraManagerImpl implements CameraManager { } @Override - public void reconnect() throws IOException { + public boolean reconnect(Handler handler, CameraOpenErrorCallback cb) { mCameraHandler.sendEmptyMessage(RECONNECT); mCameraHandler.waitDone(); + CameraOpenErrorCallback cbforward = + CameraOpenErrorCallbackForward.getNewInstance(handler, cb); if (mReconnectIOException != null) { - throw mReconnectIOException; + if (cbforward != null) { + cbforward.onReconnectionFailure(AndroidCameraManagerImpl.this); + } + return false; } + return true; } @Override @@ -776,4 +791,65 @@ class AndroidCameraManagerImpl implements CameraManager { }); } } + + /** + * A callback helps to invoke the original callback on another + * {@link android.os.Handler}. + */ + private static class CameraOpenErrorCallbackForward implements CameraOpenErrorCallback { + private final Handler mHandler; + private final CameraOpenErrorCallback mCallback; + + /** + * Returns a new instance of {@link FaceDetectionCallbackForward}. + * + * @param handler The handler in which the callback will be invoked in. + * @param cb The callback to be invoked. + * @return The instance of the {@link FaceDetectionCallbackForward}, or + * null if any parameter is null. + */ + public static CameraOpenErrorCallbackForward getNewInstance( + Handler handler, CameraOpenErrorCallback cb) { + if (handler == null || cb == null) { + return null; + } + return new CameraOpenErrorCallbackForward(handler, cb); + } + + private CameraOpenErrorCallbackForward( + Handler h, CameraOpenErrorCallback cb) { + mHandler = h; + mCallback = cb; + } + + @Override + public void onCameraDisabled(final int cameraId) { + mHandler.post(new Runnable() { + @Override + public void run() { + mCallback.onCameraDisabled(cameraId); + } + }); + } + + @Override + public void onDeviceOpenFailure(final int cameraId) { + mHandler.post(new Runnable() { + @Override + public void run() { + mCallback.onDeviceOpenFailure(cameraId); + } + }); + } + + @Override + public void onReconnectionFailure(final CameraManager mgr) { + mHandler.post(new Runnable() { + @Override + public void run() { + mCallback.onReconnectionFailure(mgr); + } + }); + } + } } diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java index f55d6bc05..15f3966a4 100644 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -19,10 +19,12 @@ package com.android.camera; import android.animation.Animator; import android.app.ActionBar; import android.app.Activity; +import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; @@ -75,6 +77,8 @@ import com.android.camera.util.PhotoSphereHelper; import com.android.camera.util.PhotoSphereHelper.PanoramaViewHelper; import com.android.camera2.R; +import static com.android.camera.CameraManager.CameraOpenErrorCallback; + public class CameraActivity extends Activity implements ModuleSwitcher.ModuleSwitchListener { @@ -206,6 +210,27 @@ public class CameraActivity extends Activity } }; + private CameraOpenErrorCallback mCameraOpenErrorCallback = + new CameraOpenErrorCallback() { + @Override + public void onCameraDisabled(int cameraId) { + CameraUtil.showErrorAndFinish(CameraActivity.this, + R.string.camera_disabled); + } + + @Override + public void onDeviceOpenFailure(int cameraId) { + CameraUtil.showErrorAndFinish(CameraActivity.this, + R.string.cannot_connect_camera); + } + + @Override + public void onReconnectionFailure(CameraManager mgr) { + CameraUtil.showErrorAndFinish(CameraActivity.this, + R.string.cannot_connect_camera); + } + }; + // close activity when screen turns off private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() { @Override @@ -1282,4 +1307,8 @@ public class CameraActivity extends Activity return (mCurrentModule instanceof VideoModule) ? ((VideoModule) mCurrentModule).isRecording() : false; } + + public CameraOpenErrorCallback getCameraOpenErrorCallback() { + return mCameraOpenErrorCallback; + } } diff --git a/src/com/android/camera/CameraButtonIntentReceiver.java b/src/com/android/camera/CameraButtonIntentReceiver.java index a65942d57..253105aca 100644 --- a/src/com/android/camera/CameraButtonIntentReceiver.java +++ b/src/com/android/camera/CameraButtonIntentReceiver.java @@ -38,7 +38,9 @@ public class CameraButtonIntentReceiver extends BroadcastReceiver { CameraHolder holder = CameraHolder.instance(); ComboPreferences pref = new ComboPreferences(context); int cameraId = CameraSettings.readPreferredCameraId(pref); - if (holder.tryOpen(cameraId) == null) return; + if (holder.tryOpen(null, cameraId, null) == null) { + return; + } // We are going to launch the camera, so hold the camera for later use holder.keep(); diff --git a/src/com/android/camera/CameraHolder.java b/src/com/android/camera/CameraHolder.java index 0ffc73663..32eae8289 100644 --- a/src/com/android/camera/CameraHolder.java +++ b/src/com/android/camera/CameraHolder.java @@ -188,8 +188,9 @@ public class CameraHolder { return mInfo; } - public synchronized CameraProxy open(int cameraId) - throws CameraHardwareException { + public synchronized CameraProxy open( + Handler handler, int cameraId, + CameraManager.CameraOpenErrorCallback cb) { if (DEBUG_OPEN_RELEASE) { collectState(cameraId, mCameraDevice); if (mCameraOpened) { @@ -204,28 +205,28 @@ public class CameraHolder { mCameraId = -1; } if (mCameraDevice == null) { - try { - Log.v(TAG, "open camera " + cameraId); - if (mMockCameraInfo == null) { - mCameraDevice = CameraManagerFactory - .getAndroidCameraManager().cameraOpen(cameraId); - } else { - if (mMockCamera == null) - throw new RuntimeException(); + Log.v(TAG, "open camera " + cameraId); + if (mMockCameraInfo == null) { + mCameraDevice = CameraManagerFactory + .getAndroidCameraManager().cameraOpen(handler, cameraId, cb); + } else { + if (mMockCamera != null) { mCameraDevice = mMockCamera[cameraId]; + } else { + Log.e(TAG, "MockCameraInfo found, but no MockCamera provided."); + mCameraDevice = null; } - mCameraId = cameraId; - } catch (RuntimeException e) { - Log.e(TAG, "fail to connect Camera", e); - throw new CameraHardwareException(e); } + if (mCameraDevice == null) { + Log.e(TAG, "fail to connect Camera:" + mCameraId + ", aborting."); + return null; + } + mCameraId = cameraId; mParameters = mCameraDevice.getParameters(); } else { - try { - mCameraDevice.reconnect(); - } catch (IOException e) { - Log.e(TAG, "reconnect failed."); - throw new CameraHardwareException(e); + if (!mCameraDevice.reconnect(handler, cb)) { + Log.e(TAG, "fail to reconnect Camera:" + mCameraId + ", aborting."); + return null; } mCameraDevice.setParameters(mParameters); } @@ -239,17 +240,9 @@ public class CameraHolder { * Tries to open the hardware camera. If the camera is being used or * unavailable then return {@code null}. */ - public synchronized CameraProxy tryOpen(int cameraId) { - try { - return !mCameraOpened ? open(cameraId) : null; - } catch (CameraHardwareException e) { - // In eng build, we throw the exception so that test tool - // can detect it and report it - if ("eng".equals(Build.TYPE)) { - throw new RuntimeException(e); - } - return null; - } + public synchronized CameraProxy tryOpen( + Handler handler, int cameraId, CameraManager.CameraOpenErrorCallback cb) { + return (!mCameraOpened ? open(handler, cameraId, cb) : null); } public synchronized void release() { diff --git a/src/com/android/camera/CameraManager.java b/src/com/android/camera/CameraManager.java index 4a8057d3f..07b8150ca 100644 --- a/src/com/android/camera/CameraManager.java +++ b/src/com/android/camera/CameraManager.java @@ -101,12 +101,49 @@ public interface CameraManager { } /** + * An interface to be called for any exception caught when opening the + * camera device. This error callback is different from the one defined + * in the framework, {@link android.hardware.Camera.ErrorCallback}, which + * is used after the camera is opened. + */ + public interface CameraOpenErrorCallback { + /** + * Callback when {@link com.android.camera.CameraDisabledException} is + * caught. + * + * @param cameraId The disabled camera. + */ + public void onCameraDisabled(int cameraId); + + /** + * Callback when {@link com.android.camera.CameraHardwareException} is + * caught. + * + * @param cameraId The camera with the hardware failure. + */ + public void onDeviceOpenFailure(int cameraId); + + /** + * Callback when {@link java.io.IOException} is caught during + * {@link android.hardware.Camera#reconnect()}. + * + * @param mgr The {@link com.android.camera.CameraManager} + * with the reconnect failure. + */ + public void onReconnectionFailure(CameraManager mgr); + } + + /** * Opens the camera of the specified ID synchronously. * - * @param cameraId The camera ID to open. + * @param handler The {@link android.os.Handler} in which the callback + * was handled. + * @param callback The callback when any error happens. + * @param cameraId The camera ID to open. * @return An instance of {@link CameraProxy} on success. null on failure. */ - public CameraProxy cameraOpen(int cameraId); + public CameraProxy cameraOpen( + Handler handler, int cameraId, CameraOpenErrorCallback callback); /** * An interface that takes camera operation requests and post messages to the @@ -132,10 +169,14 @@ public interface CameraManager { /** * Reconnects to the camera device. - * * @see android.hardware.Camera#reconnect() + * + * @param handler The {@link android.os.Handler} in which the callback + * was handled. + * @param cb The callback when any error happens. + * @return {@code false} on errors. */ - public void reconnect() throws IOException; + public boolean reconnect(Handler handler, CameraOpenErrorCallback cb); /** * Unlocks the camera device. @@ -180,7 +221,7 @@ public interface CameraManager { /** * Sets the callback for preview data. * - * @param handler handler in which the callback was handled. + * @param handler The {@link android.os.Handler} in which the callback was handled. * @param cb The callback to be invoked when the preview data is available. * @see android.hardware.Camera#setPreviewCallback(android.hardware.Camera.PreviewCallback) */ diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java index d00da1935..e3bdc25fe 100644 --- a/src/com/android/camera/PhotoModule.java +++ b/src/com/android/camera/PhotoModule.java @@ -462,16 +462,14 @@ public class PhotoModule // Restart the camera and initialize the UI. From onCreate. mPreferences.setLocalId(mActivity, mCameraId); CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); - try { - mCameraDevice = CameraUtil.openCamera(mActivity, mCameraId); - mParameters = mCameraDevice.getParameters(); - } catch (CameraHardwareException e) { - CameraUtil.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); - return; - } catch (CameraDisabledException e) { - CameraUtil.showErrorAndFinish(mActivity, R.string.camera_disabled); + mCameraDevice = CameraUtil.openCamera( + mActivity, mCameraId, mHandler, + mActivity.getCameraOpenErrorCallback()); + if (mCameraDevice == null) { + Log.e(TAG, "Failed to open camera:" + mCameraId + ", aborting."); return; } + mParameters = mCameraDevice.getParameters(); initializeCapabilities(); CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT); @@ -1166,26 +1164,32 @@ 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); + /** + * Opens the camera device. + * + * @return Whether the camera was opened successfully. + */ + private boolean prepareCamera() { + // 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, mHandler, + mActivity.getCameraOpenErrorCallback()); + if (mCameraDevice == null) { + Log.e(TAG, "Failed to open camera:" + mCameraId); + return false; } + mParameters = mCameraDevice.getParameters(); + + initializeCapabilities(); + if (mFocusManager == null) initializeFocusManager(); + setCameraParameters(UPDATE_PARAM_ALL); + mHandler.sendEmptyMessage(CAMERA_OPEN_DONE); + mCameraPreviewParamsReady = true; + startPreview(); + mOnResumeTime = SystemClock.uptimeMillis(); + checkDisplayRotation(); + return true; } @@ -1196,7 +1200,10 @@ public class PhotoModule mJpegPictureCallbackTime = 0; mZoomValue = 0; resetExposureCompensation(); - prepareCamera(); + if (!prepareCamera()) { + // Camera failure. + return; + } // If first time initialization is not finished, put it in the // message queue. @@ -1720,7 +1727,7 @@ public class PhotoModule private void updateAutoFocusMoveCallback() { if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) { mCameraDevice.setAutoFocusMoveCallback(mHandler, - (CameraManager.CameraAFMoveCallback) mAutoFocusMoveCallback); + (CameraAFMoveCallback) mAutoFocusMoveCallback); } else { mCameraDevice.setAutoFocusMoveCallback(null, null); } diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java index 56882e1cf..bf5ef8942 100644 --- a/src/com/android/camera/VideoModule.java +++ b/src/com/android/camera/VideoModule.java @@ -208,16 +208,16 @@ public class VideoModule implements CameraModule, } private void openCamera() { - try { - if (mCameraDevice == null) { - mCameraDevice = CameraUtil.openCamera(mActivity, mCameraId); - } - mParameters = mCameraDevice.getParameters(); - } catch (CameraHardwareException e) { - mOpenCameraFail = true; - } catch (CameraDisabledException e) { - mCameraDisabled = true; + if (mCameraDevice == null) { + mCameraDevice = CameraUtil.openCamera( + mActivity, mCameraId, mHandler, + mActivity.getCameraOpenErrorCallback()); } + if (mCameraDevice == null) { + // Error. + return; + } + mParameters = mCameraDevice.getParameters(); } // This Handler is used to post message back onto the main thread of the diff --git a/src/com/android/camera/WideAnglePanoramaModule.java b/src/com/android/camera/WideAnglePanoramaModule.java index abdb24825..59c4350be 100644 --- a/src/com/android/camera/WideAnglePanoramaModule.java +++ b/src/com/android/camera/WideAnglePanoramaModule.java @@ -316,11 +316,19 @@ public class WideAnglePanoramaModule } } - private void setupCamera() throws CameraHardwareException, CameraDisabledException { - openCamera(); + /** + * Opens camera and sets the parameters. + * + * @return Whether the camera was opened successfully. + */ + private boolean setupCamera() { + if (!openCamera()) { + return false; + } Parameters parameters = mCameraDevice.getParameters(); setupCaptureParams(parameters); configureCamera(parameters); + return true; } private void releaseCamera() { @@ -331,16 +339,27 @@ public class WideAnglePanoramaModule } } - private void openCamera() throws CameraHardwareException, CameraDisabledException { + /** + * Opens the camera device. The back camera has priority over the front + * one. + * + * @return Whether the camera was opened successfully. + */ + private boolean openCamera() { int cameraId = CameraHolder.instance().getBackCameraId(); // If there is no back camera, use the first camera. Camera id starts // from 0. Currently if a camera is not back facing, it is front facing. // This is also forward compatible if we have a new facing other than // back or front in the future. if (cameraId == -1) cameraId = 0; - mCameraDevice = CameraUtil.openCamera(mActivity, cameraId); + mCameraDevice = CameraUtil.openCamera(mActivity, cameraId, + mMainHandler, mActivity.getCameraOpenErrorCallback()); + if (mCameraDevice == null) { + return false; + } mCameraOrientation = CameraUtil.getCameraOrientation(cameraId); if (cameraId == CameraHolder.instance().getFrontCameraId()) mUsingFrontCamera = true; + return true; } private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3, @@ -820,13 +839,8 @@ public class WideAnglePanoramaModule mCaptureState = CAPTURE_STATE_VIEWFINDER; - try { - setupCamera(); - } catch (CameraHardwareException e) { - CameraUtil.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); - return; - } catch (CameraDisabledException e) { - CameraUtil.showErrorAndFinish(mActivity, R.string.camera_disabled); + if (!setupCamera()) { + Log.e(TAG, "Failed to open camera, aborting"); return; } diff --git a/src/com/android/camera/util/CameraUtil.java b/src/com/android/camera/util/CameraUtil.java index ca0109ab3..adaaaa776 100644 --- a/src/com/android/camera/util/CameraUtil.java +++ b/src/com/android/camera/util/CameraUtil.java @@ -48,6 +48,7 @@ import android.hardware.Camera.Size; import android.location.Location; import android.net.Uri; import android.os.Build; +import android.os.Handler; import android.os.ParcelFileDescriptor; import android.telephony.TelephonyManager; import android.util.DisplayMetrics; @@ -337,21 +338,20 @@ public class CameraUtil { } public static CameraManager.CameraProxy openCamera( - Activity activity, int cameraId) - throws CameraHardwareException, CameraDisabledException { - throwIfCameraDisabled(activity); - + Activity activity, final int cameraId, + Handler handler, final CameraManager.CameraOpenErrorCallback cb) { try { - return CameraHolder.instance().open(cameraId); - } catch (CameraHardwareException e) { - // In eng build, we throw the exception so that test tool - // can detect it and report it - if ("eng".equals(Build.TYPE)) { - throw new RuntimeException("openCamera failed", e); - } else { - throw e; - } + throwIfCameraDisabled(activity); + return CameraHolder.instance().open(handler, cameraId, cb); + } catch (CameraDisabledException ex) { + handler.post(new Runnable() { + @Override + public void run() { + cb.onCameraDisabled(cameraId); + } + }); } + return null; } public static void showErrorAndFinish(final Activity activity, int msgId) { |