Skip to content

Commit 9e5e7ce

Browse files
Fixed leak of CarAppLifecycleOwner (#7669)
1 parent 659d1ed commit 9e5e7ce

File tree

4 files changed

+42
-1
lines changed

4 files changed

+42
-1
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Fixed leak of CarAppLifecycleOwner on every copilot start.

libnavigation-copilot/src/main/java/com/mapbox/navigation/copilot/MapboxCopilotImpl.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,18 @@ internal class MapboxCopilotImpl(
144144
arrivedAtFinalDestination = true
145145
}
146146
}
147+
private val appLifecycleOwnerCleanupAction: () -> Unit
147148
private val appLifecycleOwner = if (MapboxNavigationApp.isSetup()) {
149+
appLifecycleOwnerCleanupAction = { }
148150
MapboxNavigationApp.lifecycleOwner
149151
} else {
150152
CarAppLifecycleOwner().apply {
151153
val applicationContext = mapboxNavigation.navigationOptions.applicationContext
152-
attachAllActivities(applicationContext as Application)
154+
val application = applicationContext as Application
155+
attachAllActivities(application)
156+
appLifecycleOwnerCleanupAction = {
157+
detachAllActivities(application)
158+
}
153159
}
154160
}
155161
private val historyFiles = mutableMapOf<File, CopilotMetadata>()
@@ -172,6 +178,7 @@ internal class MapboxCopilotImpl(
172178
fun stop() {
173179
unregisterUserFeedbackCallback(userFeedbackCallback)
174180
appLifecycleOwner.lifecycle.removeObserver(foregroundBackgroundLifecycleObserver)
181+
appLifecycleOwnerCleanupAction()
175182
mapboxNavigation.unregisterHistoryRecordingStateChangeObserver(
176183
historyRecordingStateChangeObserver
177184
)

libnavigation-copilot/src/test/java/com/mapbox/navigation/copilot/MapboxCopilotImplTest.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import com.mapbox.navigation.core.internal.telemetry.UserFeedbackCallback
3434
import com.mapbox.navigation.core.internal.telemetry.registerUserFeedbackCallback
3535
import com.mapbox.navigation.core.internal.telemetry.unregisterUserFeedbackCallback
3636
import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp
37+
import com.mapbox.navigation.testing.LoggingFrontendTestRule
3738
import com.mapbox.navigation.testing.MainCoroutineRule
3839
import com.mapbox.navigation.utils.internal.DefaultLifecycleObserver
3940
import com.mapbox.navigation.utils.internal.logD
@@ -73,6 +74,9 @@ class MapboxCopilotImplTest {
7374
@get:Rule
7475
val coroutineRule = MainCoroutineRule()
7576

77+
@get:Rule
78+
val loggingFrontendTestRule = LoggingFrontendTestRule()
79+
7680
@Before
7781
fun setUp() {
7882
mockkStatic(SystemClock::elapsedRealtime)
@@ -463,6 +467,30 @@ class MapboxCopilotImplTest {
463467
verify(exactly = 1) { mockedAppLifecycle.removeObserver(any()) }
464468
}
465469

470+
@Test
471+
fun `activity Lifecycle Callbacks is unregistered when stop if MapboxNavigationApp is not setup`() {
472+
val mockedMapboxNavigation = prepareBasicMockks()
473+
val mockedAppLifecycle = prepareCarAppLifecycleOwnerMockk()
474+
val historyRecordingStateChangeObserver = slot<HistoryRecordingStateChangeObserver>()
475+
every {
476+
mockedMapboxNavigation.registerHistoryRecordingStateChangeObserver(
477+
capture(historyRecordingStateChangeObserver)
478+
)
479+
} just Runs
480+
val mapboxCopilot = createMapboxCopilotImplementation(mockedMapboxNavigation)
481+
mapboxCopilot.start()
482+
val activeGuidanceHistoryRecordingSessionState =
483+
mockk<HistoryRecordingSessionState.ActiveGuidance>(relaxed = true)
484+
historyRecordingStateChangeObserver.captured.onShouldStartRecording(
485+
activeGuidanceHistoryRecordingSessionState
486+
)
487+
488+
mapboxCopilot.stop()
489+
490+
verify(exactly = 1) { anyConstructed<CarAppLifecycleOwner>().attachAllActivities(any()) }
491+
verify(exactly = 1) { anyConstructed<CarAppLifecycleOwner>().detachAllActivities(any()) }
492+
}
493+
466494
@Test
467495
fun `unregisterHistoryRecordingStateChangeObserver is called when stop`() {
468496
val mockedMapboxNavigation = prepareBasicMockks()

libnavigation-core/src/main/java/com/mapbox/navigation/core/internal/lifecycle/CarAppLifecycleOwner.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,11 @@ class CarAppLifecycleOwner : LifecycleOwner {
173173
application.registerActivityLifecycleCallbacks(activityLifecycleCallbacks)
174174
}
175175

176+
fun detachAllActivities(application: Application) {
177+
logI("detachAllActivities", LOG_CATEGORY)
178+
application.unregisterActivityLifecycleCallbacks(activityLifecycleCallbacks)
179+
}
180+
176181
fun attach(lifecycleOwner: LifecycleOwner) {
177182
logI("attach", LOG_CATEGORY)
178183
lifecycleOwner.lifecycle.addObserver(startedReferenceCounter)

0 commit comments

Comments
 (0)