From 2952bea3e29f338d854a30e2572b95e4a6673a3a Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 2 Jul 2026 06:37:37 +0200 Subject: [PATCH 1/3] build: Raise minimum AGP to 9.1.1 for Android 17 toolchain prep Bump the default AGP fallback to 9.2.1, refresh the AGP-compat matrix, and add AGP 9 migration opt-outs until we adopt built-in Kotlin and the new DSL. Includes AGP 9 compatibility fixes for replay and compose modules. Co-authored-by: Cursor --- .github/workflows/agp-matrix.yml | 2 +- AGENTS.md | 6 ++++++ build.gradle.kts | 19 +++++++++++++++++++ buildSrc/src/main/java/Config.kt | 2 +- gradle.properties | 5 ++++- sentry-android-distribution/build.gradle.kts | 5 +++++ sentry-android-replay/build.gradle.kts | 5 +---- .../replay/video/SimpleVideoEncoder.kt | 2 +- sentry-compose/build.gradle.kts | 2 -- 9 files changed, 38 insertions(+), 10 deletions(-) diff --git a/.github/workflows/agp-matrix.yml b/.github/workflows/agp-matrix.yml index d196d595d73..a752153055c 100644 --- a/.github/workflows/agp-matrix.yml +++ b/.github/workflows/agp-matrix.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - agp: [ '8.7.0','8.8.0','8.9.0' ] + agp: [ '9.1.1', '9.2.0', '9.2.1' ] integrations: [ true, false ] name: AGP Matrix Release - AGP ${{ matrix.agp }} - Integrations ${{ matrix.integrations }} diff --git a/AGENTS.md b/AGENTS.md index a05d9386607..a3f56327ae9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,6 +24,12 @@ The project uses **Gradle** with Kotlin DSL. Key build files: - `buildSrc/` and `build-logic/` - Custom build logic and plugins - `Makefile` - High-level build commands +### Android toolchain (AGP 9) +- **Minimum AGP:** 9.1.1 (fallback in `buildSrc/src/main/java/Config.kt`, currently 9.2.1) +- **Minimum Gradle:** 9.4.1 (wrapper in `gradle/wrapper/gradle-wrapper.properties`) +- SDK levels live in `gradle/libs.versions.toml` (`compileSdk`, `targetSdk`, `minSdk`) +- **AGP 9 migration:** `gradle.properties` sets `android.builtInKotlin=false` and `android.newDsl=false` until we remove `kotlin-android` and adopt built-in Kotlin / new DSL (required before AGP 10) + ## Essential Commands ### Development Workflow diff --git a/build.gradle.kts b/build.gradle.kts index 93c82cd8c9a..69c5bd2058b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import com.android.build.gradle.AppExtension +import com.android.build.gradle.LibraryExtension import com.vanniktech.maven.publish.JavaLibrary import com.vanniktech.maven.publish.JavadocJar import com.vanniktech.maven.publish.MavenPublishBaseExtension @@ -117,6 +119,23 @@ allprojects { subprojects { apply { plugin("io.sentry.spotless") } + pluginManager.withPlugin("com.android.library") { + extensions.configure { + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + } + } + pluginManager.withPlugin("com.android.application") { + extensions.configure { + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + } + } + plugins.withId(Config.QualityPlugins.detektPlugin) { configure { buildUponDefaultConfig = true diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index f0e2e9baf86..7575670a38a 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -1,6 +1,6 @@ object Config { - val AGP = System.getenv("VERSION_AGP") ?: "8.13.1" + val AGP = System.getenv("VERSION_AGP") ?: "9.2.1" val kotlinStdLib = "stdlib-jdk8" val kotlinStdLibVersionAndroid = "1.9.24" val kotlinTestJunit = "test-junit" diff --git a/gradle.properties b/gradle.properties index 804e4b58573..bd4ac97c215 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,10 @@ org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled # AndroidX required by AGP >= 3.6.x android.useAndroidX=true -android.experimental.lint.version=8.13.1 +# AGP 9+ migration opt-outs until we remove kotlin-android plugin and adopt built-in Kotlin. +android.builtInKotlin=false +android.newDsl=false +android.experimental.lint.version=9.2.1 # Release information versionName=8.46.0 diff --git a/sentry-android-distribution/build.gradle.kts b/sentry-android-distribution/build.gradle.kts index 2d23bf3ab74..a318cfaffdb 100644 --- a/sentry-android-distribution/build.gradle.kts +++ b/sentry-android-distribution/build.gradle.kts @@ -12,6 +12,11 @@ android { defaultConfig { minSdk = libs.versions.minSdk.get().toInt() } buildFeatures { buildConfig = false } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + testOptions { unitTests.apply { isReturnDefaultValues = true diff --git a/sentry-android-replay/build.gradle.kts b/sentry-android-replay/build.gradle.kts index 8d0f63797aa..e9fc373c0d0 100644 --- a/sentry-android-replay/build.gradle.kts +++ b/sentry-android-replay/build.gradle.kts @@ -25,10 +25,7 @@ android { buildFeatures { compose = true } - composeOptions { - kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get() - useLiveLiterals = false - } + composeOptions { kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get() } buildTypes { getByName("debug") { consumerProguardFiles("proguard-rules.pro") } diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/video/SimpleVideoEncoder.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/video/SimpleVideoEncoder.kt index de14aadaaab..04d573d793f 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/video/SimpleVideoEncoder.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/video/SimpleVideoEncoder.kt @@ -81,7 +81,7 @@ internal class SimpleVideoEncoder( val videoCapabilities = mediaCodec.codecInfo.getCapabilitiesForType(muxerConfig.mimeType).videoCapabilities - if (!videoCapabilities.bitrateRange.contains(bitRate)) { + if (videoCapabilities != null && !videoCapabilities.bitrateRange.contains(bitRate)) { options.logger.log( DEBUG, "Encoder doesn't support the provided bitRate: $bitRate, the value will be clamped to the closest one", diff --git a/sentry-compose/build.gradle.kts b/sentry-compose/build.gradle.kts index c45a431b1b3..52f84ec1381 100644 --- a/sentry-compose/build.gradle.kts +++ b/sentry-compose/build.gradle.kts @@ -87,8 +87,6 @@ android { buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") } - sourceSets["main"].apply { manifest.srcFile("src/androidMain/AndroidManifest.xml") } - buildTypes { getByName("debug") { consumerProguardFiles("proguard-rules.pro") } getByName("release") { consumerProguardFiles("proguard-rules.pro") } From 8dff513120d646ae771e0f5a5a4affed48d8134e Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 2 Jul 2026 06:38:46 +0200 Subject: [PATCH 2/3] build(android): Bump compileSdk and targetSdk to API 37 (Android 17) Officially support Android 17 by raising SDK levels, resolving AGP 9.2 lint findings, pinning Robolectric tests that lag compileSdk 37, and updating Sauce device-farm configs. Co-authored-by: Cursor --- .sauce/sentry-uitest-android-benchmark-lite.yml | 4 ++-- .sauce/sentry-uitest-android-ui.yml | 4 ++-- AGENTS.md | 3 ++- CHANGELOG.md | 4 ++++ gradle/libs.versions.toml | 4 ++-- .../core/internal/util/SentryFrameMetricsCollector.java | 2 +- .../src/main/res/layout/sentry_dialog_user_feedback.xml | 3 +++ .../sentry/android/distribution/UpdateResponseParserTest.kt | 2 ++ .../sentry-uitest-android-benchmark/build.gradle.kts | 2 -- .../sentry-uitest-android/build.gradle.kts | 3 +-- .../java/io/sentry/android/replay/ScreenshotRecorderTest.kt | 2 ++ .../src/test/java/io/sentry/android/replay/util/ViewsTest.kt | 2 ++ 12 files changed, 23 insertions(+), 12 deletions(-) diff --git a/.sauce/sentry-uitest-android-benchmark-lite.yml b/.sauce/sentry-uitest-android-benchmark-lite.yml index fec4a141def..4844f10054e 100644 --- a/.sauce/sentry-uitest-android-benchmark-lite.yml +++ b/.sauce/sentry-uitest-android-benchmark-lite.yml @@ -18,13 +18,13 @@ espresso: suites: - - name: "Android 15 Benchmark lite (api 35)" + - name: "Android 17 Benchmark lite (api 37)" testOptions: clearPackageData: true useTestOrchestrator: true devices: - name: ".*" - platformVersion: "15" + platformVersion: "17" artifacts: download: diff --git a/.sauce/sentry-uitest-android-ui.yml b/.sauce/sentry-uitest-android-ui.yml index a00ee10614b..fbf7a2380f2 100644 --- a/.sauce/sentry-uitest-android-ui.yml +++ b/.sauce/sentry-uitest-android-ui.yml @@ -18,13 +18,13 @@ espresso: testApp: ./sentry-android-integration-tests/sentry-uitest-android/build/outputs/apk/androidTest/release/sentry-uitest-android-release-androidTest.apk suites: - - name: "Android 15 Ui test (api 35)" + - name: "Android 17 Ui test (api 37)" testOptions: clearPackageData: true useTestOrchestrator: true devices: - name: ".*" - platformVersion: "15" + platformVersion: "17" # Controls what artifacts to fetch when the suite on Sauce Cloud has finished. artifacts: diff --git a/AGENTS.md b/AGENTS.md index a3f56327ae9..acf068ef743 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,7 +24,8 @@ The project uses **Gradle** with Kotlin DSL. Key build files: - `buildSrc/` and `build-logic/` - Custom build logic and plugins - `Makefile` - High-level build commands -### Android toolchain (AGP 9) +### Android toolchain (compileSdk 37 / Android 17) +- **Minimum Android Studio:** Panda 3 | 2025.3.3 Patch 1 or newer ([platform requirements](https://developer.android.com/build/releases/about-agp)) - **Minimum AGP:** 9.1.1 (fallback in `buildSrc/src/main/java/Config.kt`, currently 9.2.1) - **Minimum Gradle:** 9.4.1 (wrapper in `gradle/wrapper/gradle-wrapper.properties`) - SDK levels live in `gradle/libs.versions.toml` (`compileSdk`, `targetSdk`, `minSdk`) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73bb2ef396e..92ab02df8cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Features + +- Officially supports Android 17. Updated targetSdk and compileSdk to API 37 + ### Behavioral Changes - `SentryOkHttpInterceptor::intercept` now throws `IOException`. This is a source-only and Java-only breaking change ([#5654](https://github.com/getsentry/sentry-java/pull/5654)) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3984cb7115b..08ee0e9eb65 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -45,8 +45,8 @@ springboot4 = "4.0.0" sqldelight = "2.3.2" # Android -targetSdk = "36" -compileSdk = "36" +targetSdk = "37" +compileSdk = "37" minSdk = "21" [plugins] diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollector.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollector.java index 4f76a51e86f..4f6b486f3a1 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollector.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollector.java @@ -91,7 +91,7 @@ public SentryFrameMetricsCollector( } @SuppressWarnings("deprecation") - @SuppressLint({"NewApi", "PrivateApi"}) + @SuppressLint({"NewApi", "PrivateApi", "DiscouragedPrivateApi"}) public SentryFrameMetricsCollector( final @NotNull Context context, final @NotNull ILogger logger, diff --git a/sentry-android-core/src/main/res/layout/sentry_dialog_user_feedback.xml b/sentry-android-core/src/main/res/layout/sentry_dialog_user_feedback.xml index 722a0d5cf3d..370c37fa0e9 100644 --- a/sentry-android-core/src/main/res/layout/sentry_dialog_user_feedback.xml +++ b/sentry-android-core/src/main/res/layout/sentry_dialog_user_feedback.xml @@ -47,6 +47,7 @@ android:layout_height="wrap_content" android:hint="Your Name" android:inputType="textPersonName" + android:autofillHints="name" android:background="@drawable/sentry_edit_text_border" android:paddingHorizontal="8dp" android:layout_below="@id/sentry_dialog_user_feedback_txt_name" /> @@ -66,6 +67,7 @@ android:layout_height="wrap_content" android:hint="your.email@example.org" android:inputType="textEmailAddress" + android:autofillHints="emailAddress" android:background="@drawable/sentry_edit_text_border" android:paddingHorizontal="8dp" android:layout_below="@id/sentry_dialog_user_feedback_txt_email" /> @@ -85,6 +87,7 @@ android:layout_height="wrap_content" android:lines="6" android:inputType="textMultiLine" + android:importantForAutofill="no" android:gravity="top|left" android:hint="What's the bug? What did you expect?" android:background="@drawable/sentry_edit_text_border" diff --git a/sentry-android-distribution/src/test/java/io/sentry/android/distribution/UpdateResponseParserTest.kt b/sentry-android-distribution/src/test/java/io/sentry/android/distribution/UpdateResponseParserTest.kt index 3f1d083919c..f1817a39f34 100644 --- a/sentry-android-distribution/src/test/java/io/sentry/android/distribution/UpdateResponseParserTest.kt +++ b/sentry-android-distribution/src/test/java/io/sentry/android/distribution/UpdateResponseParserTest.kt @@ -8,8 +8,10 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) +@Config(sdk = [35]) class UpdateResponseParserTest { private lateinit var options: SentryOptions diff --git a/sentry-android-integration-tests/sentry-uitest-android-benchmark/build.gradle.kts b/sentry-android-integration-tests/sentry-uitest-android-benchmark/build.gradle.kts index 459c1653fa9..1dc351715ac 100644 --- a/sentry-android-integration-tests/sentry-uitest-android-benchmark/build.gradle.kts +++ b/sentry-android-integration-tests/sentry-uitest-android-benchmark/build.gradle.kts @@ -69,8 +69,6 @@ android { lint { warningsAsErrors = true checkDependencies = true - // Suppress OldTargetApi: lint 8.13.1 expects API 37 but we target 36 - disable += "OldTargetApi" // We run a full lint analysis as build part in CI, so skip vital checks for assemble tasks. checkReleaseBuilds = false diff --git a/sentry-android-integration-tests/sentry-uitest-android/build.gradle.kts b/sentry-android-integration-tests/sentry-uitest-android/build.gradle.kts index 1d725b0b595..4c718883149 100644 --- a/sentry-android-integration-tests/sentry-uitest-android/build.gradle.kts +++ b/sentry-android-integration-tests/sentry-uitest-android/build.gradle.kts @@ -56,6 +56,7 @@ android { buildTypes { getByName("release") { isMinifyEnabled = true + isShrinkResources = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") signingConfig = signingConfigs.getByName("debug") // to be able to run release mode testProguardFiles("proguard-rules.pro") @@ -67,8 +68,6 @@ android { lint { warningsAsErrors = true checkDependencies = true - // Suppress OldTargetApi: lint 8.13.1 expects API 37 but we target 36 - disable += "OldTargetApi" // We run a full lint analysis as build part in CI, so skip vital checks for assemble tasks. checkReleaseBuilds = false diff --git a/sentry-android-replay/src/test/java/io/sentry/android/replay/ScreenshotRecorderTest.kt b/sentry-android-replay/src/test/java/io/sentry/android/replay/ScreenshotRecorderTest.kt index 0a5c73f8a5c..12eee0c44af 100644 --- a/sentry-android-replay/src/test/java/io/sentry/android/replay/ScreenshotRecorderTest.kt +++ b/sentry-android-replay/src/test/java/io/sentry/android/replay/ScreenshotRecorderTest.kt @@ -14,8 +14,10 @@ import kotlin.test.Test import kotlin.test.assertTrue import org.junit.runner.RunWith import org.mockito.kotlin.mock +import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) +@Config(sdk = [35]) class ScreenshotRecorderTest { internal class Fixture() { diff --git a/sentry-android-replay/src/test/java/io/sentry/android/replay/util/ViewsTest.kt b/sentry-android-replay/src/test/java/io/sentry/android/replay/util/ViewsTest.kt index 2eaa8411cfe..3d5f6a9c506 100644 --- a/sentry-android-replay/src/test/java/io/sentry/android/replay/util/ViewsTest.kt +++ b/sentry-android-replay/src/test/java/io/sentry/android/replay/util/ViewsTest.kt @@ -20,8 +20,10 @@ import kotlin.test.assertTrue import org.junit.runner.RunWith import org.robolectric.Robolectric.buildActivity import org.robolectric.Shadows.shadowOf +import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) +@Config(sdk = [35]) class ViewsTest { @BeforeTest From b3c0995bd6b55550579ce7bfd83e9750ec4d508b Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 2 Jul 2026 12:03:33 +0200 Subject: [PATCH 3/3] fix(ci): Unblock Build workflow snapshot upload and Danger changelog Add the PR link Danger requires in CHANGELOG.md and rerun screenshot unit tests when Gradle cache omits the test-snapshots output directory. Co-authored-by: Cursor --- .github/workflows/build.yml | 7 ++++++- CHANGELOG.md | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 57106c8e05a..607a584d45c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,7 +52,12 @@ jobs: # Skip on PRs from forks, which don't have access to the upload secret if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} run: | - sentry-cli build snapshots ./sentry-android-core/build/test-snapshots \ + SNAPSHOT_DIR=./sentry-android-core/build/test-snapshots + if [ ! -d "$SNAPSHOT_DIR" ]; then + echo "Snapshot directory missing (likely Gradle cache hit); running screenshot tests" + ./gradlew :sentry-android-core:testDebugUnitTest --tests io.sentry.android.core.ScreenshotEventProcessorTest + fi + sentry-cli build snapshots "$SNAPSHOT_DIR" \ --app-id sentry-android-core env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 92ab02df8cb..f801a3f6a23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Features -- Officially supports Android 17. Updated targetSdk and compileSdk to API 37 +- Officially supports Android 17. Updated targetSdk and compileSdk to API 37 ([#5675](https://github.com/getsentry/sentry-java/pull/5675)) ### Behavioral Changes