From b7880782b92e214d98bb957fb2ff6f7d5fffd104 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Tue, 10 Nov 2015 15:34:22 +0100 Subject: Android: check for exceptions in some camera operations. Not all camera operations are documented to raise exceptions, but they actually might do so depending on the hardware/drivers. Check for exceptions in all functions that could porentially fail and react appropriately. Task-number: QTBUG-49134 Change-Id: I633ca7f2e3aeb6532e1c445735e62135f52cf25f Reviewed-by: Christian Stromme --- .../src/mediacapture/qandroidcamerasession.cpp | 29 +++++++++++++++++++++ .../src/mediacapture/qandroidcamerasession.h | 2 ++ .../android/src/wrappers/jni/androidcamera.cpp | 30 ++++++++++++++++++++-- .../android/src/wrappers/jni/androidcamera.h | 2 ++ 4 files changed, 61 insertions(+), 2 deletions(-) (limited to 'src/plugins/android/src') diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index 179bcdf96..743764cb0 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -214,6 +214,8 @@ bool QAndroidCameraSession::open() connect(m_camera, SIGNAL(pictureCaptured(QByteArray)), this, SLOT(onCameraPictureCaptured(QByteArray))); connect(m_camera, SIGNAL(previewStarted()), this, SLOT(onCameraPreviewStarted())); connect(m_camera, SIGNAL(previewStopped()), this, SLOT(onCameraPreviewStopped())); + connect(m_camera, &AndroidCamera::previewFailedToStart, this, &QAndroidCameraSession::onCameraPreviewFailedToStart); + connect(m_camera, &AndroidCamera::takePictureFailed, this, &QAndroidCameraSession::onCameraTakePictureFailed); m_nativeOrientation = m_camera->getNativeOrientation(); @@ -554,6 +556,12 @@ void QAndroidCameraSession::cancelCapture() m_captureCanceled = true; } +void QAndroidCameraSession::onCameraTakePictureFailed() +{ + emit imageCaptureError(m_currentImageCaptureId, QCameraImageCapture::ResourceError, + tr("Failed to capture image")); +} + void QAndroidCameraSession::onCameraPictureExposed() { if (m_captureCanceled) @@ -646,6 +654,27 @@ void QAndroidCameraSession::onCameraPreviewStarted() setReadyForCapture(true); } +void QAndroidCameraSession::onCameraPreviewFailedToStart() +{ + if (m_status == QCamera::StartingStatus) { + Q_EMIT error(QCamera::CameraError, tr("Camera preview failed to start.")); + + AndroidMultimediaUtils::enableOrientationListener(false); + m_camera->setPreviewSize(QSize()); + m_camera->setPreviewTexture(0); + if (m_videoOutput) { + m_videoOutput->stop(); + m_videoOutput->reset(); + } + m_previewStarted = false; + + m_status = QCamera::LoadedStatus; + emit statusChanged(m_status); + + setReadyForCapture(false); + } +} + void QAndroidCameraSession::onCameraPreviewStopped() { if (m_status == QCamera::StoppingStatus) { diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.h b/src/plugins/android/src/mediacapture/qandroidcamerasession.h index a56721bcd..c1772053d 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.h +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.h @@ -112,11 +112,13 @@ private Q_SLOTS: void onApplicationStateChanged(Qt::ApplicationState state); + void onCameraTakePictureFailed(); void onCameraPictureExposed(); void onCameraPictureCaptured(const QByteArray &data); void onLastPreviewFrameFetched(const QByteArray &preview, int width, int height); void onNewPreviewFrame(const QByteArray &frame, int width, int height); void onCameraPreviewStarted(); + void onCameraPreviewFailedToStart(); void onCameraPreviewStopped(); private: diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.cpp b/src/plugins/android/src/wrappers/jni/androidcamera.cpp index a4acbd8f9..7d8e4532d 100644 --- a/src/plugins/android/src/wrappers/jni/androidcamera.cpp +++ b/src/plugins/android/src/wrappers/jni/androidcamera.cpp @@ -224,12 +224,15 @@ public: Q_SIGNALS: void previewSizeChanged(); void previewStarted(); + void previewFailedToStart(); void previewStopped(); void autoFocusStarted(); void whiteBalanceChanged(); + void takePictureFailed(); + void lastPreviewFrameFetched(const QByteArray &preview, int width, int height); }; @@ -245,9 +248,11 @@ AndroidCamera::AndroidCamera(AndroidCameraPrivate *d, QThread *worker) connect(d, &AndroidCameraPrivate::previewSizeChanged, this, &AndroidCamera::previewSizeChanged); connect(d, &AndroidCameraPrivate::previewStarted, this, &AndroidCamera::previewStarted); + connect(d, &AndroidCameraPrivate::previewFailedToStart, this, &AndroidCamera::previewFailedToStart); connect(d, &AndroidCameraPrivate::previewStopped, this, &AndroidCamera::previewStopped); connect(d, &AndroidCameraPrivate::autoFocusStarted, this, &AndroidCamera::autoFocusStarted); connect(d, &AndroidCameraPrivate::whiteBalanceChanged, this, &AndroidCamera::whiteBalanceChanged); + connect(d, &AndroidCameraPrivate::takePictureFailed, this, &AndroidCamera::takePictureFailed); connect(d, &AndroidCameraPrivate::lastPreviewFrameFetched, this, &AndroidCamera::lastPreviewFrameFetched); } @@ -1057,15 +1062,21 @@ void AndroidCameraPrivate::setFocusAreas(const QList &areas) void AndroidCameraPrivate::autoFocus() { + QJNIEnvironmentPrivate env; + m_camera.callMethod("autoFocus", "(Landroid/hardware/Camera$AutoFocusCallback;)V", m_cameraListener.object()); - emit autoFocusStarted(); + + if (!exceptionCheckAndClear(env)) + emit autoFocusStarted(); } void AndroidCameraPrivate::cancelAutoFocus() { + QJNIEnvironmentPrivate env; m_camera.callMethod("cancelAutoFocus"); + exceptionCheckAndClear(env); } bool AndroidCameraPrivate::isAutoExposureLockSupported() @@ -1314,25 +1325,40 @@ void AndroidCameraPrivate::setJpegQuality(int quality) void AndroidCameraPrivate::startPreview() { + QJNIEnvironmentPrivate env; + setupPreviewFrameCallback(); m_camera.callMethod("startPreview"); - emit previewStarted(); + + if (exceptionCheckAndClear(env)) + emit previewFailedToStart(); + else + emit previewStarted(); } void AndroidCameraPrivate::stopPreview() { + QJNIEnvironmentPrivate env; + m_camera.callMethod("stopPreview"); + + exceptionCheckAndClear(env); emit previewStopped(); } void AndroidCameraPrivate::takePicture() { + QJNIEnvironmentPrivate env; + m_camera.callMethod("takePicture", "(Landroid/hardware/Camera$ShutterCallback;" "Landroid/hardware/Camera$PictureCallback;" "Landroid/hardware/Camera$PictureCallback;)V", m_cameraListener.object(), jobject(0), m_cameraListener.object()); + + if (exceptionCheckAndClear(env)) + emit takePictureFailed(); } void AndroidCameraPrivate::setupPreviewFrameCallback() diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.h b/src/plugins/android/src/wrappers/jni/androidcamera.h index 7a8ae8b23..b5903688d 100644 --- a/src/plugins/android/src/wrappers/jni/androidcamera.h +++ b/src/plugins/android/src/wrappers/jni/androidcamera.h @@ -168,6 +168,7 @@ public: Q_SIGNALS: void previewSizeChanged(); void previewStarted(); + void previewFailedToStart(); void previewStopped(); void autoFocusStarted(); @@ -175,6 +176,7 @@ Q_SIGNALS: void whiteBalanceChanged(); + void takePictureFailed(); void pictureExposed(); void pictureCaptured(const QByteArray &data); void lastPreviewFrameFetched(const QByteArray &preview, int width, int height); -- cgit v1.2.3