Add new app permissions API under QCoreApplication

The API allows users to request and check the status of various
permissions. A predefined enum class of the common permission types
on different platforms is used to allow requesting permission with
a common code. Platform specific permissions are defined only on their
relevant platform. For permissions that are not predefined, they can
be requested via a string variant of this API.

This adds the Android implementation only.

[ChangeLog][QtCore] Add new API for handling app permissions with an
initial implementation for Android.

Task-number: QTBUG-90498
Change-Id: I3bc98c6ab2dceeea3ee8edec20a332ed8f56ad4f
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Assam Boudjelthia 2021-03-03 00:59:29 +02:00
parent 3969ef40cc
commit afd7460aff
12 changed files with 829 additions and 6 deletions

View File

@ -119,6 +119,7 @@ qt_internal_add_module(Core
kernel/qobjectcleanuphandler.cpp kernel/qobjectcleanuphandler.h
kernel/qobjectdefs.h
kernel/qobjectdefs_impl.h
kernel/qpermission.h
kernel/qpointer.cpp kernel/qpointer.h
kernel/qproperty.cpp kernel/qproperty.h kernel/qproperty_p.h
kernel/qpropertyprivate.h
@ -976,6 +977,7 @@ qt_internal_extend_target(Core CONDITION UNIX AND NOT APPLE
qt_internal_extend_target(Core CONDITION ANDROID AND NOT ANDROID_EMBEDDED
SOURCES
io/qstandardpaths_android.cpp
kernel/qcoreapplication_android.cpp
io/qstorageinfo_unix.cpp
kernel/qjni.cpp kernel/qjni_p.h
kernel/qjnienvironment.cpp kernel/qjnienvironment.h

View File

@ -0,0 +1,141 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdebug.h>
#include <QtCore/qstring.h>
void takeSelfie() {};
void requestCameraPermissionAndroid()
{
//! [Request camera permission on Android]
QCoreApplication::requestPermission(QStringLiteral("android.permission.CAMERA"))
.then([=](QPermission::PermissionResult result) {
if (result == QPermission::Authorized)
takeSelfie();
});
//! [Request camera permission on Android]
}
void requestCameraPermission()
{
//! [Request camera permission]
QCoreApplication::requestPermission(QPermission::Camera)
.then([=](QPermission::PermissionResult result) {
if (result == QPermission::Authorized)
takeSelfie();
});
//! [Request camera permission]
}
void requestCameraPermissionSyncAndroid()
{
//! [Request camera permission sync on Android]
auto future = QCoreApplication::requestPermission(QStringLiteral("android.permission.CAMERA"));
auto result = future.result(); // blocks and waits for the result to be ready
if (result == QPermission::Authorized)
takeSelfie();
//! [Request camera permission sync on Android]
}
void requestCameraPermissionSync()
{
//! [Request camera permission sync]
auto future = QCoreApplication::requestPermission(QPermission::Camera);
auto result = future.result(); // blocks and waits for the result to be ready
if (result == QPermission::Authorized)
takeSelfie();
//! [Request camera permission sync]
}
void checkCameraPermissionAndroid()
{
//! [Check camera permission on Android]
QCoreApplication::checkPermission(QStringLiteral("android.permission.CAMERA"))
.then([=](QPermission::PermissionResult result) {
if (result == QPermission::Authorized)
takeSelfie();
});
//! [Check camera permission on Android]
}
void checkCameraPermission()
{
//! [Check camera permission]
QCoreApplication::checkPermission(QPermission::Camera)
.then([=](QPermission::PermissionResult result) {
if (result == QPermission::Authorized)
takeSelfie();
});
//! [Check camera permission]
}
void checkCameraPermissionAndroidSync()
{
//! [Check camera permission sync on Android]
auto future = QCoreApplication::checkPermission(QStringLiteral("android.permission.CAMERA"));
// may block and wait for the result to be ready on some platforms
auto result = future.result();
if (result == QPermission::Authorized)
takeSelfie();
//! [Check camera permission sync on Android]
}
void checkCameraPermissionSync()
{
//! [Check camera permission sync]
auto future = QCoreApplication::checkPermission(QPermission::Camera);
// may block and wait for the result to be ready on some platforms
auto result = future.result();
if (result == QPermission::Authorized)
takeSelfie();
//! [Check camera permission sync]
}

View File

@ -100,3 +100,8 @@
\externalpage https://docs.oracle.com/en/java/javase/13/docs/specs/jni/functions.html#interface-function-table
\title Java: Interface Function Table
*/
/*!
\externalpage https://doc.qt.io/qtcreator/creator-deploying-android.html#editing-manifest-files
\title Qt Creator: Editing Manifest Files
*/

View File

@ -60,6 +60,7 @@
#ifndef QT_NO_QOBJECT
#include <qthread.h>
#include <qthreadstorage.h>
#include <QtCore/qpromise.h>
#include <private/qthread_p.h>
#if QT_CONFIG(thread)
#include <qthreadpool.h>
@ -3076,6 +3077,156 @@ void QCoreApplication::setEventDispatcher(QAbstractEventDispatcher *eventDispatc
\sa Q_OBJECT, QObject::tr()
*/
#ifndef QT_NO_QOBJECT
#if !defined(Q_OS_ANDROID)
QFuture<QPermission::PermissionResult> defaultPermissionFuture()
{
QPromise<QPermission::PermissionResult> promise;
QFuture<QPermission::PermissionResult> future = promise.future();
promise.start();
#ifndef QT_NO_EXCEPTIONS
const auto exception = std::make_exception_ptr(
std::runtime_error("This platform doesn't have an implementation "
"for the application permissions API."));
promise.setException(exception);
#else
promise.addResult(QPermission::Denied);
#endif
promise.finish();
return future;
}
QFuture<QPermission::PermissionResult>
QCoreApplicationPrivate::requestPermission(QPermission::PermisionType permission)
{
Q_UNUSED(permission)
return defaultPermissionFuture();
}
QFuture<QPermission::PermissionResult>
QCoreApplicationPrivate::requestPermission(const QString &permission)
{
Q_UNUSED(permission)
return defaultPermissionFuture();
}
QFuture<QPermission::PermissionResult>
QCoreApplicationPrivate::checkPermission(QPermission::PermisionType permission)
{
Q_UNUSED(permission)
return defaultPermissionFuture();
}
QFuture<QPermission::PermissionResult>
QCoreApplicationPrivate::checkPermission(const QString &permission)
{
Q_UNUSED(permission)
return defaultPermissionFuture();
}
#endif
/*!
Requests the \a permission and returns a QFuture representing the
result of the request.
Applications can request a permission in a cross-platform fashion. For example
you can request permission to use the camera asynchronously as follows:
\snippet permissions/permissions.cpp Request camera permission
\note A function passed to \l {QFuture::then()} will be called once the request
is processed. It can take some suitable action in response to the
granting or refusal of the permission. It must not access objects that
might be deleted before it is called.
To do the same request synchronously:
\snippet permissions/permissions.cpp Request camera permission sync
\since 6.2
\sa checkPermission()
*/
QFuture<QPermission::PermissionResult>
QCoreApplication::requestPermission(QPermission::PermisionType permission)
{
return QCoreApplicationPrivate::requestPermission(permission);
}
/*!
Requests the \a permission and returns a QFuture representing the
result of the request.
All application permissions supported by a platform can be requested by their
platform-specific names. For example you can request permission to use the
camera asynchronously on Android as follows:
\snippet permissions/permissions.cpp Request camera permission on Android
\note A function passed to \l {QFuture::then()} will be called once the request
is processed. It can take some suitable action in response to the
granting or refusal of the permission. It must not access objects that
might be deleted before it is called.
To do the same request synchronously:
\snippet permissions/permissions.cpp Request camera permission sync on Android
\since 6.2
\sa checkPermission()
*/
QFuture<QPermission::PermissionResult>
QCoreApplication::requestPermission(const QString &permission)
{
return QCoreApplicationPrivate::requestPermission(permission);
}
/*!
Checks whether this process has the named \a permission and returns a QFuture
representing the result of the check.
Applications can check a permission in a cross-platform fashion. For example
you can check the permission to use the camera asynchronously as follows:
\snippet permissions/permissions.cpp Check camera permission
To do the same request synchronously:
\snippet permissions/permissions.cpp Check camera permission sync
\since 6.2
\sa requestPermission()
*/
QFuture<QPermission::PermissionResult>
QCoreApplication::checkPermission(QPermission::PermisionType permission)
{
return QCoreApplicationPrivate::checkPermission(permission);
}
/*!
Checks whether this process has the named \a permission and returns a QFuture
representing the result of the check.
All application permissions supported by a platform can be checked by their
platform-specific names. For example you can check the permission to use the
camera asynchronously on Android as follows:
\snippet permissions/permissions.cpp Check camera permission on Android
To do the same request synchronously:
\snippet permissions/permissions.cpp Check camera permission sync on Android
\since 6.2
\sa requestPermission()
*/
QFuture<QPermission::PermissionResult>
QCoreApplication::checkPermission(const QString &permission)
{
return QCoreApplicationPrivate::checkPermission(permission);
}
#endif
QT_END_NAMESPACE
#ifndef QT_NO_QOBJECT

View File

@ -43,9 +43,11 @@
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
#ifndef QT_NO_QOBJECT
#include <QtCore/qobject.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qeventloop.h>
#include <QtCore/qfuture.h>
#include <QtCore/qobject.h>
#include <QtCore/qpermission.h>
#else
#include <QtCore/qscopedpointer.h>
#endif
@ -156,6 +158,14 @@ public:
int n = -1);
#ifndef QT_NO_QOBJECT
static QFuture<QPermission::PermissionResult> requestPermission(
QPermission::PermisionType permission);
static QFuture<QPermission::PermissionResult> requestPermission(const QString &permission);
static QFuture<QPermission::PermissionResult> checkPermission(
QPermission::PermisionType permission);
static QFuture<QPermission::PermissionResult> checkPermission(const QString &permission);
void installNativeEventFilter(QAbstractNativeEventFilter *filterObj);
void removeNativeEventFilter(QAbstractNativeEventFilter *filterObj);

View File

@ -0,0 +1,319 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qcoreapplication.h"
#include "qcoreapplication_p.h"
#include <QtCore/private/qjnihelpers_p.h>
#include <QtCore/qfuture.h>
#include <QtCore/qjnienvironment.h>
#include <QtCore/qjniobject.h>
#include <QtCore/qlist.h>
#include <QtCore/qmutex.h>
#include <QtCore/qpromise.h>
#include <QtCore/qscopedpointer.h>
QT_BEGIN_NAMESPACE
static const char qtNativeClassName[] = "org/qtproject/qt/android/QtNative";
#ifndef QT_NO_EXCEPTIONS
static const char emptyPermissionExcept[] = "The permission cannot be an empty string.";
static const char invalidNativePermissionExcept[] =
"Coudn't convert the provided permission type to a native Android permission string.";
#endif
QPermission::PermissionResult resultFromAndroid(jint value)
{
return value == 0 ? QPermission::Authorized : QPermission::Denied;
}
using PendingPermissionRequestsHash
= QHash<int, QSharedPointer<QPromise<QPermission::PermissionResult>>>;
Q_GLOBAL_STATIC(PendingPermissionRequestsHash, g_pendingPermissionRequests);
static QBasicMutex g_pendingPermissionRequestsMutex;
static int nextRequestCode()
{
static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
return counter.fetchAndAddRelaxed(1);
}
static QStringList nativeStringsFromPermission(QPermission::PermisionType permission)
{
static const auto precisePerm = QStringLiteral("android.permission.ACCESS_FINE_LOCATION");
static const auto coarsePerm = QStringLiteral("android.permission.ACCESS_COARSE_LOCATION");
static const auto backgroundPerm =
QStringLiteral("android.permission.ACCESS_BACKGROUND_LOCATION");
switch (permission) {
case QPermission::CoarseLocation:
return {coarsePerm};
case QPermission::PreciseLocation:
return {precisePerm};
case QPermission::CoarseBackgroundLocation:
// Keep the background permission first to be able to use .first()
// in checkPermission because it takes single permission
if (QtAndroidPrivate::androidSdkVersion() >= 29)
return {backgroundPerm, coarsePerm};
return {coarsePerm};
case QPermission::PreciseBackgroundLocation:
if (QtAndroidPrivate::androidSdkVersion() >= 29)
return {backgroundPerm, precisePerm};
return {precisePerm};
case QPermission::Camera:
return {QStringLiteral("android.permission.CAMERA")};
case QPermission::Microphone:
return {QStringLiteral("android.permission.RECORD_AUDIO")};
case QPermission::BodySensors:
return {QStringLiteral("android.permission.BODY_SENSORS")};
case QPermission::PhysicalActivity:
return {QStringLiteral("android.permission.ACTIVITY_RECOGNITION")};
case QPermission::ReadContacts:
return {QStringLiteral("android.permission.READ_CONTACTS")};
case QPermission::WriteContacts:
return {QStringLiteral("android.permission.WRITE_CONTACTS")};
case QPermission::ReadStorage:
return {QStringLiteral("android.permission.READ_EXTERNAL_STORAGE")};
case QPermission::WriteStorage:
return {QStringLiteral("android.permission.WRITE_EXTERNAL_STORAGE")};
case QPermission::ReadCalendar:
return {QStringLiteral("android.permission.READ_CALENDAR")};
case QPermission::WriteCalendar:
return {QStringLiteral("android.permission.WRITE_CALENDAR")};
default:
return {};
}
}
/*!
\internal
This function is called when the result of the permission request is available.
Once a permission is requested, the result is braodcast by the OS and listened
to by QtActivity which passes it to C++ through a native JNI method call.
*/
static void sendRequestPermissionsResult(JNIEnv *env, jobject *obj, jint requestCode,
jobjectArray permissions, jintArray grantResults)
{
Q_UNUSED(obj);
QMutexLocker locker(&g_pendingPermissionRequestsMutex);
auto it = g_pendingPermissionRequests->constFind(requestCode);
if (it == g_pendingPermissionRequests->constEnd()) {
qWarning() << "Found no valid pending permission request for request code" << requestCode;
return;
}
auto request = *it;
g_pendingPermissionRequests->erase(it);
locker.unlock();
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) {
QPermission::PermissionResult result = resultFromAndroid(results[i]);
request->addResult(result, i);
}
request->finish();
}
QFuture<QPermission::PermissionResult> requestPermissionsInternal(const QStringList &permissions)
{
QSharedPointer<QPromise<QPermission::PermissionResult>> promise;
promise.reset(new QPromise<QPermission::PermissionResult>());
QFuture<QPermission::PermissionResult> future = promise->future();
promise->start();
// No mechanism to request permission for SDK version below 23, because
// permissions defined in the manifest are granted at install time.
if (QtAndroidPrivate::androidSdkVersion() < 23) {
for (int i = 0; i < permissions.size(); ++i)
promise->addResult(QCoreApplication::checkPermission(permissions.at(i)).result(), i);
promise->finish();
return future;
}
const int requestCode = nextRequestCode();
QMutexLocker locker(&g_pendingPermissionRequestsMutex);
g_pendingPermissionRequests->insert(requestCode, promise);
QtAndroidPrivate::runOnAndroidThread([permissions, requestCode] {
QJniEnvironment env;
jclass clazz = env.findClass("java/lang/String");
auto array = env->NewObjectArray(permissions.size(), clazz, nullptr);
int index = 0;
for (auto &perm : permissions)
env->SetObjectArrayElement(array, index++, QJniObject::fromString(perm).object());
QJniObject(QtAndroidPrivate::activity()).callMethod<void>("requestPermissions",
"([Ljava/lang/String;I)V",
array,
requestCode);
env->DeleteLocalRef(array);
}, QJniEnvironment().jniEnv());
return future;
}
QFuture<QPermission::PermissionResult>
QCoreApplicationPrivate::requestPermission(const QString &permission)
{
// avoid the uneccessary call and response to an empty permission string
if (permission.size() > 0)
return requestPermissionsInternal({permission});
QPromise<QPermission::PermissionResult> promise;
QFuture<QPermission::PermissionResult> future = promise.future();
promise.start();
#ifndef QT_NO_EXCEPTIONS
promise.setException(std::make_exception_ptr(std::runtime_error(emptyPermissionExcept)));
#else
promise.addResult(QPermission::Denied);
#endif
promise.finish();
return future;
}
QFuture<QPermission::PermissionResult> groupRequestToSingleResult(const QStringList &permissions)
{
QSharedPointer<QPromise<QPermission::PermissionResult>> promise;
promise.reset(new QPromise<QPermission::PermissionResult>());
QFuture<QPermission::PermissionResult> future = promise->future();
promise->start();
requestPermissionsInternal(permissions).then(
[promise](QFuture<QPermission::PermissionResult> future) {
auto results = future.results();
if (results.count(QPermission::Authorized) == results.count())
promise->addResult(QPermission::Authorized, 0);
else
promise->addResult(QPermission::Denied, 0);
promise->finish();
});
return future;
}
QFuture<QPermission::PermissionResult>
QCoreApplicationPrivate::requestPermission(QPermission::PermisionType permission)
{
const auto nativePermissions = nativeStringsFromPermission(permission);
if (nativePermissions.size() > 0)
return groupRequestToSingleResult(nativePermissions);
QPromise<QPermission::PermissionResult> promise;
QFuture<QPermission::PermissionResult> future = promise.future();
promise.start();
#ifndef QT_NO_EXCEPTIONS
promise.setException(std::make_exception_ptr(
std::runtime_error(invalidNativePermissionExcept)));
#else
promise.addResult(QPermission::Denied);
#endif
promise.finish();
return future;
}
QFuture<QPermission::PermissionResult>
QCoreApplicationPrivate::checkPermission(const QString &permission)
{
QPromise<QPermission::PermissionResult> promise;
QFuture<QPermission::PermissionResult> future = promise.future();
promise.start();
if (permission.size() > 0) {
auto res = QJniObject::callStaticMethod<jint>(qtNativeClassName,
"checkSelfPermission",
"(Ljava/lang/String;)I",
QJniObject::fromString(permission).object());
promise.addResult(resultFromAndroid(res));
} else {
#ifndef QT_NO_EXCEPTIONS
promise.setException(std::make_exception_ptr(std::runtime_error(emptyPermissionExcept)));
#else
promise.addResult(QPermission::Denied);
#endif
}
promise.finish();
return future;
}
QFuture<QPermission::PermissionResult>
QCoreApplicationPrivate::checkPermission(QPermission::PermisionType permission)
{
const auto nativePermissions = nativeStringsFromPermission(permission);
if (nativePermissions.size() > 0)
return checkPermission(nativePermissions.first());
QPromise<QPermission::PermissionResult> promise;
QFuture<QPermission::PermissionResult> future = promise.future();
promise.start();
#ifndef QT_NO_EXCEPTIONS
promise.setException(std::make_exception_ptr(
std::runtime_error(invalidNativePermissionExcept)));
#else
promise.addResult(QPermission::Denied);
#endif
promise.finish();
return future;
}
bool QtAndroidPrivate::registerPermissionNatives()
{
if (QtAndroidPrivate::androidSdkVersion() < 23)
return true;
JNINativeMethod methods[] = {
{"sendRequestPermissionsResult", "(I[Ljava/lang/String;[I)V",
reinterpret_cast<void *>(sendRequestPermissionsResult)
}};
QJniEnvironment env;
return env.registerNativeMethods(qtNativeClassName, methods, 1);
}
QT_END_NAMESPACE

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -62,6 +62,8 @@
#ifndef QT_NO_QOBJECT
#include "private/qobject_p.h"
#include "private/qlocking_p.h"
#include <QtCore/qpermission.h>
#include <QtCore/qfuture.h>
#endif
#ifdef Q_OS_MACOS
@ -200,6 +202,16 @@ public:
QString qmljs_debug_arguments; // a string containing arguments for js/qml debugging.
inline QString qmljsDebugArgumentsString() const { return qmljs_debug_arguments; }
#ifndef QT_NO_QOBJECT
static QFuture<QPermission::PermissionResult> requestPermission(
QPermission::PermisionType permission);
static QFuture<QPermission::PermissionResult> requestPermission(const QString &permission);
static QFuture<QPermission::PermissionResult> checkPermission(
QPermission::PermisionType permission);
static QFuture<QPermission::PermissionResult> checkPermission(const QString &permission);
#endif
#ifdef QT_NO_QOBJECT
QCoreApplication *q_ptr;
#endif

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -47,6 +47,7 @@
#include "qsharedpointer.h"
#include "qthread.h"
#include <QtCore/private/qcoreapplication_p.h>
#include <QtCore/qrunnable.h>
#include <deque>
@ -397,6 +398,9 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
if (!regOk && QJniEnvironment::checkAndClearExceptions(env))
return JNI_ERR;
if (!registerPermissionNatives())
return JNI_ERR;
g_runPendingCppRunnablesMethodID = env->GetStaticMethodID(jQtNative,
"runPendingCppRunnablesOnAndroidThread",
"()V");

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -129,6 +129,7 @@ namespace QtAndroidPrivate
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);
bool registerPermissionNatives();
Q_CORE_EXPORT void handleActivityResult(jint requestCode, jint resultCode, jobject data);
Q_CORE_EXPORT void registerActivityResultListener(ActivityResultListener *listener);

View File

@ -0,0 +1,78 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QPERMISSION_H
#define QPERMISSION_H
#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
namespace QPermission
{
enum PermisionType {
Camera,
Microphone,
Bluetooth,
CoarseLocation,
PreciseLocation,
CoarseBackgroundLocation,
PreciseBackgroundLocation,
BodySensors,
PhysicalActivity,
ReadContacts,
WriteContacts,
ReadStorage,
WriteStorage,
ReadCalendar,
WriteCalendar
};
enum PermissionResult {
Authorized,
Denied,
Restricted,
Undetermined
};
} // QPermission
QT_END_NAMESPACE
#endif // QPERMISSION_H

View File

@ -0,0 +1,100 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\namespace QPermission
\brief The QPermission namespace contains enums for app permission types and results.
This namespace's enums are used by \l {QCoreApplication::requestPermission()} and
\l {QCoreApplication::checkPermission()}.
*/
/*!
\enum QPermission::PermisionType
Predefined sets of permission values.
\value Camera Access the camera for taking pictures or videos and configuring
the camera settings. Maps to "android.permission.CAMERA" on Android.
\value Microphone Access the microphone, receive the sound signal (e.g. to
analyze or record it). Maps to \c "android.permission.RECORD_AUDIO"
on Android.
\value CoarseLocation Access approximate location provider (wifi, cell tower).
Maps to \c "android.permission.ACCESS_COARSE_LOCATION" on Android.
\value PreciseLocation Location Access accurate location provider (satellite).
Maps to \c "android.permission.ACCESS_FINE_LOCATION" on Android.
\value PreciseBackgroundLocation Access the precise location services when
the app is in the background. Maps to
\c "android.permission.ACCESS_BACKGROUND_LOCATION" on Android, and
implies \l PreciseLocation.
\value CoarseBackgroundLocation Access the approximate location services when
the app is in the background. Maps to
\c "android.permission.ACCESS_BACKGROUND_LOCATION" on Android, and
implies \l CoarseLocation.
\value BodySensors Access body sensors such as a heart rate sensor.
Maps to \c "android.permission.BODY_SENSORS" on Android.
\value PhysicalActivity Access to data about physical activity and body
movements. Maps to \c "android.permission.ACTIVITY_RECOGNITION"
on Android.
\value ReadContacts Read user contacts. Maps to
\c "android.permission.READ_CONTACTS" on Android.
\value WriteContacts Write user contacts. Maps to
\c "android.permission.WRITE_CONTACTS" on Android.
\value ReadStorage Access device storage with read permissions.
Maps to \c "android.permission.READ_EXTERNAL_STORAGE" on Android.
\value WriteStorage Access device storage with write permissions.
Maps to \c "android.permission.WRITE_EXTERNAL_STORAGE" on Android.
\value ReadCalendar Read the user's calendar.
Maps to \c "android.permission.READ_CALENDAR" on Android.
\value WriteCalendar Write to the user's calendar.
Maps to \c "android.permission.WRITE_CALENDAR" on Android.
\note Both Android and iOS require the native permission values to be added
to the \c AndroidManifest.xml and \c info.plist respectively. For more
information on Android permissions, see \c {Qt Creator: Editing Manifest Files}.
For more information on iOS \c info.plist, see
\l {Information Property List Files}.
\since 6.2
\sa QCoreApplication::requestPermission(), QCoreApplication::checkPermission()
*/
/*!
\enum QPermission::PermissionResult
The result values for a permission check or request.
\value Authorized The permission is authorized.
\value Denied The permission is denied.
\value Restricted The permission state is denied and cannot be changed due
to restrictions from the system.
\value Undetermined The permission state is not yet known.
\since 6.2
\sa QCoreApplication::requestPermission(), QCoreApplication::checkPermission()
*/

View File

@ -25,6 +25,8 @@
** $QT_END_LICENSE$
**
****************************************************************************/
#define QFUTURE_TEST
#include <QCoreApplication>
#include <QDebug>
#include <QSemaphore>
@ -32,8 +34,6 @@
#include <QTimer>
#include <QSignalSpy>
#define QFUTURE_TEST
#include <QTest>
#include <qfuture.h>
#include <qfuturewatcher.h>