Skip to content

Commit c48b14f

Browse files
runningcodeclaude
andauthored
ref(feedback): Extend Dialog instead of AlertDialog in SentryUserFeedbackForm (#6338)
* 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 <noreply@anthropic.com> * changelog * changelog * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 8d690e6 commit c48b14f

4 files changed

Lines changed: 58 additions & 9 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
- Remove the deprecated `Instrumenter` enum, option, span context property, and `startChild` overloads ([#6252](https://github.com/getsentry/sentry-java/pull/6252))
4949
- Remove deprecated OpenTelemetry integration classes and the legacy `SentrySpanStorage` ([#6243](https://github.com/getsentry/sentry-java/pull/6243))
5050
- 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))
51+
- `SentryUserFeedbackForm` now extends `android.app.Dialog` instead of `android.app.AlertDialog` ([#6338](https://github.com/getsentry/sentry-java/pull/6338))
52+
- The form never used `AlertDialog` features. Code that calls `AlertDialog`-only methods on it, such as `setButton` or `setMessage`, no longer compiles.
5153

5254
## 8.62.0
5355

‎sentry-android-core/api/sentry-android-core.api‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ public abstract interface class io/sentry/android/core/SentryShakeDetector$Liste
576576
public abstract fun onShake ()V
577577
}
578578

579-
public class io/sentry/android/core/SentryUserFeedbackForm : android/app/AlertDialog {
579+
public class io/sentry/android/core/SentryUserFeedbackForm : android/app/Dialog {
580580
protected fun onCreate (Landroid/os/Bundle;)V
581581
public fun onDetachedFromWindow ()V
582582
protected fun onStart ()V

‎sentry-android-core/src/main/java/io/sentry/android/core/SentryUserFeedbackForm.java‎

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
package io.sentry.android.core;
22

33
import android.app.Activity;
4-
import android.app.AlertDialog;
54
import android.app.Application;
5+
import android.app.Dialog;
66
import android.content.ContentResolver;
77
import android.content.Context;
88
import android.content.ContextWrapper;
99
import android.database.Cursor;
1010
import android.net.Uri;
1111
import android.os.Bundle;
1212
import android.provider.OpenableColumns;
13+
import android.util.TypedValue;
1314
import android.view.View;
1415
import android.view.Window;
15-
import android.view.WindowManager;
1616
import android.webkit.MimeTypeMap;
1717
import android.widget.Button;
1818
import android.widget.EditText;
@@ -39,7 +39,7 @@
3939
import org.jetbrains.annotations.NotNull;
4040
import org.jetbrains.annotations.Nullable;
4141

42-
public class SentryUserFeedbackForm extends AlertDialog {
42+
public class SentryUserFeedbackForm extends Dialog {
4343

4444
private boolean isCancelable = false;
4545
private @Nullable SentryId currentReplayId;
@@ -60,7 +60,10 @@ public class SentryUserFeedbackForm extends AlertDialog {
6060
final @Nullable SentryId associatedEventId,
6161
final @Nullable OptionsConfiguration configuration,
6262
final @Nullable SentryFeedbackOptions.OptionsConfigurator configurator) {
63-
super(context, themeResId);
63+
super(context, resolveTheme(context, themeResId));
64+
// The form draws its own title. AlertDialog requested this for us; without it, themes that
65+
// don't set windowNoTitle, like Theme.Material.Dialog, add an empty system title bar.
66+
requestWindowFeature(Window.FEATURE_NO_TITLE);
6467
this.associatedEventId = associatedEventId;
6568
final @NotNull SentryOptions options = Sentry.getCurrentScopes().getOptions();
6669
@NotNull
@@ -211,6 +214,19 @@ public void onActivitySaveInstanceState(
211214
final @NotNull Activity activity, final @NotNull Bundle outState) {}
212215
}
213216

217+
/**
218+
* {@link Dialog} falls back to {@link android.R.attr#dialogTheme} for {@code 0}, but the form has
219+
* always defaulted to {@link android.R.attr#alertDialogTheme}, as {@code AlertDialog} does.
220+
*/
221+
static int resolveTheme(final @NotNull Context context, final int themeResId) {
222+
if (themeResId != 0) {
223+
return themeResId;
224+
}
225+
final @NotNull TypedValue outValue = new TypedValue();
226+
context.getTheme().resolveAttribute(android.R.attr.alertDialogTheme, outValue, true);
227+
return outValue.resourceId;
228+
}
229+
214230
@Override
215231
public void setCancelable(boolean cancelable) {
216232
super.setCancelable(cancelable);
@@ -222,10 +238,6 @@ public void setCancelable(boolean cancelable) {
222238
protected void onCreate(Bundle savedInstanceState) {
223239
super.onCreate(savedInstanceState);
224240
setContentView(R.layout.sentry_dialog_user_feedback);
225-
final @Nullable Window window = getWindow();
226-
if (window != null) {
227-
window.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
228-
}
229241
setCancelable(isCancelable);
230242

231243
final @NotNull SentryFeedbackOptions feedbackOptions = resolvedFeedbackOptions;

‎sentry-android-core/src/test/java/io/sentry/android/core/SentryUserFeedbackFormTest.kt‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import android.database.Cursor
1010
import android.net.Uri
1111
import android.os.Looper
1212
import android.provider.OpenableColumns
13+
import android.view.ContextThemeWrapper
1314
import android.view.View
15+
import android.view.Window
1416
import android.view.WindowManager
1517
import android.widget.Button
1618
import android.widget.EditText
@@ -244,6 +246,39 @@ class SentryUserFeedbackFormTest {
244246
assertEquals(0, flags and WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM)
245247
}
246248

249+
@Test
250+
fun `dialog window has no system title, even when the theme does not set windowNoTitle`() {
251+
fixture.options.isEnabled = true
252+
val sut =
253+
SentryUserFeedbackForm(
254+
fixture.application,
255+
android.R.style.Theme_Material_Dialog,
256+
null,
257+
null,
258+
null,
259+
)
260+
sut.show()
261+
val window = sut.window
262+
assertNotNull(window)
263+
assertThat(window.hasFeature(Window.FEATURE_NO_TITLE)).isTrue()
264+
}
265+
266+
@Test
267+
fun `default theme resolves to the context's alert dialog theme`() {
268+
val context = ContextThemeWrapper(fixture.application, android.R.style.Theme_Material_Light)
269+
270+
assertThat(SentryUserFeedbackForm.resolveTheme(context, 0))
271+
.isEqualTo(android.R.style.Theme_Material_Light_Dialog_Alert)
272+
}
273+
274+
@Test
275+
fun `explicit theme is used as is`() {
276+
val context = ContextThemeWrapper(fixture.application, android.R.style.Theme_Material_Light)
277+
278+
assertThat(SentryUserFeedbackForm.resolveTheme(context, android.R.style.Theme_Material_Dialog))
279+
.isEqualTo(android.R.style.Theme_Material_Dialog)
280+
}
281+
247282
@Test
248283
fun `a crashing onFormClose callback does not crash the app when the dialog is closed`() {
249284
fixture.options.isEnabled = true

0 commit comments

Comments
 (0)