From abf47610c716955b894e6ee20cc0dae00929799a Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Fri, 6 Nov 2015 12:47:13 +0100 Subject: iOS: only force-finish start-up from file engine when on main thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The authorization dialog that grants the application access to the assets will only show after returning back from applicationDidFinishLaunching. Therefore, trying to load an asset from main before qApp->exec() would normally fail. To remedy that, we added a path that starts a QEventLoop for a split second to force the application init process to finish. But this can only work if we start it from the main thread. A bug with this is seen in QML FileDialog, since it (clumsy enough) starts to iterate, in a separate thread, all the files in its currently set directory upon start-up construction (which should be fixed as well). The result is that the application gets dead-locked on start-up. Change-Id: I0047272d53314752903960b33f88b33dc0d7e78d Reviewed-by: Tor Arne Vestbø --- .../platforms/ios/qiosfileengineassetslibrary.mm | 40 ++++++++++++++-------- 1 file changed, 26 insertions(+), 14 deletions(-) (limited to 'src/plugins/platforms/ios/qiosfileengineassetslibrary.mm') diff --git a/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm b/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm index 761a89c989..bb12c164d6 100644 --- a/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm +++ b/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm @@ -48,20 +48,29 @@ static QThreadStorage > g_assetDataCache; static const int kBufferSize = 10; static ALAsset *kNoAsset = 0; -static void ensureAuthorizationDialogNotBlocked() +static bool ensureAuthorizationDialogNotBlocked() { if ([ALAssetsLibrary authorizationStatus] != ALAuthorizationStatusNotDetermined) - return; + return true; + if (static_cast(QObjectPrivate::get(qApp))->in_exec) - return; - - // Since authorization status has not been determined, the user will be asked - // to authorize the app. But since main has not finished, the dialog will be held - // back until the launch completes. To avoid a dead-lock below, we start an event - // loop to complete the launch. - QEventLoop loop; - QTimer::singleShot(1, &loop, &QEventLoop::quit); - loop.exec(); + return true; + + if ([NSThread isMainThread]) { + // The dialog is about to show, but since main has not finished, the dialog will be held + // back until the launch completes. This is problematic since we cannot successfully return + // back to the caller before the asset is ready, which also includes showing the dialog. To + // work around this, we create an event loop to that will complete the launch (return from the + // applicationDidFinishLaunching callback). But this will only work if we're on the main thread. + QEventLoop loop; + QTimer::singleShot(1, &loop, &QEventLoop::quit); + loop.exec(); + } else { + NSLog(@"QIOSFileEngine: unable to show assets authorization dialog from non-gui thread before QApplication is executing."); + return false; + } + + return true; } // ------------------------------------------------------------------------- @@ -80,8 +89,10 @@ public: , m_writeIndex(0) , m_nextAssetReady(false) { - ensureAuthorizationDialogNotBlocked(); - startEnumerate(); + if (!ensureAuthorizationDialogNotBlocked()) + writeAsset(kNoAsset); + else + startEnumerate(); } ~QIOSAssetEnumerator() @@ -186,7 +197,8 @@ public: , m_assetUrl(assetUrl) , m_assetLibrary(0) { - ensureAuthorizationDialogNotBlocked(); + if (!ensureAuthorizationDialogNotBlocked()) + return; if (QIOSAssetData *assetData = g_assetDataCache.localData()) { // It's a common pattern that QFiles pointing to the same path are created and destroyed -- cgit v1.2.3