Skip to content

Commit 3ebf05f

Browse files
fix(replay): Allow STARTED -> RESUMED state transition in ReplayLifecycle
The ReplayLifecycle state machine did not allow transitioning from STARTED to RESUMED. This caused a bug when the app returned to foreground after being in background longer than sessionIntervalMillis: 1. Timer fires -> stop() -> state becomes STOPPED 2. App returns to foreground -> start() -> state becomes STARTED 3. resume() fails because STARTED -> RESUMED was not allowed The fix adds RESUMED as a valid transition from the STARTED state. Co-authored-by: Giancarlo Buenaflor <giancarlobuenaflor97@gmail.com>
1 parent 80672fe commit 3ebf05f

File tree

3 files changed

+30
-2
lines changed

3 files changed

+30
-2
lines changed

sentry-android-replay/src/main/java/io/sentry/android/replay/ReplayLifecycle.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ internal class ReplayLifecycle {
4646
when (currentState) {
4747
ReplayState.INITIAL -> newState == ReplayState.STARTED || newState == ReplayState.CLOSED
4848
ReplayState.STARTED ->
49-
newState == ReplayState.PAUSED ||
49+
newState == ReplayState.RESUMED ||
50+
newState == ReplayState.PAUSED ||
5051
newState == ReplayState.STOPPED ||
5152
newState == ReplayState.CLOSED
5253
ReplayState.RESUMED ->

sentry-android-replay/src/test/java/io/sentry/android/replay/ReplayIntegrationTest.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,33 @@ class ReplayIntegrationTest {
420420
assertFalse(replay.isRecording)
421421
}
422422

423+
@Test
424+
fun `after stop, start and resume restarts replay`() {
425+
val captureStrategy = mock<CaptureStrategy>()
426+
val recorder = mock<Recorder>()
427+
val replay =
428+
fixture.getSut(
429+
context,
430+
recorderProvider = { recorder },
431+
replayCaptureStrategyProvider = { captureStrategy },
432+
)
433+
434+
replay.register(fixture.scopes, fixture.options)
435+
replay.start()
436+
replay.pause()
437+
replay.stop()
438+
439+
assertFalse(replay.isRecording)
440+
441+
replay.start()
442+
replay.resume()
443+
444+
assertTrue(replay.isRecording)
445+
verify(captureStrategy, times(2)).start(any(), any(), anyOrNull())
446+
verify(captureStrategy).resume()
447+
verify(recorder).resume()
448+
}
449+
423450
@Test
424451
fun `close cleans up resources`() {
425452
val recorder = mock<Recorder>()

sentry-android-replay/src/test/java/io/sentry/android/replay/ReplayLifecycleTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ class ReplayLifecycleTest {
2929
val lifecycle = ReplayLifecycle()
3030
lifecycle.currentState = ReplayState.STARTED
3131

32+
assertTrue(lifecycle.isAllowed(ReplayState.RESUMED))
3233
assertTrue(lifecycle.isAllowed(ReplayState.PAUSED))
3334
assertTrue(lifecycle.isAllowed(ReplayState.STOPPED))
3435
assertTrue(lifecycle.isAllowed(ReplayState.CLOSED))
3536

36-
assertFalse(lifecycle.isAllowed(ReplayState.RESUMED))
3737
assertFalse(lifecycle.isAllowed(ReplayState.INITIAL))
3838
}
3939

0 commit comments

Comments
 (0)