From d1fa2393d230e88a2535b011f7c0b94e66090526 Mon Sep 17 00:00:00 2001 From: Akash Yadav Date: Sat, 13 Jan 2024 19:58:13 +0530 Subject: [PATCH] fix: reload JDK distributions when returning from terminal to onboarding activity --- .../activities/OnboardingActivity.kt | 92 +++++++++++++---- .../JdkDistributionProviderImpl.kt | 13 ++- .../configuration/IJdkDistributionProvider.kt | 8 ++ .../androidide/managers/ToolsManager.java | 2 +- .../androidide/activities/TerminalActivity.kt | 6 ++ .../terminal/IdeTerminalSessionClient.kt | 45 +++++++++ .../java/com/termux/app/TermuxActivity.java | 99 +++++++++---------- .../TermuxTerminalSessionActivityClient.java | 2 +- 8 files changed, 193 insertions(+), 74 deletions(-) create mode 100644 termux/termux-app/src/main/java/com/itsaky/androidide/terminal/IdeTerminalSessionClient.kt 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 f7c4e37f6..b8942d363 100644 --- a/app/src/main/java/com/itsaky/androidide/activities/OnboardingActivity.kt +++ b/app/src/main/java/com/itsaky/androidide/activities/OnboardingActivity.kt @@ -19,6 +19,8 @@ package com.itsaky.androidide.activities import android.content.Intent import android.os.Bundle +import android.util.Log +import androidx.activity.result.contract.ActivityResultContracts import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import com.github.appintro.AppIntro2 @@ -32,18 +34,42 @@ import com.itsaky.androidide.fragments.onboarding.IdeSetupConfigurationFragment import com.itsaky.androidide.fragments.onboarding.OnboardingInfoFragment import com.itsaky.androidide.fragments.onboarding.PermissionsFragment import com.itsaky.androidide.fragments.onboarding.StatisticsFragment +import com.itsaky.androidide.models.JdkDistribution import com.itsaky.androidide.preferences.internal.prefManager import com.itsaky.androidide.preferences.internal.statConsentDialogShown +import com.itsaky.androidide.tasks.launchAsyncWithProgress import com.itsaky.androidide.ui.themes.IThemeManager import com.itsaky.androidide.utils.Environment import com.termux.shared.android.PackageUtils import com.termux.shared.markdown.MarkdownUtils import com.termux.shared.termux.TermuxConstants +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancel +import kotlinx.coroutines.withContext class OnboardingActivity : AppIntro2() { + private val terminalActivityCallback = registerForActivityResult( + ActivityResultContracts.StartActivityForResult()) { + Log.d(TAG, "TerminalActivity: resultCode=${it.resultCode}") + if (!isFinishing) { + reloadJdkDistInfo { + tryNavigateToMainIfSetupIsCompleted() + } + } + } + + private val activityScope = + CoroutineScope(Dispatchers.Main + CoroutineName("OnboardingActivity")) + + private var listJdkInstallationsJob: Job? = null + companion object { + private const val TAG = "OnboardingActivity" private const val KEY_ARCHCONFIG_WARNING_IS_SHOWN = "ide.archConfig.experimentalWarning.isShown" } @@ -52,9 +78,8 @@ class OnboardingActivity : AppIntro2() { super.onCreate(savedInstanceState) - if (isSetupDone()) { - openActivity(MainActivity::class.java) - finish() + if (tryNavigateToMainIfSetupIsCompleted()) { + return } setSwipeLock(true) @@ -110,12 +135,16 @@ class OnboardingActivity : AppIntro2() { override fun onResume() { super.onResume() - if (isSetupDone()) { - openActivity(MainActivity::class.java) - finish() + reloadJdkDistInfo { + tryNavigateToMainIfSetupIsCompleted() } } + override fun onDestroy() { + super.onDestroy() + activityScope.cancel("Activity is being destroyed") + } + override fun onNextPressed(currentFragment: Fragment?) { (currentFragment as? StatisticsFragment?)?.updateStatOptInStatus() } @@ -129,21 +158,17 @@ class OnboardingActivity : AppIntro2() { } if (!checkToolsIsInstalled() && currentFragment is IdeSetupConfigurationFragment) { - val intenet = Intent(this, TerminalActivity::class.java) + val intent = Intent(this, TerminalActivity::class.java) if (currentFragment.isAutoInstall()) { - intenet.putExtra(TerminalActivity.EXTRA_ONBOARDING_RUN_IDESETUP, true) - intenet.putExtra(TerminalActivity.EXTRA_ONBOARDING_RUN_IDESETUP_ARGS, + intent.putExtra(TerminalActivity.EXTRA_ONBOARDING_RUN_IDESETUP, true) + intent.putExtra(TerminalActivity.EXTRA_ONBOARDING_RUN_IDESETUP_ARGS, currentFragment.buildIdeSetupArguments()) } - startActivity(intenet) + terminalActivityCallback.launch(intent) return } - openActivity(MainActivity::class.java) - } - - private fun openActivity(cls: Class<*>) { - startActivity(Intent(this, cls)) + tryNavigateToMainIfSetupIsCompleted() } private fun checkToolsIsInstalled(): Boolean { @@ -151,9 +176,40 @@ class OnboardingActivity : AppIntro2() { && Environment.ANDROID_HOME.exists() } - private fun isSetupDone() = - (checkToolsIsInstalled() && statConsentDialogShown && PermissionsFragment.areAllPermissionsGranted( - this)) + private fun isSetupCompleted(): Boolean { + return checkToolsIsInstalled() + && statConsentDialogShown + && PermissionsFragment.areAllPermissionsGranted(this) + } + + private fun tryNavigateToMainIfSetupIsCompleted(): Boolean { + if (isSetupCompleted()) { + startActivity(Intent(this, MainActivity::class.java)) + finish() + return true + } + + return false + } + + private inline fun reloadJdkDistInfo(crossinline distConsumer: (List) -> Unit) { + listJdkInstallationsJob?.cancel("Reloading JDK distributions") + + listJdkInstallationsJob = activityScope.launchAsyncWithProgress(Dispatchers.Default, + configureFlashbar = { builder, _ -> + builder.message(string.please_wait) + }) { _, _ -> + val distributionProvider = IJdkDistributionProvider.getInstance() + distributionProvider.loadDistributions() + withContext(Dispatchers.Main) { + distConsumer(distributionProvider.installedDistributions) + } + }.also { + it?.invokeOnCompletion { + listJdkInstallationsJob = null + } + } + } private fun isInstalledOnSdCard(): Boolean { // noinspection SdCardPath diff --git a/app/src/main/java/com/itsaky/androidide/app/configuration/JdkDistributionProviderImpl.kt b/app/src/main/java/com/itsaky/androidide/app/configuration/JdkDistributionProviderImpl.kt index 4e67175d7..90aef32c5 100644 --- a/app/src/main/java/com/itsaky/androidide/app/configuration/JdkDistributionProviderImpl.kt +++ b/app/src/main/java/com/itsaky/androidide/app/configuration/JdkDistributionProviderImpl.kt @@ -36,8 +36,17 @@ class JdkDistributionProviderImpl : IJdkDistributionProvider { private val log = ILogger.newInstance("JdkDistributionProviderImpl") } - override val installedDistributions: List by lazy { - JdkUtils.findJavaInstallations().also { distributions -> + private var _installedDistributions: List? = null + + override val installedDistributions: List + get() = _installedDistributions ?: emptyList() + + override fun loadDistributions() { + _installedDistributions = doLoadDistributions() + } + + private fun doLoadDistributions(): List { + return JdkUtils.findJavaInstallations().also { distributions -> // set the default value for the 'javaHome' preference if (javaHome.isBlank() && distributions.isNotEmpty()) { diff --git a/common/src/main/java/com/itsaky/androidide/app/configuration/IJdkDistributionProvider.kt b/common/src/main/java/com/itsaky/androidide/app/configuration/IJdkDistributionProvider.kt index 07a285765..5aa03ff59 100644 --- a/common/src/main/java/com/itsaky/androidide/app/configuration/IJdkDistributionProvider.kt +++ b/common/src/main/java/com/itsaky/androidide/app/configuration/IJdkDistributionProvider.kt @@ -17,6 +17,7 @@ package com.itsaky.androidide.app.configuration +import androidx.annotation.WorkerThread import com.itsaky.androidide.models.JdkDistribution import com.itsaky.androidide.utils.ServiceLoader @@ -32,6 +33,13 @@ interface IJdkDistributionProvider { */ val installedDistributions: List + /** + * Reloads the installed JDK distributions. This function is synchronous and should not be called + * on the UI thread. + */ + @WorkerThread + fun loadDistributions() + /** * Get the [JdkDistribution] instance for the given java version. * diff --git a/common/src/main/java/com/itsaky/androidide/managers/ToolsManager.java b/common/src/main/java/com/itsaky/androidide/managers/ToolsManager.java index 81a0b0f73..8d25f0480 100755 --- a/common/src/main/java/com/itsaky/androidide/managers/ToolsManager.java +++ b/common/src/main/java/com/itsaky/androidide/managers/ToolsManager.java @@ -53,7 +53,7 @@ public class ToolsManager { CompletableFuture.runAsync(() -> { // Load installed JDK distributions - IJdkDistributionProvider.getInstance().getInstalledDistributions(); + IJdkDistributionProvider.getInstance().loadDistributions(); writeNoMediaFile(); extractAapt2(); diff --git a/termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt b/termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt index 15d8c81e6..04efd6d00 100644 --- a/termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt +++ b/termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt @@ -26,12 +26,14 @@ import android.view.View import android.widget.Button import androidx.core.content.ContextCompat import androidx.core.view.WindowCompat +import com.itsaky.androidide.terminal.IdeTerminalSessionClient import com.itsaky.androidide.terminal.IdesetupSession import com.itsaky.androidide.utils.Environment import com.itsaky.androidide.utils.ILogger import com.itsaky.androidide.utils.flashError import com.termux.R import com.termux.app.TermuxActivity +import com.termux.app.terminal.TermuxTerminalSessionActivityClient import com.termux.shared.termux.shell.command.runner.terminal.TermuxSession /** @@ -70,6 +72,10 @@ class TerminalActivity : TermuxActivity() { KEY_TERMINAL_CAN_ADD_SESSIONS, true) ?: true } + override fun onCreateTerminalSessionClient(): TermuxTerminalSessionActivityClient { + return IdeTerminalSessionClient(this) + } + override fun onSaveInstanceState(savedInstanceState: Bundle) { super.onSaveInstanceState(savedInstanceState) savedInstanceState.putBoolean(KEY_TERMINAL_CAN_ADD_SESSIONS, canAddNewSessions) diff --git a/termux/termux-app/src/main/java/com/itsaky/androidide/terminal/IdeTerminalSessionClient.kt b/termux/termux-app/src/main/java/com/itsaky/androidide/terminal/IdeTerminalSessionClient.kt new file mode 100644 index 000000000..df57c5593 --- /dev/null +++ b/termux/termux-app/src/main/java/com/itsaky/androidide/terminal/IdeTerminalSessionClient.kt @@ -0,0 +1,45 @@ +/* + * This file is part of AndroidIDE. + * + * AndroidIDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AndroidIDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AndroidIDE. If not, see . + */ + +package com.itsaky.androidide.terminal + +import com.itsaky.androidide.activities.TerminalActivity +import com.termux.app.terminal.TermuxTerminalSessionActivityClient +import com.termux.terminal.TerminalSession +import com.termux.terminal.TerminalSessionClient + +/** + * [TerminalSessionClient] delegate for AndroidIDE. + * + * @author Akash Yadav + */ +class IdeTerminalSessionClient( + activity: TerminalActivity +) : TermuxTerminalSessionActivityClient(activity) { + + override fun onSessionFinished(finishedSession: TerminalSession) { + val termuxSession = mActivity?.termuxService?.getTermuxSessionForTerminalSession( + finishedSession) + if (termuxSession != null && termuxSession is IdesetupSession) { + // if the finished session was performing tools installation + // then set the result code for the installation process + mActivity.setResult(finishedSession.exitStatus) + } + + super.onSessionFinished(finishedSession) + } +} \ No newline at end of file diff --git a/termux/termux-app/src/main/java/com/termux/app/TermuxActivity.java b/termux/termux-app/src/main/java/com/termux/app/TermuxActivity.java index de19e7303..044771ce9 100644 --- a/termux/termux-app/src/main/java/com/termux/app/TermuxActivity.java +++ b/termux/termux-app/src/main/java/com/termux/app/TermuxActivity.java @@ -2,14 +2,10 @@ package com.termux.app; import android.annotation.SuppressLint; import android.app.AlertDialog; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.ServiceConnection; -import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.IBinder; @@ -23,35 +19,36 @@ import android.view.ViewGroup; import android.view.WindowManager; import android.view.autofill.AutofillManager; import android.widget.EditText; -import android.widget.ImageButton; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.Toast; - +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.viewpager.widget.ViewPager; import com.itsaky.androidide.app.BaseIDEActivity; import com.termux.R; import com.termux.app.activities.HelpActivity; import com.termux.app.api.file.FileReceiverActivity; import com.termux.app.terminal.TermuxActivityRootView; +import com.termux.app.terminal.TermuxSessionsListViewController; import com.termux.app.terminal.TermuxTerminalSessionActivityClient; +import com.termux.app.terminal.TermuxTerminalViewClient; +import com.termux.app.terminal.io.TerminalToolbarViewPager; import com.termux.app.terminal.io.TermuxTerminalExtraKeys; import com.termux.shared.activities.ReportActivity; import com.termux.shared.activity.ActivityUtils; import com.termux.shared.activity.media.AppCompatActivityUtils; -import com.termux.shared.data.IntentUtils; import com.termux.shared.android.PermissionUtils; import com.termux.shared.data.DataUtils; -import com.termux.shared.termux.TermuxConstants; +import com.termux.shared.data.IntentUtils; +import com.termux.shared.logger.Logger; import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY; +import com.termux.shared.termux.TermuxUtils; import com.termux.shared.termux.crash.TermuxCrashUtils; -import com.termux.shared.termux.settings.preferences.TermuxAppSharedPreferences; -import com.termux.app.terminal.TermuxSessionsListViewController; -import com.termux.app.terminal.io.TerminalToolbarViewPager; -import com.termux.app.terminal.TermuxTerminalViewClient; import com.termux.shared.termux.extrakeys.ExtraKeysView; import com.termux.shared.termux.interact.TextInputDialogUtils; -import com.termux.shared.logger.Logger; -import com.termux.shared.termux.TermuxUtils; +import com.termux.shared.termux.settings.preferences.TermuxAppSharedPreferences; import com.termux.shared.termux.settings.properties.TermuxAppSharedProperties; import com.termux.shared.termux.shell.command.runner.terminal.TermuxSession; import com.termux.shared.termux.theme.TermuxThemeUtils; @@ -61,13 +58,6 @@ import com.termux.terminal.TerminalSession; import com.termux.terminal.TerminalSessionClient; import com.termux.view.TerminalView; import com.termux.view.TerminalViewClient; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; -import androidx.drawerlayout.widget.DrawerLayout; -import androidx.viewpager.widget.ViewPager; - import java.util.Arrays; import java.util.Objects; import java.util.Optional; @@ -89,107 +79,107 @@ public class TermuxActivity extends BaseIDEActivity implements ServiceConnection * {@link #bindService(Intent, ServiceConnection, int)}, and obtained and stored in * {@link #onServiceConnected(ComponentName, IBinder)}. */ - TermuxService mTermuxService; + protected TermuxService mTermuxService; /** * The {@link TerminalView} shown in {@link TermuxActivity} that displays the terminal. */ - TerminalView mTerminalView; + protected TerminalView mTerminalView; /** * The {@link TerminalViewClient} interface implementation to allow for communication between * {@link TerminalView} and {@link TermuxActivity}. */ - TermuxTerminalViewClient mTermuxTerminalViewClient; + protected TermuxTerminalViewClient mTermuxTerminalViewClient; /** * The {@link TerminalSessionClient} interface implementation to allow for communication between * {@link TerminalSession} and {@link TermuxActivity}. */ - TermuxTerminalSessionActivityClient mTermuxTerminalSessionActivityClient; + protected TermuxTerminalSessionActivityClient mTermuxTerminalSessionActivityClient; /** * Termux app shared preferences manager. */ - private TermuxAppSharedPreferences mPreferences; + protected TermuxAppSharedPreferences mPreferences; /** * Termux app SharedProperties loaded from termux.properties */ - private TermuxAppSharedProperties mProperties; + protected TermuxAppSharedProperties mProperties; /** * The root view of the {@link TermuxActivity}. */ - TermuxActivityRootView mTermuxActivityRootView; + protected TermuxActivityRootView mTermuxActivityRootView; /** * The space at the bottom of {@link @mTermuxActivityRootView} of the {@link TermuxActivity}. */ - View mTermuxActivityBottomSpaceView; + protected View mTermuxActivityBottomSpaceView; /** * The terminal extra keys view. */ - ExtraKeysView mExtraKeysView; + protected ExtraKeysView mExtraKeysView; /** * The client for the {@link #mExtraKeysView}. */ - TermuxTerminalExtraKeys mTermuxTerminalExtraKeys; + protected TermuxTerminalExtraKeys mTermuxTerminalExtraKeys; /** * The termux sessions list controller. */ - TermuxSessionsListViewController mTermuxSessionListViewController; + protected TermuxSessionsListViewController mTermuxSessionListViewController; /** * The last toast shown, used cancel current toast before showing new in {@link #showToast(String, boolean)}. */ - Toast mLastToast; + protected Toast mLastToast; /** * If between onResume() and onStop(). Note that only one session is in the foreground of the terminal view at the * time, so if the session causing a change is not in the foreground it should probably be treated as background. */ - private boolean mIsVisible; + protected boolean mIsVisible; /** * If onResume() was called after onCreate(). */ - private boolean mIsOnResumeAfterOnCreate = false; + protected boolean mIsOnResumeAfterOnCreate = false; /** * If activity was restarted like due to call to {@link #recreate()} after receiving * {@link TERMUX_ACTIVITY#ACTION_RELOAD_STYLE}, system dark night mode was changed or activity * was killed by android. */ - private boolean mIsActivityRecreated = false; + protected boolean mIsActivityRecreated = false; /** * The {@link TermuxActivity} is in an invalid state and must not be run. */ - private boolean mIsInvalidState; + protected boolean mIsInvalidState; - private int mNavBarHeight; + protected int mNavBarHeight; - private float mTerminalToolbarDefaultHeight; + protected float mTerminalToolbarDefaultHeight; - private static final int CONTEXT_MENU_SELECT_URL_ID = 0; - private static final int CONTEXT_MENU_SHARE_TRANSCRIPT_ID = 1; - private static final int CONTEXT_MENU_SHARE_SELECTED_TEXT = 10; - private static final int CONTEXT_MENU_AUTOFILL_ID = 2; - private static final int CONTEXT_MENU_RESET_TERMINAL_ID = 3; - private static final int CONTEXT_MENU_KILL_PROCESS_ID = 4; - private static final int CONTEXT_MENU_TOGGLE_KEEP_SCREEN_ON = 6; - private static final int CONTEXT_MENU_HELP_ID = 7; - private static final int CONTEXT_MENU_REPORT_ID = 9; + protected static final int CONTEXT_MENU_SELECT_URL_ID = 0; + protected static final int CONTEXT_MENU_SHARE_TRANSCRIPT_ID = 1; + protected static final int CONTEXT_MENU_SHARE_SELECTED_TEXT = 10; + protected static final int CONTEXT_MENU_AUTOFILL_ID = 2; + protected static final int CONTEXT_MENU_RESET_TERMINAL_ID = 3; + protected static final int CONTEXT_MENU_KILL_PROCESS_ID = 4; + protected static final int CONTEXT_MENU_TOGGLE_KEEP_SCREEN_ON = 6; + protected static final int CONTEXT_MENU_HELP_ID = 7; + protected static final int CONTEXT_MENU_REPORT_ID = 9; - private static final String ARG_TERMINAL_TOOLBAR_TEXT_INPUT = "terminal_toolbar_text_input"; - private static final String ARG_ACTIVITY_RECREATED = "activity_recreated"; + protected static final String ARG_TERMINAL_TOOLBAR_TEXT_INPUT = "terminal_toolbar_text_input"; + protected static final String ARG_ACTIVITY_RECREATED = "activity_recreated"; - private static final String LOG_TAG = "TermuxActivity"; + protected static final String LOG_TAG = "TermuxActivity"; @SuppressLint("InflateParams") @NonNull @@ -540,7 +530,7 @@ public class TermuxActivity extends BaseIDEActivity implements ServiceConnection private void setTermuxTerminalViewAndClients() { // Set termux terminal view and session clients - mTermuxTerminalSessionActivityClient = new TermuxTerminalSessionActivityClient(this); + mTermuxTerminalSessionActivityClient = onCreateTerminalSessionClient(); mTermuxTerminalViewClient = new TermuxTerminalViewClient(this, mTermuxTerminalSessionActivityClient); // Set termux terminal view @@ -554,6 +544,11 @@ public class TermuxActivity extends BaseIDEActivity implements ServiceConnection mTermuxTerminalSessionActivityClient.onCreate(); } + @NonNull + protected TermuxTerminalSessionActivityClient onCreateTerminalSessionClient() { + return new TermuxTerminalSessionActivityClient(this); + } + private void setTermuxSessionsListView() { ListView termuxSessionsListView = findViewById(R.id.terminal_sessions_list); mTermuxSessionListViewController = new TermuxSessionsListViewController(this, mTermuxService.getTermuxSessions()); diff --git a/termux/termux-app/src/main/java/com/termux/app/terminal/TermuxTerminalSessionActivityClient.java b/termux/termux-app/src/main/java/com/termux/app/terminal/TermuxTerminalSessionActivityClient.java index ee1d1452a..0ae08a338 100644 --- a/termux/termux-app/src/main/java/com/termux/app/terminal/TermuxTerminalSessionActivityClient.java +++ b/termux/termux-app/src/main/java/com/termux/app/terminal/TermuxTerminalSessionActivityClient.java @@ -37,7 +37,7 @@ import java.util.Properties; /** The {@link TerminalSessionClient} implementation that may require an {@link Activity} for its interface methods. */ public class TermuxTerminalSessionActivityClient extends TermuxTerminalSessionClientBase { - private final TermuxActivity mActivity; + protected final TermuxActivity mActivity; private static final int MAX_SESSIONS = 8;