Commit c4e83367 authored by ekager's avatar ekager Committed by Emily Kager
Browse files

For #6832 - Fix various fragment not attached to a context crashes

parent 6457a02a
......@@ -94,7 +94,7 @@ class AddonDetailsFragment : Fragment(R.layout.fragment_add_on_details) {
}
private fun showUpdaterDialog(addon: Addon) {
lifecycleScope.launch(IO) {
viewLifecycleOwner.lifecycleScope.launch(IO) {
val updateAttempt = updateAttemptStorage.findUpdateAttemptBy(addon.id)
updateAttempt?.let {
withContext(Main) {
......
......@@ -98,10 +98,10 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management),
private fun bindRecyclerView(view: View) {
val recyclerView = view.add_ons_list
recyclerView.layoutManager = LinearLayoutManager(requireContext())
lifecycleScope.launch(IO) {
viewLifecycleOwner.lifecycleScope.launch(IO) {
try {
val addons = requireContext().components.addonManager.getAddons()
lifecycleScope.launch(Dispatchers.Main) {
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
runIfFragmentIsAttached {
val adapter = AddonsManagerAdapter(
requireContext().components.addonCollectionProvider,
......@@ -117,9 +117,12 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management),
}
}
} catch (e: AddonManagerException) {
lifecycleScope.launch(Dispatchers.Main) {
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
runIfFragmentIsAttached {
showSnackBar(view, getString(R.string.mozac_feature_addons_failed_to_query_add_ons))
showSnackBar(
view,
getString(R.string.mozac_feature_addons_failed_to_query_add_ons)
)
isInstallationInProgress = false
view.add_ons_progress_bar.isVisible = false
view.add_ons_empty_message.isVisible = true
......@@ -220,7 +223,10 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management),
val rootView = activity?.getRootView() ?: view
showSnackBar(
rootView,
getString(R.string.mozac_feature_addons_failed_to_install, addon.translatedName)
getString(
R.string.mozac_feature_addons_failed_to_install,
addon.translatedName
)
)
addonProgressOverlay?.visibility = View.GONE
isInstallationInProgress = false
......
......@@ -89,7 +89,6 @@ import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.sessionsOfType
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.home.SharedViewModel
import org.mozilla.fenix.settings.SupportUtils
import org.mozilla.fenix.theme.ThemeManager
import org.mozilla.fenix.wifi.SitePermissionsWifiIntegration
import java.lang.ref.WeakReference
......@@ -186,7 +185,6 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
return getSessionById()?.also { session ->
val browserToolbarController = DefaultBrowserToolbarController(
store = browserFragmentStore,
activity = requireActivity(),
navController = findNavController(),
readerModeController = DefaultReaderModeController(
......@@ -194,24 +192,17 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
(activity as HomeActivity).browsingModeManager.mode.isPrivate,
view.readerViewControlsBar
),
browsingModeManager = (activity as HomeActivity).browsingModeManager,
sessionManager = requireComponents.core.sessionManager,
findInPageLauncher = { findInPageIntegration.withFeature { it.launch() } },
engineView = engineView,
swipeRefresh = swipeRefresh,
browserAnimator = browserAnimator,
customTabSession = customTabSessionId?.let { sessionManager.findSessionById(it) },
getSupportUrl = {
SupportUtils.getSumoURLForTopic(
context,
SupportUtils.SumoTopic.HELP
)
},
openInFenixIntent = Intent(context, IntentReceiverActivity::class.java).apply {
action = Intent.ACTION_VIEW
},
bookmarkTapped = { lifecycleScope.launch { bookmarkTapped(it) } },
scope = lifecycleScope,
bookmarkTapped = { viewLifecycleOwner.lifecycleScope.launch { bookmarkTapped(it) } },
scope = viewLifecycleOwner.lifecycleScope,
tabCollectionStorage = requireComponents.core.tabCollectionStorage,
topSiteStorage = requireComponents.core.topSiteStorage,
sharedViewModel = sharedViewModel
......@@ -226,7 +217,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
shouldUseBottomToolbar = context.settings().shouldUseBottomToolbar,
interactor = browserInteractor,
customTabSession = customTabSessionId?.let { sessionManager.findSessionById(it) },
lifecycleOwner = this.viewLifecycleOwner
lifecycleOwner = viewLifecycleOwner
)
toolbarIntegration.set(
......@@ -725,7 +716,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
*/
private fun showQuickSettingsDialog() {
val session = getSessionById() ?: return
lifecycleScope.launch(Main) {
viewLifecycleOwner.lifecycleScope.launch(Main) {
val sitePermissions: SitePermissions? = withContext(IO) {
session.url.toUri().host?.let { host ->
val storage = requireContext().components.core.permissionStorage
......
......@@ -12,7 +12,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.components.browser.session.SessionManager
import mozilla.components.feature.tab.collections.TabCollection
import mozilla.components.feature.tabs.TabsUseCases
import org.mozilla.fenix.components.Analytics
import org.mozilla.fenix.components.TabCollectionStorage
import org.mozilla.fenix.components.metrics.Event
......@@ -64,9 +63,8 @@ class DefaultCollectionCreationController(
private val dismiss: () -> Unit,
private val analytics: Analytics,
private val tabCollectionStorage: TabCollectionStorage,
private val tabsUseCases: TabsUseCases,
private val sessionManager: SessionManager,
private val lifecycleScope: CoroutineScope
private val viewLifecycleScope: CoroutineScope
) : CollectionCreationController {
companion object {
......@@ -78,7 +76,7 @@ class DefaultCollectionCreationController(
dismiss()
val sessionBundle = tabs.toList().toSessionBundle(sessionManager)
lifecycleScope.launch(Dispatchers.IO) {
viewLifecycleScope.launch(Dispatchers.IO) {
tabCollectionStorage.createCollection(name, sessionBundle)
}
......@@ -89,7 +87,7 @@ class DefaultCollectionCreationController(
override fun renameCollection(collection: TabCollection, name: String) {
dismiss()
lifecycleScope.launch(Dispatchers.IO) {
viewLifecycleScope.launch(Dispatchers.IO) {
tabCollectionStorage.renameCollection(collection, name)
analytics.metrics.track(Event.CollectionRenamed)
}
......@@ -114,7 +112,7 @@ class DefaultCollectionCreationController(
override fun selectCollection(collection: TabCollection, tabs: List<Tab>) {
dismiss()
val sessionBundle = tabs.toList().toSessionBundle(sessionManager)
lifecycleScope.launch(Dispatchers.IO) {
viewLifecycleScope.launch(Dispatchers.IO) {
tabCollectionStorage
.addTabsToCollection(collection, sessionBundle)
}
......
......@@ -77,7 +77,6 @@ class CollectionCreationFragment : DialogFragment() {
::dismiss,
requireComponents.analytics,
requireComponents.core.tabCollectionStorage,
requireComponents.useCases.tabsUseCases,
requireComponents.core.sessionManager,
viewLifecycleOwner.lifecycleScope
)
......
......@@ -29,7 +29,6 @@ import org.mozilla.fenix.browser.BrowserAnimator
import org.mozilla.fenix.browser.BrowserAnimator.Companion.getToolbarNavOptions
import org.mozilla.fenix.browser.BrowserFragment
import org.mozilla.fenix.browser.BrowserFragmentDirections
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
import org.mozilla.fenix.browser.readermode.ReaderModeController
import org.mozilla.fenix.collections.SaveCollectionStep
import org.mozilla.fenix.components.FenixSnackbar
......@@ -59,18 +58,15 @@ interface BrowserToolbarController {
@Suppress("LargeClass")
class DefaultBrowserToolbarController(
private val store: BrowserFragmentStore,
private val activity: Activity,
private val navController: NavController,
private val readerModeController: ReaderModeController,
private val browsingModeManager: BrowsingModeManager,
private val sessionManager: SessionManager,
private val findInPageLauncher: () -> Unit,
private val engineView: EngineView,
private val browserAnimator: BrowserAnimator,
private val swipeRefresh: SwipeRefreshLayout,
private val customTabSession: Session?,
private val getSupportUrl: () -> String,
private val openInFenixIntent: Intent,
private val bookmarkTapped: (Session) -> Unit,
private val scope: CoroutineScope,
......
......@@ -214,7 +214,7 @@ class HomeFragment : Fragment() {
fragmentStore = homeFragmentStore,
navController = findNavController(),
browsingModeManager = browsingModeManager,
lifecycleScope = viewLifecycleOwner.lifecycleScope,
viewLifecycleScope = viewLifecycleOwner.lifecycleScope,
closeTab = ::closeTab,
closeAllTabs = ::closeAllTabs,
getListOfTabs = ::getListOfTabs,
......@@ -688,7 +688,7 @@ class HomeFragment : Fragment() {
HomeMenu.Item.Quit -> activity?.let { activity ->
deleteAndQuit(
activity,
lifecycleScope,
viewLifecycleOwner.lifecycleScope,
view?.let { view -> FenixSnackbar.make(
view = view,
isDisplayedWithBrowserToolbar = false
......@@ -827,7 +827,7 @@ class HomeFragment : Fragment() {
}
private fun scrollToTheTop() {
lifecycleScope.launch(Main) {
viewLifecycleOwner.lifecycleScope.launch(Main) {
delay(ANIM_SCROLL_DELAY)
sessionControlView!!.view.smoothScrollToPosition(0)
}
......
......@@ -175,7 +175,7 @@ class DefaultSessionControlController(
private val fragmentStore: HomeFragmentStore,
private val navController: NavController,
private val browsingModeManager: BrowsingModeManager,
private val lifecycleScope: CoroutineScope,
private val viewLifecycleScope: CoroutineScope,
private val closeTab: (sessionId: String) -> Unit,
private val closeAllTabs: (isPrivateMode: Boolean) -> Unit,
private val getListOfTabs: () -> List<Tab>,
......@@ -255,7 +255,7 @@ class DefaultSessionControlController(
override fun handleCollectionRemoveTab(collection: TabCollection, tab: ComponentTab) {
metrics.track(Event.CollectionTabRemoved)
lifecycleScope.launch(Dispatchers.IO) {
viewLifecycleScope.launch(Dispatchers.IO) {
tabCollectionStorage.removeTabFromCollection(collection, tab)
}
}
......@@ -304,7 +304,7 @@ class DefaultSessionControlController(
metrics.track(Event.PocketTopSiteRemoved)
}
lifecycleScope.launch(Dispatchers.IO) {
viewLifecycleScope.launch(Dispatchers.IO) {
topSiteStorage.removeTopSite(topSite)
}
}
......
......@@ -291,7 +291,7 @@ class BookmarkFragment : LibraryPageFragment<BookmarkNode>(), UserInteractionHan
else -> throw IllegalStateException("Illegal event type in onDeleteSome")
}
lifecycleScope.allowUndo(
viewLifecycleOwner.lifecycleScope.allowUndo(
view!!, message,
getString(R.string.bookmark_undo_deletion), {
pendingBookmarksToDelete.removeAll(selected)
......
......@@ -57,7 +57,7 @@ class AddBookmarkFolderFragment : Fragment(R.layout.fragment_edit_bookmark) {
super.onResume()
showToolbar(getString(R.string.bookmark_add_folder_fragment_label))
lifecycleScope.launch(Main) {
viewLifecycleOwner.lifecycleScope.launch(Main) {
sharedViewModel.selectedFolder = withContext(IO) {
sharedViewModel.selectedFolder
?: requireComponents.core.bookmarksStorage.getTree(BookmarkRoot.Mobile.id)
......@@ -95,7 +95,7 @@ class AddBookmarkFolderFragment : Fragment(R.layout.fragment_edit_bookmark) {
return true
}
this.view?.hideKeyboard()
lifecycleScope.launch(IO) {
viewLifecycleOwner.lifecycleScope.launch(IO) {
val newGuid = requireComponents.core.bookmarksStorage.addFolder(
sharedViewModel.selectedFolder!!.guid, bookmarkNameEdit.text.toString(), null
)
......
......@@ -65,7 +65,7 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
super.onViewCreated(view, savedInstanceState)
initToolbar()
lifecycleScope.launch(Main) {
viewLifecycleOwner.lifecycleScope.launch(Main) {
val context = requireContext()
withContext(IO) {
......@@ -155,7 +155,7 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
dialog.cancel()
}
setPositiveButton(R.string.tab_collection_dialog_positive) { dialog: DialogInterface, _ ->
lifecycleScope.launch(IO) {
viewLifecycleOwner.lifecycleScope.launch(IO) {
requireComponents.core.bookmarksStorage.deleteNode(args.guidToEdit)
requireComponents.analytics.metrics.track(Event.RemoveBookmark)
......@@ -194,7 +194,7 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
}
private fun updateBookmarkNode(title: String?, url: String?) {
lifecycleScope.launch(IO) {
viewLifecycleOwner.lifecycleScope.launch(IO) {
try {
requireComponents.let { components ->
if (title != bookmarkNode?.title || url != bookmarkNode?.url) {
......
......@@ -50,7 +50,7 @@ class SelectBookmarkFolderFragment : Fragment() {
super.onResume()
showToolbar(getString(R.string.bookmark_select_folder_fragment_label))
lifecycleScope.launch(Main) {
viewLifecycleOwner.lifecycleScope.launch(Main) {
bookmarkNode = withContext(IO) {
val context = requireContext()
context.components.core.bookmarksStorage
......@@ -74,7 +74,7 @@ class SelectBookmarkFolderFragment : Fragment() {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.add_folder_button -> {
lifecycleScope.launch(Main) {
viewLifecycleOwner.lifecycleScope.launch(Main) {
nav(
R.id.bookmarkSelectFolderFragment,
SelectBookmarkFolderFragmentDirections
......
......@@ -106,7 +106,7 @@ class HistoryFragment : LibraryPageFragment<HistoryItem>(), UserInteractionHandl
}
private fun deleteHistoryItems(items: Set<HistoryItem>) {
lifecycleScope.launch {
viewLifecycleOwner.lifecycleScope.launch {
context?.components?.run {
for (item in items) {
analytics.metrics.track(Event.HistoryItemRemoved)
......@@ -155,7 +155,7 @@ class HistoryFragment : LibraryPageFragment<HistoryItem>(), UserInteractionHandl
true
}
R.id.delete_history_multi_select -> {
lifecycleScope.launch(Main) {
viewLifecycleOwner.lifecycleScope.launch(Main) {
deleteSelectedHistory(historyStore.state.mode.selectedItems, requireComponents)
viewModel.invalidate()
historyStore.dispatch(HistoryFragmentAction.ExitDeletionMode)
......@@ -216,7 +216,7 @@ class HistoryFragment : LibraryPageFragment<HistoryItem>(), UserInteractionHandl
}
setPositiveButton(R.string.delete_browsing_data_prompt_allow) { dialog: DialogInterface, _ ->
historyStore.dispatch(HistoryFragmentAction.EnterDeletionMode)
lifecycleScope.launch {
viewLifecycleOwner.lifecycleScope.launch {
requireComponents.analytics.metrics.track(Event.HistoryAllItemsRemoved)
requireComponents.core.historyStorage.deleteEverything()
launch(Main) {
......
......@@ -47,7 +47,7 @@ class DefaultSearchController(
private val context: Context,
private val store: SearchFragmentStore,
private val navController: NavController,
private val lifecycleScope: CoroutineScope,
private val viewLifecycleScope: CoroutineScope,
private val clearToolbarFocus: () -> Unit
) : SearchController {
......@@ -82,7 +82,7 @@ class DefaultSearchController(
}
override fun handleEditingCancelled() {
lifecycleScope.launch {
viewLifecycleScope.launch {
clearToolbarFocus()
// Delay a short amount so the keyboard begins animating away. This makes exit animation
// much smoother instead of having two separate parts (keyboard hides THEN animation)
......
......@@ -109,7 +109,7 @@ class SearchFragment : Fragment(), UserInteractionHandler {
context = activity as HomeActivity,
store = searchStore,
navController = findNavController(),
lifecycleScope = viewLifecycleOwner.lifecycleScope,
viewLifecycleScope = viewLifecycleOwner.lifecycleScope,
clearToolbarFocus = ::clearToolbarFocus
)
......
......@@ -69,7 +69,7 @@ class LoginsFragment : PreferenceFragmentCompat(), AccountObserver {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
Log.d(LOG_TAG, "onAuthenticationSucceeded")
lifecycleScope.launch(Main) {
viewLifecycleOwner.lifecycleScope.launch(Main) {
// Workaround for likely biometric library bug
// https://github.com/mozilla-mobile/fenix/issues/8438
delay(SHORT_DELAY_MS)
......
......@@ -51,7 +51,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
private val accountObserver = object : AccountObserver {
private fun updateAccountUi(profile: Profile? = null) {
val context = context ?: return
lifecycleScope.launch {
viewLifecycleOwner.lifecycleScope.launch {
updateAccountUIState(
context = context,
profile = profile
......@@ -125,7 +125,8 @@ class SettingsFragment : PreferenceFragmentCompat() {
// update it here if we're not going through the `onCreate->onStart->onResume` lifecycle chain.
update(shouldUpdateAccountUIState = !creatingFragment)
view!!.findViewById<RecyclerView>(R.id.recycler_view)?.hideInitialScrollBar(lifecycleScope)
view!!.findViewById<RecyclerView>(R.id.recycler_view)
?.hideInitialScrollBar(viewLifecycleOwner.lifecycleScope)
// Consider finish of `onResume` to be the point at which we consider this fragment as 'created'.
creatingFragment = false
......@@ -376,10 +377,14 @@ class SettingsFragment : PreferenceFragmentCompat() {
preferenceSignIn?.isVisible = false
profile?.avatar?.url?.let { avatarUrl ->
lifecycleScope.launch(Main) {
val roundedDrawable = avatarUrl.toRoundedDrawable(context, requireComponents.core.client)
viewLifecycleOwner.lifecycleScope.launch(Main) {
val roundedDrawable =
avatarUrl.toRoundedDrawable(context, requireComponents.core.client)
preferenceFirefoxAccount?.icon =
roundedDrawable ?: AppCompatResources.getDrawable(context, R.drawable.ic_account)
roundedDrawable ?: AppCompatResources.getDrawable(
context,
R.drawable.ic_account
)
}
}
preferenceSignIn?.onPreferenceClickListener = null
......@@ -420,7 +425,8 @@ class SettingsFragment : PreferenceFragmentCompat() {
settings.overrideSyncTokenServer.isNotEmpty() ||
settings.showSecretDebugMenuThisSession
// Only enable changes to these prefs when the user isn't connected to an account.
val enabled = requireComponents.backgroundServices.accountManager.authenticatedAccount() == null
val enabled =
requireComponents.backgroundServices.accountManager.authenticatedAccount() == null
preferenceFxAOverride?.apply {
isVisible = show
isEnabled = enabled
......
......@@ -55,13 +55,13 @@ class AccountSettingsFragment : PreferenceFragmentCompat() {
// Navigate away from this fragment when we encounter auth problems or logout events.
private val accountStateObserver = object : AccountObserver {
override fun onAuthenticationProblems() {
lifecycleScope.launch {
viewLifecycleOwner.lifecycleScope.launch {
findNavController().popBackStack()
}
}
override fun onLoggedOut() {
lifecycleScope.launch {
viewLifecycleOwner.lifecycleScope.launch {
findNavController().popBackStack()
// Remove the device name when we log out.
......@@ -266,7 +266,7 @@ class AccountSettingsFragment : PreferenceFragmentCompat() {
}
private fun syncNow() {
lifecycleScope.launch {
viewLifecycleOwner.lifecycleScope.launch {
requireComponents.analytics.metrics.track(Event.SyncAccountSyncNow)
// Trigger a sync.
requireComponents.backgroundServices.accountManager.syncNowAsync(SyncReason.User)
......@@ -285,7 +285,7 @@ class AccountSettingsFragment : PreferenceFragmentCompat() {
return false
}
// This may fail, and we'll have a disparity in the UI until `updateDeviceName` is called.
lifecycleScope.launch(Main) {
viewLifecycleOwner.lifecycleScope.launch(Main) {
context?.let {
accountManager.authenticatedAccount()
?.deviceConstellation()
......@@ -336,7 +336,7 @@ class AccountSettingsFragment : PreferenceFragmentCompat() {
private val syncStatusObserver = object : SyncStatusObserver {
override fun onStarted() {
lifecycleScope.launch {
viewLifecycleOwner.lifecycleScope.launch {
val pref = findPreference<Preference>(getPreferenceKey(R.string.pref_key_sync_now))
view?.announceForAccessibility(getString(R.string.sync_syncing_in_progress))
pref?.title = getString(R.string.sync_syncing_in_progress)
......@@ -347,7 +347,7 @@ class AccountSettingsFragment : PreferenceFragmentCompat() {
// Sync stopped successfully.
override fun onIdle() {
lifecycleScope.launch {
viewLifecycleOwner.lifecycleScope.launch {
val pref = findPreference<Preference>(getPreferenceKey(R.string.pref_key_sync_now))
pref?.let {
pref.title = getString(R.string.preferences_sync_now)
......@@ -364,7 +364,7 @@ class AccountSettingsFragment : PreferenceFragmentCompat() {
// Sync stopped after encountering a problem.
override fun onError(error: Exception?) {
lifecycleScope.launch {
viewLifecycleOwner.lifecycleScope.launch {
val pref = findPreference<Preference>(getPreferenceKey(R.string.pref_key_sync_now))
pref?.let {
pref.title = getString(R.string.preferences_sync_now)
......
......@@ -61,7 +61,7 @@ class SignOutFragment : BottomSheetDialogFragment() {
super.onViewCreated(view, savedInstanceState)
view.signOutDisconnect.setOnClickListener {
lifecycleScope.launch {
viewLifecycleOwner.lifecycleScope.launch {
requireComponents
.backgroundServices.accountAbnormalities.userRequestedLogout()
accountManager.logoutAsync().await()
......
......@@ -96,7 +96,7 @@ class SavedLoginSiteInfoFragment : Fragment(R.layout.fragment_saved_login_site_i
private fun deleteLogin() {
var deleteLoginJob: Deferred<Boolean>? = null
val deleteJob = lifecycleScope.launch(IO) {
val deleteJob = viewLifecycleOwner.lifecycleScope.launch(IO) {
deleteLoginJob = async {
requireContext().components.core.passwordsStorage.delete(args.savedLoginItem.id)
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment