1
0
Fork 0

For #5843 - Ensure tabs pending deletion are removed

master
ekager 2020-02-21 21:04:43 -08:00 committed by Emily Kager
parent 13c9c39658
commit 7f34204188
3 changed files with 130 additions and 21 deletions

View File

@ -5,6 +5,7 @@
package org.mozilla.fenix.components package org.mozilla.fenix.components
import GeckoProvider import GeckoProvider
import android.app.Application
import android.content.Context import android.content.Context
import android.content.res.Configuration import android.content.res.Configuration
import io.sentry.Sentry import io.sentry.Sentry
@ -116,6 +117,11 @@ class Core(private val context: Context) {
*/ */
val customTabsStore by lazy { CustomTabsServiceStore() } val customTabsStore by lazy { CustomTabsServiceStore() }
/**
* The [PendingSessionDeletionManager] maintains a set of sessionIds that are marked for deletion
*/
val pendingSessionDeletionManager by lazy { PendingSessionDeletionManager(context as Application) }
/** /**
* The session manager component provides access to a centralized registry of * The session manager component provides access to a centralized registry of
* all browser sessions (i.e. tabs). It is initialized here to persist and restore * all browser sessions (i.e. tabs). It is initialized here to persist and restore
@ -142,6 +148,12 @@ class Core(private val context: Context) {
) )
} }
pendingSessionDeletionManager.getSessionsToDelete(context).forEach {
sessionManager.findSessionById(it)?.let { session ->
sessionManager.remove(session)
}
}
// Now that we have restored our previous state (if there's one) let's setup auto saving the state while // Now that we have restored our previous state (if there's one) let's setup auto saving the state while
// the app is used. // the app is used.
sessionStorage.autoSave(sessionManager) sessionStorage.autoSave(sessionManager)
@ -277,13 +289,13 @@ class Core(private val context: Context) {
} }
private fun geCustomCookiePolicy(): CookiePolicy { private fun geCustomCookiePolicy(): CookiePolicy {
return when (context.settings().blockCookiesSelectionInCustomTrackingProtection) { return when (context.settings().blockCookiesSelectionInCustomTrackingProtection) {
"all" -> CookiePolicy.ACCEPT_NONE "all" -> CookiePolicy.ACCEPT_NONE
"social" -> CookiePolicy.ACCEPT_NON_TRACKERS "social" -> CookiePolicy.ACCEPT_NON_TRACKERS
"unvisited" -> CookiePolicy.ACCEPT_VISITED "unvisited" -> CookiePolicy.ACCEPT_VISITED
"third-party" -> CookiePolicy.ACCEPT_ONLY_FIRST_PARTY "third-party" -> CookiePolicy.ACCEPT_ONLY_FIRST_PARTY
else -> CookiePolicy.ACCEPT_NONE else -> CookiePolicy.ACCEPT_NONE
} }
} }
private fun getCustomTrackingCategories(): Array<TrackingCategory> { private fun getCustomTrackingCategories(): Array<TrackingCategory> {

View File

@ -0,0 +1,71 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.components
import android.app.Activity
import android.app.Application
import android.content.Context
import android.os.Bundle
import org.mozilla.fenix.ext.settings
class PendingSessionDeletionManager(application: Application) :
Application.ActivityLifecycleCallbacks {
private val sessionIdsPendingDeletion = mutableSetOf<String>()
init {
application.registerActivityLifecycleCallbacks(this)
}
fun addSession(sessionId: String) {
sessionIdsPendingDeletion.add(sessionId)
}
fun removeSession(sessionId: String) {
sessionIdsPendingDeletion.remove(sessionId)
}
fun getSessionsToDelete(context: Context): Set<String> {
return context.settings().preferences.getStringSet(
PREF_KEY,
setOf()
) ?: setOf()
}
override fun onActivityPaused(activity: Activity?) {
activity?.settings()?.preferences?.edit()?.putStringSet(
PREF_KEY,
sessionIdsPendingDeletion
)?.apply()
}
override fun onActivityResumed(p0: Activity?) {
/* no-op */
}
override fun onActivityStarted(p0: Activity?) {
/* no-op */
}
override fun onActivityDestroyed(p0: Activity?) {
/* no-op */
}
override fun onActivitySaveInstanceState(p0: Activity?, p1: Bundle?) {
/* no-op */
}
override fun onActivityStopped(p0: Activity?) {
/* no-op */
}
override fun onActivityCreated(p0: Activity?, p1: Bundle?) {
/* no-op */
}
companion object {
private const val PREF_KEY = "pref_key_session_id_set_to_delete"
}
}

View File

@ -202,7 +202,7 @@ class HomeFragment : Fragment() {
registerCollectionStorageObserver = ::registerCollectionStorageObserver, registerCollectionStorageObserver = ::registerCollectionStorageObserver,
scrollToTheTop = ::scrollToTheTop, scrollToTheTop = ::scrollToTheTop,
showDeleteCollectionPrompt = ::showDeleteCollectionPrompt, showDeleteCollectionPrompt = ::showDeleteCollectionPrompt,
openSettingsScreen = :: openSettingsScreen openSettingsScreen = ::openSettingsScreen
) )
) )
updateLayout(view) updateLayout(view)
@ -277,7 +277,8 @@ class HomeFragment : Fragment() {
// TODO remove when viewLifecycleOwner is fixed // TODO remove when viewLifecycleOwner is fixed
val context = context ?: return@launch val context = context ?: return@launch
val iconSize = context.resources.getDimensionPixelSize(R.dimen.preference_icon_drawable_size) val iconSize =
context.resources.getDimensionPixelSize(R.dimen.preference_icon_drawable_size)
val searchEngine = context.components.search.provider.getDefaultEngine(context) val searchEngine = context.components.search.provider.getDefaultEngine(context)
val searchIcon = BitmapDrawable(context.resources, searchEngine.icon) val searchIcon = BitmapDrawable(context.resources, searchEngine.icon)
@ -336,7 +337,8 @@ class HomeFragment : Fragment() {
if (onboarding.userHasBeenOnboarded()) { if (onboarding.userHasBeenOnboarded()) {
homeFragmentStore.dispatch( homeFragmentStore.dispatch(
HomeFragmentAction.ModeChange(Mode.fromBrowsingMode(newMode))) HomeFragmentAction.ModeChange(Mode.fromBrowsingMode(newMode))
)
} }
} }
} }
@ -355,12 +357,14 @@ class HomeFragment : Fragment() {
val context = requireContext() val context = requireContext()
val components = context.components val components = context.components
homeFragmentStore.dispatch(HomeFragmentAction.Change( homeFragmentStore.dispatch(
collections = components.core.tabCollectionStorage.cachedTabCollections, HomeFragmentAction.Change(
mode = currentMode.getCurrentMode(), collections = components.core.tabCollectionStorage.cachedTabCollections,
tabs = getListOfSessions().toTabs(), mode = currentMode.getCurrentMode(),
topSites = components.core.topSiteStorage.cachedTopSites tabs = getListOfSessions().toTabs(),
)) topSites = components.core.topSiteStorage.cachedTopSites
)
)
requireComponents.backgroundServices.accountManager.register(currentMode, owner = this) requireComponents.backgroundServices.accountManager.register(currentMode, owner = this)
requireComponents.backgroundServices.accountManager.register(object : AccountObserver { requireComponents.backgroundServices.accountManager.register(object : AccountObserver {
@ -377,7 +381,8 @@ class HomeFragment : Fragment() {
}, owner = this) }, owner = this)
if (context.settings().showPrivateModeContextualFeatureRecommender && if (context.settings().showPrivateModeContextualFeatureRecommender &&
browsingModeManager.mode.isPrivate) { browsingModeManager.mode.isPrivate
) {
recommendPrivateBrowsingShortcut() recommendPrivateBrowsingShortcut()
} }
@ -517,7 +522,8 @@ class HomeFragment : Fragment() {
// Otherwise, we will encounter an activity token error. // Otherwise, we will encounter an activity token error.
privateBrowsingButton.post { privateBrowsingButton.post {
privateBrowsingRecommend.showAsDropDown( privateBrowsingRecommend.showAsDropDown(
privateBrowsingButton, 0, CFR_Y_OFFSET, Gravity.TOP or Gravity.END) privateBrowsingButton, 0, CFR_Y_OFFSET, Gravity.TOP or Gravity.END
)
} }
} }
} }
@ -528,7 +534,9 @@ class HomeFragment : Fragment() {
homeFragmentStore.dispatch( homeFragmentStore.dispatch(
HomeFragmentAction.ModeChange( HomeFragmentAction.ModeChange(
mode = currentMode.getCurrentMode(), mode = currentMode.getCurrentMode(),
tabs = getListOfSessions().toTabs())) tabs = getListOfSessions().toTabs()
)
)
} }
} }
@ -633,10 +641,16 @@ class HomeFragment : Fragment() {
private fun removeAllTabsWithUndo(listOfSessionsToDelete: Sequence<Session>, private: Boolean) { private fun removeAllTabsWithUndo(listOfSessionsToDelete: Sequence<Session>, private: Boolean) {
homeFragmentStore.dispatch(HomeFragmentAction.TabsChange(emptyList())) homeFragmentStore.dispatch(HomeFragmentAction.TabsChange(emptyList()))
listOfSessionsToDelete.forEach {
requireComponents.core.pendingSessionDeletionManager.addSession(
it.id
)
}
val deleteOperation: (suspend () -> Unit) = { val deleteOperation: (suspend () -> Unit) = {
listOfSessionsToDelete.forEach { listOfSessionsToDelete.forEach {
sessionManager.remove(it) sessionManager.remove(it)
requireComponents.core.pendingSessionDeletionManager.removeSession(it.id)
} }
} }
deleteAllSessionsJob = deleteOperation deleteAllSessionsJob = deleteOperation
@ -651,6 +665,11 @@ class HomeFragment : Fragment() {
view!!, view!!,
snackbarMessage, snackbarMessage,
getString(R.string.snackbar_deleted_undo), { getString(R.string.snackbar_deleted_undo), {
listOfSessionsToDelete.forEach {
requireComponents.core.pendingSessionDeletionManager.removeSession(
it.id
)
}
if (private) { if (private) {
requireComponents.analytics.metrics.track(Event.PrivateBrowsingSnackbarUndoTapped) requireComponents.analytics.metrics.track(Event.PrivateBrowsingSnackbarUndoTapped)
} }
@ -664,11 +683,13 @@ class HomeFragment : Fragment() {
private fun removeTabWithUndo(sessionId: String, private: Boolean) { private fun removeTabWithUndo(sessionId: String, private: Boolean) {
val sessionManager = requireComponents.core.sessionManager val sessionManager = requireComponents.core.sessionManager
requireComponents.core.pendingSessionDeletionManager.addSession(sessionId)
val deleteOperation: (suspend () -> Unit) = { val deleteOperation: (suspend () -> Unit) = {
sessionManager.findSessionById(sessionId) sessionManager.findSessionById(sessionId)
?.let { session -> ?.let { session ->
pendingSessionDeletion = null pendingSessionDeletion = null
sessionManager.remove(session) sessionManager.remove(session)
requireComponents.core.pendingSessionDeletionManager.removeSession(sessionId)
} }
} }
@ -684,6 +705,7 @@ class HomeFragment : Fragment() {
view!!, view!!,
snackbarMessage, snackbarMessage,
getString(R.string.snackbar_deleted_undo), { getString(R.string.snackbar_deleted_undo), {
requireComponents.core.pendingSessionDeletionManager.removeSession(sessionId)
pendingSessionDeletion = null pendingSessionDeletion = null
emitSessionChanges() emitSessionChanges()
}, },
@ -777,8 +799,12 @@ class HomeFragment : Fragment() {
border?.visibility = View.GONE border?.visibility = View.GONE
} }
override fun onAnimationStart(animation: Animator?) { /* noop */ } override fun onAnimationStart(animation: Animator?) { /* noop */
override fun onAnimationRepeat(animation: Animator?) { /* noop */ } }
override fun onAnimationRepeat(animation: Animator?) { /* noop */
}
override fun onAnimationEnd(animation: Animator?) { override fun onAnimationEnd(animation: Animator?) {
border?.animate()?.alpha(0.0F)?.setStartDelay(ANIM_ON_SCREEN_DELAY) border?.animate()?.alpha(0.0F)?.setStartDelay(ANIM_ON_SCREEN_DELAY)
?.setDuration(FADE_ANIM_DURATION) ?.setDuration(FADE_ANIM_DURATION)