diff --git a/app/src/main/java/foundation/e/apps/api/ResultSupreme.kt b/app/src/main/java/foundation/e/apps/api/ResultSupreme.kt index f74b9c218b5c3bea922017f5af13c74d59d9822b..d64afd821343078c8d7315ed226693cbf376ce4b 100644 --- a/app/src/main/java/foundation/e/apps/api/ResultSupreme.kt +++ b/app/src/main/java/foundation/e/apps/api/ResultSupreme.kt @@ -134,7 +134,7 @@ sealed class ResultSupreme { val resultObject = when { status == ResultStatus.OK && data != null -> Success(data) status == ResultStatus.TIMEOUT && data != null -> Timeout(data) - else -> Error(message, exception) + else -> Error(message.ifBlank { status.message }, exception) } resultObject.apply { if (isUnknownError()) { diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index 1ada969bf02495c39070450aeca2c0f98fbe4ac2..ac5d0e8db2e0f2a8c2638414e9e31c78cc5e609c 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -133,48 +133,32 @@ class FusedAPIImpl @Inject constructor( applicationType: String ): Pair, ResultStatus> { val list = mutableListOf() - var apiStatus = ResultStatus.OK - try { - /* - * Each category of home apps (example "Top Free Apps") will have its own timeout. - * Fetching 6 such categories will have a total timeout to 2 mins 30 seconds - * (considering each category having 25 seconds timeout). - * - * To prevent waiting so long and fail early, use withTimeout{}. - */ - withTimeout(timeoutDurationInMillis) { - if (preferenceManagerModule.isGplaySelected()) { - list.addAll(fetchGPlayHome(authData)) - } + val apiStatus = runCodeBlockWithTimeout({ - if (preferenceManagerModule.isOpenSourceSelected()) { - val response = cleanAPKRepository.getHomeScreenData( - CleanAPKInterface.APP_TYPE_ANY, - CleanAPKInterface.APP_SOURCE_FOSS - ).body() - response?.home?.let { - list.addAll(generateCleanAPKHome(it, APP_TYPE_OPEN)) - } + if (preferenceManagerModule.isGplaySelected()) { + list.addAll(fetchGPlayHome(authData)) + } + + if (preferenceManagerModule.isOpenSourceSelected()) { + val response = cleanAPKRepository.getHomeScreenData( + CleanAPKInterface.APP_TYPE_ANY, + CleanAPKInterface.APP_SOURCE_FOSS + ).body() + response?.home?.let { + list.addAll(generateCleanAPKHome(it, APP_TYPE_OPEN)) } + } - if (preferenceManagerModule.isPWASelected()) { - val response = cleanAPKRepository.getHomeScreenData( - CleanAPKInterface.APP_TYPE_PWA, - CleanAPKInterface.APP_SOURCE_ANY - ).body() - response?.home?.let { - list.addAll(generateCleanAPKHome(it, APP_TYPE_PWA)) - } + if (preferenceManagerModule.isPWASelected()) { + val response = cleanAPKRepository.getHomeScreenData( + CleanAPKInterface.APP_TYPE_PWA, + CleanAPKInterface.APP_SOURCE_ANY + ).body() + response?.home?.let { + list.addAll(generateCleanAPKHome(it, APP_TYPE_PWA)) } } - } catch (e: TimeoutCancellationException) { - e.printStackTrace() - apiStatus = ResultStatus.TIMEOUT - Timber.d("Timed out fetching home data for type: $applicationType") - } catch (e: Exception) { - apiStatus = ResultStatus.UNKNOWN - Timber.e(e) - } + }) return Pair(list, apiStatus) } @@ -1015,7 +999,7 @@ class FusedAPIImpl @Inject constructor( private suspend fun runCodeBlockWithTimeout( block: suspend () -> Unit, timeoutBlock: (() -> Unit)? = null, - exceptionBlock: (() -> Unit)? = null, + exceptionBlock: ((e: Exception) -> Unit)? = null, ): ResultStatus { return try { withTimeout(timeoutDurationInMillis) { @@ -1027,8 +1011,10 @@ class FusedAPIImpl @Inject constructor( ResultStatus.TIMEOUT } catch (e: Exception) { e.printStackTrace() - exceptionBlock?.invoke() - ResultStatus.UNKNOWN + exceptionBlock?.invoke(e) + ResultStatus.UNKNOWN.apply { + message = e.stackTraceToString() + } } } diff --git a/app/src/main/java/foundation/e/apps/application/ApplicationViewModel.kt b/app/src/main/java/foundation/e/apps/application/ApplicationViewModel.kt index 886bcadbb33bbb22829e69cfa4f63a5df3795712..6366fdb286d560717c80adb63474cf5d4ae50fea 100644 --- a/app/src/main/java/foundation/e/apps/application/ApplicationViewModel.kt +++ b/app/src/main/java/foundation/e/apps/application/ApplicationViewModel.kt @@ -105,11 +105,19 @@ class ApplicationViewModel @Inject constructor( ) fusedApp.postValue(appData) + val status = appData.second + if (appData.second != ResultStatus.OK) { val exception = if (authData.aasToken.isNotBlank() || authData.authToken.isNotBlank()) - GPlayException(appData.second == ResultStatus.TIMEOUT, "Data load error") - else CleanApkException(appData.second == ResultStatus.TIMEOUT, "Data load error") + GPlayException( + appData.second == ResultStatus.TIMEOUT, + status.message.ifBlank { "Data load error" } + ) + else CleanApkException( + appData.second == ResultStatus.TIMEOUT, + status.message.ifBlank { "Data load error" } + ) exceptionsList.add(exception) exceptionsLiveData.postValue(exceptionsList) diff --git a/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListViewModel.kt b/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListViewModel.kt index 4fe45743905407dd0335a31bb409529526267e68..d3045d9194241b0df69d6f406d0dcaa4af786a89 100644 --- a/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListViewModel.kt +++ b/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListViewModel.kt @@ -77,8 +77,14 @@ class ApplicationListViewModel @Inject constructor( if (!result.isSuccess()) { val exception = if (authData.aasToken.isNotBlank() || authData.authToken.isNotBlank()) - GPlayException(result.isTimeout(), "Data load error") - else CleanApkException(result.isTimeout(), "Data load error") + GPlayException( + result.isTimeout(), + result.message.ifBlank { "Data load error" } + ) + else CleanApkException( + result.isTimeout(), + result.message.ifBlank { "Data load error" } + ) exceptionsList.add(exception) exceptionsLiveData.postValue(exceptionsList) diff --git a/app/src/main/java/foundation/e/apps/categories/CategoriesViewModel.kt b/app/src/main/java/foundation/e/apps/categories/CategoriesViewModel.kt index 13456df3c577b58c62a059ac0ac37c4fd10d045f..d505cf1367da6f13cf485360680564db58f9f9c1 100644 --- a/app/src/main/java/foundation/e/apps/categories/CategoriesViewModel.kt +++ b/app/src/main/java/foundation/e/apps/categories/CategoriesViewModel.kt @@ -65,11 +65,19 @@ class CategoriesViewModel @Inject constructor( val categoriesData = fusedAPIRepository.getCategoriesList(type, authData) categoriesList.postValue(categoriesData) - if (categoriesData.third != ResultStatus.OK) { + val status = categoriesData.third + + if (status != ResultStatus.OK) { val exception = if (authData.aasToken.isNotBlank() || authData.authToken.isNotBlank()) - GPlayException(categoriesData.third == ResultStatus.TIMEOUT, "Data load error") - else CleanApkException(categoriesData.third == ResultStatus.TIMEOUT, "Data load error") + GPlayException( + categoriesData.third == ResultStatus.TIMEOUT, + status.message.ifBlank { "Data load error" } + ) + else CleanApkException( + categoriesData.third == ResultStatus.TIMEOUT, + status.message.ifBlank { "Data load error" } + ) exceptionsList.add(exception) exceptionsLiveData.postValue(exceptionsList) diff --git a/app/src/main/java/foundation/e/apps/home/HomeViewModel.kt b/app/src/main/java/foundation/e/apps/home/HomeViewModel.kt index 596d07673a161a19bf07cd0542e9be4301a1b7fa..25cb14b7a1826e456f4a6bc0972b2e1ab0d6ff12 100644 --- a/app/src/main/java/foundation/e/apps/home/HomeViewModel.kt +++ b/app/src/main/java/foundation/e/apps/home/HomeViewModel.kt @@ -69,11 +69,19 @@ class HomeViewModel @Inject constructor( val screenData = fusedAPIRepository.getHomeScreenData(authData) homeScreenData.postValue(screenData) - if (screenData.second != ResultStatus.OK) { + val status = screenData.second + + if (status != ResultStatus.OK) { val exception = if (authData.aasToken.isNotBlank() || authData.authToken.isNotBlank()) - GPlayException(screenData.second == ResultStatus.TIMEOUT, "Data load error") - else CleanApkException(screenData.second == ResultStatus.TIMEOUT, "Data load error") + GPlayException( + screenData.second == ResultStatus.TIMEOUT, + status.message.ifBlank { "Data load error" } + ) + else CleanApkException( + screenData.second == ResultStatus.TIMEOUT, + status.message.ifBlank { "Data load error" } + ) exceptionsList.add(exception) exceptionsLiveData.postValue(exceptionsList) diff --git a/app/src/main/java/foundation/e/apps/login/LoginSourceGPlay.kt b/app/src/main/java/foundation/e/apps/login/LoginSourceGPlay.kt index 0126beaea3be0b8a9672b5b4d93096a87bd1f7b9..27222dace42fec78eed7ae93f4fefd76b4c1bca7 100644 --- a/app/src/main/java/foundation/e/apps/login/LoginSourceGPlay.kt +++ b/app/src/main/java/foundation/e/apps/login/LoginSourceGPlay.kt @@ -17,8 +17,10 @@ package foundation.e.apps.login +import android.content.Context import com.aurora.gplayapi.data.models.AuthData import com.google.gson.Gson +import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.api.ResultSupreme import foundation.e.apps.login.api.GPlayApiFactory import foundation.e.apps.login.api.GPlayLoginInterface @@ -26,6 +28,7 @@ import foundation.e.apps.login.api.GoogleLoginApi import foundation.e.apps.login.api.LoginApiRepository import foundation.e.apps.utils.enums.User import foundation.e.apps.utils.exceptions.GPlayValidationException +import java.util.Locale import javax.inject.Inject import javax.inject.Singleton @@ -37,6 +40,7 @@ import javax.inject.Singleton */ @Singleton class LoginSourceGPlay @Inject constructor( + @ApplicationContext private val context: Context, private val gson: Gson, private val loginDataStore: LoginDataStore, ) : LoginSourceInterface { @@ -53,6 +57,9 @@ class LoginSourceGPlay @Inject constructor( private val loginApiRepository: LoginApiRepository get() = LoginApiRepository(gPlayLoginInterface, user) + private val locale: Locale + get() = context.resources.configuration.locales[0] + override fun isActive(): Boolean { if (user == User.UNAVAILABLE) { /* @@ -141,7 +148,7 @@ class LoginSourceGPlay @Inject constructor( * Get AuthData for ANONYMOUS mode. */ private suspend fun getAuthData(): ResultSupreme { - return loginApiRepository.fetchAuthData("", "").run { + return loginApiRepository.fetchAuthData("", "", locale).run { if (isSuccess()) ResultSupreme.Success(formattedAuthData(this.data!!)) else this } @@ -161,7 +168,7 @@ class LoginSourceGPlay @Inject constructor( * Use it to fetch auth data. */ if (aasToken.isNotBlank()) { - return loginApiRepository.fetchAuthData(email, aasToken) + return loginApiRepository.fetchAuthData(email, aasToken, locale) } /* @@ -192,7 +199,7 @@ class LoginSourceGPlay @Inject constructor( * Finally save the aasToken and create auth data. */ loginDataStore.saveAasToken(aasTokenFetched) - return loginApiRepository.fetchAuthData(email, aasTokenFetched) + return loginApiRepository.fetchAuthData(email, aasTokenFetched, locale) } /** @@ -205,6 +212,7 @@ class LoginSourceGPlay @Inject constructor( ): ResultSupreme { val formattedAuthData = formattedAuthData(authData) + formattedAuthData.locale = locale val validityResponse = loginApiRepository.login(formattedAuthData) @@ -216,7 +224,7 @@ class LoginSourceGPlay @Inject constructor( val playResponse = validityResponse.data return if (validityResponse.isSuccess() && playResponse?.code == 200 && playResponse.isSuccessful) { - ResultSupreme.Success(authData) + ResultSupreme.Success(formattedAuthData) } else { val message = "Validating AuthData failed.\n\n" + diff --git a/app/src/main/java/foundation/e/apps/login/api/AnonymousLoginApi.kt b/app/src/main/java/foundation/e/apps/login/api/AnonymousLoginApi.kt index dcc7f99b8bcc9edaa19052b1a73193a3208eb9f1..70d795a89a247aa3cffb27f8af79544d7a60bfd9 100644 --- a/app/src/main/java/foundation/e/apps/login/api/AnonymousLoginApi.kt +++ b/app/src/main/java/foundation/e/apps/login/api/AnonymousLoginApi.kt @@ -50,7 +50,15 @@ class AnonymousLoginApi( val response = gPlayHttpClient.postAuth(tokenUrl, gson.toJson(nativeDeviceProperty).toByteArray()) if (response.code != 200 || !response.isSuccessful) { - throw Exception("Error fetching Anonymous credentials: ${response.errorString}") + throw Exception( + "Error fetching Anonymous credentials\n" + + "Network code: ${response.code}\n" + + "Success: ${response.isSuccessful}" + + response.errorString.run { + if (isNotBlank()) "\nError message: ${response.errorString}" + else "" + } + ) } else { authData = gson.fromJson( String(response.responseBytes), diff --git a/app/src/main/java/foundation/e/apps/login/api/LoginApiRepository.kt b/app/src/main/java/foundation/e/apps/login/api/LoginApiRepository.kt index 44dcd0c7d74c6e76afa622f94a0052b196751b20..fa8602834c93a3df03245bee9a51d1f1589a5917 100644 --- a/app/src/main/java/foundation/e/apps/login/api/LoginApiRepository.kt +++ b/app/src/main/java/foundation/e/apps/login/api/LoginApiRepository.kt @@ -26,6 +26,7 @@ import foundation.e.apps.utils.enums.User import foundation.e.apps.utils.exceptions.GPlayLoginException import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.withTimeout +import java.util.Locale /** * Call methods of [GoogleLoginApi] and [AnonymousLoginApi] from here. @@ -50,11 +51,12 @@ class LoginApiRepository constructor( * @param aasToken For Google login - Access token obtained from [getAasToken] function, * else blank for Anonymous login. */ - suspend fun fetchAuthData(email: String, aasToken: String): ResultSupreme { + suspend fun fetchAuthData(email: String, aasToken: String, locale: Locale): ResultSupreme { val result = runCodeBlockWithTimeout({ gPlayLoginInterface.fetchAuthData(email, aasToken) }) return result.apply { + this.data?.locale = locale this.exception = when (result) { is ResultSupreme.Timeout -> GPlayLoginException(true, "GPlay API timeout", user) is ResultSupreme.Error -> GPlayLoginException(false, result.message, user) @@ -143,7 +145,7 @@ class LoginApiRepository constructor( private suspend fun runCodeBlockWithTimeout( block: suspend () -> T, timeoutBlock: (() -> T?)? = null, - exceptionBlock: (() -> T?)? = null, + exceptionBlock: ((e: Exception) -> T?)? = null, ): ResultSupreme { return try { withTimeout(timeoutDurationInMillis) { @@ -155,7 +157,7 @@ class LoginApiRepository constructor( } } catch (e: Exception) { e.printStackTrace() - ResultSupreme.Error(exceptionBlock?.invoke(), message = e.message ?: "") + ResultSupreme.Error(exceptionBlock?.invoke(e), message = e.message ?: "") } } } diff --git a/app/src/main/java/foundation/e/apps/search/SearchViewModel.kt b/app/src/main/java/foundation/e/apps/search/SearchViewModel.kt index 02c10cca4bbd8586417826ce71319c9e82644fba..aa0f9697ec08812597453ce9af00d7fdf3afdbe3 100644 --- a/app/src/main/java/foundation/e/apps/search/SearchViewModel.kt +++ b/app/src/main/java/foundation/e/apps/search/SearchViewModel.kt @@ -88,8 +88,16 @@ class SearchViewModel @Inject constructor( if (!it.isSuccess()) { val exception = if (authData.aasToken.isNotBlank() || authData.authToken.isNotBlank()) { - GPlayException(it.isTimeout(), "Data load error") - } else CleanApkException(it.isTimeout(), "Data load error") + GPlayException( + it.isTimeout(), + it.message.ifBlank { "Data load error" } + ) + } else { + CleanApkException( + it.isTimeout(), + it.message.ifBlank { "Data load error" } + ) + } exceptionsList.add(exception) exceptionsLiveData.postValue(exceptionsList) diff --git a/app/src/main/java/foundation/e/apps/updates/UpdatesFragment.kt b/app/src/main/java/foundation/e/apps/updates/UpdatesFragment.kt index bead0da2133bf024dddee3edaa23063c1e149d5c..7c18659934ae3107e97c89b763cf3f5a9596e596 100644 --- a/app/src/main/java/foundation/e/apps/updates/UpdatesFragment.kt +++ b/app/src/main/java/foundation/e/apps/updates/UpdatesFragment.kt @@ -39,24 +39,23 @@ import foundation.e.apps.MainActivityViewModel import foundation.e.apps.PrivacyInfoViewModel import foundation.e.apps.R import foundation.e.apps.api.ResultSupreme -import foundation.e.apps.api.fused.FusedAPIImpl import foundation.e.apps.api.fused.FusedAPIInterface import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.application.subFrags.ApplicationDialogFragment import foundation.e.apps.applicationlist.ApplicationListRVAdapter import foundation.e.apps.databinding.FragmentUpdatesBinding -import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.login.AuthObject +import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.download.data.DownloadProgress import foundation.e.apps.manager.pkg.PkgManagerModule import foundation.e.apps.manager.workmanager.InstallWorkManager.INSTALL_WORK_NAME import foundation.e.apps.updates.manager.UpdatesWorkManager import foundation.e.apps.utils.enums.ResultStatus import foundation.e.apps.utils.enums.Status -import foundation.e.apps.utils.exceptions.GPlayException -import foundation.e.apps.utils.exceptions.GPlayLoginException import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus +import foundation.e.apps.utils.exceptions.GPlayException +import foundation.e.apps.utils.exceptions.GPlayLoginException import foundation.e.apps.utils.modules.CommonUtilsModule.safeNavigate import foundation.e.apps.utils.modules.PWAManagerModule import foundation.e.apps.utils.parentFragment.TimeoutFragment diff --git a/app/src/main/java/foundation/e/apps/updates/UpdatesViewModel.kt b/app/src/main/java/foundation/e/apps/updates/UpdatesViewModel.kt index 9be088227179babdc3f04b51deb2d5fbd788cbe0..0b546decadb7696bd494dfc514148e13f53d49a0 100644 --- a/app/src/main/java/foundation/e/apps/updates/UpdatesViewModel.kt +++ b/app/src/main/java/foundation/e/apps/updates/UpdatesViewModel.kt @@ -68,18 +68,20 @@ class UpdatesViewModel @Inject constructor( else updatesManagerRepository.getUpdatesOSS() updatesList.postValue(updatesResult) - if (updatesResult.second != ResultStatus.OK) { + val status = updatesResult.second + + if (status != ResultStatus.OK) { val exception = if (authData != null && (authData.aasToken.isNotBlank() || authData.authToken.isNotBlank()) ) { GPlayException( updatesResult.second == ResultStatus.TIMEOUT, - "Data load error" + status.message.ifBlank { "Data load error" } ) } else CleanApkException( updatesResult.second == ResultStatus.TIMEOUT, - "Data load error" + status.message.ifBlank { "Data load error" } ) exceptionsList.add(exception) diff --git a/app/src/main/java/foundation/e/apps/updates/manager/UpdatesWorker.kt b/app/src/main/java/foundation/e/apps/updates/manager/UpdatesWorker.kt index 0b29b17fcb00b52a217b85a67e427a1041d99a51..c9c1076d3a29a583971d31d52e404032fa6c09eb 100644 --- a/app/src/main/java/foundation/e/apps/updates/manager/UpdatesWorker.kt +++ b/app/src/main/java/foundation/e/apps/updates/manager/UpdatesWorker.kt @@ -28,12 +28,11 @@ import foundation.e.apps.updates.UpdatesNotifier import foundation.e.apps.utils.enums.Origin import foundation.e.apps.utils.enums.ResultStatus import foundation.e.apps.utils.enums.Type +import foundation.e.apps.utils.enums.User import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus import foundation.e.apps.utils.modules.DataStoreManager import kotlinx.coroutines.delay -import foundation.e.apps.utils.enums.User -import foundation.e.apps.utils.modules.DataStoreModule import timber.log.Timber import java.io.ByteArrayOutputStream import java.net.URL diff --git a/app/src/main/java/foundation/e/apps/utils/enums/ResultStatus.kt b/app/src/main/java/foundation/e/apps/utils/enums/ResultStatus.kt index c98415ef7aa38b9649f2fe2956b579f7df1ce7c0..e13350a3f3bc6050e1697a191fd8e58a9a44b026 100644 --- a/app/src/main/java/foundation/e/apps/utils/enums/ResultStatus.kt +++ b/app/src/main/java/foundation/e/apps/utils/enums/ResultStatus.kt @@ -4,5 +4,8 @@ enum class ResultStatus { OK, TIMEOUT, UNKNOWN, - RETRY + RETRY, + ; + + var message: String = "" } diff --git a/app/src/main/res/layout/dialog_error_log.xml b/app/src/main/res/layout/dialog_error_log.xml index a7e51a73165f0d850c6019d06568c51af7cbc77c..e4005d62888edd5e2ee3382524d7df09a06239df 100644 --- a/app/src/main/res/layout/dialog_error_log.xml +++ b/app/src/main/res/layout/dialog_error_log.xml @@ -37,16 +37,23 @@ android:visibility="gone" /> - + android:layout_height="wrap_content"> + + + + \ No newline at end of file