From 58dbfcb27c6edf11720b77133af0c3c6f24433f1 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Wed, 21 Oct 2026 09:35:59 +0200 Subject: [PATCH 1/4] ref(feedback): Extend Dialog instead of AlertDialog in SentryUserFeedbackForm The form never used AlertDialog's title, message, buttons or custom view; it replaces the content with its own layout in onCreate. Dialog falls back to dialogTheme for theme 0, while AlertDialog uses alertDialogTheme, so the form now resolves alertDialogTheme itself to keep the default look unchanged. The FLAG_ALT_FOCUSABLE_IM workaround goes away because only AlertDialog set that flag. Resolves JAVA-494 Co-Authored-By: Claude Opus 5.5 --- .../api/sentry-android-core.api | 2 +- .../android/core/SentryUserFeedbackForm.java | 26 ++++++++++++------- .../core/SentryUserFeedbackFormTest.kt | 17 ++++++++++++ 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/sentry-android-core/api/sentry-android-core.api b/sentry-android-core/api/sentry-android-core.api index 3e37f1fc39..5be86ecdda 100644 --- a/sentry-android-core/api/sentry-android-core.api +++ b/sentry-android-core/api/sentry-android-core.api @@ -576,7 +576,7 @@ public abstract interface class io/sentry/android/core/SentryShakeDetector$Liste public abstract fun onShake ()V } -public class io/sentry/android/core/SentryUserFeedbackForm : android/app/AlertDialog { +public class io/sentry/android/core/SentryUserFeedbackForm : android/app/Dialog { protected fun onCreate (Landroid/os/Bundle;)V public fun onDetachedFromWindow ()V protected fun onStart ()V diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SentryUserFeedbackForm.java b/sentry-android-core/src/main/java/io/sentry/android/core/SentryUserFeedbackForm.java index 7da33575de..b3e012020d 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SentryUserFeedbackForm.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SentryUserFeedbackForm.java @@ -1,8 +1,8 @@ package io.sentry.android.core; import android.app.Activity; -import android.app.AlertDialog; import android.app.Application; +import android.app.Dialog; import android.content.ContentResolver; import android.content.Context; import android.content.ContextWrapper; @@ -10,9 +10,8 @@ import android.net.Uri; import android.os.Bundle; import android.provider.OpenableColumns; +import android.util.TypedValue; import android.view.View; -import android.view.Window; -import android.view.WindowManager; import android.webkit.MimeTypeMap; import android.widget.Button; import android.widget.EditText; @@ -39,7 +38,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class SentryUserFeedbackForm extends AlertDialog { +public class SentryUserFeedbackForm extends Dialog { private boolean isCancelable = false; private @Nullable SentryId currentReplayId; @@ -60,7 +59,7 @@ public class SentryUserFeedbackForm extends AlertDialog { final @Nullable SentryId associatedEventId, final @Nullable OptionsConfiguration configuration, final @Nullable SentryFeedbackOptions.OptionsConfigurator configurator) { - super(context, themeResId); + super(context, resolveTheme(context, themeResId)); this.associatedEventId = associatedEventId; final @NotNull SentryOptions options = Sentry.getCurrentScopes().getOptions(); @NotNull @@ -211,6 +210,19 @@ public void onActivitySaveInstanceState( final @NotNull Activity activity, final @NotNull Bundle outState) {} } + /** + * {@link Dialog} falls back to {@link android.R.attr#dialogTheme} for {@code 0}, but the form has + * always defaulted to {@link android.R.attr#alertDialogTheme}, as {@code AlertDialog} does. + */ + static int resolveTheme(final @NotNull Context context, final int themeResId) { + if (themeResId != 0) { + return themeResId; + } + final @NotNull TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(android.R.attr.alertDialogTheme, outValue, true); + return outValue.resourceId; + } + @Override public void setCancelable(boolean cancelable) { super.setCancelable(cancelable); @@ -222,10 +234,6 @@ public void setCancelable(boolean cancelable) { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sentry_dialog_user_feedback); - final @Nullable Window window = getWindow(); - if (window != null) { - window.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - } setCancelable(isCancelable); final @NotNull SentryFeedbackOptions feedbackOptions = resolvedFeedbackOptions; 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 19414515b8..86e7367bd7 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 @@ -10,6 +10,7 @@ import android.database.Cursor import android.net.Uri import android.os.Looper import android.provider.OpenableColumns +import android.view.ContextThemeWrapper import android.view.View import android.view.WindowManager import android.widget.Button @@ -244,6 +245,22 @@ class SentryUserFeedbackFormTest { assertEquals(0, flags and WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) } + @Test + fun `default theme resolves to the context's alert dialog theme`() { + 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) + } + + @Test + fun `explicit theme is used as is`() { + val context = ContextThemeWrapper(fixture.application, android.R.style.Theme_Material_Light) + + assertThat(SentryUserFeedbackForm.resolveTheme(context, android.R.style.Theme_Material_Dialog)) + .isEqualTo(android.R.style.Theme_Material_Dialog) + } + @Test fun `a crashing onFormClose callback does not crash the app when the dialog is closed`() { fixture.options.isEnabled = true From adc7f954ae8bb388569ae82b4afacd6d5c476e22 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Wed, 21 Oct 2026 09:36:11 +0200 Subject: [PATCH 2/4] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9aee0cfa25..09da568dce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,8 @@ - Support Navigation 3 integration for multi-Activity and multi-Fragment applications, where each Activity or Fragment has its own `SentryNavEffect` ([#6305](https://github.com/getsentry/sentry-java/pull/6305)) - See the [Navigation for Android docs](https://docs.sentry.io/platforms/android/integrations/navigation/#supported-setups) for a detailed list of supported vs unsupported app setups. +- `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. ### Fixes From fb8022ffe007aef1e6903c3fab647248a5cc1b9c Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Tue, 27 Oct 2026 13:02:54 +0100 Subject: [PATCH 3/4] changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09da568dce..32ec823ea7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,8 @@ `logsEnabled` argument. Pass `false` to keep Sentry Logs disabled. - Remove the Apache HttpClient transport and stop publishing `sentry-apache-http-client-5` ([#6214](https://github.com/getsentry/sentry-java/pull/6214)) - 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. ## 8.62.0 @@ -50,8 +52,6 @@ - Support Navigation 3 integration for multi-Activity and multi-Fragment applications, where each Activity or Fragment has its own `SentryNavEffect` ([#6305](https://github.com/getsentry/sentry-java/pull/6305)) - See the [Navigation for Android docs](https://docs.sentry.io/platforms/android/integrations/navigation/#supported-setups) for a detailed list of supported vs unsupported app setups. -- `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. ### Fixes From 3ab3f75477f466dd249dd49bce49772806e41a3f Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Wed, 28 Oct 2026 17:14:01 +0100 Subject: [PATCH 4/4] fix(feedback): Request no window title in SentryUserFeedbackForm AlertDialog always requested FEATURE_NO_TITLE because it draws its own title. Plain Dialog does not, so themes that don't set windowNoTitle, like Theme.Material.Dialog, added an empty system title bar above the form's own title. Co-Authored-By: Claude Opus 5.5 --- .../android/core/SentryUserFeedbackForm.java | 4 ++++ .../android/core/SentryUserFeedbackFormTest.kt | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SentryUserFeedbackForm.java b/sentry-android-core/src/main/java/io/sentry/android/core/SentryUserFeedbackForm.java index b3e012020d..999fad1227 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SentryUserFeedbackForm.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SentryUserFeedbackForm.java @@ -12,6 +12,7 @@ import android.provider.OpenableColumns; import android.util.TypedValue; import android.view.View; +import android.view.Window; import android.webkit.MimeTypeMap; import android.widget.Button; import android.widget.EditText; @@ -60,6 +61,9 @@ public class SentryUserFeedbackForm extends Dialog { final @Nullable OptionsConfiguration configuration, final @Nullable SentryFeedbackOptions.OptionsConfigurator configurator) { super(context, resolveTheme(context, themeResId)); + // The form draws its own title. AlertDialog requested this for us; without it, themes that + // don't set windowNoTitle, like Theme.Material.Dialog, add an empty system title bar. + requestWindowFeature(Window.FEATURE_NO_TITLE); this.associatedEventId = associatedEventId; final @NotNull SentryOptions options = Sentry.getCurrentScopes().getOptions(); @NotNull 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 86e7367bd7..840a0772a7 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 @@ -12,6 +12,7 @@ import android.os.Looper import android.provider.OpenableColumns import android.view.ContextThemeWrapper import android.view.View +import android.view.Window import android.view.WindowManager import android.widget.Button import android.widget.EditText @@ -245,6 +246,23 @@ class SentryUserFeedbackFormTest { assertEquals(0, flags and WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) } + @Test + fun `dialog window has no system title, even when the theme does not set windowNoTitle`() { + fixture.options.isEnabled = true + val sut = + SentryUserFeedbackForm( + fixture.application, + android.R.style.Theme_Material_Dialog, + null, + null, + null, + ) + sut.show() + val window = sut.window + assertNotNull(window) + assertThat(window.hasFeature(Window.FEATURE_NO_TITLE)).isTrue() + } + @Test fun `default theme resolves to the context's alert dialog theme`() { val context = ContextThemeWrapper(fixture.application, android.R.style.Theme_Material_Light)