Loading app/build.gradle +0 −2 Original line number Diff line number Diff line Loading @@ -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" Loading app/src/main/java/foundation/e/apps/AppLoungeApplication.kt +0 −4 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -61,9 +60,6 @@ class AppLoungeApplication : Application(), Configuration.Provider { dataStoreModule.saveTOCStatus(false, "") } } if(BuildConfig.DEBUG) { Timber.plant(Timber.DebugTree()) } } override fun getWorkManagerConfiguration() = Loading app/src/main/java/foundation/e/apps/MainActivity.kt +15 −59 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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() Loading @@ -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) { Loading @@ -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) { Loading @@ -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) { Loading @@ -161,10 +121,6 @@ class MainActivity : AppCompatActivity() { } } } } else { Log.d(TAG, "Authentication data is valid!") } } navController.addOnDestinationChangedListener { _, destination, _ -> if (!hasInternet) { Loading app/src/main/java/foundation/e/apps/MainActivityViewModel.kt +109 −20 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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() Loading @@ -90,6 +92,8 @@ class MainActivityViewModel @Inject constructor( */ var firstAuthDataFetchTime = 0L var isTokenValidationCompletedOnce = false // Downloads val downloadList = fusedManagerRepository.getDownloadLiveList() var installInProgress = false Loading @@ -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 } Loading @@ -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) } Loading Loading @@ -165,7 +161,6 @@ class MainActivityViewModel @Inject constructor( */ if (!fusedAPIRepository.fetchAuthData()) { authRequestRunning = false Timber.d(">>> authvalidity postvalue > getAuthData") authValidity.postValue(false) } } Loading Loading @@ -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() } } Loading @@ -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) } Loading app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
app/build.gradle +0 −2 Original line number Diff line number Diff line Loading @@ -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" Loading
app/src/main/java/foundation/e/apps/AppLoungeApplication.kt +0 −4 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -61,9 +60,6 @@ class AppLoungeApplication : Application(), Configuration.Provider { dataStoreModule.saveTOCStatus(false, "") } } if(BuildConfig.DEBUG) { Timber.plant(Timber.DebugTree()) } } override fun getWorkManagerConfiguration() = Loading
app/src/main/java/foundation/e/apps/MainActivity.kt +15 −59 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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() Loading @@ -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) { Loading @@ -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) { Loading @@ -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) { Loading @@ -161,10 +121,6 @@ class MainActivity : AppCompatActivity() { } } } } else { Log.d(TAG, "Authentication data is valid!") } } navController.addOnDestinationChangedListener { _, destination, _ -> if (!hasInternet) { Loading
app/src/main/java/foundation/e/apps/MainActivityViewModel.kt +109 −20 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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() Loading @@ -90,6 +92,8 @@ class MainActivityViewModel @Inject constructor( */ var firstAuthDataFetchTime = 0L var isTokenValidationCompletedOnce = false // Downloads val downloadList = fusedManagerRepository.getDownloadLiveList() var installInProgress = false Loading @@ -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 } Loading @@ -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) } Loading Loading @@ -165,7 +161,6 @@ class MainActivityViewModel @Inject constructor( */ if (!fusedAPIRepository.fetchAuthData()) { authRequestRunning = false Timber.d(">>> authvalidity postvalue > getAuthData") authValidity.postValue(false) } } Loading Loading @@ -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() } } Loading @@ -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) } Loading
app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +1 −1 Original line number Diff line number Diff line Loading @@ -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