Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import android.content.res.Configuration
import android.media.MediaScannerConnection
import android.net.Uri
import android.os.*
import android.provider.Settings
import android.text.Editable
import android.view.*
import android.view.View.*
Expand Down Expand Up @@ -63,6 +64,7 @@ import com.duckduckgo.app.brokensite.BrokenSiteActivity
import com.duckduckgo.app.brokensite.BrokenSiteData
import com.duckduckgo.app.browser.BrowserTabViewModel.*
import com.duckduckgo.app.browser.autocomplete.BrowserAutoCompleteSuggestionsAdapter
import com.duckduckgo.app.browser.downloader.DownloadFailReason
import com.duckduckgo.app.browser.downloader.FileDownloadNotificationManager
import com.duckduckgo.app.browser.downloader.FileDownloader
import com.duckduckgo.app.browser.downloader.FileDownloader.FileDownloadListener
Expand Down Expand Up @@ -1112,9 +1114,30 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope, DaxDialogLi
}
}

override fun downloadFailed(message: String) {
override fun downloadFailed(message: String, downloadFailReason: DownloadFailReason) {
Timber.w("Failed to download file [$message]")

fileDownloadNotificationManager.showDownloadFailedNotification()

val snackbar = Snackbar.make(toolbar, R.string.downloadFailed, Snackbar.LENGTH_INDEFINITE)
if (downloadFailReason == DownloadFailReason.DownloadManagerDisabled) {
snackbar.setText(message)
snackbar.setAction(getString(R.string.enable)) {
showDownloadManagerAppSettings()
}
}
snackbar.show()
}

private fun showDownloadManagerAppSettings() {
try {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = DownloadFailReason.DOWNLOAD_MANAGER_SETTINGS_URI
startActivity(intent)
} catch (e: ActivityNotFoundException) {
Timber.w(e, "Could not open DownloadManager settings")
Snackbar.make(toolbar, R.string.downloadManagerIncompatible, Snackbar.LENGTH_INDEFINITE).show()
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class DataUriDownloader @Inject constructor(
when (val parsedDataUri = dataUriParser.generate(pending.url)) {
is ParseResult.Invalid -> {
Timber.w("Failed to extract data from data URI")
callback?.downloadFailed("Failed to extract data from data URI")
callback?.downloadFailed("Failed to extract data from data URI", DownloadFailReason.DataUriParseException)
return
}
is ParseResult.ParsedDataUri -> {
Expand All @@ -50,7 +50,7 @@ class DataUriDownloader @Inject constructor(
}
} catch (e: IOException) {
Timber.e(e, "Failed to save data uri")
callback?.downloadFailed("Failed to download data uri")
callback?.downloadFailed("Failed to download data uri", DownloadFailReason.DataUriParseException)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ class FileDownloadNotificationManager @Inject constructor(

fun showDownloadFailedNotification() {
applicationContext.runOnUiThread {
applicationContext.longToast(getString(R.string.downloadFailed))

val notification = NotificationCompat.Builder(applicationContext, ChannelType.FILE_DOWNLOADED.id)
.setContentTitle(applicationContext.getString(R.string.downloadFailed))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.duckduckgo.app.browser.downloader

import android.net.Uri
import android.os.Environment
import android.webkit.URLUtil
import androidx.annotation.WorkerThread
Expand All @@ -32,9 +33,9 @@ class FileDownloader @Inject constructor(
@WorkerThread
fun download(pending: PendingFileDownload, callback: FileDownloadListener) {
when {
pending.isNetworkUrl -> networkFileDownloader.download(pending)
pending.isNetworkUrl -> networkFileDownloader.download(pending, callback)
pending.isDataUrl -> dataUriDownloader.download(pending, callback)
else -> callback.downloadFailed("Not supported")
else -> callback.downloadFailed("Not supported", DownloadFailReason.UnsupportedUrlType)
}
}

Expand All @@ -50,7 +51,7 @@ class FileDownloader @Inject constructor(
interface FileDownloadListener {
fun downloadStarted()
fun downloadFinished(file: File, mimeType: String?)
fun downloadFailed(message: String)
fun downloadFailed(message: String, downloadFailReason: DownloadFailReason)
}
}

Expand All @@ -63,3 +64,15 @@ fun FileDownloader.PendingFileDownload.guessFileName(): String {
val FileDownloader.PendingFileDownload.isDataUrl get() = URLUtil.isDataUrl(url)

val FileDownloader.PendingFileDownload.isNetworkUrl get() = URLUtil.isNetworkUrl(url)

sealed class DownloadFailReason {

object DownloadManagerDisabled : DownloadFailReason()
object UnsupportedUrlType : DownloadFailReason()
object Other : DownloadFailReason()
object DataUriParseException : DownloadFailReason()

companion object {
val DOWNLOAD_MANAGER_SETTINGS_URI: Uri = Uri.parse("package:com.android.providers.downloads")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,22 @@ package com.duckduckgo.app.browser.downloader

import android.app.DownloadManager
import android.content.Context
import android.content.pm.PackageManager.*
import android.webkit.CookieManager
import androidx.core.net.toUri
import com.duckduckgo.app.browser.R
import com.duckduckgo.app.browser.downloader.FileDownloader.PendingFileDownload
import javax.inject.Inject

class NetworkFileDownloader @Inject constructor(private val context: Context) {

fun download(pendingDownload: PendingFileDownload) {
fun download(pendingDownload: PendingFileDownload, callback: FileDownloader.FileDownloadListener) {

if (!downloadManagerAvailable()) {
callback.downloadFailed(context.getString(R.string.downloadManagerDisabled), DownloadFailReason.DownloadManagerDisabled)
return
}

val guessedFileName = pendingDownload.guessFileName()

val request = DownloadManager.Request(pendingDownload.url.toUri()).apply {
Expand All @@ -39,4 +47,17 @@ class NetworkFileDownloader @Inject constructor(private val context: Context) {
val manager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager?
manager?.enqueue(request)
}

private fun downloadManagerAvailable(): Boolean {
return when (context.packageManager.getApplicationEnabledSetting(DOWNLOAD_MANAGER_PACKAGE)) {
COMPONENT_ENABLED_STATE_DISABLED -> false
COMPONENT_ENABLED_STATE_DISABLED_USER -> false
COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED -> false
else -> true
}
}

companion object {
private const val DOWNLOAD_MANAGER_PACKAGE = "com.android.providers.downloads"
}
}
6 changes: 6 additions & 0 deletions app/src/main/res/values/string-untranslated.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,10 @@
<string name="fireproofWebsiteEmptyListHint">No websites fireproofed yet</string>
<string name="fireproofWebsiteFeatureDescription">Websites rely on cookies to keep you signed in. When you Fireproof a site, cookies won\'t be erased and you\'ll stay signed in, even after using the Fire Button.</string>
<string name="fireproofWebsiteOverflowContentDescription">More options for fireproof website %s</string>

<!-- Download Manager problems -->
<string name="downloadManagerDisabled">Download Manager is disabled</string>
<string name="downloadManagerIncompatible">Download Manager not available on this device</string>
<string name="enable">Enable</string>

</resources>