diff --git a/.github/workflows/integration-tests-ui-critical.yml b/.github/workflows/integration-tests-ui-critical.yml index 77691bfd65b..e50cbbb38c3 100644 --- a/.github/workflows/integration-tests-ui-critical.yml +++ b/.github/workflows/integration-tests-ui-critical.yml @@ -89,17 +89,7 @@ jobs: sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm - - name: AVD cache - uses: actions/cache@v5 - id: avd-cache - with: - path: | - ~/.android/avd/* - ~/.android/adb* - key: avd-api-${{ matrix.api-level }}-${{ matrix.arch }}-${{ matrix.target }} - - name: Create AVD and generate snapshot for caching - if: steps.avd-cache.outputs.cache-hit != 'true' uses: reactivecircus/android-emulator-runner@b530d96654c385303d652368551fb075bc2f0b6b # pin@v2 with: api-level: ${{ matrix.api-level }} diff --git a/CHANGELOG.md b/CHANGELOG.md index ccff564763f..6346e67acc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,10 @@ - [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#0131) - [diff](https://github.com/getsentry/sentry-native/compare/0.12.7...0.13.1) +### Internal + +- Check notification permission before launching request to fix flaky API 34 tests ([#5146](https://github.com/getsentry/sentry-java/pull/5146)) + ## 8.33.0 ### Features diff --git a/sentry-android-integration-tests/sentry-uitest-android-critical/maestro/.maestro/config.yaml b/sentry-android-integration-tests/sentry-uitest-android-critical/maestro/.maestro/config.yaml index ebb5a3a8e6d..f50373791f3 100644 --- a/sentry-android-integration-tests/sentry-uitest-android-critical/maestro/.maestro/config.yaml +++ b/sentry-android-integration-tests/sentry-uitest-android-critical/maestro/.maestro/config.yaml @@ -1,3 +1,13 @@ platform: android: disableAnimations: true +onFlowStart: + # Dismiss any ANR dialog (e.g. "Pixel Launcher isn't responding") + - runFlow: + when: + visible: "Close app" + commands: + - tapOn: "Close app" + # Close notification shade if left open from a previous test + - pressKey: back + - pressKey: home diff --git a/sentry-android-integration-tests/sentry-uitest-android-critical/maestro/appStart.yaml b/sentry-android-integration-tests/sentry-uitest-android-critical/maestro/appStart.yaml index 7356bd4bf08..f7000b21a82 100644 --- a/sentry-android-integration-tests/sentry-uitest-android-critical/maestro/appStart.yaml +++ b/sentry-android-integration-tests/sentry-uitest-android-critical/maestro/appStart.yaml @@ -23,6 +23,12 @@ name: App Start Tests all: allow - assertVisible: "Welcome!" - tapOn: "Trigger Notification" +# Grant notification permission if the system dialog appears +- runFlow: + when: + visible: "Allow" + commands: + - tapOn: "Allow" - tapOn: "Finish Activity" - assertNotVisible: "Welcome!" - waitForAnimationToEnd @@ -45,6 +51,12 @@ name: App Start Tests all: allow - assertVisible: "Welcome!" - tapOn: "Trigger Notification" +# Grant notification permission if the system dialog appears +- runFlow: + when: + visible: "Allow" + commands: + - tapOn: "Allow" - tapOn: "Finish Activity" - assertNotVisible: "Welcome!" - killApp diff --git a/sentry-android-integration-tests/sentry-uitest-android-critical/src/main/java/io/sentry/uitest/android/critical/MainActivity.kt b/sentry-android-integration-tests/sentry-uitest-android-critical/src/main/java/io/sentry/uitest/android/critical/MainActivity.kt index f6b81c869ef..6b758173a89 100644 --- a/sentry-android-integration-tests/sentry-uitest-android-critical/src/main/java/io/sentry/uitest/android/critical/MainActivity.kt +++ b/sentry-android-integration-tests/sentry-uitest-android-critical/src/main/java/io/sentry/uitest/android/critical/MainActivity.kt @@ -1,6 +1,7 @@ package io.sentry.uitest.android.critical import android.content.Intent +import android.content.pm.PackageManager import android.os.Build import android.os.Bundle import android.widget.Toast @@ -22,6 +23,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import androidx.core.content.ContextCompat import io.sentry.Sentry import io.sentry.android.core.performance.AppStartMetrics import io.sentry.uitest.android.critical.NotificationHelper.showNotification @@ -82,7 +84,13 @@ class MainActivity : ComponentActivity() { Button(onClick = { finish() }) { Text("Finish Activity") } Button( onClick = { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if ( + Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && + ContextCompat.checkSelfPermission( + this@MainActivity, + android.Manifest.permission.POST_NOTIFICATIONS, + ) != PackageManager.PERMISSION_GRANTED + ) { requestPermissionLauncher.launch(android.Manifest.permission.POST_NOTIFICATIONS) } else { postNotification() @@ -91,6 +99,9 @@ class MainActivity : ComponentActivity() { ) { Text("Trigger Notification") } + Button(onClick = { android.os.Process.killProcess(android.os.Process.myPid()) }) { + Text("Kill Process") + } Button( onClick = { startActivity( diff --git a/sentry-android-integration-tests/sentry-uitest-android-critical/src/main/java/io/sentry/uitest/android/critical/NotificationHelper.kt b/sentry-android-integration-tests/sentry-uitest-android-critical/src/main/java/io/sentry/uitest/android/critical/NotificationHelper.kt index 4cbaede1b7f..197fc378a39 100644 --- a/sentry-android-integration-tests/sentry-uitest-android-critical/src/main/java/io/sentry/uitest/android/critical/NotificationHelper.kt +++ b/sentry-android-integration-tests/sentry-uitest-android-critical/src/main/java/io/sentry/uitest/android/critical/NotificationHelper.kt @@ -19,7 +19,10 @@ object NotificationHelper { context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Create notification channel for Android 8.0+ (API 26+) + // Delete first to ensure the channel is recreated with the correct importance, + // since Android preserves channel settings across app reinstalls (adb install -r). if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationManager.deleteNotificationChannel(CHANNEL_ID) val channel = NotificationChannel(CHANNEL_ID, "Notifications", NotificationManager.IMPORTANCE_DEFAULT) channel.description = "description"