Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qpermissions_android.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qpermissions.h"
5#include "qpermissions_p.h"
6
7#include <QtCore/qstringlist.h>
8#include <QtCore/qfuture.h>
9#include <QtCore/qhash.h>
10
11#include "private/qandroidextras_p.h"
12
14
15using namespace Qt::StringLiterals;
16
18{
19 QStringList nativeLocationPermissionList;
20 const int sdkVersion = QtAndroidPrivate::androidSdkVersion();
21 static QString backgroundLocation = u"android.permission.ACCESS_BACKGROUND_LOCATION"_s;
22 static QString fineLocation = u"android.permission.ACCESS_FINE_LOCATION"_s;
23 static QString coarseLocation = u"android.permission.ACCESS_COARSE_LOCATION"_s;
24
25 // Since Android API 30, background location cannot be requested along
26 // with fine or coarse location, but it should be requested separately after
27 // the latter have been granted, see
28 // https://developer.android.com/training/location/permissions
29 if (sdkVersion < 30 || permission.availability() == QLocationPermission::WhenInUse) {
30 if (permission.accuracy() == QLocationPermission::Approximate) {
31 nativeLocationPermissionList << coarseLocation;
32 } else {
33 nativeLocationPermissionList << fineLocation;
34 // Since Android API 31, if precise location is requested, it's advised
35 // to request both fine and coarse location permissions, see
36 // https://developer.android.com/training/location/permissions#approximate-request
37 if (sdkVersion >= 31)
38 nativeLocationPermissionList << coarseLocation;
39 }
40 }
41
42 // NOTE: before Android API 29, background permission doesn't exist yet.
43
44 // Keep the background permission in front to be able to use first()
45 // on the list in checkPermission() because it takes single permission.
46 if (sdkVersion >= 29 && permission.availability() == QLocationPermission::Always)
47 nativeLocationPermissionList.prepend(backgroundLocation);
48
49 return nativeLocationPermissionList;
50}
51
53{
54 // See https://developer.android.com/guide/topics/connectivity/bluetooth/permissions
55 // for the details.
56
57 // API Level < 31
58 static QString bluetoothGeneral = u"android.permission.BLUETOOTH"_s;
59 // API Level >= 31
60 static QString bluetoothScan = u"android.permission.BLUETOOTH_SCAN"_s;
61 static QString bluetoothAdvertise = u"android.permission.BLUETOOTH_ADVERTISE"_s;
62 static QString bluetoothConnect = u"android.permission.BLUETOOTH_CONNECT"_s;
63 // Fine location is currently required for ALL API levels, but that is not
64 // strictly necessary for API Level >= 31. See QTBUG-112164.
65 static QString fineLocation = u"android.permission.ACCESS_FINE_LOCATION"_s;
66
68 return {bluetoothGeneral, fineLocation};
69 } else {
70 const auto modes = permission.communicationModes();
71 QStringList permissionList;
73 permissionList << bluetoothAdvertise;
75 permissionList << bluetoothScan << bluetoothConnect << fineLocation;
76 return permissionList;
77 }
78}
79
81{
82 const auto id = permission.type().id();
83 if (id == qMetaTypeId<QLocationPermission>()) {
85 } else if (id == qMetaTypeId<QCameraPermission>()) {
86 return { u"android.permission.CAMERA"_s };
87 } else if (id == qMetaTypeId<QMicrophonePermission>()) {
88 return { u"android.permission.RECORD_AUDIO"_s };
89 } else if (id == qMetaTypeId<QBluetoothPermission>()) {
91 } else if (id == qMetaTypeId<QContactsPermission>()) {
92 const auto readContactsString = u"android.permission.READ_CONTACTS"_s;
93 switch (permission.value<QContactsPermission>()->accessMode()) {
95 return { readContactsString };
97 return { readContactsString, u"android.permission.WRITE_CONTACTS"_s };
98 }
99 Q_UNREACHABLE_RETURN({});
100 } else if (id == qMetaTypeId<QCalendarPermission>()) {
101 const auto readContactsString = u"android.permission.READ_CALENDAR"_s;
102 switch (permission.value<QCalendarPermission>()->accessMode()) {
104 return { readContactsString };
106 return { readContactsString, u"android.permission.WRITE_CALENDAR"_s };
107 }
108 Q_UNREACHABLE_RETURN({});
109 }
110
111 return {};
112}
113
115permissionStatusForAndroidResult(QtAndroidPrivate::PermissionResult result)
116{
117 switch (result) {
118 case QtAndroidPrivate::PermissionResult::Authorized: return Qt::PermissionStatus::Granted;
119 case QtAndroidPrivate::PermissionResult::Denied: return Qt::PermissionStatus::Denied;
121 }
122}
123
124using PermissionStatusHash = QHash<int, Qt::PermissionStatus>;
126 { qMetaTypeId<QCameraPermission>(), Qt::PermissionStatus::Undetermined },
127 { qMetaTypeId<QMicrophonePermission>(), Qt::PermissionStatus::Undetermined },
128 { qMetaTypeId<QBluetoothPermission>(), Qt::PermissionStatus::Undetermined },
129 { qMetaTypeId<QContactsPermission>(), Qt::PermissionStatus::Undetermined },
130 { qMetaTypeId<QCalendarPermission>(), Qt::PermissionStatus::Undetermined },
131 { qMetaTypeId<QLocationPermission>(), Qt::PermissionStatus::Undetermined }
132}));
133
135getCombinedStatus(const QList<QtAndroidPrivate::PermissionResult> &androidResults)
136{
137 // Android returns only Denied or Granted
138 for (const auto &result : androidResults) {
139 const auto status = permissionStatusForAndroidResult(result);
140 if (status == Qt::PermissionStatus::Denied)
141 return status;
142 }
144}
145
146namespace QPermissions::Private
147{
149 {
150 const auto nativePermissionList = nativeStringsFromPermission(permission);
151 if (nativePermissionList.isEmpty())
153
154 QList<QtAndroidPrivate::PermissionResult> androidResults;
155 androidResults.reserve(nativePermissionList.size());
156 for (const auto &nativePermission : nativePermissionList)
157 androidResults.push_back(QtAndroidPrivate::checkPermission(nativePermission).result());
158
159 const auto status = getCombinedStatus(androidResults);
160 const auto it = g_permissionStatusHash->constFind(permission.type().id());
161 const bool foundStatus = (it != g_permissionStatusHash->constEnd());
162 const bool itUndetermined = foundStatus && (*it) == Qt::PermissionStatus::Undetermined;
163 if (status == Qt::PermissionStatus::Denied && itUndetermined)
165 return status;
166 }
167
168 void requestPermission(const QPermission &permission,
170 {
171 const auto nativePermissionList = nativeStringsFromPermission(permission);
172 if (nativePermissionList.isEmpty()) {
174 return;
175 }
176
177 QtAndroidPrivate::requestPermissions(nativePermissionList).then(qApp,
178 [callback, permission](QFuture<QtAndroidPrivate::PermissionResult> future) {
179 const auto androidResults = future.isValid() ? future.results()
181 const auto status = getCombinedStatus(androidResults);
182 g_permissionStatusHash->insert(permission.type().id(), status);
183 callback(status);
184 }
185 );
186 }
187}
188
Access Bluetooth peripherals.
Q_CORE_EXPORT CommunicationModes communicationModes() const
Access the user's calendar.
Q_CORE_EXPORT AccessMode accessMode() const
Returns AccessMode::ReadWrite when the request is for read-write and AccessMode::ReadOnly when it is ...
Access the user's contacts.
Q_CORE_EXPORT AccessMode accessMode() const
Returns AccessMode::ReadWrite when the request is for read-write and AccessMode::ReadOnly when it is ...
bool isValid() const
Definition qfuture.h:125
QList< T > results() const
Definition qfuture.h:114
\inmodule QtCore
Definition qhash.h:820
Definition qlist.h:75
Access the user's location.
Q_CORE_EXPORT Availability availability() const
Returns the availability of the request.
Q_CORE_EXPORT Accuracy accuracy() const
Returns the accuracy of the request.
int id(int=0) const
Definition qmetatype.h:475
\inmodule QtCore \inheaderfile QPermissions
std::optional< T > value() const
QMetaType type() const
Returns the type of the permission.
const_iterator constEnd() const noexcept
Definition qset.h:143
const_iterator constFind(const T &value) const
Definition qset.h:161
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString & prepend(QChar c)
Definition qstring.h:478
QSet< QString >::iterator it
void requestPermission(const QPermission &permission, const PermissionCallback &callback)
std::function< void(Qt::PermissionStatus)> PermissionCallback
Qt::PermissionStatus checkPermission(const QPermission &permission)
Combined button and popup list for selecting options.
\preliminary \inmodule QtCorePrivate
Q_CORE_EXPORT jint androidSdkVersion()
PermissionStatus
#define qApp
#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS)
GLuint64EXT * result
[6]
static QStringList nativeBluetoothPermission(const QBluetoothPermission &permission)
static Qt::PermissionStatus permissionStatusForAndroidResult(QtAndroidPrivate::PermissionResult result)
static Qt::PermissionStatus getCombinedStatus(const QList< QtAndroidPrivate::PermissionResult > &androidResults)
static QStringList nativeStringsFromPermission(const QPermission &permission)
static QStringList nativeLocationPermission(const QLocationPermission &permission)
QFuture< void > future
[5]