@@ -32,9 +32,10 @@ class RichDocumentDownloader(private val activity: AppCompatActivity) {
3232 fun download (uri : Uri , filename : String? , userAgent : String? ) {
3333 activity.lifecycleScope.launch(Dispatchers .IO ) {
3434 runCatching {
35+ // if filename not provided get filename from header
3536 if (filename == null ) {
3637 val url = uri.toString()
37- downloadWithOkHttp(url, filename, userAgent)
38+ downloadWithOkHttp(url, userAgent)
3839 } else {
3940 downloadWithDownloadManager(uri, filename)
4041 }
@@ -45,24 +46,18 @@ class RichDocumentDownloader(private val activity: AppCompatActivity) {
4546 }
4647
4748 private suspend fun downloadWithDownloadManager (url : Uri , filename : String ) = withContext(Dispatchers .Main ) {
48- val downloadManager = activity.getSystemService(Context .DOWNLOAD_SERVICE ) as DownloadManager ?
49-
50- if (downloadManager == null ) {
51- showMessage(false )
52- return @withContext
53- }
54-
55- val request = DownloadManager .Request (url)
56- request.allowScanningByMediaScanner()
57- request.setNotificationVisibility(DownloadManager .Request .VISIBILITY_VISIBLE_NOTIFY_COMPLETED )
58-
59- // change the name file and your current activity.
60- request.setDestinationInExternalPublicDir(Environment .DIRECTORY_DOWNLOADS , filename)
61-
62- downloadManager.enqueue(request)
49+ val downloadManager = activity.getSystemService(Context .DOWNLOAD_SERVICE ) as ? DownloadManager
50+ ? : return @withContext showMessage(false )
51+
52+ DownloadManager .Request (url).apply {
53+ @Suppress(" DEPRECATION" )
54+ allowScanningByMediaScanner()
55+ setNotificationVisibility(DownloadManager .Request .VISIBILITY_VISIBLE_NOTIFY_COMPLETED )
56+ setDestinationInExternalPublicDir(Environment .DIRECTORY_DOWNLOADS , filename)
57+ }.let (downloadManager::enqueue)
6358 }
6459
65- private fun downloadWithOkHttp (url : String , filename : String? , userAgent : String? ) {
60+ private fun downloadWithOkHttp (url : String , userAgent : String? ) {
6661 val requestBuilder = Request .Builder ().url(url).get()
6762
6863 CookieManager .getInstance().getCookie(url)?.let { requestBuilder.header(COOKIE_HEADER , it) }
@@ -76,18 +71,20 @@ class RichDocumentDownloader(private val activity: AppCompatActivity) {
7671 return
7772 }
7873
79- val resolvedName = resolveFileName(filename, response.header(CONTENT_DISPOSITION_HEADER ))
74+ val disposition = response.header(CONTENT_DISPOSITION_HEADER )
75+ val resolvedName = resolveFileName(disposition)
8076 val result = saveToDownloads(body, resolvedName)
8177 showMessage(result)
8278 }
8379 }
8480
8581 private fun showMessage (success : Boolean ) {
8682 activity.runOnUiThread {
87- val message = if (success)
83+ val message = if (success) {
8884 R .string.downloader_download_succeeded_ticker
89- else
85+ } else {
9086 R .string.failed_to_download
87+ }
9188
9289 DisplayUtils .showSnackMessage(activity, message)
9390 }
@@ -106,23 +103,22 @@ class RichDocumentDownloader(private val activity: AppCompatActivity) {
106103 }
107104 }
108105
109- private fun resolveFileName (provided : String? , disposition : String? ): String = provided?.takeIf { it.isNotBlank() }
110- ? : extractFilenameFromDisposition(disposition)
111- ? : randomFilename()
106+ private fun resolveFileName (disposition : String? ): String =
107+ extractFilenameFromDisposition(disposition) ? : randomFilename()
112108
113109 private fun extractFilenameFromDisposition (disposition : String? ): String? {
114110 if (disposition.isNullOrBlank()) return null
115111 return extractExtendedFilename(disposition) ? : extractPlainFilename(disposition)
116112 }
117113
118114 private fun extractExtendedFilename (disposition : String ): String? {
119- val regex = """ filename\*\s*=\s*[^']*''([^;]+) """ .toRegex(RegexOption .IGNORE_CASE )
115+ val regex = EXTENDED_FILENAME_REGEX .toRegex(RegexOption .IGNORE_CASE )
120116 val value = regex.find(disposition)?.groupValues?.get(1 )?.trim() ? : return null
121- return runCatching { URLDecoder .decode(value, " UTF-8 " ) }.getOrNull()
117+ return runCatching { URLDecoder .decode(value, EXTENDED_FILENAME_ENCODER ) }.getOrNull()
122118 }
123119
124120 private fun extractPlainFilename (disposition : String ): String? {
125- val regex = """ filename\s*=\s*"?([^";]+)"? """ .toRegex(RegexOption .IGNORE_CASE )
121+ val regex = PLAIN_FILENAME_REGEX .toRegex(RegexOption .IGNORE_CASE )
126122 return regex.find(disposition)?.groupValues?.get(1 )?.trim()
127123 }
128124
@@ -136,5 +132,8 @@ class RichDocumentDownloader(private val activity: AppCompatActivity) {
136132 private const val DEFAULT_MIME_TYPE = " application/octet-stream"
137133 private const val TEMP_PREFIX = " richdocument_download"
138134 private const val RANDOM_NAME_LENGTH = 8
135+ private const val EXTENDED_FILENAME_REGEX = """ filename\*\s*=\s*[^']*''([^;]+)"""
136+ private const val PLAIN_FILENAME_REGEX = """ filename\s*=\s*"?([^";]+)"?"""
137+ private const val EXTENDED_FILENAME_ENCODER = " UTF-8"
139138 }
140139}
0 commit comments