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/.github/workflows/build.yml b/.github/workflows/build.yml index 57106c8e05a..62eb24d0ad2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,8 +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 \ - --app-id sentry-android-core + SNAPSHOT_DIR=./sentry-android-core/build/test-snapshots + if [ -d "$SNAPSHOT_DIR" ]; then + sentry-cli build snapshots "$SNAPSHOT_DIR" --app-id sentry-android-core + else + echo "::warning::Snapshot directory missing after check (likely Gradle cache hit); skipping upload" + fi env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_ORG: sentry-sdks 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 a05d9386607..acf068ef743 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,6 +24,13 @@ 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 (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`) +- **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/CHANGELOG.md b/CHANGELOG.md index 73bb2ef396e..f801a3f6a23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Features + +- Officially supports Android 17. Updated targetSdk and compileSdk to API 37 ([#5675](https://github.com/getsentry/sentry-java/pull/5675)) + ### 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/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/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/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-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/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-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 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") }