Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,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 26. Apps with a lower `minSdk` must raise it or stay on 8.x ([#6435](https://github.com/getsentry/sentry-java/pull/6435))

## 8.62.0

Expand Down
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) | 26 |
| 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) | 26 |
| 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) | 26 |
| 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) | 26 |
| 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) | 26 |
| 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) | 26 |
| 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) | 26 |
| 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) | 26 |
| 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) | 26 |
| 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) | 26 |
| 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 |
Expand Down
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,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
Expand Down
5 changes: 5 additions & 0 deletions buildSrc/src/main/java/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 26, so builds that

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this is probably the only line that needs reviewing.

i also tried

  1. upgrading androidx.core
  2. adding a keep rule

but neither works. open to other ideas.

// 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 {
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ sqldelight = "2.3.2"
targetSdk = "37"
compileSdk = "37"
compileSdkMinor = "2"
minSdk = "21"
minSdk = "26"

[plugins]
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
Expand Down
2 changes: 2 additions & 0 deletions sentry-android-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ android {
lint {
warningsAsErrors = true
checkDependencies = true
// TODO(JAVA-547): Re-enable once the SDK_INT checks made obsolete by minSdk 26 are removed.
disable += "ObsoleteSdkInt"

// We run a full lint analysis as build part in CI, so skip vital checks for assemble tasks.
checkReleaseBuilds = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -703,33 +703,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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,22 +370,6 @@ class AndroidOptionsInitializerTest {
assertTrue(fixture.sentryOptions.transportGate is AndroidTransportGate)
}

@Config(sdk = [Build.VERSION_CODES.N_MR1])
@Test
fun `init on API 25 and lower sets SSLSocketFactory with bundled Sentry root CAs`() {
fixture.initSut(configureOptions = { dsn = SAAS_DSN })

assertIs<SentryRootCaSslSocketFactory>(fixture.sentryOptions.sslSocketFactory)
}

@Config(sdk = [Build.VERSION_CODES.N_MR1])
@Test
fun `init on API 25 and lower does not set SSLSocketFactory for self-hosted DSN`() {
fixture.initSut(configureOptions = { dsn = "https://key@sentry.example.com/1" })

assertNull(fixture.sentryOptions.sslSocketFactory)
}

@Config(sdk = [Build.VERSION_CODES.O])
@Test
fun `init on API 26 and higher does not set SSLSocketFactory`() {
Expand All @@ -394,20 +378,6 @@ class AndroidOptionsInitializerTest {
assertNull(fixture.sentryOptions.sslSocketFactory)
}

@Config(sdk = [Build.VERSION_CODES.N_MR1])
@Test
fun `init on API 25 and lower keeps user provided SSLSocketFactory`() {
val sslSocketFactory = mock<javax.net.ssl.SSLSocketFactory>()
fixture.initSut(
configureOptions = {
dsn = SAAS_DSN
this.sslSocketFactory = sslSocketFactory
}
)

assertEquals(sslSocketFactory, fixture.sentryOptions.sslSocketFactory)
}

@Test
fun `init should set Android continuous profiler`() {
fixture.initSut()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import org.mockito.kotlin.whenever
import org.robolectric.annotation.Config

@RunWith(AndroidJUnit4::class)
@Config(sdk = [Build.VERSION_CODES.N])
@Config(sdk = [Build.VERSION_CODES.O])
class AppStartExtensionTest {

private val metrics = mock<AppStartMetrics>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ class ScreenshotEventProcessorTest {
}

@Test
@Config(sdk = [23])
@Config(sdk = [26])
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ import org.robolectric.shadows.ShadowActivityManager.ApplicationExitInfoBuilder
import timber.log.Timber

@RunWith(AndroidJUnit4::class)
@Config(sdk = [Build.VERSION_CODES.N], shadows = [SentryShadowProcess::class])
@Config(sdk = [Build.VERSION_CODES.O], shadows = [SentryShadowProcess::class])
class SentryAndroidTest {
@get:Rule val tmpDir = TemporaryFolder()

Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import org.mockito.kotlin.whenever
import org.robolectric.annotation.Config

@RunWith(AndroidJUnit4::class)
@Config(sdk = [Build.VERSION_CODES.N], shadows = [SentryShadowProcess::class])
@Config(sdk = [Build.VERSION_CODES.O], shadows = [SentryShadowProcess::class])
class SentryPerformanceProviderTest {
private lateinit var cache: File
private lateinit var sentryCache: File
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Window>()
val activity = mock<Activity> { on { this.window } doReturn window }

val scopes = mock<IScopes>()
val options =
Expand All @@ -39,8 +37,8 @@ class SentryGestureListenerPeekDecorViewTest {
val sut = SentryGestureListener(activity, scopes, options)
sut.onSingleTapUp(mock<MotionEvent>())

// 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<Breadcrumb>(), anyOrNull())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import org.robolectric.Shadows
import org.robolectric.annotation.Config

@RunWith(AndroidJUnit4::class)
@Config(sdk = [Build.VERSION_CODES.N], shadows = [SentryShadowProcess::class])
@Config(sdk = [Build.VERSION_CODES.O], shadows = [SentryShadowProcess::class])
class AppStartMetricsTest {
@Before
fun setup() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
sdk=21
sdk=26
application=io.sentry.android.core.ApplicationStub
Original file line number Diff line number Diff line change
Expand Up @@ -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">
<!-- android:usesCleartextTraffic="true" is needed to send data to http://localhost... (the mock relay server) -->

<activity android:name=".EmptyActivity" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions sentry-android-ndk/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ android {
lint {
warningsAsErrors = true
checkDependencies = true
// TODO(JAVA-547): Re-enable once the SDK_INT checks made obsolete by minSdk 26 are removed.
disable += "ObsoleteSdkInt"

// We run a full lint analysis as build part in CI, so skip vital checks for assemble tasks.
checkReleaseBuilds = false
Expand Down
2 changes: 2 additions & 0 deletions sentry-android-replay/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ android {
lint {
warningsAsErrors = true
checkDependencies = true
// TODO(JAVA-547): Re-enable once the SDK_INT checks made obsolete by minSdk 26 are removed.
disable += "ObsoleteSdkInt"

// We run a full lint analysis as build part in CI, so skip vital checks for assemble tasks.
checkReleaseBuilds = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,16 +183,6 @@ class ReplayIntegrationTest {
SentryIntegrationPackageStorage.getInstance().clearStorage()
}

@Test
@Config(sdk = [24])
fun `when API is below 26, does not register`() {
val replay = fixture.getSut(context)

replay.register(fixture.scopes, fixture.options)

assertFalse(replay.isEnabled.get())
}

@Test
fun `when no sample rate is set, still registers`() {
val replay = fixture.getSut(context, 0.0, 0.0)
Expand Down
13 changes: 0 additions & 13 deletions sentry-android-sqlite/src/test/AndroidManifest.xml

This file was deleted.

3 changes: 1 addition & 2 deletions sentry-samples/sentry-samples-android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading