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

Commit 93cd6f44 authored by Abhishek Aggarwal's avatar Abhishek Aggarwal Committed by Abhishek Aggarwal
Browse files

fix(playstore): don't refresh token for device-restricted apps with version code 0

parent 224f6d4c
Loading
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -64,6 +64,9 @@ class ApplicationDataManager @Inject constructor(
            !isRestricted(application) -> FilterLevel.NONE
            !isApplicationVisible(application) -> FilterLevel.DATA
            application.originalSize == 0L -> FilterLevel.UI
            // Restricted with no installable build for this device (e.g. a TV-only app on a
            // phone, version code 0). Keep it visible but mark the install button N/A.
            application.latest_version_code <= 0L -> FilterLevel.UI
            else -> FilterLevel.NONE
        }
    }
+21 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
package foundation.e.apps.data.playstore

import android.content.Context
import com.aurora.gplayapi.Constants.Restriction
import com.aurora.gplayapi.data.models.Category
import com.aurora.gplayapi.data.models.ContentRating
import com.aurora.gplayapi.data.models.PlayFile
@@ -376,7 +377,13 @@ class PlayStoreRepository @Inject constructor(
            return appDetails
        }

        Timber.i("Version code is 0 for %s.", appDetails.packageName)
        // A specific restriction code means Google evaluated the request and the app simply
        // isn't installable for this account/device (e.g. a TV-only app on a phone). Refreshing
        // auth can't change that, so keep the details we have and let the UI mark it N/A.
        if (appDetails.isRestrictedFromInstall()) {
            return appDetails
        }

        val refreshedAppDetails = retryAfterSuccessfulPlayAuthRefreshOrNull(
            operationName = "app details",
            reason = "version code is 0 for ${appDetails.packageName}",
@@ -384,6 +391,9 @@ class PlayStoreRepository @Inject constructor(
        ) ?: appDetails

        if (refreshedAppDetails.versionCode == 0L) {
            if (refreshedAppDetails.isRestrictedFromInstall()) {
                return refreshedAppDetails
            }
            Timber.w("After refreshing auth, version code is still 0. Giving up installation.")
            throw IllegalStateException("App version code cannot be 0")
        }
@@ -391,6 +401,16 @@ class PlayStoreRepository @Inject constructor(
        return refreshedAppDetails
    }

    /**
     * True when Google returned a definitive restriction code for this app, meaning it can't be
     * installed for the current account/device. [Restriction.GENERIC] is excluded because it is
     * the fallback for absent/unmapped values, which can also mask a stale token; those keep the
     * auth-refresh recovery path.
     */
    private fun GplayApp.isRestrictedFromInstall(): Boolean {
        return restriction != Restriction.NOT_RESTRICTED && restriction != Restriction.GENERIC
    }

    suspend fun getAppDetailsWeb(packageName: String): Application? {
        val webAppDetailsHelper = WebAppDetailsHelper().using(gPlayHttpClient)

+24 −0
Original line number Diff line number Diff line
package foundation.e.apps.data.playstore

import androidx.test.core.app.ApplicationProvider
import com.aurora.gplayapi.Constants.Restriction
import com.aurora.gplayapi.data.models.App
import com.aurora.gplayapi.data.models.Artwork
import com.aurora.gplayapi.data.models.AuthData
@@ -140,6 +141,28 @@ class PlayStoreRepositoryTest {
        verify(exactly = 2) { anyConstructed<AppDetailsHelper>().getAppByPackageName("pkg.test") }
    }

    @Test
    fun `getAppDetails does not refresh token for restricted app with zero version code`() = runTest {
        val authData = AuthData(email = "user@gmail.com")
        val restrictedApp = buildAppDetails("pkg.test", 0)
        every { restrictedApp.restriction } returns Restriction.UNKNOWN
        val playStoreAuthManager = mock<PlayStoreAuthManager>()
        val tokenRefreshHandler = FakeTokenRefreshHandler(AuthResult.Success(Unit))

        repository = createRepository(playStoreAuthManager, tokenRefreshHandler = tokenRefreshHandler)

        whenever(playStoreAuthManager.requireValidatedPlayStoreAuth()).thenReturn(authData)
        every {
            anyConstructed<AppDetailsHelper>().getAppByPackageName("pkg.test")
        } returns restrictedApp

        val result = repository.getAppDetails("pkg.test")

        assertThat(result.latest_version_code).isEqualTo(0)
        assertThat(tokenRefreshHandler.refreshCalls).isEqualTo(0)
        verify(exactly = 1) { anyConstructed<AppDetailsHelper>().getAppByPackageName("pkg.test") }
    }

    @Test
    fun `getAppDetails does not retry zero version request when auth refresh fails`() = runTest {
        val authData = AuthData(email = "user@gmail.com")
@@ -684,6 +707,7 @@ class PlayStoreRepositoryTest {
        every { app.size } returns 1000L
        every { app.isFree } returns true
        every { app.price } returns "0"
        every { app.restriction } returns Restriction.NOT_RESTRICTED
        return app
    }