Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c3df770
Build on sdk 37
rahul-lohra Jul 27, 2026
5f51cf4
ci: Use java 21 on CI
rahul-lohra Aug 5, 2026
f1c07ca
ci: point to android ci action with compile sdk 37 support
rahul-lohra Aug 5, 2026
48daee0
build: Migrate to AGP 9.1.1 / Gradle 9.3.1 and compileSdk/targetSdk 37
rahul-lohra Aug 5, 2026
b898334
Merge branch 'develop' into feature/rahullohra/build-on-sdk-37
rahul-lohra Aug 5, 2026
574a73a
1. record paparazzi goldens on ci
rahul-lohra Aug 5, 2026
e7dcdb9
minor fix in sample app versioner
rahul-lohra Aug 5, 2026
c3ac3a0
[record-paparazzi]
rahul-lohra Aug 5, 2026
7ecf8e1
use java 21
rahul-lohra Aug 5, 2026
db85ab4
[record-paparazzi]
rahul-lohra Aug 5, 2026
17f789f
fix baselineProfileOutputDir
rahul-lohra Aug 5, 2026
dc80a1e
Fix AGP 9 ART-profile parse and androidx.collection (IntFloatMap) re…
rahul-lohra Aug 5, 2026
98800e7
[record-paparazzi]
rahul-lohra Aug 5, 2026
256438e
Merge branch 'develop' into feature/rahullohra/build-on-sdk-37
rahul-lohra Aug 5, 2026
7dc54cf
[record-paparazzi]
rahul-lohra Aug 5, 2026
e840248
fix baselineprofile
rahul-lohra Aug 5, 2026
5eb3e60
[record-paparazzi]
rahul-lohra Aug 5, 2026
33ca5df
test: Render Paparazzi at API 36 to dodge alpha05 layoutlib crashes
rahul-lohra Aug 5, 2026
1188433
paparazzi changes
rahul-lohra Aug 5, 2026
8a59e91
fix for running unit-test
rahul-lohra Aug 5, 2026
a747510
build: Add JUnit Platform launcher to core for Gradle 9
rahul-lohra Aug 6, 2026
9e387f2
fix: Fix Paparazi crashes
rahul-lohra Aug 6, 2026
beda413
[record-paparazzi]
rahul-lohra Aug 6, 2026
04d7c97
Paparazzi new goldens
rahul-lohra Aug 6, 2026
8f9b979
Add fixed for Shot library. Align the androidx.test family across eve…
rahul-lohra Aug 6, 2026
609d8bf
Revert changes
rahul-lohra Aug 10, 2026
c1c6484
Revert force resolutionStrategy for androidx.text
rahul-lohra Aug 10, 2026
6077dad
Delete robolectric.properties
rahul-lohra Aug 10, 2026
dc92d1c
Remove enterprise gradle
rahul-lohra Aug 10, 2026
9b5ee63
Revert "Delete robolectric.properties"
rahul-lohra Aug 10, 2026
0ec3602
Keep robolectric.properties
rahul-lohra Aug 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .github/workflows/apk-s3-distribute.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
- uses: GetStream/android-ci-actions/actions/setup-java@cb46e4f44d105a68738bfd2a1cfd156bb768665b
with:
java-version: '21'
- name: Prepare environment
env:
PASSPHRASE: ${{ secrets.PASSPHRASE }}
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/app-distribute-v7.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
- uses: GetStream/android-ci-actions/actions/setup-java@cb46e4f44d105a68738bfd2a1cfd156bb768665b
with:
java-version: '21'
- name: Prepare environment
env:
PASSPHRASE: ${{ secrets.PASSPHRASE }}
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/app-distribute.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
- uses: GetStream/android-ci-actions/actions/setup-java@cb46e4f44d105a68738bfd2a1cfd156bb768665b
with:
java-version: '21'
- name: Prepare environment
env:
PASSPHRASE: ${{ secrets.PASSPHRASE }}
Expand Down Expand Up @@ -50,6 +52,8 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
- uses: GetStream/android-ci-actions/actions/setup-java@cb46e4f44d105a68738bfd2a1cfd156bb768665b
with:
java-version: '21'
- name: Prepare environment
env:
PASSPHRASE: ${{ secrets.PASSPHRASE }}
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/attach-release-apk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ jobs:
fetch-depth: 0
persist-credentials: false
- uses: GetStream/android-ci-actions/actions/setup-java@main
with:
java-version: '21'
- name: Prepare signing environment
env:
RELEASE_KEYSTORE: ${{ secrets.RELEASE_KEYSTORE }}
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:
- name: Check out code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
- uses: GetStream/android-ci-actions/actions/setup-java@cb46e4f44d105a68738bfd2a1cfd156bb768665b
with:
java-version: '21'
- name: Build
run: ./gradlew assembleDebug
release_build:
Expand All @@ -33,6 +35,8 @@ jobs:
- name: Check out code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
- uses: GetStream/android-ci-actions/actions/setup-java@cb46e4f44d105a68738bfd2a1cfd156bb768665b
with:
java-version: '21'
- name: Build
run: ./gradlew assembleRelease
tests:
Expand All @@ -47,6 +51,8 @@ jobs:
with:
fetch-depth: 0 # fetch all history for sonar analysis
- uses: GetStream/android-ci-actions/actions/setup-java@cb46e4f44d105a68738bfd2a1cfd156bb768665b
with:
java-version: '21'
- name: Unit tests
run: ./gradlew :testCoverage
- name: Upload test results
Expand All @@ -70,6 +76,8 @@ jobs:
- name: Check out code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
- uses: GetStream/android-ci-actions/actions/setup-java@cb46e4f44d105a68738bfd2a1cfd156bb768665b
with:
java-version: '21'
- name: build demo debug
run: ./gradlew stream-chat-android-ui-components-sample:assembleDemoDebug
- name: Upload artifact to Emerge
Expand All @@ -88,6 +96,8 @@ jobs:
- name: Check out code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
- uses: GetStream/android-ci-actions/actions/setup-java@cb46e4f44d105a68738bfd2a1cfd156bb768665b
with:
java-version: '21'
- name: build debug
run: ./gradlew stream-chat-android-compose-sample:assembleDebug
- name: Upload artifact to Emerge
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/check-entities.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:
with:
fetch-depth: 0
- uses: GetStream/android-ci-actions/actions/setup-java@main
with:
java-version: '21'
- name: Find touched DB Entities
id: touchedEntities
continue-on-error: true
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/clean-detekt-baseline.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ jobs:
with:
token: ${{ secrets.STREAM_PUBLIC_BOT_TOKEN }}
- uses: GetStream/android-ci-actions/actions/setup-java@cb46e4f44d105a68738bfd2a1cfd156bb768665b
with:
java-version: '21'
- uses: tibdex/github-app-token@v2.1.0
id: generate-token
with:
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 @@ -23,6 +23,8 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
- uses: GetStream/android-ci-actions/actions/setup-java@cb46e4f44d105a68738bfd2a1cfd156bb768665b
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-backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
- uses: GetStream/android-ci-actions/actions/setup-java@cb46e4f44d105a68738bfd2a1cfd156bb768665b
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/e2e-test-cron.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@cb46e4f44d105a68738bfd2a1cfd156bb768665b
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 @@ -88,6 +88,8 @@ jobs:
with:
name: apks
- uses: GetStream/android-ci-actions/actions/setup-java@cb46e4f44d105a68738bfd2a1cfd156bb768665b
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
4 changes: 2 additions & 2 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
permissions:
contents: read
pull-requests: read
uses: GetStream/stream-build-conventions-android/.github/workflows/android-ci.yml@8c5fbade4ee9c06a0a979bcb0866e64669254f73
uses: GetStream/stream-build-conventions-android/.github/workflows/android-ci.yml@feature/rahullohra/build-on-sdk-37

Check failure on line 16 in .github/workflows/pr-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-chat-android&issues=AZ_WN4TpM7QpearMwu3r&open=AZ_WN4TpM7QpearMwu3r&pullRequest=6590
secrets:
BUILD_CACHE_AWS_REGION: ${{ secrets.BUILD_CACHE_AWS_REGION }}
BUILD_CACHE_AWS_BUCKET: ${{ secrets.BUILD_CACHE_AWS_BUCKET }}
Expand All @@ -28,7 +28,7 @@
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
- uses: GetStream/stream-build-conventions-android/.github/actions/setup-gradle@v0.13.1
- uses: GetStream/stream-build-conventions-android/.github/actions/setup-gradle@feature/rahullohra/build-on-sdk-37
- name: Detekt
run: ./gradlew detekt
rubocop:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ concurrency:

jobs:
pr-checklist:
uses: GetStream/stream-build-conventions-android/.github/workflows/pr-quality.yml@v0.13.1
uses: GetStream/stream-build-conventions-android/.github/workflows/pr-quality.yml@feature/rahullohra/build-on-sdk-37
secrets: inherit
55 changes: 55 additions & 0 deletions .github/workflows/record-paparazzi.yml

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can't we regenerate them locally like today? I checked on my machine and:

  • When recording: some snapshots change, but the image diff shows 0 or close to 0 pixel changes
  • When running validation: the check passes

I'd avoid having to rely on CI for regenerating snapshots if possible, as it will slow us down compared to today.

Also one less workflow + script to maintain.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Can't we regenerate them locally like today?

Yes — and your measurements match what I'd expect: Paparazzi's cross-platform rendering diff is currently tiny, so locally-recorded goldens pass. Local recording is fine as the default.

The one caveat: Paparazzi renders via a native layoutlib, and native text/anti-aliasing can differ slightly by OS + CPU arch (macOS/arm64 vs the Ubuntu/x86_64 CI). Today that difference is ~0, but a complex snapshot — or a future toolchain bump — could push a diff above maxPercentDifference, and then CI verify (which runs on Ubuntu) would fail against Mac-recorded goldens. If that ever happens, the fix is to bump the tolerance or re-record on the same OS as CI

Separately: I need to re-record the goldens now regardless, because the newer layoutlib changed its color output — so this re-record has to happen either way.

I'm happy to drop the record-paparazzi workflow + pull script once the PR is approved (one less thing to maintain). We can always re-add CI recording if a cross-platform diff ever exceeds tolerance.

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 which verifies —
# 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:
- "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-chat-android&issues=AZ_WN4RYM7QpearMwu3q&open=AZ_WN4RYM7QpearMwu3q&pullRequest=6590
- 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 @@ concurrency:

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@feature/rahullohra/build-on-sdk-37
with:
modules: "stream-chat-android-client stream-chat-android-ui-components stream-chat-android-compose"
metrics-project: "stream-chat-android-metrics"
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/snapshot-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ jobs:
- name: Check out code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
- uses: GetStream/android-ci-actions/actions/setup-java@cb46e4f44d105a68738bfd2a1cfd156bb768665b
with:
java-version: '21'
- uses: GetStream/android-ci-actions/actions/setup-ruby@main
- uses: GetStream/android-ci-actions/actions/gradle-cache@main
with:
Expand Down
1 change: 0 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ plugins {
alias(libs.plugins.detekt) apply false
alias(libs.plugins.shot) apply false
alias(libs.plugins.androidx.navigation) apply false
alias(libs.plugins.gitversioner)
alias(libs.plugins.gradle.versions)
alias(libs.plugins.binary.compatibility.validator)
}
Expand Down
13 changes: 12 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,18 @@ org.gradle.parallel=true
org.gradle.caching=true
# Disabled R8 full mode
android.enableR8.fullMode=true
android.suppressUnsupportedCompileSdk=34
android.suppressUnsupportedCompileSdk=37
# AGP 9 ships built-in Kotlin and registers its own `kotlin` extension. Opt out so the
# standalone `org.jetbrains.kotlin.android` plugin (applied across modules) keeps working.
# Transitional: AGP 10 removes this escape hatch — migrate to built-in Kotlin before then.
android.builtInKotlin=false
# AGP 9 removed the legacy DSL implementations; the standalone KGP still casts the module
# extension to the removed `BaseExtension` (fails on com.android.test / TestExtension). Restore
# the old DSL so KGP works. Also transitional — removed in AGP 10.
android.newDsl=false

# Project version
version=7.7.0

# Enabled parallel sync for Gradle 9.4+
org.gradle.tooling.parallel=true
27 changes: 15 additions & 12 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
[versions]
compileSdk = "35"
targetSdk = "34"
sampleTargetSdk = "35"
compileSdk = "37"
targetSdk = "37"
sampleTargetSdk = "37"
Comment on lines +3 to +4

@coderabbitai coderabbitai Bot Aug 6, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)gradle/(libs\.versions\.toml|.*convention.*|plugins/|build.gradle|settings.gradle)$' || true

echo "== libs.versions top =="
if [ -f gradle/libs.versions.toml ]; then
  sed -n '1,80p' gradle/libs.versions.toml | cat -n
fi

echo "== targetSdk usages =="
rg -n 'targetSdk|sampleTargetSdk|android {|namespace|sdkVersion' -S . --glob '!build/**' --glob '!gradle/wrapper/**' || true

echo "== git diff stat/name/status =="
git diff --stat || true
git diff -- gradle/libs.versions.toml | sed -n '1,160p' || true

Repository: GetStream/stream-chat-android

Length of output: 1944


🌐 Web query:

Google Developer Android 17 API 37 large screen resize orientation activity recreation targetSdk behavior

💡 Result:

For apps targeting Android 17 (API level 37) or higher, significant changes to orientation, resizability, and activity recreation behavior take effect, particularly on large screen devices (smallest width >= 600dp) [1][2][3]. Key behavioral changes and targetSdk requirements for API 37: 1. Mandatory Adaptive Behavior: On large screens (sw >= 600dp), apps targeting API 37 or higher can no longer restrict orientation, resizability, or aspect ratio [1][2][3]. Restrictions such as android:screenOrientation, android:resizableActivity, and fixed aspect ratio attributes are ignored [1]. The system no longer uses pillarboxing for these apps; they are required to fill the available display window [1]. 2. Activity Recreation and Configuration Changes: Because these apps must adapt to frequent changes in window size, orientation, and aspect ratio, the system will, by default, trigger an Activity recreation during these events [2][4]. To maintain user state and avoid data loss, developers are strongly encouraged to implement robust state preservation (e.g., ViewModel, savedInstanceState) [2][4]. 3. Opt-in for Handling Changes: If you prefer to handle these configuration changes yourself rather than letting the system recreate the activity, you must update your manifest to include the relevant configuration changes [5][4]. Specifically, adding android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" to your activity declaration will prevent the activity from restarting during these transitions [5][4]. In this case, the activity will instead receive a callback to onConfigurationChanged [5]. 4. New Default for Specific Configuration Changes: Note that starting in API 37, the system no longer restarts activities by default for several configuration changes that typically do not require full UI recreation, such as keyboard, navigation, and touch screen updates [5]. In summary, targeting API 37 mandates that your app be fully adaptive on large screens, removing previously available opt-outs for fixed orientations or aspect ratios [1][3]. Developers should focus on state preservation or explicit configuration handling to ensure a smooth user experience during the frequent resizing and rotation common in modern large-screen and multi-window environments [2][4].

Citations:


🌐 Web query:

Google Developer Android 17 SDK 37 behavior changes targetSdk compatibility

💡 Result:

Android 17 (API level 37) was released in June 2026 [1][2]. Apps targeting this version are subject to several significant behavior changes aimed at improving performance, security, and consistent UI behavior across device form factors [3][4][5]. Key behavior changes for apps targeting Android 17 (SDK 37) include: Large Screen Constraints: Apps can no longer opt out of orientation, resizability, or aspect ratio constraints on large screens (sw >= 600dp) [4][6][5]. Legacy manifest attributes (e.g., screenOrientation, resizeableActivity) and runtime APIs (e.g., setRequestedOrientation) are ignored, though games are exempt [6][5]. MessageQueue Performance: Android 17 introduces a lock-free implementation of android.os.MessageQueue [3][5]. This may break applications that use reflection to access private fields or methods within MessageQueue [3][5]. Static Field Restrictions: Apps targeting API 37 cannot modify static final fields using reflection [3]. Attempts to do so via reflection will result in an IllegalAccessException, and using JNI APIs (such as SetStaticLongField) will cause the application to crash [3]. Dynamic Code Loading (DCL): Safer DCL protections are extended to native libraries [5]. All native files loaded via System.load must be marked as read-only, or the system will throw an UnsatisfiedLinkError [5]. SMS OTP Protection: The system extends SMS OTP protection to standard SMS messages (those not using WebOTP or SMS Retriever formats) [3]. These messages are withheld from the SMS provider database and the SMS_RECEIVED_ACTION broadcast for three hours after receipt to prevent OTP hijacking [3]. Bluetooth and Keystore Limits: BluetoothSocket RFCOMM implementations now align with standard Java InputStream behavior [4]. Additionally, the system enforces a limit of 50,000 keys per app in the Android Keystore for non-system apps targeting API 37 [7]. For compatibility, developers should use the Android 17 SDK [8]. Google Play requirements mandate that new apps and updates must target at least Android 16 (API 36) by August 31, 2026 [9][10]. While migrating to API 37 is not yet a Play Store requirement as of August 2026, it is recommended for leveraging new features like the standardized Android Contact Picker [11]. Developers are encouraged to use the Android SDK Upgrade Assistant in Android Studio for assistance with these transitions [8].

Citations:


Cover Android 17 behavior changes before merging the SDK bump.

targetSdk = "37" makes apps expose Android 17 runtime changes on API 37, including large-screen resize/orientation handling, manifest restrictions being ignored, activity recreation for size changes, and changes to SMS, DCL, reflection, and socket behavior. Existing smoke testing is not enough. Add API 37 device or emulator coverage for affected flows.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gradle/libs.versions.toml` around lines 3 - 4, Before retaining the targetSdk
and sampleTargetSdk values at 37, add device or emulator coverage for Android
17/API 37 affected flows, including large-screen resizing and orientation,
activity recreation, manifest restrictions, SMS, DCL, reflection, and socket
behavior. Ensure the tests exercise these runtime changes rather than relying
only on existing smoke tests.

Sources: Coding guidelines, MCP tools

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I assume there were no behavioural changes caused by the targetSdk bump? - Should we maybe do thorough manual testing before releasing this?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== Android manifest files =='
fd -t f 'AndroidManifest\.xml$' . -x sh -c 'echo "--- $1"; rg -n -i -C2 "screenOrientation|resizableActivity|maxAspectRatio|minAspectRatio|configChanges|uses-permission.*(SMS|RECEIVE)|receiver|activity" "$1" || true' sh {}

echo '== API 37 / emulator / managed-device configuration =='
rg -n -i -C3 'api.?37|sdk.?37|system.?image|managedDevices|device\s*=|avd|emulator|connectedAndroidTest' \
  .github gradle . \
  -g '*.yml' -g '*.yaml' -g '*.gradle' -g '*.gradle.kts' -g '*.properties' -g '*.toml' \
  --glob '!build/**' || true

echo '== Compatibility-sensitive production code references =='
rg -n -i -C2 'setRequestedOrientation|requestedOrientation|onConfigurationChanged|MessageQueue|System\.load(?:Library)?\s*\(|DexClassLoader|PathClassLoader|Class\.forName|java\.lang\.reflect|BluetoothSocket|SmsManager|SMS_RECEIVED|Telephony\.Sms' \
  . --glob '!**/src/test/**' --glob '!**/src/androidTest/**' --glob '!build/**' || true

echo '== Relevant test references =='
rg -n -i -C2 'ActivityScenario|recreate\s*\(|onConfigurationChanged|setRequestedOrientation|resize|multi.window|foldable|BluetoothSocket|SmsManager|DexClassLoader|System\.load|reflect' \
  . --glob '**/src/test/**' --glob '**/src/androidTest/**' --glob '!build/**' || true

Length of output: 126039


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C3 'ANDROID_API_LEVEL|api-level:' .github/workflows \
  -g 'e2e-test*.yml' -g 'e2e-test*.yaml' -g '*.yml' -g '*.yaml' || true

Length of output: 4958


@VelikovPetar, confirmed: the visible CI configuration does not run on Android 17/API 37.

Current emulator coverage is:

  • E2E default: API 36.
  • Backend E2E: API 34.
  • Scheduled E2E: API 28.
  • Snapshot tests: API 27.

The remaining recommendation is focused manual testing before release. Test the two sample applications on an Android 17/API 37 tablet or foldable emulator. Verify rotation, split-screen resizing, activity recreation, and the main chat and composer flows. This is relevant because both sample manifests set android:screenOrientation="portrait", which Android 17 can ignore on large screens.

You are interacting with an AI system.

minSdk = "21"
allureKotlin = "2.4.0"
androidGradlePlugin = "8.10.1"
androidGradlePlugin = "9.1.1"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I understand that this is necessary - but could this be a potential breaking change - breaking customer builds?

androidJunit5GradlePlugin = "1.11.2.0"
androidLegacySupport = "1.0.0"
androidxActivityCompose = "1.9.3"
androidxActivityKtx = "1.9.3"
androidxAnnotations = "1.9.1"
androidxAppcompat = "1.7.0"
androidxCollection = "1.5.0"
androidxComposeBom = "2025.08.01"
androidxComposeConstraintLayout = "1.1.0"
androidxCoreSplashScreen = "1.2.0"
Expand All @@ -24,13 +25,13 @@ androidxNavigation = "2.8.4"
androidxPreferences = "1.2.1"
androidxRecyclerview = "1.3.2"
androidxStartup = "1.2.0"
androidxTestCore = "1.5.0"
androidxTestJunit = "1.1.5"
androidxTestCore = "1.6.1"
androidxTestJunit = "1.2.1"
androidxTestMonitor = "1.7.2"
androidxTestOrchestrator = "1.5.1"
androidxUiAutomator = "2.4.0-alpha05"
androidxViewPager2 = "1.1.0"
androidxTest = "1.5.2"
androidxTest = "1.6.2"
baseProfile = "1.3.1"
coil = "3.1.0"
composeAccompanist = "0.36.0"
Expand All @@ -44,30 +45,30 @@ firebaseAnalytics = "22.1.2"
firebaseCrashlytics = "19.2.1"
firebaseCrashlyticsPlugin = "3.0.2"
firebaseMessaging = "24.1.0"
gitversioner = "0.5.0"
googleServices = "4.4.2"
gradleVersionsPlugin = "0.51.0"
huaweiPush = "6.11.0.300"
ituDateVersion = "1.10.2"
json = "20240303"
junit4 = "4.13.2"
junit5 = "5.11.3"
junitPlatformLauncher = "1.11.3"
keyboardVisibilityEvent = "2.3.0"
kluent = "1.73"
kotest = "5.9.1"
kotlin = "2.2.0"
kotlinBinaryValidator = "0.16.3"
ksp = "2.2.0-2.0.2"
leakCanary = "2.4"
macroBenchmark = "1.2.3"
macroBenchmark = "1.5.0-alpha07"
markwon = "4.6.2"
materialComponents = "1.12.0"
mockitoKotlin = "5.4.0"
mockito = "5.14.2"
moshi = "1.15.1"
ok2curl = "0.8.0"
okhttp = "4.12.0"
paparazzi = "1.3.5"
paparazzi = "2.0.0-alpha05"
permissionx = "1.8.1"
photoview = "1.0.2"
reorderable = "2.4.0"
Expand All @@ -77,7 +78,7 @@ room = "2.7.2"
shimmer = "0.5.0"
shimmerCompose = "1.3.1"
shot = "6.1.0"
streamConventions = "0.13.1"
streamConventions = "0.13.2-SNAPSHOT"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Snapshots are pruned after some time, so this commit will start failing once that happens.

I'd publish a stable conventions version. We can use a version suffix if we want to keep the version separated from the regular ones for now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Correct.

The reason I’m still using a snapshot is that I’m finalizing the changes needed for the Android 37 build support, and I won’t know the final stream-conventions requirements until both the Video and Chat PRs are approved.

My plan is:

Step 1 — Get the build-support PRs approved

  1. Chat: build support for Android 37
  2. Video: build support for Android 37

Step 2 — Roll out stream-conventions
Once both PRs are finalized, I’ll make the required changes to stream-conventions and publish a stable conventions version.

Step 3 — Switch to the stable version
Update the Chat and Video Android 37 PRs to use the stable stream-conventions version instead of the snapshot.

This way, we avoid publishing a stable version prematurely while the required conventions are still changing.

Does it sound good to you? I am happy to change anything you suggest

streamLog = "1.3.2"
streamPush = "1.3.1"
streamResult = "1.3.2"
Expand All @@ -98,6 +99,7 @@ androidx-activity-compose = { module = "androidx.activity:activity-compose", ver
androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "androidxActivityKtx"}
androidx-annotation = { module = "androidx.annotation:annotation", version.ref = "androidxAnnotations"}
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidxAppcompat"}
androidx-collection = { module = "androidx.collection:collection", version.ref = "androidxCollection"}
androidx-benchmark-macro-junit4 = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "macroBenchmark"}
androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "androidxComposeBom"}
androidx-compose-constraintlayout-compose = { module = "androidx.constraintlayout:constraintlayout-compose", version.ref = "androidxComposeConstraintLayout"}
Expand All @@ -118,6 +120,7 @@ androidx-core-testing = { module = "androidx.arch.core:core-testing", version.re
androidx-exifinterface = { module = "androidx.exifinterface:exifinterface", version.ref = "androidxExifInterface"}
androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "androidxFragment"}
androidx-fragment-testing = { module = "androidx.fragment:fragment-testing", version.ref = "androidxFragment"}
androidx-fragment-testing-manifest = { module = "androidx.fragment:fragment-testing-manifest", version.ref = "androidxFragment"}
androidx-legacy-support = { module = "androidx.legacy:legacy-support-v4", version.ref = "androidLegacySupport"}
androidx-lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "androidxLifecycle"}
androidx-lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "androidxLifecycle"}
Expand Down Expand Up @@ -174,6 +177,7 @@ junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.re
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit5"}
junit-vintage-engine = { module = "org.junit.vintage:junit-vintage-engine", version.ref = "junit5"}
junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit5"}
junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junitPlatformLauncher"}
keyboardvisibilityevent = { module = "net.yslibrary.keyboardvisibilityevent:keyboardvisibilityevent", version.ref = "keyboardVisibilityEvent"}
kluent = { module = "org.amshove.kluent:kluent", version.ref = "kluent"}
kotest-assertions-json = { module = "io.kotest:kotest-assertions-json", version.ref = "kotest" }
Expand Down Expand Up @@ -232,7 +236,6 @@ androidx-navigation = { id = "androidx.navigation.safeargs.kotlin", version.ref
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "kotlinBinaryValidator"}
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detektPlugin"}
firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebaseCrashlyticsPlugin"}
gitversioner = { id = "com.pascalwelsch.gitversioner", version.ref = "gitversioner"}
google-services = { id = "com.google.gms.google-services", version.ref = "googleServices"}
gradle-versions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersionsPlugin"}
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin"}
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It seems Gradle 9 silently disables our Gradle Enterprise plugin. The build on this branch prints:

Gradle Enterprise plugin 3.7 has been disabled as it is incompatible with this version of Gradle.
Upgrade to Gradle Enterprise plugin 3.13.1 or newer to restore functionality.

We should likely bump it (I think it's called Develocity now).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

After mutual discussion, we are removing gradle enterprise for now. We will revisit it later when needed

networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
Loading
Loading