Skip to main content

Code

Helper code related to downloading files.

DownloadModel.kt
package com.hanmajid.androidnotebook

import android.app.DownloadManager
import android.database.Cursor
import android.os.Parcelable
import androidx.core.database.getIntOrNull
import androidx.core.database.getLongOrNull
import androidx.core.database.getStringOrNull
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
import java.text.SimpleDateFormat
import java.util.Calendar

/**
* Custom download data model retrieved from [DownloadManager.Query].
*
* Add this to your app/build.gradle.kts file to use `@Parcelize`:
* ```
* plugins {
* id("kotlin-parcelize")
* }
* ```
*/
@Parcelize
data class DownloadModel(
val id: Long?,
val bytesDownloadedSoFar: Long?,
val description: String?,
val localUri: String?,
val mediaProviderUri: String?,
val mediaType: String?,
val reason: Int?,
val status: Int?,
val title: String?,
val totalSizeBytes: Long?,
val uri: String?,
val lastModifiedTimestamp: Long?,
) : Parcelable {
@IgnoredOnParcel
val reasonStr = when (reason) {
DownloadManager.ERROR_CANNOT_RESUME -> "Cannot resume download"
DownloadManager.ERROR_DEVICE_NOT_FOUND -> "No external storage device was found"
DownloadManager.ERROR_FILE_ALREADY_EXISTS -> "File already exists"
DownloadManager.ERROR_FILE_ERROR -> "A storage issue arises which doesn't fit under any other error code"
DownloadManager.ERROR_HTTP_DATA_ERROR -> "An error receiving or processing data occurred at the HTTP level"
DownloadManager.ERROR_INSUFFICIENT_SPACE -> "Insufficient storage space"
DownloadManager.ERROR_TOO_MANY_REDIRECTS -> "Too many redirects"
DownloadManager.ERROR_UNHANDLED_HTTP_CODE -> "An HTTP code was received that download manager can't handle"
DownloadManager.ERROR_UNKNOWN -> "The download has completed with an error that doesn't fit under any other error code"
DownloadManager.PAUSED_QUEUED_FOR_WIFI -> "The download exceeds a size limit for downloads over the mobile network and the download manager is waiting for a Wi-Fi connection to proceed"
DownloadManager.PAUSED_UNKNOWN -> "The download is paused for some other reason"
DownloadManager.PAUSED_WAITING_FOR_NETWORK -> "The download is paused for some other reason"
DownloadManager.PAUSED_WAITING_TO_RETRY -> "The download is paused because some network error occurred and the download manager is waiting before retrying the request"
else -> {
"HTTP code: $reason"
}
}

@IgnoredOnParcel
val statusStr = when (status) {
DownloadManager.STATUS_FAILED -> "Failed"
DownloadManager.STATUS_PAUSED -> "Paused"
DownloadManager.STATUS_PENDING -> "Pending"
DownloadManager.STATUS_RUNNING -> "Running"
DownloadManager.STATUS_SUCCESSFUL -> "Successful"
else -> "Unknown"
}

val lastModifiedTimestampStr: String
get() {
if (lastModifiedTimestamp == null) return ""
val cal = Calendar.getInstance().apply {
timeInMillis = lastModifiedTimestamp
}
val formatter = SimpleDateFormat("MMMM d, yyyy h:mm")
return formatter.format(cal.time)
}

@IgnoredOnParcel
val isRunning = status == DownloadManager.STATUS_RUNNING

@IgnoredOnParcel
val isSuccessful = status == DownloadManager.STATUS_SUCCESSFUL

val progress: Float
get() {
return if (isRunning) {
val downloaded = bytesDownloadedSoFar ?: -1
val total = totalSizeBytes ?: -1
if (downloaded > 0 && total > 0) {
downloaded.toFloat() / total
} else {
0f
}
} else {
0f
}
}

companion object {
/**
* Create [DownloadModel] from [cursor].
*/
fun fromCursor(cursor: Cursor): DownloadModel {
return DownloadModel(
bytesDownloadedSoFar = cursor.getLongOrNull(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)),
description = cursor.getStringOrNull(cursor.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION)),
id = cursor.getLongOrNull(cursor.getColumnIndex(DownloadManager.COLUMN_ID)),
lastModifiedTimestamp = cursor.getLongOrNull(cursor.getColumnIndex(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP)),
localUri = cursor.getStringOrNull(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)),
mediaProviderUri = cursor.getStringOrNull(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIAPROVIDER_URI)),
mediaType = cursor.getStringOrNull(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE)),
reason = cursor.getIntOrNull(cursor.getColumnIndex(DownloadManager.COLUMN_REASON)),
status = cursor.getIntOrNull(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)),
title = cursor.getStringOrNull(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE)),
totalSizeBytes = cursor.getLongOrNull(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)),
uri = cursor.getStringOrNull(cursor.getColumnIndex(DownloadManager.COLUMN_URI)),
)
}
}
}