[fenix] closes https://github.com/mozilla-mobile/fenix/issues/23565: expire remote wallpapers but let users keep selected

pull/600/head
Matt Tighe 2 years ago committed by mergify[bot]
parent 1ff747b109
commit 72a0985403

@ -36,6 +36,7 @@ import org.mozilla.fenix.perf.StrictModeManager
import org.mozilla.fenix.perf.lazyMonitored
import org.mozilla.fenix.utils.ClipboardHandler
import org.mozilla.fenix.utils.Settings
import org.mozilla.fenix.wallpapers.WallpaperFileManager
import org.mozilla.fenix.wallpapers.WallpaperDownloader
import org.mozilla.fenix.wallpapers.WallpaperManager
import org.mozilla.fenix.wifi.WifiConnectionMonitor
@ -148,6 +149,7 @@ class Components(private val context: Context) {
WallpaperManager(
settings,
WallpaperDownloader(context, core.client, analytics.crashReporter),
WallpaperFileManager(context.filesDir),
analytics.crashReporter,
)
}

@ -953,7 +953,7 @@ private val Event.wrapper: EventWrapper<*>?
Wallpapers.wallpaperSelected.record(
Wallpapers.WallpaperSelectedExtra(
name = this.wallpaper.name,
themeCollection = this.wallpaper.themeCollection::class.simpleName,
themeCollection = this.wallpaper::class.simpleName,
),
)
}
@ -963,7 +963,7 @@ private val Event.wrapper: EventWrapper<*>?
Wallpapers.wallpaperSwitched.record(
Wallpapers.WallpaperSwitchedExtra(
name = this.wallpaper.name,
themeCollection = this.wallpaper.themeCollection::class.simpleName,
themeCollection = this.wallpaper::class.simpleName,
),
)
}

@ -87,7 +87,7 @@ fun WallpaperSettings(
SnackbarHost(hostState = hostState) {
WallpaperSnackbar(onViewWallpaper)
}
}
},
) {
Column {
WallpaperThumbnails(
@ -292,7 +292,7 @@ private fun WallpaperThumbnailsPreview() {
loadWallpaperResource = {
wallpaperManager.loadSavedWallpaper(context, it)
},
wallpapers = wallpaperManager.availableWallpapers,
wallpapers = wallpaperManager.wallpapers,
selectedWallpaper = wallpaperManager.currentWallpaper,
onSelectWallpaper = {},
onViewWallpaper = {},

@ -49,7 +49,7 @@ class WallpaperSettingsFragment : Fragment() {
var currentWallpaper by remember { mutableStateOf(wallpaperManager.currentWallpaper) }
var wallpapersSwitchedByLogo by remember { mutableStateOf(settings.wallpapersSwitchedByLogoTap) }
WallpaperSettings(
wallpapers = wallpaperManager.availableWallpapers,
wallpapers = wallpaperManager.wallpapers,
defaultWallpaper = WallpaperManager.defaultWallpaper,
loadWallpaperResource = {
wallpaperManager.loadSavedWallpaper(requireContext(), it)

@ -4,79 +4,62 @@
package org.mozilla.fenix.wallpapers
import android.content.Context
import android.content.res.Configuration
import org.mozilla.fenix.R
import androidx.annotation.DrawableRes
import java.util.Date
/**
* A class that represents an available wallpaper and its state.
* @property name Indicates the name of this wallpaper.
* @property portraitPath A file path for the portrait version of this wallpaper.
* @property landscapePath A file path for the landscape version of this wallpaper.
* @property isDark Indicates if the most predominant color on the wallpaper is dark.
* @property themeCollection The theme collection this wallpaper belongs to.
* Type hierarchy defining the various wallpapers that are available as home screen backgrounds.
* @property name The name of the wallpaper.
*/
data class Wallpaper(
val name: String,
val themeCollection: WallpaperThemeCollection,
)
sealed class Wallpaper {
abstract val name: String
/**
* A type hierarchy representing the different theme collections [Wallpaper]s belong to.
*/
enum class WallpaperThemeCollection(val origin: WallpaperOrigin) {
NONE(WallpaperOrigin.LOCAL),
FIREFOX(WallpaperOrigin.LOCAL),
FOCUS(WallpaperOrigin.REMOTE),
}
/**
* The default wallpaper. This uses the standard color resource to as a background, instead of
* loading a bitmap.
*/
object Default : Wallpaper() {
override val name = "default"
}
/**
* The parent directory name of a wallpaper. Since wallpapers that are [WallpaperOrigin.LOCAL] are
* stored in drawables, this extension is not applicable to them.
*/
val WallpaperThemeCollection.directoryName: String get() = when (this) {
WallpaperThemeCollection.NONE,
WallpaperThemeCollection.FIREFOX -> ""
WallpaperThemeCollection.FOCUS -> "focus"
}
/**
* Wallpapers that are included directly in the shipped APK.
*
* @property drawableId The drawable bitmap used as the background.
*/
sealed class Local : Wallpaper() {
abstract val drawableId: Int
data class Firefox(override val name: String, @DrawableRes override val drawableId: Int) : Local()
}
/**
* Types defining whether a [Wallpaper] is delivered through a remote source or is included locally
* in the APK.
*/
enum class WallpaperOrigin {
LOCAL,
REMOTE,
}
/**
* Wallpapers that need to be fetched from a network resource.
*
* @property expirationDate Optional date at which this wallpaper should no longer be available.
*/
sealed class Remote : Wallpaper() {
abstract val expirationDate: Date?
data class Focus(override val name: String, override val expirationDate: Date? = null) : Remote()
val Wallpaper.drawableId: Int get() = when (name) {
"amethyst" -> R.drawable.amethyst
"cerulean" -> R.drawable.cerulean
"sunrise" -> R.drawable.sunrise
else -> -1
}
/**
* Get the expected local path on disk for a wallpaper. This will differ depending
* on orientation and app theme.
*/
fun Wallpaper.getLocalPathFromContext(context: Context): String {
val orientation = if (context.isLandscape()) "landscape" else "portrait"
val theme = if (context.isDark()) "dark" else "light"
return getLocalPath(orientation, theme)
}
/**
* Get the expected local path on disk for a wallpaper if orientation and app theme are known.
*/
fun Wallpaper.getLocalPath(orientation: String, theme: String): String =
"$orientation/$theme/${themeCollection.directoryName}/$name.png"
private fun Context.isLandscape(): Boolean {
return resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
}
/**
* If a user had previously selected a wallpaper, they are allowed to retain it even if
* the wallpaper is otherwise expired. This type exists as a wrapper around that current
* wallpaper.
*/
data class Expired(override val name: String) : Remote() {
override val expirationDate: Date? = null
}
}
private fun Context.isDark(): Boolean {
return resources.configuration.uiMode and
Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
companion object {
/**
* Defines the standard path at which a wallpaper resource is kept on disk.
*
* @param orientation One of landscape/portrait.
* @param theme One of dark/light.
* @param name The name of the wallpaper.
*/
fun getBaseLocalPath(orientation: String, theme: String, name: String): String =
"wallpapers/$orientation/$theme/$name.png"
}
}

@ -35,8 +35,8 @@ class WallpaperDownloader(
* found at a remote path in the form:
* <WALLPAPER_URL>/<resolution>/<orientation>/<app theme>/<wallpaper theme>/<wallpaper name>.png
*/
suspend fun downloadWallpaper(wallpaper: Wallpaper) = withContext(Dispatchers.IO) {
for (metadata in wallpaper.toMetadata()) {
suspend fun downloadWallpaper(wallpaper: Wallpaper.Remote) = withContext(Dispatchers.IO) {
for (metadata in wallpaper.toMetadata(context)) {
val localFile = File(context.filesDir.absolutePath, metadata.localPath)
if (localFile.exists()) continue
val request = Request(
@ -62,18 +62,15 @@ class WallpaperDownloader(
private data class WallpaperMetadata(val remotePath: String, val localPath: String)
private fun Wallpaper.toMetadata(): List<WallpaperMetadata> = when (themeCollection.origin) {
WallpaperOrigin.LOCAL -> listOf()
WallpaperOrigin.REMOTE -> {
listOf("landscape", "portrait").flatMap { orientation ->
listOf("light", "dark").map { theme ->
val basePath = getLocalPath(orientation, theme)
val remotePath = "${context.resolutionSegment()}/$basePath"
WallpaperMetadata(remotePath, basePath)
}
private fun Wallpaper.Remote.toMetadata(context: Context): List<WallpaperMetadata> =
listOf("landscape", "portrait").flatMap { orientation ->
listOf("light", "dark").map { theme ->
val remoteParent = this::class.simpleName!!.lowercase()
val localPath = "wallpapers/$orientation/$theme/$name.png"
val remotePath = "${context.resolutionSegment()}/$orientation/$theme/$remoteParent$name.png"
WallpaperMetadata(remotePath, localPath)
}
}
}
@Suppress("MagicNumber")
private fun Context.resolutionSegment(): String = when (resources.displayMetrics.densityDpi) {

@ -0,0 +1,56 @@
/* 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.wallpapers
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
class WallpaperFileManager(
private val rootDirectory: File,
coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO
) {
private val scope = CoroutineScope(coroutineDispatcher)
private val portraitDirectory = File(rootDirectory, "wallpapers/portrait")
private val landscapeDirectory = File(rootDirectory, "wallpapers/landscape")
/**
* Lookup all the files for a wallpaper name. This lookup will fail if there are not
* files for each of the following orientation and theme combinations:
* light/portrait - light/landscape - dark/portrait - dark/landscape
*/
fun lookupExpiredWallpaper(name: String): Wallpaper.Remote.Expired? {
return if (getAllLocalWallpaperPaths(name).all { File(rootDirectory, it).exists() }) {
Wallpaper.Remote.Expired(name)
} else null
}
private fun getAllLocalWallpaperPaths(name: String): List<String> =
listOf("landscape", "portrait").flatMap { orientation ->
listOf("light", "dark").map { theme ->
Wallpaper.getBaseLocalPath(orientation, theme, name)
}
}
/**
* Remove all wallpapers that are not the [currentWallpaper] or in [availableWallpapers].
*/
fun clean(currentWallpaper: Wallpaper, availableWallpapers: List<Wallpaper.Remote>) {
val wallpapersToKeep = (listOf(currentWallpaper) + availableWallpapers).map { it.name }
cleanChildren(portraitDirectory, wallpapersToKeep)
cleanChildren(landscapeDirectory, wallpapersToKeep)
}
private fun cleanChildren(dir: File, wallpapersToKeep: List<String>) {
for (file in dir.walkTopDown()) {
if (file.isDirectory || file.nameWithoutExtension in wallpapersToKeep) continue
scope.launch {
file.delete()
}
}
}
}

@ -7,6 +7,7 @@ package org.mozilla.fenix.wallpapers
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Context
import android.content.res.Configuration
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
@ -22,6 +23,7 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.perf.runBlockingIncrement
import org.mozilla.fenix.utils.Settings
import java.io.File
import java.util.Date
/**
* Provides access to available wallpapers and manages their states.
@ -30,17 +32,13 @@ import java.io.File
class WallpaperManager(
private val settings: Settings,
private val downloader: WallpaperDownloader,
private val fileManager: WallpaperFileManager,
private val crashReporter: CrashReporter,
allWallpapers: List<Wallpaper> = availableWallpapers
) {
val logger = Logger("WallpaperManager")
private val remoteWallpapers = listOf(
Wallpaper(
"focus",
themeCollection = WallpaperThemeCollection.FOCUS
),
)
var availableWallpapers: List<Wallpaper> = localWallpapers + remoteWallpapers
private set
val wallpapers = allWallpapers.filter(::filterExpiredRemoteWallpapers)
var currentWallpaper: Wallpaper = getCurrentWallpaperFromSettings()
set(value) {
@ -48,6 +46,10 @@ class WallpaperManager(
field = value
}
init {
fileManager.clean(currentWallpaper, wallpapers.filterIsInstance<Wallpaper.Remote>())
}
/**
* Apply the [newWallpaper] into the [wallpaperContainer] and update the [currentWallpaper].
*/
@ -75,7 +77,7 @@ class WallpaperManager(
* Download all known remote wallpapers.
*/
suspend fun downloadAllRemoteWallpapers() {
for (wallpaper in remoteWallpapers) {
for (wallpaper in wallpapers.filterIsInstance<Wallpaper.Remote>()) {
downloader.downloadWallpaper(wallpaper)
}
}
@ -85,7 +87,7 @@ class WallpaperManager(
* the first available [Wallpaper] will be returned.
*/
fun switchToNextWallpaper(): Wallpaper {
val values = availableWallpapers
val values = wallpapers
val index = values.indexOf(currentWallpaper) + 1
return if (index >= values.size) {
@ -95,12 +97,22 @@ class WallpaperManager(
}
}
private fun filterExpiredRemoteWallpapers(wallpaper: Wallpaper): Boolean = when (wallpaper) {
is Wallpaper.Remote -> {
val notExpired = wallpaper.expirationDate?.let { Date().before(it) } ?: true
notExpired || wallpaper.name == settings.currentWallpaper
}
else -> true
}
private fun getCurrentWallpaperFromSettings(): Wallpaper {
val currentWallpaper = settings.currentWallpaper
return if (currentWallpaper.isEmpty()) {
defaultWallpaper
} else {
availableWallpapers.find { it.name == currentWallpaper } ?: defaultWallpaper
wallpapers.find { it.name == currentWallpaper }
?: fileManager.lookupExpiredWallpaper(currentWallpaper)
?: defaultWallpaper
}
}
@ -108,20 +120,20 @@ class WallpaperManager(
* Load a wallpaper that is saved locally.
*/
fun loadSavedWallpaper(context: Context, wallpaper: Wallpaper): Bitmap? =
if (wallpaper.themeCollection.origin == WallpaperOrigin.LOCAL) {
loadWallpaperFromDrawables(context, wallpaper)
} else {
loadWallpaperFromDisk(context, wallpaper)
when (wallpaper) {
is Wallpaper.Local -> loadWallpaperFromDrawables(context, wallpaper)
is Wallpaper.Remote -> loadWallpaperFromDisk(context, wallpaper)
else -> null
}
private fun loadWallpaperFromDrawables(context: Context, wallpaper: Wallpaper): Bitmap? = Result.runCatching {
private fun loadWallpaperFromDrawables(context: Context, wallpaper: Wallpaper.Local): Bitmap? = Result.runCatching {
BitmapFactory.decodeResource(context.resources, wallpaper.drawableId)
}.getOrNull()
/**
* Load a wallpaper from app-specific storage.
*/
private fun loadWallpaperFromDisk(context: Context, wallpaper: Wallpaper): Bitmap? = Result.runCatching {
private fun loadWallpaperFromDisk(context: Context, wallpaper: Wallpaper.Remote): Bitmap? = Result.runCatching {
val path = wallpaper.getLocalPathFromContext(context)
runBlockingIncrement {
withContext(Dispatchers.IO) {
@ -131,6 +143,25 @@ class WallpaperManager(
}
}.getOrNull()
/**
* Get the expected local path on disk for a wallpaper. This will differ depending
* on orientation and app theme.
*/
private fun Wallpaper.Remote.getLocalPathFromContext(context: Context): String {
val orientation = if (context.isLandscape()) "landscape" else "portrait"
val theme = if (context.isDark()) "dark" else "light"
return Wallpaper.getBaseLocalPath(orientation, theme, name)
}
private fun Context.isLandscape(): Boolean {
return resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
}
private fun Context.isDark(): Boolean {
return resources.configuration.uiMode and
Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
}
/**
* Animates the Firefox logo, if it hasn't been animated before, otherwise nothing will happen.
* After animating the first time, the [Settings.shouldAnimateFirefoxLogo] setting
@ -166,16 +197,18 @@ class WallpaperManager(
companion object {
const val DEFAULT_RESOURCE = R.attr.homeBackground
val defaultWallpaper = Wallpaper(
name = "default",
themeCollection = WallpaperThemeCollection.NONE
val defaultWallpaper = Wallpaper.Default
private val localWallpapers: List<Wallpaper.Local> = listOf(
Wallpaper.Local.Firefox("amethyst", R.drawable.amethyst),
Wallpaper.Local.Firefox("cerulean", R.drawable.cerulean),
Wallpaper.Local.Firefox("sunrise", R.drawable.sunrise),
)
val localWallpapers = listOf(
defaultWallpaper,
Wallpaper("amethyst", themeCollection = WallpaperThemeCollection.FIREFOX),
Wallpaper("cerulean", themeCollection = WallpaperThemeCollection.FIREFOX),
Wallpaper("sunrise", themeCollection = WallpaperThemeCollection.FIREFOX),
private val remoteWallpapers: List<Wallpaper.Remote> = listOf(
Wallpaper.Remote.Focus(
"focus",
),
)
private val availableWallpapers = listOf(defaultWallpaper) + localWallpapers + remoteWallpapers
private const val ANIMATION_DELAY_MS = 1500L
}
}

@ -0,0 +1,91 @@
/* 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.wallpapers
import kotlinx.coroutines.test.TestCoroutineDispatcher
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.io.File
class WallpaperFileManagerTest {
@Rule
@JvmField
val tempFolder = TemporaryFolder()
private lateinit var portraitLightFolder: File
private lateinit var portraitDarkFolder: File
private lateinit var landscapeLightFolder: File
private lateinit var landscapeDarkFolder: File
private val dispatcher = TestCoroutineDispatcher()
private lateinit var fileManager: WallpaperFileManager
@Before
fun setup() {
portraitLightFolder = tempFolder.newFolder("wallpapers", "portrait", "light")
portraitDarkFolder = tempFolder.newFolder("wallpapers", "portrait", "dark")
landscapeLightFolder = tempFolder.newFolder("wallpapers", "landscape", "light")
landscapeDarkFolder = tempFolder.newFolder("wallpapers", "landscape", "dark")
fileManager = WallpaperFileManager(
rootDirectory = tempFolder.root,
coroutineDispatcher = dispatcher,
)
}
@Test
fun `GIVEN files exist in all directories WHEN expired wallpaper looked up THEN expired wallpaper returned`() {
val wallpaperName = "name"
createAllFiles(wallpaperName)
val expected = Wallpaper.Remote.Expired(name = wallpaperName)
assertEquals(expected, fileManager.lookupExpiredWallpaper(wallpaperName))
}
@Test
fun `GIVEN any missing file in directories WHEN expired wallpaper looked up THEN null returned`() {
val wallpaperName = "name"
File(landscapeLightFolder, "$wallpaperName.png").createNewFile()
File(landscapeDarkFolder, "$wallpaperName.png").createNewFile()
assertEquals(null, fileManager.lookupExpiredWallpaper(wallpaperName))
}
@Test
fun `WHEN cleaned THEN current wallpaper and available wallpapers kept`() {
val currentName = "current"
val currentWallpaper = Wallpaper.Remote.Expired(currentName)
val availableName = "available"
val available = Wallpaper.Remote.Focus(name = availableName)
val unavailableName = "unavailable"
createAllFiles(currentName)
createAllFiles(availableName)
createAllFiles(unavailableName)
fileManager.clean(currentWallpaper, listOf(available))
assertTrue(getAllFiles(currentName).all { it.exists() })
assertTrue(getAllFiles(availableName).all { it.exists() })
assertTrue(getAllFiles(unavailableName).none { it.exists() })
}
private fun createAllFiles(name: String) {
for (file in getAllFiles(name)) {
file.createNewFile()
}
}
private fun getAllFiles(name: String): List<File> {
return listOf(
File(portraitLightFolder, "$name.png"),
File(portraitDarkFolder, "$name.png"),
File(landscapeLightFolder, "$name.png"),
File(landscapeDarkFolder, "$name.png"),
)
}
}

@ -1,32 +1,150 @@
package org.mozilla.fenix.wallpapers
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.runs
import io.mockk.slot
import kotlinx.coroutines.test.runBlockingTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.utils.Settings
import java.util.Calendar
import java.util.Date
class WallpaperManagerTest {
// initialize this once, so it can be shared throughout tests
private val baseFakeDate = Date()
private val fakeCalendar = Calendar.getInstance()
private val mockSettings: Settings = mockk()
private val mockMetrics: MetricController = mockk()
private val mockDownloader: WallpaperDownloader = mockk {
coEvery { downloadWallpaper(any()) } just runs
}
private val mockFileManager: WallpaperFileManager = mockk {
every { clean(any(), any()) } just runs
}
@Test
fun `WHEN wallpaper set THEN current wallpaper updated in settings`() {
every { mockMetrics.track(any()) } just runs
val currentCaptureSlot = slot<String>()
every { mockSettings.currentWallpaper } returns "a different name"
every { mockSettings.currentWallpaper } returns ""
every { mockSettings.currentWallpaper = capture(currentCaptureSlot) } just runs
val updatedWallpaper = WallpaperManager.defaultWallpaper
val wallpaperManager = WallpaperManager(mockSettings, mockk(), mockk())
val updatedName = "new name"
val updatedWallpaper = Wallpaper.Local.Firefox(updatedName, drawableId = 0)
val wallpaperManager = WallpaperManager(mockSettings, mockk(), mockFileManager, mockk(), listOf())
wallpaperManager.currentWallpaper = updatedWallpaper
assertEquals(updatedWallpaper.name, currentCaptureSlot.captured)
}
@Test
fun `GIVEN no remote wallpapers expired WHEN downloading remote wallpapers THEN all downloaded`() = runBlockingTest {
every { mockSettings.currentWallpaper } returns ""
val fakeRemoteWallpapers = listOf("first", "second", "third").map { name ->
makeFakeRemoteWallpaper(TimeRelation.LATER, name)
}
val wallpaperManager = WallpaperManager(
mockSettings,
mockDownloader,
mockFileManager,
mockk(),
allWallpapers = fakeRemoteWallpapers
)
wallpaperManager.downloadAllRemoteWallpapers()
for (fakeRemoteWallpaper in fakeRemoteWallpapers) {
coVerify { mockDownloader.downloadWallpaper(fakeRemoteWallpaper) }
}
}
@Test
fun `GIVEN some expired wallpapers WHEN initialized THEN wallpapers are not available`() {
every { mockSettings.currentWallpaper } returns ""
val expiredRemoteWallpaper = makeFakeRemoteWallpaper(TimeRelation.BEFORE, "expired")
val activeRemoteWallpaper = makeFakeRemoteWallpaper(TimeRelation.LATER, "expired")
val wallpaperManager = WallpaperManager(
mockSettings,
mockDownloader,
mockFileManager,
mockk(),
allWallpapers = listOf(expiredRemoteWallpaper, activeRemoteWallpaper)
)
assertFalse(wallpaperManager.wallpapers.contains(expiredRemoteWallpaper))
assertTrue(wallpaperManager.wallpapers.contains(activeRemoteWallpaper))
}
@Test
fun `GIVEN current wallpaper is expired THEN it is available as expired even when others are filtered`() {
val currentWallpaperName = "named"
val currentExpiredWallpaper = makeFakeRemoteWallpaper(TimeRelation.BEFORE, name = currentWallpaperName)
every { mockSettings.currentWallpaper } returns currentWallpaperName
val expiredRemoteWallpaper = makeFakeRemoteWallpaper(TimeRelation.BEFORE, "expired")
val expected = Wallpaper.Remote.Expired(currentWallpaperName)
every { mockFileManager.lookupExpiredWallpaper(currentWallpaperName) } returns expected
val wallpaperManager = WallpaperManager(
mockSettings,
mockDownloader,
mockFileManager,
mockk(),
allWallpapers = listOf(expiredRemoteWallpaper)
)
assertFalse(wallpaperManager.wallpapers.contains(expiredRemoteWallpaper))
assertFalse(wallpaperManager.wallpapers.contains(currentExpiredWallpaper))
assertEquals(expected, wallpaperManager.currentWallpaper)
}
@Test
fun `GIVEN current wallpaper is expired THEN it is available even if not listed in initial parameter`() {
val currentWallpaperName = "named"
every { mockSettings.currentWallpaper } returns currentWallpaperName
val expected = Wallpaper.Remote.Expired(currentWallpaperName)
every { mockFileManager.lookupExpiredWallpaper(currentWallpaperName) } returns expected
val wallpaperManager = WallpaperManager(
mockSettings,
mockDownloader,
mockFileManager,
mockk(),
allWallpapers = listOf()
)
assertEquals(expected, wallpaperManager.currentWallpaper)
}
private enum class TimeRelation {
BEFORE,
NOW,
LATER,
}
/**
* [timeRelation] should specify a time relative to the time the tests are run
*/
private fun makeFakeRemoteWallpaper(
timeRelation: TimeRelation,
name: String = "name"
): Wallpaper.Remote {
fakeCalendar.time = baseFakeDate
when (timeRelation) {
TimeRelation.BEFORE -> fakeCalendar.add(Calendar.DATE, -5)
TimeRelation.NOW -> Unit
TimeRelation.LATER -> fakeCalendar.add(Calendar.DATE, 5)
}
val relativeTime = fakeCalendar.time
return Wallpaper.Remote.Focus(name = name, expirationDate = relativeTime)
}
}

Loading…
Cancel
Save