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

Verified Commit 5ee74ab7 authored by Fahim M. Choudhury's avatar Fahim M. Choudhury
Browse files

fix: refresh token before PlayStore app installation when a limited response is returned from GPlay

When users try to install an app from the Home, Search or Categories screens, the API calling switches from web-based to auth-based. By that time, if the token expires in the background, Google returns a limited response (version code being 0) because of the stale token, which is inadequate to install the app.

To fix this, the token is refreshed and app details are fetched again with the refreshed token. Even after refreshing, if the version code is still 0, then it's not possible to further proceed to installation from there and an exception is thrown.
parent 2c65f604
Loading
Loading
Loading
Loading
Loading
+36 −19
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import foundation.e.apps.data.application.utils.toApplication
import foundation.e.apps.data.enums.Source
import foundation.e.apps.data.handleNetworkResult
import foundation.e.apps.data.login.AuthenticatorRepository
import foundation.e.apps.data.login.PlayStoreAuthenticator
import foundation.e.apps.data.playstore.utils.GPlayHttpClient
import foundation.e.apps.utils.SystemInfoProvider
import kotlinx.coroutines.Dispatchers
@@ -144,21 +145,39 @@ class PlayStoreRepository @Inject constructor(
        return categoryList
    }

    override suspend fun getAppDetails(packageName: String): Application {
        var appDetails: GplayApp?
    override suspend fun getAppDetails(packageName: String): Application =
        withContext(Dispatchers.IO) {
            var appDetails: GplayApp
            appDetails = getAppDetailsHelper().getAppByPackageName(packageName)

        val appDetailsHelper =
            AppDetailsHelper(authenticatorRepository.getGPlayAuthOrThrow()).using(gPlayHttpClient)
            if (!isEmulator() && appDetails.versionCode == 0) {
                // Google Play returns limited result ( i.e. version code being 0) with a stale token,
                // so we need to refresh authentication to get a new token.
                Timber.i("Version code is 0 for ${appDetails.packageName}.")

        withContext(Dispatchers.IO) {
            appDetails = appDetailsHelper.getAppByPackageName(packageName)
        }
                refreshPlayStoreAuthentication()

        if (!isEmulator() && appDetails?.versionCode == 0) {
                appDetails = getAppDetailsHelper().getAppByPackageName(packageName)

                if (appDetails.versionCode == 0) {
                    Timber.w("After refreshing auth, version code is still 0. Giving up installation.")
                    throw IllegalStateException("App version code cannot be 0")
                }
            }

            appDetails.toApplication(context)
        }

    private fun getAppDetailsHelper(): AppDetailsHelper {
        val authData = authenticatorRepository.getGPlayAuthOrThrow()
        val appDetailsHelper = AppDetailsHelper(authData).using(gPlayHttpClient)

        return appDetailsHelper
    }

        return appDetails?.toApplication(context) ?: Application()
    private suspend fun refreshPlayStoreAuthentication() {
        Timber.i("Refreshing authentication.")
        authenticatorRepository.getAuthObjects(listOf(PlayStoreAuthenticator::class.java.simpleName))
    }

    suspend fun getAppDetailsWeb(packageName: String): Application? {
@@ -206,10 +225,7 @@ class PlayStoreRepository @Inject constructor(
        idOrPackageName: String,
        versionCode: Int,
        offerType: Int
    ): List<File> {
        val downloadData = mutableListOf<File>()
        val authData = authenticatorRepository.getGPlayAuthOrThrow()

    ): List<File> = withContext(Dispatchers.IO) {
        var version = versionCode
        var offer = offerType

@@ -223,11 +239,12 @@ class PlayStoreRepository @Inject constructor(
            throw IllegalStateException("Could not get download details for $idOrPackageName")
        }

        withContext(Dispatchers.IO) {
            val purchaseHelper = PurchaseHelper(authData).using(gPlayHttpClient)
            downloadData.addAll(purchaseHelper.purchase(idOrPackageName, version, offer))
        }
        return downloadData
        // Don't store auth data in a variable. Always get GPlay auth from repository,
        // because auth might get refreshed while fetching app details.
        val purchaseHelper = PurchaseHelper(authenticatorRepository.getGPlayAuthOrThrow())
            .using(gPlayHttpClient)

        buildList { addAll(purchaseHelper.purchase(idOrPackageName, version, offer)) }
    }

    suspend fun getOnDemandModule(
+1 −1
Original line number Diff line number Diff line
@@ -206,7 +206,7 @@ class AppInstallProcessor @Inject constructor(
            )
            return false
        } catch (e: IllegalStateException) {
            EventBus.invokeEvent(AppEvent.InvalidAuthEvent(AuthObject.GPlayAuth::class.java.simpleName))
            Timber.e(e)
        } catch (e: Exception) {
            handleUpdateDownloadError(
                appInstall,