Android: Fix deadlock when calling requestPermission
The hang happend when using QtAndroidPrivate::requestPermissions before the QApplication::exec. Android UI calls "sendRequestPermissionsResult" which was blocking until the event is delivered, but the qt main loop is blocked and waits for the main surface to be created by the Android UI thread which is already blocked. With this patch sendRequestPermissionsResult won't block for the result to be delivered. Change-Id: I48ada65fe9ea63471ab46d8a9d839ba1b91d17b3 Reviewed-by: Christian Stromme <christian.stromme@qt.io>
This commit is contained in:
parent
d31deab632
commit
e8ea1edd89
@ -80,13 +80,13 @@ class PermissionsResultClass : public QObject
|
||||
Q_OBJECT
|
||||
public:
|
||||
PermissionsResultClass(const QtAndroidPrivate::PermissionsResultFunc &func) : m_func(func) {}
|
||||
Q_INVOKABLE void sendResult(const QtAndroidPrivate::PermissionsHash &result) { m_func(result); }
|
||||
Q_INVOKABLE void sendResult(const QtAndroidPrivate::PermissionsHash &result) { m_func(result); delete this;}
|
||||
|
||||
private:
|
||||
QtAndroidPrivate::PermissionsResultFunc m_func;
|
||||
};
|
||||
|
||||
typedef QHash<int, QSharedPointer<PermissionsResultClass>> PendingPermissionRequestsHash;
|
||||
typedef QHash<int, PermissionsResultClass*> PendingPermissionRequestsHash;
|
||||
Q_GLOBAL_STATIC(PendingPermissionRequestsHash, g_pendingPermissionRequests);
|
||||
static QBasicMutex g_pendingPermissionRequestsMutex;
|
||||
static int nextRequestCode()
|
||||
@ -131,11 +131,11 @@ static void sendRequestPermissionsResult(JNIEnv *env, jobject /*obj*/, jint requ
|
||||
// show an error or something ?
|
||||
return;
|
||||
}
|
||||
auto request = std::move(*it);
|
||||
auto request = *it;
|
||||
g_pendingPermissionRequests->erase(it);
|
||||
locker.unlock();
|
||||
|
||||
Qt::ConnectionType connection = QThread::currentThread() == request->thread() ? Qt::DirectConnection : Qt::BlockingQueuedConnection;
|
||||
Qt::ConnectionType connection = QThread::currentThread() == request->thread() ? Qt::DirectConnection : Qt::QueuedConnection;
|
||||
QtAndroidPrivate::PermissionsHash hash;
|
||||
const int size = env->GetArrayLength(permissions);
|
||||
std::unique_ptr<jint[]> results(new jint[size]);
|
||||
@ -147,7 +147,7 @@ static void sendRequestPermissionsResult(JNIEnv *env, jobject /*obj*/, jint requ
|
||||
QtAndroidPrivate::PermissionsResult::Denied;
|
||||
hash[permission] = value;
|
||||
}
|
||||
QMetaObject::invokeMethod(request.data(), "sendResult", connection, Q_ARG(QtAndroidPrivate::PermissionsHash, hash));
|
||||
QMetaObject::invokeMethod(request, "sendResult", connection, Q_ARG(QtAndroidPrivate::PermissionsHash, hash));
|
||||
}
|
||||
|
||||
static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event)
|
||||
@ -410,6 +410,7 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
|
||||
g_jNativeClass = static_cast<jclass>(env->NewGlobalRef(jQtNative));
|
||||
env->DeleteLocalRef(jQtNative);
|
||||
|
||||
qRegisterMetaType<QtAndroidPrivate::PermissionsHash>();
|
||||
return JNI_OK;
|
||||
}
|
||||
|
||||
@ -491,13 +492,13 @@ void QtAndroidPrivate::requestPermissions(JNIEnv *env, const QStringList &permis
|
||||
const int requestCode = nextRequestCode();
|
||||
if (!directCall) {
|
||||
QMutexLocker locker(&g_pendingPermissionRequestsMutex);
|
||||
(*g_pendingPermissionRequests)[requestCode] = QSharedPointer<PermissionsResultClass>::create(callbackFunc);
|
||||
(*g_pendingPermissionRequests)[requestCode] = new PermissionsResultClass(callbackFunc);
|
||||
}
|
||||
|
||||
runOnAndroidThread([permissions, callbackFunc, requestCode, directCall] {
|
||||
if (directCall) {
|
||||
QMutexLocker locker(&g_pendingPermissionRequestsMutex);
|
||||
(*g_pendingPermissionRequests)[requestCode] = QSharedPointer<PermissionsResultClass>::create(callbackFunc);
|
||||
(*g_pendingPermissionRequests)[requestCode] = new PermissionsResultClass(callbackFunc);
|
||||
}
|
||||
|
||||
QJNIEnvironmentPrivate env;
|
||||
|
@ -52,8 +52,10 @@
|
||||
//
|
||||
|
||||
#include <jni.h>
|
||||
#include <QtCore/private/qglobal_p.h>
|
||||
#include <functional>
|
||||
#include <QtCore/private/qglobal_p.h>
|
||||
#include <QHash>
|
||||
#include <QMetaType>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -117,7 +119,7 @@ namespace QtAndroidPrivate
|
||||
Q_CORE_EXPORT void runOnAndroidThreadSync(const Runnable &runnable, JNIEnv *env, int timeoutMs = INT_MAX);
|
||||
Q_CORE_EXPORT void runOnUiThread(QRunnable *runnable, JNIEnv *env);
|
||||
Q_CORE_EXPORT void requestPermissions(JNIEnv *env, const QStringList &permissions, const PermissionsResultFunc &callbackFunc, bool directCall = false);
|
||||
Q_CORE_EXPORT QHash<QString, PermissionsResult> requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs = INT_MAX);
|
||||
Q_CORE_EXPORT PermissionsHash requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs = INT_MAX);
|
||||
Q_CORE_EXPORT PermissionsResult checkPermission(const QString &permission);
|
||||
Q_CORE_EXPORT bool shouldShowRequestPermissionRationale(const QString &permission);
|
||||
|
||||
@ -145,4 +147,6 @@ namespace QtAndroidPrivate
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QtAndroidPrivate::PermissionsHash)
|
||||
|
||||
#endif // QJNIHELPERS_H
|
||||
|
Loading…
Reference in New Issue
Block a user