QPermission: return the combined result of a permission group on Android

QPermission might resolve to multiple underlying permissions on Android.
The existing code was only using the first permission from the list
in checkPermission(), and also checked only for the first result
returned by requestPermissions().
This can lead to a situation when only one of the requested permissions
is granted, but the API reports that all required permissions are
granted.

This patch fixes it by checking the combined status of all permissions.
If at least one of the permissions is denied, the whole list of
permissions in considered denied.

Fixes: QTBUG-112527
Pick-to: 6.5
Change-Id: I243b73bb5a842197cd0ef70937b8eac344ff9596
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
Ivan Solovev 2023-04-03 15:57:15 +02:00
parent 2f226336a2
commit 10242a8250

View File

@ -124,6 +124,18 @@ Q_GLOBAL_STATIC_WITH_ARGS(PermissionStatusHash, g_permissionStatusHash, ({
{ qMetaTypeId<QLocationPermission>(), Qt::PermissionStatus::Undetermined }
}));
static Qt::PermissionStatus
getCombinedStatus(const QList<QtAndroidPrivate::PermissionResult> &androidResults)
{
// Android returns only Denied or Granted
for (const auto &result : androidResults) {
const auto status = permissionStatusForAndroidResult(result);
if (status == Qt::PermissionStatus::Denied)
return status;
}
return Qt::PermissionStatus::Granted;
}
namespace QPermissions::Private
{
Qt::PermissionStatus checkPermission(const QPermission &permission)
@ -132,8 +144,12 @@ namespace QPermissions::Private
if (nativePermissionList.isEmpty())
return Qt::PermissionStatus::Granted;
const auto result = QtAndroidPrivate::checkPermission(nativePermissionList.first()).result();
const auto status = permissionStatusForAndroidResult(result);
QList<QtAndroidPrivate::PermissionResult> androidResults;
androidResults.reserve(nativePermissionList.size());
for (const auto &nativePermission : nativePermissionList)
androidResults.push_back(QtAndroidPrivate::checkPermission(nativePermission).result());
const auto status = getCombinedStatus(androidResults);
const auto it = g_permissionStatusHash->constFind(permission.type().id());
const bool foundStatus = (it != g_permissionStatusHash->constEnd());
const bool itUndetermined = foundStatus && (*it) == Qt::PermissionStatus::Undetermined;
@ -153,8 +169,9 @@ namespace QPermissions::Private
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);
const auto androidResults = future.isValid() ? future.results()
: QList{QtAndroidPrivate::Denied};
const auto status = getCombinedStatus(androidResults);
g_permissionStatusHash->insert(permission.type().id(), status);
callback(status);
}