Skip to content

Commit

Permalink
Refactor TermuxActivity
Browse files Browse the repository at this point in the history
This commit majorly refactors `TermuxActivity` and moves its view components and functions into dedicated classes.

- The view layouts and ids have been given meaningful names, like `termux_activity.xml`.
- The `TerminalToolbarViewPager` class has been created to handle the now called toolbar that shows on the bottom of the terminal view. It currently contains extra keys view defined by `terminal_toolbar_extra_keys_view.xml` file and a text input view defined by `terminal_toolbar_text_input_view.xml` file when user can switch to by swiping left. The input text will now be preserved if android destroys the activity or its recreated.
- The `TermuxSessionsListViewController` class has been created to handle view related functionality of the termux sessions list shown in the left drawer, namely view creation, `onItemClick()`, `onItemLongClick()`, etc. Its list view is defined by `termux_activity.xml` file and each item's layout is defined by the `terminal_sessions_list_item.xml` file.
- The `TextDataUtils` class has been added to the `com.termux.app.utils` package for text utils.
- The design for the `SessionChangedCallback` interface for `TerminalSession` has been majorly changed. Firstly, it has been renamed and moved from `TerminalSession` to the dedicated `TerminalSessionClient` class file. The interface now also supports the termux app centralized logging framework so that `TerminalSession` and `TerminalEmulator` can use them. Previously, `TermuxService` was implementing a wrapper interface, which would then call the real interface defined by the `TermuxActivity` if it was currently bound to the service. This cluttered and partially duplicated the code. Now, the implementation is defined by the `TermuxSessionClientBase` and `TermuxSessionClient` classes. The `TermuxSessionClientBase` implements the `TerminalSessionClient` interface but the definition of the activity related functions do not do anything, only the background ones like the logging functions are fully implemented. The `TermuxSessionClient` class inherits from the `TermuxSessionClientBase` class and provides the implementation for the activity related functions. The design for how this works is that if the `TermuxService` is not bound to `TermuxActivity`, it just passes the `TermuxSessionClientBase` implementation to `TerminalSession`. If the activity is bound at some point, then in `onServiceConnected()` it replaces/updates the client objects stored in `TerminalSession` and `TerminalEmulator` with `TermuxSessionClient`, and then replaces them back with `TermuxSessionClientBase` in `onDestroy()`. This seems to be working for now without an issue.
  • Loading branch information
agnostic-apollo committed Mar 16, 2021
1 parent 5e0b29b commit c9e18e5
Show file tree
Hide file tree
Showing 19 changed files with 1,631 additions and 970 deletions.
1,221 changes: 426 additions & 795 deletions app/src/main/java/com/termux/app/TermuxActivity.java

Large diffs are not rendered by default.

88 changes: 56 additions & 32 deletions app/src/main/java/com/termux/app/TermuxService.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@
import com.termux.app.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY;
import com.termux.app.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
import com.termux.app.settings.preferences.TermuxSharedPreferences;
import com.termux.app.terminal.TermuxSessionClient;
import com.termux.app.terminal.TermuxSessionClientBase;
import com.termux.app.utils.Logger;
import com.termux.terminal.TerminalEmulator;
import com.termux.terminal.TerminalSession;
import com.termux.terminal.TerminalSession.SessionChangedCallback;
import com.termux.terminal.TerminalSessionClient;

import java.io.File;
import java.util.ArrayList;
Expand All @@ -44,13 +47,11 @@
* Optionally may hold a wake and a wifi lock, in which case that is shown in the notification - see
* {@link #buildNotification()}.
*/
public final class TermuxService extends Service implements SessionChangedCallback {
public final class TermuxService extends Service {

private static final String NOTIFICATION_CHANNEL_ID = "termux_notification_channel";
private static final int NOTIFICATION_ID = 1337;

private static final String LOG_TAG = "TermuxService";

/** This service is only bound from inside the same process and never uses IPC. */
class LocalBinder extends Binder {
public final TermuxService service = TermuxService.this;
Expand All @@ -63,15 +64,23 @@ class LocalBinder extends Binder {
/**
* The terminal sessions which this service manages.
* <p/>
* Note that this list is observed by {@link TermuxActivity#mListViewAdapter}, so any changes must be made on the UI
* 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<BackgroundJob> mBackgroundTasks = new ArrayList<>();

/** Note that the service may often outlive the activity, so need to clear this reference. */
SessionChangedCallback mSessionChangeCallback;
/** The full implementation of the {@link TerminalSessionClient} interface to be used by {@link TerminalSession}
* that holds activity references for activity related functions.
* Note that the service may often outlive the activity, so need to clear this reference.
*/
TermuxSessionClient mTermuxSessionClient;

/** The basic implementation of the {@link TerminalSessionClient} interface to be used by {@link TerminalSession}
* that does not hold activity references.
*/
final TermuxSessionClientBase mTermuxSessionClientBase = new TermuxSessionClientBase();;

/** The wake lock and wifi lock are always acquired and released together. */
private PowerManager.WakeLock mWakeLock;
Expand All @@ -80,6 +89,8 @@ class LocalBinder extends Binder {
/** If the user has executed the {@link TermuxConstants.TERMUX_APP.TERMUX_SERVICE#ACTION_STOP_SERVICE} intent. */
boolean mWantsToStop = false;

private static final String LOG_TAG = "TermuxService";

@SuppressLint("Wakelock")
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Expand Down Expand Up @@ -266,7 +277,7 @@ public List<TerminalSession> getSessions() {
return mTerminalSessions;
}

TerminalSession createTermSession(String executablePath, String[] arguments, String cwd, boolean failSafe) {
public TerminalSession createTermSession(String executablePath, String[] arguments, String cwd, boolean failSafe) {
TermuxConstants.TERMUX_HOME_DIR.mkdirs();

if (cwd == null || cwd.isEmpty()) cwd = TermuxConstants.TERMUX_HOME_DIR_PATH;
Expand Down Expand Up @@ -302,7 +313,7 @@ TerminalSession createTermSession(String executablePath, String[] arguments, Str
args[0] = processName;
if (processArgs.length > 1) System.arraycopy(processArgs, 1, args, 1, processArgs.length - 1);

TerminalSession session = new TerminalSession(executablePath, cwd, args, env, this);
TerminalSession session = new TerminalSession(executablePath, cwd, args, env, getTermuxSessionClient());
mTerminalSessions.add(session);
updateNotification();

Expand All @@ -327,35 +338,48 @@ public int removeTermSession(TerminalSession sessionToRemove) {
return indexOfRemoved;
}

@Override
public void onTitleChanged(TerminalSession changedSession) {
if (mSessionChangeCallback != null) mSessionChangeCallback.onTitleChanged(changedSession);
}

@Override
public void onSessionFinished(final TerminalSession finishedSession) {
if (mSessionChangeCallback != null)
mSessionChangeCallback.onSessionFinished(finishedSession);
/** 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
* callback is received, it should call {@link #setTermuxSessionClient} to set the
* {@link TermuxService#mTermuxSessionClient} so that further terminal sessions are directly
* passed the {@link TermuxSessionClient} object which fully implements the
* {@link TerminalSessionClient} interface.
*
* @return Returns the {@link TermuxSessionClient} if {@link TermuxActivity} has bound with
* {@link TermuxService}, otherwise {@link TermuxSessionClientBase}.
*/
public TermuxSessionClientBase getTermuxSessionClient() {
if (mTermuxSessionClient != null)
return mTermuxSessionClient;
else
return mTermuxSessionClientBase;
}

@Override
public void onTextChanged(TerminalSession changedSession) {
if (mSessionChangeCallback != null) mSessionChangeCallback.onTextChanged(changedSession);
}
/** This should be called when {@link TermuxActivity#onServiceConnected} is called to set the
* {@link TermuxService#mTermuxSessionClient} variable and update the {@link TerminalSession}
* and {@link TerminalEmulator} clients in case they were passed {@link TermuxSessionClientBase}
* earlier.
*
* @param termuxSessionClient The {@link TermuxSessionClient} object that fully
* implements the {@link TerminalSessionClient} interface.
*/
public void setTermuxSessionClient(TermuxSessionClient termuxSessionClient) {
mTermuxSessionClient = termuxSessionClient;

@Override
public void onClipboardText(TerminalSession session, String text) {
if (mSessionChangeCallback != null) mSessionChangeCallback.onClipboardText(session, text);
for (int i = 0; i < mTerminalSessions.size(); i++)
mTerminalSessions.get(i).updateTerminalSessionClient(mTermuxSessionClient);
}

@Override
public void onBell(TerminalSession session) {
if (mSessionChangeCallback != null) mSessionChangeCallback.onBell(session);
}
/** This should be called when {@link TermuxActivity} has been destroyed so that the
* {@link TermuxService} and {@link TerminalSession} and {@link TerminalEmulator} clients do not
* hold an activity references.
*/
public void unsetTermuxSessionClient() {
mTermuxSessionClient = null;

@Override
public void onColorsChanged(TerminalSession session) {
if (mSessionChangeCallback != null) mSessionChangeCallback.onColorsChanged(session);
for (int i = 0; i < mTerminalSessions.size(); i++)
mTerminalSessions.get(i).updateTerminalSessionClient(mTermuxSessionClientBase);
}

public void onBackgroundJobExited(final BackgroundJob task) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
*/
public final class TermuxPreferenceConstants {

/** Defines the key for whether to show extra keys in termux terminal view */
public static final String KEY_SHOW_EXTRA_KEYS = "show_extra_keys";
public static final boolean DEFAULT_VALUE_SHOW_EXTRA_KEYS = true;
/** Defines the key for whether to show terminal toolbar containing extra keys and text input field */
public static final String KEY_SHOW_TERMINAL_TOOLBAR = "show_extra_keys";
public static final boolean DEFAULT_VALUE_SHOW_TERMINAL_TOOLBAR = true;



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,17 @@ private static SharedPreferences getSharedPreferences(Context context) {



public boolean getShowExtraKeys() {
return mSharedPreferences.getBoolean(TermuxPreferenceConstants.KEY_SHOW_EXTRA_KEYS, TermuxPreferenceConstants.DEFAULT_VALUE_SHOW_EXTRA_KEYS);
public boolean getShowTerminalToolbar() {
return mSharedPreferences.getBoolean(TermuxPreferenceConstants.KEY_SHOW_TERMINAL_TOOLBAR, TermuxPreferenceConstants.DEFAULT_VALUE_SHOW_TERMINAL_TOOLBAR);
}

public void setShowExtraKeys(boolean value) {
mSharedPreferences.edit().putBoolean(TermuxPreferenceConstants.KEY_SHOW_EXTRA_KEYS, value).apply();
public void setShowTerminalToolbar(boolean value) {
mSharedPreferences.edit().putBoolean(TermuxPreferenceConstants.KEY_SHOW_TERMINAL_TOOLBAR, value).apply();
}

public boolean toggleShowExtraKeys() {
boolean currentValue = getShowExtraKeys();
setShowExtraKeys(!currentValue);
public boolean toogleShowTerminalToolbar() {
boolean currentValue = getShowTerminalToolbar();
setShowTerminalToolbar(!currentValue);
return !currentValue;
}

Expand Down Expand Up @@ -108,13 +108,6 @@ public void changeFontSize(Context context, boolean increase) {
setFontSize(Integer.toString(fontSize));
}

/**
* If value is not in the range [min, max], set it to either min or max.
*/
static int clamp(int value, int min, int max) {
return Math.min(Math.max(value, min), max);
}



public String getCurrentSession() {
Expand Down Expand Up @@ -152,4 +145,13 @@ public void setTerminalViewKeyLoggingEnabled(boolean value) {
mSharedPreferences.edit().putBoolean(TermuxPreferenceConstants.KEY_TERMINAL_VIEW_KEY_LOGGING_ENABLED, value).apply();
}



/**
* If value is not in the range [min, max], set it to either min or max.
*/
static int clamp(int value, int min, int max) {
return Math.min(Math.max(value, min), max);
}

}
Loading

0 comments on commit c9e18e5

Please sign in to comment.