Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
a8c599e
Add new network monitor and network sample UI in core
aleksandar-apostolov Oct 16, 2025
6cee404
Spotless
aleksandar-apostolov Oct 16, 2025
078cb67
Update test
aleksandar-apostolov Oct 16, 2025
edac873
Missing permission check
aleksandar-apostolov Oct 16, 2025
b25c1a3
Missing permission check
aleksandar-apostolov Oct 16, 2025
4b54265
Add tests for the stream network monitor utils and processing
aleksandar-apostolov Oct 16, 2025
bf78bb9
Move network monitor initialization after connection is established, …
aleksandar-apostolov Oct 16, 2025
c010b50
Stop network monitor on Disconnect
aleksandar-apostolov Oct 16, 2025
e945bfa
Refactor the callback into separate delegate and add tests
aleksandar-apostolov Oct 22, 2025
fce3cfa
Fix lint errors and run spotless
aleksandar-apostolov Oct 22, 2025
3ff9bb1
Refactor snapshot builder and add tests
aleksandar-apostolov Oct 22, 2025
dd99226
Refactor signal processing and add tests
aleksandar-apostolov Oct 22, 2025
c9f8003
Add more tests
aleksandar-apostolov Oct 22, 2025
d1188f6
Spotless
aleksandar-apostolov Oct 22, 2025
b91fcdc
Fix algebra
aleksandar-apostolov Oct 22, 2025
77f24ef
Update wrapper is now more generic
aleksandar-apostolov Oct 22, 2025
693328e
Spotless
aleksandar-apostolov Oct 22, 2025
e0e234c
Change state update mechanism
aleksandar-apostolov Oct 22, 2025
c2c3cef
Spotless
aleksandar-apostolov Oct 22, 2025
3b30b03
Update network info UI in sample
aleksandar-apostolov Oct 22, 2025
bace614
Update client test
aleksandar-apostolov Oct 22, 2025
f484eb4
Spotless
aleksandar-apostolov Oct 22, 2025
885d450
Move update helper in a separate class
aleksandar-apostolov Oct 23, 2025
3bed610
Spotless
aleksandar-apostolov Oct 23, 2025
c1e5668
Connection recovery handler and monitors
aleksandar-apostolov Nov 20, 2025
08363ed
Add more tests
aleksandar-apostolov Nov 21, 2025
836e574
Remove onNetworkState method
aleksandar-apostolov Nov 21, 2025
914cf9d
Merge branch 'develop' into connection-recovery-handler
aleksandar-apostolov Nov 21, 2025
5a0b34e
Merged devop and reformatted
aleksandar-apostolov Nov 21, 2025
e550526
Remove the network state
aleksandar-apostolov Nov 21, 2025
3dd800b
Spotless
aleksandar-apostolov Nov 21, 2025
2c86894
add tests
aleksandar-apostolov Nov 21, 2025
90c3538
add tests
aleksandar-apostolov Nov 21, 2025
f0a0e45
Update sonar paths
aleksandar-apostolov Nov 24, 2025
3e0986b
Update coverage parts
aleksandar-apostolov Nov 24, 2025
d176eab
Spotless and koverXmlReport dependency for sonar
aleksandar-apostolov Nov 24, 2025
d4e2a2b
Update stream-android-core/src/main/java/io/getstream/android/core/in…
aleksandar-apostolov Nov 26, 2025
f20e65d
Update stream-android-core/src/main/java/io/getstream/android/core/ap…
aleksandar-apostolov Nov 26, 2025
41cbf28
Update stream-android-core/src/main/java/io/getstream/android/core/in…
aleksandar-apostolov Nov 26, 2025
ac231f8
Remove forEachSuspend as it breaks the async functionality since it u…
aleksandar-apostolov Nov 26, 2025
7334c00
Merge remote-tracking branch 'origin/connection-recovery-handler' int…
aleksandar-apostolov Nov 26, 2025
398e9d1
Update stream-android-core/src/main/java/io/getstream/android/core/in…
aleksandar-apostolov Nov 26, 2025
a0a25d3
Update stream-android-core/src/main/java/io/getstream/android/core/in…
aleksandar-apostolov Nov 26, 2025
faca6d8
Spotless & condition update
aleksandar-apostolov Nov 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
Expand All @@ -40,24 +41,38 @@ import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import io.getstream.android.core.api.StreamClient
import io.getstream.android.core.api.authentication.StreamTokenProvider
import io.getstream.android.core.api.model.connection.network.StreamNetworkState
import io.getstream.android.core.api.model.connection.StreamConnectionState
import io.getstream.android.core.api.model.connection.recovery.Recovery
import io.getstream.android.core.api.model.value.StreamApiKey
import io.getstream.android.core.api.model.value.StreamHttpClientInfoHeader
import io.getstream.android.core.api.model.value.StreamToken
import io.getstream.android.core.api.model.value.StreamUserId
import io.getstream.android.core.api.model.value.StreamWsUrl
import io.getstream.android.core.api.socket.listeners.StreamClientListener
import io.getstream.android.core.api.subscribe.StreamSubscription
import io.getstream.android.core.api.subscribe.StreamSubscriptionManager
import io.getstream.android.core.sample.client.createStreamClient
import io.getstream.android.core.sample.ui.ConnectionStateCard
import io.getstream.android.core.sample.ui.NetworkInfoCard
import io.getstream.android.core.sample.ui.theme.StreamandroidcoreTheme
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

class SampleActivity : ComponentActivity() {
class SampleActivity : ComponentActivity(), StreamClientListener {

val userId = StreamUserId.fromString("petar")
var streamClient: StreamClient? = null

var handle: StreamSubscription? = null

override fun onRecovery(recovery: Recovery) {
super.onRecovery(recovery)
Log.d("SampleActivity", "Recovery: $recovery")
}

override fun onError(err: Throwable) {
super.onError(err)
Log.e("SampleActivity", "Error: $err")
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val streamClient2 =
Expand Down Expand Up @@ -91,7 +106,21 @@ class SampleActivity : ComponentActivity() {
)
streamClient = streamClient2
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) { streamClient?.connect() }
repeatOnLifecycle(Lifecycle.State.CREATED) { streamClient?.connect() }
}

if (handle == null) {
handle =
streamClient2
.subscribe(
this,
options =
StreamSubscriptionManager.Options(
retention =
StreamSubscriptionManager.Options.Retention.KEEP_UNTIL_CANCELLED
),
)
.getOrThrow()
}
enableEdgeToEdge()
setContent {
Expand All @@ -108,16 +137,43 @@ class SampleActivity : ComponentActivity() {
) {
Greeting(name = "Android")
ClientInfo(streamClient = streamClient2)
val state = streamClient?.connectionState?.collectAsStateWithLifecycle()
val buttonState =
when (state?.value) {
is StreamConnectionState.Connected -> {
Triple(
"Disconnect",
true,
{
lifecycleScope.launch { streamClient?.disconnect() }
Unit
},
)
}

is StreamConnectionState.Connecting -> {
Triple("Connecting", false, { Unit })
}

else -> {
Triple(
"Connect",
true,
{
lifecycleScope.launch { streamClient?.connect() }
Unit
},
)
}
}
Button(onClick = buttonState.third, enabled = buttonState.second) {
Text(text = buttonState.first)
}
}
}
}
}
}

override fun onStop() {
runBlocking { streamClient?.disconnect() }
super.onStop()
}
}

@Composable
Expand All @@ -134,18 +190,8 @@ fun GreetingPreview() {
@Composable
fun ClientInfo(streamClient: StreamClient) {
val state = streamClient.connectionState.collectAsStateWithLifecycle()
val networkSnapshot = streamClient.networkState.collectAsStateWithLifecycle()
Log.d("SampleActivity", "Client state: ${state.value}")
val networkState = networkSnapshot.value
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
ConnectionStateCard(state = state.value)
when (networkState) {
is StreamNetworkState.Available -> {
NetworkInfoCard(snapshot = networkState.snapshot)
}
else -> {
NetworkInfoCard(snapshot = null)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ import io.getstream.android.core.api.model.value.StreamApiKey
import io.getstream.android.core.api.model.value.StreamHttpClientInfoHeader
import io.getstream.android.core.api.model.value.StreamUserId
import io.getstream.android.core.api.model.value.StreamWsUrl
import io.getstream.android.core.api.observers.lifecycle.StreamLifecycleMonitor
import io.getstream.android.core.api.observers.network.StreamNetworkMonitor
import io.getstream.android.core.api.processing.StreamBatcher
import io.getstream.android.core.api.processing.StreamRetryProcessor
import io.getstream.android.core.api.processing.StreamSerialProcessingQueue
import io.getstream.android.core.api.processing.StreamSingleFlightProcessor
import io.getstream.android.core.api.recovery.StreamConnectionRecoveryEvaluator
import io.getstream.android.core.api.serialization.StreamEventSerialization
import io.getstream.android.core.api.socket.StreamConnectionIdHolder
import io.getstream.android.core.api.socket.StreamWebSocketFactory
Expand Down Expand Up @@ -109,6 +111,15 @@ fun createStreamClient(
logger = logProvider.taggedLogger("SCNetworkMonitorSubscriptions")
),
)
val lifecycleMonitor =
StreamLifecycleMonitor(
logger = logProvider.taggedLogger("SCLifecycleMonitor"),
subscriptionManager =
StreamSubscriptionManager(
logger = logProvider.taggedLogger("SCLifecycleMonitorSubscriptions")
),
lifecycle = androidComponentsProvider.lifecycle(),
)

return StreamClient(
scope = scope,
Expand Down Expand Up @@ -136,6 +147,12 @@ fun createStreamClient(
override fun deserialize(raw: String): Result<Unit> = Result.success(Unit)
}
),
lifecycleMonitor = lifecycleMonitor,
connectionRecoveryEvaluator =
StreamConnectionRecoveryEvaluator(
logger = logProvider.taggedLogger("SCConnectionRecoveryEvaluator"),
singleFlightProcessor = singleFlight,
),
batcher = batcher,
)
}
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ junitVersion = "1.3.0"
espressoCore = "3.7.0"
appcompat = "1.7.1"
kotlinxCoroutines = "1.10.2"
lifecycleRuntime = "2.9.4"
lintApi = "31.12.0"
material = "1.12.0"
jetbrainsKotlinJvm = "2.2.0"
Expand All @@ -35,6 +36,8 @@ annotationJvm = "1.9.1"
[libraries]
androidx-core = { module = "androidx.test:core", version.ref = "core" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime", version.ref = "lifecycleRuntime" }
androidx-lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "lifecycleRuntime" }
detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
Expand Down
16 changes: 16 additions & 0 deletions gradle/scripts/sonar.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ ext.sonar.ignoreModules.each {
ext.sonar.excludeFilter << "**/${it}/**"
}


def coverageReports = rootProject.subprojects
.findAll { !rootProject.ext.sonar.ignoreModules.contains(it.name) }
.collect { "${it.buildDir}/reports/kover/report.xml" }

if (coverageReports.isEmpty()) {
coverageReports << "${rootProject.buildDir}/reports/kover/report.xml"
}

sonarqube {
properties {
property("sonar.host.url", "https://sonarcloud.io")
Expand All @@ -32,6 +41,13 @@ sonarqube {
property "sonar.java.coveragePlugin", "jacoco"
property "sonar.sourceEncoding", "UTF-8"
property "sonar.java.binaries", "${rootDir}/**/build/tmp/java-classes/debug"
property "sonar.coverage.jacoco.xmlReportPaths", coverageReports.join(",")
property "sonar.coverage.exclusions", rootProject.ext.sonar.excludeFilter
}
}

tasks.named("sonar").configure {
rootProject.subprojects
.findAll { !rootProject.ext.sonar.ignoreModules.contains(it.name) }
.each { dependsOn("${it.path}:koverXmlReport") }
}
2 changes: 2 additions & 0 deletions stream-android-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ dependencies {

// Android
implementation(libs.androidx.annotation.jvm)
implementation(libs.androidx.lifecycle.runtime)
implementation(libs.androidx.lifecycle.process)

// Network
implementation(libs.moshi)
Expand Down
1 change: 1 addition & 0 deletions stream-android-core/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

</manifest>
Loading