Created
April 3, 2022 06:41
-
-
Save androidovshchik/13630a6fc43cce61726dd7c950dac6c7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.girlapp | |
import android.app.DownloadManager | |
import android.content.BroadcastReceiver | |
import android.content.Context | |
import android.content.Intent | |
import android.content.IntentFilter | |
import android.database.ContentObserver | |
import android.net.Uri | |
import android.os.Build | |
import android.os.Environment | |
import android.os.Handler | |
import android.os.Looper | |
import android.util.ArrayMap | |
import android.webkit.MimeTypeMap | |
import org.jetbrains.anko.downloadManager | |
import java.util.* | |
import java.util.concurrent.Executors | |
class File( | |
var fileKey: String, | |
var fileName: String, | |
var fileExtension: String, | |
var url: String | |
) { | |
override fun toString(): String { | |
return "File(fileKey='$fileKey', fileName='$fileName')" | |
} | |
} | |
@Suppress("MemberVisibilityCanBePrivate") | |
class DownloadFileManager(context: Context) : ContentObserver(null) { | |
private val executor = Executors.newSingleThreadExecutor() | |
private val handler = Handler(Looper.getMainLooper()) | |
private val downloadManager = context.downloadManager | |
private val contentResolver = context.contentResolver | |
private val receiver = object : BroadcastReceiver() { | |
override fun onReceive(context: Context, intent: Intent) { | |
queryDownloads() | |
} | |
} | |
private val listeners = mutableSetOf<Listener>() | |
private val downloadFiles = Collections.synchronizedMap(ArrayMap<Long, File>()) | |
val isDownloading: Boolean | |
get() = downloadFiles.isNotEmpty() | |
init { | |
// [android.provider.Downloads.Impl.CONTENT_URI] | |
val uri = Uri.parse("content://downloads/my_downloads") | |
contentResolver.registerContentObserver(uri, true, this) | |
context.registerReceiver(receiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) | |
} | |
fun addListener(listener: Listener) { | |
listeners.add(listener) | |
} | |
@Suppress("DEPRECATION") | |
fun startDownload(file: File) { | |
val mimeType = MimeTypeMap.getSingleton() | |
.getMimeTypeFromExtension(file.fileExtension) | |
val request = DownloadManager.Request(Uri.parse(file.url)).apply { | |
setMimeType(mimeType) | |
setTitle(file.fileName) | |
setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, file.fileName) | |
setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) | |
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { | |
setVisibleInDownloadsUi(true) | |
allowScanningByMediaScanner() | |
} | |
} | |
val id = downloadManager.enqueue(request) | |
downloadFiles[id] = file | |
} | |
override fun onChange(selfChange: Boolean) { | |
queryDownloads() | |
} | |
private fun queryDownloads() { | |
executor.execute { | |
val ids = HashSet(downloadFiles.keys) | |
val query = DownloadManager.Query().apply { | |
setFilterById(*ids.toLongArray()) | |
} | |
downloadManager.query(query).use { cursor -> | |
while (cursor.moveToNext()) { | |
val id = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID)) | |
ids.remove(id) | |
val file = downloadFiles[id] ?: continue | |
when (cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS))) { | |
DownloadManager.STATUS_SUCCESSFUL -> { | |
downloadFiles.remove(id) | |
handler.post { | |
listeners.forEach { | |
it.onComplete(file) | |
} | |
} | |
} | |
DownloadManager.STATUS_FAILED -> { | |
downloadFiles.remove(id) | |
handler.post { | |
listeners.forEach { | |
it.onFailure(file) | |
} | |
} | |
} | |
else -> { | |
val bytes = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)) | |
handler.post { | |
listeners.forEach { | |
it.onProgress(file, bytes) | |
} | |
} | |
} | |
} | |
} | |
ids.forEach { id -> | |
val file = downloadFiles[id] | |
downloadFiles.remove(id) | |
if (file != null) { | |
handler.post { | |
listeners.forEach { | |
it.onFailure(file) | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
fun removeListener(listener: Listener) { | |
listeners.remove(listener) | |
} | |
fun release(context: Context) { | |
context.unregisterReceiver(receiver) | |
contentResolver.unregisterContentObserver(this) | |
executor.shutdown() | |
listeners.clear() | |
} | |
interface Listener { | |
fun onProgress(file: File, downloadBytes: Int) | |
fun onComplete(file: File) | |
fun onFailure(file: File) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment