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

Commit 83b30add authored by Hasib Prince's avatar Hasib Prince
Browse files

App Lounge: Login data flow is updated

App Lounge: refactoring login codes
parent 9439a354
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -108,8 +108,6 @@ dependencies {
    implementation "io.coil-kt:coil:1.4.0"
    implementation 'com.github.Baseflow:PhotoView:2.3.0'

    implementation 'com.jakewharton.timber:timber:5.0.1'

    //Protobuf and Gson
    implementation 'com.google.code.gson:gson:2.8.9'
    implementation "com.google.protobuf:protobuf-java:3.14.0"
+0 −4
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import foundation.e.apps.utils.modules.DataStoreModule
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import timber.log.Timber
import java.util.concurrent.Executors
import javax.inject.Inject

@@ -61,9 +60,6 @@ class AppLoungeApplication : Application(), Configuration.Provider {
                dataStoreModule.saveTOCStatus(false, "")
            }
        }
        if(BuildConfig.DEBUG) {
            Timber.plant(Timber.DebugTree())
        }
    }

    override fun getWorkManagerConfiguration() =
+15 −59
Original line number Diff line number Diff line
@@ -44,16 +44,15 @@ import foundation.e.apps.purchase.AppPurchaseFragmentDirections
import foundation.e.apps.setup.signin.SignInViewModel
import foundation.e.apps.updates.UpdatesNotifier
import foundation.e.apps.utils.enums.Status
import foundation.e.apps.utils.enums.User
import foundation.e.apps.utils.modules.CommonUtilsModule
import foundation.e.apps.utils.parentFragment.TimeoutFragment
import kotlinx.coroutines.launch
import timber.log.Timber
import java.io.File
import java.util.UUID

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    private lateinit var signInViewModel: SignInViewModel
    private lateinit var binding: ActivityMainBinding
    private val TAG = MainActivity::class.java.simpleName
    private lateinit var viewModel: MainActivityViewModel
@@ -72,7 +71,7 @@ class MainActivity : AppCompatActivity() {
        var hasInternet = true

        viewModel = ViewModelProvider(this)[MainActivityViewModel::class.java]
        val signInViewModel = ViewModelProvider(this)[SignInViewModel::class.java]
        signInViewModel = ViewModelProvider(this)[SignInViewModel::class.java]

        // navOptions and activityNavController for TOS and SignIn Fragments
        val navOptions = NavOptions.Builder()
@@ -86,31 +85,6 @@ class MainActivity : AppCompatActivity() {
            }
        }

        fun generateAuthDataBasedOnUserType(user: String) {
            if (user.isNotBlank() && viewModel.tocStatus.value == true) {
                when (User.valueOf(user)) {
                    User.ANONYMOUS -> {
                        if (viewModel.authDataJson.value.isNullOrEmpty() && !viewModel.authRequestRunning) {
                            Log.d(TAG, "Fetching new authentication data")
                            viewModel.setFirstTokenFetchTime()
                            viewModel.getAuthData()
                        }
                    }
                    User.UNAVAILABLE -> {
                        Timber.d(">>> UNAVAILABLE > destorycredentials")
                        viewModel.destroyCredentials(null)
                    }
                    User.GOOGLE -> {
                        if (viewModel.authData.value == null && !viewModel.authRequestRunning) {
                            Log.d(TAG, "Fetching new authentication data")
                            viewModel.setFirstTokenFetchTime()
                            signInViewModel.fetchAuthData()
                        }
                    }
                }
            }
        }

        viewModel.internetConnection.observe(this) { isInternetAvailable ->
            hasInternet = isInternetAvailable
            if (isInternetAvailable) {
@@ -118,8 +92,7 @@ class MainActivity : AppCompatActivity() {
                binding.fragment.visibility = View.VISIBLE

                viewModel.userType.observe(this) { user ->
                    Timber.d(">>> auth: usertype: $user")
                    generateAuthDataBasedOnUserType(user)
                    viewModel.handleAuthDataJson()
                }

                signInViewModel.authLiveData.observe(this) {
@@ -128,27 +101,14 @@ class MainActivity : AppCompatActivity() {

                // Watch and refresh authentication data
                viewModel.authDataJson.observe(this) {
                    Timber.d(">>> auth: authDataJson: ${it.length}")
                    if (!it.isNullOrEmpty() && !viewModel.userType.value.isNullOrEmpty() && !viewModel.userType.value.contentEquals(User.UNAVAILABLE.name)) {
                        viewModel.generateAuthData()
                        viewModel.validateAuthData()
                        Log.d(TAG, "Authentication data is available!")
                    }
                    viewModel.handleAuthDataJson()
                }
            }
        }

        viewModel.authValidity.observe(this) {
            Timber.d(">>> auth: authvalidity: $it")
            if(SignInViewModel.isGoogleLoginRunning) {
                return@observe
            }
            if (it != true) {
                Log.d(TAG, "Authentication data validation failed!")
                viewModel.destroyCredentials { user ->
                    if (viewModel.isTimeEligibleForTokenRefresh()) {
                        generateAuthDataBasedOnUserType(user)
                    } else {

            viewModel.handleAuthValidity(it) {
                Log.d(TAG, "Timeout validating auth data!")
                val lastFragment = navHostFragment.childFragmentManager.fragments[0]
                if (lastFragment is TimeoutFragment) {
@@ -161,10 +121,6 @@ class MainActivity : AppCompatActivity() {
                }
            }
        }
            } else {
                Log.d(TAG, "Authentication data is valid!")
            }
        }

        navController.addOnDestinationChangedListener { _, destination, _ ->
            if (!hasInternet) {
+109 −20
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import foundation.e.apps.api.cleanapk.blockedApps.BlockedAppRepository
import foundation.e.apps.api.ecloud.EcloudRepository
import foundation.e.apps.api.fused.FusedAPIRepository
import foundation.e.apps.api.fused.data.FusedApp
import foundation.e.apps.api.gplay.utils.AC2DMTask
import foundation.e.apps.manager.database.fusedDownload.FusedDownload
import foundation.e.apps.manager.fused.FusedManagerRepository
import foundation.e.apps.manager.pkg.PkgManagerModule
@@ -53,8 +54,8 @@ import foundation.e.apps.utils.modules.CommonUtilsModule.timeoutDurationInMillis
import foundation.e.apps.utils.modules.DataStoreModule
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import ru.beryukhov.reactivenetwork.ReactiveNetwork
import timber.log.Timber
import java.io.ByteArrayOutputStream
import javax.inject.Inject

@@ -67,6 +68,7 @@ class MainActivityViewModel @Inject constructor(
    private val pkgManagerModule: PkgManagerModule,
    private val ecloudRepository: EcloudRepository,
    private val blockedAppRepository: BlockedAppRepository,
    private val aC2DMTask: AC2DMTask,
) : ViewModel() {

    val authDataJson: LiveData<String> = dataStoreModule.authData.asLiveData()
@@ -90,6 +92,8 @@ class MainActivityViewModel @Inject constructor(
     */
    var firstAuthDataFetchTime = 0L

    var isTokenValidationCompletedOnce = false

    // Downloads
    val downloadList = fusedManagerRepository.getDownloadLiveList()
    var installInProgress = false
@@ -104,15 +108,16 @@ class MainActivityViewModel @Inject constructor(

    companion object {
        private const val TAG = "MainActivityViewModel"
        private var isGoogleLoginRunning = false
    }

    fun setFirstTokenFetchTime() {
    private fun setFirstTokenFetchTime() {
        if (firstAuthDataFetchTime == 0L) {
            firstAuthDataFetchTime = SystemClock.uptimeMillis()
        }
    }

    fun isTimeEligibleForTokenRefresh(): Boolean {
    private fun isTimeEligibleForTokenRefresh(): Boolean {
        return (SystemClock.uptimeMillis() - firstAuthDataFetchTime) <= timeoutDurationInMillis
    }

@@ -124,17 +129,8 @@ class MainActivityViewModel @Inject constructor(
     * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5404
     */
    fun retryFetchingTokenAfterTimeout() {
        Timber.d(
            ">>> userType: ${userType.value} authDataJson: ${
                authDataJson.value?.length
            } authData: ${authData.value?.authToken}"
        )
//        if(authDataJson.value.isNullOrEmpty() && authData.value == null) {
//            return
//        }
        firstAuthDataFetchTime = 0
        setFirstTokenFetchTime()
        Timber.d(">>> authvalidity postvalue > retryfetching")
        authValidity.postValue(false)
    }

@@ -165,7 +161,6 @@ class MainActivityViewModel @Inject constructor(
                 */
                if (!fusedAPIRepository.fetchAuthData()) {
                    authRequestRunning = false
                    Timber.d(">>> authvalidity postvalue > getAuthData")
                    authValidity.postValue(false)
                }
            }
@@ -197,7 +192,6 @@ class MainActivityViewModel @Inject constructor(
                        regenerateFunction(user)
                    } else {
                        Log.d(TAG, "Ask Google user to log in again")
                        Timber.d(">>> cleared user type")
                        dataStoreModule.clearUserType()
                    }
                }
@@ -206,21 +200,116 @@ class MainActivityViewModel @Inject constructor(
    }

    fun generateAuthData() {
        val data = gson.fromJson(authDataJson.value, AuthData::class.java)
        Timber.d(">>> generated authdata: ${data.authToken}")
        val data = jsonToAuthData()
        _authData.value = data
    }

    private fun jsonToAuthData() = gson.fromJson(authDataJson.value, AuthData::class.java)

    fun validateAuthData() {
        _authData.value?.let {
        viewModelScope.launch {
                Timber.d(">>> authvalidity postvalue > validateAuthData")
                authValidity.postValue(isAuthValid(it))
            jsonToAuthData()?.let {
                val isAuthValid = isAuthValid(it)
                authValidity.postValue(isAuthValid)
                authRequestRunning = false
            }
        }
    }

    fun handleAuthDataJson() {
        val user = userType.value
        val json = authDataJson.value

        if (user == null || json == null) {
            return
        }

        if (isUserNOTLoggedIn(user, json)) {
            generateAuthDataBasedOnUserType(user)
        } else if (isEligibleToValidateJson(json)) {
            validateAuthData()
            Log.d(TAG, ">>> Authentication data is available!")
        }
    }

    private fun isUserNOTLoggedIn(user: String, json: String) =
        !user.isNullOrEmpty() && !user.contentEquals(User.UNAVAILABLE.name) && json.isEmpty()

    private fun isEligibleToValidateJson(authDataJson: String?) =
        !authDataJson.isNullOrEmpty() && !userType.value.isNullOrEmpty() && !userType.value.contentEquals(
            User.UNAVAILABLE.name
        )

    fun handleAuthValidity(isValid: Boolean, handleTimeoOut: () -> Unit) {
        if (isGoogleLoginRunning) {
            return
        }
        isTokenValidationCompletedOnce = true
        if (!isValid) {
            Log.d(TAG, ">>> Authentication data validation failed!")
            destroyCredentials { user ->
                if (isTimeEligibleForTokenRefresh()) {
                    generateAuthDataBasedOnUserType(user)
                } else {
                    handleTimeoOut()
                }
            }
        } else {
            Log.d(TAG, "Authentication data is valid!")
            generateAuthData()
        }
    }

    private fun generateAuthDataBasedOnUserType(user: String) {
        if (user.isNotBlank() && tocStatus.value == true && !isGoogleLoginRunning) {
            when (User.valueOf(user)) {
                User.ANONYMOUS -> {
                    if (authDataJson.value.isNullOrEmpty() && !authRequestRunning) {
                        Log.d(TAG, ">>> Fetching new authentication data")
                        setFirstTokenFetchTime()
                        getAuthData()
                    }
                }
                User.UNAVAILABLE -> {
                    destroyCredentials(null)
                }
                User.GOOGLE -> {
                    if (authData.value == null && !authRequestRunning) {
                        Log.d(TAG, ">>> Fetching new authentication data")
                        setFirstTokenFetchTime()
                        fetchAuthData()
                    }
                }
            }
        }
    }

    private suspend fun fetchAuthData(email: String, oauthToken: String) {
        var responseMap: Map<String, String>
        withContext(Dispatchers.IO) {
            val response = aC2DMTask.getAC2DMResponse(email, oauthToken)
            responseMap = response
            responseMap["Token"]?.let {
                if (fusedAPIRepository.fetchAuthData(email, it) == null) {
                    dataStoreModule.clearUserType()
                    _errorMessageStringResource.value = R.string.unknown_error
                }
            }
        }
    }

    private fun fetchAuthData() {
        viewModelScope.launch {
            isGoogleLoginRunning = true
            val email = dataStoreModule.getEmail()
            val oauthToken = dataStoreModule.getAASToken()
            if (email.isNotEmpty() && oauthToken.isNotEmpty()) {
                fetchAuthData(email, oauthToken)
            }
            isGoogleLoginRunning = false
        }
    }

    private suspend fun isAuthValid(authData: AuthData): Boolean {
        return fusedAPIRepository.validateAuthData(authData)
    }
+1 −1
Original line number Diff line number Diff line
@@ -241,7 +241,7 @@ class FusedAPIImpl @Inject constructor(
        return gPlayAPIRepository.fetchAuthData()
    }

    suspend fun fetchAuthData(email: String, aasToken: String): AuthData {
    suspend fun fetchAuthData(email: String, aasToken: String): AuthData? {
        return gPlayAPIRepository.fetchAuthData(email, aasToken)
    }

Loading