Loading app/src/main/java/foundation/e/apps/data/fused/FusedAPIRepository.kt +1 −1 Original line number Diff line number Diff line Loading @@ -118,7 +118,7 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedApi) suspend fun getGplaySearchResults( query: String, nextPageSubBundle: Set<SearchBundle.SubBundle>? ): Pair<List<FusedApp>, Set<SearchBundle.SubBundle>> { ): GplaySearchResult { return fusedAPIImpl.getGplaySearchResult(query, nextPageSubBundle) } Loading app/src/main/java/foundation/e/apps/data/fused/FusedApi.kt +3 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ import foundation.e.apps.data.fused.utils.CategoryType import foundation.e.apps.data.fusedDownload.models.FusedDownload import retrofit2.Response typealias GplaySearchResult = ResultSupreme<Pair<List<FusedApp>, Set<SearchBundle.SubBundle>>> interface FusedApi { companion object { const val APP_TYPE_ANY = "any" Loading Loading @@ -68,7 +70,7 @@ interface FusedApi { suspend fun getGplaySearchResult( query: String, nextPageSubBundle: Set<SearchBundle.SubBundle>? ): Pair<List<FusedApp>, Set<SearchBundle.SubBundle>> ): GplaySearchResult suspend fun getSearchSuggestions(query: String): List<SearchSuggestEntry> Loading app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt +954 −939 Original line number Diff line number Diff line Loading @@ -64,11 +64,15 @@ import foundation.e.apps.data.fused.utils.CategoryType import foundation.e.apps.data.fused.utils.CategoryUtils import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.gplay.GplayStoreRepository import foundation.e.apps.data.gplay.utils.GplayHttpRequestException import foundation.e.apps.data.gplay.utils.runFlowWithTimeout import foundation.e.apps.data.login.exceptions.GPlayException import foundation.e.apps.data.login.exceptions.UnknownSourceException import foundation.e.apps.data.preference.PreferenceManagerModule import foundation.e.apps.install.pkg.PWAManagerModule import foundation.e.apps.install.pkg.PkgManagerModule import foundation.e.apps.ui.home.model.HomeChildFusedAppDiffUtil import foundation.e.apps.ui.search.SearchViewModel import kotlinx.coroutines.Deferred import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.async Loading @@ -78,11 +82,11 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.withTimeout import retrofit2.Response import timber.log.Timber import java.net.SocketTimeoutException import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton typealias GplaySearchResultFlow = Flow<ResultSupreme<Pair<List<FusedApp>, Boolean>>> typealias FusedHomeDeferred = Deferred<ResultSupreme<List<FusedHome>>> @Singleton Loading @@ -101,6 +105,8 @@ class FusedApiImpl @Inject constructor( private const val CATEGORY_TITLE_REPLACEABLE_CONJUNCTION = "&" private const val CATEGORY_OPEN_GAMES_ID = "game_open_games" private const val CATEGORY_OPEN_GAMES_TITLE = "Open games" private const val ERROR_GPLAY_SEARCH = "Gplay search is failed!" private const val ERROR_GPLAY_SOURCE_NOT_SELECTED = "Gplay apps are not selected!" } /** Loading Loading @@ -1103,22 +1109,31 @@ private suspend fun getCleanAPKSearchResults( override suspend fun getGplaySearchResult( query: String, nextPageSubBundle: Set<SearchBundle.SubBundle>? ): Pair<List<FusedApp>, Set<SearchBundle.SubBundle>> { ): GplaySearchResult { try { val searchResults = gplayRepository.getSearchResult(query, nextPageSubBundle?.toMutableSet()) if (!preferenceManagerModule.isGplaySelected()) { return Pair(emptyList(), emptySet()) return ResultSupreme.Error(ERROR_GPLAY_SOURCE_NOT_SELECTED) } val fusedAppList = searchResults.first.map { app -> replaceWithFDroid(app) }.toMutableList() val fusedAppList = searchResults.first.map { app -> replaceWithFDroid(app) }.toMutableList() if (searchResults.second.isNotEmpty()) { fusedAppList.add(FusedApp(isPlaceHolder = true)) } return Pair( fusedAppList, searchResults.second ) return ResultSupreme.Success(Pair(fusedAppList.toList(), searchResults.second.toSet())) } catch (e: GplayHttpRequestException) { val message = e.localizedMessage?.ifBlank { ERROR_GPLAY_SEARCH } ?: ERROR_GPLAY_SEARCH val exception = GPlayException(e.status == 408, message) return ResultSupreme.Error(message, exception) } catch (e: Exception) { val exception = GPlayException(e is SocketTimeoutException, e.localizedMessage) return ResultSupreme.Error(e.localizedMessage, exception) } } /* Loading app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt +19 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import timber.log.Timber import java.io.IOException import java.net.SocketTimeoutException import java.net.UnknownHostException import java.util.concurrent.TimeUnit import javax.inject.Inject class GPlayHttpClient @Inject constructor( Loading @@ -52,10 +53,12 @@ class GPlayHttpClient @Inject constructor( companion object { private const val TAG = "GPlayHttpClient" private const val HTTP_TIMEOUT_IN_SECOND = 10L } private val okHttpClient = OkHttpClient().newBuilder() .retryOnConnectionFailure(false) .callTimeout(HTTP_TIMEOUT_IN_SECOND, TimeUnit.SECONDS) .followRedirects(true) .followSslRedirects(true) .cache(cache) Loading Loading @@ -155,6 +158,13 @@ class GPlayHttpClient @Inject constructor( val call = okHttpClient.newCall(request) buildPlayResponse(call.execute()) } catch (e: Exception) { //TODO: exception will be thrown for all apis when all gplay api implementation // will handle the exceptions. this will be done in following issue. // Issue: https://gitlab.e.foundation/e/os/backlog/-/issues/1483 if (request.url.toString().contains("search")) { throw e } when (e) { is UnknownHostException, is SocketTimeoutException -> handleExceptionOnGooglePlayRequest(e) Loading Loading @@ -185,6 +195,13 @@ class GPlayHttpClient @Inject constructor( Timber.d("$TAG: Url: ${response.request.url}\nStatus: $code") //TODO: exception will be thrown for all apis when all gplay api implementation // will handle the exceptions. this will be done in following issue. // Issue: https://gitlab.e.foundation/e/os/backlog/-/issues/1483 if (response.request.url.toString().contains("search") && code != 200) { throw GplayHttpRequestException(code, response.message) } if (code == 401) { MainScope().launch { EventBus.invokeEvent( Loading @@ -203,3 +220,5 @@ class GPlayHttpClient @Inject constructor( } } } class GplayHttpRequestException (val status: Int, message: String) : Exception(message) No newline at end of file app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt +2 −17 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import foundation.e.apps.install.updates.UpdatesNotifier import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus import foundation.e.apps.utils.getFormattedString import foundation.e.apps.utils.isNetworkAvailable import kotlinx.coroutines.flow.transformWhile import timber.log.Timber import java.text.NumberFormat Loading Loading @@ -122,7 +123,7 @@ class AppInstallProcessor @Inject constructor( return } if (!isNetworkAvailable()) { if (!context.isNetworkAvailable()) { fusedManagerRepository.installationIssue(fusedDownload) EventBus.invokeEvent(AppEvent.NoInternetEvent(false)) return Loading Loading @@ -185,22 +186,6 @@ class AppInstallProcessor @Inject constructor( return statFs.availableBytes } private fun isNetworkAvailable(): Boolean { val connectivityManager = context.getSystemService(ConnectivityManager::class.java) val capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork) ?: return false if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) ) { return true } return false } suspend fun processInstall( fusedDownloadId: String, isItUpdateWork: Boolean, Loading Loading
app/src/main/java/foundation/e/apps/data/fused/FusedAPIRepository.kt +1 −1 Original line number Diff line number Diff line Loading @@ -118,7 +118,7 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedApi) suspend fun getGplaySearchResults( query: String, nextPageSubBundle: Set<SearchBundle.SubBundle>? ): Pair<List<FusedApp>, Set<SearchBundle.SubBundle>> { ): GplaySearchResult { return fusedAPIImpl.getGplaySearchResult(query, nextPageSubBundle) } Loading
app/src/main/java/foundation/e/apps/data/fused/FusedApi.kt +3 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ import foundation.e.apps.data.fused.utils.CategoryType import foundation.e.apps.data.fusedDownload.models.FusedDownload import retrofit2.Response typealias GplaySearchResult = ResultSupreme<Pair<List<FusedApp>, Set<SearchBundle.SubBundle>>> interface FusedApi { companion object { const val APP_TYPE_ANY = "any" Loading Loading @@ -68,7 +70,7 @@ interface FusedApi { suspend fun getGplaySearchResult( query: String, nextPageSubBundle: Set<SearchBundle.SubBundle>? ): Pair<List<FusedApp>, Set<SearchBundle.SubBundle>> ): GplaySearchResult suspend fun getSearchSuggestions(query: String): List<SearchSuggestEntry> Loading
app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt +954 −939 Original line number Diff line number Diff line Loading @@ -64,11 +64,15 @@ import foundation.e.apps.data.fused.utils.CategoryType import foundation.e.apps.data.fused.utils.CategoryUtils import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.gplay.GplayStoreRepository import foundation.e.apps.data.gplay.utils.GplayHttpRequestException import foundation.e.apps.data.gplay.utils.runFlowWithTimeout import foundation.e.apps.data.login.exceptions.GPlayException import foundation.e.apps.data.login.exceptions.UnknownSourceException import foundation.e.apps.data.preference.PreferenceManagerModule import foundation.e.apps.install.pkg.PWAManagerModule import foundation.e.apps.install.pkg.PkgManagerModule import foundation.e.apps.ui.home.model.HomeChildFusedAppDiffUtil import foundation.e.apps.ui.search.SearchViewModel import kotlinx.coroutines.Deferred import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.async Loading @@ -78,11 +82,11 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.withTimeout import retrofit2.Response import timber.log.Timber import java.net.SocketTimeoutException import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton typealias GplaySearchResultFlow = Flow<ResultSupreme<Pair<List<FusedApp>, Boolean>>> typealias FusedHomeDeferred = Deferred<ResultSupreme<List<FusedHome>>> @Singleton Loading @@ -101,6 +105,8 @@ class FusedApiImpl @Inject constructor( private const val CATEGORY_TITLE_REPLACEABLE_CONJUNCTION = "&" private const val CATEGORY_OPEN_GAMES_ID = "game_open_games" private const val CATEGORY_OPEN_GAMES_TITLE = "Open games" private const val ERROR_GPLAY_SEARCH = "Gplay search is failed!" private const val ERROR_GPLAY_SOURCE_NOT_SELECTED = "Gplay apps are not selected!" } /** Loading Loading @@ -1103,22 +1109,31 @@ private suspend fun getCleanAPKSearchResults( override suspend fun getGplaySearchResult( query: String, nextPageSubBundle: Set<SearchBundle.SubBundle>? ): Pair<List<FusedApp>, Set<SearchBundle.SubBundle>> { ): GplaySearchResult { try { val searchResults = gplayRepository.getSearchResult(query, nextPageSubBundle?.toMutableSet()) if (!preferenceManagerModule.isGplaySelected()) { return Pair(emptyList(), emptySet()) return ResultSupreme.Error(ERROR_GPLAY_SOURCE_NOT_SELECTED) } val fusedAppList = searchResults.first.map { app -> replaceWithFDroid(app) }.toMutableList() val fusedAppList = searchResults.first.map { app -> replaceWithFDroid(app) }.toMutableList() if (searchResults.second.isNotEmpty()) { fusedAppList.add(FusedApp(isPlaceHolder = true)) } return Pair( fusedAppList, searchResults.second ) return ResultSupreme.Success(Pair(fusedAppList.toList(), searchResults.second.toSet())) } catch (e: GplayHttpRequestException) { val message = e.localizedMessage?.ifBlank { ERROR_GPLAY_SEARCH } ?: ERROR_GPLAY_SEARCH val exception = GPlayException(e.status == 408, message) return ResultSupreme.Error(message, exception) } catch (e: Exception) { val exception = GPlayException(e is SocketTimeoutException, e.localizedMessage) return ResultSupreme.Error(e.localizedMessage, exception) } } /* Loading
app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt +19 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import timber.log.Timber import java.io.IOException import java.net.SocketTimeoutException import java.net.UnknownHostException import java.util.concurrent.TimeUnit import javax.inject.Inject class GPlayHttpClient @Inject constructor( Loading @@ -52,10 +53,12 @@ class GPlayHttpClient @Inject constructor( companion object { private const val TAG = "GPlayHttpClient" private const val HTTP_TIMEOUT_IN_SECOND = 10L } private val okHttpClient = OkHttpClient().newBuilder() .retryOnConnectionFailure(false) .callTimeout(HTTP_TIMEOUT_IN_SECOND, TimeUnit.SECONDS) .followRedirects(true) .followSslRedirects(true) .cache(cache) Loading Loading @@ -155,6 +158,13 @@ class GPlayHttpClient @Inject constructor( val call = okHttpClient.newCall(request) buildPlayResponse(call.execute()) } catch (e: Exception) { //TODO: exception will be thrown for all apis when all gplay api implementation // will handle the exceptions. this will be done in following issue. // Issue: https://gitlab.e.foundation/e/os/backlog/-/issues/1483 if (request.url.toString().contains("search")) { throw e } when (e) { is UnknownHostException, is SocketTimeoutException -> handleExceptionOnGooglePlayRequest(e) Loading Loading @@ -185,6 +195,13 @@ class GPlayHttpClient @Inject constructor( Timber.d("$TAG: Url: ${response.request.url}\nStatus: $code") //TODO: exception will be thrown for all apis when all gplay api implementation // will handle the exceptions. this will be done in following issue. // Issue: https://gitlab.e.foundation/e/os/backlog/-/issues/1483 if (response.request.url.toString().contains("search") && code != 200) { throw GplayHttpRequestException(code, response.message) } if (code == 401) { MainScope().launch { EventBus.invokeEvent( Loading @@ -203,3 +220,5 @@ class GPlayHttpClient @Inject constructor( } } } class GplayHttpRequestException (val status: Int, message: String) : Exception(message) No newline at end of file
app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt +2 −17 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import foundation.e.apps.install.updates.UpdatesNotifier import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus import foundation.e.apps.utils.getFormattedString import foundation.e.apps.utils.isNetworkAvailable import kotlinx.coroutines.flow.transformWhile import timber.log.Timber import java.text.NumberFormat Loading Loading @@ -122,7 +123,7 @@ class AppInstallProcessor @Inject constructor( return } if (!isNetworkAvailable()) { if (!context.isNetworkAvailable()) { fusedManagerRepository.installationIssue(fusedDownload) EventBus.invokeEvent(AppEvent.NoInternetEvent(false)) return Loading Loading @@ -185,22 +186,6 @@ class AppInstallProcessor @Inject constructor( return statFs.availableBytes } private fun isNetworkAvailable(): Boolean { val connectivityManager = context.getSystemService(ConnectivityManager::class.java) val capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork) ?: return false if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) ) { return true } return false } suspend fun processInstall( fusedDownloadId: String, isItUpdateWork: Boolean, Loading