For #3700 - Add Setting to Delete Data on "Quit" menu action
parent
ddc1b2e648
commit
e3209dcc84
@ -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()
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue