Loading app/detekt-baseline.xml +0 −1 Original line number Diff line number Diff line Loading @@ -147,7 +147,6 @@ <ID>ReturnCount:SystemAppsUpdatesRepository.kt$SystemAppsUpdatesRepository$private suspend fun getApplication( packageName: String, releaseType: OsReleaseType, sdkLevel: Int, device: String, ): Application?</ID> <ID>ReturnCount:SystemAppsUpdatesRepository.kt$SystemAppsUpdatesRepository$private suspend fun getReleaseDetailsUrl( systemAppProject: SystemAppProject, releaseType: OsReleaseType, ): String?</ID> <ID>ReturnCount:UpdatesManagerImpl.kt$UpdatesManagerImpl$private suspend fun calculateSignatureVersion(latestCleanapkApp: Application): String</ID> <ID>SpreadOperator:DownloadProgressLD.kt$DownloadProgressLD$(*downloadingIds.toLongArray())</ID> <ID>SpreadOperator:EglExtensionProvider.kt$EglExtensionProvider$(*`as`)</ID> <ID>SpreadOperator:NativeDeviceInfoProviderModule.kt$NativeDeviceInfoProviderModule$(*context.assets.locales)</ID> <ID>SpreadOperator:NativeDeviceInfoProviderModule.kt$NativeDeviceInfoProviderModule$(*systemSharedLibraryNames)</ID> Loading app/src/main/java/foundation/e/apps/data/enums/Status.kt +10 −1 Original line number Diff line number Diff line Loading @@ -29,5 +29,14 @@ enum class Status { BLOCKED, INSTALLATION_ISSUE, AWAITING, PURCHASE_NEEDED PURCHASE_NEEDED; companion object { val downloadStatuses = setOf( QUEUED, AWAITING, DOWNLOADING, DOWNLOADED ) } } app/src/main/java/foundation/e/apps/data/install/AppManagerWrapper.kt +16 −2 Original line number Diff line number Diff line Loading @@ -143,8 +143,22 @@ class AppManagerWrapper @Inject constructor( application: Application, downloadProgress: DownloadProgress ): Boolean { val download = getFusedDownload(downloadProgress.downloadId) return download.id == application._id val download = getDownloadList().singleOrNull { it.id == application._id && it.packageName == application.package_name } ?: return false /* * We cannot rely on a single downloadId because DownloadProgress aggregates * multiple ids and downloadId is overwritten while iterating. * Validation instead checks whether any of the app's download ids are present * in the progress maps, which makes progress computation resilient to * concurrent multi-part downloads. */ val appDownloadIds = download.downloadIdMap.keys return appDownloadIds.any { id -> downloadProgress.totalSizeBytes.containsKey(id) || downloadProgress.bytesDownloadedSoFar.containsKey(id) } } fun handleRatingFormat(rating: Double): String? { Loading app/src/main/java/foundation/e/apps/install/download/data/DownloadProgressLD.kt +57 −40 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.app.DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR import android.app.DownloadManager.COLUMN_ID import android.app.DownloadManager.COLUMN_STATUS import android.app.DownloadManager.COLUMN_TOTAL_SIZE_BYTES import android.database.Cursor import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LiveData Loading Loading @@ -67,22 +68,42 @@ class DownloadProgressLD @Inject constructor( try { findDownloadProgress(downloadingIds) } catch (e: Exception) { Timber.e("downloading Ids: $downloadingIds ${e.localizedMessage}") Timber.w("downloading Ids: $downloadingIds $e") } delay(20) } } } @Suppress("SpreadOperator") // DownloadManager#Query requires vararg ids; unavoidable spread. private fun findDownloadProgress(downloadingIds: MutableList<Long>) { downloadManager.query(downloadManagerQuery.setFilterById(*downloadingIds.toLongArray())) .use { cursor -> cursor.moveToFirst() while (!cursor.isAfterLast) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(COLUMN_ID)) val status = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_STATUS)) val idsToQuery = downloadingIds.toLongArray() if (idsToQuery.isEmpty()) { return } downloadManager.query(downloadManagerQuery.setFilterById(*idsToQuery)) ?.use { safeCursor -> processCursor(safeCursor, downloadingIds) } ?: run { Timber.w("DownloadManager returned null cursor for ids $downloadingIds") postValue(downloadProgress) } } private fun processCursor( cursor: Cursor, downloadingIds: List<Long> ) { if (!cursor.moveToFirst()) { postValue(downloadProgress) return } do { val id = cursor.getLong(cursor.getColumnIndexOrThrow(COLUMN_ID)) val status = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_STATUS)) val totalSizeBytes = cursor.getLong(cursor.getColumnIndexOrThrow(COLUMN_TOTAL_SIZE_BYTES)) val bytesDownloadedSoFar = Loading @@ -105,16 +126,12 @@ class DownloadProgressLD @Inject constructor( downloadProgress.status[id] = status == DownloadManager.STATUS_SUCCESSFUL || status == DownloadManager.STATUS_FAILED if (downloadingIds.size == cursor.count) { postValue(downloadProgress) } if (downloadingIds.isEmpty()) { cancel() } cursor.moveToNext() } } } while (cursor.moveToNext()) postValue(downloadProgress) } override fun onInactive() { Loading app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListFragment.kt +15 −13 Original line number Diff line number Diff line Loading @@ -303,7 +303,10 @@ class ApplicationListFragment : val adapter = recyclerView.adapter as ApplicationListRVAdapter viewLifecycleOwner.lifecycleScope.launch { adapter.currentList.forEach { fusedApp -> if (fusedApp.status == Status.DOWNLOADING) { if (fusedApp.status !in Status.downloadStatuses) { return@forEach } val progress = appProgressViewModel.calculateProgress(fusedApp, downloadProgress) if (progress == -1) { Loading @@ -319,7 +322,6 @@ class ApplicationListFragment : } } } } override fun onPause() { binding.shimmerLayout.stopShimmer() Loading Loading
app/detekt-baseline.xml +0 −1 Original line number Diff line number Diff line Loading @@ -147,7 +147,6 @@ <ID>ReturnCount:SystemAppsUpdatesRepository.kt$SystemAppsUpdatesRepository$private suspend fun getApplication( packageName: String, releaseType: OsReleaseType, sdkLevel: Int, device: String, ): Application?</ID> <ID>ReturnCount:SystemAppsUpdatesRepository.kt$SystemAppsUpdatesRepository$private suspend fun getReleaseDetailsUrl( systemAppProject: SystemAppProject, releaseType: OsReleaseType, ): String?</ID> <ID>ReturnCount:UpdatesManagerImpl.kt$UpdatesManagerImpl$private suspend fun calculateSignatureVersion(latestCleanapkApp: Application): String</ID> <ID>SpreadOperator:DownloadProgressLD.kt$DownloadProgressLD$(*downloadingIds.toLongArray())</ID> <ID>SpreadOperator:EglExtensionProvider.kt$EglExtensionProvider$(*`as`)</ID> <ID>SpreadOperator:NativeDeviceInfoProviderModule.kt$NativeDeviceInfoProviderModule$(*context.assets.locales)</ID> <ID>SpreadOperator:NativeDeviceInfoProviderModule.kt$NativeDeviceInfoProviderModule$(*systemSharedLibraryNames)</ID> Loading
app/src/main/java/foundation/e/apps/data/enums/Status.kt +10 −1 Original line number Diff line number Diff line Loading @@ -29,5 +29,14 @@ enum class Status { BLOCKED, INSTALLATION_ISSUE, AWAITING, PURCHASE_NEEDED PURCHASE_NEEDED; companion object { val downloadStatuses = setOf( QUEUED, AWAITING, DOWNLOADING, DOWNLOADED ) } }
app/src/main/java/foundation/e/apps/data/install/AppManagerWrapper.kt +16 −2 Original line number Diff line number Diff line Loading @@ -143,8 +143,22 @@ class AppManagerWrapper @Inject constructor( application: Application, downloadProgress: DownloadProgress ): Boolean { val download = getFusedDownload(downloadProgress.downloadId) return download.id == application._id val download = getDownloadList().singleOrNull { it.id == application._id && it.packageName == application.package_name } ?: return false /* * We cannot rely on a single downloadId because DownloadProgress aggregates * multiple ids and downloadId is overwritten while iterating. * Validation instead checks whether any of the app's download ids are present * in the progress maps, which makes progress computation resilient to * concurrent multi-part downloads. */ val appDownloadIds = download.downloadIdMap.keys return appDownloadIds.any { id -> downloadProgress.totalSizeBytes.containsKey(id) || downloadProgress.bytesDownloadedSoFar.containsKey(id) } } fun handleRatingFormat(rating: Double): String? { Loading
app/src/main/java/foundation/e/apps/install/download/data/DownloadProgressLD.kt +57 −40 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.app.DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR import android.app.DownloadManager.COLUMN_ID import android.app.DownloadManager.COLUMN_STATUS import android.app.DownloadManager.COLUMN_TOTAL_SIZE_BYTES import android.database.Cursor import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LiveData Loading Loading @@ -67,22 +68,42 @@ class DownloadProgressLD @Inject constructor( try { findDownloadProgress(downloadingIds) } catch (e: Exception) { Timber.e("downloading Ids: $downloadingIds ${e.localizedMessage}") Timber.w("downloading Ids: $downloadingIds $e") } delay(20) } } } @Suppress("SpreadOperator") // DownloadManager#Query requires vararg ids; unavoidable spread. private fun findDownloadProgress(downloadingIds: MutableList<Long>) { downloadManager.query(downloadManagerQuery.setFilterById(*downloadingIds.toLongArray())) .use { cursor -> cursor.moveToFirst() while (!cursor.isAfterLast) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(COLUMN_ID)) val status = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_STATUS)) val idsToQuery = downloadingIds.toLongArray() if (idsToQuery.isEmpty()) { return } downloadManager.query(downloadManagerQuery.setFilterById(*idsToQuery)) ?.use { safeCursor -> processCursor(safeCursor, downloadingIds) } ?: run { Timber.w("DownloadManager returned null cursor for ids $downloadingIds") postValue(downloadProgress) } } private fun processCursor( cursor: Cursor, downloadingIds: List<Long> ) { if (!cursor.moveToFirst()) { postValue(downloadProgress) return } do { val id = cursor.getLong(cursor.getColumnIndexOrThrow(COLUMN_ID)) val status = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_STATUS)) val totalSizeBytes = cursor.getLong(cursor.getColumnIndexOrThrow(COLUMN_TOTAL_SIZE_BYTES)) val bytesDownloadedSoFar = Loading @@ -105,16 +126,12 @@ class DownloadProgressLD @Inject constructor( downloadProgress.status[id] = status == DownloadManager.STATUS_SUCCESSFUL || status == DownloadManager.STATUS_FAILED if (downloadingIds.size == cursor.count) { postValue(downloadProgress) } if (downloadingIds.isEmpty()) { cancel() } cursor.moveToNext() } } } while (cursor.moveToNext()) postValue(downloadProgress) } override fun onInactive() { Loading
app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListFragment.kt +15 −13 Original line number Diff line number Diff line Loading @@ -303,7 +303,10 @@ class ApplicationListFragment : val adapter = recyclerView.adapter as ApplicationListRVAdapter viewLifecycleOwner.lifecycleScope.launch { adapter.currentList.forEach { fusedApp -> if (fusedApp.status == Status.DOWNLOADING) { if (fusedApp.status !in Status.downloadStatuses) { return@forEach } val progress = appProgressViewModel.calculateProgress(fusedApp, downloadProgress) if (progress == -1) { Loading @@ -319,7 +322,6 @@ class ApplicationListFragment : } } } } override fun onPause() { binding.shimmerLayout.stopShimmer() Loading