TP-69167 | Background resource caching [ResourceManager] (#11423)

This commit is contained in:
shreyansu raj
2024-06-18 16:24:57 +05:30
committed by GitHub
parent 9f4822751e
commit fa545aba10
15 changed files with 225 additions and 145 deletions

View File

@@ -479,7 +479,7 @@ com.th3rdwave.safeareacontext, com.horcrux.svg, org.reactnative.maskedview, com.
<data android:host="collect" />
<data android:host="mandate" />
</intent-filter>
</activity>
</activity>
<service
android:name=".services.KillAppInBackgroundService"
@@ -501,4 +501,4 @@ com.th3rdwave.safeareacontext, com.horcrux.svg, org.reactnative.maskedview, com.
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3741839945842082~4098575184"/>
</application>
</manifest>
</manifest>

View File

@@ -42,6 +42,7 @@ import com.navi.base.utils.AppLaunchUtils
import com.navi.base.utils.NetWatchManger
import com.navi.chat.base.ChatBaseActivity
import com.navi.common.CommonLibManager
import com.navi.common.resourcemanager.manager.ResourceManager
import com.navi.common.ui.activity.BaseActivity
import com.navi.common.uitron.util.UiTronDependencyProvider
import com.navi.common.utils.CommonUtils.isQaRelease
@@ -283,6 +284,7 @@ open class NaviApplication :
DeeplinkManager.deInitFirebase(this)
if (isDifferentPackage.not()) {
AlfredManager.stopRecording()
ResourceManager.initResourceDownloadWorker(applicationContext)
}
NaviTrackEvent.trackEventOnClickStream(eventName = NAVIAPP_BACKGROUND_PUSH)
}

View File

@@ -2427,7 +2427,7 @@ class HomePageActivity :
initResourceManager &&
FirebaseRemoteConfigHelper.getBoolean(RESOURCE_MANAGER_ENABLED)
) {
ResourceManager.init(context = this@HomePageActivity)
ResourceManager.init(context = applicationContext)
}
}
}

View File

@@ -23,16 +23,22 @@ import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.navi.base.utils.orFalse
import com.navi.common.resourcemanager.manager.ResourceManager.resourceDownloadListener
import com.navi.common.resourcemanager.listener.ResourceDownloadListener
import com.navi.common.resourcemanager.model.IconData
import com.navi.common.utils.Constants.COIL
import com.navi.common.utils.Constants.GLIDE
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class CacheResource @Inject constructor(val context: Context) {
class CacheResource
@Inject
constructor(
@ApplicationContext val context: Context,
val downloadListener: ResourceDownloadListener
) {
suspend fun cacheImageResource(data: IconData?) {
if (data?.cacheStrategy?.contains(COIL).orFalse()) {
@@ -54,21 +60,18 @@ class CacheResource @Inject constructor(val context: Context) {
.listener(
object : ImageRequest.Listener {
override fun onCancel(request: ImageRequest) {
resourceDownloadListener.onResourceDownloadFailed()
downloadListener.onResourceDownloadFailed()
}
override fun onError(request: ImageRequest, result: ErrorResult) {
resourceDownloadListener.onResourceDownloadFailed()
downloadListener.onResourceDownloadFailed()
}
override fun onStart(request: ImageRequest) {}
override fun onSuccess(request: ImageRequest, result: SuccessResult) {
CoroutineScope(Dispatchers.IO).launch {
resourceDownloadListener.onResourceDownloadSuccess(
url.orEmpty(),
true
)
downloadListener.onResourceDownloadSuccess(url.orEmpty(), true)
}
}
}
@@ -93,7 +96,7 @@ class CacheResource @Inject constructor(val context: Context) {
target: Target<Bitmap>?,
isFirstResource: Boolean
): Boolean {
resourceDownloadListener.onResourceDownloadFailed()
downloadListener.onResourceDownloadFailed()
return false
}
@@ -105,7 +108,7 @@ class CacheResource @Inject constructor(val context: Context) {
isFirstResource: Boolean
): Boolean {
CoroutineScope(Dispatchers.IO).launch {
resourceDownloadListener.onResourceDownloadSuccess(url.orEmpty(), true)
downloadListener.onResourceDownloadSuccess(url.orEmpty(), true)
}
return true
}
@@ -119,10 +122,10 @@ class CacheResource @Inject constructor(val context: Context) {
LottieCompositionFactory.fromUrl(context, it)
.addListener {
CoroutineScope(Dispatchers.IO).launch {
resourceDownloadListener.onResourceDownloadSuccess(lottieUrl, true)
downloadListener.onResourceDownloadSuccess(lottieUrl, true)
}
}
.addFailureListener { error -> resourceDownloadListener.onResourceDownloadFailed() }
.addFailureListener { downloadListener.onResourceDownloadFailed() }
}
}
}

View File

@@ -0,0 +1,30 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.common.resourcemanager
import android.content.Context
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.navi.analytics.utils.NaviTrackEvent
import com.navi.common.utils.Constants.INIT_RESOURCE_DOWNLOAD_WORKER
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
class ResourceDownloadWorker
@Inject
constructor(@ApplicationContext val context: Context, workerParameters: WorkerParameters) :
CoroutineWorker(context, workerParameters) {
private val resourceManagerUseCase = ResourceManagerUseCase(context)
override suspend fun doWork(): Result {
NaviTrackEvent.trackEvent(INIT_RESOURCE_DOWNLOAD_WORKER)
resourceManagerUseCase.execute(context, 1)
return Result.success()
}
}

View File

@@ -7,32 +7,92 @@
package com.navi.common.resourcemanager
import com.navi.common.resourcemanager.manager.ResourceManager
import com.navi.common.resourcemanager.manager.ResourceManager.cacheResource
import android.content.Context
import com.navi.alfred.utils.orZero
import com.navi.analytics.utils.NaviTrackEvent
import com.navi.common.resourcemanager.db.ResourceManagerDatabase
import com.navi.common.resourcemanager.db.dao.ResourceDao
import com.navi.common.resourcemanager.db.model.ResourceEntity
import com.navi.common.resourcemanager.di.ResourceManagerEntryPoint
import com.navi.common.resourcemanager.listener.ResourceDownloadListener
import com.navi.common.resourcemanager.manager.ResourceManager.exceptionHandler
import com.navi.common.resourcemanager.manager.ResourceManager.repository
import com.navi.common.resourcemanager.model.IconData
import com.navi.common.resourcemanager.repository.ResourceManagerRepository
import com.navi.common.resourcemanager.resourceDownloader.ResourceDownloadManagerImpl
import com.navi.common.resourcemanager.util.enum.ConnectionQuality
import com.navi.common.resourcemanager.util.enum.ResourceType
import com.navi.common.utils.Constants.AUDIO_EXTENSTION
import com.navi.common.utils.Constants.BUCKET_SIZE
import com.navi.common.utils.Constants.JSON_EXTENSTION
import com.navi.common.utils.Constants.PNG_EXTENSTION
import com.navi.common.utils.Constants.RESOURCE_DOWNLOAD_BUCKET
import com.navi.common.utils.EMPTY
import com.navi.common.utils.getDownloadNetworkStrength
import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import okio.Closeable
class ResourceManagerUseCase {
class ResourceManagerUseCase @Inject constructor(@ApplicationContext context: Context) :
Closeable, ResourceDownloadListener {
private val job = CoroutineScope(Dispatchers.IO + SupervisorJob() + exceptionHandler)
private lateinit var resourceDB: ResourceManagerDatabase
private lateinit var resourceDao: ResourceDao
private lateinit var resourceDownloadManager: ResourceDownloadManagerImpl
private lateinit var cacheResource: CacheResource
private lateinit var repository: ResourceManagerRepository
suspend fun execute() {
job.launch { fetchDownloadBucket() }
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob() + exceptionHandler)
private val downloadCounter = MutableStateFlow<Int?>(null)
init {
initData(context)
}
private suspend fun fetchDownloadBucket() {
val resourceList = repository.fetchResourceBucket()
private fun initData(context: Context) {
val entryPoint =
EntryPointAccessors.fromApplication(context, ResourceManagerEntryPoint::class.java)
repository = entryPoint.resourceManagerRepository()
resourceDB = entryPoint.resourceManagerDB()
resourceDao = entryPoint.resourceDao()
resourceDownloadManager = ResourceDownloadManagerImpl(context, this)
cacheResource = CacheResource(context, this)
}
suspend fun execute(context: Context, priority: Int?) {
setDownloadCounter(0)
scope.launch { initialiseResourceDownloadUseCase(context, priority) }.join()
}
private suspend fun initialiseResourceDownloadUseCase(context: Context, priority: Int?) {
downloadCounter.collect { downloadCounter ->
if (downloadCounter == 0) {
if (getNetworkQuality(context) == ConnectionQuality.GOOD) {
val bucket = repository.fetchResourceBucket(priority = priority)
NaviTrackEvent.trackEventOnClickStream(
RESOURCE_DOWNLOAD_BUCKET,
eventValues = mapOf(BUCKET_SIZE to bucket.size.toString())
)
if (bucket.isEmpty()) {
close()
return@collect
}
setDownloadCounter(bucket.size)
downloadBucket(bucket)
} else {
close()
}
}
}
}
private suspend fun downloadBucket(resourceList: List<ResourceEntity>) {
resourceList.forEach {
when (getFileType(it.resourceUrl)) {
ResourceType.ICON -> {
@@ -56,12 +116,7 @@ class ResourceManagerUseCase {
}
private fun downloadResourceToLocalStorage(resourceUrl: String) {
job.launch {
ResourceManager.resourceDownloadManager.downloadResource(
resourceUrl,
getFileExtension(resourceUrl)
)
}
resourceDownloadManager.downloadResource(resourceUrl, getFileExtension(resourceUrl))
}
private fun getFileExtension(resourceUrl: String): String {
@@ -81,7 +136,40 @@ class ResourceManagerUseCase {
}
}
fun cancelJob() {
job.cancel()
private fun setDownloadCounter(bucketSize: Int?) {
downloadCounter.value = bucketSize
}
private fun updateDownloadCounter() {
if (downloadCounter.value.orZero() > 0) {
downloadCounter.value = downloadCounter.value?.minus(1)
}
}
private fun getNetworkQuality(context: Context): ConnectionQuality {
val speed = getDownloadNetworkStrength(context)
return when (speed) {
in 0f..500f -> ConnectionQuality.POOR
in 501f..1000f -> ConnectionQuality.MODERATE
else -> ConnectionQuality.GOOD
}
}
override suspend fun onResourceDownloadSuccess(
url: String,
status: Boolean,
resourceUri: String?,
resourcePath: String?
) {
repository.updateDownloadStatus(url, status, resourceUri, resourcePath)
updateDownloadCounter()
}
override fun onResourceDownloadFailed() {
updateDownloadCounter()
}
override fun close() {
scope.cancel()
}
}

View File

@@ -46,7 +46,7 @@ interface ResourceDao {
)
@Query(
"SELECT * from $RESOURCE_MANAGER_TABLE where priority = 0 and downloaded = 0 LIMIT :bucketSize"
"SELECT * from $RESOURCE_MANAGER_TABLE where priority = :priority and downloaded = 0 LIMIT :bucketSize"
)
fun fetchResourceBucket(bucketSize: Int?): List<ResourceEntity>
fun fetchResourceBucket(bucketSize: Int?, priority: Int?): List<ResourceEntity>
}

View File

@@ -7,11 +7,10 @@
package com.navi.common.resourcemanager.di
import com.navi.common.resourcemanager.CacheResource
import com.navi.common.resourcemanager.ResourceManagerUseCase
import com.navi.common.resourcemanager.db.ResourceManagerDatabase
import com.navi.common.resourcemanager.db.dao.ResourceDao
import com.navi.common.resourcemanager.repository.ResourceManagerRepository
import com.navi.common.resourcemanager.resourceDownloader.ResourceDownloadManagerImpl
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@@ -25,7 +24,5 @@ interface ResourceManagerEntryPoint {
fun resourceManagerRepository(): ResourceManagerRepository
fun resourceDownloadManagerImpl(): ResourceDownloadManagerImpl
fun cacheResource(): CacheResource
fun resourceManagerUseCase(): ResourceManagerUseCase
}

View File

@@ -8,11 +8,10 @@
package com.navi.common.resourcemanager.di
import android.content.Context
import com.navi.common.resourcemanager.CacheResource
import com.navi.common.resourcemanager.ResourceManagerUseCase
import com.navi.common.resourcemanager.db.ResourceManagerDatabase
import com.navi.common.resourcemanager.db.dao.ResourceDao
import com.navi.common.resourcemanager.repository.ResourceManagerRepository
import com.navi.common.resourcemanager.resourceDownloader.ResourceDownloadManagerImpl
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@@ -42,15 +41,6 @@ object ResourceManagerModule {
@Singleton
@Provides
fun providesResourceDownloadManagerImpl(
@ApplicationContext context: Context
): ResourceDownloadManagerImpl {
return ResourceDownloadManagerImpl(context)
}
@Singleton
@Provides
fun provideCacheResource(@ApplicationContext context: Context): CacheResource {
return CacheResource(context)
}
fun provideResourceManagerUseCase(@ApplicationContext context: Context) =
ResourceManagerUseCase(context)
}

View File

@@ -9,7 +9,7 @@ package com.navi.common.resourcemanager.listener
interface ResourceDownloadListener {
fun onResourceDownloadSuccess(
suspend fun onResourceDownloadSuccess(
url: String,
status: Boolean,
resourceUri: String? = null,

View File

@@ -7,21 +7,23 @@
package com.navi.common.resourcemanager.manager
import android.annotation.SuppressLint
import android.content.Context
import com.navi.alfred.utils.orZero
import com.navi.common.resourcemanager.CacheResource
import androidx.work.Constraints
import androidx.work.Data
import androidx.work.ExistingWorkPolicy
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import com.navi.analytics.utils.NaviTrackEvent
import com.navi.common.resourcemanager.ResourceDownloadWorker
import com.navi.common.resourcemanager.ResourceManagerUseCase
import com.navi.common.resourcemanager.db.ResourceManagerDatabase
import com.navi.common.resourcemanager.db.dao.ResourceDao
import com.navi.common.resourcemanager.db.model.ResourceEntity
import com.navi.common.resourcemanager.di.ResourceManagerEntryPoint
import com.navi.common.resourcemanager.listener.ResourceDownloadListener
import com.navi.common.resourcemanager.model.ResourceModuleData
import com.navi.common.resourcemanager.repository.ResourceManagerRepository
import com.navi.common.resourcemanager.resourceDownloader.ResourceDownloadManagerImpl
import com.navi.common.resourcemanager.util.enum.ConnectionQuality
import com.navi.common.utils.getDownloadNetworkStrength
import com.navi.common.utils.Constants.INIT_RESOURCE_DOWNLOAD_WORKER
import com.navi.common.utils.Constants.INIT_RESOURCE_MANAGER
import com.navi.common.utils.Constants.RESOURCE_DOWNLOAD_WORKER
import com.navi.common.utils.log
import dagger.hilt.android.EntryPointAccessors
import java.io.Closeable
@@ -40,30 +42,20 @@ import kotlinx.coroutines.withContext
@Singleton
object ResourceManager : Closeable {
private lateinit var resourceDB: ResourceManagerDatabase
private lateinit var resourceDao: ResourceDao
internal lateinit var repository: ResourceManagerRepository
internal lateinit var resourceDownloadManager: ResourceDownloadManagerImpl
internal lateinit var cacheResource: CacheResource
private lateinit var resourceManagerUseCase: ResourceManagerUseCase
val exceptionHandler = CoroutineExceptionHandler { _, exception -> exception.log() }
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob() + exceptionHandler)
private var downloadScope: CoroutineScope? = null
private val criticalJourneyState = MutableStateFlow<Boolean>(false)
private val downloadCounter = MutableStateFlow<Int?>(null)
suspend fun init(context: Context) =
withContext(Dispatchers.IO) {
NaviTrackEvent.trackEventOnClickStream(INIT_RESOURCE_MANAGER)
val entryPoint =
EntryPointAccessors.fromApplication(context, ResourceManagerEntryPoint::class.java)
resourceDB = entryPoint.resourceManagerDB()
resourceDao = entryPoint.resourceDao()
repository = entryPoint.resourceManagerRepository()
resourceDownloadManager = entryPoint.resourceDownloadManagerImpl()
cacheResource = entryPoint.cacheResource()
resourceManagerUseCase = ResourceManagerUseCase()
resourceManagerUseCase = entryPoint.resourceManagerUseCase()
fetchResource(context)
}
@@ -75,7 +67,6 @@ object ResourceManager : Closeable {
}
}
@SuppressLint("RestrictedApi")
private suspend fun observeCriticalJourneyState(context: Context) {
criticalJourneyState.collect { isCriticalFlow ->
initResourceDownload(context, isCriticalFlow)
@@ -84,32 +75,9 @@ object ResourceManager : Closeable {
private suspend fun initResourceDownload(context: Context, isCriticalFlow: Boolean) {
if (!isCriticalFlow) {
downloadScope = CoroutineScope(Dispatchers.IO + SupervisorJob() + exceptionHandler)
initialiseResourceDownloadUseCase(context)
setDownloadCounter(0)
resourceManagerUseCase.execute(context = context, priority = 0)
} else {
downloadScope?.cancel()
setDownloadCounter(null)
}
}
private suspend fun initialiseResourceDownloadUseCase(context: Context) {
downloadScope?.launch {
downloadCounter.collect {
if (it == 0) {
if (getNetworkQuality(context) == ConnectionQuality.GOOD) {
val bucketSize = repository.fetchResourceBucket().size
if (bucketSize == 0) {
close()
return@collect
}
setDownloadCounter(bucketSize)
resourceManagerUseCase.execute()
} else {
resourceManagerUseCase.cancelJob()
}
}
}
resourceManagerUseCase.close()
}
}
@@ -167,50 +135,40 @@ object ResourceManager : Closeable {
}
}
private fun getNetworkQuality(context: Context): ConnectionQuality {
val speed = getDownloadNetworkStrength(context)
return when (speed) {
in 0f..500f -> ConnectionQuality.POOR
in 501f..1000f -> ConnectionQuality.MODERATE
else -> ConnectionQuality.GOOD
}
}
fun updateCriticalFlowStatus(status: Boolean) {
criticalJourneyState.value = status
}
private fun setDownloadCounter(bucketSize: Int?) {
downloadCounter.value = bucketSize
}
fun updateDownloadCounter() {
if (downloadCounter.value.orZero() > 0) {
downloadCounter.value = downloadCounter.value?.minus(1)
}
}
val resourceDownloadListener =
object : ResourceDownloadListener {
override fun onResourceDownloadSuccess(
url: String,
status: Boolean,
resourceUri: String?,
resourcePath: String?
) {
scope.launch {
repository.updateDownloadStatus(url, status, resourceUri, resourcePath)
updateDownloadCounter()
fun initResourceDownloadWorker(context: Context) {
if (::repository.isInitialized) {
scope.launch {
val resourceSize = repository.fetchResourceBucket(priority = 1).size
if (resourceSize == 0) {
return@launch
}
}
override fun onResourceDownloadFailed() {
updateDownloadCounter()
NaviTrackEvent.trackEventOnClickStream(INIT_RESOURCE_DOWNLOAD_WORKER)
val constraint =
Constraints.Builder()
.setRequiresCharging(false)
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val workRequest =
OneTimeWorkRequestBuilder<ResourceDownloadWorker>()
.setInputData(Data.Builder().build())
.setConstraints(constraint)
.build()
WorkManager.getInstance(context)
.enqueueUniqueWork(
RESOURCE_DOWNLOAD_WORKER,
ExistingWorkPolicy.REPLACE,
workRequest
)
}
}
}
override fun close() {
scope.cancel()
downloadScope?.cancel()
resourceManagerUseCase.close()
}
}

View File

@@ -51,8 +51,9 @@ class ResourceManagerRepository @Inject constructor(private val resourceDao: Res
}
fun fetchResourceBucket(
bucketSize: Int? = RESOURCE_DOWNLOAD_BUCKET_SIZE
bucketSize: Int? = RESOURCE_DOWNLOAD_BUCKET_SIZE,
priority: Int? = 0
): List<ResourceEntity> {
return resourceDao.fetchResourceBucket(bucketSize)
return resourceDao.fetchResourceBucket(bucketSize, priority)
}
}

View File

@@ -13,7 +13,7 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.work.impl.utils.ForceStopRunnable.BroadcastReceiver
import com.navi.common.resourcemanager.manager.ResourceManager
import com.navi.common.resourcemanager.listener.ResourceDownloadListener
import com.navi.common.utils.log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -22,7 +22,8 @@ import kotlinx.coroutines.launch
@SuppressLint("RestrictedApi")
internal class ResourceDownloadBroadcastReceiver(
private val downloadManager: DownloadManager,
private val downloadInProgressIds: HashMap<Long, String>
private val downloadInProgressIds: HashMap<Long, String>,
private val downloadListener: ResourceDownloadListener
) : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
@@ -51,7 +52,7 @@ internal class ResourceDownloadBroadcastReceiver(
}
}
DownloadManager.STATUS_FAILED -> {
ResourceManager.resourceDownloadListener.onResourceDownloadFailed()
downloadListener.onResourceDownloadFailed()
}
}
}
@@ -60,7 +61,7 @@ internal class ResourceDownloadBroadcastReceiver(
val fileUri = getFileUri(downloadId)
val filePath = getFilePath(downloadId)
fileUri?.let { uri ->
ResourceManager.resourceDownloadListener.onResourceDownloadSuccess(
downloadListener.onResourceDownloadSuccess(
resourceUrl,
true,
uri.toString(),

View File

@@ -11,19 +11,23 @@ import android.app.DownloadManager
import android.content.Context
import android.content.IntentFilter
import android.net.Uri
import com.navi.common.resourcemanager.listener.ResourceDownloadListener
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
class ResourceDownloadManagerImpl
@Inject
constructor(@ApplicationContext private val context: Context) {
constructor(
@ApplicationContext private val context: Context,
downloadListener: ResourceDownloadListener
) {
private var downloadIds: HashMap<Long, String> = HashMap()
private val downloadManager =
context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
init {
initReceiver()
initReceiver(downloadListener)
}
fun downloadResource(resourceUrl: String, fileNameWithExtension: String) {
@@ -40,11 +44,12 @@ constructor(@ApplicationContext private val context: Context) {
downloadIds.put(downloadId, resourceUrl)
}
private fun initReceiver() {
private fun initReceiver(downloadListener: ResourceDownloadListener) {
val downloadStatusReceiver =
ResourceDownloadBroadcastReceiver(
downloadManager = downloadManager,
downloadInProgressIds = downloadIds
downloadInProgressIds = downloadIds,
downloadListener = downloadListener
)
val downloadCompleteIntentFilter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
context.registerReceiver(downloadStatusReceiver, downloadCompleteIntentFilter)

View File

@@ -314,4 +314,9 @@ object Constants {
const val JSON_EXTENSTION = ".json"
const val AUDIO_EXTENSTION = ".mp3"
const val RESOURCE_DOWNLOAD_BUCKET_SIZE = 10
const val RESOURCE_DOWNLOAD_WORKER = "RESOURCE_DOWNLOAD_WORKER"
const val INIT_RESOURCE_MANAGER = "init_resource_manager"
const val INIT_RESOURCE_DOWNLOAD_WORKER = "init_resource_download_worker"
const val RESOURCE_DOWNLOAD_BUCKET = "resource_download_bucket"
const val BUCKET_SIZE = "bucket_size"
}