TP-69167 | Background resource caching [ResourceManager] (#11423)
This commit is contained in:
@@ -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>
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -2427,7 +2427,7 @@ class HomePageActivity :
|
||||
initResourceManager &&
|
||||
FirebaseRemoteConfigHelper.getBoolean(RESOURCE_MANAGER_ENABLED)
|
||||
) {
|
||||
ResourceManager.init(context = this@HomePageActivity)
|
||||
ResourceManager.init(context = applicationContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ package com.navi.common.resourcemanager.listener
|
||||
|
||||
interface ResourceDownloadListener {
|
||||
|
||||
fun onResourceDownloadSuccess(
|
||||
suspend fun onResourceDownloadSuccess(
|
||||
url: String,
|
||||
status: Boolean,
|
||||
resourceUri: String? = null,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user