From c5b0478e9abf9dc1f1f659e7d5a0e2f89602ef29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Fri, 10 Apr 2015 14:29:18 -0700 Subject: [PATCH 1/3] Detach GLKView while app is in background MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Throw a static snapshot up for the app switcher. Hope you didn’t plan on moving markers around while the app is in the background. Fixes #1050, #1186, #1203, #1243. --- platform/ios/MGLMapView.mm | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index f70f9f348..afea8ae4f 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -67,6 +67,8 @@ static NSURL *MGLURLForBundledStyleNamed(NSString *styleName) @property (nonatomic) EAGLContext *context; @property (nonatomic) GLKView *glView; +/** A static view to impersonate `glView` when the app is in the background. */ +@property (nonatomic) UIImageView *glImpersonatingView; @property (nonatomic) NSOperationQueue *regionChangeDelegateQueue; @property (nonatomic) UIImageView *compass; @property (nonatomic) UIImageView *logoBug; @@ -240,6 +242,13 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; [self insertSubview:_glView atIndex:0]; _glView.contentMode = UIViewContentModeCenter; + + // create GL impersonating view + // + _glImpersonatingView = [[UIImageView alloc] initWithFrame:_glView.frame]; + _glImpersonatingView.autoresizingMask = _glView.autoresizingMask; + [self insertSubview:_glImpersonatingView belowSubview:_glView]; + [self setBackgroundColor:[UIColor clearColor]]; // load extensions @@ -583,6 +592,10 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; { [MGLMapboxEvents flush]; + UIImage *snapshot = [self.glView snapshot]; + self.glImpersonatingView.image = snapshot; + [self.glView removeFromSuperview]; + mbglMap->stop(); [self.glView deleteDrawable]; @@ -593,6 +606,8 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; [self.glView bindDrawable]; mbglMap->start(); + + [self insertSubview:self.glView aboveSubview:self.glImpersonatingView]; } - (void)tintColorDidChange From e19b6afb264deca6b24f2c6832ac71f961be7b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Tue, 14 Apr 2015 22:23:13 -0700 Subject: [PATCH 2/3] Leave GLKView in place, obscured by snapshot Generate the snapshot using `-[UIView snapshotViewAfterScreenUpdates:]` and place it _over_ the `GLKView`. UIKit appears to be able to detect that the `GLKView` is completely obscured and avoids `-_display`ing it. --- platform/ios/MGLMapView.mm | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index afea8ae4f..d2ccd7396 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -67,8 +67,8 @@ static NSURL *MGLURLForBundledStyleNamed(NSString *styleName) @property (nonatomic) EAGLContext *context; @property (nonatomic) GLKView *glView; -/** A static view to impersonate `glView` when the app is in the background. */ -@property (nonatomic) UIImageView *glImpersonatingView; +/** A static view to simulate and obscure `glView` when the app is in the background. */ +@property (nonatomic) UIView *glSnapshotView; @property (nonatomic) NSOperationQueue *regionChangeDelegateQueue; @property (nonatomic) UIImageView *compass; @property (nonatomic) UIImageView *logoBug; @@ -243,12 +243,6 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; _glView.contentMode = UIViewContentModeCenter; - // create GL impersonating view - // - _glImpersonatingView = [[UIImageView alloc] initWithFrame:_glView.frame]; - _glImpersonatingView.autoresizingMask = _glView.autoresizingMask; - [self insertSubview:_glImpersonatingView belowSubview:_glView]; - [self setBackgroundColor:[UIColor clearColor]]; // load extensions @@ -568,8 +562,11 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; // This is the delegate of the GLKView object's display call. - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { - mbglView->resize(rect.size.width, rect.size.height, view.contentScaleFactor, view.drawableWidth, view.drawableHeight); - mbglMap->renderSync(); + if (!self.glSnapshotView) + { + mbglView->resize(rect.size.width, rect.size.height, view.contentScaleFactor, view.drawableWidth, view.drawableHeight); + mbglMap->renderSync(); + } } // This gets called when the view dimension changes, e.g. because the device is being rotated. @@ -592,9 +589,9 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; { [MGLMapboxEvents flush]; - UIImage *snapshot = [self.glView snapshot]; - self.glImpersonatingView.image = snapshot; - [self.glView removeFromSuperview]; + self.glSnapshotView = [self.glView snapshotViewAfterScreenUpdates:YES]; + self.glSnapshotView.autoresizingMask = self.glView.autoresizingMask; + [self insertSubview:self.glSnapshotView aboveSubview:self.glView]; mbglMap->stop(); @@ -607,7 +604,8 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; mbglMap->start(); - [self insertSubview:self.glView aboveSubview:self.glImpersonatingView]; + [self.glSnapshotView removeFromSuperview]; + self.glSnapshotView = nil; } - (void)tintColorDidChange From ec987ca434dbef232102903f16cef5dc189abf4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 15 Apr 2015 10:18:15 -0700 Subject: [PATCH 3/3] Assert that snapshot view obscures GL view when it exists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just in case the host app mucks around with `MGLView`’s internal view hierarchy. --- platform/ios/MGLMapView.mm | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index d2ccd7396..e0680df56 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -562,7 +562,16 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; // This is the delegate of the GLKView object's display call. - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { - if (!self.glSnapshotView) + if (self.glSnapshotView) + { + NSUInteger snapshotIdx = [self.subviews indexOfObject:self.glSnapshotView]; + NSUInteger glIdx = [self.subviews indexOfObject:self.glView]; + NSAssert(snapshotIdx > glIdx, + @"The snapshot view is the %luth subview, behind the GL view, which is the %luth. " + @"The snapshot view should obscure the GL view to prevent crashing while the app is in the background.", + (unsigned long)snapshotIdx, (unsigned long)glIdx); + } + else { mbglView->resize(rect.size.width, rect.size.height, view.contentScaleFactor, view.drawableWidth, view.drawableHeight); mbglMap->renderSync();