Skip to content

Commit 514d320

Browse files
maiosgithub-actions[bot]
authored andcommitted
[maps-ios] fix display link not running for CarPlay Dashboard/Instrument Cluster scenes (#11181)
Cache the connected scene of map view (scene contains map view's window that is activated) to correctly determine display link pause/resume state if the current window does not have reference to `windowScene` (i.e CarPlay dashboard scene) After mapbox/mapbox-sdk#5770 which introduced Display link tweak, it was changed from `shouldPauseDisplayLink` which would never pause for window of CarPlay dashboard scene, to `shouldRunDisplayLink` which would never run for same scene MAPSIOS-2130 The issue can be reproduced with our CarPlay example - Run Examples app on CarPlay in split screen mode (dashboard) - On the left panel, tap on `Start` and `Stop` button; observe that on main branch the map would not perform any camera animation **Before** https://github.com/user-attachments/assets/ce6f8f67-ecfe-4c30-b8a7-d3c1c70d18f4 **After** https://github.com/user-attachments/assets/7943b4ca-d05c-402e-ba29-662fd3ca4f9e cc @mapbox/maps-ios GitOrigin-RevId: ab46d0b02e8bdb9ab15f53ac3c37c76dffa4ac13
1 parent d239ef0 commit 514d320

File tree

4 files changed

+19
-53
lines changed

4 files changed

+19
-53
lines changed

Sources/MapboxMaps/Foundation/Extensions/UIWindow+ParentScene.swift

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,6 @@ import UIKit
55

66
extension UIWindow {
77

8-
/// The `UIScene` containing this window.
9-
internal var parentScene: UIScene? {
10-
#if canImport(CarPlay)
11-
switch self {
12-
case let carPlayWindow as CPWindow:
13-
return carPlayWindow.templateApplicationScene
14-
default:
15-
return windowScene
16-
}
17-
#else
18-
return windowScene
19-
#endif
20-
}
21-
228
var isCarPlay: Bool {
239
#if canImport(CarPlay)
2410
return self is CPWindow

Sources/MapboxMaps/Foundation/MapView.swift

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,17 @@ open class MapView: UIView, SizeTrackingLayerDelegate {
117117
didSet {
118118
// cache activation state for efficiency
119119
permissibleActivationStates = displayState.sceneActivationStates
120-
displayLink?.isRunning = shouldRunDisplayLink(for: window?.parentScene)
120+
displayLink?.isRunning = shouldRunDisplayLink(for: window?.windowScene)
121121
}
122122
}
123123
private var permissibleActivationStates: Set<UIScene.ActivationState> = [.foregroundActive, .foregroundInactive]
124124

125+
/// The scene that is currently connected to this map view.
126+
///
127+
/// This property is set when a scene containing the map view's window becomes activated,
128+
/// and reset to `nil` when that scene becomes deactivated.
129+
private weak var connectedScene: UIScene?
130+
125131
/// The `gestures` object will be responsible for all gestures on the map.
126132
public private(set) var gestures: GestureManager!
127133

@@ -543,26 +549,28 @@ open class MapView: UIView, SizeTrackingLayerDelegate {
543549
notificationCenter.addObserver(self,
544550
selector: #selector(sceneDidEnterBackground(_:)),
545551
name: UIScene.didEnterBackgroundNotification,
546-
object: window?.parentScene)
552+
object: window?.windowScene)
547553
notificationCenter.addObserver(self,
548554
selector: #selector(sceneWillDeactivate(_:)),
549555
name: UIScene.willDeactivateNotification,
550-
object: window?.parentScene)
556+
object: window?.windowScene)
551557
notificationCenter.addObserver(self,
552558
selector: #selector(sceneDidActivate(_:)),
553559
name: UIScene.didActivateNotification,
554-
object: window?.parentScene)
560+
object: window?.windowScene)
555561
}
556562

557563
@objc private func sceneDidActivate(_ notification: Notification) {
558564
guard let scene = notification.object as? UIScene, let window = window, scene.allWindows.contains(window) else { return }
559565

566+
connectedScene = scene
560567
displayLink?.isRunning = true
561568
}
562569

563570
@objc private func sceneWillDeactivate(_ notification: Notification) {
564571
guard let scene = notification.object as? UIScene, let window = window, scene.allWindows.contains(window) else { return }
565572

573+
connectedScene = nil
566574
displayLink?.isRunning = displayState.shouldRunDisplayLinkWhenInactive
567575
}
568576

@@ -694,7 +702,7 @@ open class MapView: UIView, SizeTrackingLayerDelegate {
694702

695703
@_spi(Metrics) public var metricsReporter: MapViewMetricsReporter?
696704
private func updateFromDisplayLink(displayLink: CADisplayLink) {
697-
if !shouldRunDisplayLink(for: window?.parentScene) {
705+
if !shouldRunDisplayLink(for: window?.windowScene) {
698706
displayLink.isPaused = true
699707
return
700708
}
@@ -786,7 +794,7 @@ open class MapView: UIView, SizeTrackingLayerDelegate {
786794
subscribeSceneToLifecycleNotifications()
787795

788796
// make sure that the display link is (de)activated for a current app/scene state
789-
displayLink.isRunning = shouldRunDisplayLink(for: window.parentScene)
797+
displayLink.isRunning = shouldRunDisplayLink(for: window.windowScene)
790798

791799
displayLink.add(to: .current, forMode: .common)
792800
}
@@ -799,8 +807,8 @@ open class MapView: UIView, SizeTrackingLayerDelegate {
799807
displayLink?.isRunning = true
800808
}
801809

802-
private func shouldRunDisplayLink(for scene: UIScene?) -> Bool {
803-
if let scene, permissibleActivationStates.contains(scene.activationState) {
810+
private func shouldRunDisplayLink(for scene: UIScene? = nil) -> Bool {
811+
if let scene = scene ?? connectedScene, permissibleActivationStates.contains(scene.activationState) {
804812
return true
805813
}
806814

Tests/MapboxMapsTests/Foundation/Extensions/UIWindow+ParentSceneTests.swift

Lines changed: 0 additions & 28 deletions
This file was deleted.

Tests/MapboxMapsTests/Foundation/MapViewTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -407,21 +407,21 @@ final class MapViewTestsWithScene: XCTestCase {
407407
func testDisplayLinkResumedWhenSceneDidActivate() throws {
408408
displayLink.$isPausedStub.setStub.reset()
409409

410-
notificationCenter.post(name: UIScene.didActivateNotification, object: window.parentScene)
410+
notificationCenter.post(name: UIScene.didActivateNotification, object: window.windowScene)
411411

412412
XCTAssertEqual(displayLink.$isPausedStub.setStub.invocations.map(\.parameters), [false])
413413
}
414414

415415
func testDisplayLinkRunningWhenSceneWillDeactivate() throws {
416416
displayLink.$isPausedStub.setStub.reset()
417417

418-
notificationCenter.post(name: UIScene.willDeactivateNotification, object: window.parentScene)
418+
notificationCenter.post(name: UIScene.willDeactivateNotification, object: window.windowScene)
419419

420420
XCTAssertEqual(displayLink.$isPausedStub.setStub.invocations.map(\.parameters), [false])
421421
}
422422

423423
func testReleaseDrawablesInvokedWhenSceneMovingToBackground() throws {
424-
notificationCenter.post(name: UIScene.didEnterBackgroundNotification, object: window.parentScene)
424+
notificationCenter.post(name: UIScene.didEnterBackgroundNotification, object: window.windowScene)
425425

426426
XCTAssertEqual(metalView.releaseDrawablesStub.invocations.count, 1)
427427
}

0 commit comments

Comments
 (0)