summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/ios/qiosapplicationstate.mm
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2017-12-04 14:41:36 +0100
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2017-12-06 20:46:51 +0000
commite37c9d5d5f4ba9874808a4e565c36b2953eb96da (patch)
tree1a7f0a1ae885fccfb6ff8114c4eed9e197bb7908 /src/plugins/platforms/ios/qiosapplicationstate.mm
parent77942a1bdf9fe22d8f076e59ce19fe9a9d7870d7 (diff)
iOS: Harden application state change logic
Make sure we catch application state changes as early as possible, and deal properly with any changes delivered before we have an app to send them to. Change-Id: I6d0ea0398f9fab88fc182342769b075cb144227f Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
Diffstat (limited to 'src/plugins/platforms/ios/qiosapplicationstate.mm')
-rw-r--r--src/plugins/platforms/ios/qiosapplicationstate.mm110
1 files changed, 52 insertions, 58 deletions
diff --git a/src/plugins/platforms/ios/qiosapplicationstate.mm b/src/plugins/platforms/ios/qiosapplicationstate.mm
index 7c8e1f9927..fed09999b5 100644
--- a/src/plugins/platforms/ios/qiosapplicationstate.mm
+++ b/src/plugins/platforms/ios/qiosapplicationstate.mm
@@ -40,82 +40,76 @@
#include "qiosapplicationstate.h"
#include "qiosglobal.h"
+#include "qiosintegration.h"
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/qcoreapplication.h>
#include <QtGui/private/qguiapplication_p.h>
-#import <UIKit/UIKit.h>
+QT_BEGIN_NAMESPACE
-static Qt::ApplicationState qtApplicationState(UIApplicationState uiApplicationState)
+static void qRegisterApplicationStateNotifications()
{
- switch (uiApplicationState) {
- case UIApplicationStateActive:
- // The application is visible in front, and receiving events
- return Qt::ApplicationActive;
- case UIApplicationStateInactive:
- // The app is running in the foreground but is not receiving events. This
- // typically happens while transitioning to/from active/background, like
- // upon app launch or when receiving incoming calls.
- return Qt::ApplicationInactive;
- case UIApplicationStateBackground:
- // Normally the app would enter this state briefly before it gets
- // suspeded (you have five seconds, according to Apple).
- // You can request more time and start a background task, which would
- // normally map closer to Qt::ApplicationHidden. But since we have no
- // API for doing that yet, we handle this state as "about to be suspended".
- // Note: A screen-shot for the SpringBoard will also be taken after this
- // call returns.
- return Qt::ApplicationSuspended;
+ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+ NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
+
+ // Map between notifications and corresponding application state. Note that
+ // there's no separate notification for moving to UIApplicationStateInactive,
+ // so we use UIApplicationWillResignActiveNotification as an intermediate.
+ static QMap<NSNotificationName, UIApplicationState> notifications {
+ { UIApplicationDidBecomeActiveNotification, UIApplicationStateActive },
+ { UIApplicationWillResignActiveNotification, UIApplicationStateInactive },
+ { UIApplicationDidEnterBackgroundNotification, UIApplicationStateBackground },
+ };
+
+ for (auto i = notifications.constBegin(); i != notifications.constEnd(); ++i) {
+ [notificationCenter addObserverForName:i.key() object:nil queue:mainQueue
+ usingBlock:^void(NSNotification *notification) {
+ NSRange nameRange = NSMakeRange(2, notification.name.length - 14);
+ QString reason = QString::fromNSString([notification.name substringWithRange:nameRange]);
+ QIOSApplicationState::handleApplicationStateChanged(i.value(), reason);
+ }];
}
-}
-static void handleApplicationStateChanged(UIApplicationState uiApplicationState)
-{
- Qt::ApplicationState state = qtApplicationState(uiApplicationState);
- qCDebug(lcQpaApplication) << "moved to" << state;
- QWindowSystemInterface::handleApplicationStateChanged(state);
+ // Initialize correct startup state, which may not be the Qt default (inactive)
+ UIApplicationState startupState = [UIApplication sharedApplication].applicationState;
+ QIOSApplicationState::handleApplicationStateChanged(startupState, QLatin1String("Application loaded"));
}
-
-QT_BEGIN_NAMESPACE
+Q_CONSTRUCTOR_FUNCTION(qRegisterApplicationStateNotifications)
QIOSApplicationState::QIOSApplicationState()
{
- NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
-
- m_observers.push_back([notificationCenter addObserverForName:UIApplicationDidBecomeActiveNotification
- object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *) {
- handleApplicationStateChanged(UIApplicationStateActive);
- }
- ]);
-
- m_observers.push_back([notificationCenter addObserverForName:UIApplicationWillResignActiveNotification
- object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *) {
- // Note: UIApplication is still UIApplicationStateActive at this point,
- // but since there is no separate notification for the inactive state,
- // we report UIApplicationStateInactive now.
- handleApplicationStateChanged(UIApplicationStateInactive);
- }
- ]);
-
- m_observers.push_back([notificationCenter addObserverForName:UIApplicationDidEnterBackgroundNotification
- object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *) {
- handleApplicationStateChanged(UIApplicationStateBackground);
- }
- ]);
-
- // Initialize correct startup state, which may not be the Qt default (inactive)
UIApplicationState startupState = [UIApplication sharedApplication].applicationState;
- QGuiApplicationPrivate::applicationState = qtApplicationState(startupState);
+ QIOSApplicationState::handleApplicationStateChanged(startupState, QLatin1String("Application launched"));
}
-QIOSApplicationState::~QIOSApplicationState()
+void QIOSApplicationState::handleApplicationStateChanged(UIApplicationState uiState, const QString &reason)
{
- NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
- foreach (const NSObject* observer, m_observers)
- [notificationCenter removeObserver:observer];
+ Qt::ApplicationState state = toQtApplicationState(uiState);
+ qCDebug(lcQpaApplication) << qPrintable(reason)
+ << "- moving from" << QGuiApplication::applicationState() << "to" << state;
+
+ if (QIOSIntegration *integration = QIOSIntegration::instance()) {
+ emit integration->applicationState.applicationStateWillChange(state);
+ QWindowSystemInterface::handleApplicationStateChanged(state);
+ emit integration->applicationState.applicationStateDidChange(state);
+ qCDebug(lcQpaApplication) << "done moving to" << state;
+ } else {
+ qCDebug(lcQpaApplication) << "no platform integration yet, setting state directly";
+ QGuiApplicationPrivate::applicationState = state;
+ }
}
-QT_END_NAMESPACE
+Qt::ApplicationState QIOSApplicationState::toQtApplicationState(UIApplicationState state)
+{
+ switch (state) {
+ case UIApplicationStateActive: return Qt::ApplicationActive;
+ case UIApplicationStateInactive: return Qt::ApplicationInactive;
+ case UIApplicationStateBackground: return Qt::ApplicationSuspended;
+ }
+}
+#include "moc_qiosapplicationstate.cpp"
+
+QT_END_NAMESPACE