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
import GeckoProvider
import android.app.Application
import android.content.Context
import android.content.res.Configuration
import io.sentry.Sentry
@ -116,6 +117,11 @@ class Core(private val context: Context) {
*/
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
* 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
// the app is used.
sessionStorage.autoSave(sessionManager)
@ -277,13 +289,13 @@ class Core(private val context: Context) {
}
private fun geCustomCookiePolicy(): CookiePolicy {
return when (context.settings().blockCookiesSelectionInCustomTrackingProtection) {
"all" -> CookiePolicy.ACCEPT_NONE
"social" -> CookiePolicy.ACCEPT_NON_TRACKERS
"unvisited" -> CookiePolicy.ACCEPT_VISITED
"third-party" -> CookiePolicy.ACCEPT_ONLY_FIRST_PARTY
else -> CookiePolicy.ACCEPT_NONE
}
return when (context.settings().blockCookiesSelectionInCustomTrackingProtection) {
"all" -> CookiePolicy.ACCEPT_NONE
"social" -> CookiePolicy.ACCEPT_NON_TRACKERS
"unvisited" -> CookiePolicy.ACCEPT_VISITED
"third-party" -> CookiePolicy.ACCEPT_ONLY_FIRST_PARTY
else -> CookiePolicy.ACCEPT_NONE
}
}
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,
scrollToTheTop = ::scrollToTheTop,
showDeleteCollectionPrompt = ::showDeleteCollectionPrompt,
openSettingsScreen = :: openSettingsScreen
openSettingsScreen = ::openSettingsScreen
)
)
updateLayout(view)
@ -277,7 +277,8 @@ class HomeFragment : Fragment() {
// TODO remove when viewLifecycleOwner is fixed
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 searchIcon = BitmapDrawable(context.resources, searchEngine.icon)
@ -336,7 +337,8 @@ class HomeFragment : Fragment() {
if (onboarding.userHasBeenOnboarded()) {
homeFragmentStore.dispatch(
HomeFragmentAction.ModeChange(Mode.fromBrowsingMode(newMode)))
HomeFragmentAction.ModeChange(Mode.fromBrowsingMode(newMode))
)
}
}
}
@ -355,12 +357,14 @@ class HomeFragment : Fragment() {
val context = requireContext()
val components = context.components
homeFragmentStore.dispatch(HomeFragmentAction.Change(
collections = components.core.tabCollectionStorage.cachedTabCollections,
mode = currentMode.getCurrentMode(),
tabs = getListOfSessions().toTabs(),
topSites = components.core.topSiteStorage.cachedTopSites
))
homeFragmentStore.dispatch(
HomeFragmentAction.Change(
collections = components.core.tabCollectionStorage.cachedTabCollections,
mode = currentMode.getCurrentMode(),
tabs = getListOfSessions().toTabs(),
topSites = components.core.topSiteStorage.cachedTopSites
)
)
requireComponents.backgroundServices.accountManager.register(currentMode, owner = this)
requireComponents.backgroundServices.accountManager.register(object : AccountObserver {
@ -377,7 +381,8 @@ class HomeFragment : Fragment() {
}, owner = this)
if (context.settings().showPrivateModeContextualFeatureRecommender &&
browsingModeManager.mode.isPrivate) {
browsingModeManager.mode.isPrivate
) {
recommendPrivateBrowsingShortcut()
}
@ -517,7 +522,8 @@ class HomeFragment : Fragment() {
// Otherwise, we will encounter an activity token error.
privateBrowsingButton.post {
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(
HomeFragmentAction.ModeChange(
mode = currentMode.getCurrentMode(),
tabs = getListOfSessions().toTabs()))
tabs = getListOfSessions().toTabs()
)
)
}
}
@ -633,10 +641,16 @@ class HomeFragment : Fragment() {
private fun removeAllTabsWithUndo(listOfSessionsToDelete: Sequence<Session>, private: Boolean) {
homeFragmentStore.dispatch(HomeFragmentAction.TabsChange(emptyList()))
listOfSessionsToDelete.forEach {
requireComponents.core.pendingSessionDeletionManager.addSession(
it.id
)
}
val deleteOperation: (suspend () -> Unit) = {
listOfSessionsToDelete.forEach {
sessionManager.remove(it)
requireComponents.core.pendingSessionDeletionManager.removeSession(it.id)
}
}
deleteAllSessionsJob = deleteOperation
@ -651,6 +665,11 @@ class HomeFragment : Fragment() {
view!!,
snackbarMessage,
getString(R.string.snackbar_deleted_undo), {
listOfSessionsToDelete.forEach {
requireComponents.core.pendingSessionDeletionManager.removeSession(
it.id
)
}
if (private) {
requireComponents.analytics.metrics.track(Event.PrivateBrowsingSnackbarUndoTapped)
}
@ -664,11 +683,13 @@ class HomeFragment : Fragment() {
private fun removeTabWithUndo(sessionId: String, private: Boolean) {
val sessionManager = requireComponents.core.sessionManager
requireComponents.core.pendingSessionDeletionManager.addSession(sessionId)
val deleteOperation: (suspend () -> Unit) = {
sessionManager.findSessionById(sessionId)
?.let { session ->
pendingSessionDeletion = null
sessionManager.remove(session)
requireComponents.core.pendingSessionDeletionManager.removeSession(sessionId)
}
}
@ -684,6 +705,7 @@ class HomeFragment : Fragment() {
view!!,
snackbarMessage,
getString(R.string.snackbar_deleted_undo), {
requireComponents.core.pendingSessionDeletionManager.removeSession(sessionId)
pendingSessionDeletion = null
emitSessionChanges()
},
@ -777,8 +799,12 @@ class HomeFragment : Fragment() {
border?.visibility = View.GONE
}
override fun onAnimationStart(animation: Animator?) { /* noop */ }
override fun onAnimationRepeat(animation: Animator?) { /* noop */ }
override fun onAnimationStart(animation: Animator?) { /* noop */
}
override fun onAnimationRepeat(animation: Animator?) { /* noop */
}
override fun onAnimationEnd(animation: Animator?) {
border?.animate()?.alpha(0.0F)?.setStartDelay(ANIM_ON_SCREEN_DELAY)
?.setDuration(FADE_ANIM_DURATION)