tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit bad4051d3ab19b35c8c4402b5a6cb57f066f8b00
parent a7b3748dfc3d43ff7c8f32b8b6299fdb153e0c10
Author: mcarare <48995920+mcarare@users.noreply.github.com>
Date:   Tue,  2 Dec 2025 07:48:03 +0000

Bug 2003023 - Refactor manual CoroutineScope usage to lifecycle-aware scopes. r=android-reviewers,giorga

This patch removes the manual implementation of `CoroutineScope` and manual `Job` management from several Fragments and FocusApplication.

Specific changes include:
*   Migrating Fragments to use `viewLifecycleOwner.lifecycleScope` for coroutine launching, removing the need for manual job cancellation in `onPause`/`onStop`.
*   Replacing `GlobalScope` and manual scope usage in `FocusApplication` with a dedicated `applicationScope` backed by a `SupervisorJob`.
*   Updating `DomainListAdapter` to use `suspend` functions for data operations, delegating the scope execution to the caller.
*   Switching context to `Dispatchers.IO` for database and IO operations.

Differential Revision: https://phabricator.services.mozilla.com/D274433

Diffstat:
Mmobile/android/focus-android/app/src/main/java/org/mozilla/focus/FocusApplication.kt | 27+++++++++++++++------------
Mmobile/android/focus-android/app/src/main/java/org/mozilla/focus/autocomplete/AutocompleteAddFragment.kt | 45+++++++++++++++++++--------------------------
Mmobile/android/focus-android/app/src/main/java/org/mozilla/focus/autocomplete/AutocompleteListFragment.kt | 63+++++++++++++++++++++++++++++++--------------------------------
Mmobile/android/focus-android/app/src/main/java/org/mozilla/focus/autocomplete/AutocompleteRemoveFragment.kt | 31+++++++++++--------------------
Mmobile/android/focus-android/app/src/main/java/org/mozilla/focus/exceptions/ExceptionsListFragment.kt | 20++++----------------
Mmobile/android/focus-android/app/src/main/java/org/mozilla/focus/exceptions/ExceptionsRemoveFragment.kt | 4++--
Mmobile/android/focus-android/app/src/main/java/org/mozilla/focus/search/SearchEngineListPreference.kt | 20+++++++-------------
Mmobile/android/focus-android/app/src/main/java/org/mozilla/focus/searchsuggestions/ui/SearchSuggestionsFragment.kt | 22++++------------------
Mmobile/android/focus-android/quality/detekt-baseline.xml | 3---
9 files changed, 93 insertions(+), 142 deletions(-)

diff --git a/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/FocusApplication.kt b/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/FocusApplication.kt @@ -15,10 +15,8 @@ import androidx.lifecycle.ProcessLifecycleOwner import androidx.work.Configuration.Builder import androidx.work.Configuration.Provider import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import mozilla.components.support.AppServicesInitializer import mozilla.components.support.base.facts.register @@ -38,13 +36,14 @@ import org.mozilla.focus.session.VisibilityLifeCycleCallback import org.mozilla.focus.telemetry.FactsProcessor import org.mozilla.focus.telemetry.ProfilerMarkerFactProcessor import org.mozilla.focus.utils.AppConstants -import kotlin.coroutines.CoroutineContext import mozilla.components.support.AppServicesInitializer.Config as AppServiceConfig -open class FocusApplication : LocaleAwareApplication(), Provider, CoroutineScope { - private var job = Job() - override val coroutineContext: CoroutineContext - get() = job + Dispatchers.Main +/** + * Focus application class. + */ +open class FocusApplication : LocaleAwareApplication(), Provider { + + protected val applicationScope = CoroutineScope(Dispatchers.Main + SupervisorJob()) open val components: Components by lazy { Components(this) } @@ -54,7 +53,6 @@ open class FocusApplication : LocaleAwareApplication(), Provider, CoroutineScope private val storeLink by lazy { StoreLink(components.appStore, components.store) } private val lockObserver by lazy { LockObserver(this, components.store, components.appStore) } - @OptIn(DelicateCoroutinesApi::class) override fun onCreate() { super.onCreate() @@ -91,7 +89,8 @@ open class FocusApplication : LocaleAwareApplication(), Provider, CoroutineScope components.startupActivityLog.registerInAppOnCreate(this) ProcessLifecycleOwner.get().lifecycle.addObserver(lockObserver) - GlobalScope.launch(Dispatchers.IO) { + + applicationScope.launch { // Remove stale temporary uploaded files. components.fileUploadsDirCleaner.cleanUploadsDirectory() } @@ -107,6 +106,11 @@ open class FocusApplication : LocaleAwareApplication(), Provider, CoroutineScope // no-op, LeakCanary is disabled by default } + /** + * Updates the configuration of LeakCanary based on the provided state. + * + * @param isEnabled Whether LeakCanary features should be enabled. + */ open fun updateLeakCanaryState(isEnabled: Boolean) { // no-op, LeakCanary is disabled by default } @@ -151,10 +155,9 @@ open class FocusApplication : LocaleAwareApplication(), Provider, CoroutineScope /** * Finish Megazord setup sequence. */ - @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage @OpenForTesting open fun finishSetupMegazord() { - GlobalScope.launch(Dispatchers.IO) { + applicationScope.launch(Dispatchers.IO) { // We need to use an unwrapped client because native components do not support private // requests. @Suppress("Deprecation") diff --git a/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/autocomplete/AutocompleteAddFragment.kt b/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/autocomplete/AutocompleteAddFragment.kt @@ -12,11 +12,10 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.Dispatchers.Main -import kotlinx.coroutines.Job +import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import mozilla.components.browser.domains.CustomDomains import mozilla.components.support.ktx.android.view.hideKeyboard import mozilla.components.support.ktx.android.view.showKeyboard @@ -28,25 +27,17 @@ import org.mozilla.focus.ext.showToolbar import org.mozilla.focus.settings.BaseSettingsLikeFragment import org.mozilla.focus.state.AppAction import org.mozilla.focus.utils.ViewUtils -import kotlin.coroutines.CoroutineContext /** * Fragment showing settings UI to add custom autocomplete domains. */ -class AutocompleteAddFragment : BaseSettingsLikeFragment(), CoroutineScope { - private var job = Job() - override val coroutineContext: CoroutineContext - get() = job + Main +class AutocompleteAddFragment : BaseSettingsLikeFragment() { + private var _binding: FragmentAutocompleteAddDomainBinding? = null private val binding get() = _binding!! override fun onResume() { super.onResume() - - if (job.isCancelled) { - job = Job() - } - showToolbar(getString(R.string.preference_autocomplete_title_add)) } @@ -65,7 +56,6 @@ class AutocompleteAddFragment : BaseSettingsLikeFragment(), CoroutineScope { } override fun onPause() { - job.cancel() activity?.currentFocus?.hideKeyboard() super.onPause() } @@ -83,20 +73,21 @@ class AutocompleteAddFragment : BaseSettingsLikeFragment(), CoroutineScope { R.id.save -> { val domain = binding.domainView.text.toString().trim() - launch(IO) { - val domains = CustomDomains.load(requireActivity()) + viewLifecycleOwner.lifecycleScope.launch { + val domains = withContext(Dispatchers.IO) { + CustomDomains.load(requireActivity()) + } + val error = when { domain.isEmpty() -> getString(R.string.preference_autocomplete_add_error) domains.contains(domain) -> getString(R.string.preference_autocomplete_duplicate_url_error) else -> null } - launch(Main) { - if (error != null) { - binding.domainView.error = error - } else { - saveDomainAndClose(requireActivity().applicationContext, domain) - } + if (error != null) { + binding.domainView.error = error + } else { + saveDomainAndClose(requireActivity().applicationContext, domain) } } true @@ -106,9 +97,11 @@ class AutocompleteAddFragment : BaseSettingsLikeFragment(), CoroutineScope { } private fun saveDomainAndClose(context: Context, domain: String) { - launch(IO) { - CustomDomains.add(context, domain) - Autocomplete.domainAdded.add() + viewLifecycleOwner.lifecycleScope.launch { + withContext(Dispatchers.IO) { + CustomDomains.add(context, domain) + Autocomplete.domainAdded.add() + } } ViewUtils.showBrandedSnackbar(view, R.string.preference_autocomplete_add_confirmation, 0) diff --git a/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/autocomplete/AutocompleteListFragment.kt b/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/autocomplete/AutocompleteListFragment.kt @@ -18,15 +18,13 @@ import android.widget.TextView import androidx.annotation.LayoutRes import androidx.core.content.ContextCompat import androidx.core.view.isVisible +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper.SimpleCallback import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.Dispatchers.Main -import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import mozilla.components.browser.domains.CustomDomains @@ -40,17 +38,13 @@ import org.mozilla.focus.state.AppAction import org.mozilla.focus.state.Screen import org.mozilla.focus.utils.ViewUtils import java.util.Collections -import kotlin.coroutines.CoroutineContext typealias DomainFormatter = (String) -> String /** * Fragment showing settings UI listing all custom autocomplete domains entered by the user. */ -open class AutocompleteListFragment : BaseSettingsLikeFragment(), CoroutineScope { - private var job = Job() - override val coroutineContext: CoroutineContext - get() = job + Main +open class AutocompleteListFragment : BaseSettingsLikeFragment() { private var _binding: FragmentAutocompleteCustomdomainsBinding? = null protected val binding get() = _binding!! @@ -67,7 +61,9 @@ open class AutocompleteListFragment : BaseSettingsLikeFragment(), CoroutineScope val from = viewHolder.bindingAdapterPosition val to = target.bindingAdapterPosition - (recyclerView.adapter as DomainListAdapter).move(from, to) + viewLifecycleOwner.lifecycleScope.launch { + (recyclerView.adapter as DomainListAdapter).move(requireContext(), from, to) + } return true } @@ -146,19 +142,16 @@ open class AutocompleteListFragment : BaseSettingsLikeFragment(), CoroutineScope override fun onResume() { super.onResume() - if (job.isCancelled) { - job = Job() - } - showToolbar(getString(R.string.preference_autocomplete_subitem_manage_sites)) - (binding.domainList.adapter as DomainListAdapter).refresh(requireActivity()) { - activity?.invalidateOptionsMenu() + viewLifecycleOwner.lifecycleScope.launch { + (binding.domainList.adapter as DomainListAdapter).refresh(requireActivity()) { + activity?.invalidateOptionsMenu() + } } } override fun onPause() { - job.cancel() super.onPause() } @@ -200,20 +193,22 @@ open class AutocompleteListFragment : BaseSettingsLikeFragment(), CoroutineScope private val domains: MutableList<String> = mutableListOf() private val selectedDomains: MutableList<String> = mutableListOf() - fun refresh(context: Context, body: (() -> Unit)? = null) { - launch(Main) { - val updatedDomains = - withContext(Dispatchers.Default) { - CustomDomains.load(context) - } + internal suspend fun refresh( + context: Context, + ioDispatcher: CoroutineDispatcher = Dispatchers.IO, + body: (() -> Unit)? = null, + ) { + val updatedDomains = + withContext(ioDispatcher) { + CustomDomains.load(context) + } - domains.clear() - domains.addAll(updatedDomains) + domains.clear() + domains.addAll(updatedDomains) - notifyDataSetChanged() + notifyDataSetChanged() - body?.invoke() - } + body?.invoke() } override fun getItemViewType(position: Int) = @@ -256,14 +251,18 @@ open class AutocompleteListFragment : BaseSettingsLikeFragment(), CoroutineScope } } - fun selection(): List<String> = selectedDomains + internal fun selection(): List<String> = selectedDomains - fun move(from: Int, to: Int) { + internal suspend fun move( + context: Context, + from: Int, to: Int, + ioDispatcher: CoroutineDispatcher = Dispatchers.IO, + ) { Collections.swap(domains, from, to) notifyItemMoved(from, to) - launch(IO) { - CustomDomains.save(activity!!.applicationContext, domains) + withContext(ioDispatcher) { + CustomDomains.save(context, domains) Autocomplete.listOrderChanged.add() } } diff --git a/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/autocomplete/AutocompleteRemoveFragment.kt b/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/autocomplete/AutocompleteRemoveFragment.kt @@ -8,10 +8,8 @@ import android.content.Context import android.view.Menu import android.view.MenuInflater import android.view.MenuItem -import kotlinx.coroutines.CoroutineScope +import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Dispatchers.Main -import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import mozilla.components.browser.domains.CustomDomains @@ -20,12 +18,15 @@ import org.mozilla.focus.R import org.mozilla.focus.ext.requireComponents import org.mozilla.focus.ext.showToolbar import org.mozilla.focus.state.AppAction -import kotlin.coroutines.CoroutineContext -class AutocompleteRemoveFragment : AutocompleteListFragment(), CoroutineScope { - private var job = Job() - override val coroutineContext: CoroutineContext - get() = job + Main +/** + * A Fragment that allows the user to select and remove custom autocomplete domains. + * + * This fragment extends [AutocompleteListFragment] to display the list of domains but operates + * in a selection mode, allowing the user to pick specific items to delete from the [CustomDomains] storage. + * It inflates a specific menu containing a removal action and handles the deletion logic asynchronously. + */ +class AutocompleteRemoveFragment : AutocompleteListFragment() { override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { menuInflater.inflate(R.menu.menu_autocomplete_remove, menu) @@ -42,8 +43,8 @@ class AutocompleteRemoveFragment : AutocompleteListFragment(), CoroutineScope { private fun removeSelectedDomains(context: Context) { val domains = (binding.domainList.adapter as DomainListAdapter).selection() if (domains.isNotEmpty()) { - launch(Main) { - withContext(Dispatchers.Default) { + viewLifecycleOwner.lifecycleScope.launch { + withContext(Dispatchers.IO) { CustomDomains.remove(context, domains) Autocomplete.domainRemoved.add() } @@ -59,16 +60,6 @@ class AutocompleteRemoveFragment : AutocompleteListFragment(), CoroutineScope { override fun onResume() { super.onResume() - - if (job.isCancelled) { - job = Job() - } - showToolbar(getString(R.string.preference_autocomplete_title_remove)) } - - override fun onPause() { - job.cancel() - super.onPause() - } } diff --git a/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/exceptions/ExceptionsListFragment.kt b/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/exceptions/ExceptionsListFragment.kt @@ -18,13 +18,11 @@ import android.widget.TextView import androidx.annotation.LayoutRes import androidx.core.content.ContextCompat import androidx.core.view.isVisible +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper.SimpleCallback import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.launch import mozilla.components.concept.engine.content.blocking.TrackingProtectionException import org.mozilla.focus.GleanMetrics.TrackingProtectionExceptions @@ -39,7 +37,6 @@ import org.mozilla.focus.state.AppAction import org.mozilla.focus.state.Screen import org.mozilla.focus.utils.ViewUtils import java.util.Collections -import kotlin.coroutines.CoroutineContext private const val REMOVE_EXCEPTIONS_DISABLED_ALPHA = 0.5f typealias DomainFormatter = (String) -> String @@ -47,10 +44,8 @@ typealias DomainFormatter = (String) -> String /** * Fragment showing settings UI listing all exception domains. */ -open class ExceptionsListFragment : BaseSettingsLikeFragment(), CoroutineScope { - private var job = Job() - override val coroutineContext: CoroutineContext - get() = job + Dispatchers.Main +open class ExceptionsListFragment : BaseSettingsLikeFragment() { + private var _binding: FragmentExceptionsDomainsBinding? = null protected val binding get() = _binding!! @@ -152,8 +147,6 @@ open class ExceptionsListFragment : BaseSettingsLikeFragment(), CoroutineScope { override fun onResume() { super.onResume() - job = Job() - showToolbar(getString(R.string.preference_exceptions)) (binding.exceptionList.adapter as DomainListAdapter).refresh(requireActivity()) { @@ -169,11 +162,6 @@ open class ExceptionsListFragment : BaseSettingsLikeFragment(), CoroutineScope { } } - override fun onStop() { - job.cancel() - super.onStop() - } - override fun onDestroyView() { super.onDestroyView() _binding = null @@ -212,7 +200,7 @@ open class ExceptionsListFragment : BaseSettingsLikeFragment(), CoroutineScope { private val selectedExceptions: MutableList<TrackingProtectionException> = mutableListOf() fun refresh(context: Context, body: (() -> Unit)? = null) { - this@ExceptionsListFragment.launch(Dispatchers.Main) { + viewLifecycleOwner.lifecycleScope.launch { context.components.trackingProtectionUseCases.fetchExceptions { exceptions = it notifyDataSetChanged() diff --git a/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/exceptions/ExceptionsRemoveFragment.kt b/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/exceptions/ExceptionsRemoveFragment.kt @@ -8,7 +8,7 @@ import android.content.Context import android.view.Menu import android.view.MenuInflater import android.view.MenuItem -import kotlinx.coroutines.Dispatchers.Main +import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.launch import org.mozilla.focus.GleanMetrics.TrackingProtectionExceptions import org.mozilla.focus.R @@ -39,7 +39,7 @@ class ExceptionsRemoveFragment : ExceptionsListFragment() { ) if (exceptions.isNotEmpty()) { - launch(Main) { + viewLifecycleOwner.lifecycleScope.launch { exceptions.withEach { exception -> context.components.trackingProtectionUseCases.removeException(exception) } diff --git a/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/search/SearchEngineListPreference.kt b/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/search/SearchEngineListPreference.kt @@ -15,25 +15,21 @@ import androidx.core.graphics.drawable.toDrawable import androidx.preference.Preference import androidx.preference.PreferenceViewHolder import androidx.recyclerview.widget.RecyclerView -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import mozilla.components.browser.state.search.SearchEngine import mozilla.components.browser.state.state.searchEngines import mozilla.components.browser.state.state.selectedOrDefaultSearchEngine import org.mozilla.focus.R import org.mozilla.focus.ext.components -import kotlin.coroutines.CoroutineContext +/** + * Abstract base class for a preference that displays a list of available search engines. + */ abstract class SearchEngineListPreference @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, -) : Preference(context, attrs, defStyleAttr), CoroutineScope { +) : Preference(context, attrs, defStyleAttr) { - private val job = Job() - override val coroutineContext: CoroutineContext - get() = job + Dispatchers.Main protected var searchEngines: List<SearchEngine> = emptyList() protected var searchEngineGroup: RadioGroup? = null @@ -53,13 +49,11 @@ abstract class SearchEngineListPreference @JvmOverloads constructor( refreshSearchEngineViews(context) } - override fun onDetached() { - job.cancel() - super.onDetached() - } - protected abstract fun updateDefaultItem(defaultButton: CompoundButton) + /** + * Updates the list of search engines from the application store and refreshes the UI. + */ fun refetchSearchEngines() { searchEngines = context.components.store.state.search.searchEngines refreshSearchEngineViews(this@SearchEngineListPreference.context) diff --git a/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/searchsuggestions/ui/SearchSuggestionsFragment.kt b/mobile/android/focus-android/app/src/main/java/org/mozilla/focus/searchsuggestions/ui/SearchSuggestionsFragment.kt @@ -14,9 +14,6 @@ import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import mozilla.components.support.ktx.android.view.hideKeyboard import mozilla.telemetry.glean.private.NoExtras import org.mozilla.focus.GleanMetrics.ShowSearchSuggestions @@ -27,12 +24,11 @@ import org.mozilla.focus.ext.requireComponents import org.mozilla.focus.searchsuggestions.SearchSuggestionsViewModel import org.mozilla.focus.searchsuggestions.State import org.mozilla.focus.ui.theme.FocusTheme -import kotlin.coroutines.CoroutineContext -class SearchSuggestionsFragment : Fragment(), CoroutineScope { - private var job = Job() - override val coroutineContext: CoroutineContext - get() = job + Dispatchers.Main +/** + * Fragment responsible for displaying search suggestions and related UI states. + */ +class SearchSuggestionsFragment : Fragment() { private var _binding: FragmentSearchSuggestionsBinding? = null private val binding get() = _binding!! @@ -44,19 +40,9 @@ class SearchSuggestionsFragment : Fragment(), CoroutineScope { override fun onResume() { super.onResume() - - if (job.isCancelled) { - job = Job() - } - searchSuggestionsViewModel.refresh() } - override fun onPause() { - job.cancel() - super.onPause() - } - override fun onDestroyView() { super.onDestroyView() _binding = null diff --git a/mobile/android/focus-android/quality/detekt-baseline.xml b/mobile/android/focus-android/quality/detekt-baseline.xml @@ -46,7 +46,6 @@ <ID>UndocumentedPublicClass:FenixProductDetector.kt$FenixProductDetector</ID> <ID>UndocumentedPublicClass:FenixProductDetector.kt$FenixProductDetector$FenixVersion</ID> <ID>UndocumentedPublicClass:FindInPageIntegration.kt$FindInPageIntegration : LifecycleAwareFeatureUserInteractionHandler</ID> - <ID>UndocumentedPublicClass:FocusApplication.kt$FocusApplication : LocaleAwareApplicationProviderCoroutineScope</ID> <ID>UndocumentedPublicClass:FocusSnackbar.kt$FocusSnackbar : BaseTransientBottomBar</ID> <ID>UndocumentedPublicClass:FocusSnackbarDelegate.kt$FocusSnackbarDelegate : SnackbarDelegate</ID> <ID>UndocumentedPublicClass:FullScreenIntegration.kt$FullScreenIntegration : LifecycleAwareFeatureUserInteractionHandler</ID> @@ -154,7 +153,6 @@ <ID>UndocumentedPublicFunction:FenixProductDetector.kt$FenixProductDetector$fun isFenixDefaultBrowser(defaultBrowser: ActivityInfo?): Boolean</ID> <ID>UndocumentedPublicFunction:FindInPageIntegration.kt$FindInPageIntegration$fun hide()</ID> <ID>UndocumentedPublicFunction:FindInPageIntegration.kt$FindInPageIntegration$fun show(sessionState: SessionState)</ID> - <ID>UndocumentedPublicFunction:FocusApplication.kt$FocusApplication$open fun updateLeakCanaryState(isEnabled: Boolean)</ID> <ID>UndocumentedPublicFunction:FocusSnackbar.kt$FocusSnackbar$fun setText(text: String)</ID> <ID>UndocumentedPublicFunction:FocusTheme.kt$fun phoneDimensions()</ID> <ID>UndocumentedPublicFunction:FocusTheme.kt$fun tabletDimensions()</ID> @@ -181,7 +179,6 @@ <ID>UndocumentedPublicFunction:RadioButtonPreference.kt$GroupableRadioButton$fun updateRadioValue(isChecked: Boolean)</ID> <ID>UndocumentedPublicFunction:RadioButtonPreference.kt$RadioButtonPreference$fun onClickListener(listener: (() -&gt; Unit))</ID> <ID>UndocumentedPublicFunction:RadioButtonPreference.kt$fun Iterable&lt;GroupableRadioButton&gt;.uncheckAll()</ID> - <ID>UndocumentedPublicFunction:SearchEngineListPreference.kt$SearchEngineListPreference$fun refetchSearchEngines()</ID> <ID>UndocumentedPublicFunction:SearchSuggestionsPreferences.kt$SearchSuggestionsPreferences$fun disableSearchSuggestions()</ID> <ID>UndocumentedPublicFunction:SearchSuggestionsPreferences.kt$SearchSuggestionsPreferences$fun dismissNoSuggestionsMessage()</ID> <ID>UndocumentedPublicFunction:SearchSuggestionsPreferences.kt$SearchSuggestionsPreferences$fun enableSearchSuggestions()</ID>