1
0
Fork 0

For #3106: Granular options for clearing user data

master
Colin Lee 2019-09-04 15:27:30 -05:00 committed by Emily Kager
parent eb26d951ab
commit 2b9efccfca
10 changed files with 340 additions and 77 deletions

View File

@ -329,6 +329,7 @@ dependencies {
implementation Deps.kotlin_stdlib implementation Deps.kotlin_stdlib
implementation Deps.kotlin_coroutines implementation Deps.kotlin_coroutines
testImplementation Deps.kotlin_coroutines_test
implementation Deps.androidx_appcompat implementation Deps.androidx_appcompat
implementation Deps.androidx_constraintlayout implementation Deps.androidx_constraintlayout
implementation Deps.androidx_coordinatorlayout implementation Deps.androidx_coordinatorlayout

View File

@ -36,4 +36,10 @@ object FeatureFlags {
* https://github.com/mozilla-mobile/fenix/issues/4431 * https://github.com/mozilla-mobile/fenix/issues/4431
*/ */
const val mediaIntegration = true 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
} }

View File

@ -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
}
}

View File

@ -15,16 +15,17 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController 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.*
import kotlinx.android.synthetic.main.fragment_delete_browsing_data.view.* import kotlinx.android.synthetic.main.fragment_delete_browsing_data.view.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import mozilla.components.browser.session.Session import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager 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 mozilla.components.feature.tab.collections.TabCollection
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
@ -34,6 +35,7 @@ import org.mozilla.fenix.ext.requireComponents
class DeleteBrowsingDataFragment : Fragment() { class DeleteBrowsingDataFragment : Fragment() {
private lateinit var sessionObserver: SessionManager.Observer private lateinit var sessionObserver: SessionManager.Observer
private var tabCollections: List<TabCollection> = listOf() private var tabCollections: List<TabCollection> = listOf()
private lateinit var controller: DeleteBrowsingDataController
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -45,6 +47,8 @@ class DeleteBrowsingDataFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
controller = DefaultDeleteBrowsingDataController(context!!)
sessionObserver = object : SessionManager.Observer { sessionObserver = object : SessionManager.Observer {
override fun onSessionAdded(session: Session) = updateTabCount() override fun onSessionAdded(session: Session) = updateTabCount()
override fun onSessionRemoved(session: Session) = updateTabCount() override fun onSessionRemoved(session: Session) = updateTabCount()
@ -60,9 +64,9 @@ class DeleteBrowsingDataFragment : Fragment() {
}) })
} }
view.open_tabs_item?.onCheckListener = { _ -> updateDeleteButton() } getCheckboxes().forEach {
view.browsing_data_item?.onCheckListener = { _ -> updateDeleteButton() } it.onCheckListener = { _ -> updateDeleteButton() }
view.collections_item?.onCheckListener = { _ -> updateDeleteButton() } }
view.delete_data?.setOnClickListener { view.delete_data?.setOnClickListener {
askToDelete() askToDelete()
} }
@ -75,10 +79,11 @@ class DeleteBrowsingDataFragment : Fragment() {
supportActionBar?.show() supportActionBar?.show()
} }
updateTabCount() getCheckboxes().forEach {
updateHistoryCount() it.visibility = View.VISIBLE
updateCollectionsCount() }
updateDeleteButton()
updateItemCounts()
} }
private fun askToDelete() { private fun askToDelete() {
@ -100,15 +105,20 @@ class DeleteBrowsingDataFragment : Fragment() {
} }
private fun deleteSelected() { private fun deleteSelected() {
val openTabsChecked = view!!.open_tabs_item!!.isChecked
val browsingDataChecked = view!!.browsing_data_item!!.isChecked
val collectionsChecked = view!!.collections_item!!.isChecked
startDeletion() startDeletion()
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) { viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
if (openTabsChecked) deleteTabs() getCheckboxes().mapIndexed { i, v ->
if (browsingDataChecked) deleteBrowsingData() if (v.isChecked) {
if (collectionsChecked) deleteCollections() 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) { launch(Dispatchers.Main) {
finishDeletion() finishDeletion()
@ -131,28 +141,34 @@ class DeleteBrowsingDataFragment : Fragment() {
delete_browsing_data_wrapper.isClickable = true delete_browsing_data_wrapper.isClickable = true
delete_browsing_data_wrapper.alpha = ENABLED_ALPHA delete_browsing_data_wrapper.alpha = ENABLED_ALPHA
listOf(open_tabs_item, browsing_data_item, collections_item).forEach { getCheckboxes().forEach {
it.isChecked = false it.isChecked = false
} }
updateTabCount() updateItemCounts()
updateHistoryCount()
updateCollectionsCount()
FenixSnackbar.make(view!!, FenixSnackbar.LENGTH_SHORT) FenixSnackbar.make(view!!, FenixSnackbar.LENGTH_SHORT)
.setText(resources.getString(R.string.preferences_delete_browsing_data_snackbar)) .setText(resources.getString(R.string.preferences_delete_browsing_data_snackbar))
.show() .show()
if (popAfter) viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) { if (popAfter || FeatureFlags.granularDataDeletion) viewLifecycleOwner.lifecycleScope.launch(
Dispatchers.Main
) {
findNavController().popBackStack(R.id.homeFragment, false) findNavController().popBackStack(R.id.homeFragment, false)
} }
} }
private fun updateItemCounts() {
updateTabCount()
updateHistoryCount()
updateCollectionsCount()
updateCookies()
updateCachedImagesAndFiles()
updateSitePermissions()
}
private fun updateDeleteButton() { private fun updateDeleteButton() {
val openTabs = view!!.open_tabs_item!!.isChecked val enabled = getCheckboxes().any { it.isChecked }
val browsingData = view!!.browsing_data_item!!.isChecked
val collections = view!!.collections_item!!.isChecked
val enabled = openTabs || browsingData || collections
view?.delete_data?.isEnabled = enabled view?.delete_data?.isEnabled = enabled
view?.delete_data?.alpha = if (enabled) ENABLED_ALPHA else DISABLED_ALPHA view?.delete_data?.alpha = if (enabled) ENABLED_ALPHA else DISABLED_ALPHA
@ -206,30 +222,52 @@ class DeleteBrowsingDataFragment : Fragment() {
} }
} }
private suspend fun deleteTabs() { private fun updateCookies() {
withContext(Dispatchers.Main) { // NO OP until we have GeckoView methods to count cookies
requireComponents.useCases.tabsUseCases.removeAllTabs.invoke()
}
} }
private suspend fun deleteBrowsingData() { private fun updateCachedImagesAndFiles() {
withContext(Dispatchers.Main) { // NO OP until we have GeckoView methods to count cached images and files
requireComponents.core.engine.clearData(Engine.BrowsingData.all())
}
requireComponents.core.historyStorage.deleteEverything()
} }
private suspend fun deleteCollections() { private fun updateSitePermissions() {
while (requireComponents.core.tabCollectionStorage.getTabCollectionsCount() != tabCollections.size) { val liveData =
delay(DELAY_IN_MILLIS) 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 { companion object {
private const val ENABLED_ALPHA = 1f private const val ENABLED_ALPHA = 1f
private const val DISABLED_ALPHA = 0.6f 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
} }
} }

View File

@ -48,20 +48,15 @@ class DeleteBrowsingDataItem @JvmOverloads constructor(
} }
context.withStyledAttributes(attrs, R.styleable.DeleteBrowsingDataItem, defStyleAttr, 0) { 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( val titleId = getResourceId(
R.styleable.DeleteBrowsingDataItem_deleteBrowsingDataItemTitle, R.styleable.DeleteBrowsingDataItem_deleteBrowsingDataItemTitle,
R.string.browser_menu_your_library R.string.browser_menu_your_library
) )
val subtitleId = getResourceId( val subtitleId = getResourceId(
R.styleable.DeleteBrowsingDataItem_deleteBrowsingDataItemSubtitle, 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) title.text = resources.getString(titleId)
subtitle.text = resources.getString(subtitleId) subtitle.text = resources.getString(subtitleId)
} }

View File

@ -9,17 +9,12 @@
android:layout_height="@dimen/library_item_height" android:layout_height="@dimen/library_item_height"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout"> tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<ImageView <CheckBox
android:id="@+id/icon" android:id="@+id/checkbox"
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"
android:clickable="false" 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_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
@ -32,9 +27,9 @@
android:textAppearance="@style/ListItemTextStyle" android:textAppearance="@style/ListItemTextStyle"
android:clickable="false" android:clickable="false"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
app:layout_constraintStart_toEndOf="@id/icon" app:layout_constraintStart_toEndOf="@id/checkbox"
app:layout_constraintEnd_toStartOf="@id/checkbox" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintTop_toTopOf="parent" /> tools:text="Open Tabs" />
<TextView <TextView
android:id="@+id/subtitle" android:id="@+id/subtitle"
@ -43,17 +38,7 @@
android:layout_marginStart="@dimen/library_item_icon_margin_horizontal" android:layout_marginStart="@dimen/library_item_icon_margin_horizontal"
android:textAppearance="@style/SubtitleTextStyle" android:textAppearance="@style/SubtitleTextStyle"
android:clickable="false" android:clickable="false"
app:layout_constraintStart_toEndOf="@id/icon" app:layout_constraintStart_toEndOf="@id/checkbox"
app:layout_constraintEnd_toStartOf="@id/checkbox" app:layout_constraintTop_toBottomOf="@id/title"
app:layout_constraintTop_toBottomOf="@id/title" /> tools:text="2 Open Tabs" />
<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" />
</merge> </merge>

View File

@ -36,7 +36,6 @@
android:background="?android:attr/selectableItemBackground" android:background="?android:attr/selectableItemBackground"
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
app:deleteBrowsingDataItemIcon="@drawable/ic_tab_circle_background"
app:deleteBrowsingDataItemTitle="@string/preferences_delete_browsing_data_tabs_title" app:deleteBrowsingDataItemTitle="@string/preferences_delete_browsing_data_tabs_title"
app:deleteBrowsingDataItemSubtitle="@string/preferences_delete_browsing_data_tabs_subtitle" /> app:deleteBrowsingDataItemSubtitle="@string/preferences_delete_browsing_data_tabs_subtitle" />
<org.mozilla.fenix.settings.DeleteBrowsingDataItem <org.mozilla.fenix.settings.DeleteBrowsingDataItem
@ -46,7 +45,6 @@
android:background="?android:attr/selectableItemBackground" android:background="?android:attr/selectableItemBackground"
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
app:deleteBrowsingDataItemIcon="@drawable/library_icon_history_circle_background"
app:deleteBrowsingDataItemTitle="@string/preferences_delete_browsing_data_browsing_data_title" app:deleteBrowsingDataItemTitle="@string/preferences_delete_browsing_data_browsing_data_title"
app:deleteBrowsingDataItemSubtitle="@string/preferences_delete_browsing_data_browsing_data_subtitle" /> app:deleteBrowsingDataItemSubtitle="@string/preferences_delete_browsing_data_browsing_data_subtitle" />
<org.mozilla.fenix.settings.DeleteBrowsingDataItem <org.mozilla.fenix.settings.DeleteBrowsingDataItem
@ -56,9 +54,37 @@
android:background="?android:attr/selectableItemBackground" android:background="?android:attr/selectableItemBackground"
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
app:deleteBrowsingDataItemIcon="@drawable/ic_collections_circle_background"
app:deleteBrowsingDataItemTitle="@string/preferences_delete_browsing_data_collections_title" app:deleteBrowsingDataItemTitle="@string/preferences_delete_browsing_data_collections_title"
app:deleteBrowsingDataItemSubtitle="@string/preferences_delete_browsing_data_collections_subtitle" /> 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 <com.google.android.material.button.MaterialButton
android:id="@+id/delete_data" android:id="@+id/delete_data"
style="@style/ThemeIndependentMaterialGreyButtonDestructive" style="@style/ThemeIndependentMaterialGreyButtonDestructive"

View File

@ -21,4 +21,7 @@
<!-- 1.0.1 strings --> <!-- 1.0.1 strings -->
<!-- Bookmark deletion confirmation --> <!-- Bookmark deletion confirmation -->
<string name="bookmark_deletion_confirmation" translatable="false">Are you sure you want to delete this bookmark?</string> <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> </resources>

View File

@ -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()
}
}
}

View File

@ -4,7 +4,7 @@
object Versions { object Versions {
const val kotlin = "1.3.30" 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 android_gradle_plugin = "3.5.0"
const val newest_r8 = "ceaee94e172c6c057cc05e646f5324853fc5d4c5" const val newest_r8 = "ceaee94e172c6c057cc05e646f5324853fc5d4c5"
const val rxAndroid = "2.1.0" 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 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_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 = "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 kotlin_coroutines_android = "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.coroutines}"
const val allopen = "org.jetbrains.kotlin:kotlin-allopen:${Versions.kotlin}" const val allopen = "org.jetbrains.kotlin:kotlin-allopen:${Versions.kotlin}"