1
0
Fork 0

For #3700 - Add Setting to Delete Data on "Quit" menu action

master
Emily Kager 2019-09-10 13:29:21 -07:00 committed by Emily Kager
parent ddc1b2e648
commit e3209dcc84
23 changed files with 616 additions and 21 deletions

View File

@ -78,11 +78,12 @@ events:
description: >
A string containing the name of the item the user tapped. These items include:
Settings, Library, Help, Desktop Site toggle on/off, Find in Page, New Tab,
Private Tab, Share, Report Site Issue, Back/Forward button, Reload Button
Private Tab, Share, Report Site Issue, Back/Forward button, Reload Button, Quit
bugs:
- 1024
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/1214#issue-264756708
- https://github.com/mozilla-mobile/fenix/pull/5098#issuecomment-529658996
notification_emails:
- fenix-core@mozilla.com
expires: "2020-03-01"

View File

@ -47,4 +47,9 @@ object FeatureFlags {
* setting screen for cookies, cached images and files, and site permissions.
*/
val granularDataDeletion = nightly or debug
/**
* Gives option in Settings to Delete Browsing Data on new menu option Quit
*/
val deleteDataOnQuit = nightly or debug
}

View File

@ -171,7 +171,8 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs
action = Intent.ACTION_VIEW
flags = Intent.FLAG_ACTIVITY_NEW_TASK
},
bottomSheetBehavior = QuickActionSheetBehavior.from(nestedScrollQuickAction)
bottomSheetBehavior = QuickActionSheetBehavior.from(nestedScrollQuickAction),
scope = lifecycleScope
)
browserInteractor =

View File

@ -266,7 +266,7 @@ sealed class Event {
enum class Item {
SETTINGS, LIBRARY, HELP, DESKTOP_VIEW_ON, DESKTOP_VIEW_OFF, FIND_IN_PAGE, NEW_TAB,
NEW_PRIVATE_TAB, SHARE, REPORT_SITE_ISSUE, BACK, FORWARD, RELOAD, STOP, OPEN_IN_FENIX,
SAVE_TO_COLLECTION, ADD_TO_HOMESCREEN
SAVE_TO_COLLECTION, ADD_TO_HOMESCREEN, QUIT
}
override val extras: Map<Events.browserMenuActionKeys, String>?

View File

@ -8,6 +8,7 @@ import android.app.Activity
import android.content.Context
import android.content.Intent
import androidx.core.widget.NestedScrollView
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.navigation.NavController
import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlinx.coroutines.ExperimentalCoroutinesApi
@ -29,6 +30,7 @@ import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.toTab
import org.mozilla.fenix.lib.Do
import org.mozilla.fenix.quickactionsheet.QuickActionSheetBehavior
import org.mozilla.fenix.utils.deleteAndQuit
/**
* An interface that handles the view manipulation of the BrowserToolbar, triggered by the Interactor
@ -50,7 +52,8 @@ class DefaultBrowserToolbarController(
private val viewModel: CreateCollectionViewModel,
private val getSupportUrl: () -> String,
private val openInFenixIntent: Intent,
private val bottomSheetBehavior: QuickActionSheetBehavior<NestedScrollView>
private val bottomSheetBehavior: QuickActionSheetBehavior<NestedScrollView>,
private val scope: LifecycleCoroutineScope
) : BrowserToolbarController {
override fun handleToolbarPaste(text: String) {
@ -176,6 +179,7 @@ class DefaultBrowserToolbarController(
// Close this activity since it is no longer displaying any session
(context as Activity).finish()
}
ToolbarMenu.Item.Quit -> context.deleteAndQuit(scope)
}
}
@ -204,6 +208,7 @@ class DefaultBrowserToolbarController(
ToolbarMenu.Item.Share -> Event.BrowserMenuItemTapped.Item.SHARE
ToolbarMenu.Item.SaveToCollection -> Event.BrowserMenuItemTapped.Item.SAVE_TO_COLLECTION
ToolbarMenu.Item.AddToHomeScreen -> Event.BrowserMenuItemTapped.Item.ADD_TO_HOMESCREEN
ToolbarMenu.Item.Quit -> Event.BrowserMenuItemTapped.Item.QUIT
}
context.components.analytics.metrics.track(Event.BrowserMenuItemTapped(eventItem))

View File

@ -17,6 +17,7 @@ import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.ext.asActivity
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.theme.ThemeManager
import org.mozilla.fenix.utils.Settings
class DefaultToolbarMenu(
private val context: Context,
@ -203,6 +204,18 @@ class DefaultToolbarMenu(
)
}
if (Settings.getInstance(context).shouldDeleteBrowsingDataOnQuit) {
items.add(
BrowserMenuImageText(
context.getString(R.string.delete_browsing_data_on_quit_action),
R.drawable.ic_exit,
ThemeManager.resolveAttribute(R.attr.primaryText, context)
) {
onItemTapped.invoke(ToolbarMenu.Item.Quit)
}
)
}
items.add(
BrowserMenuDivider()
)

View File

@ -25,6 +25,7 @@ interface ToolbarMenu {
object OpenInFenix : Item()
object SaveToCollection : Item()
object AddToHomeScreen : Item()
object Quit : Item()
}
val menuBuilder: BrowserMenuBuilder

View File

@ -34,12 +34,19 @@ class DefaultDeleteBrowsingDataController(
}
override suspend fun deleteBrowsingData() {
withContext(coroutineContext) {
if (FeatureFlags.granularDataDeletion) {
context.components.core.engine.clearData(Engine.BrowsingData.select(Engine.BrowsingData.DOM_STORAGES))
} else {
if (FeatureFlags.granularDataDeletion) {
deleteHistoryAndDOMStorages()
} else {
withContext(coroutineContext) {
context.components.core.engine.clearData(Engine.BrowsingData.all())
}
context.components.core.historyStorage.deleteEverything()
}
}
suspend fun deleteHistoryAndDOMStorages() {
withContext(coroutineContext) {
context.components.core.engine.clearData(Engine.BrowsingData.select(Engine.BrowsingData.DOM_STORAGES))
}
context.components.core.historyStorage.deleteEverything()
}

View File

@ -0,0 +1,105 @@
/* 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.settings
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.CheckBoxPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.getPreferenceKey
import org.mozilla.fenix.utils.Settings
class DeleteBrowsingDataOnQuitFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.delete_browsing_data_quit_preferences, rootKey)
}
@Suppress("ComplexMethod")
override fun onResume() {
super.onResume()
activity?.title = getString(R.string.preferences_delete_browsing_data_on_quit)
(activity as AppCompatActivity).supportActionBar?.show()
val checkboxUpdater = object : SharedPreferenceUpdater() {
override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
super.onPreferenceChange(preference, newValue)
if (!Settings.getInstance(preference.context).shouldDeleteAnyDataOnQuit()) {
findPreference<SwitchPreference>(
getPreferenceKey(R.string.pref_key_delete_browsing_data_on_quit)
)?.apply {
isChecked = false
}
Settings.getInstance(preference.context).preferences.edit().putBoolean(
getString(R.string.pref_key_delete_browsing_data_on_quit),
false
).apply()
}
return true
}
}
val switchUpdater = object : SharedPreferenceUpdater() {
override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
setAllCheckboxes(newValue as Boolean)
return super.onPreferenceChange(preference, newValue)
}
}
findPreference<CheckBoxPreference>(getPreferenceKey(R.string.pref_key_delete_open_tabs_on_quit))?.apply {
onPreferenceChangeListener = checkboxUpdater
}
findPreference<CheckBoxPreference>(getPreferenceKey(R.string.pref_key_delete_browsing_history_on_quit))?.apply {
onPreferenceChangeListener = checkboxUpdater
}
findPreference<CheckBoxPreference>(getPreferenceKey(R.string.pref_key_delete_caches_on_quit))?.apply {
onPreferenceChangeListener = checkboxUpdater
}
findPreference<CheckBoxPreference>(getPreferenceKey(R.string.pref_key_delete_permissions_on_quit))?.apply {
onPreferenceChangeListener = checkboxUpdater
}
findPreference<CheckBoxPreference>(getPreferenceKey(R.string.pref_key_delete_cookies_on_quit))?.apply {
onPreferenceChangeListener = checkboxUpdater
}
// Delete Browsing Data on Quit Switch
val deleteOnQuitKey = getPreferenceKey(R.string.pref_key_delete_browsing_data_on_quit)
findPreference<SwitchPreference>(deleteOnQuitKey)?.apply {
onPreferenceChangeListener = switchUpdater
isChecked = Settings.getInstance(context!!).shouldDeleteBrowsingDataOnQuit
}
}
private fun setAllCheckboxes(newValue: Boolean) {
val openTabs =
findPreference<CheckBoxPreference>(getPreferenceKey(R.string.pref_key_delete_open_tabs_on_quit))
val history =
findPreference<CheckBoxPreference>(getPreferenceKey(R.string.pref_key_delete_browsing_history_on_quit))
val cache =
findPreference<CheckBoxPreference>(getPreferenceKey(R.string.pref_key_delete_caches_on_quit))
val permissions =
findPreference<CheckBoxPreference>(getPreferenceKey(R.string.pref_key_delete_permissions_on_quit))
val cookies =
findPreference<CheckBoxPreference>(getPreferenceKey(R.string.pref_key_delete_cookies_on_quit))
openTabs?.isChecked = newValue
history?.isChecked = newValue
cache?.isChecked = newValue
permissions?.isChecked = newValue
cookies?.isChecked = newValue
Settings.getInstance(context!!).preferences.edit().putBoolean(openTabs?.key, newValue)
.apply()
Settings.getInstance(context!!).preferences.edit().putBoolean(history?.key, newValue)
.apply()
Settings.getInstance(context!!).preferences.edit().putBoolean(cache?.key, newValue).apply()
Settings.getInstance(context!!).preferences.edit().putBoolean(permissions?.key, newValue)
.apply()
Settings.getInstance(context!!).preferences.edit().putBoolean(cookies?.key, newValue)
.apply()
}
}

View File

@ -29,6 +29,7 @@ import mozilla.components.concept.sync.OAuthAccount
import mozilla.components.concept.sync.Profile
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.Config
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.FenixApplication
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
@ -40,6 +41,7 @@ import org.mozilla.fenix.R.string.pref_key_account_category
import org.mozilla.fenix.R.string.pref_key_add_private_browsing_shortcut
import org.mozilla.fenix.R.string.pref_key_data_choices
import org.mozilla.fenix.R.string.pref_key_delete_browsing_data
import org.mozilla.fenix.R.string.pref_key_delete_browsing_data_on_quit_preference
import org.mozilla.fenix.R.string.pref_key_help
import org.mozilla.fenix.R.string.pref_key_language
import org.mozilla.fenix.R.string.pref_key_leakcanary
@ -99,6 +101,14 @@ class SettingsFragment : PreferenceFragmentCompat(), AccountObserver {
isVisible = false
}
}
if (FeatureFlags.deleteDataOnQuit) {
findPreference<Preference>(
getPreferenceKey(R.string.pref_key_delete_browsing_data_on_quit_preference)
)?.apply {
isVisible = true
}
}
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
@ -203,6 +213,9 @@ class SettingsFragment : PreferenceFragmentCompat(), AccountObserver {
resources.getString(pref_key_delete_browsing_data) -> {
navigateToDeleteBrowsingData()
}
resources.getString(pref_key_delete_browsing_data_on_quit_preference) -> {
navigateToDeleteBrowsingDataOnQuit()
}
resources.getString(pref_key_theme) -> {
navigateToThemeSettings()
}
@ -335,6 +348,12 @@ class SettingsFragment : PreferenceFragmentCompat(), AccountObserver {
Navigation.findNavController(view!!).navigate(directions)
}
private fun navigateToDeleteBrowsingDataOnQuit() {
val directions =
SettingsFragmentDirections.actionSettingsFragmentToDeleteBrowsingDataOnQuitFragment()
Navigation.findNavController(view!!).navigate(directions)
}
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) {
lifecycleScope.launch {
context?.let {

View File

@ -8,7 +8,7 @@ import org.mozilla.fenix.ext.settings
* Updates the corresponding [android.content.SharedPreferences] when the boolean [Preference] is changed.
* The preference key is used as the shared preference key.
*/
class SharedPreferenceUpdater : Preference.OnPreferenceChangeListener {
open class SharedPreferenceUpdater : Preference.OnPreferenceChangeListener {
override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
val newBooleanValue = newValue as? Boolean ?: return false

View File

@ -0,0 +1,43 @@
/* 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.utils
import android.content.Context
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.mozilla.fenix.ext.asActivity
import org.mozilla.fenix.settings.DefaultDeleteBrowsingDataController
/**
* Deletes selected browsing data and finishes the activity
*/
fun Context.deleteAndQuit(coroutineScope: CoroutineScope) {
coroutineScope.launch {
runBlocking {
val controller =
DefaultDeleteBrowsingDataController(this@deleteAndQuit, coroutineContext)
if (Settings.getInstance(this@deleteAndQuit).deleteCacheOnQuit) {
controller.deleteCachedFiles()
}
if (Settings.getInstance(this@deleteAndQuit).deleteTabsOnQuit) {
controller.deleteTabs()
}
if (Settings.getInstance(this@deleteAndQuit).deletePermissionsOnQuit) {
launch(Dispatchers.IO) {
controller.deleteSitePermissions()
}
}
if (Settings.getInstance(this@deleteAndQuit).deleteCookiesOnQuit) {
controller.deleteCookies()
}
if (Settings.getInstance(this@deleteAndQuit).deleteHistoryOnQuit) {
controller.deleteHistoryAndDOMStorages()
}
}
this@deleteAndQuit.asActivity()?.finish()
}
}

View File

@ -27,6 +27,7 @@ import java.security.InvalidParameterException
/**
* A simple wrapper for SharedPreferences that makes reading preference a little bit easier.
*/
@Suppress("LargeClass")
class Settings private constructor(
context: Context,
private val isCrashReportEnabledInBuild: Boolean
@ -168,6 +169,44 @@ class Settings private constructor(
true
)
var shouldDeleteBrowsingDataOnQuit by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_delete_browsing_data_on_quit),
default = false
)
var deleteTabsOnQuit by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_delete_open_tabs_on_quit),
default = false
)
var deleteHistoryOnQuit by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_delete_browsing_history_on_quit),
default = false
)
var deleteCookiesOnQuit by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_delete_cookies_on_quit),
default = false
)
var deleteCacheOnQuit by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_delete_caches_on_quit),
default = false
)
var deletePermissionsOnQuit by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_delete_permissions_on_quit),
default = false
)
fun shouldDeleteAnyDataOnQuit(): Boolean {
return deleteCacheOnQuit ||
deleteCookiesOnQuit ||
deleteHistoryOnQuit ||
deletePermissionsOnQuit ||
deleteTabsOnQuit
}
val themeSettingString: String
get() = when {
shouldFollowDeviceTheme -> appContext.getString(R.string.preference_follow_device_theme)
@ -265,7 +304,10 @@ class Settings private constructor(
)
private val numTimesPrivateModeOpened: Int
get() = preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_private_mode_opened), 0)
get() = preferences.getInt(
appContext.getPreferenceKey(R.string.pref_key_private_mode_opened),
0
)
val showPrivateModeContextualFeatureRecommender: Boolean
get() {
@ -275,7 +317,7 @@ class Settings private constructor(
val showCondition =
(numTimesPrivateModeOpened == CFR_COUNT_CONDITION_FOCUS_INSTALLED && focusInstalled) ||
(numTimesPrivateModeOpened == CFR_COUNT_CONDITION_FOCUS_NOT_INSTALLED && !focusInstalled)
(numTimesPrivateModeOpened == CFR_COUNT_CONDITION_FOCUS_NOT_INSTALLED && !focusInstalled)
if (showCondition && !showedPrivateModeContextualFeatureRecommender) {
showedPrivateModeContextualFeatureRecommender = true

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?primaryText"
android:pathData="M12,1a11,11 0,1 0,11 11A11,11 0,0 0,12 1zM12,21a9,9 0,1 1,9 -9,9 9,0 0,1 -9,9zM16.71,7.29a1,1 0,0 0,-1.42 0L12,10.59l-3.29,-3.3a1,1 0,1 0,-1.42 1.42l3.3,3.29 -3.3,3.29a1,1 0,0 0,0 1.42,1 1,0 0,0 1.42,0l3.29,-3.3 3.29,3.3a1,1 0,0 0,1.42 0,1 1,0 0,0 0,-1.42L13.41,12l3.3,-3.29a1,1 0,0 0,0 -1.42z" />
</vector>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="64dp"
android:background="?android:selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingEnd="?android:attr/scrollbarSize">
<LinearLayout
android:id="@android:id/widget_frame"
android:layout_width="48dp"
android:layout_height="0dp"
android:gravity="center_vertical"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@android:id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@android:id/summary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@android:id/widget_frame"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Delete browsing data category" />
<TextView
android:id="@android:id/summary"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@android:id/widget_frame"
app:layout_constraintTop_toBottomOf="@android:id/title"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Delete browsing data summary" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -110,7 +110,7 @@
android:name="pastedText"
android:defaultValue="@null"
app:argType="string"
app:nullable="true"/>
app:nullable="true" />
</fragment>
<fragment
@ -253,7 +253,7 @@
app:argType="string" />
<action
android:id="@+id/action_bookmarkFragment_to_browserFragment"
app:destination="@id/browserFragment"/>
app:destination="@id/browserFragment" />
<action
android:id="@+id/action_bookmarkFragment_self"
app:destination="@id/bookmarkFragment" />
@ -359,6 +359,9 @@
<action
android:id="@+id/action_settingsFragment_to_accountProblemFragment"
app:destination="@id/accountProblemFragment" />
<action
android:id="@+id/action_settingsFragment_to_deleteBrowsingDataOnQuitFragment"
app:destination="@id/deleteBrowsingDataOnQuitFragment" />
</fragment>
<fragment
android:id="@+id/dataChoicesFragment"
@ -407,7 +410,7 @@
<fragment
android:id="@+id/pairFragment"
android:name="org.mozilla.fenix.settings.PairFragment"
android:label="@string/preferences_sync"></fragment>
android:label="@string/preferences_sync" />
<fragment
android:id="@+id/aboutFragment"
@ -566,4 +569,8 @@
android:name="strictMode"
app:argType="boolean" />
</fragment>
<fragment
android:id="@+id/deleteBrowsingDataOnQuitFragment"
android:name="org.mozilla.fenix.settings.DeleteBrowsingDataOnQuitFragment"
android:label="DeleteBrowsingDataOnQuitFragment" />
</navigation>

View File

@ -16,6 +16,15 @@
<string name="pref_key_data_choices" translatable="false">pref_key_data_choices</string>
<string name="pref_key_privacy_link" translatable="false">pref_key_privacy_link</string>
<string name="pref_key_delete_browsing_data" translatable="false">pref_key_delete_browsing_data</string>
<string name="pref_key_delete_browsing_data_on_quit_preference" translatable="false">pref_key_delete_browsing_data_on_quit_preference</string>
<string name="pref_key_delete_browsing_data_on_quit" translatable="false">pref_key_delete_browsing_data_on_quit</string>
<string name="pref_key_delete_open_tabs_on_quit" translatable="false">pref_key_delete_open_tabs_on_quit</string>
<string name="pref_key_delete_browsing_history_on_quit" translatable="false">pref_key_delete_browsing_history_on_quit</string>
<string name="pref_key_delete_cookies_on_quit" translatable="false">pref_key_delete_cookies_on_quit</string>
<string name="pref_key_delete_caches_on_quit" translatable="false">pref_key_delete_caches_on_quit</string>
<string name="pref_key_delete_permissions_on_quit" translatable="false">pref_key_delete_permissions_on_quit</string>
<string name="pref_key_delete_browsing_data_on_quit_categories" translatable="false">pref_key_delete_browsing_data_on_quit_categories</string>
<string name="pref_key_help" translatable="false">pref_key_help</string>
<string name="pref_key_rate" translatable="false">pref_key_rate</string>
<string name="pref_key_feedback" translatable="false">pref_key_feedback</string>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<SwitchPreference
android:defaultValue="false"
android:key="@string/pref_key_delete_browsing_data_on_quit"
android:summary="@string/preference_summary_delete_browsing_data_on_quit_2"
android:title="@string/preferences_delete_browsing_data_on_quit" />
<PreferenceCategory
android:dependency="@string/pref_key_delete_browsing_data_on_quit"
android:key="@string/pref_key_delete_browsing_data_on_quit_categories"
app:allowDividerAbove="false"
app:iconSpaceReserved="false">
<CheckBoxPreference
android:key="@string/pref_key_delete_open_tabs_on_quit"
android:layout="@layout/delete_browsing_category_checkbox"
android:title="@string/preferences_delete_browsing_data_tabs_title" />
<CheckBoxPreference
android:key="@string/pref_key_delete_browsing_history_on_quit"
android:layout="@layout/delete_browsing_category_checkbox"
android:title="@string/preferences_delete_browsing_data_on_quit_browsing_history" />
<CheckBoxPreference
android:key="@string/pref_key_delete_cookies_on_quit"
android:layout="@layout/delete_browsing_category_checkbox"
android:summary="@string/preferences_delete_browsing_data_cookies_subtitle"
android:title="@string/preferences_delete_browsing_data_cookies" />
<CheckBoxPreference
android:key="@string/pref_key_delete_caches_on_quit"
android:layout="@layout/delete_browsing_category_checkbox"
android:summary="@string/preferences_delete_browsing_data_cached_files_subtitle"
android:title="@string/preferences_delete_browsing_data_cached_files" />
<CheckBoxPreference
android:key="@string/pref_key_delete_permissions_on_quit"
android:layout="@layout/delete_browsing_category_checkbox"
android:title="@string/preferences_delete_browsing_data_site_permissions" />
</PreferenceCategory>
</androidx.preference.PreferenceScreen>

View File

@ -70,6 +70,11 @@
android:icon="@drawable/ic_delete"
android:key="@string/pref_key_delete_browsing_data"
android:title="@string/preferences_delete_browsing_data" />
<androidx.preference.Preference
app:isPreferenceVisible="false"
android:icon="@drawable/ic_exit"
android:key="@string/pref_key_delete_browsing_data_on_quit_preference"
android:title="@string/preferences_delete_browsing_data_on_quit" />
<androidx.preference.Preference
android:icon="@drawable/ic_data_collection"
android:key="@string/pref_key_data_choices"

View File

@ -4,8 +4,10 @@
package org.mozilla.fenix.components.toolbar
import android.content.Context
import android.content.Intent
import androidx.core.widget.NestedScrollView
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.navigation.NavController
import io.mockk.Runs
import io.mockk.every
@ -14,13 +16,18 @@ import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.verify
import io.mockk.verifyOrder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.newSingleThreadContext
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import mozilla.components.concept.engine.EngineView
import mozilla.components.feature.session.SessionUseCases
import mozilla.components.feature.tabs.TabsUseCases
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.mozilla.fenix.HomeActivity
@ -40,11 +47,14 @@ import org.mozilla.fenix.ext.toTab
import org.mozilla.fenix.home.sessioncontrol.Tab
import org.mozilla.fenix.home.sessioncontrol.TabCollection
import org.mozilla.fenix.quickactionsheet.QuickActionSheetBehavior
import org.mozilla.fenix.utils.deleteAndQuit
@ExperimentalCoroutinesApi
@ObsoleteCoroutinesApi
class DefaultBrowserToolbarControllerTest {
private val mainThreadSurrogate = newSingleThreadContext("UI thread")
private var context: HomeActivity = mockk(relaxed = true)
private var analytics: Analytics = mockk(relaxed = true)
private val browsingModeManager: BrowsingModeManager = mockk(relaxed = true)
@ -56,14 +66,18 @@ class DefaultBrowserToolbarControllerTest {
private val getSupportUrl: () -> String = { "https://supportUrl.org" }
private val openInFenixIntent: Intent = mockk(relaxed = true)
private val currentSessionAsTab: Tab = mockk(relaxed = true)
private val bottomSheetBehavior: QuickActionSheetBehavior<NestedScrollView> = mockk(relaxed = true)
private val bottomSheetBehavior: QuickActionSheetBehavior<NestedScrollView> =
mockk(relaxed = true)
private val metrics: MetricController = mockk(relaxed = true)
private val sessionUseCases: SessionUseCases = mockk(relaxed = true)
private val scope: LifecycleCoroutineScope = mockk(relaxed = true)
private lateinit var controller: DefaultBrowserToolbarController
@Before
fun setUp() {
Dispatchers.setMain(mainThreadSurrogate)
controller = DefaultBrowserToolbarController(
context = context,
navController = navController,
@ -74,7 +88,8 @@ class DefaultBrowserToolbarControllerTest {
viewModel = viewModel,
getSupportUrl = getSupportUrl,
openInFenixIntent = openInFenixIntent,
bottomSheetBehavior = bottomSheetBehavior
bottomSheetBehavior = bottomSheetBehavior,
scope = scope
)
mockkStatic(
@ -82,6 +97,11 @@ class DefaultBrowserToolbarControllerTest {
)
every { any<Session>().toTab(any()) } returns currentSessionAsTab
mockkStatic(
"org.mozilla.fenix.utils.DeleteAndQuitKt"
)
every { any<Context>().deleteAndQuit(any()) } just Runs
every { context.components.analytics } returns analytics
every { analytics.metrics } returns metrics
every { context.components.useCases.sessionUseCases } returns sessionUseCases
@ -117,6 +137,12 @@ class DefaultBrowserToolbarControllerTest {
}
}
@After
fun tearDown() {
Dispatchers.resetMain() // reset main dispatcher to the original Main dispatcher
mainThreadSurrogate.close()
}
@Test
fun handleToolbarClick() {
every { currentSession.id } returns "1"
@ -208,7 +234,8 @@ class DefaultBrowserToolbarControllerTest {
@Test
fun handleToolbarRequestDesktopOnPress() {
val requestDesktopSiteUseCase: SessionUseCases.RequestDesktopSiteUseCase = mockk(relaxed = true)
val requestDesktopSiteUseCase: SessionUseCases.RequestDesktopSiteUseCase =
mockk(relaxed = true)
val item = ToolbarMenu.Item.RequestDesktop(true)
every { sessionUseCases.requestDesktopSite } returns requestDesktopSiteUseCase
@ -226,7 +253,8 @@ class DefaultBrowserToolbarControllerTest {
@Test
fun handleToolbarRequestDesktopOffPress() {
val requestDesktopSiteUseCase: SessionUseCases.RequestDesktopSiteUseCase = mockk(relaxed = true)
val requestDesktopSiteUseCase: SessionUseCases.RequestDesktopSiteUseCase =
mockk(relaxed = true)
val item = ToolbarMenu.Item.RequestDesktop(false)
every { sessionUseCases.requestDesktopSite } returns requestDesktopSiteUseCase
@ -309,7 +337,12 @@ class DefaultBrowserToolbarControllerTest {
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.REPORT_SITE_ISSUE)) }
verify {
// Hardcoded URL because this function modifies the URL with an apply
addTabUseCase.invoke(String.format(BrowserFragment.REPORT_SITE_ISSUE_URL, "https://mozilla.org"))
addTabUseCase.invoke(
String.format(
BrowserFragment.REPORT_SITE_ISSUE_URL,
"https://mozilla.org"
)
)
}
}
@ -386,7 +419,8 @@ class DefaultBrowserToolbarControllerTest {
viewModel = viewModel,
getSupportUrl = getSupportUrl,
openInFenixIntent = openInFenixIntent,
bottomSheetBehavior = bottomSheetBehavior
bottomSheetBehavior = bottomSheetBehavior,
scope = scope
)
val sessionManager: SessionManager = mockk(relaxed = true)
@ -404,4 +438,13 @@ class DefaultBrowserToolbarControllerTest {
verify { context.startActivity(openInFenixIntent) }
verify { context.finish() }
}
@Test
fun handleToolbarQuitPress() {
val item = ToolbarMenu.Item.Quit
controller.handleToolbarItemInteraction(item)
verify { context.deleteAndQuit(scope) }
}
}

View File

@ -0,0 +1,140 @@
/* 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/. */
@file:Suppress("DEPRECATION")
package org.mozilla.fenix.utils
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.newSingleThreadContext
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.test.setMain
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
import mozilla.components.concept.engine.Engine
import mozilla.components.feature.tabs.TabsUseCases
import mozilla.components.support.test.robolectric.testContext
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.TestApplication
import org.mozilla.fenix.components.PermissionStorage
import org.mozilla.fenix.ext.asActivity
import org.mozilla.fenix.ext.clearAndCommit
import org.mozilla.fenix.ext.components
import org.robolectric.annotation.Config
@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
@RunWith(AndroidJUnit4::class)
@Config(application = TestApplication::class)
class DeleteAndQuitTest {
private val mainThreadSurrogate = newSingleThreadContext("UI thread")
private var context: HomeActivity = mockk(relaxed = true)
lateinit var settings: Settings
private val tabUseCases: TabsUseCases = mockk(relaxed = true)
private val historyStorage: PlacesHistoryStorage = mockk(relaxed = true)
private val permissionStorage: PermissionStorage = mockk(relaxed = true)
private val engine: Engine = mockk(relaxed = true)
private val removeAllTabsUseCases: TabsUseCases.RemoveAllTabsUseCase = mockk(relaxed = true)
@Before
fun setUp() {
settings = Settings.getInstance(testContext).apply {
clear()
}
Dispatchers.setMain(mainThreadSurrogate)
every { context.components.core.historyStorage } returns historyStorage
every { context.components.core.permissionStorage } returns permissionStorage
every { context.components.useCases.tabsUseCases } returns tabUseCases
every { tabUseCases.removeAllTabs } returns removeAllTabsUseCases
every { context.components.core.engine } returns engine
}
@After
fun tearDown() {
Dispatchers.resetMain() // reset main dispatcher to the original Main dispatcher
mainThreadSurrogate.close()
}
private fun Settings.clear() {
preferences.clearAndCommit()
}
@Test
fun `delete only tabs and quit`() = runBlockingTest {
// When
settings.deleteTabsOnQuit = true
context.deleteAndQuit(this)
verify {
removeAllTabsUseCases.invoke()
context.asActivity()?.finish()
}
verify(exactly = 0) {
historyStorage
engine.clearData(
Engine.BrowsingData.select(
Engine.BrowsingData.COOKIES
)
)
permissionStorage.deleteAllSitePermissions()
engine.clearData(Engine.BrowsingData.allCaches())
}
}
@Test
fun `delete everything and quit`() = runBlockingTest {
// When
settings.deleteTabsOnQuit = true
settings.deletePermissionsOnQuit = true
settings.deleteHistoryOnQuit = true
settings.deleteCookiesOnQuit = true
settings.deleteCacheOnQuit = true
context.deleteAndQuit(this)
verify(exactly = 1) {
engine.clearData(Engine.BrowsingData.allCaches())
removeAllTabsUseCases.invoke()
engine.clearData(
Engine.BrowsingData.select(Engine.BrowsingData.ALL_SITE_SETTINGS)
)
permissionStorage.deleteAllSitePermissions()
engine.clearData(
Engine.BrowsingData.select(
Engine.BrowsingData.COOKIES,
Engine.BrowsingData.AUTH_SESSIONS
)
)
engine.clearData(Engine.BrowsingData.select(Engine.BrowsingData.DOM_STORAGES))
historyStorage
context.asActivity()?.finish()
}
}
}

View File

@ -54,6 +54,51 @@ class SettingsTest {
assertFalse(settings.usePrivateMode)
}
@Test
fun clearDataOnQuit() {
// When just created
// Then
assertFalse(settings.shouldDeleteBrowsingDataOnQuit)
// When
settings.shouldDeleteBrowsingDataOnQuit = true
// Then
assertTrue(settings.shouldDeleteBrowsingDataOnQuit)
// When
settings.shouldDeleteBrowsingDataOnQuit = false
// Then
assertFalse(settings.shouldDeleteBrowsingDataOnQuit)
}
@Test
fun clearAnyDataOnQuit() {
// When just created
// Then
assertFalse(settings.shouldDeleteAnyDataOnQuit())
// When
settings.deleteTabsOnQuit = true
// Then
assertTrue(settings.shouldDeleteAnyDataOnQuit())
// When
settings.deletePermissionsOnQuit = true
// Then
assertTrue(settings.shouldDeleteAnyDataOnQuit())
// When
settings.deletePermissionsOnQuit = false
settings.deleteTabsOnQuit = false
// Then
assertFalse(settings.shouldDeleteAnyDataOnQuit())
}
@Test
fun defaultSearchEngineName() {
// When just created

View File

@ -76,11 +76,12 @@
<td>event</td>
<td>A browser menu item was tapped</td>
<td><a href="https://github.com/mozilla-mobile/fenix/pull/1214#issue-264756708">link</a></td>
<td><a href="https://github.com/mozilla-mobile/fenix/pull/5098#issuecomment-529658996">link</a></td>
<td>
<table>
<tr><td>item</td><td>A string containing the name of the item the user tapped. These items include:
Settings, Library, Help, Desktop Site toggle on/off, Find in Page, New Tab,
Private Tab, Share, Report Site Issue, Back/Forward button, Reload Button</td></tr>
Private Tab, Share, Report Site Issue, Back/Forward button, Reload Button, Quit</td></tr>
</table>
</td>
<td>2020-03-01</td>