From 24ff0957feba7f17d7c24b21e7926e0db3159a71 Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Wed, 27 Sep 2023 14:26:25 +0600 Subject: [PATCH 1/4] 7102-Show_notification_on_no_space_to_download issue: https://gitlab.e.foundation/e/backlog/-/issues/7102 when user's device has not enough space & auto-update triggered, we want to show a notification to let user to clear up some space to download happen. We also observered some abnormal behavior with os downloadManager, where with enough space available it returns status success with reason insufficient space (ref: https://gitlab.e.foundation/e/backlog/-/issues/7102#note_413144). For this, we want to sanitize the downloadManager status. --- .../foundation/e/apps/data/DownloadManager.kt | 55 +++++++++++- .../e/apps/data/fused/FusedApiImpl.kt | 3 - .../fusedDownload/models/FusedDownload.kt | 2 +- .../e/apps/data/updates/UpdatesManagerImpl.kt | 6 +- .../install/download/DownloadManagerUtils.kt | 30 ++++--- .../notification/NotificationManagerUtils.kt | 83 +++++++++++++++++- .../e/apps/install/updates/UpdatesNotifier.kt | 12 +-- .../e/apps/install/updates/UpdatesWorker.kt | 10 +-- .../workmanager/AppInstallProcessor.kt | 87 ++++++++----------- .../foundation/e/apps/utils/StorageUtils.kt | 53 +++++++++++ app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values/strings.xml | 3 + .../e/apps/UpdateManagerImptTest.kt | 1 - .../e/apps/gplay/GplyHttpClientTest.kt | 4 +- .../AppInstallProcessorTest.kt | 7 +- .../e/apps/login/LoginViewModelTest.kt | 2 +- .../java/foundation/e/apps/util/FakeCall.kt | 3 +- 20 files changed, 272 insertions(+), 93 deletions(-) create mode 100644 app/src/main/java/foundation/e/apps/utils/StorageUtils.kt diff --git a/app/src/main/java/foundation/e/apps/data/DownloadManager.kt b/app/src/main/java/foundation/e/apps/data/DownloadManager.kt index 3806bfb8e..e72bc81f0 100644 --- a/app/src/main/java/foundation/e/apps/data/DownloadManager.kt +++ b/app/src/main/java/foundation/e/apps/data/DownloadManager.kt @@ -35,6 +35,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 @@ -124,12 +125,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)) val bytesDownloadedSoFar = cursor.getLong(cursor.getColumnIndexOrThrow(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 @@ -166,6 +172,32 @@ 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 = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)) + bytesDownloadedSoFar = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)) + } + } + } catch (e: Exception) { + Timber.e(e) + } + + 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 @@ -187,7 +219,26 @@ class DownloadManager @Inject constructor( if (status != DownloadManager.STATUS_SUCCESSFUL) { Timber.e("Download Issue: $downloadId status: $status reason: $reason") } - return status + + 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 { diff --git a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt index 07cb797f0..5aa83c320 100644 --- a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt @@ -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 @@ -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 diff --git a/app/src/main/java/foundation/e/apps/data/fusedDownload/models/FusedDownload.kt b/app/src/main/java/foundation/e/apps/data/fusedDownload/models/FusedDownload.kt index 0d9333021..905d4182b 100644 --- a/app/src/main/java/foundation/e/apps/data/fusedDownload/models/FusedDownload.kt +++ b/app/src/main/java/foundation/e/apps/data/fusedDownload/models/FusedDownload.kt @@ -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 = mutableListOf(), var signature: String = String() ) { diff --git a/app/src/main/java/foundation/e/apps/data/updates/UpdatesManagerImpl.kt b/app/src/main/java/foundation/e/apps/data/updates/UpdatesManagerImpl.kt index 42e90174a..226b43bcb 100644 --- a/app/src/main/java/foundation/e/apps/data/updates/UpdatesManagerImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/updates/UpdatesManagerImpl.kt @@ -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, diff --git a/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt b/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt index f263fc012..12993e3b1 100644 --- a/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt +++ b/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt @@ -25,6 +25,7 @@ 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.NotificationManagerUtils import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay @@ -39,7 +40,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 notificationManagerUtils: NotificationManagerUtils, ) { private val mutex = Mutex() @@ -64,10 +66,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 } @@ -87,27 +88,29 @@ 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) { + notificationManagerUtils.showNotEnoughSpaceNotification(fusedDownload, downloadId) + } } private suspend fun validateDownload( numberOfDownloadedItems: Int, fusedDownload: FusedDownload, downloadId: Long - ) = downloadManager.isDownloadSuccessful(downloadId) && - areAllFilesDownloaded( - numberOfDownloadedItems, - fusedDownload - ) && checkCleanApkSignatureOK(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, @@ -119,8 +122,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") diff --git a/app/src/main/java/foundation/e/apps/install/notification/NotificationManagerUtils.kt b/app/src/main/java/foundation/e/apps/install/notification/NotificationManagerUtils.kt index 32d24712b..01ab2b9ae 100644 --- a/app/src/main/java/foundation/e/apps/install/notification/NotificationManagerUtils.kt +++ b/app/src/main/java/foundation/e/apps/install/notification/NotificationManagerUtils.kt @@ -1,6 +1,7 @@ /* * Apps Quickly and easily install Android apps onto your device! * Copyright (C) 2021 E FOUNDATION + * Copyright (C) 2023 MURENA SAS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,12 +19,88 @@ package foundation.e.apps.install.notification +import android.Manifest +import android.app.Notification import android.content.Context +import android.content.pm.PackageManager +import androidx.core.app.ActivityCompat +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat import dagger.hilt.android.qualifiers.ApplicationContext -import foundation.e.apps.data.preference.PreferenceManagerModule +import foundation.e.apps.R +import foundation.e.apps.data.DownloadManager +import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.utils.StorageUtils import javax.inject.Inject class NotificationManagerUtils @Inject constructor( @ApplicationContext private val context: Context, - private val preferenceManagerModule: PreferenceManagerModule -) + private val downloadManager: DownloadManager, +) { + companion object { + const val NOT_ENOUGH_SPACE_NOTIFICATION_ID = 7874 + } + + fun showNotEnoughSpaceNotification(fusedDownload: FusedDownload, downloadId: Long? = null) { + + with(NotificationManagerCompat.from(context)) { + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) + != PackageManager.PERMISSION_GRANTED + ) { + return + } + + val content = getNotEnoughSpaceNotificationContent(fusedDownload, downloadId) + + notify( + NOT_ENOUGH_SPACE_NOTIFICATION_ID, + getNotEnoughSpaceNotification(content) + ) + } + } + + private fun getNotEnoughSpaceNotificationContent( + fusedDownload: FusedDownload, + downloadId: Long? = null + ): String { + val requiredInByte = getSpaceMissing(fusedDownload, downloadId) + + if (requiredInByte <= 0L) { + return context.getString(R.string.not_enough_storage) + } + + return context.getString( + R.string.free_space_for_update, + StorageUtils.humanReadableByteCountSI(requiredInByte) + ) + } + + private fun getSpaceMissing(fusedDownload: FusedDownload, downloadId: Long? = null): Long { + if (fusedDownload.appSize > 0L) { + return calculateSpaceMissingFromFusedDownload(fusedDownload) + } + + if (downloadId == null) { + return 0 + } + + return downloadManager.getSizeRequired(downloadId) + } + + private fun calculateSpaceMissingFromFusedDownload(fusedDownload: FusedDownload): Long { + var requiredInByte = StorageUtils.spaceMissing(fusedDownload) + if (requiredInByte <= 0L) { + requiredInByte = fusedDownload.appSize + } + + return requiredInByte + } + + private fun getNotEnoughSpaceNotification(content: String): Notification { + return NotificationCompat.Builder(context, NotificationManagerModule.DOWNLOADS) + .setContentText(content) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .setSmallIcon(R.drawable.app_lounge_notification_icon) + .build() + } +} diff --git a/app/src/main/java/foundation/e/apps/install/updates/UpdatesNotifier.kt b/app/src/main/java/foundation/e/apps/install/updates/UpdatesNotifier.kt index 988debf40..63eafed67 100644 --- a/app/src/main/java/foundation/e/apps/install/updates/UpdatesNotifier.kt +++ b/app/src/main/java/foundation/e/apps/install/updates/UpdatesNotifier.kt @@ -38,12 +38,12 @@ object UpdatesNotifier { private const val UPDATES_NOTIFICATION_CHANNEL_ID = "updates_notification" private const val UPDATES_NOTIFICATION_CHANNEL_TITLE = "App updates" - fun getNotification( + private fun getNotification( context: Context, numberOfApps: Int, installAutomatically: Boolean, - unmeteredNetworkOnly: Boolean, - isConnectedToUnmeteredNetwork: Boolean + unMeteredNetworkOnly: Boolean, + isConnectedToUnMeteredNetwork: Boolean ): Notification { val notificationBuilder = createNotificationBuilder(context) @@ -51,7 +51,7 @@ object UpdatesNotifier { when (numberOfApps) { 0 -> { notificationBuilder.setContentTitle( - "Checking Updates..." + context.resources.getString(R.string.checking_updates) ) } 1 -> { @@ -75,7 +75,7 @@ object UpdatesNotifier { } if (installAutomatically) { notificationBuilder.setContentText(context.getString(R.string.automatically_install_updates_notification_text)) - if (unmeteredNetworkOnly && !isConnectedToUnmeteredNetwork) { + if (unMeteredNetworkOnly && !isConnectedToUnMeteredNetwork) { notificationBuilder.setSubText( context .getString(R.string.updates_notification_unmetered_network_warning) @@ -170,7 +170,7 @@ object UpdatesNotifier { } } - fun getNotification(context: Context, title: String, message: String): Notification { + private fun getNotification(context: Context, title: String, message: String): Notification { val notificationBuilder = createNotificationBuilder(context) notificationBuilder.setContentTitle(title) notificationBuilder.setContentText(message) diff --git a/app/src/main/java/foundation/e/apps/install/updates/UpdatesWorker.kt b/app/src/main/java/foundation/e/apps/install/updates/UpdatesWorker.kt index 7470db10a..1f7804cb6 100644 --- a/app/src/main/java/foundation/e/apps/install/updates/UpdatesWorker.kt +++ b/app/src/main/java/foundation/e/apps/install/updates/UpdatesWorker.kt @@ -103,7 +103,7 @@ class UpdatesWorker @AssistedInject constructor( private suspend fun checkForUpdates() { loadSettings() - val isConnectedToUnmeteredNetwork = isConnectedToUnmeteredNetwork(applicationContext) + val isConnectedToUnMeteredNetwork = isConnectedToUnMeteredNetwork(applicationContext) val appsNeededToUpdate = mutableListOf() val user = getUser() val authData = loginSourceRepository.getValidatedAuthData().data @@ -134,7 +134,7 @@ class UpdatesWorker @AssistedInject constructor( } Timber.i("Updates found: ${appsNeededToUpdate.size}; $resultStatus") if (isAutoUpdate && shouldShowNotification) { - handleNotification(appsNeededToUpdate.size, isConnectedToUnmeteredNetwork) + handleNotification(appsNeededToUpdate.size, isConnectedToUnMeteredNetwork) } if (resultStatus != ResultStatus.OK) { @@ -146,11 +146,11 @@ class UpdatesWorker @AssistedInject constructor( */ retryCount = 0 if (isAutoUpdate && shouldShowNotification) { - handleNotification(appsNeededToUpdate.size, isConnectedToUnmeteredNetwork) + handleNotification(appsNeededToUpdate.size, isConnectedToUnMeteredNetwork) } triggerUpdateProcessOnSettings( - isConnectedToUnmeteredNetwork, + isConnectedToUnMeteredNetwork, appsNeededToUpdate, /* * If authData is null, only cleanApk data will be present @@ -251,7 +251,7 @@ class UpdatesWorker @AssistedInject constructor( * @param context current Context * @return returns true if the connections is not metered, false otherwise */ - private fun isConnectedToUnmeteredNetwork(context: Context): Boolean { + private fun isConnectedToUnMeteredNetwork(context: Context): Boolean { val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val capabilities = diff --git a/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt b/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt index 0c6ac89ae..b786e8f06 100644 --- a/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt +++ b/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt @@ -19,8 +19,6 @@ package foundation.e.apps.install.workmanager import android.content.Context -import android.os.Environment -import android.os.StatFs import com.aurora.gplayapi.exceptions.ApiException import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R @@ -35,7 +33,9 @@ import foundation.e.apps.data.fusedDownload.FusedDownloadRepository import foundation.e.apps.data.fusedDownload.FusedManagerRepository import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.preference.DataStoreManager +import foundation.e.apps.install.notification.NotificationManagerUtils import foundation.e.apps.install.updates.UpdatesNotifier +import foundation.e.apps.utils.StorageUtils import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus import foundation.e.apps.utils.getFormattedString @@ -51,7 +51,8 @@ class AppInstallProcessor @Inject constructor( private val fusedDownloadRepository: FusedDownloadRepository, private val fusedManagerRepository: FusedManagerRepository, private val fusedAPIRepository: FusedAPIRepository, - private val dataStoreManager: DataStoreManager + private val dataStoreManager: DataStoreManager, + private val notificationManagerUtils: NotificationManagerUtils ) { private var isItUpdateWork = false @@ -127,8 +128,9 @@ class AppInstallProcessor @Inject constructor( return } - if (!isStorageAvailable(fusedDownload)) { + if (StorageUtils.spaceMissing(fusedDownload) > 0) { Timber.d("Storage is not available for: ${fusedDownload.name} size: ${fusedDownload.appSize}") + notificationManagerUtils.showNotEnoughSpaceNotification(fusedDownload) fusedManagerRepository.installationIssue(fusedDownload) EventBus.invokeEvent(AppEvent.ErrorMessageEvent(R.string.not_enough_storage)) return @@ -137,7 +139,10 @@ class AppInstallProcessor @Inject constructor( fusedManagerRepository.updateAwaiting(fusedDownload) InstallWorkManager.enqueueWork(fusedDownload, isAnUpdate) } catch (e: Exception) { - Timber.e("Enqueuing App install work is failed for ${fusedDownload.packageName} exception: ${e.localizedMessage}", e) + Timber.e( + "Enqueuing App install work is failed for ${fusedDownload.packageName} exception: ${e.localizedMessage}", + e + ) fusedManagerRepository.installationIssue(fusedDownload) } } @@ -151,12 +156,14 @@ class AppInstallProcessor @Inject constructor( EventBus.invokeEvent(AppEvent.AppPurchaseEvent(fusedDownload)) return false } catch (e: Exception) { - Timber.e("Updating download Urls failed for ${fusedDownload.packageName} exception: ${e.localizedMessage}", e) + Timber.e( + "Updating download Urls failed for ${fusedDownload.packageName} exception: ${e.localizedMessage}", + e + ) EventBus.invokeEvent( AppEvent.UpdateEvent( ResultSupreme.WorkError( - ResultStatus.UNKNOWN, - fusedDownload + ResultStatus.UNKNOWN, fusedDownload ) ) ) @@ -169,22 +176,10 @@ class AppInstallProcessor @Inject constructor( fusedDownload: FusedDownload ) { fusedAPIRepository.updateFusedDownloadWithDownloadingInfo( - fusedDownload.origin, - fusedDownload + fusedDownload.origin, fusedDownload ) } - private fun isStorageAvailable(fusedDownload: FusedDownload): Boolean { - val availableSpace = calculateAvailableDiskSpace() - return availableSpace > fusedDownload.appSize + (500 * (1000 * 1000)) - } - - private fun calculateAvailableDiskSpace(): Long { - val path = Environment.getDataDirectory().absolutePath - val statFs = StatFs(path) - return statFs.availableBytes - } - suspend fun processInstall( fusedDownloadId: String, isItUpdateWork: Boolean, @@ -199,8 +194,8 @@ class AppInstallProcessor @Inject constructor( fusedDownload?.let { - this.isItUpdateWork = isItUpdateWork && - fusedManagerRepository.isFusedDownloadInstalled(fusedDownload) + this.isItUpdateWork = + isItUpdateWork && fusedManagerRepository.isFusedDownloadInstalled(fusedDownload) if (!fusedDownload.isAppInstalling()) { Timber.d("!!! returned") @@ -223,7 +218,10 @@ class AppInstallProcessor @Inject constructor( startAppInstallationProcess(it) } } catch (e: Exception) { - Timber.e("Install worker is failed for ${fusedDownload?.packageName} exception: ${e.localizedMessage}", e) + Timber.e( + "Install worker is failed for ${fusedDownload?.packageName} exception: ${e.localizedMessage}", + e + ) fusedDownload?.let { fusedManagerRepository.cancelDownload(fusedDownload) } @@ -234,11 +232,7 @@ class AppInstallProcessor @Inject constructor( } private fun areFilesDownloadedButNotInstalled(fusedDownload: FusedDownload) = - fusedDownload.areFilesDownloaded() && ( - !fusedManagerRepository.isFusedDownloadInstalled( - fusedDownload - ) || fusedDownload.status == Status.INSTALLING - ) + fusedDownload.areFilesDownloaded() && (!fusedManagerRepository.isFusedDownloadInstalled(fusedDownload) || fusedDownload.status == Status.INSTALLING) private suspend fun checkUpdateWork( fusedDownload: FusedDownload? @@ -261,14 +255,11 @@ class AppInstallProcessor @Inject constructor( } private suspend fun isUpdateCompleted(): Boolean { - val downloadListWithoutAnyIssue = - fusedDownloadRepository.getDownloadList() - .filter { - !listOf( - Status.INSTALLATION_ISSUE, - Status.PURCHASE_NEEDED - ).contains(it.status) - } + val downloadListWithoutAnyIssue = fusedDownloadRepository.getDownloadList().filter { + !listOf( + Status.INSTALLATION_ISSUE, Status.PURCHASE_NEEDED + ).contains(it.status) + } return UpdatesDao.successfulUpdatedApps.isNotEmpty() && downloadListWithoutAnyIssue.isEmpty() } @@ -276,9 +267,9 @@ class AppInstallProcessor @Inject constructor( private fun showNotificationOnUpdateEnded() { val locale = dataStoreManager.getAuthData().locale val date = Date().getFormattedString(DATE_FORMAT, locale) - val numberOfUpdatedApps = NumberFormat.getNumberInstance(locale) - .format(UpdatesDao.successfulUpdatedApps.size) - .toString() + val numberOfUpdatedApps = + NumberFormat.getNumberInstance(locale).format(UpdatesDao.successfulUpdatedApps.size) + .toString() UpdatesNotifier.showNotification( context, context.getString(R.string.update), @@ -294,13 +285,12 @@ class AppInstallProcessor @Inject constructor( Timber.i("===> doWork: Download started ${fusedDownload.name} ${fusedDownload.status}") } - fusedDownloadRepository.getDownloadFlowById(fusedDownload.id) - .transformWhile { - emit(it) - isInstallRunning(it) - }.collect { latestFusedDownload -> - handleFusedDownload(latestFusedDownload, fusedDownload) - } + fusedDownloadRepository.getDownloadFlowById(fusedDownload.id).transformWhile { + emit(it) + isInstallRunning(it) + }.collect { latestFusedDownload -> + handleFusedDownload(latestFusedDownload, fusedDownload) + } } /** @@ -360,8 +350,7 @@ class AppInstallProcessor @Inject constructor( else -> { Timber.wtf( - TAG, - "===> ${fusedDownload.name} is in wrong state ${fusedDownload.status}" + TAG, "===> ${fusedDownload.name} is in wrong state ${fusedDownload.status}" ) finishInstallation(fusedDownload) } diff --git a/app/src/main/java/foundation/e/apps/utils/StorageUtils.kt b/app/src/main/java/foundation/e/apps/utils/StorageUtils.kt new file mode 100644 index 000000000..ae77d9330 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/utils/StorageUtils.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2023 MUREANA SAS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package foundation.e.apps.utils + +import android.os.Environment +import android.os.StatFs +import foundation.e.apps.data.fusedDownload.models.FusedDownload +import java.text.CharacterIterator +import java.text.StringCharacterIterator + +object StorageUtils { + fun spaceMissing(fusedDownload: FusedDownload): Long { + return getRequiredSpace(fusedDownload) - calculateAvailableDiskSpace() + } + + private fun getRequiredSpace(fusedDownload: FusedDownload) = + fusedDownload.appSize + (500 * (1000 * 1000)) + + private fun calculateAvailableDiskSpace(): Long { + val path = Environment.getDataDirectory().absolutePath + val statFs = StatFs(path) + return statFs.availableBytes + } + + fun humanReadableByteCountSI(byteValue: Long): String { + var bytes = byteValue + + if (-1000 < bytes && bytes < 1000) { + return "$bytes B" + } + val ci: CharacterIterator = StringCharacterIterator("kMGTPE") + while (bytes <= -999950 || bytes >= 999950) { + bytes /= 1000 + ci.next() + } + return String.format("%.1f %cB", bytes / 1000.0, ci.current()) + } +} diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 1611e4485..bc8637159 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -165,4 +165,5 @@ \n \n\t• Micro-Targeting abzuschwächen \n\t• die Auswirkungen zu begrenzen, falls dieses Konto von Google eingeschränkt wird + Bitte %1$s Speicherplatz auf diesem Gerät freimachen, damtit die neueste Aktualisierung installiert werden kann. \ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 1ed92dcb2..ac0af2df9 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -154,4 +154,5 @@ Acerca de PWA y aplicaciones de código abierto O mostrar sólo + Libera %1$s en tu teléfono para recibir las últimas actualizaciones. \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 23bbc55a3..7ec04744c 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -165,4 +165,5 @@ \n \n\t• limiter le micro-ciblage \n\t• limiter les impacts au cas où ce compte serait restreint par Google + Libérez %1$s sur votre téléphone afin de bénéficier des dernières mises à jour. \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 0b480e892..537c56f53 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -165,4 +165,5 @@ \n \n\t• ridurre il micro-targeting \n\t• limitare l\'impatto nel caso in cui l\'account venga bloccato da Google + Per scaricare l\'aggiornamento, devi liberare %1$s di spazio sullo smartphone. \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 66c4effc7..c404c57a8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -130,6 +130,7 @@ Update All + Checking Updates... %1$d app update is available %1$d app updates are available @@ -231,4 +232,6 @@ Request Exodus report Clicking on \"%1$s\" will open a tab in your browser with the app\'s package name prefilled.<br /><br />Click on \"Perform analysis\" to start the analysis by Exodus.<br /><br />When the button \"See the report\" is displayed (it can take a while depending on the app) you can close the tab and go back to the app description in %2$s where you should see the Privacy Score. Sometimes Exodus can fail to analyze the app.<br /><br />NB: it can take up to 10 min for the score to be displayed in the app description. + + Free up %1$s on your phone to get the latest updates. diff --git a/app/src/test/java/foundation/e/apps/UpdateManagerImptTest.kt b/app/src/test/java/foundation/e/apps/UpdateManagerImptTest.kt index 8bf8335f7..b7a4c8ed7 100644 --- a/app/src/test/java/foundation/e/apps/UpdateManagerImptTest.kt +++ b/app/src/test/java/foundation/e/apps/UpdateManagerImptTest.kt @@ -18,7 +18,6 @@ package foundation.e.apps import android.content.Context -import android.content.pm.ApplicationInfo import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.aurora.gplayapi.data.models.AuthData import foundation.e.apps.data.blockedApps.BlockedAppRepository diff --git a/app/src/test/java/foundation/e/apps/gplay/GplyHttpClientTest.kt b/app/src/test/java/foundation/e/apps/gplay/GplyHttpClientTest.kt index f906f6fb9..38aa99e04 100644 --- a/app/src/test/java/foundation/e/apps/gplay/GplyHttpClientTest.kt +++ b/app/src/test/java/foundation/e/apps/gplay/GplyHttpClientTest.kt @@ -34,6 +34,8 @@ import kotlinx.coroutines.test.runTest import okhttp3.Cache import okhttp3.OkHttpClient import okhttp3.RequestBody.Companion.toRequestBody +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test @@ -41,8 +43,6 @@ import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations import org.mockito.kotlin.any -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue @OptIn(ExperimentalCoroutinesApi::class) class GplyHttpClientTest { diff --git a/app/src/test/java/foundation/e/apps/installProcessor/AppInstallProcessorTest.kt b/app/src/test/java/foundation/e/apps/installProcessor/AppInstallProcessorTest.kt index c6da9c22e..92587077a 100644 --- a/app/src/test/java/foundation/e/apps/installProcessor/AppInstallProcessorTest.kt +++ b/app/src/test/java/foundation/e/apps/installProcessor/AppInstallProcessorTest.kt @@ -28,6 +28,7 @@ import foundation.e.apps.data.fusedDownload.FusedDownloadRepository import foundation.e.apps.data.fusedDownload.IFusedManager import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.preference.DataStoreManager +import foundation.e.apps.install.notification.NotificationManagerUtils import foundation.e.apps.install.workmanager.AppInstallProcessor import foundation.e.apps.util.MainCoroutineRule import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -74,6 +75,9 @@ class AppInstallProcessorTest { private lateinit var appInstallProcessor: AppInstallProcessor + @Mock + private lateinit var notificationManagerUtils: NotificationManagerUtils + @Before fun setup() { MockitoAnnotations.openMocks(this) @@ -87,7 +91,8 @@ class AppInstallProcessorTest { fusedDownloadRepository, fakeFusedManagerRepository, fusedAPIRepository, - dataStoreManager + dataStoreManager, + notificationManagerUtils ) } diff --git a/app/src/test/java/foundation/e/apps/login/LoginViewModelTest.kt b/app/src/test/java/foundation/e/apps/login/LoginViewModelTest.kt index 01521a1ff..662ede447 100644 --- a/app/src/test/java/foundation/e/apps/login/LoginViewModelTest.kt +++ b/app/src/test/java/foundation/e/apps/login/LoginViewModelTest.kt @@ -67,4 +67,4 @@ class LoginViewModelTest { assert(invalidGplayAuth != null) assert((invalidGplayAuth as AuthObject.GPlayAuth).result.isUnknownError()) } -} \ No newline at end of file +} diff --git a/app/src/test/java/foundation/e/apps/util/FakeCall.kt b/app/src/test/java/foundation/e/apps/util/FakeCall.kt index 1c6aa71d8..c05e9487a 100644 --- a/app/src/test/java/foundation/e/apps/util/FakeCall.kt +++ b/app/src/test/java/foundation/e/apps/util/FakeCall.kt @@ -23,7 +23,6 @@ import okhttp3.Callback import okhttp3.Protocol import okhttp3.Request import okhttp3.Response -import okhttp3.ResponseBody import okhttp3.ResponseBody.Companion.toResponseBody import okio.Timeout @@ -76,4 +75,4 @@ class FakeCall : Call { override fun timeout(): Timeout { TODO("Not yet implemented") } -} \ No newline at end of file +} -- GitLab From 1c842ae883f1ca40ad13750460f9f04ea19fbf51 Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Wed, 27 Sep 2023 17:18:19 +0600 Subject: [PATCH 2/4] update according to review --- .../foundation/e/apps/data/DownloadManager.kt | 18 +++++++++++++----- .../install/download/DownloadManagerUtils.kt | 4 ++++ .../notification/NotificationManagerUtils.kt | 6 +++--- .../install/workmanager/AppInstallProcessor.kt | 4 ++-- .../{StorageUtils.kt => StorageComputer.kt} | 2 +- 5 files changed, 23 insertions(+), 11 deletions(-) rename app/src/main/java/foundation/e/apps/utils/{StorageUtils.kt => StorageComputer.kt} (98%) diff --git a/app/src/main/java/foundation/e/apps/data/DownloadManager.kt b/app/src/main/java/foundation/e/apps/data/DownloadManager.kt index e72bc81f0..1d30d0c9b 100644 --- a/app/src/main/java/foundation/e/apps/data/DownloadManager.kt +++ b/app/src/main/java/foundation/e/apps/data/DownloadManager.kt @@ -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 @@ -128,9 +129,9 @@ class DownloadManager @Inject constructor( 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)) @@ -180,12 +181,15 @@ class DownloadManager @Inject constructor( downloadManager.query(downloadManagerQuery.setFilterById(downloadId)) .use { cursor -> if (cursor.moveToFirst()) { - totalSizeBytes = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)) - bytesDownloadedSoFar = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)) + 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.") } catch (e: Exception) { - Timber.e(e) + Timber.e(e, "exception on retrieving download file size.") } if (totalSizeBytes <= 0) { @@ -198,6 +202,7 @@ class DownloadManager @Inject constructor( return abs(totalSizeBytes - bytesDownloadedSoFar) } + private fun getDownloadStatus(downloadId: Long): Int { var status = -1 var reason = -1 @@ -256,4 +261,7 @@ class DownloadManager @Inject constructor( } return reason } + + private fun getLong(cursor: Cursor, column: String) = + cursor.getLong(cursor.getColumnIndexOrThrow(column)) } diff --git a/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt b/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt index 12993e3b1..e9df0dc74 100644 --- a/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt +++ b/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt @@ -20,12 +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.NotificationManagerUtils +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 @@ -95,6 +98,7 @@ class DownloadManagerUtils @Inject constructor( if (downloadManager.getDownloadFailureReason(downloadId) == android.app.DownloadManager.ERROR_INSUFFICIENT_SPACE) { notificationManagerUtils.showNotEnoughSpaceNotification(fusedDownload, downloadId) + EventBus.invokeEvent(AppEvent.ErrorMessageEvent(R.string.not_enough_storage)) } } diff --git a/app/src/main/java/foundation/e/apps/install/notification/NotificationManagerUtils.kt b/app/src/main/java/foundation/e/apps/install/notification/NotificationManagerUtils.kt index 01ab2b9ae..8750b84ba 100644 --- a/app/src/main/java/foundation/e/apps/install/notification/NotificationManagerUtils.kt +++ b/app/src/main/java/foundation/e/apps/install/notification/NotificationManagerUtils.kt @@ -30,7 +30,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.data.DownloadManager import foundation.e.apps.data.fusedDownload.models.FusedDownload -import foundation.e.apps.utils.StorageUtils +import foundation.e.apps.utils.StorageComputer import javax.inject.Inject class NotificationManagerUtils @Inject constructor( @@ -71,7 +71,7 @@ class NotificationManagerUtils @Inject constructor( return context.getString( R.string.free_space_for_update, - StorageUtils.humanReadableByteCountSI(requiredInByte) + StorageComputer.humanReadableByteCountSI(requiredInByte) ) } @@ -88,7 +88,7 @@ class NotificationManagerUtils @Inject constructor( } private fun calculateSpaceMissingFromFusedDownload(fusedDownload: FusedDownload): Long { - var requiredInByte = StorageUtils.spaceMissing(fusedDownload) + var requiredInByte = StorageComputer.spaceMissing(fusedDownload) if (requiredInByte <= 0L) { requiredInByte = fusedDownload.appSize } diff --git a/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt b/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt index b786e8f06..1b1472bbd 100644 --- a/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt +++ b/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt @@ -35,7 +35,7 @@ import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.preference.DataStoreManager import foundation.e.apps.install.notification.NotificationManagerUtils import foundation.e.apps.install.updates.UpdatesNotifier -import foundation.e.apps.utils.StorageUtils +import foundation.e.apps.utils.StorageComputer import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus import foundation.e.apps.utils.getFormattedString @@ -128,7 +128,7 @@ class AppInstallProcessor @Inject constructor( return } - if (StorageUtils.spaceMissing(fusedDownload) > 0) { + if (StorageComputer.spaceMissing(fusedDownload) > 0) { Timber.d("Storage is not available for: ${fusedDownload.name} size: ${fusedDownload.appSize}") notificationManagerUtils.showNotEnoughSpaceNotification(fusedDownload) fusedManagerRepository.installationIssue(fusedDownload) diff --git a/app/src/main/java/foundation/e/apps/utils/StorageUtils.kt b/app/src/main/java/foundation/e/apps/utils/StorageComputer.kt similarity index 98% rename from app/src/main/java/foundation/e/apps/utils/StorageUtils.kt rename to app/src/main/java/foundation/e/apps/utils/StorageComputer.kt index ae77d9330..f92e855a4 100644 --- a/app/src/main/java/foundation/e/apps/utils/StorageUtils.kt +++ b/app/src/main/java/foundation/e/apps/utils/StorageComputer.kt @@ -23,7 +23,7 @@ import foundation.e.apps.data.fusedDownload.models.FusedDownload import java.text.CharacterIterator import java.text.StringCharacterIterator -object StorageUtils { +object StorageComputer { fun spaceMissing(fusedDownload: FusedDownload): Long { return getRequiredSpace(fusedDownload) - calculateAvailableDiskSpace() } -- GitLab From 81198621a567ab7d7b6e9cae5d6966ef95bb18c3 Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Wed, 27 Sep 2023 18:36:58 +0600 Subject: [PATCH 3/4] update according to review --- app/src/main/java/foundation/e/apps/data/DownloadManager.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/DownloadManager.kt b/app/src/main/java/foundation/e/apps/data/DownloadManager.kt index 1d30d0c9b..56ba57137 100644 --- a/app/src/main/java/foundation/e/apps/data/DownloadManager.kt +++ b/app/src/main/java/foundation/e/apps/data/DownloadManager.kt @@ -188,8 +188,6 @@ class DownloadManager @Inject constructor( } } catch (e: RuntimeException) { Timber.e(e, "runtime exception on retrieving download file size.") - } catch (e: Exception) { - Timber.e(e, "exception on retrieving download file size.") } if (totalSizeBytes <= 0) { -- GitLab From 5d248901175885cbf4140a414856d8aa51a53cc3 Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Thu, 28 Sep 2023 08:48:34 +0600 Subject: [PATCH 4/4] rename notificationManagerUtil to storageNotificationManager following review --- .../e/apps/install/download/DownloadManagerUtils.kt | 6 +++--- ...icationManagerUtils.kt => StorageNotificationManager.kt} | 2 +- .../e/apps/install/workmanager/AppInstallProcessor.kt | 6 +++--- .../e/apps/installProcessor/AppInstallProcessorTest.kt | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) rename app/src/main/java/foundation/e/apps/install/notification/{NotificationManagerUtils.kt => StorageNotificationManager.kt} (95%) diff --git a/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt b/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt index e9df0dc74..1438ad18f 100644 --- a/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt +++ b/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt @@ -26,7 +26,7 @@ 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.NotificationManagerUtils +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 @@ -44,7 +44,7 @@ class DownloadManagerUtils @Inject constructor( @ApplicationContext private val context: Context, private val fusedManagerRepository: FusedManagerRepository, private val downloadManager: DownloadManager, - private val notificationManagerUtils: NotificationManagerUtils, + private val storageNotificationManager: StorageNotificationManager, ) { private val mutex = Mutex() @@ -97,7 +97,7 @@ class DownloadManagerUtils @Inject constructor( Timber.w("===> Download failed: ${fusedDownload.name} ${fusedDownload.status}") if (downloadManager.getDownloadFailureReason(downloadId) == android.app.DownloadManager.ERROR_INSUFFICIENT_SPACE) { - notificationManagerUtils.showNotEnoughSpaceNotification(fusedDownload, downloadId) + storageNotificationManager.showNotEnoughSpaceNotification(fusedDownload, downloadId) EventBus.invokeEvent(AppEvent.ErrorMessageEvent(R.string.not_enough_storage)) } } diff --git a/app/src/main/java/foundation/e/apps/install/notification/NotificationManagerUtils.kt b/app/src/main/java/foundation/e/apps/install/notification/StorageNotificationManager.kt similarity index 95% rename from app/src/main/java/foundation/e/apps/install/notification/NotificationManagerUtils.kt rename to app/src/main/java/foundation/e/apps/install/notification/StorageNotificationManager.kt index 8750b84ba..be74895ea 100644 --- a/app/src/main/java/foundation/e/apps/install/notification/NotificationManagerUtils.kt +++ b/app/src/main/java/foundation/e/apps/install/notification/StorageNotificationManager.kt @@ -33,7 +33,7 @@ import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.utils.StorageComputer import javax.inject.Inject -class NotificationManagerUtils @Inject constructor( +class StorageNotificationManager @Inject constructor( @ApplicationContext private val context: Context, private val downloadManager: DownloadManager, ) { diff --git a/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt b/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt index 1b1472bbd..e17278dde 100644 --- a/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt +++ b/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt @@ -33,7 +33,7 @@ import foundation.e.apps.data.fusedDownload.FusedDownloadRepository import foundation.e.apps.data.fusedDownload.FusedManagerRepository import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.preference.DataStoreManager -import foundation.e.apps.install.notification.NotificationManagerUtils +import foundation.e.apps.install.notification.StorageNotificationManager import foundation.e.apps.install.updates.UpdatesNotifier import foundation.e.apps.utils.StorageComputer import foundation.e.apps.utils.eventBus.AppEvent @@ -52,7 +52,7 @@ class AppInstallProcessor @Inject constructor( private val fusedManagerRepository: FusedManagerRepository, private val fusedAPIRepository: FusedAPIRepository, private val dataStoreManager: DataStoreManager, - private val notificationManagerUtils: NotificationManagerUtils + private val storageNotificationManager: StorageNotificationManager ) { private var isItUpdateWork = false @@ -130,7 +130,7 @@ class AppInstallProcessor @Inject constructor( if (StorageComputer.spaceMissing(fusedDownload) > 0) { Timber.d("Storage is not available for: ${fusedDownload.name} size: ${fusedDownload.appSize}") - notificationManagerUtils.showNotEnoughSpaceNotification(fusedDownload) + storageNotificationManager.showNotEnoughSpaceNotification(fusedDownload) fusedManagerRepository.installationIssue(fusedDownload) EventBus.invokeEvent(AppEvent.ErrorMessageEvent(R.string.not_enough_storage)) return diff --git a/app/src/test/java/foundation/e/apps/installProcessor/AppInstallProcessorTest.kt b/app/src/test/java/foundation/e/apps/installProcessor/AppInstallProcessorTest.kt index 92587077a..8aca9593e 100644 --- a/app/src/test/java/foundation/e/apps/installProcessor/AppInstallProcessorTest.kt +++ b/app/src/test/java/foundation/e/apps/installProcessor/AppInstallProcessorTest.kt @@ -28,7 +28,7 @@ import foundation.e.apps.data.fusedDownload.FusedDownloadRepository import foundation.e.apps.data.fusedDownload.IFusedManager import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.preference.DataStoreManager -import foundation.e.apps.install.notification.NotificationManagerUtils +import foundation.e.apps.install.notification.StorageNotificationManager import foundation.e.apps.install.workmanager.AppInstallProcessor import foundation.e.apps.util.MainCoroutineRule import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -76,7 +76,7 @@ class AppInstallProcessorTest { private lateinit var appInstallProcessor: AppInstallProcessor @Mock - private lateinit var notificationManagerUtils: NotificationManagerUtils + private lateinit var storageNotificationManager: StorageNotificationManager @Before fun setup() { @@ -92,7 +92,7 @@ class AppInstallProcessorTest { fakeFusedManagerRepository, fusedAPIRepository, dataStoreManager, - notificationManagerUtils + storageNotificationManager ) } -- GitLab