Android: Make sure we check and clear exceptions from the camera.
In several places we where ignoring the fact that we might get an exception from the camera code on Android. Failing to clear them will cause the application to to terminate. Task-number: QTBUG-39425 Change-Id: Idfe40e1749f54d551d37dae25912d9ddbc3da01e Reviewed-by: Yoann Lopes <yoann.lopes@digia.com>
This commit is contained in:
committed by
Christian Stromme
parent
389d66b3ed
commit
a7d10a265a
@@ -331,11 +331,12 @@ bool QAndroidCameraSession::startPreview()
|
|||||||
if (m_previewStarted)
|
if (m_previewStarted)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (m_videoOutput->isReady())
|
if (!m_videoOutput->isReady())
|
||||||
m_camera->setPreviewTexture(m_videoOutput->surfaceTexture());
|
|
||||||
else
|
|
||||||
return true; // delay starting until the video output is ready
|
return true; // delay starting until the video output is ready
|
||||||
|
|
||||||
|
if (!m_camera->setPreviewTexture(m_videoOutput->surfaceTexture()))
|
||||||
|
return false;
|
||||||
|
|
||||||
m_status = QCamera::StartingStatus;
|
m_status = QCamera::StartingStatus;
|
||||||
emit statusChanged(m_status);
|
emit statusChanged(m_status);
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,19 @@ static QMutex g_cameraMapMutex;
|
|||||||
typedef QMap<int, AndroidCamera *> CameraMap;
|
typedef QMap<int, AndroidCamera *> CameraMap;
|
||||||
Q_GLOBAL_STATIC(CameraMap, g_cameraMap)
|
Q_GLOBAL_STATIC(CameraMap, g_cameraMap)
|
||||||
|
|
||||||
|
static inline bool exceptionCheckAndClear(JNIEnv *env)
|
||||||
|
{
|
||||||
|
if (Q_UNLIKELY(env->ExceptionCheck())) {
|
||||||
|
#ifdef QT_DEBUG
|
||||||
|
env->ExceptionDescribe();
|
||||||
|
#endif // QT_DEBUG
|
||||||
|
env->ExceptionClear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static QRect areaToRect(jobject areaObj)
|
static QRect areaToRect(jobject areaObj)
|
||||||
{
|
{
|
||||||
QJNIObjectPrivate area(areaObj);
|
QJNIObjectPrivate area(areaObj);
|
||||||
@@ -132,9 +145,9 @@ public:
|
|||||||
Q_INVOKABLE bool init(int cameraId);
|
Q_INVOKABLE bool init(int cameraId);
|
||||||
|
|
||||||
Q_INVOKABLE void release();
|
Q_INVOKABLE void release();
|
||||||
Q_INVOKABLE void lock();
|
Q_INVOKABLE bool lock();
|
||||||
Q_INVOKABLE void unlock();
|
Q_INVOKABLE bool unlock();
|
||||||
Q_INVOKABLE void reconnect();
|
Q_INVOKABLE bool reconnect();
|
||||||
|
|
||||||
Q_INVOKABLE AndroidCamera::CameraFacing getFacing();
|
Q_INVOKABLE AndroidCamera::CameraFacing getFacing();
|
||||||
Q_INVOKABLE int getNativeOrientation();
|
Q_INVOKABLE int getNativeOrientation();
|
||||||
@@ -147,7 +160,7 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE QSize previewSize() const { return m_previewSize; }
|
Q_INVOKABLE QSize previewSize() const { return m_previewSize; }
|
||||||
Q_INVOKABLE void updatePreviewSize();
|
Q_INVOKABLE void updatePreviewSize();
|
||||||
Q_INVOKABLE void setPreviewTexture(void *surfaceTexture);
|
Q_INVOKABLE bool setPreviewTexture(void *surfaceTexture);
|
||||||
|
|
||||||
Q_INVOKABLE bool isZoomSupported();
|
Q_INVOKABLE bool isZoomSupported();
|
||||||
Q_INVOKABLE int getMaxZoom();
|
Q_INVOKABLE int getMaxZoom();
|
||||||
@@ -266,7 +279,7 @@ AndroidCamera *AndroidCamera::open(int cameraId)
|
|||||||
worker->start();
|
worker->start();
|
||||||
d->moveToThread(worker);
|
d->moveToThread(worker);
|
||||||
connect(worker, &QThread::finished, d, &AndroidCameraPrivate::deleteLater);
|
connect(worker, &QThread::finished, d, &AndroidCameraPrivate::deleteLater);
|
||||||
bool ok = false;
|
bool ok = true;
|
||||||
QMetaObject::invokeMethod(d, "init", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ok), Q_ARG(int, cameraId));
|
QMetaObject::invokeMethod(d, "init", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ok), Q_ARG(int, cameraId));
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
worker->quit();
|
worker->quit();
|
||||||
@@ -289,22 +302,28 @@ int AndroidCamera::cameraId() const
|
|||||||
return d->m_cameraId;
|
return d->m_cameraId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidCamera::lock()
|
bool AndroidCamera::lock()
|
||||||
{
|
{
|
||||||
Q_D(AndroidCamera);
|
Q_D(AndroidCamera);
|
||||||
QMetaObject::invokeMethod(d, "lock", Qt::BlockingQueuedConnection);
|
bool ok = true;
|
||||||
|
QMetaObject::invokeMethod(d, "lock", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ok));
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidCamera::unlock()
|
bool AndroidCamera::unlock()
|
||||||
{
|
{
|
||||||
Q_D(AndroidCamera);
|
Q_D(AndroidCamera);
|
||||||
QMetaObject::invokeMethod(d, "unlock", Qt::BlockingQueuedConnection);
|
bool ok = true;
|
||||||
|
QMetaObject::invokeMethod(d, "unlock", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ok));
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidCamera::reconnect()
|
bool AndroidCamera::reconnect()
|
||||||
{
|
{
|
||||||
Q_D(AndroidCamera);
|
Q_D(AndroidCamera);
|
||||||
QMetaObject::invokeMethod(d, "reconnect");
|
bool ok = true;
|
||||||
|
QMetaObject::invokeMethod(d, "reconnect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ok));
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidCamera::release()
|
void AndroidCamera::release()
|
||||||
@@ -368,13 +387,16 @@ void AndroidCamera::setPreviewSize(const QSize &size)
|
|||||||
QMetaObject::invokeMethod(d, "updatePreviewSize");
|
QMetaObject::invokeMethod(d, "updatePreviewSize");
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidCamera::setPreviewTexture(AndroidSurfaceTexture *surfaceTexture)
|
bool AndroidCamera::setPreviewTexture(AndroidSurfaceTexture *surfaceTexture)
|
||||||
{
|
{
|
||||||
Q_D(AndroidCamera);
|
Q_D(AndroidCamera);
|
||||||
|
bool ok = true;
|
||||||
QMetaObject::invokeMethod(d,
|
QMetaObject::invokeMethod(d,
|
||||||
"setPreviewTexture",
|
"setPreviewTexture",
|
||||||
Qt::BlockingQueuedConnection,
|
Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(bool, ok),
|
||||||
Q_ARG(void *, surfaceTexture ? surfaceTexture->surfaceTexture() : 0));
|
Q_ARG(void *, surfaceTexture ? surfaceTexture->surfaceTexture() : 0));
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidCamera::isZoomSupported()
|
bool AndroidCamera::isZoomSupported()
|
||||||
@@ -698,12 +720,12 @@ AndroidCameraPrivate::~AndroidCameraPrivate()
|
|||||||
bool AndroidCameraPrivate::init(int cameraId)
|
bool AndroidCameraPrivate::init(int cameraId)
|
||||||
{
|
{
|
||||||
m_cameraId = cameraId;
|
m_cameraId = cameraId;
|
||||||
|
QJNIEnvironmentPrivate env;
|
||||||
m_camera = QJNIObjectPrivate::callStaticObjectMethod("android/hardware/Camera",
|
m_camera = QJNIObjectPrivate::callStaticObjectMethod("android/hardware/Camera",
|
||||||
"open",
|
"open",
|
||||||
"(I)Landroid/hardware/Camera;",
|
"(I)Landroid/hardware/Camera;",
|
||||||
cameraId);
|
cameraId);
|
||||||
|
if (exceptionCheckAndClear(env) || !m_camera.isValid())
|
||||||
if (!m_camera.isValid())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_cameraListener = QJNIObjectPrivate(g_qtCameraListenerClass, "(I)V", m_cameraId);
|
m_cameraListener = QJNIObjectPrivate(g_qtCameraListenerClass, "(I)V", m_cameraId);
|
||||||
@@ -731,26 +753,25 @@ void AndroidCameraPrivate::release()
|
|||||||
m_camera.callMethod<void>("release");
|
m_camera.callMethod<void>("release");
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidCameraPrivate::lock()
|
bool AndroidCameraPrivate::lock()
|
||||||
{
|
{
|
||||||
|
QJNIEnvironmentPrivate env;
|
||||||
m_camera.callMethod<void>("lock");
|
m_camera.callMethod<void>("lock");
|
||||||
|
return !exceptionCheckAndClear(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidCameraPrivate::unlock()
|
bool AndroidCameraPrivate::unlock()
|
||||||
{
|
{
|
||||||
|
QJNIEnvironmentPrivate env;
|
||||||
m_camera.callMethod<void>("unlock");
|
m_camera.callMethod<void>("unlock");
|
||||||
|
return !exceptionCheckAndClear(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidCameraPrivate::reconnect()
|
bool AndroidCameraPrivate::reconnect()
|
||||||
{
|
{
|
||||||
QJNIEnvironmentPrivate env;
|
QJNIEnvironmentPrivate env;
|
||||||
m_camera.callMethod<void>("reconnect");
|
m_camera.callMethod<void>("reconnect");
|
||||||
if (env->ExceptionCheck()) {
|
return !exceptionCheckAndClear(env);
|
||||||
#ifdef QT_DEBUG
|
|
||||||
env->ExceptionDescribe();
|
|
||||||
#endif // QT_DEBUG
|
|
||||||
env->ExceptionDescribe();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidCamera::CameraFacing AndroidCameraPrivate::getFacing()
|
AndroidCamera::CameraFacing AndroidCameraPrivate::getFacing()
|
||||||
@@ -832,11 +853,13 @@ void AndroidCameraPrivate::updatePreviewSize()
|
|||||||
emit previewSizeChanged();
|
emit previewSizeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidCameraPrivate::setPreviewTexture(void *surfaceTexture)
|
bool AndroidCameraPrivate::setPreviewTexture(void *surfaceTexture)
|
||||||
{
|
{
|
||||||
|
QJNIEnvironmentPrivate env;
|
||||||
m_camera.callMethod<void>("setPreviewTexture",
|
m_camera.callMethod<void>("setPreviewTexture",
|
||||||
"(Landroid/graphics/SurfaceTexture;)V",
|
"(Landroid/graphics/SurfaceTexture;)V",
|
||||||
static_cast<jobject>(surfaceTexture));
|
static_cast<jobject>(surfaceTexture));
|
||||||
|
return !exceptionCheckAndClear(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidCameraPrivate::isZoomSupported()
|
bool AndroidCameraPrivate::isZoomSupported()
|
||||||
@@ -1020,8 +1043,7 @@ void AndroidCameraPrivate::setFocusAreas(const QList<QRect> &areas)
|
|||||||
arrayList.callMethod<jboolean>("add",
|
arrayList.callMethod<jboolean>("add",
|
||||||
"(Ljava/lang/Object;)Z",
|
"(Ljava/lang/Object;)Z",
|
||||||
rectToArea(areas.at(i)).object());
|
rectToArea(areas.at(i)).object());
|
||||||
if (env->ExceptionCheck())
|
exceptionCheckAndClear(env);
|
||||||
env->ExceptionClear();
|
|
||||||
}
|
}
|
||||||
list = arrayList;
|
list = arrayList;
|
||||||
}
|
}
|
||||||
@@ -1347,9 +1369,11 @@ void AndroidCameraPrivate::fetchLastPreviewFrame()
|
|||||||
|
|
||||||
void AndroidCameraPrivate::applyParameters()
|
void AndroidCameraPrivate::applyParameters()
|
||||||
{
|
{
|
||||||
|
QJNIEnvironmentPrivate env;
|
||||||
m_camera.callMethod<void>("setParameters",
|
m_camera.callMethod<void>("setParameters",
|
||||||
"(Landroid/hardware/Camera$Parameters;)V",
|
"(Landroid/hardware/Camera$Parameters;)V",
|
||||||
m_parameters.object());
|
m_parameters.object());
|
||||||
|
exceptionCheckAndClear(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList AndroidCameraPrivate::callParametersStringListMethod(const QByteArray &methodName)
|
QStringList AndroidCameraPrivate::callParametersStringListMethod(const QByteArray &methodName)
|
||||||
@@ -1386,10 +1410,8 @@ static JNINativeMethod methods[] = {
|
|||||||
bool AndroidCamera::initJNI(JNIEnv *env)
|
bool AndroidCamera::initJNI(JNIEnv *env)
|
||||||
{
|
{
|
||||||
jclass clazz = env->FindClass("org/qtproject/qt5/android/multimedia/QtCameraListener");
|
jclass clazz = env->FindClass("org/qtproject/qt5/android/multimedia/QtCameraListener");
|
||||||
if (env->ExceptionCheck())
|
|
||||||
env->ExceptionClear();
|
|
||||||
|
|
||||||
if (clazz) {
|
if (!exceptionCheckAndClear(env) && clazz) {
|
||||||
g_qtCameraListenerClass = static_cast<jclass>(env->NewGlobalRef(clazz));
|
g_qtCameraListenerClass = static_cast<jclass>(env->NewGlobalRef(clazz));
|
||||||
if (env->RegisterNatives(g_qtCameraListenerClass,
|
if (env->RegisterNatives(g_qtCameraListenerClass,
|
||||||
methods,
|
methods,
|
||||||
|
|||||||
@@ -90,9 +90,9 @@ public:
|
|||||||
|
|
||||||
int cameraId() const;
|
int cameraId() const;
|
||||||
|
|
||||||
void lock();
|
bool lock();
|
||||||
void unlock();
|
bool unlock();
|
||||||
void reconnect();
|
bool reconnect();
|
||||||
void release();
|
void release();
|
||||||
|
|
||||||
CameraFacing getFacing();
|
CameraFacing getFacing();
|
||||||
@@ -106,7 +106,7 @@ public:
|
|||||||
|
|
||||||
QSize previewSize() const;
|
QSize previewSize() const;
|
||||||
void setPreviewSize(const QSize &size);
|
void setPreviewSize(const QSize &size);
|
||||||
void setPreviewTexture(AndroidSurfaceTexture *surfaceTexture);
|
bool setPreviewTexture(AndroidSurfaceTexture *surfaceTexture);
|
||||||
|
|
||||||
bool isZoomSupported();
|
bool isZoomSupported();
|
||||||
int getMaxZoom();
|
int getMaxZoom();
|
||||||
|
|||||||
Reference in New Issue
Block a user