summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/corelib/permissions/CMakeLists.txt4
-rw-r--r--examples/corelib/permissions/android/AndroidManifest.xml53
-rw-r--r--src/corelib/CMakeLists.txt5
-rw-r--r--src/corelib/configure.cmake2
-rw-r--r--src/corelib/global/qnamespace.qdoc7
-rw-r--r--src/corelib/kernel/qpermissions.cpp33
-rw-r--r--src/corelib/kernel/qpermissions_android.cpp137
-rw-r--r--src/corelib/platform/android/qandroidextras.cpp138
-rw-r--r--src/corelib/platform/android/qandroidextras_p.h22
-rw-r--r--tests/manual/permissions/CMakeLists.txt6
-rw-r--r--tests/manual/permissions/android/AndroidManifest.xml53
11 files changed, 315 insertions, 145 deletions
diff --git a/examples/corelib/permissions/CMakeLists.txt b/examples/corelib/permissions/CMakeLists.txt
index 5c9af5f0d9..7204947ff5 100644
--- a/examples/corelib/permissions/CMakeLists.txt
+++ b/examples/corelib/permissions/CMakeLists.txt
@@ -12,14 +12,18 @@ set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/permissions")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_add_executable(permissions
+ MANUAL_FINALIZATION
main.cpp
)
set_target_properties(permissions PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist"
+ QT_ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android"
)
+qt_finalize_executable(permissions)
+
target_link_libraries(permissions PUBLIC
Qt::Core
Qt::Gui
diff --git a/examples/corelib/permissions/android/AndroidManifest.xml b/examples/corelib/permissions/android/AndroidManifest.xml
new file mode 100644
index 0000000000..557ec8007e
--- /dev/null
+++ b/examples/corelib/permissions/android/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.qtproject.example"
+ android:installLocation="auto"
+ android:versionCode="-- %%INSERT_VERSION_CODE%% --"
+ android:versionName="-- %%INSERT_VERSION_NAME%% --">
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+ <uses-permission android:name="android.permission.READ_CALENDAR" />
+ <uses-permission android:name="android.permission.WRITE_CALENDAR" />
+ <!-- %%INSERT_PERMISSIONS -->
+ <!-- %%INSERT_FEATURES -->
+ <supports-screens
+ android:anyDensity="true"
+ android:largeScreens="true"
+ android:normalScreens="true"
+ android:smallScreens="true" />
+ <application
+ android:name="org.qtproject.qt.android.bindings.QtApplication"
+ android:hardwareAccelerated="true"
+ android:label="-- %%INSERT_APP_NAME%% --"
+ android:requestLegacyExternalStorage="true"
+ android:allowNativeHeapPointerTagging="false"
+ android:allowBackup="true"
+ android:fullBackupOnly="false">
+ <activity
+ android:name="org.qtproject.qt.android.bindings.QtActivity"
+ android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
+ android:label="-- %%INSERT_APP_NAME%% --"
+ android:launchMode="singleTop"
+ android:screenOrientation="unspecified"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ <meta-data
+ android:name="android.app.lib_name"
+ android:value="-- %%INSERT_APP_LIB_NAME%% --" />
+
+ <meta-data
+ android:name="android.app.extract_android_style"
+ android:value="minimal" />
+ </activity>
+ </application>
+</manifest>
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index f9dc9f7f20..68444d5ee4 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -1225,6 +1225,11 @@ if(QT_FEATURE_permissions AND APPLE)
)
endif()
+qt_internal_extend_target(Core CONDITION QT_FEATURE_permissions AND ANDROID
+ SOURCES
+ kernel/qpermissions_android.cpp
+)
+
#### Keys ignored in scope 171:.:mimetypes:mimetypes/mimetypes.pri:QT_FEATURE_mimetype:
# MIME_DATABASE = "mimetypes/mime/packages/freedesktop.org.xml"
# OTHER_FILES = "$$MIME_DATABASE"
diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake
index 0e625408a7..d2e8fa4205 100644
--- a/src/corelib/configure.cmake
+++ b/src/corelib/configure.cmake
@@ -971,7 +971,7 @@ qt_feature("permissions" PUBLIC
SECTION "Utilities"
LABEL "Application permissions"
PURPOSE "Provides support for requesting user permission to access restricted data or APIs"
- CONDITION APPLE
+ CONDITION APPLE OR ANDROID
)
qt_configure_add_summary_section(NAME "Qt Core")
qt_configure_add_summary_entry(ARGS "backtrace")
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index 5414369efe..004899891c 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -3315,6 +3315,13 @@
or the permission is known to not be accessible or applicable to applications
on the given platform.
+ \note On Android, there is no \c Undetermined status by the platform's APIs.
+ Thus, if a permission is denied for an app,
+ \l QCoreApplication::checkPermission() returns \c Undetermined
+ by default until \l QCoreApplication::requestPermission() is called.
+ After that \l QCoreApplication::checkPermission() reports a non \c Undetermined
+ status.
+
\since 6.5
\sa QCoreApplication::requestPermission(), QCoreApplication::checkPermission(),
{Application Permissions}
diff --git a/src/corelib/kernel/qpermissions.cpp b/src/corelib/kernel/qpermissions.cpp
index be9717694a..4fded99915 100644
--- a/src/corelib/kernel/qpermissions.cpp
+++ b/src/corelib/kernel/qpermissions.cpp
@@ -280,6 +280,10 @@ QMetaType QPermission::type() const
\li Apple
\li \l{apple-usage-description}{Usage description}
\li \c NSCameraUsageDescription
+ \row
+ \li Android
+ \li \l{android-uses-permission}{\c{uses-permission}}
+ \li \c android.permission.CAMERA
\include permissions.qdocinc end-usage-declarations
\include permissions.qdocinc permission-metadata
@@ -298,6 +302,10 @@ QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QCameraPermission)
\li Apple
\li \l{apple-usage-description}{Usage description}
\li \c NSMicrophoneUsageDescription
+ \row
+ \li Android
+ \li \l{android-uses-permission}{\c{uses-permission}}
+ \li \c android.permission.RECORD_AUDIO
\include permissions.qdocinc end-usage-declarations
\include permissions.qdocinc permission-metadata
@@ -316,6 +324,10 @@ QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QMicrophonePermission)
\li Apple
\li \l{apple-usage-description}{Usage description}
\li \c NSBluetoothAlwaysUsageDescription
+ \row
+ \li Android
+ \li \l{android-uses-permission}{\c{uses-permission}}
+ \li \c android.permission.BLUETOOTH
\include permissions.qdocinc end-usage-declarations
\include permissions.qdocinc permission-metadata
@@ -341,6 +353,17 @@ QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QBluetoothPermission)
\li \c NSLocationWhenInUseUsageDescription, and
\c NSLocationAlwaysUsageDescription if requesting
QLocationPermission::Always
+ \row
+ \li Android
+ \li \l{android-uses-permission}{\c{uses-permission}}
+ \li \list
+ \li \c android.permission.ACCESS_FINE_LOCATION for QLocationPermission::Precise
+ \li \c android.permission.ACCESS_COARSE_LOCATION for QLocationPermission::Approximate
+ \li \c android.permission.ACCESS_BACKGROUND_LOCATION for QLocationPermission::Always
+ \endlist
+ \note QLocationPermission::Always \c uses-permission string has
+ to be combined with one or both of QLocationPermission::Precise
+ and QLocationPermission::Approximate strings.
\include permissions.qdocinc end-usage-declarations
\include permissions.qdocinc permission-metadata
@@ -425,6 +448,11 @@ QLocationPermission::Availability QLocationPermission::availability() const
\li Apple
\li \l{apple-usage-description}{Usage description}
\li \c NSContactsUsageDescription
+ \row
+ \li Android
+ \li \l{android-uses-permission}{\c{uses-permission}}
+ \li \c android.permission.READ_CONTACTS. \c android.permission.WRITE_CONTACTS if
+ QContactsPermission::isReadOnly() is set to \c false.
\include permissions.qdocinc end-usage-declarations
\include permissions.qdocinc permission-metadata
@@ -468,6 +496,11 @@ bool QContactsPermission::isReadOnly() const
\li Apple
\li \l{apple-usage-description}{Usage description}
\li \c NSCalendarsUsageDescription
+ \row
+ \li Android
+ \li \l{android-uses-permission}{\c{uses-permission}}
+ \li \c android.permission.READ_CALENDAR. \c android.permission.WRITE_CALENDAR if
+ QContactsPermission::isReadOnly() is set to \c false.
\include permissions.qdocinc end-usage-declarations
\include permissions.qdocinc permission-metadata
diff --git a/src/corelib/kernel/qpermissions_android.cpp b/src/corelib/kernel/qpermissions_android.cpp
new file mode 100644
index 0000000000..cdafb0144c
--- /dev/null
+++ b/src/corelib/kernel/qpermissions_android.cpp
@@ -0,0 +1,137 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qpermissions.h"
+#include "qpermissions_p.h"
+
+#include <QtCore/qstringlist.h>
+#include <QtCore/qfuture.h>
+#include <QtCore/qhash.h>
+
+#include "private/qandroidextras_p.h"
+
+using namespace Qt::StringLiterals;
+
+QT_BEGIN_NAMESPACE
+
+static QStringList nativeLocationPermission(const QLocationPermission &permission)
+{
+ QStringList nativeLocationPermissionList;
+ const int sdkVersion = QtAndroidPrivate::androidSdkVersion();
+ static QString backgroundLocation = u"android.permission.ACCESS_BACKGROUND_LOCATION"_s;
+ static QString fineLocation = u"android.permission.ACCESS_FINE_LOCATION"_s;
+ static QString coarseLocation = u"android.permission.ACCESS_COARSE_LOCATION"_s;
+
+ // Since Android API 30, background location cannot be requested along
+ // with fine or coarse location, but it should be requested separately after
+ // the latter have been granted, see
+ // https://developer.android.com/training/location/permissions
+ if (sdkVersion < 30 || permission.availability() == QLocationPermission::WhenInUse) {
+ if (permission.accuracy() == QLocationPermission::Approximate) {
+ nativeLocationPermissionList << coarseLocation;
+ } else {
+ nativeLocationPermissionList << fineLocation;
+ // Since Android API 31, if precise location is requested, it's advised
+ // to request both fine and coarse location permissions, see
+ // https://developer.android.com/training/location/permissions#approximate-request
+ if (sdkVersion >= 31)
+ nativeLocationPermissionList << coarseLocation;
+ }
+ }
+
+ // NOTE: before Android API 29, background permission doesn't exist yet.
+
+ // Keep the background permission in front to be able to use first()
+ // on the list in checkPermission() because it takes single permission.
+ if (sdkVersion >= 29 && permission.availability() == QLocationPermission::Always)
+ nativeLocationPermissionList.prepend(backgroundLocation);
+
+ return nativeLocationPermissionList;
+}
+
+static QStringList nativeStringsFromPermission(const QPermission &permission)
+{
+ const auto id = permission.type().id();
+ if (id == qMetaTypeId<QLocationPermission>()) {
+ return nativeLocationPermission(permission.data<QLocationPermission>());
+ } else if (id == qMetaTypeId<QCameraPermission>()) {
+ return { u"android.permission.CAMERA"_s };
+ } else if (id == qMetaTypeId<QMicrophonePermission>()) {
+ return { u"android.permission.RECORD_AUDIO"_s };
+ } else if (id == qMetaTypeId<QBluetoothPermission>()) {
+ // TODO: handle Android 12 new bluetooth permissions
+ return { u"android.permission.BLUETOOTH"_s };
+ } else if (id == qMetaTypeId<QContactsPermission>()) {
+ const auto readContactsString = u"android.permission.READ_CONTACTS"_s;
+ if (permission.data<QContactsPermission>().isReadOnly())
+ return { readContactsString };
+ return { readContactsString, u"android.permission.WRITE_CONTACTS"_s };
+ } else if (id == qMetaTypeId<QCalendarPermission>()) {
+ const auto readContactsString = u"android.permission.READ_CALENDAR"_s;
+ if (permission.data<QCalendarPermission>().isReadOnly())
+ return { readContactsString };
+ return { readContactsString, u"android.permission.WRITE_CALENDAR"_s };
+ }
+
+ return {};
+}
+
+static Qt::PermissionStatus
+permissionStatusForAndroidResult(QtAndroidPrivate::PermissionResult result)
+{
+ switch (result) {
+ case QtAndroidPrivate::PermissionResult::Authorized: return Qt::PermissionStatus::Granted;
+ case QtAndroidPrivate::PermissionResult::Denied: return Qt::PermissionStatus::Denied;
+ default: return Qt::PermissionStatus::Undetermined;
+ }
+}
+
+using PermissionStatusHash = QHash<int, Qt::PermissionStatus>;
+Q_GLOBAL_STATIC_WITH_ARGS(PermissionStatusHash, g_permissionStatusHash, ({
+ { qMetaTypeId<QCameraPermission>(), Qt::PermissionStatus::Undetermined },
+ { qMetaTypeId<QMicrophonePermission>(), Qt::PermissionStatus::Undetermined },
+ { qMetaTypeId<QBluetoothPermission>(), Qt::PermissionStatus::Undetermined },
+ { qMetaTypeId<QContactsPermission>(), Qt::PermissionStatus::Undetermined },
+ { qMetaTypeId<QCalendarPermission>(), Qt::PermissionStatus::Undetermined },
+ { qMetaTypeId<QLocationPermission>(), Qt::PermissionStatus::Undetermined }
+}));
+
+namespace QPermissions::Private
+{
+ Qt::PermissionStatus checkPermission(const QPermission &permission)
+ {
+ const auto nativePermissionList = nativeStringsFromPermission(permission);
+ if (nativePermissionList.isEmpty())
+ return Qt::PermissionStatus::Granted;
+
+ const auto result = QtAndroidPrivate::checkPermission(nativePermissionList.first()).result();
+ const auto status = permissionStatusForAndroidResult(result);
+ const auto it = g_permissionStatusHash->constFind(permission.type().id());
+ const bool foundStatus = (it != g_permissionStatusHash->constEnd());
+ const bool itUndetermined = foundStatus && (*it) == Qt::PermissionStatus::Undetermined;
+ if (status == Qt::PermissionStatus::Denied && itUndetermined)
+ return Qt::PermissionStatus::Undetermined;
+ return status;
+ }
+
+ void requestPermission(const QPermission &permission,
+ const QPermissions::Private::PermissionCallback &callback)
+ {
+ const auto nativePermissionList = nativeStringsFromPermission(permission);
+ if (nativePermissionList.isEmpty()) {
+ callback(Qt::PermissionStatus::Granted);
+ return;
+ }
+
+ QtAndroidPrivate::requestPermissions(nativePermissionList).then(qApp,
+ [callback, permission](QFuture<QtAndroidPrivate::PermissionResult> future) {
+ const auto result = future.isValid() ? future.result() : QtAndroidPrivate::Denied;
+ const auto status = permissionStatusForAndroidResult(result);
+ g_permissionStatusHash->insert(permission.type().id(), status);
+ callback(status);
+ }
+ );
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/platform/android/qandroidextras.cpp b/src/corelib/platform/android/qandroidextras.cpp
index aa2d849d96..414374d1e0 100644
--- a/src/corelib/platform/android/qandroidextras.cpp
+++ b/src/corelib/platform/android/qandroidextras.cpp
@@ -1030,54 +1030,6 @@ static int nextRequestCode()
return counter.fetchAndAddRelaxed(1);
}
-static QStringList nativeStringsFromPermission(QtAndroidPrivate::PermissionType 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 QtAndroidPrivate::Location:
- return {coarsePerm};
- case QtAndroidPrivate::PreciseLocation:
- return {precisePerm};
- case QtAndroidPrivate::BackgroundLocation:
- // 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 QtAndroidPrivate::PreciseBackgroundLocation:
- // Keep the background permission first to be able to use .first()
- // in checkPermission because it takes single permission
- if (QtAndroidPrivate::androidSdkVersion() >= 29)
- return {backgroundPerm, precisePerm};
- return {precisePerm};
- case QtAndroidPrivate::Camera:
- return {QStringLiteral("android.permission.CAMERA")};
- case QtAndroidPrivate::Microphone:
- return {QStringLiteral("android.permission.RECORD_AUDIO")};
- case QtAndroidPrivate::Bluetooth:
- return { QStringLiteral("android.permission.BLUETOOTH") };
- case QtAndroidPrivate::BodySensors:
- return {QStringLiteral("android.permission.BODY_SENSORS")};
- case QtAndroidPrivate::PhysicalActivity:
- return {QStringLiteral("android.permission.ACTIVITY_RECOGNITION")};
- case QtAndroidPrivate::Contacts:
- return {QStringLiteral("android.permission.READ_CONTACTS"),
- QStringLiteral("android.permission.WRITE_CONTACTS")};
- case QtAndroidPrivate::Storage:
- return {QStringLiteral("android.permission.READ_EXTERNAL_STORAGE"),
- QStringLiteral("android.permission.WRITE_EXTERNAL_STORAGE")};
- case QtAndroidPrivate::Calendar:
- return {QStringLiteral("android.permission.READ_CALENDAR"),
- QStringLiteral("android.permission.WRITE_CALENDAR")};
- }
-
- return {};
-}
-
/*!
\internal
@@ -1110,6 +1062,7 @@ static void sendRequestPermissionsResult(JNIEnv *env, jobject *obj, jint request
request->addResult(result, i);
}
+ QtAndroidPrivate::releaseAndroidDeadlockProtector();
request->finish();
}
@@ -1130,6 +1083,12 @@ requestPermissionsInternal(const QStringList &permissions)
return future;
}
+ if (!QtAndroidPrivate::acquireAndroidDeadlockProtector()) {
+ promise->addResult(QtAndroidPrivate::Denied);
+ promise->finish();
+ return future;
+ }
+
const int requestCode = nextRequestCode();
QMutexLocker locker(&g_pendingPermissionRequestsMutex);
g_pendingPermissionRequests->insert(requestCode, promise);
@@ -1164,9 +1123,15 @@ requestPermissionsInternal(const QStringList &permissions)
QFuture<QtAndroidPrivate::PermissionResult>
QtAndroidPrivate::requestPermission(const QString &permission)
{
+ return requestPermissions({permission});
+}
+
+QFuture<QtAndroidPrivate::PermissionResult>
+QtAndroidPrivate::requestPermissions(const QStringList &permissions)
+{
// avoid the uneccessary call and response to an empty permission string
- if (permission.size() > 0)
- return requestPermissionsInternal({permission});
+ if (permissions.size() > 0)
+ return requestPermissionsInternal(permissions);
QPromise<QtAndroidPrivate::PermissionResult> promise;
QFuture<QtAndroidPrivate::PermissionResult> future = promise.future();
@@ -1176,55 +1141,6 @@ QtAndroidPrivate::requestPermission(const QString &permission)
return future;
}
-static bool isBackgroundLocationApi29(QtAndroidPrivate::PermissionType permission)
-{
- return QNativeInterface::QAndroidApplication::sdkVersion() >= 29
- && (permission == QtAndroidPrivate::BackgroundLocation
- || permission == QtAndroidPrivate::PreciseBackgroundLocation);
-}
-
-/*!
- \preliminary
-
- Requests the \a permission and returns a QFuture representing the
- result of the request.
-
- \since 6.2
- \sa checkPermission()
-*/
-QFuture<QtAndroidPrivate::PermissionResult>
-QtAndroidPrivate::requestPermission(QtAndroidPrivate::PermissionType permission)
-{
- QSharedPointer<QPromise<QtAndroidPrivate::PermissionResult>> promise;
- promise.reset(new QPromise<QtAndroidPrivate::PermissionResult>());
- QFuture<QtAndroidPrivate::PermissionResult> future = promise->future();
- promise->start();
- const auto nativePermissions = nativeStringsFromPermission(permission);
-
- if (nativePermissions.size() > 0 && QtAndroidPrivate::acquireAndroidDeadlockProtector()) {
- requestPermissionsInternal(nativePermissions).then(
- [promise, permission](QFuture<QtAndroidPrivate::PermissionResult> future) {
- auto AuthorizedCount = future.results().count(QtAndroidPrivate::Authorized);
- if (AuthorizedCount > 0) {
- if (isBackgroundLocationApi29(permission))
- promise->addResult(future.resultAt(0), 0);
- else
- promise->addResult(QtAndroidPrivate::Authorized, 0);
- } else {
- promise->addResult(QtAndroidPrivate::Denied, 0);
- }
- QtAndroidPrivate::releaseAndroidDeadlockProtector();
- promise->finish();
- });
-
- return future;
- }
-
- promise->addResult(QtAndroidPrivate::Denied);
- promise->finish();
- return future;
-}
-
/*!
\preliminary
Checks whether this process has the named \a permission and returns a QFuture
@@ -1254,30 +1170,6 @@ QtAndroidPrivate::checkPermission(const QString &permission)
return future;
}
-/*!
- \preliminary
- Checks whether this process has the named \a permission and returns a QFuture
- representing the result of the check.
-
- \since 6.2
- \sa requestPermission()
-*/
-QFuture<QtAndroidPrivate::PermissionResult>
-QtAndroidPrivate::checkPermission(QtAndroidPrivate::PermissionType permission)
-{
- const auto nativePermissions = nativeStringsFromPermission(permission);
-
- if (nativePermissions.size() > 0)
- return checkPermission(nativePermissions.first());
-
- QPromise<QtAndroidPrivate::PermissionResult> promise;
- QFuture<QtAndroidPrivate::PermissionResult> future = promise.future();
- promise.start();
- promise.addResult(QtAndroidPrivate::Denied);
- promise.finish();
- return future;
-}
-
bool QtAndroidPrivate::registerPermissionNatives()
{
if (QtAndroidPrivate::androidSdkVersion() < 23)
diff --git a/src/corelib/platform/android/qandroidextras_p.h b/src/corelib/platform/android/qandroidextras_p.h
index 00d1f74a47..efdc6cf74f 100644
--- a/src/corelib/platform/android/qandroidextras_p.h
+++ b/src/corelib/platform/android/qandroidextras_p.h
@@ -225,21 +225,6 @@ namespace QtAndroidPrivate
BindFlags flags = BindFlag::None);
#if QT_CONFIG(future)
- enum PermissionType {
- Camera,
- Microphone,
- Bluetooth,
- Location,
- PreciseLocation,
- BackgroundLocation,
- PreciseBackgroundLocation,
- BodySensors,
- PhysicalActivity,
- Contacts,
- Storage,
- Calendar
- };
-
enum PermissionResult {
Undetermined,
Authorized,
@@ -247,12 +232,9 @@ namespace QtAndroidPrivate
};
Q_CORE_EXPORT QFuture<QtAndroidPrivate::PermissionResult>
- requestPermission(QtAndroidPrivate::PermissionType permission);
- Q_CORE_EXPORT QFuture<QtAndroidPrivate::PermissionResult>
requestPermission(const QString &permission);
-
- Q_CORE_EXPORT QFuture<QtAndroidPrivate::PermissionResult>
- checkPermission(QtAndroidPrivate::PermissionType permission);
+ QFuture<QtAndroidPrivate::PermissionResult>
+ requestPermissions(const QStringList &permissions);
Q_CORE_EXPORT QFuture<QtAndroidPrivate::PermissionResult>
checkPermission(const QString &permission);
#endif
diff --git a/tests/manual/permissions/CMakeLists.txt b/tests/manual/permissions/CMakeLists.txt
index 50ec89665f..cac8716129 100644
--- a/tests/manual/permissions/CMakeLists.txt
+++ b/tests/manual/permissions/CMakeLists.txt
@@ -6,7 +6,11 @@ qt_internal_add_test(tst_qpermissions
Qt::CorePrivate
)
-if (APPLE)
+if(ANDROID)
+ set_property(TARGET tst_qpermissions
+ PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
+ qt_android_generate_deployment_settings(tst_qpermissions)
+elseif(APPLE)
# Test an app bundle, but without any usage descriptions
qt_internal_add_test(tst_qpermissions_app
diff --git a/tests/manual/permissions/android/AndroidManifest.xml b/tests/manual/permissions/android/AndroidManifest.xml
new file mode 100644
index 0000000000..557ec8007e
--- /dev/null
+++ b/tests/manual/permissions/android/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.qtproject.example"
+ android:installLocation="auto"
+ android:versionCode="-- %%INSERT_VERSION_CODE%% --"
+ android:versionName="-- %%INSERT_VERSION_NAME%% --">
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+ <uses-permission android:name="android.permission.READ_CALENDAR" />
+ <uses-permission android:name="android.permission.WRITE_CALENDAR" />
+ <!-- %%INSERT_PERMISSIONS -->
+ <!-- %%INSERT_FEATURES -->
+ <supports-screens
+ android:anyDensity="true"
+ android:largeScreens="true"
+ android:normalScreens="true"
+ android:smallScreens="true" />
+ <application
+ android:name="org.qtproject.qt.android.bindings.QtApplication"
+ android:hardwareAccelerated="true"
+ android:label="-- %%INSERT_APP_NAME%% --"
+ android:requestLegacyExternalStorage="true"
+ android:allowNativeHeapPointerTagging="false"
+ android:allowBackup="true"
+ android:fullBackupOnly="false">
+ <activity
+ android:name="org.qtproject.qt.android.bindings.QtActivity"
+ android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
+ android:label="-- %%INSERT_APP_NAME%% --"
+ android:launchMode="singleTop"
+ android:screenOrientation="unspecified"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ <meta-data
+ android:name="android.app.lib_name"
+ android:value="-- %%INSERT_APP_LIB_NAME%% --" />
+
+ <meta-data
+ android:name="android.app.extract_android_style"
+ android:value="minimal" />
+ </activity>
+ </application>
+</manifest>