summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2016-06-16 15:39:33 +0200
committerTor Arne Vestbø <tor.arne.vestbo@theqtcompany.com>2016-06-17 13:18:29 +0000
commit3e4f885f0c8f9d4e951241459d310ed977936806 (patch)
tree706f8cfc22a4dbb02b9ddbfe375e13d5376ec0a8 /src/plugins
parent655687d84d6a5914227f2580889e20b7e1b31095 (diff)
UIKit: Ensure that Qt's application state is initialized at startup
Using dispatch_async to deliver the initial application state at startup was broken, as that would leave the application in the default application state, inactive, until the next runloop pass. This became a problem when an application was started backgrounded, eg. in response to location updates or a Bluetooth accessory waking it up, as it would have a small window of time at startup where it would think it was able to render content (since the window was exposed), while in fact the application was running in the background. iOS will in these situations kill the app for doing background rendering. Change-Id: I1ab4a6af08a154d8625c6451b4b5c8f4453e6b43 Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/ios/qiosapplicationstate.h7
-rw-r--r--src/plugins/platforms/ios/qiosapplicationstate.mm134
2 files changed, 46 insertions, 95 deletions
diff --git a/src/plugins/platforms/ios/qiosapplicationstate.h b/src/plugins/platforms/ios/qiosapplicationstate.h
index 0564533043..710621c65b 100644
--- a/src/plugins/platforms/ios/qiosapplicationstate.h
+++ b/src/plugins/platforms/ios/qiosapplicationstate.h
@@ -35,10 +35,11 @@
#define QIOSAPPLICATIONSTATE_H
#include <QtCore/qglobal.h>
+#include <QtCore/qvector.h>
-QT_BEGIN_NAMESPACE
+Q_FORWARD_DECLARE_OBJC_CLASS(NSObject);
-@class QIOSApplicationStateListener;
+QT_BEGIN_NAMESPACE
class QIOSApplicationState
{
@@ -46,7 +47,7 @@ public:
QIOSApplicationState();
~QIOSApplicationState();
private:
- QIOSApplicationStateListener *m_listener;
+ QVector<NSObject*> m_observers;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosapplicationstate.mm b/src/plugins/platforms/ios/qiosapplicationstate.mm
index 7a37e213bd..70a4c8a507 100644
--- a/src/plugins/platforms/ios/qiosapplicationstate.mm
+++ b/src/plugins/platforms/ios/qiosapplicationstate.mm
@@ -36,100 +36,21 @@
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/qcoreapplication.h>
-#import <UIKit/UIKit.h>
-
-@interface QIOSApplicationStateListener : NSObject
-@end
+#include <QtGui/private/qguiapplication_p.h>
-@implementation QIOSApplicationStateListener
-
-- (id)init
-{
- self = [super init];
- if (self) {
- // Listen for application state changes.
- // Note: We use notifications rather than application delegate callbacks to
- // also support hybrid applications were QIOSApplicationDelegate is not in use.
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(applicationDidBecomeActive)
- name:UIApplicationDidBecomeActiveNotification
- object:nil];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(applicationWillResignActive)
- name:UIApplicationWillResignActiveNotification
- object:nil];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(applicationDidEnterBackground)
- name:UIApplicationDidEnterBackgroundNotification
- object:nil];
-
- // Update the current state now, since we have missed all the updates
- // posted from AppKit so far. But let QPA finish initialization first.
- dispatch_async(dispatch_get_main_queue(), ^{
- [self handleApplicationStateChanged:[UIApplication sharedApplication].applicationState];
- });
- }
- return self;
-}
-
-- (void)dealloc
-{
- [[NSNotificationCenter defaultCenter]
- removeObserver:self
- name:UIApplicationDidBecomeActiveNotification
- object:nil];
- [[NSNotificationCenter defaultCenter]
- removeObserver:self
- name:UIApplicationWillResignActiveNotification
- object:nil];
- [[NSNotificationCenter defaultCenter]
- removeObserver:self
- name:UIApplicationDidEnterBackgroundNotification
- object:nil];
- [super dealloc];
-}
-
-- (void)applicationDidBecomeActive
-{
- [self handleApplicationStateChanged:UIApplicationStateActive];
-}
-
-- (void)applicationWillResignActive
-{
- // Note that UIApplication is still UIApplicationStateActive at this
- // point, but since there is no separate notification for the inactive
- // state, we report UIApplicationStateInactive now:
- [self handleApplicationStateChanged:UIApplicationStateInactive];
-}
-
-- (void)applicationDidEnterBackground
-{
- [self handleApplicationStateChanged:UIApplicationStateBackground];
-}
+#import <UIKit/UIKit.h>
-- (void)handleApplicationStateChanged:(UIApplicationState)uiApplicationState
+static Qt::ApplicationState qtApplicationState(UIApplicationState uiApplicationState)
{
- // We may receive application state changes after QCoreApplication has
- // gone down, as the block we schedule on the main queue keeps the
- // listener alive. In that case we just ignore the notification.
- if (!qApp)
- return;
-
- Qt::ApplicationState state;
switch (uiApplicationState) {
case UIApplicationStateActive:
- // The application is visible in front, and receiving events:
- state = Qt::ApplicationActive;
- break;
+ // 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:
- state = Qt::ApplicationInactive;
- break;
+ // 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).
@@ -138,25 +59,54 @@
// 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.
- state = Qt::ApplicationSuspended;
- break;
+ return Qt::ApplicationSuspended;
}
+}
+
+static void handleApplicationStateChanged(UIApplicationState uiApplicationState)
+{
+ Qt::ApplicationState state = qtApplicationState(uiApplicationState);
QWindowSystemInterface::handleApplicationStateChanged(state);
QWindowSystemInterface::flushWindowSystemEvents();
}
-@end
-
QT_BEGIN_NAMESPACE
QIOSApplicationState::QIOSApplicationState()
- : m_listener([[QIOSApplicationStateListener alloc] init])
{
+ 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::~QIOSApplicationState()
{
- [m_listener release];
+ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+ foreach (const NSObject* observer, m_observers)
+ [notificationCenter removeObserver:observer];
}
QT_END_NAMESPACE