Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5e1ea3ce authored by Hasib Prince's avatar Hasib Prince
Browse files

improved handling event from downloadManager

parent f352a435
Loading
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -90,8 +90,8 @@ android {

    buildTypes {
        debug {
            versionNameSuffix ".debug"
            applicationIdSuffix ".debug"
//            versionNameSuffix ".debug"
//            applicationIdSuffix ".debug"
            signingConfig signingConfigs.debugConfig
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
+9 −0
Original line number Diff line number Diff line
@@ -83,6 +83,15 @@
            </intent-filter>
        </receiver>

        <receiver android:name=".receivers.DumpAppInstallStatusReceiver"
            android:enabled="true"
            android:exported="true"
            tools:ignore="ExportedReceiver">
            <intent-filter>
                <action android:name="foundation.e.apps.action.APP_INSTALL_STATE"/>
            </intent-filter>
        </receiver>

        <!-- TODO: ExportedReceiver, suppressing because changes are needed in other apps -->
        <receiver android:name=".install.receiver.PWAPlayerStatusReceiver"
            tools:ignore="ExportedReceiver"
+6 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import androidx.work.ExistingPeriodicWorkPolicy
import dagger.hilt.android.HiltAndroidApp
import foundation.e.apps.data.Constants.TAG_APP_INSTALL_STATE
import foundation.e.apps.data.Constants.TAG_AUTHDATA_DUMP
import foundation.e.apps.data.preference.AppLoungeDataStore
import foundation.e.apps.data.preference.AppLoungePreference
@@ -90,7 +91,11 @@ class AppLoungeApplication : Application(), Configuration.Provider {
            Telemetry.init(BuildConfig.SENTRY_DSN, this)
            plant(object : Timber.Tree() {
                override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
                    if (priority <= Log.WARN && tag != TAG_AUTHDATA_DUMP) {
                    if (priority <= Log.WARN && !listOf(
                            TAG_AUTHDATA_DUMP,
                            TAG_APP_INSTALL_STATE
                        ).contains(tag)
                    ) {
                        return
                    }
                    Log.println(priority, tag, message)
+3 −0
Original line number Diff line number Diff line
@@ -9,4 +9,7 @@ object Constants {

    const val ACTION_AUTHDATA_DUMP = "foundation.e.apps.action.DUMP_GACCOUNT_INFO"
    const val TAG_AUTHDATA_DUMP = "AUTHDATA_DUMP"

    const val ACTION_DUMP_APP_INSTALL_STATE = "foundation.e.apps.action.APP_INSTALL_STATE"
    const val TAG_APP_INSTALL_STATE = "APP_INSTALL_STATE"
}
+50 −20
Original line number Diff line number Diff line
@@ -29,14 +29,16 @@ 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.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import android.app.DownloadManager as PlatformDownloadManager
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton

@Singleton
@@ -45,12 +47,13 @@ class DownloadManagerUtils @Inject constructor(
    private val fusedManagerRepository: FusedManagerRepository,
    private val downloadManager: DownloadManager,
    private val storageNotificationManager: StorageNotificationManager,
    @Named("ioCoroutineScope") private val coroutineScope: CoroutineScope
) {
    private val mutex = Mutex()

    @DelicateCoroutinesApi
    fun cancelDownload(downloadId: Long) {
        GlobalScope.launch {
        coroutineScope.launch {
            val fusedDownload = fusedManagerRepository.getFusedDownload(downloadId)
            fusedManagerRepository.cancelDownload(fusedDownload)
        }
@@ -58,27 +61,25 @@ class DownloadManagerUtils @Inject constructor(

    @DelicateCoroutinesApi
    fun updateDownloadStatus(downloadId: Long) {
        GlobalScope.launch {
        coroutineScope.launch {
            mutex.withLock {
                delay(1500) // Waiting for downloadmanager to publish the progress of last bytes
                val fusedDownload = fusedManagerRepository.getFusedDownload(downloadId)
                if (fusedDownload.id.isNotEmpty()) {
                    updateDownloadIdMap(fusedDownload, downloadId)
                    val numberOfDownloadedItems =
                        fusedDownload.downloadIdMap.values.filter { it }.size
                    Timber.d("===> updateDownloadStatus: ${fusedDownload.name}: $downloadId: $numberOfDownloadedItems/${fusedDownload.downloadIdMap.size}")

                    if (downloadManager.hasDownloadFailed(downloadId)) {
                        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
                    }

                    if (validateDownload(numberOfDownloadedItems, fusedDownload, downloadId)) {
                        handleDownloadSuccess(fusedDownload)
                    }
                    validateDownload(fusedDownload, downloadId)
                }
            }
        }
@@ -87,9 +88,11 @@ class DownloadManagerUtils @Inject constructor(
    private suspend fun handleDownloadSuccess(fusedDownload: FusedDownload) {
        Timber.i("===> Download is completed for: ${fusedDownload.name}")
        fusedManagerRepository.moveOBBFileToOBBDirectory(fusedDownload)
        if (fusedDownload.status == Status.DOWNLOADING) {
            fusedDownload.status = Status.DOWNLOADED
            fusedManagerRepository.updateFusedDownload(fusedDownload)
        }
    }

    private suspend fun handleDownloadFailed(fusedDownload: FusedDownload, downloadId: Long) {
        fusedManagerRepository.installationIssue(fusedDownload)
@@ -103,20 +106,47 @@ class DownloadManagerUtils @Inject constructor(
    }

    private suspend fun validateDownload(
        numberOfDownloadedItems: Int,
        fusedDownload: FusedDownload,
        downloadId: Long
    ): Boolean {
    ) {
        val incompleteDownloadState = listOf(
            PlatformDownloadManager.STATUS_PENDING,
            PlatformDownloadManager.STATUS_RUNNING,
            PlatformDownloadManager.STATUS_PAUSED,
        )

        val isDownloadSuccessful = downloadManager.isDownloadSuccessful(downloadId)

        if (isDownloadSuccessful.first) {
            updateDownloadIdMap(fusedDownload, downloadId)
        }

        val numberOfDownloadedItems =
            fusedDownload.downloadIdMap.values.filter { it }.size
        Timber.d("===> updateDownloadStatus: ${fusedDownload.name}: $downloadId: $numberOfDownloadedItems/${fusedDownload.downloadIdMap.size}")

        // if download status code is unknown (-1), consider installation is failed.
        if (isDownloadSuccessful.second == -1) {
            handleDownloadFailed(fusedDownload, downloadId)
        val areAllFilesDownloaded = areAllFilesDownloaded(
            numberOfDownloadedItems,
            fusedDownload
        )

        if (isDownloadSuccessful.first && areAllFilesDownloaded && checkCleanApkSignatureOK(fusedDownload)) {
            handleDownloadSuccess(fusedDownload)
            return
        }

        return isDownloadSuccessful.first && areAllFilesDownloaded(
            numberOfDownloadedItems, fusedDownload
        ) && checkCleanApkSignatureOK(fusedDownload)
        if (incompleteDownloadState.contains(isDownloadSuccessful.second)
            || (isDownloadSuccessful.first && !areAllFilesDownloaded)
        ) {
            return
        }

        handleDownloadFailed(fusedDownload, downloadId)
        Timber.e(
            "Download failed for ${fusedDownload.packageName}: " +
                    "Download Status: ${isDownloadSuccessful.second}"
        )
    }

    private fun areAllFilesDownloaded(
Loading