Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@

jobs:
base-android-ci:
uses: GetStream/stream-build-conventions-android/.github/workflows/android-ci.yml@v0.13.1
uses: GetStream/stream-build-conventions-android/.github/workflows/android-ci.yml@feature/rahullohra/build-on-sdk-37

Check failure on line 21 in .github/workflows/android.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use full commit SHA hash for this dependency.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-video-android&issues=AZ-4o3QQR2yJSRFwJgL7&open=AZ-4o3QQR2yJSRFwJgL7&pullRequest=1756

Check failure

Code scanning / SonarCloud

External GitHub Actions and workflows should be pinned to a commit hash High

Use full commit SHA hash for this dependency. See more on SonarQube Cloud
secrets: inherit
2 changes: 2 additions & 0 deletions .github/workflows/app-distribute.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ jobs:
steps:
- uses: actions/checkout@v6
- uses: GetStream/android-ci-actions/actions/setup-java@main
with:
java-version: '21'
- name: Prepare environment
run: |
echo "${{ secrets.RELEASE_KEYSTORE }}" > .sign/release.keystore.asc
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/e2e-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ jobs:
steps:
- uses: actions/checkout@v6
- uses: GetStream/android-ci-actions/actions/setup-java@main
with:
java-version: '21'
- uses: GetStream/android-ci-actions/actions/enable-kvm@main
- uses: GetStream/android-ci-actions/actions/setup-ruby@main
- uses: GetStream/android-ci-actions/actions/gradle-cache@main
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/e2e-test-cron.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ jobs:
with:
name: apks
- uses: GetStream/android-ci-actions/actions/setup-java@main
with:
java-version: '21'
- uses: GetStream/android-ci-actions/actions/enable-kvm@main
- uses: GetStream/android-ci-actions/actions/setup-ruby@main
- uses: GetStream/android-ci-actions/actions/allure-launch@main
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ jobs:
with:
name: apks
- uses: GetStream/android-ci-actions/actions/setup-java@main
with:
java-version: '21'
- uses: GetStream/android-ci-actions/actions/enable-kvm@main
- uses: GetStream/android-ci-actions/actions/setup-ruby@main
- name: Run tests
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/internal-app-distribute.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:
steps:
- uses: actions/checkout@v6
- uses: GetStream/android-ci-actions/actions/setup-java@main
with:
java-version: '21'
- name: Prepare environment
run: |
echo "${{ secrets.RELEASE_KEYSTORE }}" > .sign/release.keystore.asc
Expand Down
55 changes: 55 additions & 0 deletions .github/workflows/record-paparazzi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Record Paparazzi Snapshots

# Manually-triggered job that regenerates Paparazzi golden images on the CI runner (Linux/amd64)
# and uploads them as an artifact. Paparazzi renders via native layoutlib, whose pixels depend on
# OS + architecture, so goldens must be produced in the same environment that verifies them —
# the CI runner.
# Download the artifact with scripts/paparazzi-pull-goldens.sh, then commit + push.
# Deliberately does NOT commit back: no write permissions needed, and you review the diff locally.
on:
# Manual trigger — only works once this file is on the default branch (kept for later).
workflow_dispatch:
# Branch trigger — works from a feature branch without default-branch access. The heavy job is
# gated by a commit-message marker (see the job's `if:`) so ordinary pushes don't run it.
# To trigger: git commit --allow-empty -m "record goldens [record-paparazzi]" && git push
push:
branches:
- "v2/feature/rahullohra/**"

concurrency:
group: record-paparazzi-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
record:
name: Record golden images (Linux/amd64)
runs-on: ubuntu-latest # Same runner as the verify job, so recorded pixels match verification.
# Run only on manual dispatch, or on a push whose commit message contains [record-paparazzi].
if: >-
github.event_name == 'workflow_dispatch' ||
contains(github.event.head_commit.message, '[record-paparazzi]')
steps:
- uses: actions/checkout@v7
- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: '21' # Paparazzi 2.0.0-alpha05 requires JDK 21.
distribution: temurin
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

Check failure on line 42 in .github/workflows/record-paparazzi.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use full commit SHA hash for this dependency.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-video-android&issues=AZ-4o3QHR2yJSRFwJgL6&open=AZ-4o3QHR2yJSRFwJgL6&pullRequest=1756

Check failure

Code scanning / SonarCloud

External GitHub Actions and workflows should be pinned to a commit hash High

Use full commit SHA hash for this dependency. See more on SonarQube Cloud
- name: Record Paparazzi goldens
# cleanRecord so stale / differently-named goldens are removed and the artifact is the
# exact set the current tests produce under this Paparazzi/layoutlib version.
run: ./gradlew cleanRecordPaparazziDebug --stacktrace
- name: Upload recorded goldens
uses: actions/upload-artifact@v4
with:
name: paparazzi-goldens
# Paths are preserved relative to the workspace, i.e. <module>/src/test/snapshots/...,
# so the local pull script can overlay them straight onto the repo root.
path: '**/src/test/snapshots/**'
if-no-files-found: error
retention-days: 7
2 changes: 1 addition & 1 deletion .github/workflows/sdk-size-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

jobs:
compare-sdk-sizes:
uses: GetStream/stream-build-conventions-android/.github/workflows/sdk-size-checks.yml@v0.13.1
uses: GetStream/stream-build-conventions-android/.github/workflows/sdk-size-checks.yml.yml@feature/rahullohra/build-on-sdk-37

Check failure on line 16 in .github/workflows/sdk-size-checks.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use full commit SHA hash for this dependency.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-video-android&issues=AZ-4o3L0R2yJSRFwJgL5&open=AZ-4o3L0R2yJSRFwJgL5&pullRequest=1756

Check failure

Code scanning / SonarCloud

External GitHub Actions and workflows should be pinned to a commit hash High

Use full commit SHA hash for this dependency. See more on SonarQube Cloud
with:
modules: "stream-video-android-core stream-video-android-ui-xml stream-video-android-ui-compose"
metrics-project: "stream-video-android-metrics"
Expand Down
10 changes: 4 additions & 6 deletions benchmark/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,10 @@ android {

targetProjectPath = ":demo-app"

testOptions.managedDevices.devices {
maybeCreate<com.android.build.api.dsl.ManagedVirtualDevice>("pixel6api31").apply {
device = "Pixel 6"
apiLevel = 31
systemImageSource = "aosp"
}
testOptions.managedDevices.localDevices.maybeCreate("pixel6api31").apply {
device = "Pixel 6"
apiLevel = 31
systemImageSource = "aosp"
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import com.android.build.gradle.LibraryExtension
import io.getstream.video.configureAndroidCompose
import io.getstream.video.configureKotlinAndroid
import io.getstream.video.kotlinCompilerOptions
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

class AndroidLibraryComposeConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply("io.getstream.android.library")
pluginManager.apply("org.jetbrains.kotlin.plugin.compose")
pluginManager.apply("org.jetbrains.kotlin.android")
pluginManager.apply("binary-compatibility-validator")
pluginManager.apply("androidx.baselineprofile")
Expand All @@ -26,8 +26,10 @@ class AndroidLibraryComposeConventionPlugin : Plugin<Project> {
}
}

kotlinCompilerOptions {
freeCompilerArgs.add("-Xexplicit-api=strict")
tasks.withType<KotlinCompile>().configureEach {
compilerOptions {
freeCompilerArgs.addAll("-Xexplicit-api=strict")
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,28 @@ import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.getByType
import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginExtension
import org.jetbrains.kotlin.compose.compiler.gradle.ComposeFeatureFlag

/**
* Configure Compose-specific options
*/
internal fun Project.configureAndroidCompose(
commonExtension: CommonExtension<*, *, *, *, *, *>,
commonExtension: CommonExtension,
) {
pluginManager.apply("org.jetbrains.kotlin.plugin.compose")
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
pluginManager.apply("org.jetbrains.kotlin.plugin.compose")
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")

commonExtension.apply {
buildFeatures {
compose = true
}
}
commonExtension.buildFeatures.compose = true

dependencies {
val bom = libs.findLibrary("androidx-compose-bom").get()
add("implementation", platform(bom))
add("androidTestImplementation", platform(bom))
}
dependencies {
val bom = libs.findLibrary("androidx-compose-bom").get()
add("implementation", platform(bom))
add("androidTestImplementation", platform(bom))
}

extensions.configure<ComposeCompilerGradlePluginExtension> {
featureFlags.addAll(ComposeFeatureFlag.StrongSkipping, ComposeFeatureFlag.IntrinsicRemember)
reportsDestination = layout.buildDirectory.dir("compose_compiler")
metricsDestination = layout.buildDirectory.dir("compose_compiler_metrics")
stabilityConfigurationFiles.add(
rootProject.layout.projectDirectory.file("compose_compiler_config.conf"),
)
}
extensions.configure<ComposeCompilerGradlePluginExtension> {
reportsDestination = layout.buildDirectory.dir("compose_compiler")
stabilityConfigurationFiles.add(
rootProject.layout.projectDirectory.file("compose_compiler_config.conf"),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.dsl.ApplicationProductFlavor
import com.android.build.api.dsl.CommonExtension
import com.android.build.api.dsl.ProductFlavor
import org.gradle.api.NamedDomainObjectContainer

@Suppress("EnumEntryName")
enum class FlavorDimension {
Expand All @@ -21,28 +22,28 @@ enum class VideoDemoFlavor(val dimension: FlavorDimension, val applicationIdSuff
}

internal fun configureFlavors(
commonExtension: CommonExtension<*, *, *, *, *, *>,
commonExtension: CommonExtension,
) {
commonExtension.apply {
flavorDimensions += "environment"
productFlavors {
VideoDemoFlavor.values().forEach { flavor ->
create(flavor.name) {
dimension = "environment"
buildConfigField(
"String",
"APP_FLAVOR_SUFFIX",
"\"${flavor.applicationIdSuffix.orEmpty()}\"",
)
commonExtension.flavorDimensions += "environment"

if (this@apply is ApplicationExtension && this is ApplicationProductFlavor) {
if (flavor.applicationIdSuffix != null) {
applicationIdSuffix = flavor.applicationIdSuffix
}
}
proguardFiles("benchmark-rules.pro")
@Suppress("UNCHECKED_CAST")
val productFlavors =
commonExtension.productFlavors as NamedDomainObjectContainer<ProductFlavor>
VideoDemoFlavor.values().forEach { flavor ->
productFlavors.create(flavor.name) {
dimension = "environment"
buildConfigField(
"String",
"APP_FLAVOR_SUFFIX",
"\"${flavor.applicationIdSuffix.orEmpty()}\"",
)

if (commonExtension is ApplicationExtension && this is ApplicationProductFlavor) {
if (flavor.applicationIdSuffix != null) {
applicationIdSuffix = flavor.applicationIdSuffix
}
}
proguardFiles("benchmark-rules.pro")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,22 @@ package io.getstream.video
import com.android.build.api.dsl.CommonExtension
import org.gradle.api.Project
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

/**
* Configure base Kotlin with Android options
*/
internal fun Project.configureKotlinAndroid(
commonExtension: CommonExtension<*, *, *, *, *, *>,
commonExtension: CommonExtension,
) {
commonExtension.apply {
lint {
abortOnError = false
}
}
commonExtension.lint.abortOnError = false

val warningsAsErrors = properties["warningsAsErrors"] as? Boolean ?: false

tasks.withType<KotlinCompile>().configureEach {
compilerOptions {
// Treat all Kotlin warnings as errors (disabled by default)
allWarningsAsErrors.set(warningsAsErrors)

freeCompilerArgs.addAll(
"-Xjvm-default=all",
"-opt-in=kotlin.RequiresOptIn",
Expand All @@ -32,9 +28,3 @@ internal fun Project.configureKotlinAndroid(
}
}
}

fun Project.kotlinCompilerOptions(block: KotlinJvmCompilerOptions.() -> Unit) {
tasks.withType<KotlinCompile>().configureEach {
compilerOptions(block)
}
}
16 changes: 7 additions & 9 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,12 @@ subprojects {

afterEvaluate {
println("Running Add Pre Commit Git Hook Script on Build")
exec {
if (System.getProperty("os.name").toLowerCase().contains("win")) {
// Windows-specific command
commandLine("cmd", "/c", "copy", ".\\scripts\\git-hooks\\pre-push", ".\\.git\\hooks")
} else {
// Unix-based systems
commandLine("cp", "./scripts/git-hooks/pre-push", "./.git/hooks")
}
val prePushSource = file("scripts/git-hooks/pre-push")
val gitHooksDir = file(".git/hooks")
if (prePushSource.exists() && gitHooksDir.isDirectory) {
val prePushTarget = File(gitHooksDir, "pre-push")
prePushSource.copyTo(prePushTarget, overwrite = true)
prePushTarget.setExecutable(true)
println("Added pre-push Git Hook Script.")
}
println("Added pre-push Git Hook Script.")
}
13 changes: 12 additions & 1 deletion demo-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ androidComponents {
.forEach {
val key: String = it.key.toString()
.replace(resConfigKeyPrefix, "")
.toLowerCase()
.lowercase()
applicationVariant.resValues?.put(
applicationVariant.makeResValueKey("string", key),
ResValue("${it.value}"),
Expand All @@ -208,6 +208,17 @@ androidComponents {
}
}

// stream-chat (6.10.0) transitively pulls the old stream-log file logger (1.3.1), whose namespace
// `io.getstream.log` collides with stream-log-android's. AGP 9 rejects duplicate namespaces (was a
// warning before). Bumping the catalog `streamLog` only moves the direct stream-log-android; this
// forces the transitive stream-log-file family up to 1.3.4, where it moved to `io.getstream.log.file`.
configurations.configureEach {
resolutionStrategy.eachDependency {
if (requested.group == "io.getstream" && requested.name.startsWith("stream-log")) {
useVersion("1.3.4")
}
}
}
dependencies {
// Stream Video SDK
implementation(project(":stream-video-android-ui-compose"))
Expand Down
12 changes: 11 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,21 @@ android.defaults.buildfeatures.shaders=false
android.nonTransitiveRClass=true

# Disabled R8 full mode
android.suppressUnsupportedCompileSdk=34
android.suppressUnsupportedCompileSdk=37

# AGP 9 ships built-in Kotlin support (auto-registers the `kotlin` extension). This project
# still applies `org.jetbrains.kotlin.android` explicitly via convention plugins, so opt out of
# built-in Kotlin to avoid a duplicate `kotlin` extension. TODO: remove when migrating to
# built-in Kotlin (required before AGP 10). See https://developer.android.com/build/migrate-to-built-in-kotlin
android.builtInKotlin=false
android.newDsl=false

# Build Compose Compiler metrics
enableComposeCompilerMetrics=true
enableComposeCompilerReports=true

# Project version
version=1.23.1

# Enabled parallel sync for Gradle 9.4+
org.gradle.tooling.parallel=true
Loading
Loading