From 459be975886069e74c4182865015f35310208bb7 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Mon, 9 Nov 2026 14:15:57 +0100 Subject: [PATCH 1/5] feat(android): Raise minSdk from 21 to 24 Raise the minimum supported Android API level of all Android modules from 21 to 24. The SDK_INT checks this makes obsolete stay for now, so lint's ObsoleteSdkInt check is disabled until they are removed. The R8 bundled with AGP 9.0 and 9.2 crashes on androidx.core at the new minSdk, so builds that override AGP run the R8 of the default AGP. Resolves #5508 Resolves JAVA-547 Co-Authored-By: Claude Opus 5.5 --- README.md | 20 +++++++------- build.gradle.kts | 2 ++ buildSrc/src/main/java/Config.kt | 5 ++++ gradle/libs.versions.toml | 2 +- sentry-android-core/build.gradle.kts | 2 ++ .../core/ActivityLifecycleIntegrationTest.kt | 27 ------------------- .../core/ScreenshotEventProcessorTest.kt | 2 +- .../sentry/android/core/SentryAndroidTest.kt | 1 + .../core/SentryUserFeedbackFormTest.kt | 2 +- .../SentryGestureListenerPeekDecorViewTest.kt | 16 +++++------ .../src/test/resources/robolectric.properties | 2 +- sentry-android-ndk/build.gradle.kts | 2 ++ sentry-android-replay/build.gradle.kts | 2 ++ .../src/test/AndroidManifest.xml | 13 --------- .../sentry-samples-android/build.gradle.kts | 3 +-- 15 files changed, 36 insertions(+), 65 deletions(-) delete mode 100644 sentry-android-sqlite/src/test/AndroidManifest.xml diff --git a/README.md b/README.md index a073fcad6c1..89af6e7f128 100644 --- a/README.md +++ b/README.md @@ -18,17 +18,17 @@ Sentry SDK for Java and Android | Packages | Maven Central | Minimum Android API Version | |-----------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| ------- | -| sentry-android | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android) | 21 | -| sentry-android-core | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-core?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-core) | 21 | -| sentry-android-distribution | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-distribution?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-distribution) | 21 | -| sentry-android-ndk | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-ndk?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-ndk) | 21 | -| sentry-android-timber | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-timber?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-timber) | 21 | -| sentry-android-fragment | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-fragment?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-fragment) | 21 | -| sentry-android-navigation | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-navigation?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-navigation) | 21 | -| sentry-android-navigation3 | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-navigation3?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-navigation3) | 23 | -| sentry-android-sqlite | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-sqlite?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-sqlite) | 21 | +| sentry-android | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android) | 24 | +| sentry-android-core | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-core?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-core) | 24 | +| sentry-android-distribution | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-distribution?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-distribution) | 24 | +| sentry-android-ndk | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-ndk?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-ndk) | 24 | +| sentry-android-timber | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-timber?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-timber) | 24 | +| sentry-android-fragment | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-fragment?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-fragment) | 24 | +| sentry-android-navigation | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-navigation?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-navigation) | 24 | +| sentry-android-navigation3 | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-navigation3?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-navigation3) | 24 | +| sentry-android-sqlite | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-sqlite?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-sqlite) | 24 | | sentry-android-replay | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-android-replay?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-android-replay) | 26 | -| sentry-compose-android | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-compose-android?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-compose-android) | 21 | +| sentry-compose-android | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-compose-android?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-compose-android) | 24 | | sentry-compose-desktop | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-compose-desktop?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-compose-desktop) | | sentry-compose | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry-compose?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry-compose) | | sentry | [![Maven Central Version](https://img.shields.io/maven-central/v/io.sentry/sentry?style=for-the-badge&logo=sentry&color=green)](https://central.sonatype.com/artifact/io.sentry/sentry) | 21 | diff --git a/build.gradle.kts b/build.gradle.kts index 6a42fe07a42..1f0e87fefcc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,6 +33,8 @@ buildscript { google() } dependencies { + // R8 must come before AGP on the classpath to replace the R8 bundled with AGP. + Config.BuildPlugins.r8?.let { classpath(it) } classpath(Config.BuildPlugins.androidGradle) // add classpath of sentry android gradle plugin diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 05786658ef3..78991110635 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -7,6 +7,11 @@ object Config { object BuildPlugins { val androidGradle = "com.android.tools.build:gradle:$AGP" + + // The R8 bundled with AGP 9.0 and 9.2 crashes on androidx.core at minSdk 24, so builds that + // override AGP (the AGP matrix) run the R8 that ships with the default AGP instead. + val r8: String? + get() = if (System.getenv("VERSION_AGP") != null) "com.android.tools:r8:9.4.14" else null } object Android { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 49f20a5b213..ec1280cc278 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -55,7 +55,7 @@ sqldelight = "2.3.2" targetSdk = "37" compileSdk = "37" compileSdkMinor = "2" -minSdk = "21" +minSdk = "24" [plugins] kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } diff --git a/sentry-android-core/build.gradle.kts b/sentry-android-core/build.gradle.kts index d111a71ecc3..c1ac3e935bf 100644 --- a/sentry-android-core/build.gradle.kts +++ b/sentry-android-core/build.gradle.kts @@ -56,6 +56,8 @@ android { lint { warningsAsErrors = true checkDependencies = true + // TODO: Re-enable once the SDK_INT checks made obsolete by minSdk 24 are removed. + disable += "ObsoleteSdkInt" // 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-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt index ae215d29efb..d2a8f05b996 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt @@ -691,33 +691,6 @@ class ActivityLifecycleIntegrationTest { assertEquals(SpanStatus.OK, transaction.status) } - @Test - @Config(sdk = [Build.VERSION_CODES.M]) - fun `onHeadlessAppStart creates standalone App Start transaction on API 23`() { - val sut = fixture.getSut { - it.tracesSampleRate = 1.0 - it.isEnableStandaloneAppStartTracing = true - } - sut.register(fixture.scopes, fixture.options) - prepareHeadlessSdkInitAppStart() - - driveHeadlessAppStart() - - assertEquals(1, fixture.capturedContexts.size) - val context = fixture.capturedContexts.single() - val options = fixture.capturedOptions.single() - val transaction = fixture.createdTransactions.single() - assertEquals(ActivityLifecycleIntegration.STANDALONE_APP_START_OP, context.operation) - assertEquals("App Start", context.name) - assertEquals(DateUtils.millisToNanos(100), options.startTimestamp!!.nanoTimestamp()) - assertEquals( - transaction.spanContext.traceId, - AppStartMetrics.getInstance().getAppStartTraceId(), - ) - assertTrue(transaction.isFinished) - assertEquals(SpanStatus.OK, transaction.status) - } - @Test fun `onHeadlessAppStart creates standalone App Start transaction when appStartType is WARM`() { val sut = fixture.getSut { diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ScreenshotEventProcessorTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ScreenshotEventProcessorTest.kt index 1dfb277175d..e875e7845a0 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ScreenshotEventProcessorTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ScreenshotEventProcessorTest.kt @@ -208,7 +208,7 @@ class ScreenshotEventProcessorTest { } @Test - @Config(sdk = [23]) + @Config(sdk = [24]) fun `when screenshot event processor is called from background thread it executes on main thread`() { val sut = fixture.getSut(true) whenever(fixture.threadChecker.isMainThread).thenReturn(false) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt index 6d02b678c5e..9b79c5bb56d 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt @@ -178,6 +178,7 @@ class SentryAndroidTest { fun `set up`() { Sentry.close() AppStartMetrics.getInstance().clear() + ContextUtils.resetInstance() context = ApplicationProvider.getApplicationContext() val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager? fixture.shadowActivityManager = Shadow.extract(activityManager) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/SentryUserFeedbackFormTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/SentryUserFeedbackFormTest.kt index 840a0772a7f..22a35016e77 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/SentryUserFeedbackFormTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/SentryUserFeedbackFormTest.kt @@ -268,7 +268,7 @@ class SentryUserFeedbackFormTest { val context = ContextThemeWrapper(fixture.application, android.R.style.Theme_Material_Light) assertThat(SentryUserFeedbackForm.resolveTheme(context, 0)) - .isEqualTo(android.R.style.Theme_Material_Light_Dialog_Alert) + .isEqualTo(android.R.style.ThemeOverlay_Material_Dialog_Alert) } @Test diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/internal/gestures/SentryGestureListenerPeekDecorViewTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/internal/gestures/SentryGestureListenerPeekDecorViewTest.kt index 7b26aa55c79..5d6fd79f178 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/internal/gestures/SentryGestureListenerPeekDecorViewTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/internal/gestures/SentryGestureListenerPeekDecorViewTest.kt @@ -2,31 +2,29 @@ package io.sentry.android.core.internal.gestures import android.app.Activity import android.view.MotionEvent +import android.view.Window import androidx.test.ext.junit.runners.AndroidJUnit4 import io.sentry.Breadcrumb import io.sentry.IScopes import io.sentry.android.core.SentryAndroidOptions import io.sentry.util.LazyEvaluator import kotlin.test.Test -import kotlin.test.assertNull import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.verify -import org.robolectric.Robolectric.buildActivity @RunWith(AndroidJUnit4::class) class SentryGestureListenerPeekDecorViewTest { @Test fun `does not force decor view creation when peekDecorView returns null`() { - // A plain Activity that never calls setContentView — peekDecorView() should return null - val activity = buildActivity(Activity::class.java).create().get() - - // Sanity check: decor view has not been created yet - assertNull(activity.window.peekDecorView()) + // Robolectric creates the decor view in onCreate on API 23+, so mock a window without one + val window = mock() + val activity = mock { on { this.window } doReturn window } val scopes = mock() val options = @@ -39,8 +37,8 @@ class SentryGestureListenerPeekDecorViewTest { val sut = SentryGestureListener(activity, scopes, options) sut.onSingleTapUp(mock()) - // The key assertion: peekDecorView is still null — we did not force view hierarchy creation - assertNull(activity.window.peekDecorView()) + // The key assertion: we did not force view hierarchy creation + verify(window, never()).decorView // And no breadcrumb was captured verify(scopes, never()).addBreadcrumb(any(), anyOrNull()) diff --git a/sentry-android-core/src/test/resources/robolectric.properties b/sentry-android-core/src/test/resources/robolectric.properties index c216eeab9dc..64ab54e15fc 100644 --- a/sentry-android-core/src/test/resources/robolectric.properties +++ b/sentry-android-core/src/test/resources/robolectric.properties @@ -1,2 +1,2 @@ -sdk=21 +sdk=24 application=io.sentry.android.core.ApplicationStub diff --git a/sentry-android-ndk/build.gradle.kts b/sentry-android-ndk/build.gradle.kts index dbfeeec5550..9fd7dce011a 100644 --- a/sentry-android-ndk/build.gradle.kts +++ b/sentry-android-ndk/build.gradle.kts @@ -45,6 +45,8 @@ android { lint { warningsAsErrors = true checkDependencies = true + // TODO: Re-enable once the SDK_INT checks made obsolete by minSdk 24 are removed. + disable += "ObsoleteSdkInt" // 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 7794e32c55e..11e47e113fb 100644 --- a/sentry-android-replay/build.gradle.kts +++ b/sentry-android-replay/build.gradle.kts @@ -56,6 +56,8 @@ android { lint { warningsAsErrors = true checkDependencies = true + // TODO: Re-enable once the SDK_INT checks made obsolete by minSdk 24 are removed. + disable += "ObsoleteSdkInt" // 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-sqlite/src/test/AndroidManifest.xml b/sentry-android-sqlite/src/test/AndroidManifest.xml deleted file mode 100644 index 967265a1f16..00000000000 --- a/sentry-android-sqlite/src/test/AndroidManifest.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - diff --git a/sentry-samples/sentry-samples-android/build.gradle.kts b/sentry-samples/sentry-samples-android/build.gradle.kts index 441271bc5eb..f832020037d 100644 --- a/sentry-samples/sentry-samples-android/build.gradle.kts +++ b/sentry-samples/sentry-samples-android/build.gradle.kts @@ -48,8 +48,7 @@ android { defaultConfig { applicationId = "io.sentry.samples.android" - // androidx.sqlite 2.6+ require minSdk 23; the Sentry SDK still supports 21. - minSdk = 23 + minSdk = libs.versions.minSdk.get().toInt() targetSdk = libs.versions.targetSdk.get().toInt() versionCode = 2 versionName = project.version.toString() From 96339435eeb252822a8fdf52d117abf3390ef159 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Mon, 9 Nov 2026 14:16:25 +0100 Subject: [PATCH 2/5] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cfe1c307ba..9dbe9e60bee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ - Decide whether foregrounding the app starts a new session on a monotonic clock instead of the wall clock, so that a device time change no longer starts a session that should have been resumed, or resumes one that should have ended. This affects session counts ([#6096](https://github.com/getsentry/sentry-java/pull/6096)) - `SentryUserFeedbackForm` now extends `android.app.Dialog` instead of `android.app.AlertDialog` ([#6338](https://github.com/getsentry/sentry-java/pull/6338)) - The form never used `AlertDialog` features. Code that calls `AlertDialog`-only methods on it, such as `setButton` or `setMessage`, no longer compiles. +- Raise the minimum supported Android API level (`minSdk`) of all Android modules from 21 to 24. Apps with a lower `minSdk` must raise it or stay on 8.x ([#6518](https://github.com/getsentry/sentry-java/pull/6518)) - `sentry-android` no longer includes `sentry-android-ndk` as a default dependency. Instead, tombstone reporting is enabled by default, which provides more detailed native crashes on Android 11+ (API 30). If you're using sentry-android-ndk APIs, or need native crashes on Android 10 and lower, manually add the `io.sentry:sentry-android-ndk` dependency to your app. ([#6436](https://github.com/getsentry/sentry-java/pull/6436)) - Remove the Android `enablePerformanceV2` option and its `io.sentry.performance-v2.enable` manifest metadata. Performance V2 is always on ([#6458](https://github.com/getsentry/sentry-java/pull/6458)) - App starts are measured from process start on Android 7.0+ (API 24), and slow and frozen frames are measured per span From 36aa094865f19e9388db164ebc8eba577d97c5f4 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Mon, 9 Nov 2026 14:40:18 +0100 Subject: [PATCH 3/5] test(android): Drop obsolete API checks from the UI test app sentry-uitest-android lints with warningsAsErrors and is part of the root build, so its two pre-24 checks fail check at minSdk 24. Co-Authored-By: Claude Opus 5.5 --- .../sentry-uitest-android/src/main/AndroidManifest.xml | 3 +-- .../java/io/sentry/uitest/android/ProfilingSampleActivity.kt | 5 +---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/sentry-android-integration-tests/sentry-uitest-android/src/main/AndroidManifest.xml b/sentry-android-integration-tests/sentry-uitest-android/src/main/AndroidManifest.xml index 6bcad62e6de..0b676446a85 100644 --- a/sentry-android-integration-tests/sentry-uitest-android/src/main/AndroidManifest.xml +++ b/sentry-android-integration-tests/sentry-uitest-android/src/main/AndroidManifest.xml @@ -9,8 +9,7 @@ android:label="Sentry End2End Tests" android:largeHeap="true" android:icon="@android:mipmap/sym_def_app_icon" - android:usesCleartextTraffic="true" - tools:targetApi="m"> + android:usesCleartextTraffic="true"> diff --git a/sentry-android-integration-tests/sentry-uitest-android/src/main/java/io/sentry/uitest/android/ProfilingSampleActivity.kt b/sentry-android-integration-tests/sentry-uitest-android/src/main/java/io/sentry/uitest/android/ProfilingSampleActivity.kt index fdfeb61e05f..1ac1590e78a 100644 --- a/sentry-android-integration-tests/sentry-uitest-android/src/main/java/io/sentry/uitest/android/ProfilingSampleActivity.kt +++ b/sentry-android-integration-tests/sentry-uitest-android/src/main/java/io/sentry/uitest/android/ProfilingSampleActivity.kt @@ -2,7 +2,6 @@ package io.sentry.uitest.android import android.graphics.Bitmap import android.graphics.Color -import android.os.Build import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup @@ -31,9 +30,7 @@ class ProfilingSampleActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - window.setSustainedPerformanceMode(true) - } + window.setSustainedPerformanceMode(true) binding = ActivityProfilingSampleBinding.inflate(layoutInflater) setContentView(binding.root) From f2578613aec76b59bc632857d29fb27a253afbc6 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Tue, 10 Nov 2026 08:28:25 +0100 Subject: [PATCH 4/5] ref(android): Remove code made obsolete by minSdk 24 (#6519) * ref(android): Remove code made obsolete by minSdk 24 Remove the SDK_INT checks for API 24 and lower, with the branches they guarded, and turn lint's ObsoleteSdkInt check back on. Most checks go through BuildInfoProvider, which lint doesn't see, so it flagged only five of them. Code for API 25 and lower, such as the bundled root CAs, the pre-O screenshot canvas and the Choreographer frame start, stays. Co-Authored-By: Claude Opus 5.5 * ref(android): Remove NewApi suppressions lint no longer needs At minSdk 24, 35 of the 54 NewApi suppressions in sentry-android-core and sentry-android-replay no longer hide any lint error. The same goes for the two remaining ObsoleteSdkInt suppressions. The 19 that stay cover APIs above 24, behind BuildInfoProvider checks that lint can't see. Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 --- sentry-android-core/build.gradle.kts | 2 - .../core/AndroidContinuousProfiler.java | 11 -- .../sentry/android/core/AndroidProfiler.java | 4 - .../core/AndroidTransactionProfiler.java | 12 -- .../sentry/android/core/AnrV2Integration.java | 1 - .../ApplicationExitInfoEventProcessor.java | 2 - .../io/sentry/android/core/ContextUtils.java | 1 - .../sentry/android/core/DeviceInfoUtil.java | 1 - .../core/NetworkBreadcrumbsIntegration.java | 6 - .../io/sentry/android/core/SentryAndroid.java | 10 +- .../core/SentryPerformanceProvider.java | 10 +- .../gestures/WindowCallbackAdapter.java | 3 - .../util/AndroidConnectionStatusProvider.java | 112 ++++-------------- .../CellularNetworkTechnologyProvider.java | 6 +- .../util/ContentProviderSecurityChecker.java | 2 - .../core/internal/util/ScreenshotUtils.java | 1 - .../util/SentryFrameMetricsCollector.java | 14 +-- .../core/performance/AppStartMetrics.java | 31 ++--- .../core/AndroidContinuousProfilerTest.kt | 11 -- .../core/AndroidTransactionProfilerTest.kt | 11 -- .../core/NetworkBreadcrumbsIntegrationTest.kt | 12 -- .../AndroidConnectionStatusProviderTest.kt | 11 -- .../CellularNetworkTechnologyProviderTest.kt | 8 -- .../util/SentryFrameMetricsCollectorTest.kt | 13 +- sentry-android-ndk/build.gradle.kts | 2 - sentry-android-replay/build.gradle.kts | 2 - .../java/io/sentry/android/replay/Windows.kt | 5 +- .../android/replay/capture/CaptureStrategy.kt | 2 - .../replay/screenshot/CanvasStrategy.kt | 2 - .../replay/screenshot/PixelCopyStrategy.kt | 1 - .../replay/util/FixedWindowCallback.java | 3 - .../io/sentry/android/replay/util/Views.kt | 3 - .../replay/video/SimpleVideoEncoder.kt | 2 - 33 files changed, 43 insertions(+), 274 deletions(-) diff --git a/sentry-android-core/build.gradle.kts b/sentry-android-core/build.gradle.kts index c1ac3e935bf..d111a71ecc3 100644 --- a/sentry-android-core/build.gradle.kts +++ b/sentry-android-core/build.gradle.kts @@ -56,8 +56,6 @@ android { lint { warningsAsErrors = true checkDependencies = true - // TODO: Re-enable once the SDK_INT checks made obsolete by minSdk 24 are removed. - disable += "ObsoleteSdkInt" // 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-core/src/main/java/io/sentry/android/core/AndroidContinuousProfiler.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidContinuousProfiler.java index 4f115ca9d7f..23a72b131fc 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidContinuousProfiler.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidContinuousProfiler.java @@ -4,7 +4,6 @@ import static io.sentry.IConnectionStatusProvider.ConnectionStatus.DISCONNECTED; import static java.util.concurrent.TimeUnit.SECONDS; -import android.os.Build; import io.sentry.CompositePerformanceCollector; import io.sentry.DataCategory; import io.sentry.IContinuousProfiler; @@ -176,10 +175,6 @@ private void initScopes() { private void start() { initScopes(); - // Debug.startMethodTracingSampling() is only available since Lollipop, but Android Profiler - // causes crashes on api 21 -> https://github.com/getsentry/sentry-java/issues/3392 - if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.LOLLIPOP_MR1) return; - // Let's initialize trace folder and profiling interval init(); // init() didn't create profiler, should never happen @@ -281,12 +276,6 @@ private void stop(final boolean restartProfiler) { return; } - // onTransactionStart() is only available since Lollipop_MR1 - // and SystemClock.elapsedRealtimeNanos() since Jelly Bean - if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.LOLLIPOP_MR1) { - return; - } - List performanceCollectionData = null; if (performanceCollector != null) { performanceCollectionData = performanceCollector.stop(chunkId.toString()); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidProfiler.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidProfiler.java index 3f569df5378..8710c5d637f 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidProfiler.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidProfiler.java @@ -1,6 +1,5 @@ package io.sentry.android.core; -import android.annotation.SuppressLint; import android.os.Debug; import android.os.Process; import android.os.SystemClock; @@ -116,7 +115,6 @@ public AndroidProfiler( Objects.requireNonNull(frameMetricsCollector, "SentryFrameMetricsCollector is required"); } - @SuppressLint("NewApi") public @Nullable ProfileStartData start() { try (final @NotNull ISentryLifecycleToken ignored = lock.acquire()) { // intervalUs is 0 only if there was a problem in the init @@ -225,7 +223,6 @@ public void onFrameMetricCollected( } } - @SuppressLint("NewApi") public @Nullable ProfileEndData endAndCollect( final boolean isTimeout, final @Nullable List performanceCollectionData) { @@ -299,7 +296,6 @@ public void close() { } } - @SuppressLint("NewApi") private void putPerformanceCollectionDataInMeasurements( final @Nullable List performanceCollectionData) { diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidTransactionProfiler.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidTransactionProfiler.java index e44ed746a08..f5d65ed4bed 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidTransactionProfiler.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidTransactionProfiler.java @@ -2,7 +2,6 @@ import static java.util.concurrent.TimeUnit.SECONDS; -import android.annotation.SuppressLint; import android.content.Context; import android.os.Build; import io.sentry.DateUtils; @@ -151,10 +150,6 @@ private void init() { @Override public void start() { - // Debug.startMethodTracingSampling() is only available since Lollipop, but Android Profiler - // causes crashes on api 21 -> https://github.com/getsentry/sentry-java/issues/3392 - if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.LOLLIPOP_MR1) return; - // When the first transaction is starting, we can start profiling if (!isRunning.getAndSet(true)) { // Let's initialize trace folder and profiling interval @@ -179,7 +174,6 @@ public void start() { } } - @SuppressLint("NewApi") private boolean onFirstStart() { // init() didn't create profiler, should never happen if (profiler == null) { @@ -225,7 +219,6 @@ public void bindTransaction(final @NotNull ITransaction transaction) { options); } - @SuppressLint("NewApi") private @Nullable ProfilingTraceData onTransactionFinish( final @NotNull String transactionName, final @NotNull String transactionId, @@ -234,11 +227,6 @@ public void bindTransaction(final @NotNull ITransaction transaction) { final @Nullable List performanceCollectionData, final @NotNull SentryOptions options) { - // onTransactionStart() is only available since Lollipop_MR1 - // and SystemClock.elapsedRealtimeNanos() since Jelly Bean - // and SUPPORTED_ABIS since KITKAT - if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.LOLLIPOP_MR1) return null; - // check if profiler was created if (profiler == null) { return null; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java b/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java index 5e5500297f8..c80ce982b95 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java @@ -62,7 +62,6 @@ public AnrV2Integration(final @NotNull Context context) { this.dateProvider = dateProvider; } - @SuppressLint("NewApi") // we do the check in the AnrIntegrationFactory @Override public void register(@NotNull IScopes scopes, @NotNull SentryOptions options) { this.options = diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java index 80da05967ea..79e671b4f49 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java @@ -18,7 +18,6 @@ import static io.sentry.cache.PersistingScopeObserver.USER_FILENAME; import static io.sentry.protocol.Contexts.REPLAY_ID; -import android.annotation.SuppressLint; import android.app.ActivityManager; import android.content.Context; import android.content.pm.PackageInfo; @@ -728,7 +727,6 @@ private void setDevice(final @NotNull SentryBaseEvent event) { // only use static data that does not change between app launches (e.g. timezone, boottime, // battery level will change) - @SuppressLint("NewApi") private @NotNull Device getDevice() { Device device = new Device(); device.setManufacturer(Build.MANUFACTURER); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java b/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java index 60ae00f2ead..b189746fde6 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java @@ -218,7 +218,6 @@ static PackageInfo getPackageInfo( * * @return the Application's ApplicationInfo if possible, or throws */ - @SuppressLint("NewApi") @Nullable @SuppressWarnings("deprecation") static ApplicationInfo getApplicationInfo( diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java b/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java index 7d45ebcf6e5..3cc0b3c67f5 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java @@ -247,7 +247,6 @@ private void setDeviceIO( } } - @SuppressWarnings("NewApi") @NotNull private TimeZone getTimeZone() { // Only use the costly Calendar API on Android 13+ (API Level 33+) when the locale contains a diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/NetworkBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/NetworkBreadcrumbsIntegration.java index c7f3182b97d..0151c96de67 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/NetworkBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/NetworkBreadcrumbsIntegration.java @@ -64,12 +64,6 @@ public void register(final @NotNull IScopes scopes, final @NotNull SentryOptions if (androidOptions.isEnableNetworkEventBreadcrumbs()) { - // The specific error is logged in the ConnectivityChecker method - if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.N) { - options.getLogger().log(SentryLevel.DEBUG, "NetworkCallbacks need Android N+."); - return; - } - try (final @NotNull ISentryLifecycleToken ignored = lock.acquire()) { networkCallback = new NetworkBreadcrumbsNetworkCallback( diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java b/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java index e649e9e094c..1544a721c10 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java @@ -1,6 +1,5 @@ package io.sentry.android.core; -import android.annotation.SuppressLint; import android.app.Application; import android.content.Context; import android.os.Process; @@ -91,7 +90,6 @@ public static void init( * @param logger your custom logger that implements ILogger * @param configuration Sentry.OptionsConfiguration configuration handler */ - @SuppressLint("NewApi") public static void init( @NotNull final Context context, @NotNull ILogger logger, @@ -154,11 +152,9 @@ public static void init( // if SentryPerformanceProvider was disabled or removed, // we set the app start / sdk init time here instead final @NotNull AppStartMetrics appStartMetrics = AppStartMetrics.getInstance(); - if (buildInfoProvider.getSdkInfoVersion() >= android.os.Build.VERSION_CODES.N) { - final @NotNull TimeSpan appStartTimeSpan = appStartMetrics.getAppStartTimeSpan(); - if (appStartTimeSpan.hasNotStarted()) { - appStartTimeSpan.setStartedAt(Process.getStartUptimeMillis()); - } + final @NotNull TimeSpan appStartTimeSpan = appStartMetrics.getAppStartTimeSpan(); + if (appStartTimeSpan.hasNotStarted()) { + appStartTimeSpan.setStartedAt(Process.getStartUptimeMillis()); } if (context.getApplicationContext() instanceof Application) { appStartMetrics.registerLifecycleCallbacks( diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SentryPerformanceProvider.java b/sentry-android-core/src/main/java/io/sentry/android/core/SentryPerformanceProvider.java index 9d1f2e13ec4..d156b00fa5a 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SentryPerformanceProvider.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SentryPerformanceProvider.java @@ -2,7 +2,6 @@ import static io.sentry.Sentry.APP_START_PROFILING_CONFIG_FILE_NAME; -import android.annotation.SuppressLint; import android.app.Application; import android.content.Context; import android.content.pm.ProviderInfo; @@ -250,7 +249,6 @@ private void createAndStartTransactionProfiler( appStartProfiler.start(); } - @SuppressLint("NewApi") private void onAppLaunched( final @Nullable Context context, final @NotNull AppStartMetrics appStartMetrics) { @@ -258,12 +256,8 @@ private void onAppLaunched( final @NotNull TimeSpan sdkInitTimeSpan = appStartMetrics.getSdkInitTimeSpan(); sdkInitTimeSpan.setStartedAt(sdkInitMillis); - // performance v2: Uses Process.getStartUptimeMillis() - // requires API level 24+ - if (buildInfoProvider.getSdkInfoVersion() >= android.os.Build.VERSION_CODES.N) { - final @NotNull TimeSpan appStartTimespan = appStartMetrics.getAppStartTimeSpan(); - appStartTimespan.setStartedAt(Process.getStartUptimeMillis()); - } + final @NotNull TimeSpan appStartTimespan = appStartMetrics.getAppStartTimeSpan(); + appStartTimespan.setStartedAt(Process.getStartUptimeMillis()); if (context instanceof Application) { app = (Application) context; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/gestures/WindowCallbackAdapter.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/gestures/WindowCallbackAdapter.java index c6a3e627115..a44643934ab 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/gestures/WindowCallbackAdapter.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/gestures/WindowCallbackAdapter.java @@ -1,6 +1,5 @@ package io.sentry.android.core.internal.gestures; -import android.annotation.SuppressLint; import android.view.ActionMode; import android.view.KeyEvent; import android.view.Menu; @@ -115,7 +114,6 @@ public boolean onSearchRequested() { return delegate.onSearchRequested(); } - @SuppressLint("NewApi") @Override public boolean onSearchRequested(SearchEvent searchEvent) { return delegate.onSearchRequested(searchEvent); @@ -127,7 +125,6 @@ public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) { return delegate.onWindowStartingActionMode(callback); } - @SuppressLint("NewApi") @Nullable @Override public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int i) { diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProvider.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProvider.java index 62a212e6dcc..a5ff05e27d5 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProvider.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProvider.java @@ -99,9 +99,7 @@ public AndroidConnectionStatusProvider( new CellularNetworkTechnologyProvider(this.context, options.getLogger(), buildInfoProvider); capabilities[0] = NetworkCapabilities.NET_CAPABILITY_INTERNET; - if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.M) { - capabilities[1] = NetworkCapabilities.NET_CAPABILITY_VALIDATED; - } + capabilities[1] = NetworkCapabilities.NET_CAPABILITY_VALIDATED; // Register network callback immediately for caching //noinspection Convert2MethodRef @@ -123,13 +121,9 @@ private boolean isNetworkEffectivelyConnected( } // Check for general internet capability AND validated status - boolean hasInternetAndValidated = - networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.M) { - hasInternetAndValidated = - hasInternetAndValidated - && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); - } + final boolean hasInternetAndValidated = + networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); if (!hasInternetAndValidated) { return false; @@ -375,7 +369,7 @@ private boolean hasSignificantTransportChanges( } } - @SuppressLint({"NewApi", "MissingPermission"}) + @SuppressLint("MissingPermission") private void updateCache(@Nullable NetworkCapabilities networkCapabilities) { try (final @NotNull ISentryLifecycleToken ignored = lock.acquire()) { try { @@ -393,12 +387,6 @@ private void updateCache(@Nullable NetworkCapabilities networkCapabilities) { return; } - if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.M) { - cachedNetworkCapabilities = null; - cacheFreshUntil = Deadline.after(ticker, CACHE_TTL_MINUTES, TimeUnit.MINUTES); - return; - } - // Fallback: query current active network final ConnectivityManager connectivityManager = getConnectivityManager(context, options.getLogger()); @@ -611,7 +599,7 @@ public NetworkCapabilities getCachedNetworkCapabilities() { * @param buildInfoProvider the BuildInfoProvider provider * @return the connection type wifi, ethernet, cellular or null */ - @SuppressLint({"ObsoleteSdkInt", "MissingPermission", "NewApi"}) + @SuppressLint("MissingPermission") public static @Nullable String getConnectionType( final @NotNull Context context, final @NotNull ILogger logger, @@ -630,65 +618,25 @@ public NetworkCapabilities getCachedNetworkCapabilities() { boolean wifi = false; boolean cellular = false; - if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.M) { - - final Network activeNetwork = connectivityManager.getActiveNetwork(); - if (activeNetwork == null) { - logger.log(SentryLevel.INFO, "Network is null and cannot check network status"); - return null; - } - final NetworkCapabilities networkCapabilities = - connectivityManager.getNetworkCapabilities(activeNetwork); - if (networkCapabilities == null) { - logger.log(SentryLevel.INFO, "NetworkCapabilities is null and cannot check network type"); - return null; - } - if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) { - ethernet = true; - } - if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { - wifi = true; - } - if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { - cellular = true; - } - } else { - // ideally using connectivityManager.getAllNetworks(), but its >= Android L only - - // for some reason linting didn't allow a single @SuppressWarnings("deprecation") on method - // signature - @SuppressWarnings("deprecation") - final android.net.NetworkInfo activeNetworkInfo = - connectivityManager.getActiveNetworkInfo(); - - if (activeNetworkInfo == null) { - logger.log(SentryLevel.INFO, "NetworkInfo is null, there's no active network."); - return null; - } - - @SuppressWarnings("deprecation") - final int type = activeNetworkInfo.getType(); - - @SuppressWarnings("deprecation") - final int TYPE_ETHERNET = ConnectivityManager.TYPE_ETHERNET; - - @SuppressWarnings("deprecation") - final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; - - @SuppressWarnings("deprecation") - final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; - - switch (type) { - case TYPE_ETHERNET: - ethernet = true; - break; - case TYPE_WIFI: - wifi = true; - break; - case TYPE_MOBILE: - cellular = true; - break; - } + final Network activeNetwork = connectivityManager.getActiveNetwork(); + if (activeNetwork == null) { + logger.log(SentryLevel.INFO, "Network is null and cannot check network status"); + return null; + } + final NetworkCapabilities networkCapabilities = + connectivityManager.getNetworkCapabilities(activeNetwork); + if (networkCapabilities == null) { + logger.log(SentryLevel.INFO, "NetworkCapabilities is null and cannot check network type"); + return null; + } + if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) { + ethernet = true; + } + if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + wifi = true; + } + if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + cellular = true; } // TODO: change the protocol to be a list of transports as a device may have the capability of @@ -758,11 +706,6 @@ public static boolean addNetworkCallback( final @NotNull ILogger logger, final @NotNull BuildInfoProvider buildInfoProvider, final @NotNull NetworkCallback networkCallback) { - if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.N) { - logger.log(SentryLevel.DEBUG, "NetworkCallbacks need Android N+."); - return false; - } - if (!Permissions.hasPermission(context, Manifest.permission.ACCESS_NETWORK_STATE)) { logger.log(SentryLevel.INFO, "No permission (ACCESS_NETWORK_STATE) to check network status."); return false; @@ -787,10 +730,6 @@ static boolean registerNetworkCallback( final @NotNull BuildInfoProvider buildInfoProvider, final @Nullable Handler handler, final @NotNull NetworkCallback networkCallback) { - if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.N) { - logger.log(SentryLevel.DEBUG, "NetworkCallbacks need Android N+."); - return false; - } final ConnectivityManager connectivityManager = getConnectivityManager(context, logger); if (connectivityManager == null) { return false; @@ -812,7 +751,6 @@ static boolean registerNetworkCallback( return true; } - @SuppressLint("NewApi") static void unregisterNetworkCallback( final @NotNull Context context, final @NotNull ILogger logger, diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/CellularNetworkTechnologyProvider.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/CellularNetworkTechnologyProvider.java index a5468ae913f..f26a57103ad 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/CellularNetworkTechnologyProvider.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/CellularNetworkTechnologyProvider.java @@ -142,12 +142,8 @@ public void unregister() { } } - @SuppressLint({"MissingPermission", "InlinedApi", "NewApi"}) + @SuppressLint({"MissingPermission", "InlinedApi"}) private @Nullable String getDataNetworkTechnology() { - if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.N) { - // getDataNetworkType was added in API 24. - return null; - } // The SDK doesn't declare these permissions, so the technology is only available to apps that // already request one of them. READ_BASIC_PHONE_STATE only exists from API 31 on, where the // display info listener is used instead, but checking it is harmless. diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ContentProviderSecurityChecker.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ContentProviderSecurityChecker.java index 9aa21507f73..61cb813e53d 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ContentProviderSecurityChecker.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ContentProviderSecurityChecker.java @@ -1,6 +1,5 @@ package io.sentry.android.core.internal.util; -import android.annotation.SuppressLint; import android.content.ContentProvider; import android.os.Build; import io.sentry.NoOpLogger; @@ -42,7 +41,6 @@ public ContentProviderSecurityChecker(final @NotNull BuildInfoProvider buildInfo *

The vulnerability is specific to un-patched versions of Android 8 and 9 (API 26 to 28). * Therefore, this security check is limited to those versions to mitigate risk of regression. */ - @SuppressLint("NewApi") public void checkPrivilegeEscalation(@NotNull ContentProvider contentProvider) { final int sdkVersion = buildInfoProvider.getSdkInfoVersion(); if (sdkVersion >= Build.VERSION_CODES.O && sdkVersion <= Build.VERSION_CODES.P) { diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ScreenshotUtils.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ScreenshotUtils.java index 00d9cc37e3c..76700beaf4a 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ScreenshotUtils.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ScreenshotUtils.java @@ -40,7 +40,6 @@ public class ScreenshotUtils { } // Used by Hybrid SDKs - @SuppressLint("NewApi") public static @Nullable byte[] takeScreenshot( final @NotNull Activity activity, final @NotNull IThreadChecker threadChecker, 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 2c0ae246558..1af8f97fea2 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 @@ -12,7 +12,6 @@ import android.view.Choreographer; import android.view.FrameMetrics; import android.view.Window; -import androidx.annotation.RequiresApi; import io.sentry.ILogger; import io.sentry.ISentryLifecycleToken; import io.sentry.SentryLevel; @@ -65,7 +64,6 @@ public final class SentryFrameMetricsCollector implements Application.ActivityLi private final @NotNull ConcurrentSkipListSet delayedFrames = new ConcurrentSkipListSet<>(); - @SuppressLint("NewApi") public SentryFrameMetricsCollector( final @NotNull Context context, final @NotNull SentryOptions options, @@ -73,7 +71,6 @@ public SentryFrameMetricsCollector( this(context, options, buildInfoProvider, new WindowFrameMetricsManager() {}); } - @SuppressLint("NewApi") public SentryFrameMetricsCollector( final @NotNull Context context, final @NotNull ILogger logger, @@ -81,7 +78,7 @@ public SentryFrameMetricsCollector( this(context, logger, buildInfoProvider, new WindowFrameMetricsManager() {}); } - @SuppressLint({"NewApi", "DiscouragedPrivateApi"}) + @SuppressLint("DiscouragedPrivateApi") public SentryFrameMetricsCollector( final @NotNull Context context, final @NotNull SentryOptions options, @@ -110,10 +107,6 @@ public SentryFrameMetricsCollector( if (!(appContext instanceof Application)) { return; } - // FrameMetrics api is only available since sdk version N - if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.N) { - return; - } isAvailable = true; // The frame metrics HandlerThread is started lazily on the first startCollection() call. @@ -240,7 +233,6 @@ private long getFrameStartTimestamp(final @NotNull FrameMetrics frameMetrics) { * Return time spent on the main thread (cpu) for frame creation. It doesn't consider time spent * on the render thread (gpu). */ - @RequiresApi(api = Build.VERSION_CODES.N) private long getFrameCpuDuration(final @NotNull FrameMetrics frameMetrics) { // Inspired by JankStats // https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStatsApi24Impl.kt;l=74-79;drc=1de6215c6bd9e887e3d94556e9ac55cfb7b8c797 @@ -327,7 +319,6 @@ public void stopCollection(final @Nullable String listenerId) { } } - @SuppressLint("NewApi") private void stopTrackingWindow(final @NotNull Window window) { new Handler(Looper.getMainLooper()) .post( @@ -353,7 +344,6 @@ private void setCurrentWindow(final @NotNull Window window) { trackCurrentWindow(); } - @SuppressLint("NewApi") private void trackCurrentWindow() { @Nullable Window window = currentWindow != null ? currentWindow.get() : null; if (window == null || !isAvailable) { @@ -512,7 +502,6 @@ void onFrameMetricCollected( @ApiStatus.Internal public interface WindowFrameMetricsManager { - @RequiresApi(api = Build.VERSION_CODES.N) default void addOnFrameMetricsAvailableListener( final @NotNull Window window, final @Nullable Window.OnFrameMetricsAvailableListener frameMetricsAvailableListener, @@ -523,7 +512,6 @@ default void addOnFrameMetricsAvailableListener( window.addOnFrameMetricsAvailableListener(frameMetricsAvailableListener, handler); } - @RequiresApi(api = Build.VERSION_CODES.N) default void removeOnFrameMetricsAvailableListener( final @NotNull Window window, final @Nullable Window.OnFrameMetricsAvailableListener frameMetricsAvailableListener) { diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/performance/AppStartMetrics.java b/sentry-android-core/src/main/java/io/sentry/android/core/performance/AppStartMetrics.java index a23b9a8720b..e49bada831a 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/performance/AppStartMetrics.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/performance/AppStartMetrics.java @@ -550,28 +550,15 @@ private void scheduleHeadlessAppStartCheckOnMain() { if (!headlessAppStartCheckPending.compareAndSet(false, true)) { return; } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - Looper.getMainLooper() - .getQueue() - .addIdleHandler( - () -> { - firstIdle = SystemClock.uptimeMillis(); - headlessAppStartCheckPending.set(false); - handleHeadlessAppStartIfNeededOnMain(); - return false; - }); - } else { - final Handler handler = new Handler(Looper.getMainLooper()); - handler.post( - () -> { - firstIdle = SystemClock.uptimeMillis(); - handler.post( - () -> { - headlessAppStartCheckPending.set(false); - handleHeadlessAppStartIfNeededOnMain(); - }); - }); - } + Looper.getMainLooper() + .getQueue() + .addIdleHandler( + () -> { + firstIdle = SystemClock.uptimeMillis(); + headlessAppStartCheckPending.set(false); + handleHeadlessAppStartIfNeededOnMain(); + return false; + }); } /** diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidContinuousProfilerTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidContinuousProfilerTest.kt index b5b4b76e18a..386bbe04eb6 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidContinuousProfilerTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidContinuousProfilerTest.kt @@ -302,17 +302,6 @@ class AndroidContinuousProfilerTest { assertEquals(0, profiler.rootSpanCounter) } - @Test - fun `profiler works only on api 22+`() { - val buildInfo = - mock { - whenever(it.sdkInfoVersion).thenReturn(Build.VERSION_CODES.LOLLIPOP) - } - val profiler = fixture.getSut(buildInfo) - profiler.startProfiler(ProfileLifecycle.MANUAL, fixture.mockTracesSampler) - assertFalse(profiler.isRunning) - } - @Test fun `profiler evaluates profilingTracesDirPath options only on first start`() { val profiler = fixture.getSut { it.cacheDirPath = null } diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidTransactionProfilerTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidTransactionProfilerTest.kt index 1d2b3a78685..ca9939de84b 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidTransactionProfilerTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidTransactionProfilerTest.kt @@ -240,17 +240,6 @@ class AndroidTransactionProfilerTest { assertEquals(profilingTraceData.transactionId, fixture.transaction1.eventId.toString()) } - @Test - fun `profiler works only on api 22+`() { - val buildInfo = - mock { - whenever(it.sdkInfoVersion).thenReturn(Build.VERSION_CODES.LOLLIPOP) - } - val profiler = fixture.getSut(context, buildInfo) - profiler.start() - assertFalse(profiler.isRunning) - } - @Test fun `profiler on profilesSampleRate=0 false`() { fixture.options.apply { profilesSampleRate = 0.0 } diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/NetworkBreadcrumbsIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/NetworkBreadcrumbsIntegrationTest.kt index 711f5f7fe0b..8085189b029 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/NetworkBreadcrumbsIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/NetworkBreadcrumbsIntegrationTest.kt @@ -94,18 +94,6 @@ class NetworkBreadcrumbsIntegrationTest { assertNull(sut.networkCallback) } - @Test - fun `It doesn't register callback if not on Android N+`() { - val buildInfo = mock() - whenever(buildInfo.sdkInfoVersion).thenReturn(Build.VERSION_CODES.M) - val sut = fixture.getSut(buildInfo = buildInfo) - - sut.register(fixture.scopes, fixture.options) - - assertTrue(AndroidConnectionStatusProvider.getChildCallbacks().isEmpty()) - assertNull(sut.networkCallback) - } - @Test fun `When NetworkBreadcrumbsIntegration is closed, it should unregister the callback`() { val sut = fixture.getSut() diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProviderTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProviderTest.kt index 56a2a12928c..d534ba436d3 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProviderTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProviderTest.kt @@ -662,17 +662,6 @@ class AndroidConnectionStatusProviderTest { ) } - @Test - fun `API level below M falls back to legacy method`() { - whenever(buildInfo.sdkInfoVersion).thenReturn(Build.VERSION_CODES.LOLLIPOP) - whenever(networkInfo.isConnected).thenReturn(true) - - assertEquals( - IConnectionStatusProvider.ConnectionStatus.CONNECTED, - connectionStatusProvider.connectionStatus, - ) - } - @Test fun `onCapabilitiesChanged updates cache`() { whenever(buildInfo.sdkInfoVersion).thenReturn(Build.VERSION_CODES.N) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/CellularNetworkTechnologyProviderTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/CellularNetworkTechnologyProviderTest.kt index 4bf1d7de427..29047ee304e 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/CellularNetworkTechnologyProviderTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/CellularNetworkTechnologyProviderTest.kt @@ -335,14 +335,6 @@ class CellularNetworkTechnologyProviderTest { assertThat(provider.cellularNetworkTechnology).isNull() } - @Test - fun `below Android 7 the technology is not read because getDataNetworkType is unavailable`() { - val provider = fixture.getSut(sdkVersion = Build.VERSION_CODES.M, hasPermission = true) - - assertThat(provider.cellularNetworkTechnology).isNull() - verify(fixture.telephonyManager, never()).dataNetworkType - } - @Test fun `below Android 12 registering does nothing`() { val provider = fixture.getSut(sdkVersion = Build.VERSION_CODES.R) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollectorTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollectorTest.kt index 334ce229066..fbd944b7dcf 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollectorTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollectorTest.kt @@ -117,15 +117,6 @@ class SentryFrameMetricsCollectorTest { } } - @Test - fun `collector works only on api 24+`() { - val buildInfo = - mock { whenever(it.sdkInfoVersion).thenReturn(Build.VERSION_CODES.M) } - val collector = fixture.getSut(context, buildInfo) - val id = collector.startCollection(mock()) - assertNull(id) - } - @Test fun `collector works only if context is instance of Application`() { val collector = fixture.getSut(mock()) @@ -611,9 +602,7 @@ class SentryFrameMetricsCollectorTest { @Test fun `getFramesDelay returns -1 when not available`() { - val buildInfo = - mock { whenever(it.sdkInfoVersion).thenReturn(Build.VERSION_CODES.M) } - val collector = fixture.getSut(context, buildInfo) + val collector = fixture.getSut(mock()) val result = collector.getFramesDelay(0, TimeUnit.SECONDS.toNanos(1)) assertEquals(-1.0, result.delaySeconds) diff --git a/sentry-android-ndk/build.gradle.kts b/sentry-android-ndk/build.gradle.kts index 9fd7dce011a..dbfeeec5550 100644 --- a/sentry-android-ndk/build.gradle.kts +++ b/sentry-android-ndk/build.gradle.kts @@ -45,8 +45,6 @@ android { lint { warningsAsErrors = true checkDependencies = true - // TODO: Re-enable once the SDK_INT checks made obsolete by minSdk 24 are removed. - disable += "ObsoleteSdkInt" // 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 11e47e113fb..7794e32c55e 100644 --- a/sentry-android-replay/build.gradle.kts +++ b/sentry-android-replay/build.gradle.kts @@ -56,8 +56,6 @@ android { lint { warningsAsErrors = true checkDependencies = true - // TODO: Re-enable once the SDK_INT checks made obsolete by minSdk 24 are removed. - disable += "ObsoleteSdkInt" // 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/main/java/io/sentry/android/replay/Windows.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/Windows.kt index e81c815dc11..4f8f6cabf58 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/Windows.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/Windows.kt @@ -123,7 +123,6 @@ internal class RootViewsSpy private constructor() : Closeable { private val delegatingViewList: ArrayList = object : ArrayList() { - @Suppress("NewApi") override fun addAll(elements: Collection): Boolean { listeners.forEach { listener -> elements.forEach { element -> listener.onRootViewsChanged(element, true) } @@ -131,13 +130,11 @@ internal class RootViewsSpy private constructor() : Closeable { return super.addAll(elements) } - @Suppress("NewApi") override fun add(element: View): Boolean { listeners.forEach { it.onRootViewsChanged(element, true) } return super.add(element) } - @Suppress("NewApi") override fun removeAt(index: Int): View { val removedView = super.removeAt(index) listeners.forEach { it.onRootViewsChanged(removedView, false) } @@ -191,7 +188,7 @@ internal object WindowManagerSpy { } // You can discourage me all you want I'll still do it. - @SuppressLint("PrivateApi", "ObsoleteSdkInt", "DiscouragedPrivateApi") + @SuppressLint("PrivateApi", "DiscouragedPrivateApi") fun swapWindowManagerGlobalMViews(swap: (ArrayList) -> ArrayList) { try { windowManagerInstance?.let { windowManagerInstance -> diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/CaptureStrategy.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/CaptureStrategy.kt index fc8b8d13065..ddd9f840c4c 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/CaptureStrategy.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/CaptureStrategy.kt @@ -141,7 +141,6 @@ internal interface CaptureStrategy { ) } - @Suppress("NewApi") private fun buildReplay( options: SentryOptions, video: File, @@ -277,7 +276,6 @@ internal interface CaptureStrategy { scopes?.captureReplay(replay, hint.apply { replayRecording = recording }) } - @Suppress("NewApi") fun setSegmentId(segmentId: Int) { replay.segmentId = segmentId recording.payload?.forEach { diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/CanvasStrategy.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/CanvasStrategy.kt index 6956782cc27..f40d8c8cc5f 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/CanvasStrategy.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/CanvasStrategy.kt @@ -72,7 +72,6 @@ internal class CanvasStrategy( IntegrationUtils.addIntegrationToSdkVersion("ReplayCanvasStrategy") } - @SuppressLint("NewApi") private val pictureRenderTask = Runnable { if (isClosed.get()) { options.logger.log( @@ -152,7 +151,6 @@ internal class CanvasStrategy( } } - @SuppressLint("NewApi") override fun capture(root: View) { if (isClosed.get()) { return diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/PixelCopyStrategy.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/PixelCopyStrategy.kt index 06be58e19de..4672e7dbfbc 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/PixelCopyStrategy.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/PixelCopyStrategy.kt @@ -222,7 +222,6 @@ internal class PixelCopyStrategy( } } - @SuppressLint("NewApi") private fun captureSurfaceViews( root: View, surfaceViewNodes: List, diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/util/FixedWindowCallback.java b/sentry-android-replay/src/main/java/io/sentry/android/replay/util/FixedWindowCallback.java index 7245eefabed..59593e1fad1 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/util/FixedWindowCallback.java +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/util/FixedWindowCallback.java @@ -189,7 +189,6 @@ public boolean onSearchRequested() { return delegate.onSearchRequested(); } - @SuppressLint("NewApi") @Override public boolean onSearchRequested(SearchEvent searchEvent) { if (delegate == null) { @@ -207,7 +206,6 @@ public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) { return delegate.onWindowStartingActionMode(callback); } - @SuppressLint("NewApi") @Nullable @Override public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) { @@ -233,7 +231,6 @@ public void onActionModeFinished(ActionMode mode) { delegate.onActionModeFinished(mode); } - @SuppressLint("NewApi") @Override public void onProvideKeyboardShortcuts( List data, @Nullable Menu menu, int deviceId) { diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/util/Views.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/util/Views.kt index cacd2b1c217..a70dafbc3b9 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/util/Views.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/util/Views.kt @@ -1,7 +1,6 @@ package io.sentry.android.replay.util import android.annotation.SuppressLint -import android.annotation.TargetApi import android.graphics.Point import android.graphics.Rect import android.graphics.drawable.BitmapDrawable @@ -105,8 +104,6 @@ internal fun View.isVisibleToUser(): Pair { return false to null } -@SuppressLint("ObsoleteSdkInt", "UseRequiresApi") -@TargetApi(21) internal fun Drawable?.isMaskable(): Boolean { // TODO: maybe find a way how to check if the drawable is coming from the apk or loaded from // network 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 b1e3cd20513..e8b77b0994c 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 @@ -349,8 +349,6 @@ internal fun shouldUseSoftwareCanvas(): Boolean = Build.HARDWARE.contains("goldfish", ignoreCase = true) || Build.HARDWARE.contains("ranchu", ignoreCase = true) -@SuppressLint("UseRequiresApi") -@TargetApi(24) internal data class MuxerConfig( val file: File, var recordingWidth: Int, From 671dfce8a6815c4a13e5212954c366fd8ed66e0a Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Tue, 10 Nov 2026 08:49:51 +0100 Subject: [PATCH 5/5] fix(replay): Update detekt baseline for the removed NewApi suppression The baseline keys buildReplay by its signature, which included the @Suppress("NewApi") annotation removed in #6519. Co-Authored-By: Claude Opus 5.5 --- sentry-android-replay/detekt-baseline.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sentry-android-replay/detekt-baseline.xml b/sentry-android-replay/detekt-baseline.xml index 8432d83f8dd..0567ebb5521 100644 --- a/sentry-android-replay/detekt-baseline.xml +++ b/sentry-android-replay/detekt-baseline.xml @@ -8,7 +8,7 @@ ComplexCondition:ReplayIntegration.kt$ReplayIntegration$state.get().captureStrategy is SessionCaptureStrategy && (lastKnownConnectionStatus == DISCONNECTED || scopes?.rateLimiter?.isActiveForCategory(All) == true || scopes?.rateLimiter?.isActiveForCategory(Replay) == true) ComplexCondition:ScreenshotRecorder.kt$ScreenshotRecorder$root == null || root.width <= 0 || root.height <= 0 || !root.isShown ComplexCondition:SimpleVideoEncoder.kt$SimpleVideoEncoder$Build.MANUFACTURER.contains("xiaomi", ignoreCase = true) || Build.MANUFACTURER.contains("motorola", ignoreCase = true) || SystemProperties.get(SystemProperties.Property.SOC_MANUFACTURER) .equals("spreadtrum", ignoreCase = true) || SystemProperties.get(SystemProperties.Property.SOC_MANUFACTURER) .equals("unisoc", ignoreCase = true) - CyclomaticComplexMethod:CaptureStrategy.kt$CaptureStrategy.Companion$@Suppress("NewApi") private fun buildReplay( options: SentryOptions, video: File, currentReplayId: SentryId, segmentTimestamp: Date, segmentId: Int, height: Int, width: Int, frameCount: Int, frameRate: Int, videoDuration: Long, replayType: ReplayType, screenAtStart: String?, breadcrumbs: List<Breadcrumb>, events: Deque<RRWebEvent>, traceIds: List<String>, segmentNames: List<String>, ): ReplaySegment + CyclomaticComplexMethod:CaptureStrategy.kt$CaptureStrategy.Companion$private fun buildReplay( options: SentryOptions, video: File, currentReplayId: SentryId, segmentTimestamp: Date, segmentId: Int, height: Int, width: Int, frameCount: Int, frameRate: Int, videoDuration: Long, replayType: ReplayType, screenAtStart: String?, breadcrumbs: List<Breadcrumb>, events: Deque<RRWebEvent>, traceIds: List<String>, segmentNames: List<String>, ): ReplaySegment CyclomaticComplexMethod:ComposeViewHierarchyNode.kt$ComposeViewHierarchyNode$private fun fromComposeNode( node: LayoutNode, parent: ViewHierarchyNode?, distance: Int, isComposeRoot: Boolean, options: SentryMaskingOptions, logger: ILogger, ): ViewHierarchyNode? CyclomaticComplexMethod:DefaultReplayBreadcrumbConverter.kt$DefaultReplayBreadcrumbConverter$override fun convert(breadcrumb: Breadcrumb): RRWebEvent? CyclomaticComplexMethod:DefaultReplayBreadcrumbConverter.kt$DefaultReplayBreadcrumbConverter$private fun Breadcrumb.toRRWebSpanEvent(): RRWebSpanEvent @@ -45,7 +45,7 @@ LargeClass:CanvasStrategy.kt$TextIgnoringDelegateCanvas : Canvas LargeClass:ReplayCacheTest.kt$ReplayCacheTest LargeClass:ReplayIntegrationTest.kt$ReplayIntegrationTest - LongMethod:CaptureStrategy.kt$CaptureStrategy.Companion$@Suppress("NewApi") private fun buildReplay( options: SentryOptions, video: File, currentReplayId: SentryId, segmentTimestamp: Date, segmentId: Int, height: Int, width: Int, frameCount: Int, frameRate: Int, videoDuration: Long, replayType: ReplayType, screenAtStart: String?, breadcrumbs: List<Breadcrumb>, events: Deque<RRWebEvent>, traceIds: List<String>, segmentNames: List<String>, ): ReplaySegment + LongMethod:CaptureStrategy.kt$CaptureStrategy.Companion$private fun buildReplay( options: SentryOptions, video: File, currentReplayId: SentryId, segmentTimestamp: Date, segmentId: Int, height: Int, width: Int, frameCount: Int, frameRate: Int, videoDuration: Long, replayType: ReplayType, screenAtStart: String?, breadcrumbs: List<Breadcrumb>, events: Deque<RRWebEvent>, traceIds: List<String>, segmentNames: List<String>, ): ReplaySegment LongMethod:ComposeViewHierarchyNode.kt$ComposeViewHierarchyNode$private fun fromComposeNode( node: LayoutNode, parent: ViewHierarchyNode?, distance: Int, isComposeRoot: Boolean, options: SentryMaskingOptions, logger: ILogger, ): ViewHierarchyNode? LongMethod:DefaultReplayBreadcrumbConverter.kt$DefaultReplayBreadcrumbConverter$override fun convert(breadcrumb: Breadcrumb): RRWebEvent? LongMethod:DefaultReplayBreadcrumbConverter.kt$DefaultReplayBreadcrumbConverter$private fun Breadcrumb.toRRWebSpanEvent(): RRWebSpanEvent @@ -103,7 +103,7 @@ MatchingDeclarationName:Persistable.kt$PersistableLinkedList : ConcurrentLinkedDeque MatchingDeclarationName:ReplayLifecycle.kt$ReplayLifecycleState MaxLineLength:ComposeMaskingOptionsTest.kt$ComposeMaskingOptionsTest$"Flaky: Robolectric intermittently reports zero bounds for nodes, causing isVisible=false and making the assertion non-deterministic" - NestedBlockDepth:CaptureStrategy.kt$CaptureStrategy.Companion$@Suppress("NewApi") private fun buildReplay( options: SentryOptions, video: File, currentReplayId: SentryId, segmentTimestamp: Date, segmentId: Int, height: Int, width: Int, frameCount: Int, frameRate: Int, videoDuration: Long, replayType: ReplayType, screenAtStart: String?, breadcrumbs: List<Breadcrumb>, events: Deque<RRWebEvent>, traceIds: List<String>, segmentNames: List<String>, ): ReplaySegment + NestedBlockDepth:CaptureStrategy.kt$CaptureStrategy.Companion$private fun buildReplay( options: SentryOptions, video: File, currentReplayId: SentryId, segmentTimestamp: Date, segmentId: Int, height: Int, width: Int, frameCount: Int, frameRate: Int, videoDuration: Long, replayType: ReplayType, screenAtStart: String?, breadcrumbs: List<Breadcrumb>, events: Deque<RRWebEvent>, traceIds: List<String>, segmentNames: List<String>, ): ReplaySegment NestedBlockDepth:DefaultReplayBreadcrumbConverter.kt$DefaultReplayBreadcrumbConverter$private fun Breadcrumb.toRRWebSpanEvent(): RRWebSpanEvent NestedBlockDepth:Nodes.kt$internal fun LayoutNode.findPainter(): Painter? NestedBlockDepth:Nodes.kt$internal fun LayoutNode.findTextColor(): Color?