summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java5
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtNative.java19
-rw-r--r--src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java7
-rw-r--r--src/android/java/src/org/qtproject/qt5/android/bindings/QtApplication.java1
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp122
-rw-r--r--src/corelib/kernel/qjnihelpers_p.h11
6 files changed, 158 insertions, 7 deletions
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java
index b602cabd27..bfdbaed43f 100644
--- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java
@@ -1455,4 +1455,9 @@ public class QtActivityDelegate
}
return false;
}
+
+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
+ {
+ QtNative.sendRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
}
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
index 4df2cb88c9..6876aac11f 100644
--- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
@@ -455,20 +455,25 @@ public class QtNative
}
}
- public static int checkSelfPermission(final String permission)
+ public static Context getContext() {
+ if (m_activity == null)
+ return m_activity;
+ return m_service;
+ }
+
+ public static int checkSelfPermission(String permission)
{
int perm = PackageManager.PERMISSION_DENIED;
synchronized (m_mainActivityMutex) {
- if (m_activity == null)
- return perm;
+ Context context = getContext();
try {
if (Build.VERSION.SDK_INT >= 23) {
if (m_checkSelfPermissionMethod == null)
m_checkSelfPermissionMethod = Context.class.getMethod("checkSelfPermission", String.class);
- perm = (Integer)m_checkSelfPermissionMethod.invoke(m_activity, permission);
+ perm = (Integer)m_checkSelfPermissionMethod.invoke(context, permission);
} else {
- final PackageManager pm = m_activity.getPackageManager();
- perm = pm.checkPermission(permission, m_activity.getPackageName());
+ final PackageManager pm = context.getPackageManager();
+ perm = pm.checkPermission(permission, context.getApplicationContext().getPackageName());
}
} catch (Exception e) {
e.printStackTrace();
@@ -831,6 +836,8 @@ public class QtNative
public static native void runPendingCppRunnables();
+ public static native void sendRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults);
+
private static native void setNativeActivity(Activity activity);
private static native void setNativeService(Service service);
}
diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java
index 573a28e44b..22ff1738c8 100644
--- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java
+++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java
@@ -981,4 +981,11 @@ public class QtActivity extends Activity
//---------------------------------------------------------------------------
//@ANDROID-12
+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.onRequestPermissionsResult != null) {
+ QtApplication.invokeDelegateMethod(QtApplication.onRequestPermissionsResult, requestCode , permissions, grantResults);
+ return;
+ }
+ }
}
diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtApplication.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtApplication.java
index 1078060d7f..afc0432bdd 100644
--- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtApplication.java
+++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtApplication.java
@@ -64,6 +64,7 @@ public class QtApplication extends Application
public static Method onKeyShortcut = null;
public static Method dispatchGenericMotionEvent = null;
public static Method onGenericMotionEvent = null;
+ public static Method onRequestPermissionsResult = null;
private static String activityClassName;
public static void setQtContextDelegate(Class<?> clazz, Object listener)
{
diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp
index 102b835089..6a46f7dd11 100644
--- a/src/corelib/kernel/qjnihelpers.cpp
+++ b/src/corelib/kernel/qjnihelpers.cpp
@@ -38,14 +38,17 @@
****************************************************************************/
#include "qjnihelpers_p.h"
+#include "qjni_p.h"
#include "qmutex.h"
#include "qlist.h"
#include "qsemaphore.h"
#include "qsharedpointer.h"
#include "qvector.h"
+#include "qthread.h"
#include <QtCore/qrunnable.h>
#include <deque>
+#include <memory>
QT_BEGIN_NAMESPACE
@@ -60,6 +63,22 @@ static jmethodID g_hideSplashScreenMethodID = Q_NULLPTR;
Q_GLOBAL_STATIC(std::deque<QtAndroidPrivate::Runnable>, g_pendingRunnables);
Q_GLOBAL_STATIC(QMutex, g_pendingRunnablesMutex);
+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); }
+
+private:
+ QtAndroidPrivate::PermissionsResultFunc m_func;
+};
+
+typedef QHash<int, QSharedPointer<PermissionsResultClass>> PendingPermissionRequestsHash;
+Q_GLOBAL_STATIC(PendingPermissionRequestsHash, g_pendingPermissionRequests);
+Q_GLOBAL_STATIC(QMutex, g_pendingPermissionRequestsMutex);
+Q_GLOBAL_STATIC(QAtomicInt, g_requestPermissionsRequestCode);
+
// function called from Java from Android UI thread
static void runPendingCppRunnables(JNIEnv */*env*/, jobject /*obj*/)
{
@@ -81,9 +100,43 @@ namespace {
QMutex mutex;
QVector<QtAndroidPrivate::GenericMotionEventListener *> listeners;
};
+
+ enum {
+ PERMISSION_GRANTED = 0
+ };
}
Q_GLOBAL_STATIC(GenericMotionEventListeners, g_genericMotionEventListeners)
+static void sendRequestPermissionsResult(JNIEnv *env, jobject /*obj*/, jint requestCode,
+ jobjectArray permissions, jintArray grantResults)
+{
+ g_pendingPermissionRequestsMutex->lock();
+ auto it = g_pendingPermissionRequests->find(requestCode);
+ if (it == g_pendingPermissionRequests->end()) {
+ g_pendingPermissionRequestsMutex->unlock();
+ // show an error or something ?
+ return;
+ }
+ g_pendingPermissionRequestsMutex->unlock();
+
+ Qt::ConnectionType connection = QThread::currentThread() == it.value()->thread() ? Qt::DirectConnection : Qt::BlockingQueuedConnection;
+ QtAndroidPrivate::PermissionsHash hash;
+ const int size = env->GetArrayLength(permissions);
+ std::unique_ptr<jint[]> results(new jint[size]);
+ env->GetIntArrayRegion(grantResults, 0, size, results.get());
+ for (int i = 0 ; i < size; ++i) {
+ const auto &permission = QJNIObjectPrivate(env->GetObjectArrayElement(permissions, i)).toString();
+ auto value = results[i] == PERMISSION_GRANTED ?
+ QtAndroidPrivate::PermissionsResult::Granted :
+ QtAndroidPrivate::PermissionsResult::Denied;
+ hash[permission] = value;
+ }
+ QMetaObject::invokeMethod(it.value().data(), "sendResult", connection, Q_ARG(QtAndroidPrivate::PermissionsHash, hash));
+ g_pendingPermissionRequestsMutex->lock();
+ g_pendingPermissionRequests->erase(it);
+ g_pendingPermissionRequestsMutex->unlock();
+}
+
static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event)
{
jboolean ret = JNI_FALSE;
@@ -328,7 +381,8 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
{"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast<void *>(dispatchGenericMotionEvent)},
{"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast<void *>(dispatchKeyEvent)},
{"setNativeActivity", "(Landroid/app/Activity;)V", reinterpret_cast<void *>(setNativeActivity)},
- {"setNativeService", "(Landroid/app/Service;)V", reinterpret_cast<void *>(setNativeService)}
+ {"setNativeService", "(Landroid/app/Service;)V", reinterpret_cast<void *>(setNativeService)},
+ {"sendRequestPermissionsResult", "(I[Ljava/lang/String;[I)V", reinterpret_cast<void *>(sendRequestPermissionsResult)},
};
const bool regOk = (env->RegisterNatives(jQtNative, methods, sizeof(methods) / sizeof(methods[0])) == JNI_OK);
@@ -411,6 +465,70 @@ void QtAndroidPrivate::runOnAndroidThreadSync(const QtAndroidPrivate::Runnable &
sem->tryAcquire(1, timeoutMs);
}
+void QtAndroidPrivate::requestPermissions(JNIEnv *env, const QStringList &permissions, const QtAndroidPrivate::PermissionsResultFunc &callbackFunc, bool directCall)
+{
+ if (androidSdkVersion() < 23 || !activity()) {
+ QHash<QString, QtAndroidPrivate::PermissionsResult> res;
+ for (const auto &perm : permissions)
+ res[perm] = checkPermission(perm);
+ callbackFunc(res);
+ return;
+ }
+ // Check API 23+ permissions
+ const int requestCode = (*g_requestPermissionsRequestCode)++;
+ if (!directCall) {
+ g_pendingPermissionRequestsMutex->lock();
+ (*g_pendingPermissionRequests)[requestCode] = QSharedPointer<PermissionsResultClass>::create(callbackFunc);
+ g_pendingPermissionRequestsMutex->unlock();
+ }
+
+ runOnAndroidThread([permissions, callbackFunc, requestCode, directCall] {
+ if (directCall) {
+ g_pendingPermissionRequestsMutex->lock();
+ (*g_pendingPermissionRequests)[requestCode] = QSharedPointer<PermissionsResultClass>::create(callbackFunc);
+ g_pendingPermissionRequestsMutex->unlock();
+ }
+
+ QJNIEnvironmentPrivate env;
+ auto array = env->NewObjectArray(permissions.size(), env->FindClass("java/lang/String"), nullptr);
+ int index = 0;
+ for (const auto &perm : permissions)
+ env->SetObjectArrayElement(array, index++, QJNIObjectPrivate::fromString(perm).object());
+ QJNIObjectPrivate(activity()).callMethod<void>("requestPermissions", "([Ljava/lang/String;I)V", array, requestCode);
+ env->DeleteLocalRef(array);
+ }, env);
+}
+
+QHash<QString, QtAndroidPrivate::PermissionsResult> QtAndroidPrivate::requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs)
+{
+ QSharedPointer<QHash<QString, QtAndroidPrivate::PermissionsResult>> res(new QHash<QString, QtAndroidPrivate::PermissionsResult>());
+ QSharedPointer<QSemaphore> sem(new QSemaphore);
+ requestPermissions(env, permissions, [sem, res](const QHash<QString, PermissionsResult> &result){
+ *res = result;
+ sem->release();
+ }, true);
+ sem->tryAcquire(1, timeoutMs);
+ return *res;
+}
+
+QtAndroidPrivate::PermissionsResult QtAndroidPrivate::checkPermission(const QString &permission)
+{
+ const auto res = QJNIObjectPrivate::callStaticMethod<jint>("org/qtproject/qt5/android/QtNative",
+ "checkSelfPermission",
+ "(Ljava/lang/String;)I",
+ QJNIObjectPrivate::fromString(permission).object());
+ return res == PERMISSION_GRANTED ? PermissionsResult::Granted : PermissionsResult::Denied;
+}
+
+bool QtAndroidPrivate::shouldShowRequestPermissionRationale(const QString &permission)
+{
+ if (androidSdkVersion() < 23 || !activity())
+ return false;
+
+ return QJNIObjectPrivate(activity()).callMethod<jboolean>("shouldShowRequestPermissionRationale", "(Ljava/lang/String;)Z",
+ QJNIObjectPrivate::fromString(permission).object());
+}
+
void QtAndroidPrivate::registerGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener)
{
QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
@@ -441,3 +559,5 @@ void QtAndroidPrivate::hideSplashScreen(JNIEnv *env)
}
QT_END_NAMESPACE
+
+#include "qjnihelpers.moc"
diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h
index 43e2f3af20..478f62a5c7 100644
--- a/src/corelib/kernel/qjnihelpers_p.h
+++ b/src/corelib/kernel/qjnihelpers_p.h
@@ -58,6 +58,7 @@
QT_BEGIN_NAMESPACE
class QRunnable;
+class QStringList;
namespace QtAndroidPrivate
{
@@ -97,7 +98,13 @@ namespace QtAndroidPrivate
virtual bool handleKeyEvent(jobject event) = 0;
};
+ enum class PermissionsResult {
+ Granted,
+ Denied
+ };
+ typedef QHash<QString, QtAndroidPrivate::PermissionsResult> PermissionsHash;
typedef std::function<void()> Runnable;
+ typedef std::function<void(const PermissionsHash &)> PermissionsResultFunc;
Q_CORE_EXPORT jobject activity();
Q_CORE_EXPORT jobject service();
@@ -109,6 +116,10 @@ namespace QtAndroidPrivate
Q_CORE_EXPORT void runOnAndroidThread(const Runnable &runnable, JNIEnv *env);
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 PermissionsResult checkPermission(const QString &permission);
+ Q_CORE_EXPORT bool shouldShowRequestPermissionRationale(const QString &permission);
Q_CORE_EXPORT void handleActivityResult(jint requestCode, jint resultCode, jobject data);
Q_CORE_EXPORT void registerActivityResultListener(ActivityResultListener *listener);