Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add maximum parallel download configuration to DownloadConfig.kt #41

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
50 changes: 15 additions & 35 deletions app/src/main/java/com/khush/sample/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package com.khush.sample

import android.app.NotificationManager
import android.content.Intent
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.util.Log
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.snackbar.Snackbar
import com.khush.sample.databinding.ActivityMainBinding
Expand All @@ -18,9 +16,20 @@ class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var snackbar: Snackbar

private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) {
Toast.makeText(this, "$it", Toast.LENGTH_SHORT).show()
}

companion object {
private const val TAG = "susTest"
}

@SuppressLint("NewApi")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.i("Testing", "RequestId " + intent.extras?.getInt("key_request_id"))
if (checkSelfPermission(WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissionLauncher.launch(WRITE_EXTERNAL_STORAGE)
}

binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
Expand All @@ -32,35 +41,6 @@ class MainActivity : AppCompatActivity() {
return
}

var permissions = arrayOf<String>()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && !getSystemService(NotificationManager::class.java).areNotificationsEnabled()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
permissions = permissions.plus(android.Manifest.permission.POST_NOTIFICATIONS)
}
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) {
snackbar =
Snackbar.make(binding.root, "Allow storage permission", Snackbar.LENGTH_INDEFINITE)
.setAction("Settings") {
val getpermission = Intent()
getpermission.action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
startActivity(getpermission)
snackbar.dismiss()
}
snackbar.show()
} else if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
permissions = permissions.plus(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
}

if (permissions.isNotEmpty()) {
requestPermissions(permissions, 101)
Toast.makeText(this, "Notification and Storage Permission Required", Toast.LENGTH_SHORT)
.show()
return
}

openTestFragment()
}
Expand Down
111 changes: 56 additions & 55 deletions app/src/main/java/com/khush/sample/MainFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.khush.sample
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.os.Environment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
Expand All @@ -22,6 +21,7 @@ import androidx.recyclerview.widget.SimpleItemAnimator
import com.ketch.DownloadModel
import com.ketch.Ketch
import com.ketch.Status
import com.ketch.DownloadRequest
import com.khush.sample.databinding.FragmentMainBinding
import com.khush.sample.databinding.ItemFileBinding
import kotlinx.coroutines.Dispatchers
Expand All @@ -45,6 +45,8 @@ class MainFragment : Fragment() {
}
}

private val downloadDirectory by lazy { requireContext().cacheDir.path }

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
Expand All @@ -66,9 +68,7 @@ class MainFragment : Fragment() {
if (file.exists()) {
val uri = [email protected]?.applicationContext?.let {
FileProvider.getUriForFile(
it,
it.packageName + ".provider",
file
it, it.packageName + ".provider", file
)
}
if (uri != null) {
Expand All @@ -84,9 +84,7 @@ class MainFragment : Fragment() {
}
} else {
Toast.makeText(
[email protected],
"Something went wrong",
Toast.LENGTH_SHORT
[email protected], "Something went wrong", Toast.LENGTH_SHORT
).show()
}
}
Expand Down Expand Up @@ -130,16 +128,15 @@ class MainFragment : Fragment() {
LinearLayoutManager(this.context, LinearLayoutManager.VERTICAL, false)
fragmentMainBinding.recyclerView.addItemDecoration(
DividerItemDecoration(
this.context,
DividerItemDecoration.VERTICAL
this.context, DividerItemDecoration.VERTICAL
)
)

fragmentMainBinding.bt1.text = "Video 1"
fragmentMainBinding.bt1.setOnClickListener {
ketch.download(
url = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path,
path = downloadDirectory,
fileName = "Sample_Video_1.mp4",
tag = "Video",
metaData = "158"
Expand All @@ -150,7 +147,7 @@ class MainFragment : Fragment() {
fragmentMainBinding.bt2.setOnClickListener {
ketch.download(
url = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4",
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path,
path = downloadDirectory,
fileName = "Sample_Video_2.mp4",
tag = "Video",
metaData = "169"
Expand All @@ -161,7 +158,7 @@ class MainFragment : Fragment() {
fragmentMainBinding.bt3.setOnClickListener {
ketch.download(
url = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/SubaruOutbackOnStreetAndDirt.mp4",
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path,
path = downloadDirectory,
fileName = "Sample_Video_3.mp4",
tag = "Video",
metaData = "48"
Expand All @@ -172,7 +169,7 @@ class MainFragment : Fragment() {
fragmentMainBinding.bt4.setOnClickListener {
ketch.download(
url = "https://picsum.photos/200/300",
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path,
path = downloadDirectory,
fileName = "Sample_Image_1.jpg",
tag = "Document",
metaData = "1"
Expand All @@ -183,7 +180,7 @@ class MainFragment : Fragment() {
fragmentMainBinding.bt5.setOnClickListener {
ketch.download(
url = "https://sample-videos.com/pdf/Sample-pdf-5mb.pdf",
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path,
path = downloadDirectory,
fileName = "Sample_Pdf_1.pdf",
tag = "Document",
metaData = "5"
Expand All @@ -192,47 +189,51 @@ class MainFragment : Fragment() {

fragmentMainBinding.bt6.text = "Multiple"
fragmentMainBinding.bt6.setOnClickListener {
ketch.download(
url = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path,
fileName = "Sample_Video_1.mp4",
tag = "Video",
metaData = "158"
)
ketch.download(
url = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4",
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path,
fileName = "Sample_Video_2.mp4",
tag = "Video",
metaData = "169"
)
ketch.download(
url = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/SubaruOutbackOnStreetAndDirt.mp4",
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path,
fileName = "Sample_Video_3.mp4",
tag = "Video",
metaData = "48"
)
ketch.download(
url = "https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_30mb.mp4",
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path,
fileName = "Sample_Video_4.mp4",
tag = "Video",
metaData = "30"
)
ketch.download(
url = "https://picsum.photos/200/300",
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path,
fileName = "Sample_Image_1.jpg",
tag = "Document",
metaData = "1"
)
ketch.download(
url = "https://sample-videos.com/pdf/Sample-pdf-5mb.pdf",
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path,
fileName = "Sample_Pdf_1.pdf",
tag = "Document",
metaData = "5"
ketch.downloadMultiple(
listOf(
DownloadRequest(
url = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
path = downloadDirectory,
fileName = "Sample_Video_1.mp4",
tag = "Video",
metaData = "158",
),
DownloadRequest(
url = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4",
path = downloadDirectory,
fileName = "Sample_Video_2.mp4",
tag = "Video",
metaData = "169",
),
DownloadRequest(
url = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/SubaruOutbackOnStreetAndDirt.mp4",
path = downloadDirectory,
fileName = "Sample_Video_3.mp4",
tag = "Video",
metaData = "48",
),
DownloadRequest(
url = "https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_30mb.mp4",
path = downloadDirectory,
fileName = "Sample_Video_4.mp4",
tag = "Video",
metaData = "30",
),
DownloadRequest(
url = "https://picsum.photos/200/300",
path = downloadDirectory,
fileName = "Sample_Image_1.jpg",
tag = "Document",
metaData = "1",
),
DownloadRequest(
url = "https://sample-videos.com/pdf/Sample-pdf-5mb.pdf",
path = downloadDirectory,
fileName = "Sample_Pdf_1.pdf",
tag = "Document",
metaData = "5"
),
)
)
}
}
Expand Down
9 changes: 7 additions & 2 deletions ketch/src/main/java/com/ketch/DownloadConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,10 @@ import kotlinx.serialization.Serializable
@Serializable
data class DownloadConfig(
val connectTimeOutInMs: Long = DownloadConst.DEFAULT_VALUE_CONNECT_TIMEOUT_MS,
val readTimeOutInMs: Long = DownloadConst.DEFAULT_VALUE_READ_TIMEOUT_MS
)
val readTimeOutInMs: Long = DownloadConst.DEFAULT_VALUE_READ_TIMEOUT_MS,
val maxParallelDownloads: Int = DownloadConst.DEFAULT_VALUE_MAX_PARALLEL_DOWNLOAD, // -1 for infinite parallel download
) {
init {
if (maxParallelDownloads < -1) throw IllegalArgumentException("Max parallel download can't be negative")
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.ketch.internal.download
package com.ketch

import com.ketch.internal.utils.FileUtil.getUniqueId
import kotlinx.serialization.Serializable

@Serializable
internal data class DownloadRequest(
data class DownloadRequest(
val url: String,
val path: String,
val fileName: String,
Expand Down
14 changes: 12 additions & 2 deletions ketch/src/main/java/com/ketch/Ketch.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import androidx.work.WorkManager
import com.ketch.internal.database.DatabaseInstance
import com.ketch.internal.download.ApiResponseHeaderChecker
import com.ketch.internal.download.DownloadManager
import com.ketch.internal.download.DownloadRequest
import com.ketch.internal.network.RetrofitInstance
import com.ketch.internal.utils.DownloadConst
import com.ketch.internal.utils.DownloadLogger
Expand Down Expand Up @@ -81,7 +80,7 @@ import java.util.concurrent.TimeUnit
* @property logger [Logger] implementation to print logs
* @constructor Create empty Ketch
*/
@Suppress("TooManyFunctions")
@Suppress("TooManyFunctions", "unused")
class Ketch private constructor(
private val context: Context,
private var downloadConfig: DownloadConfig,
Expand Down Expand Up @@ -205,6 +204,17 @@ class Ketch private constructor(
return downloadRequest.id
}

fun downloadMultiple(downloadRequests: List<DownloadRequest>) {
downloadRequests.forEach {
it.apply {
require(url.isNotEmpty() && path.isNotEmpty() && fileName.isNotEmpty()) {
"Missing ${if (url.isEmpty()) "url" else if (path.isEmpty()) "path" else "fileName"}"
}
}
}
downloadManager.downloadAsync(downloadRequests)
}

/**
* Cancel download with given [id]
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ internal interface DownloadDao {
@Query("SELECT * FROM downloads ORDER BY timeQueued ASC")
fun getAllEntityFlow(): Flow<List<DownloadEntity>>

@Query("SELECT COUNT(*) FROM downloads WHERE status = 'PROGRESS' or status = 'STARTED'")
fun getInProgressOrStartedEntityCount() : Int

@Query("SELECT * FROM downloads WHERE lastModified <= :timeMillis ORDER BY timeQueued ASC")
fun getEntityTillTimeFlow(timeMillis: Long): Flow<List<DownloadEntity>>

Expand All @@ -39,6 +42,9 @@ internal interface DownloadDao {
@Query("SELECT * FROM downloads ORDER BY timeQueued ASC")
suspend fun getAllEntity(): List<DownloadEntity>

@Query("SELECT * FROM downloads WHERE status = 'QUEUED' ORDER BY timeQueued ASC")
suspend fun getAllQueuedEntity(): List<DownloadEntity>

@Query("SELECT * FROM downloads WHERE lastModified <= :timeMillis ORDER BY timeQueued ASC")
suspend fun getEntityTillTime(timeMillis: Long): List<DownloadEntity>

Expand Down
Loading