diff --git a/app/src/main/java/com/itsaky/androidide/activities/OnboardingActivity.kt b/app/src/main/java/com/itsaky/androidide/activities/OnboardingActivity.kt index 770299bcab..d62d73046a 100644 --- a/app/src/main/java/com/itsaky/androidide/activities/OnboardingActivity.kt +++ b/app/src/main/java/com/itsaky/androidide/activities/OnboardingActivity.kt @@ -249,10 +249,14 @@ class OnboardingActivity : AppIntro2() { checkToolsIsInstalled() && PermissionsHelper.areAllPermissionsGranted(this) + internal fun navigateToMain() { + startActivity(Intent(this, MainActivity::class.java)) + finish() + } + internal fun tryNavigateToMainIfSetupIsCompleted(): Boolean { if (isSetupCompleted()) { - startActivity(Intent(this, MainActivity::class.java)) - finish() + navigateToMain() return true } diff --git a/app/src/main/java/com/itsaky/androidide/fragments/onboarding/PermissionsFragment.kt b/app/src/main/java/com/itsaky/androidide/fragments/onboarding/PermissionsFragment.kt index 271c6c14a1..9319c6cfd4 100644 --- a/app/src/main/java/com/itsaky/androidide/fragments/onboarding/PermissionsFragment.kt +++ b/app/src/main/java/com/itsaky/androidide/fragments/onboarding/PermissionsFragment.kt @@ -233,17 +233,17 @@ class PermissionsFragment : } private fun startIdeSetup() { - val shouldProceed = viewModel.checkStorageAndNotify(requireContext()) - if (!shouldProceed) { - return - } + viewLifecycleScope.launch { + val shouldProceed = viewModel.checkStorageAndNotify(requireContext()) + if (!shouldProceed) { + return@launch + } - if (viewModel.isSetupComplete()) { - (activity as? OnboardingActivity)?.tryNavigateToMainIfSetupIsCompleted() - return - } + if (viewModel.isSetupCompleteAsync()) { + (activity as? OnboardingActivity)?.navigateToMain() + return@launch + } - viewLifecycleScope.launch { doAsyncWithProgress( Dispatchers.IO, configureFlashbar = { builder, _ -> @@ -265,7 +265,7 @@ class PermissionsFragment : when (state) { is InstallationState.InstallationComplete -> { withContext(Dispatchers.Main) { - (activity as? OnboardingActivity)?.tryNavigateToMainIfSetupIsCompleted() + (activity as? OnboardingActivity)?.navigateToMain() } true } diff --git a/app/src/main/java/com/itsaky/androidide/localWebServer/WebServer.kt b/app/src/main/java/com/itsaky/androidide/localWebServer/WebServer.kt index 4743433ed7..b0f9a1d149 100644 --- a/app/src/main/java/com/itsaky/androidide/localWebServer/WebServer.kt +++ b/app/src/main/java/com/itsaky/androidide/localWebServer/WebServer.kt @@ -8,6 +8,7 @@ import java.io.ByteArrayOutputStream import java.io.File import java.io.InputStream import java.io.PrintWriter +import android.net.TrafficStats import java.net.InetSocketAddress import java.net.ServerSocket import java.net.Socket @@ -110,6 +111,7 @@ FROM LastChange } fun start() { + TrafficStats.setThreadStatsTag(0xC0DE) try { log.info( "Starting WebServer on {}, port {}, debugEnabled={}, debugEnablePath='{}', debugDatabasePath='{}', experimentsEnabled={}, experimentsEnablePath='{}'.", @@ -220,6 +222,7 @@ clientSocket and the catch block logic are updated accordingly. if (::serverSocket.isInitialized) { serverSocket.close() } + TrafficStats.clearThreadStatsTag() } } diff --git a/app/src/main/java/com/itsaky/androidide/viewmodel/InstallationViewModel.kt b/app/src/main/java/com/itsaky/androidide/viewmodel/InstallationViewModel.kt index 95c1f7e714..2da418b61e 100644 --- a/app/src/main/java/com/itsaky/androidide/viewmodel/InstallationViewModel.kt +++ b/app/src/main/java/com/itsaky/androidide/viewmodel/InstallationViewModel.kt @@ -60,71 +60,69 @@ class InstallationViewModel : ViewModel() { return } - if (!checkStorageAndNotify(context)) { - return - } - if (!checkToolsIsInstalled()) { - viewModelScope.launch { - try { - _state.update { Installing() } - - withContext(Dispatchers.IO) { - val result = - withStopWatch("Assets installation") { - AssetsInstallationHelper.install(context) { progress -> - log.debug("Assets installation progress: {}", progress.message) - _installationProgress.value = progress.message - } + viewModelScope.launch { + if (!checkStorageAndNotify(context)) { + return@launch + } + if (withContext(Dispatchers.IO) { checkToolsIsInstalled() }) { + // Tools already installed + _state.update { InstallationComplete } + return@launch + } + try { + _state.update { Installing() } + + withContext(Dispatchers.IO) { + val result = + withStopWatch("Assets installation") { + AssetsInstallationHelper.install(context) { progress -> + log.debug("Assets installation progress: {}", progress.message) + _installationProgress.value = progress.message } + } - log.info("Assets installation result: {}", result) + log.info("Assets installation result: {}", result) - when (result) { - is AssetsInstallationHelper.Result.Success -> { - val distributionProvider = IJdkDistributionProvider.getInstance() - distributionProvider.loadDistributions() + when (result) { + is AssetsInstallationHelper.Result.Success -> { + val distributionProvider = IJdkDistributionProvider.getInstance() + distributionProvider.loadDistributions() - _state.update { InstallationComplete } + _state.update { InstallationComplete } + } + is AssetsInstallationHelper.Result.Failure -> { + if (result.shouldReportToSentry) { + result.cause?.let { Sentry.captureException(it) } } - is AssetsInstallationHelper.Result.Failure -> { - if (result.shouldReportToSentry) { - result.cause?.let { Sentry.captureException(it) } - } - val errorMsg = result.errorMessage - ?: context.getString(R.string.title_installation_failed) - viewModelScope.launch { - _events.emit(InstallationEvent.ShowError(errorMsg)) - } - _state.update { - InstallationError(errorMsg) - } + val errorMsg = result.errorMessage + ?: context.getString(R.string.title_installation_failed) + _events.emit(InstallationEvent.ShowError(errorMsg)) + _state.update { + InstallationError(errorMsg) } } } - } catch (e: Exception) { - if (e is CancellationException) { - _state.update { InstallationPending } - throw e - } - Sentry.captureException(e) - log.error("IDE setup installation failed", e) - val errorMsg = e.message ?: context.getString(R.string.unknown_error) - viewModelScope.launch { - _events.emit(InstallationEvent.ShowError(errorMsg)) - } - _state.update { - InstallationError(errorMsg) - } + } + } catch (e: Exception) { + if (e is CancellationException) { + _state.update { InstallationPending } + throw e + } + Sentry.captureException(e) + log.error("IDE setup installation failed", e) + val errorMsg = e.message ?: context.getString(R.string.unknown_error) + _events.emit(InstallationEvent.ShowError(errorMsg)) + _state.update { + InstallationError(errorMsg) } } - } else { - // Tools already installed - _state.update { InstallationComplete } } } fun isSetupComplete(): Boolean = checkToolsIsInstalled() + suspend fun isSetupCompleteAsync(): Boolean = withContext(Dispatchers.IO) { checkToolsIsInstalled() } + private fun checkToolsIsInstalled(): Boolean = IJdkDistributionProvider.getInstance().installedDistributions.isNotEmpty() && Environment.ANDROID_HOME.exists() @@ -147,7 +145,7 @@ class InstallationViewModel : ViewModel() { return StorageInfo(isLowStorage, availableStorageInBytes, additionalBytesNeeded) } - fun checkStorageAndNotify(context: Context): Boolean { + suspend fun checkStorageAndNotify(context: Context): Boolean = withContext(Dispatchers.IO) { val storageInfo = getStorageInfo(context) if (storageInfo.isLowStorage) { @@ -160,13 +158,11 @@ class InstallationViewModel : ViewModel() { availableGB ) - viewModelScope.launch { - _events.emit(InstallationEvent.ShowError(errorMessage)) - } - return false + _events.emit(InstallationEvent.ShowError(errorMessage)) + return@withContext false } - return true + return@withContext true } }