Commit 1f1b5ad1 authored by MozLando's avatar MozLando
Browse files

Merge #8218



8218: Dismiss previous download dialogs when navigating away r=csadilek a=Amejia481



Co-authored-by: default avatarArturo Mejia <arturomejiamarmol@gmail.com>
parents 0c99550d fdccdcc1
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import mozilla.components.support.base.feature.OnNeedToRequestPermissions
import mozilla.components.support.base.feature.PermissionsFeature
import mozilla.components.support.ktx.android.content.appName
import mozilla.components.support.ktx.android.content.isPermissionGranted
import mozilla.components.support.ktx.kotlin.isSameOriginAs
import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged
import mozilla.components.support.utils.Browsers

@@ -85,17 +86,46 @@ class DownloadsFeature(

    private var scope: CoroutineScope? = null

    @VisibleForTesting
    internal var dismissPromptScope: CoroutineScope? = null
    @VisibleForTesting
    internal var previousTab: SessionState? = null

    /**
     * Starts observing downloads on the selected session and sends them to the [DownloadManager]
     * to be processed.
     */
    @Suppress("Deprecation")
    override fun start() {
        // Dismiss the previous prompts when the user navigates to another site.
        // This prevents prompts from the previous page from covering content.
        dismissPromptScope = store.flowScoped { flow ->
            flow.mapNotNull { state -> state.findTabOrCustomTabOrSelectedTab(tabId) }
                    .ifChanged { it.content.url }
                    .collect {
                        val currentHost = previousTab?.content?.url
                        val newHost = it.content.url

                        // The user is navigating to another site
                        if (currentHost?.isSameOriginAs(newHost) == false) {
                            previousTab?.let { tab ->
                                // We have an old download request.
                                tab.content.download?.let { download ->
                                    dismissAllDownloadDialogs()
                                    useCases.consumeDownload(tab.id, download.id)
                                    previousTab = null
                                }
                            }
                        }
                    }
        }

        scope = store.flowScoped { flow ->
            flow.mapNotNull { state -> state.findTabOrCustomTabOrSelectedTab(tabId) }
                .ifChanged { it.content.download }
                .collect { state ->
                    state.content.download?.let { downloadState ->
                        previousTab = state
                        processDownload(state, downloadState)
                    }
                }
@@ -115,6 +145,7 @@ class DownloadsFeature(
     */
    override fun stop() {
        scope?.cancel()
        dismissPromptScope?.cancel()
        downloadManager.unregisterListeners()
    }

@@ -309,6 +340,12 @@ class DownloadsFeature(
                .map { it.toDownloaderApp(context, download) } + listOfNotNull(thisApp)
    }

    @VisibleForTesting
    internal fun dismissAllDownloadDialogs() {
        findPreviousDownloadDialogFragment()?.dismiss()
        findPreviousAppDownloaderDialogFragment()?.dismiss()
    }

    private val ActivityInfo.identifier: String get() = packageName + name

    private fun DownloaderApp.toIntent(): Intent {
+71 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import mozilla.components.browser.state.action.ContentAction
import mozilla.components.browser.state.action.TabListAction
import mozilla.components.browser.state.selector.findTab
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.content.DownloadState
@@ -729,6 +730,76 @@ class DownloadsFeatureTest {
        val app = resolveInfo.toDownloaderApp(spyContext, download)
        assertEquals(expectedApp, app)
    }

    @Test
    fun `previous dialogs MUST be dismissed when navigating to another website`() {
        val downloadsUseCases = spy(DownloadsUseCases(store))
        val consumeDownloadUseCase = mock<ConsumeDownloadUseCase>()
        val download = DownloadState(url = "https://www.mozilla.org", sessionId = "test-tab")
        store.dispatch(ContentAction.UpdateDownloadAction("test-tab", download = download))
                .joinBlocking()

        doReturn(consumeDownloadUseCase).`when`(downloadsUseCases).consumeDownload

        val feature = spy(DownloadsFeature(
            testContext,
            store,
            useCases = downloadsUseCases,
            downloadManager = mock()
        ))

        doNothing().`when`(feature).dismissAllDownloadDialogs()
        doReturn(true).`when`(feature).processDownload(any(), any())

        feature.start()

        store.dispatch(ContentAction.UpdateDownloadAction("test-tab", download = download))
                .joinBlocking()

        grantPermissions()

        val tab = createTab("https://www.firefox.com")
        store.dispatch(TabListAction.AddTabAction(tab, select = true)).joinBlocking()

        verify(feature).dismissAllDownloadDialogs()
        verify(downloadsUseCases).consumeDownload
        assertNull(feature.previousTab)
    }

    @Test
    fun `previous dialogs must NOT be dismissed when navigating on the same website`() {
        val downloadsUseCases = spy(DownloadsUseCases(store))
        val consumeDownloadUseCase = mock<ConsumeDownloadUseCase>()
        val download = DownloadState(url = "https://www.mozilla.org", sessionId = "test-tab")
        store.dispatch(ContentAction.UpdateDownloadAction("test-tab", download = download))
                .joinBlocking()

        doReturn(consumeDownloadUseCase).`when`(downloadsUseCases).consumeDownload

        val feature = spy(DownloadsFeature(
            testContext,
            store,
            useCases = downloadsUseCases,
            downloadManager = mock()
        ))

        doNothing().`when`(feature).dismissAllDownloadDialogs()
        doReturn(true).`when`(feature).processDownload(any(), any())

        feature.start()

        store.dispatch(ContentAction.UpdateDownloadAction("test-tab", download = download))
                .joinBlocking()

        grantPermissions()

        val tab = createTab("https://www.mozilla.org/example")
        store.dispatch(TabListAction.AddTabAction(tab, select = true)).joinBlocking()

        verify(feature, never()).dismissAllDownloadDialogs()
        verify(downloadsUseCases, never()).consumeDownload
        assertNotNull(feature.previousTab)
    }
}

private fun grantPermissions() {