Skip to content

Conversation

@aleksandar-apostolov
Copy link
Collaborator

@aleksandar-apostolov aleksandar-apostolov commented Oct 16, 2025

Goal

AND791
Introduce a network monitor into core, as a pre-requisite for implementing connection recovery.

Implementation

Network Monitor

StreamNetworkMonitor interface. An network monitor supplied externally to the StreamClient. Internal implementation in StreamNetworkMonitorImpl

Exposed networkState via the client and onNetworkState in the client listener.

Components provider

In order to avoid depending on Context directly and be able to inject dependencies we are providing a StreamAndroidComponentsProvider which gives us the likes of ConnectivityManager etc..

Other

HealthMonitor changed return type to be Result<*>

Added Algebra.kt where operations are written e.g. Exception + Exception will give a combined exception.

Testing

Checklist

  • Issue linked (if any)
  • Tests/docs updated
  • I have signed the Stream CLA (required for external contributors)

@github-actions
Copy link
Contributor

github-actions bot commented Oct 16, 2025

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled.

🎉 Great job! This PR is ready for review.

@aleksandar-apostolov aleksandar-apostolov changed the title Introduce a network monitor into core [AND-791] Introduce a network monitor into core Oct 16, 2025
@aleksandar-apostolov aleksandar-apostolov changed the title [AND-791] Introduce a network monitor into core Introduce a network monitor into core Oct 16, 2025
@aleksandar-apostolov aleksandar-apostolov marked this pull request as ready for review October 22, 2025 08:48
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a network monitor into the core module as a prerequisite for connection recovery. The implementation provides real-time network connectivity information including transport types, signal strength, bandwidth estimates, and connection properties.

Key changes:

  • Adds StreamNetworkMonitor interface with internal implementation that observes Android's ConnectivityManager
  • Exposes networkInfo via StreamClient as an internal API
  • Introduces StreamAndroidComponentsProvider for dependency injection of Android system services

Reviewed Changes

Copilot reviewed 39 out of 39 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
StreamSocketSessionTest.kt Updated mock for health monitor to return Result instead of Unit
Multiple test files (StreamNetwork*.kt) Added comprehensive test coverage for network monitoring components
AlgebraTest.kt Tests for new exception and Result combination operators
StreamHealthMonitorImpl.kt Changed return types from Unit to Result
StreamNetworkSnapshotBuilder.kt Builds network capability snapshots from Android system data
StreamNetworkSignalProcessing.kt Processes WiFi and cellular signal strength information
StreamNetworkMonitorUtils.kt Utility functions for safe capability checks
StreamNetworkMonitorImpl.kt Core implementation of network monitoring
StreamNetworkMonitorCallback.kt Handles ConnectivityManager callbacks
StreamAndroidComponentsProviderImpl.kt Implementation for accessing Android system services
StreamClientImpl.kt Integrates network monitor into client lifecycle
Algebra.kt Defines operators for combining exceptions and Results
StreamHealthMonitor.kt Updated interface with Result return types
StreamNetworkMonitorListener.kt Listener interface for network state changes
StreamNetworkMonitor.kt Public API and factory function for network monitor
StreamNetworkInfo.kt Data models for network state snapshots
StreamAndroidComponentsProvider.kt Interface for accessing Android system services
StreamClient.kt Added networkInfo property and networkMonitor parameter
AndroidManifest.xml Added required network permissions
build.gradle.kts Added androidx.annotation dependency
libs.versions.toml Added annotation-jvm library version
Sample app files UI components and integration for displaying network info

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 42 out of 42 changed files in this pull request and generated 2 comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link
Collaborator

@gpunto gpunto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, I left just a few nitpicks

*
* @param snapshot A [StreamNetworkInfo.Snapshot] describing the newly connected network.
*/
public suspend fun onNetworkConnected(snapshot: StreamNetworkInfo.Snapshot?) {}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make the parameter non-nullable? The only usage I see is after a null check.

With that we can also make the snapshot in StremNetworkState.Available non-nullable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Snapshot is not available pre API 24 and our min is API 21, its either this, or having a separate callback without the snapshot for lower APIs.

Do you have any other suggestion?

Comment on lines +128 to +169
object : StreamNetworkMonitorListener {
override suspend fun onNetworkConnected(
snapshot: StreamNetworkInfo.Snapshot?
) {
logger.v {
"[connect] Network connected: $snapshot"
}
val state = StreamNetworkState.Available(snapshot)
mutableNetworkState.update(state)
subscriptionManager.forEach {
it.onNetworkState(state)
}
}

override suspend fun onNetworkLost(permanent: Boolean) {
logger.v { "[connect] Network lost" }
val state =
if (permanent) {
StreamNetworkState.Unavailable
} else {
StreamNetworkState.Disconnected
}
mutableNetworkState.update(state)
subscriptionManager.forEach {
it.onNetworkState(state)
}
}

override suspend fun onNetworkPropertiesChanged(
snapshot: StreamNetworkInfo.Snapshot
) {
logger.v { "[connect] Network changed: $snapshot" }
mutableNetworkState.update(
StreamNetworkState.Available(snapshot)
)
subscriptionManager.forEach {
it.onNetworkState(
StreamNetworkState.Available(snapshot)
)
}
}
},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd extract this to a function that creates the listener, just for clarity

…ternal/observers/network/StreamNetworkMonitorCallback.kt

Co-authored-by: Gianmarco <[email protected]>
@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:new-feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants