Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ import android.os.Bundle
import android.os.IBinder
import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat
import androidx.lifecycle.lifecycleScope
import com.itsaky.androidide.utils.Environment
import com.termux.app.TermuxActivity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

/**
* @author Akash Yadav
Expand All @@ -45,6 +48,8 @@ class TerminalActivity : TermuxActivity() {

override fun onServiceConnected(componentName: ComponentName?, service: IBinder?) {
super.onServiceConnected(componentName, service)
Environment.mkdirIfNotExists(Environment.TMP_DIR)
lifecycleScope.launch(Dispatchers.IO) {
Environment.mkdirIfNotExists(Environment.TMP_DIR)
}
}
}
97 changes: 76 additions & 21 deletions termux/termux-app/src/main/java/com/termux/app/TermuxActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
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.TermuxExecutor;
import com.termux.shared.termux.TermuxUtils;
import com.termux.shared.termux.crash.TermuxCrashUtils;
import com.termux.shared.termux.extrakeys.ExtraKeysView;
Expand Down Expand Up @@ -145,6 +146,7 @@ public class TermuxActivity extends BaseIDEActivity implements ServiceConnection
* time, so if the session causing a change is not in the foreground it should probably be treated as background.
*/
protected boolean mIsVisible;
protected boolean mIsResumed;

/**
* If onResume() was called after onCreate().
Expand Down Expand Up @@ -202,6 +204,14 @@ public void onCreate(Bundle savedInstanceState) {
// Delete ReportInfo serialized object files from cache older than 14 days
ReportActivity.deleteReportInfoFilesOlderThanXDays(this, 14, false);

TermuxExecutor.executeInBackground(() -> {
try {
Class.forName("com.termux.terminal.JNI");
} catch (ClassNotFoundException e) {
Logger.logStackTraceWithMessage(LOG_TAG, "JNI preload failed", e);
}
});

ensureTermuxPropertiesInitialized();

// Load Termux app SharedProperties from disk
Expand All @@ -214,15 +224,27 @@ public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

// Load termux shared preferences
// This will also fail if TermuxConstants.TERMUX_PACKAGE_NAME does not equal applicationId
mPreferences = TermuxAppSharedPreferences.build(this, true);
if (mPreferences == null) {
// An AlertDialog should have shown to kill the app, so we don't continue running activity code
mIsInvalidState = true;
return;
}
TermuxExecutor.executeInBackground(() -> {
// Load termux shared preferences
// This will also fail if TermuxConstants.TERMUX_PACKAGE_NAME does not equal applicationId
final TermuxAppSharedPreferences loadedPrefs = TermuxAppSharedPreferences.build(getApplicationContext(), true);

TermuxExecutor.executeOnMain(() -> {
if (isFinishing() || isDestroyed()) return;

mPreferences = loadedPrefs;

if (mPreferences == null) {
// An AlertDialog should have shown to kill the app, so we don't continue running activity code
mIsInvalidState = true;
return;
}
completeOnCreate(savedInstanceState);
});
});
}

private void completeOnCreate(Bundle savedInstanceState) {
setMargins();

mTermuxActivityRootView = findViewById(R.id.activity_termux_root_view);
Expand Down Expand Up @@ -277,6 +299,13 @@ public void onCreate(Bundle savedInstanceState) {
// Send the {@link TermuxConstants#BROADCAST_TERMUX_OPENED} broadcast to notify apps that Termux
// app has been opened.
TermuxUtils.sendTermuxOpenedBroadcast(this);

if (mIsVisible) {
if (mTermuxTerminalSessionActivityClient != null) mTermuxTerminalSessionActivityClient.onStart();
if (mTermuxTerminalViewClient != null) mTermuxTerminalViewClient.onStart();
if (mPreferences.isTerminalMarginAdjustmentEnabled()) addTermuxActivityRootViewGlobalLayoutListener();
}
if (mIsResumed && mIsOnResumeAfterOnCreate) { runOnResumeCallbacks(); }
}

@Override
Expand All @@ -289,6 +318,8 @@ public void onStart() {

mIsVisible = true;

if (mPreferences == null) return;

if (mTermuxTerminalSessionActivityClient != null)
mTermuxTerminalSessionActivityClient.onStart();

Expand All @@ -307,19 +338,24 @@ public void onResume() {
Logger.logVerbose(LOG_TAG, "onResume");

if (mIsInvalidState) return;
mIsResumed = true;
if (mPreferences == null) return;

runOnResumeCallbacks();
}

private void runOnResumeCallbacks() {
if (mTermuxTerminalSessionActivityClient != null)
mTermuxTerminalSessionActivityClient.onResume();

if (mTermuxTerminalViewClient != null)
mTermuxTerminalViewClient.onResume();

// Check if a crash happened on last run of the app or if a plugin crashed and show a
// notification with the crash details if it did
TermuxCrashUtils.notifyAppCrashFromCrashLogFile(this, LOG_TAG);
TermuxExecutor.executeInBackground(() -> TermuxCrashUtils.notifyAppCrashFromCrashLogFile(this, LOG_TAG));

mIsOnResumeAfterOnCreate = false;
feedbackButtonManager.loadFabPosition();

if (feedbackButtonManager != null) { feedbackButtonManager.loadFabPosition(); }
}

@Override
Expand All @@ -331,6 +367,8 @@ protected void onStop() {
if (mIsInvalidState) return;

mIsVisible = false;
mIsResumed = false;
if (mPreferences == null) return;

if (mTermuxTerminalSessionActivityClient != null)
mTermuxTerminalSessionActivityClient.onStop();
Expand Down Expand Up @@ -514,10 +552,14 @@ public void onServiceDisconnected(ComponentName name) {


private void reloadProperties() {
mProperties.loadTermuxPropertiesFromDisk();

if (mTermuxTerminalViewClient != null)
mTermuxTerminalViewClient.onReloadProperties();
TermuxExecutor.execute(
() -> mProperties.loadTermuxPropertiesFromDisk(),
() -> {
if (mTermuxTerminalViewClient != null) {
mTermuxTerminalViewClient.onReloadProperties();
}
}
);
}


Expand Down Expand Up @@ -570,7 +612,17 @@ private void setTermuxTerminalViewAndClients() {

@NonNull
protected TermuxTerminalSessionActivityClient onCreateTerminalSessionClient() {
return new TermuxTerminalSessionActivityClient(this);
return new TermuxTerminalSessionActivityClient(this) {
@Override
public void setCurrentSession(TerminalSession session) {
TermuxExecutor.executeOnMain(() -> super.setCurrentSession(session));
}

@Override
public void onResetTerminalSession() {
TermuxExecutor.executeOnMain(super::onResetTerminalSession);
}
};
}

private void setTermuxSessionsListView() {
Expand Down Expand Up @@ -650,7 +702,11 @@ private void setNewSessionButtonView() {
}

protected void onCreateNewSession(boolean isFailsafe, String sessionName, String workingDirectory) {
mTermuxTerminalSessionActivityClient.addNewSession(isFailsafe, sessionName, workingDirectory);
if (mTermuxTerminalSessionActivityClient == null) return;

TermuxExecutor.executeInBackground(() -> {
mTermuxTerminalSessionActivityClient.addNewSession(isFailsafe, sessionName, workingDirectory);
});
}

private void setToggleKeyboardView() {
Expand Down Expand Up @@ -917,7 +973,7 @@ public boolean isTerminalToolbarTextInputViewSelected() {


public void termuxSessionListNotifyUpdated() {
mTermuxSessionListViewController.notifyDataSetChanged();
TermuxExecutor.executeOnMain(() -> mTermuxSessionListViewController.notifyDataSetChanged());
}

public boolean isVisible() {
Expand Down Expand Up @@ -1030,5 +1086,4 @@ public static Intent newInstance(@NonNull final Context context) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return intent;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.termux.shared.interact.ShareUtils;
import com.termux.shared.logger.Logger;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.termux.TermuxExecutor;
import com.termux.shared.termux.interact.TextInputDialogUtils;
import com.termux.shared.termux.settings.properties.TermuxPropertyConstants;
import com.termux.shared.termux.shell.command.runner.terminal.TermuxSession;
Expand Down Expand Up @@ -364,8 +365,10 @@ public void addNewSession(boolean isFailSafe, String sessionName, String working
if (service == null) return;

if (service.getTermuxSessionsSize() >= MAX_SESSIONS) {
new AlertDialog.Builder(mActivity).setTitle(R.string.title_max_terminals_reached).setMessage(R.string.msg_max_terminals_reached)
.setPositiveButton(android.R.string.ok, null).show();
TermuxExecutor.executeOnMain(() -> {
new AlertDialog.Builder(mActivity).setTitle(R.string.title_max_terminals_reached).setMessage(R.string.msg_max_terminals_reached)
.setPositiveButton(android.R.string.ok, null).show();
});
} else {
TerminalSession currentSession = mActivity.getCurrentSession();

Expand All @@ -383,7 +386,7 @@ public void addNewSession(boolean isFailSafe, String sessionName, String working
TerminalSession newTerminalSession = newTermuxSession.getTerminalSession();
setCurrentSession(newTerminalSession);

mActivity.getDrawer().closeDrawers();
TermuxExecutor.executeOnMain(() -> mActivity.getDrawer().closeDrawers());
}
}

Expand Down Expand Up @@ -491,29 +494,33 @@ String toToastTitle(TerminalSession session) {


public void checkForFontAndColors() {
try {
File colorsFile = TermuxConstants.TERMUX_COLOR_PROPERTIES_FILE;
File fontFile = TermuxConstants.TERMUX_FONT_FILE;

final Properties props = new Properties();
if (colorsFile.isFile()) {
try (InputStream in = new FileInputStream(colorsFile)) {
props.load(in);
TermuxExecutor.executeInBackground(() -> {
try {
File colorsFile = TermuxConstants.TERMUX_COLOR_PROPERTIES_FILE;
File fontFile = TermuxConstants.TERMUX_FONT_FILE;

final Properties props = new Properties();
if (colorsFile.isFile()) {
try (InputStream in = new FileInputStream(colorsFile)) {
props.load(in);
}
}
}

TerminalColors.COLOR_SCHEME.updateWith(props);
TerminalSession session = mActivity.getCurrentSession();
if (session != null && session.getEmulator() != null) {
session.getEmulator().mColors.reset();
final Typeface newTypeface = (fontFile.exists() && fontFile.length() > 0) ? Typeface.createFromFile(fontFile) : Typeface.MONOSPACE;
TermuxExecutor.executeOnMain(() -> {
if (mActivity == null || mActivity.isFinishing()) return;
TerminalColors.COLOR_SCHEME.updateWith(props);
TerminalSession session = mActivity.getCurrentSession();
if (session != null && session.getEmulator() != null) {
session.getEmulator().mColors.reset();
}
updateBackgroundColor();
mActivity.getTerminalView().setTypeface(newTypeface);
});
} catch (Exception e) {
Logger.logStackTraceWithMessage(LOG_TAG, "Error in checkForFontAndColors()", e);
}
updateBackgroundColor();

final Typeface newTypeface = (fontFile.exists() && fontFile.length() > 0) ? Typeface.createFromFile(fontFile) : Typeface.MONOSPACE;
mActivity.getTerminalView().setTypeface(newTypeface);
} catch (Exception e) {
Logger.logStackTraceWithMessage(LOG_TAG, "Error in checkForFontAndColors()", e);
}
});
}

public void updateBackgroundColor() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public final class TerminalSession extends TerminalOutput {
/** Set by the application for user identification of session, not by terminal. */
public String mSessionName;

final Handler mMainThreadHandler = new MainThreadHandler();
final Handler mMainThreadHandler = new MainThreadHandler(android.os.Looper.getMainLooper());

private final String mShellPath;
private final String mCwd;
Expand Down Expand Up @@ -336,6 +336,10 @@ private static FileDescriptor wrapFileDescriptor(int fileDescriptor, TerminalSes
@SuppressLint("HandlerLeak")
class MainThreadHandler extends Handler {

public MainThreadHandler(android.os.Looper looper) {
super(looper);
}

final byte[] mReceiveBuffer = new byte[4 * 1024];

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.termux.shared.termux;

import android.os.Handler;
import android.os.Looper;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TermuxExecutor {
private static final ExecutorService backgroundExecutor = Executors.newSingleThreadExecutor();
private static final Handler mainHandler = new Handler(Looper.getMainLooper());

public static void executeInBackground(Runnable task) {
if (task == null) return;
backgroundExecutor.execute(task);
}

public static void executeOnMain(Runnable task) {
if (task == null) return;
mainHandler.post(task);
}

public static void execute(Runnable backgroundTask, Runnable mainThreadCallback) {
if (backgroundTask == null) {
if (mainThreadCallback != null) mainHandler.post(mainThreadCallback);
return;
}
backgroundExecutor.execute(() -> {
try {
backgroundTask.run();
} finally {
if (mainThreadCallback != null) {
mainHandler.post(mainThreadCallback);
}
}
});
}
}
Loading