diff --git a/components/feature/downloads/src/main/java/mozilla/components/feature/downloads/DownloadMiddleware.kt b/components/feature/downloads/src/main/java/mozilla/components/feature/downloads/DownloadMiddleware.kt index 19677e30713..1df1c2ffa4b 100644 --- a/components/feature/downloads/src/main/java/mozilla/components/feature/downloads/DownloadMiddleware.kt +++ b/components/feature/downloads/src/main/java/mozilla/components/feature/downloads/DownloadMiddleware.kt @@ -55,21 +55,21 @@ class DownloadMiddleware( is DownloadAction.RemoveAllDownloadsAction -> removeDownloads() is DownloadAction.UpdateDownloadAction -> updateDownload(action.download, context) is DownloadAction.RestoreDownloadsStateAction -> restoreDownloads(context.store) + is DownloadAction.AddDownloadAction -> { + if (!saveDownload(context.store, action.download)) { + // The download was already added before, so we are ignoring this request. + logger.debug("Ignored add action for ${action.download.id} " + + "download already in store.downloads") + return + } + } } next(action) when (action) { - is DownloadAction.AddDownloadAction -> { - scope.launch { - downloadStorage.add(action.download) - logger.debug("Added download ${action.download.fileName} to the storage") - } - sendDownloadIntent(action.download) - } - is DownloadAction.RestoreDownloadStateAction -> { - sendDownloadIntent(action.download) - } + is DownloadAction.AddDownloadAction -> sendDownloadIntent(action.download) + is DownloadAction.RestoreDownloadStateAction -> sendDownloadIntent(action.download) } } @@ -111,6 +111,18 @@ class DownloadMiddleware( } } + private fun saveDownload(store: Store, download: DownloadState): Boolean { + return if (!store.state.downloads.containsKey(download.id)) { + scope.launch { + downloadStorage.add(download) + logger.debug("Added download ${download.fileName} to the storage") + } + true + } else { + false + } + } + @VisibleForTesting internal fun sendDownloadIntent(download: DownloadState) { if (download.status !in arrayOf(COMPLETED, CANCELLED, FAILED)) { diff --git a/components/feature/downloads/src/test/java/mozilla/components/feature/downloads/DownloadMiddlewareTest.kt b/components/feature/downloads/src/test/java/mozilla/components/feature/downloads/DownloadMiddlewareTest.kt index bde65aada38..2cb221ebb3f 100644 --- a/components/feature/downloads/src/test/java/mozilla/components/feature/downloads/DownloadMiddlewareTest.kt +++ b/components/feature/downloads/src/test/java/mozilla/components/feature/downloads/DownloadMiddlewareTest.kt @@ -112,6 +112,29 @@ class DownloadMiddlewareTest { verify(downloadStorage).add(download) } + @Test + fun `previously added downloads MUST be ignored`() = runBlockingTest { + val applicationContext: Context = mock() + val downloadStorage: DownloadStorage = mock() + val download = DownloadState("https://mozilla.org/download") + val downloadMiddleware = DownloadMiddleware( + applicationContext, + AbstractFetchDownloadService::class.java, + downloadStorage = downloadStorage, + coroutineContext = dispatcher + ) + val store = BrowserStore( + initialState = BrowserState( + downloads = mapOf(download.id to download) + ), + middleware = listOf(downloadMiddleware) + ) + + store.dispatch(DownloadAction.AddDownloadAction(download)).joinBlocking() + + verify(downloadStorage, never()).add(download) + } + @Test fun `RemoveDownloadAction MUST remove from the storage`() = runBlockingTest { val applicationContext: Context = mock() diff --git a/docs/changelog.md b/docs/changelog.md index 9ccea5c1031..461296e1f67 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -19,6 +19,8 @@ permalink: /changelog/ * ⚠️ **This is a breaking change**: Removed `TabsUseCases.removeAllTabsOfType()`. * **browser-session** * Added `SessionManager.removeNormalSessions()` and `SessionManager.removePrivateSessions()`. +* **feature-downloads** + * 🚒 Bug fixed [issue #8456](https://github.com/mozilla-mobile/android-components/issues/8456) Crash SQLiteConstraintException UNIQUE constraint failed: downloads.id (code 1555). # 59.0.0