Bug 1979277 - Fix Set to default switch from Settings. r=android-reviewers,alastun,twhite

Issue: The switch Set as default browser from settings doesn't do anything when the set as default prompt is blocked by the system or the browser is already set as default.

  Changes:
   - Use maybeRequestDefaultBrowserPrompt instead of activity?.openSetDefaultBrowserOption().
   - modify the function maybeNavigateToSystemSetToDefaultAction to redirect the user device settings when either the set as default prompt was blocked or when the browser is already set as default, but it's not a checklist flow.
   - rename shouldNavigateToAppSettingsLauncher to wasPromptBlockedBySystem.

Differential Revision: https://phabricator.services.mozilla.com/D291100
This commit is contained in:
RebecaTudor
2026-04-27 15:20:41 +00:00
committed by rtudor@mozilla.com
parent 5b0bd23c7d
commit c71b18e655
3 changed files with 43 additions and 14 deletions
@@ -299,9 +299,10 @@ class HomeFragment : Fragment(), SystemInsetsPaddedFragment {
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
with(requireContext()) {
maybeNavigateToSystemSetToDefaultAction(
result.resultCode,
settings(),
dateTimeProvider,
resultCode = result.resultCode,
settings = settings(),
dateTimeProvider = dateTimeProvider,
isChecklistTask = true,
) {
navigateToDefaultBrowserAppsSettings(BuildManufacturerChecker())
}
@@ -38,6 +38,8 @@ private const val MINIMUM_INTERACTION_DURATION_MS = 300
* @param settings The [Settings] instance used to access and reset the prompt timestamp.
* @param dateTimeProvider A provider used to retrieve the current system time, allowing for consistent
* time calculations and easier unit testing.
* @param isChecklistTask A boolean flag indicating whether it's triggered from a checklist flow.
* When true and the browser is already set as default, we avoid redirecting the user to device settings.
* @param navigationAction A lambda function that executes the navigation to the system's default
* app settings screen.
*/
@@ -45,14 +47,18 @@ fun maybeNavigateToSystemSetToDefaultAction(
resultCode: Int,
settings: Settings,
dateTimeProvider: DateTimeProvider,
isChecklistTask: Boolean = false,
navigationAction: () -> Unit,
) {
if (shouldNavigateToAppSettingsLauncher(
resultCode,
settings.setToDefaultPromptRequested,
dateTimeProvider,
)
) {
val promptBlockedBySystem = wasPromptBlockedBySystem(
resultCode,
settings.setToDefaultPromptRequested,
dateTimeProvider,
)
val isEligibleForAppSettingsNavigation = settings.isDefaultBrowser && !isChecklistTask
val shouldNavigateToAppSettingsLauncher = promptBlockedBySystem || isEligibleForAppSettingsNavigation
if (shouldNavigateToAppSettingsLauncher) {
navigationAction()
}
@@ -110,10 +116,9 @@ fun maybeRequestDefaultBrowserPrompt(
* displayed, used to calculate the interaction duration.
* @param dateTimeProvider A provider used to retrieve the current system time, allowing for consistent
* time calculations and easier unit testing.
* @return True if the prompt was likely blocked by the system (detected by a very short interaction time)
* or if the user explicitly accepted the prompt, indicating a need for further configuration in Settings.
* @return True if the prompt was likely blocked by system.
*/
private fun shouldNavigateToAppSettingsLauncher(
private fun wasPromptBlockedBySystem(
resultCode: Int,
promptRequestTimestamp: Long,
dateTimeProvider: DateTimeProvider,
@@ -6,12 +6,15 @@ package org.mozilla.fenix.settings
import android.annotation.SuppressLint
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.VisibleForTesting
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.edit
@@ -41,6 +44,10 @@ import mozilla.components.feature.addons.ui.AddonFilePicker
import mozilla.components.service.fxrelay.eligibility.Eligible
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
import mozilla.components.support.ktx.android.view.showKeyboard
import mozilla.components.support.utils.BuildManufacturerChecker
import mozilla.components.support.utils.DateTimeProvider
import mozilla.components.support.utils.DefaultDateTimeProvider
import mozilla.components.support.utils.ext.navigateToDefaultBrowserAppsSettings
import mozilla.components.ui.widgets.withCenterAlignedButtons
import mozilla.telemetry.glean.private.NoExtras
import org.mozilla.fenix.Config
@@ -51,6 +58,7 @@ import org.mozilla.fenix.GleanMetrics.Events
import org.mozilla.fenix.GleanMetrics.SettingsSearch
import org.mozilla.fenix.GleanMetrics.TrackingProtection
import org.mozilla.fenix.GleanMetrics.Translations
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.components.Components
import org.mozilla.fenix.components.accounts.FenixFxAEntryPoint
@@ -61,11 +69,12 @@ import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.getPreferenceKey
import org.mozilla.fenix.ext.navigateToNotificationsSettings
import org.mozilla.fenix.ext.openInNewTab
import org.mozilla.fenix.ext.openSetDefaultBrowserOption
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.ext.showToolbar
import org.mozilla.fenix.ext.showToolbarWithIconButton
import org.mozilla.fenix.home.maybeNavigateToSystemSetToDefaultAction
import org.mozilla.fenix.home.maybeRequestDefaultBrowserPrompt
import org.mozilla.fenix.nimbus.FxNimbus
import org.mozilla.fenix.perf.ProfilerViewModel
import org.mozilla.fenix.perf.ProfilerViewModelFactory
@@ -73,6 +82,7 @@ import org.mozilla.fenix.settings.account.AccountUiView
import org.mozilla.fenix.snackbar.FenixSnackbarDelegate
import org.mozilla.fenix.snackbar.SnackbarBinding
import org.mozilla.fenix.utils.Settings
import java.lang.ref.WeakReference
import kotlin.system.exitProcess
import mozilla.components.ui.icons.R as iconsR
import org.mozilla.fenix.GleanMetrics.Settings as SettingsMetrics
@@ -91,6 +101,7 @@ class SettingsFragment : PreferenceFragmentCompat(), SystemInsetsPaddedFragment
ProfilerViewModelFactory(requireActivity().application)
}
private val snackbarBinding = ViewBoundFeatureWrapper<SnackbarBinding>()
private val dateTimeProvider: DateTimeProvider by lazy { DefaultDateTimeProvider() }
@VisibleForTesting
internal val accountObserver = object : AccountObserver {
@@ -643,6 +654,15 @@ class SettingsFragment : PreferenceFragmentCompat(), SystemInsetsPaddedFragment
setupEmailMaskPreference(settings, requireComponents)
}
private val setToDefaultPromptRequestLauncher: ActivityResultLauncher<Intent> =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
with(requireContext()) {
maybeNavigateToSystemSetToDefaultAction(result.resultCode, settings(), dateTimeProvider) {
navigateToDefaultBrowserAppsSettings(BuildManufacturerChecker())
}
}
}
/**
* For >=Q -> Use new RoleManager API to show in-app browser switching dialog.
* For <Q && >=N -> Navigate user to Android Default Apps Settings.
@@ -650,7 +670,10 @@ class SettingsFragment : PreferenceFragmentCompat(), SystemInsetsPaddedFragment
*/
private fun getClickListenerForMakeDefaultBrowser(): Preference.OnPreferenceClickListener {
return Preference.OnPreferenceClickListener {
activity?.openSetDefaultBrowserOption()
maybeRequestDefaultBrowserPrompt(
WeakReference((requireActivity() as? HomeActivity)),
setToDefaultPromptRequestLauncher,
)
true
}
}