Loading app/src/main/java/foundation/e/apps/data/DownloadManager.kt +61 −4 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package foundation.e.apps.data import android.app.DownloadManager import android.content.Context import android.database.Cursor import android.net.Uri import android.os.Environment import dagger.hilt.android.qualifiers.ApplicationContext Loading @@ -35,6 +36,7 @@ import java.io.File import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton import kotlin.math.abs import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds Loading Loading @@ -124,12 +126,17 @@ class DownloadManager @Inject constructor( downloadManager.query(downloadManagerQuery.setFilterById(downloadId)) .use { cursor -> if (cursor.moveToFirst()) { val status = var status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)) val totalSizeBytes = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)) getLong(cursor, DownloadManager.COLUMN_TOTAL_SIZE_BYTES) val bytesDownloadedSoFar = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)) getLong(cursor, DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR) val reason = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_REASON)) status = sanitizeStatus(downloadId, status, reason) if (status == DownloadManager.STATUS_FAILED) { Timber.d("Download Failed: $filePath=> $bytesDownloadedSoFar/$totalSizeBytes $status") downloadsMaps[downloadId] = false Loading Loading @@ -166,6 +173,34 @@ class DownloadManager @Inject constructor( return getDownloadStatus(downloadId) == DownloadManager.STATUS_FAILED } fun getSizeRequired(downloadId: Long): Long { var totalSizeBytes = -1L var bytesDownloadedSoFar = -1L try { downloadManager.query(downloadManagerQuery.setFilterById(downloadId)) .use { cursor -> if (cursor.moveToFirst()) { totalSizeBytes = getLong(cursor, DownloadManager.COLUMN_TOTAL_SIZE_BYTES) bytesDownloadedSoFar = getLong(cursor, DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR) } } } catch (e: RuntimeException) { Timber.e(e, "runtime exception on retrieving download file size.") } if (totalSizeBytes <= 0) { return 0 } if (bytesDownloadedSoFar <= 0) { return totalSizeBytes } return abs(totalSizeBytes - bytesDownloadedSoFar) } private fun getDownloadStatus(downloadId: Long): Int { var status = -1 var reason = -1 Loading @@ -187,9 +222,28 @@ class DownloadManager @Inject constructor( if (status != DownloadManager.STATUS_SUCCESSFUL) { Timber.e("Download Issue: $downloadId status: $status reason: $reason") } return sanitizeStatus(downloadId, status, reason) } private fun sanitizeStatus(downloadId: Long, status: Int, reason: Int): Int { if (reason <= 0) { return status } if (status in listOf(DownloadManager.STATUS_FAILED, DownloadManager.STATUS_PAUSED)) { return status } Timber.e("Download Issue: $downloadId : DownloadManager returns status: $status but the failed because: reason: $reason") if (reason <= DownloadManager.PAUSED_UNKNOWN) { return DownloadManager.STATUS_PAUSED } return DownloadManager.STATUS_FAILED } fun getDownloadFailureReason(downloadId: Long): Int { var reason = -1 try { Loading @@ -205,4 +259,7 @@ class DownloadManager @Inject constructor( } return reason } private fun getLong(cursor: Cursor, column: String) = cursor.getLong(cursor.getColumnIndexOrThrow(column)) } app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt +0 −3 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import com.aurora.gplayapi.data.models.SearchBundle import com.aurora.gplayapi.data.models.StreamCluster import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.data.Constants.timeoutDurationInMillis import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.cleanapk.CleanApkDownloadInfoFetcher import foundation.e.apps.data.cleanapk.CleanApkRetrofit Loading Loading @@ -68,10 +67,8 @@ import foundation.e.apps.install.pkg.PWAManagerModule import foundation.e.apps.install.pkg.PkgManagerModule import foundation.e.apps.ui.home.model.HomeChildFusedAppDiffUtil import kotlinx.coroutines.Deferred import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.withTimeout import retrofit2.Response import timber.log.Timber import javax.inject.Inject Loading app/src/main/java/foundation/e/apps/data/fusedDownload/models/FusedDownload.kt +1 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ data class FusedDownload( val versionCode: Int = 1, val offerType: Int = -1, val isFree: Boolean = true, val appSize: Long = 0, var appSize: Long = 0, var files: List<File> = mutableListOf(), var signature: String = String() ) { Loading app/src/main/java/foundation/e/apps/data/updates/UpdatesManagerImpl.kt +3 −3 Original line number Diff line number Diff line Loading @@ -36,12 +36,12 @@ import foundation.e.apps.data.fused.data.FusedApp import foundation.e.apps.data.preference.PreferenceManagerModule import foundation.e.apps.install.pkg.PkgManagerModule import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import timber.log.Timber import javax.inject.Inject import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.withContext import timber.log.Timber import javax.inject.Inject class UpdatesManagerImpl @Inject constructor( @ApplicationContext private val context: Context, Loading app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt +20 −14 Original line number Diff line number Diff line Loading @@ -20,11 +20,15 @@ package foundation.e.apps.install.download import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.data.DownloadManager import foundation.e.apps.data.enums.Origin import foundation.e.apps.data.enums.Status import foundation.e.apps.data.fusedDownload.FusedManagerRepository import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.install.notification.StorageNotificationManager import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay Loading @@ -39,7 +43,8 @@ import javax.inject.Singleton class DownloadManagerUtils @Inject constructor( @ApplicationContext private val context: Context, private val fusedManagerRepository: FusedManagerRepository, private val downloadManager: DownloadManager private val downloadManager: DownloadManager, private val storageNotificationManager: StorageNotificationManager, ) { private val mutex = Mutex() Loading @@ -64,10 +69,9 @@ class DownloadManagerUtils @Inject constructor( Timber.d("===> updateDownloadStatus: ${fusedDownload.name}: $downloadId: $numberOfDownloadedItems/${fusedDownload.downloadIdMap.size}") if (downloadManager.hasDownloadFailed(downloadId)) { handleDownloadFailed(fusedDownload) handleDownloadFailed(fusedDownload, downloadId) Timber.e( "Download failed for ${fusedDownload.packageName}, " + "reason: ${downloadManager.getDownloadFailureReason(downloadId)}" "Download failed for ${fusedDownload.packageName}, " + "reason: " + "${downloadManager.getDownloadFailureReason(downloadId)}" ) return@launch } Loading @@ -87,27 +91,30 @@ class DownloadManagerUtils @Inject constructor( fusedManagerRepository.updateFusedDownload(fusedDownload) } private suspend fun handleDownloadFailed(fusedDownload: FusedDownload) { private suspend fun handleDownloadFailed(fusedDownload: FusedDownload, downloadId: Long) { fusedManagerRepository.installationIssue(fusedDownload) fusedManagerRepository.cancelDownload(fusedDownload) Timber.w("===> Download failed: ${fusedDownload.name} ${fusedDownload.status}") if (downloadManager.getDownloadFailureReason(downloadId) == android.app.DownloadManager.ERROR_INSUFFICIENT_SPACE) { storageNotificationManager.showNotEnoughSpaceNotification(fusedDownload, downloadId) EventBus.invokeEvent(AppEvent.ErrorMessageEvent(R.string.not_enough_storage)) } } private suspend fun validateDownload( numberOfDownloadedItems: Int, fusedDownload: FusedDownload, downloadId: Long ) = downloadManager.isDownloadSuccessful(downloadId) && areAllFilesDownloaded( numberOfDownloadedItems, fusedDownload ) = downloadManager.isDownloadSuccessful(downloadId) && areAllFilesDownloaded( numberOfDownloadedItems, fusedDownload ) && checkCleanApkSignatureOK(fusedDownload) private fun areAllFilesDownloaded( numberOfDownloadedItems: Int, fusedDownload: FusedDownload ) = numberOfDownloadedItems == fusedDownload.downloadIdMap.size && numberOfDownloadedItems == fusedDownload.downloadURLList.size ) = numberOfDownloadedItems == fusedDownload.downloadIdMap.size && numberOfDownloadedItems == fusedDownload.downloadURLList.size private suspend fun updateDownloadIdMap( fusedDownload: FusedDownload, Loading @@ -119,8 +126,7 @@ class DownloadManagerUtils @Inject constructor( private suspend fun checkCleanApkSignatureOK(fusedDownload: FusedDownload): Boolean { if (fusedDownload.origin != Origin.CLEANAPK || fusedManagerRepository.isFdroidApplicationSigned( context, fusedDownload context, fusedDownload ) ) { Timber.d("Apk signature is OK") Loading Loading
app/src/main/java/foundation/e/apps/data/DownloadManager.kt +61 −4 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package foundation.e.apps.data import android.app.DownloadManager import android.content.Context import android.database.Cursor import android.net.Uri import android.os.Environment import dagger.hilt.android.qualifiers.ApplicationContext Loading @@ -35,6 +36,7 @@ import java.io.File import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton import kotlin.math.abs import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds Loading Loading @@ -124,12 +126,17 @@ class DownloadManager @Inject constructor( downloadManager.query(downloadManagerQuery.setFilterById(downloadId)) .use { cursor -> if (cursor.moveToFirst()) { val status = var status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)) val totalSizeBytes = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)) getLong(cursor, DownloadManager.COLUMN_TOTAL_SIZE_BYTES) val bytesDownloadedSoFar = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)) getLong(cursor, DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR) val reason = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_REASON)) status = sanitizeStatus(downloadId, status, reason) if (status == DownloadManager.STATUS_FAILED) { Timber.d("Download Failed: $filePath=> $bytesDownloadedSoFar/$totalSizeBytes $status") downloadsMaps[downloadId] = false Loading Loading @@ -166,6 +173,34 @@ class DownloadManager @Inject constructor( return getDownloadStatus(downloadId) == DownloadManager.STATUS_FAILED } fun getSizeRequired(downloadId: Long): Long { var totalSizeBytes = -1L var bytesDownloadedSoFar = -1L try { downloadManager.query(downloadManagerQuery.setFilterById(downloadId)) .use { cursor -> if (cursor.moveToFirst()) { totalSizeBytes = getLong(cursor, DownloadManager.COLUMN_TOTAL_SIZE_BYTES) bytesDownloadedSoFar = getLong(cursor, DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR) } } } catch (e: RuntimeException) { Timber.e(e, "runtime exception on retrieving download file size.") } if (totalSizeBytes <= 0) { return 0 } if (bytesDownloadedSoFar <= 0) { return totalSizeBytes } return abs(totalSizeBytes - bytesDownloadedSoFar) } private fun getDownloadStatus(downloadId: Long): Int { var status = -1 var reason = -1 Loading @@ -187,9 +222,28 @@ class DownloadManager @Inject constructor( if (status != DownloadManager.STATUS_SUCCESSFUL) { Timber.e("Download Issue: $downloadId status: $status reason: $reason") } return sanitizeStatus(downloadId, status, reason) } private fun sanitizeStatus(downloadId: Long, status: Int, reason: Int): Int { if (reason <= 0) { return status } if (status in listOf(DownloadManager.STATUS_FAILED, DownloadManager.STATUS_PAUSED)) { return status } Timber.e("Download Issue: $downloadId : DownloadManager returns status: $status but the failed because: reason: $reason") if (reason <= DownloadManager.PAUSED_UNKNOWN) { return DownloadManager.STATUS_PAUSED } return DownloadManager.STATUS_FAILED } fun getDownloadFailureReason(downloadId: Long): Int { var reason = -1 try { Loading @@ -205,4 +259,7 @@ class DownloadManager @Inject constructor( } return reason } private fun getLong(cursor: Cursor, column: String) = cursor.getLong(cursor.getColumnIndexOrThrow(column)) }
app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt +0 −3 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import com.aurora.gplayapi.data.models.SearchBundle import com.aurora.gplayapi.data.models.StreamCluster import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.data.Constants.timeoutDurationInMillis import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.cleanapk.CleanApkDownloadInfoFetcher import foundation.e.apps.data.cleanapk.CleanApkRetrofit Loading Loading @@ -68,10 +67,8 @@ import foundation.e.apps.install.pkg.PWAManagerModule import foundation.e.apps.install.pkg.PkgManagerModule import foundation.e.apps.ui.home.model.HomeChildFusedAppDiffUtil import kotlinx.coroutines.Deferred import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.withTimeout import retrofit2.Response import timber.log.Timber import javax.inject.Inject Loading
app/src/main/java/foundation/e/apps/data/fusedDownload/models/FusedDownload.kt +1 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ data class FusedDownload( val versionCode: Int = 1, val offerType: Int = -1, val isFree: Boolean = true, val appSize: Long = 0, var appSize: Long = 0, var files: List<File> = mutableListOf(), var signature: String = String() ) { Loading
app/src/main/java/foundation/e/apps/data/updates/UpdatesManagerImpl.kt +3 −3 Original line number Diff line number Diff line Loading @@ -36,12 +36,12 @@ import foundation.e.apps.data.fused.data.FusedApp import foundation.e.apps.data.preference.PreferenceManagerModule import foundation.e.apps.install.pkg.PkgManagerModule import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import timber.log.Timber import javax.inject.Inject import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.withContext import timber.log.Timber import javax.inject.Inject class UpdatesManagerImpl @Inject constructor( @ApplicationContext private val context: Context, Loading
app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt +20 −14 Original line number Diff line number Diff line Loading @@ -20,11 +20,15 @@ package foundation.e.apps.install.download import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.data.DownloadManager import foundation.e.apps.data.enums.Origin import foundation.e.apps.data.enums.Status import foundation.e.apps.data.fusedDownload.FusedManagerRepository import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.install.notification.StorageNotificationManager import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay Loading @@ -39,7 +43,8 @@ import javax.inject.Singleton class DownloadManagerUtils @Inject constructor( @ApplicationContext private val context: Context, private val fusedManagerRepository: FusedManagerRepository, private val downloadManager: DownloadManager private val downloadManager: DownloadManager, private val storageNotificationManager: StorageNotificationManager, ) { private val mutex = Mutex() Loading @@ -64,10 +69,9 @@ class DownloadManagerUtils @Inject constructor( Timber.d("===> updateDownloadStatus: ${fusedDownload.name}: $downloadId: $numberOfDownloadedItems/${fusedDownload.downloadIdMap.size}") if (downloadManager.hasDownloadFailed(downloadId)) { handleDownloadFailed(fusedDownload) handleDownloadFailed(fusedDownload, downloadId) Timber.e( "Download failed for ${fusedDownload.packageName}, " + "reason: ${downloadManager.getDownloadFailureReason(downloadId)}" "Download failed for ${fusedDownload.packageName}, " + "reason: " + "${downloadManager.getDownloadFailureReason(downloadId)}" ) return@launch } Loading @@ -87,27 +91,30 @@ class DownloadManagerUtils @Inject constructor( fusedManagerRepository.updateFusedDownload(fusedDownload) } private suspend fun handleDownloadFailed(fusedDownload: FusedDownload) { private suspend fun handleDownloadFailed(fusedDownload: FusedDownload, downloadId: Long) { fusedManagerRepository.installationIssue(fusedDownload) fusedManagerRepository.cancelDownload(fusedDownload) Timber.w("===> Download failed: ${fusedDownload.name} ${fusedDownload.status}") if (downloadManager.getDownloadFailureReason(downloadId) == android.app.DownloadManager.ERROR_INSUFFICIENT_SPACE) { storageNotificationManager.showNotEnoughSpaceNotification(fusedDownload, downloadId) EventBus.invokeEvent(AppEvent.ErrorMessageEvent(R.string.not_enough_storage)) } } private suspend fun validateDownload( numberOfDownloadedItems: Int, fusedDownload: FusedDownload, downloadId: Long ) = downloadManager.isDownloadSuccessful(downloadId) && areAllFilesDownloaded( numberOfDownloadedItems, fusedDownload ) = downloadManager.isDownloadSuccessful(downloadId) && areAllFilesDownloaded( numberOfDownloadedItems, fusedDownload ) && checkCleanApkSignatureOK(fusedDownload) private fun areAllFilesDownloaded( numberOfDownloadedItems: Int, fusedDownload: FusedDownload ) = numberOfDownloadedItems == fusedDownload.downloadIdMap.size && numberOfDownloadedItems == fusedDownload.downloadURLList.size ) = numberOfDownloadedItems == fusedDownload.downloadIdMap.size && numberOfDownloadedItems == fusedDownload.downloadURLList.size private suspend fun updateDownloadIdMap( fusedDownload: FusedDownload, Loading @@ -119,8 +126,7 @@ class DownloadManagerUtils @Inject constructor( private suspend fun checkCleanApkSignatureOK(fusedDownload: FusedDownload): Boolean { if (fusedDownload.origin != Origin.CLEANAPK || fusedManagerRepository.isFdroidApplicationSigned( context, fusedDownload context, fusedDownload ) ) { Timber.d("Apk signature is OK") Loading