From 4d8253d281c036d99e2ae861e3d9318004960117 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Mon, 6 Jul 2026 16:49:17 +0200 Subject: [PATCH] fix(samples): Add back navigation to secondary Android sample screens Secondary screens in the Android sample had no way to navigate back. XML AppCompat activities now enable the ActionBar up arrow (setDisplayHomeAsUpEnabled + onSupportNavigateUp); Compose activities get a Material3 TopAppBar with a back arrow. Also fix SecondActivity: it (and MainActivity's launcher) called finish() before startActivity, removing MainActivity from the back stack so system back exited the app. It now stays on the stack and back returns to Main. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../samples/android/CameraXActivity.java | 9 + .../android/DetachAttachTabsActivity.kt | 6 + .../android/FrameDataForSpansActivity.kt | 56 ++-- .../samples/android/GesturesActivity.kt | 6 + .../io/sentry/samples/android/MainActivity.kt | 5 +- .../samples/android/PermissionsActivity.kt | 6 + .../android/ReplayAnimationsActivity.kt | 27 +- .../sentry/samples/android/SecondActivity.kt | 13 +- .../samples/android/ThirdActivityFragment.kt | 6 + .../android/TriggerHttpRequestActivity.java | 9 + .../android/compose/ComposeActivity.kt | 25 +- .../samples/android/sqlite/SQLiteActivity.kt | 241 ++++++++++-------- .../samples/android/sqlite/UiLoadActivity.kt | 34 ++- 13 files changed, 303 insertions(+), 140 deletions(-) diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/CameraXActivity.java b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/CameraXActivity.java index b8c0491459f..49d80d876a5 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/CameraXActivity.java +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/CameraXActivity.java @@ -42,6 +42,9 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityCameraxBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); + if (getSupportActionBar() != null) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } previewView = binding.previewView; @@ -57,6 +60,12 @@ protected void onCreate(Bundle savedInstanceState) { binding.backButton.setOnClickListener(view -> finish()); } + @Override + public boolean onSupportNavigateUp() { + getOnBackPressedDispatcher().onBackPressed(); + return true; + } + private void startCamera() { cameraProviderFuture = ProcessCameraProvider.getInstance(this); cameraProviderFuture.addListener( diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/DetachAttachTabsActivity.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/DetachAttachTabsActivity.kt index 3a38814c5d8..07225d40b9d 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/DetachAttachTabsActivity.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/DetachAttachTabsActivity.kt @@ -25,6 +25,12 @@ class DetachAttachTabsActivity : AppCompatActivity(R.layout.activity_detach_atta detach(tabB) } } + supportActionBar?.setDisplayHomeAsUpEnabled(true) + } + + override fun onSupportNavigateUp(): Boolean { + onBackPressedDispatcher.onBackPressed() + return true } private fun showTab(index: Int) { diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/FrameDataForSpansActivity.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/FrameDataForSpansActivity.kt index 2eb995dbcf1..c96a5ac1394 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/FrameDataForSpansActivity.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/FrameDataForSpansActivity.kt @@ -20,11 +20,18 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ProvideTextStyle +import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableIntState import androidx.compose.runtime.mutableIntStateOf @@ -44,29 +51,42 @@ class FrameDataForSpansActivity : ComponentActivity() { private val model = ViewModel() private var txn: ITransaction? = null + @OptIn(ExperimentalMaterial3Api::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MaterialTheme { - Surface { - val infiniteTransition = rememberInfiniteTransition(label = "infiniteTransition") - val progress = - infiniteTransition.animateFloat( - label = "progress", - initialValue = 0f, - targetValue = 1f, - animationSpec = - infiniteRepeatable(animation = tween(1000), repeatMode = RepeatMode.Reverse), + Scaffold( + topBar = { + TopAppBar( + title = { Text("Frame Data for Spans") }, + navigationIcon = { + IconButton(onClick = { onBackPressedDispatcher.onBackPressed() }) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + }, ) - Column(modifier = Modifier.padding(24.dp)) { - Text(text = "Frame Data for Spans", style = MaterialTheme.typography.headlineMedium) - LinearProgressIndicator(progress = progress.value, modifier = Modifier.fillMaxWidth()) - Spacer(modifier = Modifier.size(24.dp)) - Text(text = "Tap to trigger a new frame render") - FrameControls(model) - Spacer(modifier = Modifier.size(24.dp)) - Text(text = "Span Control") - SpanControls(model) + } + ) { innerPadding -> + Surface(modifier = Modifier.padding(innerPadding)) { + val infiniteTransition = rememberInfiniteTransition(label = "infiniteTransition") + val progress = + infiniteTransition.animateFloat( + label = "progress", + initialValue = 0f, + targetValue = 1f, + animationSpec = + infiniteRepeatable(animation = tween(1000), repeatMode = RepeatMode.Reverse), + ) + Column(modifier = Modifier.padding(24.dp)) { + LinearProgressIndicator(progress = progress.value, modifier = Modifier.fillMaxWidth()) + Spacer(modifier = Modifier.size(24.dp)) + Text(text = "Tap to trigger a new frame render") + FrameControls(model) + Spacer(modifier = Modifier.size(24.dp)) + Text(text = "Span Control") + SpanControls(model) + } } } } diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/GesturesActivity.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/GesturesActivity.kt index ab30d001250..0027f8075d9 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/GesturesActivity.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/GesturesActivity.kt @@ -43,6 +43,12 @@ class GesturesActivity : AppCompatActivity() { binding.scrollingCrash.setOnClickListener { throw RuntimeException("Uncaught Exception") } setContentView(binding.root) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + } + + override fun onSupportNavigateUp(): Boolean { + onBackPressedDispatcher.onBackPressed() + return true } override fun onResume() { diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/MainActivity.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/MainActivity.kt index 9fdcaafb008..360758862b5 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/MainActivity.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/MainActivity.kt @@ -499,10 +499,7 @@ fun TracingScreen() { item { SentryTraced("open_second_activity") { OutlinedButton( - onClick = { - activity.finish() - activity.startActivity(Intent(activity, SecondActivity::class.java)) - }, + onClick = { activity.startActivity(Intent(activity, SecondActivity::class.java)) }, modifier = Modifier, ) { Text("Open Second Activity", maxLines = 2, overflow = TextOverflow.Ellipsis) diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/PermissionsActivity.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/PermissionsActivity.kt index 60a57ba88e2..c38c649b0cd 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/PermissionsActivity.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/PermissionsActivity.kt @@ -37,6 +37,12 @@ class PermissionsActivity : AppCompatActivity() { } setContentView(binding.root) + supportActionBar?.setDisplayHomeAsUpEnabled(true) Sentry.reportFullyDisplayed() } + + override fun onSupportNavigateUp(): Boolean { + onBackPressedDispatcher.onBackPressed() + return true + } } diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/ReplayAnimationsActivity.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/ReplayAnimationsActivity.kt index 0fe6cda581f..9fb38bb36dd 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/ReplayAnimationsActivity.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/ReplayAnimationsActivity.kt @@ -33,10 +33,17 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable @@ -65,6 +72,7 @@ import kotlin.math.roundToInt import kotlin.math.sin class ReplayAnimationsActivity : ComponentActivity() { + @OptIn(ExperimentalMaterial3Api::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -77,7 +85,24 @@ class ReplayAnimationsActivity : ComponentActivity() { else lightColorScheme(primary = primaryColor, secondary = accentColor, tertiary = primaryColor) - MaterialTheme(colorScheme = colorScheme) { ReplayAnimationsScreen(onClose = { finish() }) } + MaterialTheme(colorScheme = colorScheme) { + Scaffold( + topBar = { + TopAppBar( + title = { Text("Replay Animations") }, + navigationIcon = { + IconButton(onClick = { onBackPressedDispatcher.onBackPressed() }) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + }, + ) + } + ) { innerPadding -> + Box(modifier = Modifier.padding(innerPadding)) { + ReplayAnimationsScreen(onClose = { finish() }) + } + } + } } } } diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/SecondActivity.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/SecondActivity.kt index d46573855d6..cc23fc15300 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/SecondActivity.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/SecondActivity.kt @@ -1,6 +1,5 @@ package io.sentry.samples.android -import android.content.Intent import android.os.Bundle import android.view.View import androidx.appcompat.app.AppCompatActivity @@ -26,18 +25,22 @@ class SecondActivity : AppCompatActivity() { binding.doRequest.setOnClickListener { updateRepos() } - binding.backMain.setOnClickListener { - finish() - startActivity(Intent(this, MainActivity::class.java)) - } + binding.backMain.setOnClickListener { finish() } // do some stuff setContentView(binding.root) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + span?.finish(SpanStatus.OK) } + override fun onSupportNavigateUp(): Boolean { + onBackPressedDispatcher.onBackPressed() + return true + } + private fun showText(visible: Boolean = true, text: String = "") { binding.text.text = if (visible) text else "" binding.text.visibility = if (visible) View.VISIBLE else View.GONE diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/ThirdActivityFragment.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/ThirdActivityFragment.kt index 39dbde791c0..294e5e27053 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/ThirdActivityFragment.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/ThirdActivityFragment.kt @@ -17,5 +17,11 @@ class ThirdActivityFragment : AppCompatActivity(R.layout.activity_third_fragment add(R.id.fragment_container_view, args = bundle) } } + supportActionBar?.setDisplayHomeAsUpEnabled(true) + } + + override fun onSupportNavigateUp(): Boolean { + onBackPressedDispatcher.onBackPressed() + return true } } diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/TriggerHttpRequestActivity.java b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/TriggerHttpRequestActivity.java index 5671a044437..f3141db3bbb 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/TriggerHttpRequestActivity.java +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/TriggerHttpRequestActivity.java @@ -52,6 +52,9 @@ public class TriggerHttpRequestActivity extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_trigger_http_request); + if (getSupportActionBar() != null) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } dateFormat = new SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault()); @@ -60,6 +63,12 @@ protected void onCreate(Bundle savedInstanceState) { setupClickListeners(); } + @Override + public boolean onSupportNavigateUp() { + getOnBackPressedDispatcher().onBackPressed(); + return true; + } + private void initializeViews() { urlInput = findViewById(R.id.url_input); requestDisplay = findViewById(R.id.request_display); diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/compose/ComposeActivity.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/compose/ComposeActivity.kt index b27da13c770..5b4c31d1a92 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/compose/ComposeActivity.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/compose/ComposeActivity.kt @@ -10,6 +10,7 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -17,14 +18,20 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.AlertDialogDefaults import androidx.compose.material3.BasicAlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextField +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -60,12 +67,28 @@ import kotlinx.coroutines.launch class ComposeActivity : ComponentActivity() { + @OptIn(ExperimentalMaterial3Api::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val navController = rememberNavController().withSentryObservableEffect() - SampleNavigation(navController) + MaterialTheme { + Scaffold( + topBar = { + TopAppBar( + title = { Text("Compose") }, + navigationIcon = { + IconButton(onClick = { onBackPressedDispatcher.onBackPressed() }) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + }, + ) + } + ) { innerPadding -> + Box(modifier = Modifier.padding(innerPadding)) { SampleNavigation(navController) } + } + } } } } diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/sqlite/SQLiteActivity.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/sqlite/SQLiteActivity.kt index 54334b6e407..947fbfe7cb1 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/sqlite/SQLiteActivity.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/sqlite/SQLiteActivity.kt @@ -25,16 +25,19 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.PlainTooltip +import androidx.compose.material3.Scaffold import androidx.compose.material3.SegmentedButton import androidx.compose.material3.SegmentedButtonDefaults import androidx.compose.material3.SingleChoiceSegmentedButtonRow @@ -45,6 +48,7 @@ import androidx.compose.material3.SwitchDefaults import androidx.compose.material3.Text import androidx.compose.material3.TooltipBox import androidx.compose.material3.TooltipDefaults +import androidx.compose.material3.TopAppBar import androidx.compose.material3.rememberTooltipState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -289,133 +293,150 @@ class SQLiteActivity : ComponentActivity() { */ private var screenTraceHeader = newScreenTrace() + @OptIn(ExperimentalMaterial3Api::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MaterialTheme { - Surface { - Column( - modifier = - Modifier.fillMaxWidth() - .statusBarsPadding() - .padding(16.dp) - .verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - val screenHeightDp = LocalConfiguration.current.screenHeightDp - // A small gap below the screen title that grows with screen height and collapses to 0 - // on short screens, so the title isn't crowded against "Configure it" on tall devices. - val titleGap = - (((((screenHeightDp / 4) - 48) / 3).coerceAtLeast(0).dp + TOGGLE_SECTION_GAP) / 2 - - SECTION_HEADER_HEIGHT) - .coerceAtLeast(0.dp) - - // Pulse the "Under the hood" outline in the integration color whenever a tap runs SQL. - val shimmer = remember { Animatable(0f) } - LaunchedEffect(runTick) { - if (runTick == 0) return@LaunchedEffect - shimmer.animateTo( - targetValue = 0f, - animationSpec = - keyframes { - durationMillis = 900 - 0f at 0 - 1f at 200 - 0.4f at 450 - 1f at 650 - 0f at 900 - }, - ) - } + Scaffold( + topBar = { + TopAppBar( + title = { Text("SQLite") }, + navigationIcon = { + IconButton(onClick = { onBackPressedDispatcher.onBackPressed() }) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + }, + ) + } + ) { innerPadding -> + Surface(modifier = Modifier.padding(innerPadding)) { + Column( + modifier = + Modifier.fillMaxWidth() + .statusBarsPadding() + .padding(16.dp) + .verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + val screenHeightDp = LocalConfiguration.current.screenHeightDp + // A small gap below the screen title that grows with screen height and collapses to 0 + // on short screens, so the title isn't crowded against "Configure it" on tall + // devices. + val titleGap = + (((((screenHeightDp / 4) - 48) / 3).coerceAtLeast(0).dp + TOGGLE_SECTION_GAP) / 2 - + SECTION_HEADER_HEIGHT) + .coerceAtLeast(0.dp) + + // Pulse the "Under the hood" outline in the integration color whenever a tap runs + // SQL. + val shimmer = remember { Animatable(0f) } + LaunchedEffect(runTick) { + if (runTick == 0) return@LaunchedEffect + shimmer.animateTo( + targetValue = 0f, + animationSpec = + keyframes { + durationMillis = 900 + 0f at 0 + 1f at 200 + 0.4f at 450 + 1f at 650 + 0f at 900 + }, + ) + } - val detailOutline = - lerp(MaterialTheme.colorScheme.outline, integration.color, shimmer.value) + val detailOutline = + lerp(MaterialTheme.colorScheme.outline, integration.color, shimmer.value) - Text(text = "SQLite Instrumentation", style = MaterialTheme.typography.headlineSmall) - SagpBuildPill() + Text(text = "SQLite Instrumentation", style = MaterialTheme.typography.headlineSmall) + SagpBuildPill() - Spacer(Modifier.height(titleGap)) + Spacer(Modifier.height(titleGap)) - SectionHeader("Configure it") + SectionHeader("Configure it") - val controlSwitchColors = - SwitchDefaults.colors( - checkedTrackColor = Color.Black, - checkedBorderColor = Color.Black, + val controlSwitchColors = + SwitchDefaults.colors( + checkedTrackColor = Color.Black, + checkedBorderColor = Color.Black, + ) + IntegrationModeSelector( + selected = integration, + onSelected = { + integration = it + sqlDetail = SQL_DETAIL_HINT + latestResult = "" + }, ) - IntegrationModeSelector( - selected = integration, - onSelected = { - integration = it - sqlDetail = SQL_DETAIL_HINT - latestResult = "" - }, - ) - ToggleRow( - label = if (heavyWork) "Heavy app-level work" else "No app-level work", - checked = heavyWork, - switchColors = controlSwitchColors, - ) { - heavyWork = it - } - ToggleRow( - label = - if (shareScreenTrace) "Single trace for all button clicks" - else "Separate trace per button click", - checked = shareScreenTrace, - switchColors = controlSwitchColors, - ) { - shareScreenTrace = it - } + ToggleRow( + label = if (heavyWork) "Heavy app-level work" else "No app-level work", + checked = heavyWork, + switchColors = controlSwitchColors, + ) { + heavyWork = it + } + ToggleRow( + label = + if (shareScreenTrace) "Single trace for all button clicks" + else "Separate trace per button click", + checked = shareScreenTrace, + switchColors = controlSwitchColors, + ) { + shareScreenTrace = it + } - SectionHeader("Run it", topPadding = CONTROL_SECTION_GAP) { HelpTooltip() } - - // One consolidated list of demo buttons. Each row dispatches to the selected - // integration's variant; a row that doesn't apply explains why via a toast (see - // [DemoRowButton]). - DEMO_ROWS.forEach { row -> - val variant = row.variantFor(integration) - DemoRowButton( - label = row.label, - color = integration.color, - variant = variant, - sagpDisabledReason = sagpDisabledReason(integration, row), - disabledReason = "${row.label} doesn't support the ${integration.apiName} stack", - ) - } + SectionHeader("Run it", topPadding = CONTROL_SECTION_GAP) { HelpTooltip() } + + // One consolidated list of demo buttons. Each row dispatches to the selected + // integration's variant; a row that doesn't apply explains why via a toast (see + // [DemoRowButton]). + DEMO_ROWS.forEach { row -> + val variant = row.variantFor(integration) + DemoRowButton( + label = row.label, + color = integration.color, + variant = variant, + sagpDisabledReason = sagpDisabledReason(integration, row), + disabledReason = "${row.label} doesn't support the ${integration.apiName} stack", + ) + } - ResetButton( - dbOperationInFlight = dbOperationInFlight, - resetInProgress = resetInProgress, - ) + ResetButton( + dbOperationInFlight = dbOperationInFlight, + resetInProgress = resetInProgress, + ) - // Same [CONTROL_SECTION_GAP] above as the other sections, separating the controls from - // the detail output. - SectionHeader("Under the hood", topPadding = CONTROL_SECTION_GAP) - LaunchedEffect(Unit) { - while (!SampleDatabases.isWarmUpComplete()) { + // Same [CONTROL_SECTION_GAP] above as the other sections, separating the controls + // from + // the detail output. + SectionHeader("Under the hood", topPadding = CONTROL_SECTION_GAP) + LaunchedEffect(Unit) { + while (!SampleDatabases.isWarmUpComplete()) { + warmUpErrors = SampleDatabases.warmUpErrors + delay(250) + } warmUpErrors = SampleDatabases.warmUpErrors - delay(250) } - warmUpErrors = SampleDatabases.warmUpErrors - } - if (warmUpErrors.isNotEmpty()) { - Text( - text = warmUpErrors, - style = MaterialTheme.typography.bodyMedium, - color = SentryRed, - ) - } - // The latest run result (row counts, errors). Hidden until the first run. - if (latestResult.isNotEmpty()) { - Text( - text = latestResult, - style = MaterialTheme.typography.bodyMedium, - color = if (latestResult.looksLikeError()) SentryRed else Color.Unspecified, - ) + if (warmUpErrors.isNotEmpty()) { + Text( + text = warmUpErrors, + style = MaterialTheme.typography.bodyMedium, + color = SentryRed, + ) + } + // The latest run result (row counts, errors). Hidden until the first run. + if (latestResult.isNotEmpty()) { + Text( + text = latestResult, + style = MaterialTheme.typography.bodyMedium, + color = if (latestResult.looksLikeError()) SentryRed else Color.Unspecified, + ) + } + DetailField("SQL run", sqlDetail, borderColor = detailOutline) } - DetailField("SQL run", sqlDetail, borderColor = detailOutline) } } } diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/sqlite/UiLoadActivity.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/sqlite/UiLoadActivity.kt index 3cc6d394daa..9c2a5693410 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/sqlite/UiLoadActivity.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/sqlite/UiLoadActivity.kt @@ -6,9 +6,21 @@ import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier import androidx.lifecycle.lifecycleScope import io.sentry.Sentry import kotlinx.coroutines.Dispatchers @@ -28,6 +40,7 @@ class UiLoadActivity : ComponentActivity() { private var status by mutableStateOf("Running under the screen's auto ui.load transaction…") + @OptIn(ExperimentalMaterial3Api::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -39,7 +52,26 @@ class UiLoadActivity : ComponentActivity() { } val heavy = intent.getBooleanExtra(EXTRA_HEAVY, false) - setContent { UiLoadScreen(status = status, onClose = ::finish) } + setContent { + MaterialTheme { + Scaffold( + topBar = { + TopAppBar( + title = { Text("UI Load") }, + navigationIcon = { + IconButton(onClick = { onBackPressedDispatcher.onBackPressed() }) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + }, + ) + } + ) { innerPadding -> + Box(modifier = Modifier.padding(innerPadding)) { + UiLoadScreen(status = status, onClose = ::finish) + } + } + } + } // No Sentry.startTransaction(): the work runs under the auto ui.load:UiLoadActivity span. lifecycleScope.launch {