mirror of
https://github.com/fankes/termux-app.git
synced 2025-09-06 10:45:23 +08:00
Add the TermuxSession class for linking a TerminalSession to an ExecutionCommand.
TermuxSession will maintain info for foreground Termux sessions. Each terminal session started by TermuxService will now be linked to a ExectionCommand that started it. This also fixes bugs where newly created session in some cases were not being automatically selected and scrolled to, like when adding a named or failsafe session or those which were created for executable intents.
This commit is contained in:
@@ -214,7 +214,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
||||
// Get the session stored in shared preferences stored by {@link #onStop} if its valid,
|
||||
// otherwise get the last session currently running.
|
||||
mTermuxSessionClient.setCurrentSession(mTermuxSessionClient.getCurrentStoredSessionOrLast());
|
||||
terminalSessionListNotifyUpdated();
|
||||
termuxSessionListNotifyUpdated();
|
||||
}
|
||||
|
||||
registerReceiver(mTermuxActivityBroadcastReceiever, new IntentFilter(TERMUX_ACTIVITY.ACTION_RELOAD_STYLE));
|
||||
@@ -242,7 +242,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
||||
|
||||
setTermuxSessionsListView();
|
||||
|
||||
if (mTermuxService.getSessions().isEmpty()) {
|
||||
if (mTermuxService.isTermuxSessionsEmpty()) {
|
||||
if (mIsVisible) {
|
||||
TermuxInstaller.setupIfNeeded(TermuxActivity.this, () -> {
|
||||
if (mTermuxService == null) return; // Activity might have been destroyed.
|
||||
@@ -395,9 +395,10 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
||||
View newSessionButton = findViewById(R.id.new_session_button);
|
||||
newSessionButton.setOnClickListener(v -> mTermuxSessionClient.addNewSession(false, null));
|
||||
newSessionButton.setOnLongClickListener(v -> {
|
||||
DialogUtils.textInput(TermuxActivity.this, R.string.title_create_named_session, null, R.string.action_create_named_session_confirm,
|
||||
text -> mTermuxSessionClient.addNewSession(false, text), R.string.action_new_session_failsafe, text -> mTermuxSessionClient.addNewSession(true, text)
|
||||
, -1, null, null);
|
||||
DialogUtils.textInput(TermuxActivity.this, R.string.title_create_named_session, null,
|
||||
R.string.action_create_named_session_confirm, text -> mTermuxSessionClient.addNewSession(false, text),
|
||||
R.string.action_new_session_failsafe, text -> mTermuxSessionClient.addNewSession(true, text),
|
||||
-1, null, null);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@@ -439,7 +440,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
||||
|
||||
private void setTermuxSessionsListView() {
|
||||
ListView termuxSessionsListView = findViewById(R.id.terminal_sessions_list);
|
||||
mTermuxSessionListViewController = new TermuxSessionsListViewController(this, mTermuxService.getSessions());
|
||||
mTermuxSessionListViewController = new TermuxSessionsListViewController(this, mTermuxService.getTermuxSessions());
|
||||
termuxSessionsListView.setAdapter(mTermuxSessionListViewController);
|
||||
termuxSessionsListView.setOnItemClickListener(mTermuxSessionListViewController);
|
||||
termuxSessionsListView.setOnItemLongClickListener(mTermuxSessionListViewController);
|
||||
@@ -468,6 +469,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
||||
|
||||
/** Show a toast and dismiss the last one if still visible. */
|
||||
public void showToast(String text, boolean longDuration) {
|
||||
if(text == null || text.isEmpty()) return;
|
||||
if (mLastToast != null) mLastToast.cancel();
|
||||
mLastToast = Toast.makeText(TermuxActivity.this, text, longDuration ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT);
|
||||
mLastToast.setGravity(Gravity.TOP, 0, 0);
|
||||
@@ -642,7 +644,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
||||
return (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||
}
|
||||
|
||||
public void terminalSessionListNotifyUpdated() {
|
||||
public void termuxSessionListNotifyUpdated() {
|
||||
mTermuxSessionListViewController.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@@ -683,6 +685,13 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
||||
|
||||
|
||||
|
||||
public static void updateTermuxActivityStyling(Context context) {
|
||||
// Make sure that terminal styling is always applied.
|
||||
Intent stylingIntent = new Intent(TERMUX_ACTIVITY.ACTION_RELOAD_STYLE);
|
||||
stylingIntent.putExtra(TERMUX_ACTIVITY.EXTRA_RELOAD_STYLE, "styling");
|
||||
context.sendBroadcast(stylingIntent);
|
||||
}
|
||||
|
||||
class TermuxActivityBroadcastReceiever extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
@@ -24,9 +24,11 @@ import com.termux.R;
|
||||
import com.termux.app.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY;
|
||||
import com.termux.app.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
|
||||
import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
|
||||
import com.termux.app.terminal.TermuxSession;
|
||||
import com.termux.app.terminal.TermuxSessionClient;
|
||||
import com.termux.app.terminal.TermuxSessionClientBase;
|
||||
import com.termux.app.utils.Logger;
|
||||
import com.termux.app.utils.ShellUtils;
|
||||
import com.termux.app.utils.TextDataUtils;
|
||||
import com.termux.models.ExecutionCommand;
|
||||
import com.termux.models.ExecutionCommand.ExecutionState;
|
||||
@@ -38,8 +40,10 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A service holding a list of terminal sessions, {@link #mTerminalSessions}, showing a foreground notification while
|
||||
* A service holding a list of termux sessions, {@link #mTermuxSessions}, showing a foreground notification while
|
||||
* running so that it is not terminated. The user interacts with the session through {@link TermuxActivity}, but this
|
||||
* service may outlive the activity when the user or the system disposes of the activity. In that case the user may
|
||||
* restart {@link TermuxActivity} later to yet again access the sessions.
|
||||
@@ -67,12 +71,12 @@ public final class TermuxService extends Service {
|
||||
private final Handler mHandler = new Handler();
|
||||
|
||||
/**
|
||||
* The terminal sessions which this service manages.
|
||||
* The termux sessions which this service manages.
|
||||
* Note that this list is observed by {@link TermuxActivity#mTermuxSessionListViewController},
|
||||
* so any changes must be made on the UI thread and followed by a call to
|
||||
* {@link ArrayAdapter#notifyDataSetChanged()} }.
|
||||
*/
|
||||
final List<TerminalSession> mTerminalSessions = new ArrayList<>();
|
||||
final List<TermuxSession> mTermuxSessions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The background jobs which this service manages.
|
||||
@@ -160,7 +164,7 @@ public final class TermuxService extends Service {
|
||||
}
|
||||
|
||||
actionReleaseWakeLock(false);
|
||||
finishAllTerminalSessions();
|
||||
finishAllTermuxSessions();
|
||||
runStopForeground();
|
||||
}
|
||||
|
||||
@@ -205,7 +209,7 @@ public final class TermuxService extends Service {
|
||||
/** Process action to stop service. */
|
||||
private void actionStopService() {
|
||||
mWantsToStop = true;
|
||||
finishAllTerminalSessions();
|
||||
finishAllTermuxSessions();
|
||||
requestStopService();
|
||||
}
|
||||
|
||||
@@ -273,7 +277,8 @@ public final class TermuxService extends Service {
|
||||
Logger.logDebug(LOG_TAG, "WakeLocks released successfully");
|
||||
}
|
||||
|
||||
/** Process action to execute a shell command in a foreground session or in background. */
|
||||
/** Process {@link TERMUX_SERVICE#ACTION_SERVICE_EXECUTE} intent to execute a shell command in
|
||||
* a foreground termux session or in background. */
|
||||
private void actionServiceExecute(Intent intent) {
|
||||
if (intent == null){
|
||||
Logger.logError(LOG_TAG, "Ignoring null intent to actionServiceExecute");
|
||||
@@ -303,15 +308,18 @@ public final class TermuxService extends Service {
|
||||
if (executionCommand.inBackground) {
|
||||
executeBackgroundCommand(executionCommand);
|
||||
} else {
|
||||
executeForegroundCommand(executionCommand);
|
||||
executeTermuxSessionCommand(executionCommand);
|
||||
}
|
||||
}
|
||||
|
||||
/** Execute a shell command in background with {@link BackgroundJob}. */
|
||||
private void executeBackgroundCommand(ExecutionCommand executionCommand) {
|
||||
if (executionCommand == null) return;
|
||||
|
||||
Logger.logDebug(LOG_TAG, "Starting background command");
|
||||
|
||||
Logger.logDebug(LOG_TAG, executionCommand.toString());
|
||||
if(Logger.getLogLevel() >= Logger.LOG_LEVEL_VERBOSE)
|
||||
Logger.logVerbose(LOG_TAG, executionCommand.toString());
|
||||
|
||||
BackgroundJob task = new BackgroundJob(executionCommand, this);
|
||||
|
||||
@@ -328,65 +336,134 @@ public final class TermuxService extends Service {
|
||||
}
|
||||
|
||||
/** Execute a shell command in a foreground terminal session. */
|
||||
private void executeForegroundCommand(ExecutionCommand executionCommand) {
|
||||
Logger.logDebug(LOG_TAG, "Starting foreground command");
|
||||
private void executeTermuxSessionCommand(ExecutionCommand executionCommand) {
|
||||
if (executionCommand == null) return;
|
||||
|
||||
if(!executionCommand.setState(ExecutionState.EXECUTING))
|
||||
return;
|
||||
Logger.logDebug(LOG_TAG, "Starting foreground termux session command");
|
||||
|
||||
Logger.logDebug(LOG_TAG, executionCommand.toString());
|
||||
|
||||
TerminalSession newSession = createTerminalSession(executionCommand.executable, executionCommand.arguments, executionCommand.workingDirectory, executionCommand.isFailsafe);
|
||||
String sessionName = null;
|
||||
|
||||
// Transform executable path to session name, e.g. "/bin/do-something.sh" => "do something.sh".
|
||||
if (executionCommand.executable != null) {
|
||||
int lastSlash = executionCommand.executable.lastIndexOf('/');
|
||||
String name = (lastSlash == -1) ? executionCommand.executable : executionCommand.executable.substring(lastSlash + 1);
|
||||
name = name.replace('-', ' ');
|
||||
newSession.mSessionName = name;
|
||||
sessionName = ShellUtils.getExecutableBasename(executionCommand.executable).replace('-', ' ');
|
||||
}
|
||||
|
||||
TermuxSession newTermuxSession = createTermuxSession(executionCommand, sessionName);
|
||||
if (newTermuxSession == null) return;
|
||||
|
||||
handleSessionAction(TextDataUtils.getIntFromString(executionCommand.sessionAction,
|
||||
TERMUX_SERVICE.VALUE_EXTRA_SESSION_ACTION_SWITCH_TO_NEW_SESSION_AND_OPEN_ACTIVITY),
|
||||
newTermuxSession.getTerminalSession());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a termux session.
|
||||
* Currently called by {@link TermuxSessionClient#addNewSession(boolean, String)} to add a new termux session.
|
||||
*/
|
||||
@Nullable
|
||||
public TermuxSession createTermuxSession(String executablePath, String[] arguments, String workingDirectory, boolean isFailSafe, String sessionName) {
|
||||
return createTermuxSession(new ExecutionCommand(getNextExecutionId(), executablePath, arguments, workingDirectory, false, isFailSafe), sessionName);
|
||||
}
|
||||
|
||||
/** Create a termux session. */
|
||||
@Nullable
|
||||
public synchronized TermuxSession createTermuxSession(ExecutionCommand executionCommand, String sessionName) {
|
||||
if (executionCommand == null) return null;
|
||||
|
||||
Logger.logDebug(LOG_TAG, "Creating termux session");
|
||||
|
||||
if (executionCommand.inBackground) {
|
||||
Logger.logDebug(LOG_TAG, "Ignoring a background execution command passed to createTermuxSession()");
|
||||
return null;
|
||||
}
|
||||
|
||||
if(Logger.getLogLevel() >= Logger.LOG_LEVEL_VERBOSE)
|
||||
Logger.logVerbose(LOG_TAG, executionCommand.toString());
|
||||
|
||||
TermuxSession newTermuxSession = TermuxSession.create(executionCommand, getTermuxSessionClient(), sessionName);
|
||||
if (newTermuxSession == null) {
|
||||
Logger.logError(LOG_TAG, "Failed to execute new termux session command for:\n" + executionCommand.toString());
|
||||
return null;
|
||||
};
|
||||
|
||||
mTermuxSessions.add(newTermuxSession);
|
||||
|
||||
// Notify {@link TermuxSessionsListViewController} that sessions list has been updated if
|
||||
// activity in is foreground
|
||||
if(mTermuxSessionClient != null)
|
||||
mTermuxSessionClient.terminalSessionListNotifyUpdated();
|
||||
mTermuxSessionClient.termuxSessionListNotifyUpdated();
|
||||
|
||||
handleSessionAction(TextDataUtils.getIntFromString(executionCommand.sessionAction, TERMUX_SERVICE.VALUE_EXTRA_SESSION_ACTION_SWITCH_TO_NEW_SESSION_AND_OPEN_ACTIVITY), newSession);
|
||||
updateNotification();
|
||||
TermuxActivity.updateTermuxActivityStyling(this);
|
||||
|
||||
return newTermuxSession;
|
||||
}
|
||||
|
||||
private void setCurrentStoredSession(TerminalSession newSession) {
|
||||
// Make the newly created session the current one to be displayed:
|
||||
TermuxAppSharedPreferences preferences = new TermuxAppSharedPreferences(this);
|
||||
preferences.setCurrentSession(newSession.mHandle);
|
||||
/** Remove a termux session. */
|
||||
public synchronized int removeTermuxSession(TerminalSession sessionToRemove) {
|
||||
int index = getIndexOfSession(sessionToRemove);
|
||||
|
||||
if(index >= 0) {
|
||||
TermuxSession termuxSession = mTermuxSessions.get(index);
|
||||
|
||||
if (termuxSession.getExecutionCommand().setState(ExecutionState.EXECUTED)) {
|
||||
;
|
||||
}
|
||||
|
||||
mTermuxSessions.remove(termuxSession);
|
||||
|
||||
// Notify {@link TermuxSessionsListViewController} that sessions list has been updated if
|
||||
// activity in is foreground
|
||||
if(mTermuxSessionClient != null)
|
||||
mTermuxSessionClient.termuxSessionListNotifyUpdated();
|
||||
}
|
||||
|
||||
if (mTermuxSessions.isEmpty() && mWakeLock == null) {
|
||||
// Finish if there are no sessions left and the wake lock is not held, otherwise keep the service alive if
|
||||
// holding wake lock since there may be daemon processes (e.g. sshd) running.
|
||||
requestStopService();
|
||||
} else {
|
||||
updateNotification();
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/** Finish all termux sessions by sending SIGKILL to their shells. */
|
||||
private synchronized void finishAllTermuxSessions() {
|
||||
for (int i = 0; i < mTermuxSessions.size(); i++)
|
||||
mTermuxSessions.get(i).getTerminalSession().finishIfRunning();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Process session action for new session. */
|
||||
private void handleSessionAction(int sessionAction, TerminalSession newSession) {
|
||||
Logger.logDebug(LOG_TAG, "Processing sessionAction \"" + sessionAction + "\" for session \"" + newSession.mSessionName + "\"");
|
||||
private void handleSessionAction(int sessionAction, TerminalSession newTerminalSession) {
|
||||
Logger.logDebug(LOG_TAG, "Processing sessionAction \"" + sessionAction + "\" for session \"" + newTerminalSession.mSessionName + "\"");
|
||||
|
||||
switch (sessionAction) {
|
||||
case TERMUX_SERVICE.VALUE_EXTRA_SESSION_ACTION_SWITCH_TO_NEW_SESSION_AND_OPEN_ACTIVITY:
|
||||
setCurrentStoredSession(newSession);
|
||||
setCurrentStoredTerminalSession(newTerminalSession);
|
||||
if(mTermuxSessionClient != null)
|
||||
mTermuxSessionClient.setCurrentSession(newSession);
|
||||
mTermuxSessionClient.setCurrentSession(newTerminalSession);
|
||||
startTermuxActivity();
|
||||
break;
|
||||
case TERMUX_SERVICE.VALUE_EXTRA_SESSION_ACTION_KEEP_CURRENT_SESSION_AND_OPEN_ACTIVITY:
|
||||
if(mTerminalSessions.size() == 1)
|
||||
setCurrentStoredSession(newSession);
|
||||
if(getTermuxSessionsSize() == 1)
|
||||
setCurrentStoredTerminalSession(newTerminalSession);
|
||||
startTermuxActivity();
|
||||
break;
|
||||
case TERMUX_SERVICE.VALUE_EXTRA_SESSION_ACTION_SWITCH_TO_NEW_SESSION_AND_DONT_OPEN_ACTIVITY:
|
||||
setCurrentStoredSession(newSession);
|
||||
setCurrentStoredTerminalSession(newTerminalSession);
|
||||
if(mTermuxSessionClient != null)
|
||||
mTermuxSessionClient.setCurrentSession(newSession);
|
||||
mTermuxSessionClient.setCurrentSession(newTerminalSession);
|
||||
break;
|
||||
case TERMUX_SERVICE.VALUE_EXTRA_SESSION_ACTION_KEEP_CURRENT_SESSION_AND_DONT_OPEN_ACTIVITY:
|
||||
if(mTerminalSessions.size() == 1)
|
||||
setCurrentStoredSession(newSession);
|
||||
if(getTermuxSessionsSize() == 1)
|
||||
setCurrentStoredTerminalSession(newTerminalSession);
|
||||
break;
|
||||
default:
|
||||
Logger.logError(LOG_TAG, "Invalid sessionAction: \"" + sessionAction + "\"");
|
||||
Logger.logError(LOG_TAG, "Invalid sessionAction: \"" + sessionAction + "\". Force using default sessionAction.");
|
||||
handleSessionAction(TERMUX_SERVICE.VALUE_EXTRA_SESSION_ACTION_SWITCH_TO_NEW_SESSION_AND_OPEN_ACTIVITY, newTerminalSession);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -396,78 +473,6 @@ public final class TermuxService extends Service {
|
||||
startActivity(new Intent(this, TermuxActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
|
||||
/** Create a terminal session. */
|
||||
public TerminalSession createTerminalSession(String executablePath, String[] arguments, String workingDirectory, boolean isFailSafe) {
|
||||
TermuxConstants.TERMUX_HOME_DIR.mkdirs();
|
||||
|
||||
if (workingDirectory == null || workingDirectory.isEmpty()) workingDirectory = TermuxConstants.TERMUX_HOME_DIR_PATH;
|
||||
|
||||
String[] env = BackgroundJob.buildEnvironment(isFailSafe, workingDirectory);
|
||||
boolean isLoginShell = false;
|
||||
|
||||
if (executablePath == null) {
|
||||
if (!isFailSafe) {
|
||||
for (String shellBinary : new String[]{"login", "bash", "zsh"}) {
|
||||
File shellFile = new File(TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH, shellBinary);
|
||||
if (shellFile.canExecute()) {
|
||||
executablePath = shellFile.getAbsolutePath();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (executablePath == null) {
|
||||
// Fall back to system shell as last resort:
|
||||
executablePath = "/system/bin/sh";
|
||||
}
|
||||
isLoginShell = true;
|
||||
}
|
||||
|
||||
String[] processArgs = BackgroundJob.setupProcessArgs(executablePath, arguments);
|
||||
executablePath = processArgs[0];
|
||||
int lastSlashIndex = executablePath.lastIndexOf('/');
|
||||
String processName = (isLoginShell ? "-" : "") +
|
||||
(lastSlashIndex == -1 ? executablePath : executablePath.substring(lastSlashIndex + 1));
|
||||
|
||||
String[] args = new String[processArgs.length];
|
||||
args[0] = processName;
|
||||
if (processArgs.length > 1) System.arraycopy(processArgs, 1, args, 1, processArgs.length - 1);
|
||||
|
||||
TerminalSession session = new TerminalSession(executablePath, workingDirectory, args, env, getTermuxSessionClient());
|
||||
mTerminalSessions.add(session);
|
||||
updateNotification();
|
||||
|
||||
// Make sure that terminal styling is always applied.
|
||||
Intent stylingIntent = new Intent(TERMUX_ACTIVITY.ACTION_RELOAD_STYLE);
|
||||
stylingIntent.putExtra(TERMUX_ACTIVITY.EXTRA_RELOAD_STYLE, "styling");
|
||||
sendBroadcast(stylingIntent);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/** Remove a terminal session. */
|
||||
public int removeTerminalSession(TerminalSession sessionToRemove) {
|
||||
int indexOfRemoved = mTerminalSessions.indexOf(sessionToRemove);
|
||||
mTerminalSessions.remove(indexOfRemoved);
|
||||
|
||||
if (mTerminalSessions.isEmpty() && mWakeLock == null) {
|
||||
// Finish if there are no sessions left and the wake lock is not held, otherwise keep the service alive if
|
||||
// holding wake lock since there may be daemon processes (e.g. sshd) running.
|
||||
requestStopService();
|
||||
} else {
|
||||
updateNotification();
|
||||
}
|
||||
return indexOfRemoved;
|
||||
}
|
||||
|
||||
/** Finish all terminal sessions by sending SIGKILL to their shells. */
|
||||
private void finishAllTerminalSessions() {
|
||||
for (int i = 0; i < mTerminalSessions.size(); i++)
|
||||
mTerminalSessions.get(i).finishIfRunning();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** If {@link TermuxActivity} has not bound to the {@link TermuxService} yet or is destroyed, then
|
||||
* interface functions requiring the activity should not be available to the terminal sessions,
|
||||
* so we just return the {@link #mTermuxSessionClientBase}. Once {@link TermuxActivity} bind
|
||||
@@ -479,7 +484,7 @@ public final class TermuxService extends Service {
|
||||
* @return Returns the {@link TermuxSessionClient} if {@link TermuxActivity} has bound with
|
||||
* {@link TermuxService}, otherwise {@link TermuxSessionClientBase}.
|
||||
*/
|
||||
public TermuxSessionClientBase getTermuxSessionClient() {
|
||||
public synchronized TermuxSessionClientBase getTermuxSessionClient() {
|
||||
if (mTermuxSessionClient != null)
|
||||
return mTermuxSessionClient;
|
||||
else
|
||||
@@ -494,20 +499,20 @@ public final class TermuxService extends Service {
|
||||
* @param termuxSessionClient The {@link TermuxSessionClient} object that fully
|
||||
* implements the {@link TerminalSessionClient} interface.
|
||||
*/
|
||||
public void setTermuxSessionClient(TermuxSessionClient termuxSessionClient) {
|
||||
public synchronized void setTermuxSessionClient(TermuxSessionClient termuxSessionClient) {
|
||||
mTermuxSessionClient = termuxSessionClient;
|
||||
|
||||
for (int i = 0; i < mTerminalSessions.size(); i++)
|
||||
mTerminalSessions.get(i).updateTerminalSessionClient(mTermuxSessionClient);
|
||||
for (int i = 0; i < mTermuxSessions.size(); i++)
|
||||
mTermuxSessions.get(i).getTerminalSession().updateTerminalSessionClient(mTermuxSessionClient);
|
||||
}
|
||||
|
||||
/** This should be called when {@link TermuxActivity} has been destroyed and in {@link #onUnbind(Intent)}
|
||||
* so that the {@link TermuxService} and {@link TerminalSession} and {@link TerminalEmulator}
|
||||
* clients do not hold an activity references.
|
||||
*/
|
||||
public void unsetTermuxSessionClient() {
|
||||
for (int i = 0; i < mTerminalSessions.size(); i++)
|
||||
mTerminalSessions.get(i).updateTerminalSessionClient(mTermuxSessionClientBase);
|
||||
public synchronized void unsetTermuxSessionClient() {
|
||||
for (int i = 0; i < mTermuxSessions.size(); i++)
|
||||
mTermuxSessions.get(i).getTerminalSession().updateTerminalSessionClient(mTermuxSessionClientBase);
|
||||
|
||||
mTermuxSessionClient = null;
|
||||
}
|
||||
@@ -521,7 +526,7 @@ public final class TermuxService extends Service {
|
||||
notifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifyIntent, 0);
|
||||
|
||||
int sessionCount = mTerminalSessions.size();
|
||||
int sessionCount = getTermuxSessionsSize();
|
||||
int taskCount = mBackgroundTasks.size();
|
||||
String contentText = sessionCount + " session" + (sessionCount == 1 ? "" : "s");
|
||||
if (taskCount > 0) {
|
||||
@@ -582,7 +587,7 @@ public final class TermuxService extends Service {
|
||||
|
||||
/** Update the shown foreground service notification after making any changes that affect it. */
|
||||
void updateNotification() {
|
||||
if (mWakeLock == null && mTerminalSessions.isEmpty() && mBackgroundTasks.isEmpty()) {
|
||||
if (mWakeLock == null && mTermuxSessions.isEmpty() && mBackgroundTasks.isEmpty()) {
|
||||
// Exit if we are updating after the user disabled all locks with no sessions or tasks running.
|
||||
requestStopService();
|
||||
} else {
|
||||
@@ -592,16 +597,63 @@ public final class TermuxService extends Service {
|
||||
|
||||
|
||||
|
||||
private void setCurrentStoredTerminalSession(TerminalSession session) {
|
||||
if(session == null) return;
|
||||
// Make the newly created session the current one to be displayed:
|
||||
TermuxAppSharedPreferences preferences = new TermuxAppSharedPreferences(this);
|
||||
preferences.setCurrentSession(session.mHandle);
|
||||
}
|
||||
|
||||
public synchronized boolean isTermuxSessionsEmpty() {
|
||||
return mTermuxSessions.isEmpty();
|
||||
}
|
||||
|
||||
public synchronized int getTermuxSessionsSize() {
|
||||
return mTermuxSessions.size();
|
||||
}
|
||||
|
||||
public synchronized List<TermuxSession> getTermuxSessions() {
|
||||
return mTermuxSessions;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public synchronized TermuxSession getTermuxSession(int index) {
|
||||
if(index >= 0 && index < mTermuxSessions.size())
|
||||
return mTermuxSessions.get(index);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized TermuxSession getLastTermuxSession() {
|
||||
return mTermuxSessions.isEmpty() ? null : mTermuxSessions.get(mTermuxSessions.size() - 1);
|
||||
}
|
||||
|
||||
public synchronized int getIndexOfSession(TerminalSession terminalSession) {
|
||||
for (int i = 0; i < mTermuxSessions.size(); i++) {
|
||||
if (mTermuxSessions.get(i).getTerminalSession().equals(terminalSession))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public synchronized TerminalSession getTerminalSessionForHandle(String sessionHandle) {
|
||||
TerminalSession terminalSession;
|
||||
for (int i = 0, len = mTermuxSessions.size(); i < len; i++) {
|
||||
terminalSession = mTermuxSessions.get(i).getTerminalSession();
|
||||
if (terminalSession.mHandle.equals(sessionHandle))
|
||||
return terminalSession;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static synchronized int getNextExecutionId() {
|
||||
return EXECUTION_ID++;
|
||||
}
|
||||
|
||||
public boolean wantsToStop() {
|
||||
return mWantsToStop;
|
||||
}
|
||||
|
||||
public List<TerminalSession> getSessions() {
|
||||
return mTerminalSessions;
|
||||
}
|
||||
|
||||
synchronized public static int getNextExecutionId() {
|
||||
return EXECUTION_ID++;
|
||||
}
|
||||
|
||||
}
|
||||
|
87
app/src/main/java/com/termux/app/terminal/TermuxSession.java
Normal file
87
app/src/main/java/com/termux/app/terminal/TermuxSession.java
Normal file
@@ -0,0 +1,87 @@
|
||||
package com.termux.app.terminal;
|
||||
|
||||
import com.termux.app.TermuxConstants;
|
||||
import com.termux.app.utils.Logger;
|
||||
import com.termux.app.utils.ShellUtils;
|
||||
import com.termux.models.ExecutionCommand;
|
||||
import com.termux.terminal.TerminalSession;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* A class that maintains info for foreground Termux sessions.
|
||||
* It also provides a way to link each {@link TerminalSession} with the {@link ExecutionCommand}
|
||||
* that started it.
|
||||
*/
|
||||
public class TermuxSession {
|
||||
|
||||
private final TerminalSession mTerminalSession;
|
||||
private final ExecutionCommand mExecutionCommand;
|
||||
|
||||
private static final String LOG_TAG = "TermuxSession";
|
||||
|
||||
private TermuxSession(TerminalSession terminalSession, ExecutionCommand executionCommand) {
|
||||
this.mTerminalSession = terminalSession;
|
||||
this.mExecutionCommand = executionCommand;
|
||||
}
|
||||
|
||||
public static TermuxSession create(ExecutionCommand executionCommand, TermuxSessionClientBase termuxSessionClient, String sessionName) {
|
||||
TermuxConstants.TERMUX_HOME_DIR.mkdirs();
|
||||
|
||||
if (executionCommand.workingDirectory == null || executionCommand.workingDirectory.isEmpty()) executionCommand.workingDirectory = TermuxConstants.TERMUX_HOME_DIR_PATH;
|
||||
|
||||
String[] environment = ShellUtils.buildEnvironment(executionCommand.isFailsafe, executionCommand.workingDirectory);
|
||||
boolean isLoginShell = false;
|
||||
|
||||
if (executionCommand.executable == null) {
|
||||
if (!executionCommand.isFailsafe) {
|
||||
for (String shellBinary : new String[]{"login", "bash", "zsh"}) {
|
||||
File shellFile = new File(TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH, shellBinary);
|
||||
if (shellFile.canExecute()) {
|
||||
executionCommand.executable = shellFile.getAbsolutePath();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (executionCommand.executable == null) {
|
||||
// Fall back to system shell as last resort:
|
||||
executionCommand.executable = "/system/bin/sh";
|
||||
}
|
||||
isLoginShell = true;
|
||||
}
|
||||
|
||||
String[] processArgs = ShellUtils.setupProcessArgs(executionCommand.executable, executionCommand.arguments);
|
||||
|
||||
executionCommand.executable = processArgs[0];
|
||||
String processName = (isLoginShell ? "-" : "") + ShellUtils.getExecutableBasename(executionCommand.executable);
|
||||
|
||||
String[] arguments = new String[processArgs.length];
|
||||
arguments[0] = processName;
|
||||
if (processArgs.length > 1) System.arraycopy(processArgs, 1, arguments, 1, processArgs.length - 1);
|
||||
|
||||
executionCommand.arguments = arguments;
|
||||
|
||||
if(!executionCommand.setState(ExecutionCommand.ExecutionState.EXECUTING))
|
||||
return null;
|
||||
|
||||
Logger.logDebug(LOG_TAG, executionCommand.toString());
|
||||
|
||||
TerminalSession terminalSession = new TerminalSession(executionCommand.executable, executionCommand.workingDirectory, executionCommand.arguments, environment, termuxSessionClient);
|
||||
|
||||
if (sessionName != null) {
|
||||
terminalSession.mSessionName = sessionName;
|
||||
}
|
||||
|
||||
return new TermuxSession(terminalSession, executionCommand);
|
||||
}
|
||||
|
||||
public TerminalSession getTerminalSession() {
|
||||
return mTerminalSession;
|
||||
}
|
||||
|
||||
public ExecutionCommand getExecutionCommand() {
|
||||
return mExecutionCommand;
|
||||
}
|
||||
|
||||
}
|
@@ -27,7 +27,6 @@ import com.termux.terminal.TextStyle;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
public class TermuxSessionClient extends TermuxSessionClientBase {
|
||||
@@ -68,7 +67,7 @@ public class TermuxSessionClient extends TermuxSessionClientBase {
|
||||
mActivity.showToast(toToastTitle(updatedSession), true);
|
||||
}
|
||||
|
||||
terminalSessionListNotifyUpdated();
|
||||
termuxSessionListNotifyUpdated();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,7 +80,7 @@ public class TermuxSessionClient extends TermuxSessionClientBase {
|
||||
|
||||
if (mActivity.isVisible() && finishedSession != mActivity.getCurrentSession()) {
|
||||
// Show toast for non-current sessions that exit.
|
||||
int indexOfSession = mActivity.getTermuxService().getSessions().indexOf(finishedSession);
|
||||
int indexOfSession = mActivity.getTermuxService().getIndexOfSession(finishedSession);
|
||||
// Verify that session was not removed before we got told about it finishing:
|
||||
if (indexOfSession >= 0)
|
||||
mActivity.showToast(toToastTitle(finishedSession) + " - exited", true);
|
||||
@@ -90,7 +89,7 @@ public class TermuxSessionClient extends TermuxSessionClientBase {
|
||||
if (mActivity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
|
||||
// On Android TV devices we need to use older behaviour because we may
|
||||
// not be able to have multiple launcher icons.
|
||||
if (mActivity.getTermuxService().getSessions().size() > 1) {
|
||||
if (mActivity.getTermuxService().getTermuxSessionsSize() > 1) {
|
||||
removeFinishedSession(finishedSession);
|
||||
}
|
||||
} else {
|
||||
@@ -100,8 +99,6 @@ public class TermuxSessionClient extends TermuxSessionClientBase {
|
||||
removeFinishedSession(finishedSession);
|
||||
}
|
||||
}
|
||||
|
||||
terminalSessionListNotifyUpdated();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,38 +135,49 @@ public class TermuxSessionClient extends TermuxSessionClientBase {
|
||||
|
||||
|
||||
|
||||
/** Try switching to session and note about it, but do nothing if already displaying the session. */
|
||||
/** Try switching to session. */
|
||||
public void setCurrentSession(TerminalSession session) {
|
||||
if(session == null) return;
|
||||
|
||||
if (mActivity.getTerminalView().attachSession(session)) {
|
||||
noteSessionInfo();
|
||||
updateBackgroundColor();
|
||||
// notify about switched session if not already displaying the session
|
||||
notifyOfSessionChange();
|
||||
}
|
||||
|
||||
// We call the following even when the session is already being displayed since config may
|
||||
// be stale, like current session not selected or scrolled to.
|
||||
checkAndScrollToSession(session);
|
||||
updateBackgroundColor();
|
||||
}
|
||||
|
||||
void noteSessionInfo() {
|
||||
void notifyOfSessionChange() {
|
||||
if (!mActivity.isVisible()) return;
|
||||
|
||||
TerminalSession session = mActivity.getCurrentSession();
|
||||
final int indexOfSession = mActivity.getTermuxService().getSessions().indexOf(session);
|
||||
mActivity.showToast(toToastTitle(session), false);
|
||||
terminalSessionListNotifyUpdated();
|
||||
|
||||
final ListView termuxSessionsListView = mActivity.findViewById(R.id.terminal_sessions_list);
|
||||
termuxSessionsListView.setItemChecked(indexOfSession, true);
|
||||
termuxSessionsListView.smoothScrollToPosition(indexOfSession);
|
||||
}
|
||||
|
||||
public void switchToSession(boolean forward) {
|
||||
TermuxService service = mActivity.getTermuxService();
|
||||
|
||||
TerminalSession currentSession = mActivity.getCurrentSession();
|
||||
int index = service.getSessions().indexOf(currentSession);
|
||||
TerminalSession currentTerminalSession = mActivity.getCurrentSession();
|
||||
int index = service.getIndexOfSession(currentTerminalSession);
|
||||
int size = service.getTermuxSessionsSize();
|
||||
if (forward) {
|
||||
if (++index >= service.getSessions().size()) index = 0;
|
||||
if (++index >= size) index = 0;
|
||||
} else {
|
||||
if (--index < 0) index = service.getSessions().size() - 1;
|
||||
if (--index < 0) index = size - 1;
|
||||
}
|
||||
setCurrentSession(service.getSessions().get(index));
|
||||
|
||||
TermuxSession termuxSession = service.getTermuxSession(index);
|
||||
if(termuxSession != null)
|
||||
setCurrentSession(termuxSession.getTerminalSession());
|
||||
}
|
||||
|
||||
public void switchToSession(int index) {
|
||||
TermuxSession termuxSession = mActivity.getTermuxService().getTermuxSession(index);
|
||||
if(termuxSession != null)
|
||||
setCurrentSession(termuxSession.getTerminalSession());
|
||||
}
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
@@ -178,12 +186,12 @@ public class TermuxSessionClient extends TermuxSessionClientBase {
|
||||
|
||||
DialogUtils.textInput(mActivity, R.string.title_rename_session, sessionToRename.mSessionName, R.string.action_rename_session_confirm, text -> {
|
||||
sessionToRename.mSessionName = text;
|
||||
terminalSessionListNotifyUpdated();
|
||||
termuxSessionListNotifyUpdated();
|
||||
}, -1, null, -1, null, null);
|
||||
}
|
||||
|
||||
public void addNewSession(boolean isFailSafe, String sessionName) {
|
||||
if (mActivity.getTermuxService().getSessions().size() >= MAX_SESSIONS) {
|
||||
if (mActivity.getTermuxService().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();
|
||||
} else {
|
||||
@@ -196,11 +204,12 @@ public class TermuxSessionClient extends TermuxSessionClientBase {
|
||||
workingDirectory = currentSession.getCwd();
|
||||
}
|
||||
|
||||
TerminalSession newSession = mActivity.getTermuxService().createTerminalSession(null, null, workingDirectory, isFailSafe);
|
||||
if (sessionName != null) {
|
||||
newSession.mSessionName = sessionName;
|
||||
}
|
||||
setCurrentSession(newSession);
|
||||
TermuxSession newTermuxSession = mActivity.getTermuxService().createTermuxSession(null, null, workingDirectory, isFailSafe, sessionName);
|
||||
if (newTermuxSession == null) return;
|
||||
|
||||
TerminalSession newTerminalSession = newTermuxSession.getTerminalSession();
|
||||
setCurrentSession(newTerminalSession);
|
||||
|
||||
mActivity.getDrawer().closeDrawers();
|
||||
}
|
||||
}
|
||||
@@ -222,8 +231,11 @@ public class TermuxSessionClient extends TermuxSessionClientBase {
|
||||
return stored;
|
||||
} else {
|
||||
// Else return the last session currently running
|
||||
List<TerminalSession> sessions = mActivity.getTermuxService().getSessions();
|
||||
return sessions.isEmpty() ? null : sessions.get(sessions.size() - 1);
|
||||
TermuxSession termuxSession = mActivity.getTermuxService().getLastTermuxSession();
|
||||
if(termuxSession != null)
|
||||
return termuxSession.getTerminalSession();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,41 +247,50 @@ public class TermuxSessionClient extends TermuxSessionClientBase {
|
||||
return null;
|
||||
|
||||
// Check if the session handle found matches one of the currently running sessions
|
||||
List<TerminalSession> sessions = context.getTermuxService().getSessions();
|
||||
for (int i = 0, len = sessions.size(); i < len; i++) {
|
||||
TerminalSession session = sessions.get(i);
|
||||
if (session.mHandle.equals(sessionHandle))
|
||||
return session;
|
||||
}
|
||||
|
||||
return null;
|
||||
return context.getTermuxService().getTerminalSessionForHandle(sessionHandle);
|
||||
}
|
||||
|
||||
public void removeFinishedSession(TerminalSession finishedSession) {
|
||||
// Return pressed with finished session - remove it.
|
||||
TermuxService service = mActivity.getTermuxService();
|
||||
|
||||
int index = service.removeTerminalSession(finishedSession);
|
||||
terminalSessionListNotifyUpdated();
|
||||
if (mActivity.getTermuxService().getSessions().isEmpty()) {
|
||||
int index = service.removeTermuxSession(finishedSession);
|
||||
int size = mActivity.getTermuxService().getTermuxSessionsSize();
|
||||
if (size == 0) {
|
||||
// There are no sessions to show, so finish the activity.
|
||||
mActivity.finishActivityIfNotFinishing();
|
||||
} else {
|
||||
if (index >= service.getSessions().size()) {
|
||||
index = service.getSessions().size() - 1;
|
||||
if (index >= size) {
|
||||
index = size - 1;
|
||||
}
|
||||
setCurrentSession(service.getSessions().get(index));
|
||||
TermuxSession termuxSession = service.getTermuxSession(index);
|
||||
if(termuxSession != null)
|
||||
setCurrentSession(termuxSession.getTerminalSession());
|
||||
}
|
||||
}
|
||||
|
||||
public void terminalSessionListNotifyUpdated() {
|
||||
mActivity.terminalSessionListNotifyUpdated();
|
||||
public void termuxSessionListNotifyUpdated() {
|
||||
mActivity.termuxSessionListNotifyUpdated();
|
||||
}
|
||||
|
||||
public void checkAndScrollToSession(TerminalSession session) {
|
||||
if (!mActivity.isVisible()) return;
|
||||
final int indexOfSession = mActivity.getTermuxService().getIndexOfSession(session);
|
||||
if (indexOfSession < 0) return;
|
||||
final ListView termuxSessionsListView = mActivity.findViewById(R.id.terminal_sessions_list);
|
||||
if(termuxSessionsListView == null) return;
|
||||
|
||||
termuxSessionsListView.setItemChecked(indexOfSession, true);
|
||||
// Delay is necessary otherwise sometimes scroll to newly added session does not happen
|
||||
termuxSessionsListView.postDelayed(() -> termuxSessionsListView.smoothScrollToPosition(indexOfSession), 1000);
|
||||
|
||||
Logger.logError("scrolled to " + indexOfSession);
|
||||
}
|
||||
|
||||
|
||||
|
||||
String toToastTitle(TerminalSession session) {
|
||||
final int indexOfSession = mActivity.getTermuxService().getSessions().indexOf(session);
|
||||
final int indexOfSession = mActivity.getTermuxService().getIndexOfSession(session);
|
||||
if (indexOfSession < 0) return null;
|
||||
StringBuilder toastTitle = new StringBuilder("[" + (indexOfSession + 1) + "]");
|
||||
if (!TextUtils.isEmpty(session.mSessionName)) {
|
||||
toastTitle.append(" ").append(session.mSessionName);
|
||||
@@ -311,6 +332,7 @@ public class TermuxSessionClient extends TermuxSessionClientBase {
|
||||
}
|
||||
|
||||
public void updateBackgroundColor() {
|
||||
if (!mActivity.isVisible()) return;
|
||||
TerminalSession session = mActivity.getCurrentSession();
|
||||
if (session != null && session.getEmulator() != null) {
|
||||
mActivity.getWindow().getDecorView().setBackgroundColor(session.getEmulator().mColors.mCurrentColors[TextStyle.COLOR_INDEX_BACKGROUND]);
|
||||
|
@@ -24,14 +24,14 @@ import com.termux.terminal.TerminalSession;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TermuxSessionsListViewController extends ArrayAdapter<TerminalSession> implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener {
|
||||
public class TermuxSessionsListViewController extends ArrayAdapter<TermuxSession> implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener {
|
||||
|
||||
final TermuxActivity mActivity;
|
||||
|
||||
final StyleSpan boldSpan = new StyleSpan(Typeface.BOLD);
|
||||
final StyleSpan italicSpan = new StyleSpan(Typeface.ITALIC);
|
||||
|
||||
public TermuxSessionsListViewController(TermuxActivity activity, List<TerminalSession> sessionList) {
|
||||
public TermuxSessionsListViewController(TermuxActivity activity, List<TermuxSession> sessionList) {
|
||||
super(activity.getApplicationContext(), R.layout.item_terminal_sessions_list, sessionList);
|
||||
this.mActivity = activity;
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public class TermuxSessionsListViewController extends ArrayAdapter<TerminalSessi
|
||||
|
||||
TextView sessionTitleView = sessionRowView.findViewById(R.id.session_title);
|
||||
|
||||
TerminalSession sessionAtRow = getItem(position);
|
||||
TerminalSession sessionAtRow = getItem(position).getTerminalSession();
|
||||
if (sessionAtRow == null) {
|
||||
sessionTitleView.setText("null session");
|
||||
return sessionRowView;
|
||||
@@ -91,16 +91,16 @@ public class TermuxSessionsListViewController extends ArrayAdapter<TerminalSessi
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
TerminalSession clickedSession = getItem(position);
|
||||
mActivity.getTermuxSessionClient().setCurrentSession(clickedSession);
|
||||
TermuxSession clickedSession = getItem(position);
|
||||
mActivity.getTermuxSessionClient().setCurrentSession(clickedSession.getTerminalSession());
|
||||
mActivity.getDrawer().closeDrawers();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
final TerminalSession selectedSession = getItem(position);
|
||||
mActivity.getTermuxSessionClient().renameSession(selectedSession);
|
||||
final TermuxSession selectedSession = getItem(position);
|
||||
mActivity.getTermuxSessionClient().renameSession(selectedSession.getTerminalSession());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,6 @@ import android.widget.Toast;
|
||||
|
||||
import com.termux.R;
|
||||
import com.termux.app.TermuxActivity;
|
||||
import com.termux.app.TermuxService;
|
||||
import com.termux.app.terminal.io.KeyboardShortcut;
|
||||
import com.termux.app.terminal.io.extrakeys.ExtraKeysView;
|
||||
import com.termux.app.settings.properties.TermuxPropertyConstants;
|
||||
@@ -135,10 +134,8 @@ public class TermuxViewClient implements TerminalViewClient {
|
||||
} else if (unicodeChar == '-') {
|
||||
changeFontSize(false);
|
||||
} else if (unicodeChar >= '1' && unicodeChar <= '9') {
|
||||
int num = unicodeChar - '1';
|
||||
TermuxService service = mActivity.getTermuxService();
|
||||
if (service.getSessions().size() > num)
|
||||
mTermuxSessionClient.setCurrentSession(service.getSessions().get(num));
|
||||
int index = unicodeChar - '1';
|
||||
mTermuxSessionClient.switchToSession(index);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
Reference in New Issue
Block a user