summaryrefslogtreecommitdiffstats
path: root/src/corelib/platform/darwin/qdarwinpermissionplugin.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/platform/darwin/qdarwinpermissionplugin.mm')
-rw-r--r--src/corelib/platform/darwin/qdarwinpermissionplugin.mm90
1 files changed, 90 insertions, 0 deletions
diff --git a/src/corelib/platform/darwin/qdarwinpermissionplugin.mm b/src/corelib/platform/darwin/qdarwinpermissionplugin.mm
new file mode 100644
index 0000000000..5c527f396c
--- /dev/null
+++ b/src/corelib/platform/darwin/qdarwinpermissionplugin.mm
@@ -0,0 +1,90 @@
+// 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 "qdarwinpermissionplugin_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QDarwinPermissionPlugin::QDarwinPermissionPlugin(QDarwinPermissionHandler *handler)
+ : QPermissionPlugin()
+ , m_handler(handler)
+{
+}
+
+QDarwinPermissionPlugin::~QDarwinPermissionPlugin()
+{
+ [m_handler release];
+}
+
+Qt::PermissionStatus QDarwinPermissionPlugin::checkPermission(const QPermission &permission)
+{
+ return [m_handler checkPermission:permission];
+}
+
+void QDarwinPermissionPlugin::requestPermission(const QPermission &permission, const PermissionCallback &callback)
+{
+ if (!verifyUsageDescriptions(permission)) {
+ callback(Qt::PermissionStatus::Denied);
+ return;
+ }
+
+ [m_handler requestPermission:permission withCallback:[=](Qt::PermissionStatus status) {
+ // In case the callback comes in on a secondary thread we need to marshal it
+ // back to the main thread. And if it doesn't, we still want to propagate it
+ // via an event, to avoid any GCD locks deadlocking the application on iOS
+ // if the user responds to the result by running a nested event loop.
+ // Luckily Qt::QueuedConnection gives us exactly what we need.
+ QMetaObject::invokeMethod(this, "permissionUpdated", Qt::QueuedConnection,
+ Q_ARG(Qt::PermissionStatus, status), Q_ARG(PermissionCallback, callback));
+ }];
+}
+
+void QDarwinPermissionPlugin::permissionUpdated(Qt::PermissionStatus status, const PermissionCallback &callback)
+{
+ callback(status);
+}
+
+bool QDarwinPermissionPlugin::verifyUsageDescriptions(const QPermission &permission)
+{
+ // FIXME: Look up the responsible process and inspect that,
+ // as that's what needs to have the usage descriptions.
+ // FIXME: Verify entitlements if the process is sandboxed.
+ auto *infoDictionary = NSBundle.mainBundle.infoDictionary;
+ for (auto description : [m_handler usageDescriptionsFor:permission]) {
+ if (!infoDictionary[description.toNSString()]) {
+ qCWarning(lcPermissions) <<
+ "Requesting" << permission.type().name() <<
+ "requires" << description << "in Info.plist";
+ return false;
+ }
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
+
+QT_USE_NAMESPACE
+
+@implementation QDarwinPermissionHandler
+
+- (Qt::PermissionStatus)checkPermission:(QPermission)permission
+{
+ Q_UNREACHABLE(); // All handlers should at least provide a check
+}
+
+- (void)requestPermission:(QPermission)permission withCallback:(PermissionCallback)callback
+{
+ Q_UNUSED(permission);
+ qCWarning(lcPermissions).nospace() << "Could not request " << permission.type().name() << ". "
+ << "Please make sure you have included the required usage description in your Info.plist";
+ callback(Qt::PermissionStatus::Denied);
+}
+
+- (QStringList)usageDescriptionsFor:(QPermission)permission
+{
+ return {};
+}
+
+@end
+
+#include "moc_qdarwinpermissionplugin_p.cpp"