diff --git a/stream-android-core/src/main/java/io/getstream/android/core/internal/recovery/StreamConnectionRecoveryEvaluatorImpl.kt b/stream-android-core/src/main/java/io/getstream/android/core/internal/recovery/StreamConnectionRecoveryEvaluatorImpl.kt index d6812d25..99c09c8d 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/internal/recovery/StreamConnectionRecoveryEvaluatorImpl.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/internal/recovery/StreamConnectionRecoveryEvaluatorImpl.kt @@ -59,6 +59,12 @@ internal class StreamConnectionRecoveryEvaluatorImpl( val previousLifecycle = lastLifecycleState val previousNetwork = lastNetworkState val networkAvailable = networkState is StreamNetworkState.Available + // Only a reported loss counts as offline. `Unknown` means no callback has fired yet, + // which is not the same as "no network" and must not tear a connection down — the same + // way an `Unknown` lifecycle state is not treated as backgrounded below. + val networkLost = + networkState is StreamNetworkState.Disconnected || + networkState is StreamNetworkState.Unavailable val networkBecameAvailable = networkAvailable && previousNetwork !is StreamNetworkState.Available val lifecycleForeground = lifecycleState == StreamLifecycleState.Foreground @@ -67,7 +73,7 @@ internal class StreamConnectionRecoveryEvaluatorImpl( val shouldDisconnect = (isConnected || isConnecting) && - (!networkAvailable || lifecycleState == StreamLifecycleState.Background) + (networkLost || lifecycleState == StreamLifecycleState.Background) val shouldConnect = hasConnectedBefore && diff --git a/stream-android-core/src/test/java/io/getstream/android/core/internal/recovery/StreamConnectionRecoveryEvaluatorImplTest.kt b/stream-android-core/src/test/java/io/getstream/android/core/internal/recovery/StreamConnectionRecoveryEvaluatorImplTest.kt index 3fffb6ae..b47f7673 100644 --- a/stream-android-core/src/test/java/io/getstream/android/core/internal/recovery/StreamConnectionRecoveryEvaluatorImplTest.kt +++ b/stream-android-core/src/test/java/io/getstream/android/core/internal/recovery/StreamConnectionRecoveryEvaluatorImplTest.kt @@ -211,6 +211,41 @@ class StreamConnectionRecoveryEvaluatorImplTest { assertNull(recovery) } + // `Unknown` is the state before any connectivity callback has fired, which happens when the + // platform reports no viable network at registration time. Tearing the in-flight connect down + // there turns a socket failure into a cancellation of the caller's connect(). + @Test + fun `does not disconnect while connecting before the first network callback`() = runTest { + val evaluator = evaluator() + + val recovery = + evaluator + .evaluate( + connectionState = StreamConnectionState.Connecting.Opening(TEST_USER_ID), + lifecycleState = StreamLifecycleState.Foreground, + networkState = StreamNetworkState.Unknown, + ) + .getOrThrow() + + assertNull(recovery) + } + + @Test + fun `disconnects when the network is reported unavailable`() = runTest { + val evaluator = evaluator() + + val recovery = + evaluator + .evaluate( + connectionState = connectedState(), + lifecycleState = StreamLifecycleState.Foreground, + networkState = StreamNetworkState.Unavailable, + ) + .getOrThrow() + + assertIs>(recovery) + } + @Test fun `stays idle when returning foreground while already reconnecting`() = runTest { val evaluator = evaluator()