For #3106: Granular options for clearing user data
parent
eb26d951ab
commit
2b9efccfca
|
@ -329,6 +329,7 @@ dependencies {
|
|||
|
||||
implementation Deps.kotlin_stdlib
|
||||
implementation Deps.kotlin_coroutines
|
||||
testImplementation Deps.kotlin_coroutines_test
|
||||
implementation Deps.androidx_appcompat
|
||||
implementation Deps.androidx_constraintlayout
|
||||
implementation Deps.androidx_coordinatorlayout
|
||||
|
|
|
@ -36,4 +36,10 @@ object FeatureFlags {
|
|||
* https://github.com/mozilla-mobile/fenix/issues/4431
|
||||
*/
|
||||
const val mediaIntegration = true
|
||||
|
||||
/**
|
||||
* Granular data deletion provides additional choices on the Delete Browsing Data
|
||||
* setting screen for cookies, cached images and files, and site permissions.
|
||||
*/
|
||||
val granularDataDeletion = nightly or debug
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/* 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.content.Context
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.withContext
|
||||
import mozilla.components.concept.engine.Engine
|
||||
import mozilla.components.feature.tab.collections.TabCollection
|
||||
import org.mozilla.fenix.ext.components
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
interface DeleteBrowsingDataController {
|
||||
suspend fun deleteTabs()
|
||||
suspend fun deleteBrowsingData()
|
||||
suspend fun deleteCollections(collections: List<TabCollection>)
|
||||
suspend fun deleteCookies()
|
||||
suspend fun deleteCachedFiles()
|
||||
suspend fun deleteSitePermissions()
|
||||
}
|
||||
|
||||
class DefaultDeleteBrowsingDataController(
|
||||
val context: Context,
|
||||
val coroutineContext: CoroutineContext = Dispatchers.Main
|
||||
) : DeleteBrowsingDataController {
|
||||
override suspend fun deleteTabs() {
|
||||
withContext(coroutineContext) {
|
||||
context.components.useCases.tabsUseCases.removeAllTabs.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deleteBrowsingData() {
|
||||
withContext(coroutineContext) {
|
||||
context.components.core.engine.clearData(Engine.BrowsingData.all())
|
||||
}
|
||||
context.components.core.historyStorage.deleteEverything()
|
||||
}
|
||||
|
||||
override suspend fun deleteCollections(collections: List<TabCollection>) {
|
||||
while (context.components.core.tabCollectionStorage.getTabCollectionsCount() != collections.size) {
|
||||
delay(DELAY_IN_MILLIS)
|
||||
}
|
||||
|
||||
collections.forEach { context.components.core.tabCollectionStorage.removeCollection(it) }
|
||||
}
|
||||
|
||||
override suspend fun deleteCookies() {
|
||||
withContext(coroutineContext) {
|
||||
context.components.core.engine.clearData(Engine.BrowsingData.select(Engine.BrowsingData.COOKIES))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deleteCachedFiles() {
|
||||
withContext(coroutineContext) {
|
||||
context.components.core.engine.clearData(
|
||||
Engine.BrowsingData.select(Engine.BrowsingData.ALL_CACHES)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deleteSitePermissions() {
|
||||
withContext(coroutineContext) {
|
||||
context.components.core.engine.clearData(
|
||||
Engine.BrowsingData.select(Engine.BrowsingData.ALL_SITE_SETTINGS)
|
||||
)
|
||||
}
|
||||
context.components.core.permissionStorage.deleteAllSitePermissions()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val DELAY_IN_MILLIS = 500L
|
||||
}
|
||||
}
|
|
@ -15,16 +15,17 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.paging.PagedList
|
||||
import androidx.paging.toLiveData
|
||||
import kotlinx.android.synthetic.main.fragment_delete_browsing_data.*
|
||||
import kotlinx.android.synthetic.main.fragment_delete_browsing_data.view.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.browser.session.SessionManager
|
||||
import mozilla.components.concept.engine.Engine
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||
import mozilla.components.feature.tab.collections.TabCollection
|
||||
import org.mozilla.fenix.FeatureFlags
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.components.FenixSnackbar
|
||||
import org.mozilla.fenix.components.metrics.Event
|
||||
|
@ -34,6 +35,7 @@ import org.mozilla.fenix.ext.requireComponents
|
|||
class DeleteBrowsingDataFragment : Fragment() {
|
||||
private lateinit var sessionObserver: SessionManager.Observer
|
||||
private var tabCollections: List<TabCollection> = listOf()
|
||||
private lateinit var controller: DeleteBrowsingDataController
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
@ -45,6 +47,8 @@ class DeleteBrowsingDataFragment : Fragment() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
controller = DefaultDeleteBrowsingDataController(context!!)
|
||||
|
||||
sessionObserver = object : SessionManager.Observer {
|
||||
override fun onSessionAdded(session: Session) = updateTabCount()
|
||||
override fun onSessionRemoved(session: Session) = updateTabCount()
|
||||
|
@ -60,9 +64,9 @@ class DeleteBrowsingDataFragment : Fragment() {
|
|||
})
|
||||
}
|
||||
|
||||
view.open_tabs_item?.onCheckListener = { _ -> updateDeleteButton() }
|
||||
view.browsing_data_item?.onCheckListener = { _ -> updateDeleteButton() }
|
||||
view.collections_item?.onCheckListener = { _ -> updateDeleteButton() }
|
||||
getCheckboxes().forEach {
|
||||
it.onCheckListener = { _ -> updateDeleteButton() }
|
||||
}
|
||||
view.delete_data?.setOnClickListener {
|
||||
askToDelete()
|
||||
}
|
||||
|
@ -75,10 +79,11 @@ class DeleteBrowsingDataFragment : Fragment() {
|
|||
supportActionBar?.show()
|
||||
}
|
||||
|
||||
updateTabCount()
|
||||
updateHistoryCount()
|
||||
updateCollectionsCount()
|
||||
updateDeleteButton()
|
||||
getCheckboxes().forEach {
|
||||
it.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
updateItemCounts()
|
||||
}
|
||||
|
||||
private fun askToDelete() {
|
||||
|
@ -100,15 +105,20 @@ class DeleteBrowsingDataFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun deleteSelected() {
|
||||
val openTabsChecked = view!!.open_tabs_item!!.isChecked
|
||||
val browsingDataChecked = view!!.browsing_data_item!!.isChecked
|
||||
val collectionsChecked = view!!.collections_item!!.isChecked
|
||||
|
||||
startDeletion()
|
||||
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
|
||||
if (openTabsChecked) deleteTabs()
|
||||
if (browsingDataChecked) deleteBrowsingData()
|
||||
if (collectionsChecked) deleteCollections()
|
||||
getCheckboxes().mapIndexed { i, v ->
|
||||
if (v.isChecked) {
|
||||
when (i) {
|
||||
OPEN_TABS_INDEX -> controller.deleteTabs()
|
||||
HISTORY_INDEX -> controller.deleteBrowsingData()
|
||||
COLLECTIONS_INDEX -> controller.deleteCollections(tabCollections)
|
||||
COOKIES_INDEX -> controller.deleteCookies()
|
||||
CACHED_INDEX -> controller.deleteCachedFiles()
|
||||
PERMS_INDEX -> controller.deleteSitePermissions()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
launch(Dispatchers.Main) {
|
||||
finishDeletion()
|
||||
|
@ -131,28 +141,34 @@ class DeleteBrowsingDataFragment : Fragment() {
|
|||
delete_browsing_data_wrapper.isClickable = true
|
||||
delete_browsing_data_wrapper.alpha = ENABLED_ALPHA
|
||||
|
||||
listOf(open_tabs_item, browsing_data_item, collections_item).forEach {
|
||||
getCheckboxes().forEach {
|
||||
it.isChecked = false
|
||||
}
|
||||
|
||||
updateTabCount()
|
||||
updateHistoryCount()
|
||||
updateCollectionsCount()
|
||||
updateItemCounts()
|
||||
|
||||
FenixSnackbar.make(view!!, FenixSnackbar.LENGTH_SHORT)
|
||||
.setText(resources.getString(R.string.preferences_delete_browsing_data_snackbar))
|
||||
.show()
|
||||
|
||||
if (popAfter) viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
|
||||
if (popAfter || FeatureFlags.granularDataDeletion) viewLifecycleOwner.lifecycleScope.launch(
|
||||
Dispatchers.Main
|
||||
) {
|
||||
findNavController().popBackStack(R.id.homeFragment, false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateItemCounts() {
|
||||
updateTabCount()
|
||||
updateHistoryCount()
|
||||
updateCollectionsCount()
|
||||
updateCookies()
|
||||
updateCachedImagesAndFiles()
|
||||
updateSitePermissions()
|
||||
}
|
||||
|
||||
private fun updateDeleteButton() {
|
||||
val openTabs = view!!.open_tabs_item!!.isChecked
|
||||
val browsingData = view!!.browsing_data_item!!.isChecked
|
||||
val collections = view!!.collections_item!!.isChecked
|
||||
val enabled = openTabs || browsingData || collections
|
||||
val enabled = getCheckboxes().any { it.isChecked }
|
||||
|
||||
view?.delete_data?.isEnabled = enabled
|
||||
view?.delete_data?.alpha = if (enabled) ENABLED_ALPHA else DISABLED_ALPHA
|
||||
|
@ -206,30 +222,52 @@ class DeleteBrowsingDataFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun deleteTabs() {
|
||||
withContext(Dispatchers.Main) {
|
||||
requireComponents.useCases.tabsUseCases.removeAllTabs.invoke()
|
||||
}
|
||||
private fun updateCookies() {
|
||||
// NO OP until we have GeckoView methods to count cookies
|
||||
}
|
||||
|
||||
private suspend fun deleteBrowsingData() {
|
||||
withContext(Dispatchers.Main) {
|
||||
requireComponents.core.engine.clearData(Engine.BrowsingData.all())
|
||||
}
|
||||
requireComponents.core.historyStorage.deleteEverything()
|
||||
private fun updateCachedImagesAndFiles() {
|
||||
// NO OP until we have GeckoView methods to count cached images and files
|
||||
}
|
||||
|
||||
private suspend fun deleteCollections() {
|
||||
while (requireComponents.core.tabCollectionStorage.getTabCollectionsCount() != tabCollections.size) {
|
||||
delay(DELAY_IN_MILLIS)
|
||||
}
|
||||
private fun updateSitePermissions() {
|
||||
val liveData =
|
||||
requireComponents.core.permissionStorage.getSitePermissionsPaged().toLiveData(1)
|
||||
liveData.observe(
|
||||
this,
|
||||
object : Observer<PagedList<SitePermissions>> {
|
||||
override fun onChanged(list: PagedList<SitePermissions>?) {
|
||||
view?.site_permissions_item?.isEnabled = !list.isNullOrEmpty()
|
||||
liveData.removeObserver(this)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
tabCollections.forEach { requireComponents.core.tabCollectionStorage.removeCollection(it) }
|
||||
private fun getCheckboxes(): List<DeleteBrowsingDataItem> {
|
||||
val fragmentView = view!!
|
||||
val originalList = listOf(
|
||||
fragmentView.open_tabs_item,
|
||||
fragmentView.browsing_data_item,
|
||||
fragmentView.collections_item
|
||||
)
|
||||
@Suppress("ConstantConditionIf")
|
||||
val granularList = if (FeatureFlags.granularDataDeletion) listOf(
|
||||
fragmentView.cookies_item,
|
||||
fragmentView.cached_files_item,
|
||||
fragmentView.site_permissions_item
|
||||
) else emptyList()
|
||||
return originalList + granularList
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ENABLED_ALPHA = 1f
|
||||
private const val DISABLED_ALPHA = 0.6f
|
||||
private const val DELAY_IN_MILLIS = 500L
|
||||
|
||||
private const val OPEN_TABS_INDEX = 0
|
||||
private const val HISTORY_INDEX = 1
|
||||
private const val COLLECTIONS_INDEX = 2
|
||||
private const val COOKIES_INDEX = 3
|
||||
private const val CACHED_INDEX = 4
|
||||
private const val PERMS_INDEX = 5
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,20 +48,15 @@ class DeleteBrowsingDataItem @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
context.withStyledAttributes(attrs, R.styleable.DeleteBrowsingDataItem, defStyleAttr, 0) {
|
||||
val iconId = getResourceId(
|
||||
R.styleable.DeleteBrowsingDataItem_deleteBrowsingDataItemIcon,
|
||||
R.drawable.library_icon_reading_list_circle_background
|
||||
)
|
||||
val titleId = getResourceId(
|
||||
R.styleable.DeleteBrowsingDataItem_deleteBrowsingDataItemTitle,
|
||||
R.string.browser_menu_your_library
|
||||
)
|
||||
val subtitleId = getResourceId(
|
||||
R.styleable.DeleteBrowsingDataItem_deleteBrowsingDataItemSubtitle,
|
||||
R.string.browser_menu_your_library
|
||||
R.string.empty_string
|
||||
)
|
||||
|
||||
icon.background = resources.getDrawable(iconId, context.theme)
|
||||
title.text = resources.getString(titleId)
|
||||
subtitle.text = resources.getString(subtitleId)
|
||||
}
|
||||
|
|
|
@ -9,17 +9,12 @@
|
|||
android:layout_height="@dimen/library_item_height"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="@dimen/library_item_icon_height"
|
||||
android:layout_height="@dimen/library_item_icon_height"
|
||||
android:layout_marginStart="@dimen/library_item_icon_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/library_item_icon_margin_vertical"
|
||||
android:layout_marginEnd="@dimen/library_item_icon_margin_horizontal"
|
||||
android:layout_marginBottom="@dimen/library_item_icon_margin_vertical"
|
||||
android:background="@drawable/library_icon_reading_list_circle_background"
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox"
|
||||
android:clickable="false"
|
||||
android:importantForAccessibility="no"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
@ -32,9 +27,9 @@
|
|||
android:textAppearance="@style/ListItemTextStyle"
|
||||
android:clickable="false"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintStart_toEndOf="@id/icon"
|
||||
app:layout_constraintEnd_toStartOf="@id/checkbox"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintStart_toEndOf="@id/checkbox"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Open Tabs" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtitle"
|
||||
|
@ -43,17 +38,7 @@
|
|||
android:layout_marginStart="@dimen/library_item_icon_margin_horizontal"
|
||||
android:textAppearance="@style/SubtitleTextStyle"
|
||||
android:clickable="false"
|
||||
app:layout_constraintStart_toEndOf="@id/icon"
|
||||
app:layout_constraintEnd_toStartOf="@id/checkbox"
|
||||
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox"
|
||||
android:clickable="false"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintStart_toEndOf="@id/checkbox"
|
||||
app:layout_constraintTop_toBottomOf="@id/title"
|
||||
tools:text="2 Open Tabs" />
|
||||
</merge>
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:deleteBrowsingDataItemIcon="@drawable/ic_tab_circle_background"
|
||||
app:deleteBrowsingDataItemTitle="@string/preferences_delete_browsing_data_tabs_title"
|
||||
app:deleteBrowsingDataItemSubtitle="@string/preferences_delete_browsing_data_tabs_subtitle" />
|
||||
<org.mozilla.fenix.settings.DeleteBrowsingDataItem
|
||||
|
@ -46,7 +45,6 @@
|
|||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:deleteBrowsingDataItemIcon="@drawable/library_icon_history_circle_background"
|
||||
app:deleteBrowsingDataItemTitle="@string/preferences_delete_browsing_data_browsing_data_title"
|
||||
app:deleteBrowsingDataItemSubtitle="@string/preferences_delete_browsing_data_browsing_data_subtitle" />
|
||||
<org.mozilla.fenix.settings.DeleteBrowsingDataItem
|
||||
|
@ -56,9 +54,37 @@
|
|||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:deleteBrowsingDataItemIcon="@drawable/ic_collections_circle_background"
|
||||
app:deleteBrowsingDataItemTitle="@string/preferences_delete_browsing_data_collections_title"
|
||||
app:deleteBrowsingDataItemSubtitle="@string/preferences_delete_browsing_data_collections_subtitle" />
|
||||
<org.mozilla.fenix.settings.DeleteBrowsingDataItem
|
||||
android:id="@+id/cookies_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:visibility="gone"
|
||||
app:deleteBrowsingDataItemTitle="@string/preferences_delete_browsing_data_cookies"
|
||||
app:deleteBrowsingDataItemSubtitle="@string/preferences_delete_browsing_data_cookies_subtitle" />
|
||||
<org.mozilla.fenix.settings.DeleteBrowsingDataItem
|
||||
android:id="@+id/cached_files_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:visibility="gone"
|
||||
app:deleteBrowsingDataItemTitle="@string/preferences_delete_browsing_data_cached_files"
|
||||
app:deleteBrowsingDataItemSubtitle="@string/preferences_delete_browsing_data_cached_files_subtitle" />
|
||||
<org.mozilla.fenix.settings.DeleteBrowsingDataItem
|
||||
android:id="@+id/site_permissions_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:visibility="gone"
|
||||
app:deleteBrowsingDataItemTitle="@string/preferences_delete_browsing_data_site_permissions" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/delete_data"
|
||||
style="@style/ThemeIndependentMaterialGreyButtonDestructive"
|
||||
|
|
|
@ -21,4 +21,7 @@
|
|||
<!-- 1.0.1 strings -->
|
||||
<!-- Bookmark deletion confirmation -->
|
||||
<string name="bookmark_deletion_confirmation" translatable="false">Are you sure you want to delete this bookmark?</string>
|
||||
|
||||
<!--suppress CheckTagEmptyBody This is a default value for places where we don't want a string set-->
|
||||
<string name="empty_string" translatable="false"></string>
|
||||
</resources>
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
/* 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.content.Context
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.mockk.Runs
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.ObsoleteCoroutinesApi
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.newSingleThreadContext
|
||||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import kotlinx.coroutines.test.setMain
|
||||
import mozilla.components.concept.engine.Engine
|
||||
import mozilla.components.feature.tab.collections.TabCollection
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.TestApplication
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@ObsoleteCoroutinesApi
|
||||
@ExperimentalCoroutinesApi
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@Config(application = TestApplication::class)
|
||||
class DefaultDeleteBrowsingDataControllerTest {
|
||||
|
||||
private val mainThreadSurrogate = newSingleThreadContext("UI thread")
|
||||
|
||||
private val context: Context = mockk(relaxed = true)
|
||||
private lateinit var controller: DefaultDeleteBrowsingDataController
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
Dispatchers.setMain(mainThreadSurrogate)
|
||||
|
||||
every { context.components.core.engine.clearData(any()) } just Runs
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
Dispatchers.resetMain() // reset main dispatcher to the original Main dispatcher
|
||||
mainThreadSurrogate.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deleteTabs() = runBlockingTest {
|
||||
controller = DefaultDeleteBrowsingDataController(context, coroutineContext)
|
||||
every { context.components.useCases.tabsUseCases.removeAllTabs.invoke() } just Runs
|
||||
|
||||
controller.deleteTabs()
|
||||
|
||||
verify {
|
||||
context.components.useCases.tabsUseCases.removeAllTabs.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deleteBrowsingData() = runBlockingTest {
|
||||
controller = DefaultDeleteBrowsingDataController(context, coroutineContext)
|
||||
every { context.components.core.historyStorage } returns mockk(relaxed = true)
|
||||
|
||||
controller.deleteBrowsingData()
|
||||
|
||||
verify {
|
||||
context.components.core.engine.clearData(Engine.BrowsingData.all())
|
||||
context.components.core.historyStorage
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deleteCollections() = runBlockingTest {
|
||||
controller = DefaultDeleteBrowsingDataController(context, coroutineContext)
|
||||
|
||||
val collections: List<TabCollection> = listOf(mockk(relaxed = true))
|
||||
every { context.components.core.tabCollectionStorage.getTabCollectionsCount() } returns 1
|
||||
|
||||
controller.deleteCollections(collections)
|
||||
|
||||
verify {
|
||||
context.components.core.tabCollectionStorage.removeCollection(collections[0])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deleteCookies() = runBlockingTest {
|
||||
controller = DefaultDeleteBrowsingDataController(context, coroutineContext)
|
||||
|
||||
controller.deleteCookies()
|
||||
|
||||
verify {
|
||||
context.components.core.engine.clearData(Engine.BrowsingData.select(Engine.BrowsingData.COOKIES))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deleteCachedFiles() = runBlockingTest {
|
||||
controller = DefaultDeleteBrowsingDataController(context, coroutineContext)
|
||||
|
||||
controller.deleteCachedFiles()
|
||||
|
||||
verify {
|
||||
context.components.core.engine.clearData(Engine.BrowsingData.select(Engine.BrowsingData.ALL_CACHES))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deleteSitePermissions() = runBlockingTest {
|
||||
controller = DefaultDeleteBrowsingDataController(context, coroutineContext)
|
||||
every { context.components.core.permissionStorage.deleteAllSitePermissions() } just Runs
|
||||
|
||||
launch(IO) {
|
||||
controller.deleteSitePermissions()
|
||||
}
|
||||
|
||||
verify {
|
||||
context.components.core.engine.clearData(Engine.BrowsingData.select(Engine.BrowsingData.ALL_SITE_SETTINGS))
|
||||
context.components.core.permissionStorage.deleteAllSitePermissions()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
object Versions {
|
||||
const val kotlin = "1.3.30"
|
||||
const val coroutines = "1.3.0-RC2"
|
||||
const val coroutines = "1.3.1"
|
||||
const val android_gradle_plugin = "3.5.0"
|
||||
const val newest_r8 = "ceaee94e172c6c057cc05e646f5324853fc5d4c5"
|
||||
const val rxAndroid = "2.1.0"
|
||||
|
@ -73,6 +73,7 @@ object Deps {
|
|||
const val tools_kotlingradle = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}"
|
||||
const val kotlin_stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.kotlin}"
|
||||
const val kotlin_coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.coroutines}"
|
||||
const val kotlin_coroutines_test = "org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.coroutines}"
|
||||
const val kotlin_coroutines_android = "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.coroutines}"
|
||||
|
||||
const val allopen = "org.jetbrains.kotlin:kotlin-allopen:${Versions.kotlin}"
|
||||
|
|
Loading…
Reference in New Issue