diff --git a/CHANGELOG.md b/CHANGELOG.md index 9aee0cfa25..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 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..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 @@ -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,9 @@ 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 +39,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 +60,10 @@ 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)); + // 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 @@ -211,6 +214,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 +238,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..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 @@ -10,7 +10,9 @@ 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.Window import android.view.WindowManager import android.widget.Button import android.widget.EditText @@ -244,6 +246,39 @@ 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) + + 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