Skip to content

Commit c9e18e5

Browse files
Refactor TermuxActivity
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.
1 parent 5e0b29b commit c9e18e5

19 files changed

+1631
-970
lines changed

app/src/main/java/com/termux/app/TermuxActivity.java

Lines changed: 426 additions & 795 deletions
Large diffs are not rendered by default.

app/src/main/java/com/termux/app/TermuxService.java

Lines changed: 56 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@
2424
import com.termux.app.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY;
2525
import com.termux.app.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
2626
import com.termux.app.settings.preferences.TermuxSharedPreferences;
27+
import com.termux.app.terminal.TermuxSessionClient;
28+
import com.termux.app.terminal.TermuxSessionClientBase;
2729
import com.termux.app.utils.Logger;
30+
import com.termux.terminal.TerminalEmulator;
2831
import com.termux.terminal.TerminalSession;
29-
import com.termux.terminal.TerminalSession.SessionChangedCallback;
32+
import com.termux.terminal.TerminalSessionClient;
3033

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

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

52-
private static final String LOG_TAG = "TermuxService";
53-
5455
/** This service is only bound from inside the same process and never uses IPC. */
5556
class LocalBinder extends Binder {
5657
public final TermuxService service = TermuxService.this;
@@ -63,15 +64,23 @@ class LocalBinder extends Binder {
6364
/**
6465
* The terminal sessions which this service manages.
6566
* <p/>
66-
* Note that this list is observed by {@link TermuxActivity#mListViewAdapter}, so any changes must be made on the UI
67+
* Note that this list is observed by {@link TermuxActivity#mTermuxSessionListViewController}, so any changes must be made on the UI
6768
* thread and followed by a call to {@link ArrayAdapter#notifyDataSetChanged()} }.
6869
*/
6970
final List<TerminalSession> mTerminalSessions = new ArrayList<>();
7071

7172
final List<BackgroundJob> mBackgroundTasks = new ArrayList<>();
7273

73-
/** Note that the service may often outlive the activity, so need to clear this reference. */
74-
SessionChangedCallback mSessionChangeCallback;
74+
/** The full implementation of the {@link TerminalSessionClient} interface to be used by {@link TerminalSession}
75+
* that holds activity references for activity related functions.
76+
* Note that the service may often outlive the activity, so need to clear this reference.
77+
*/
78+
TermuxSessionClient mTermuxSessionClient;
79+
80+
/** The basic implementation of the {@link TerminalSessionClient} interface to be used by {@link TerminalSession}
81+
* that does not hold activity references.
82+
*/
83+
final TermuxSessionClientBase mTermuxSessionClientBase = new TermuxSessionClientBase();;
7584

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

92+
private static final String LOG_TAG = "TermuxService";
93+
8394
@SuppressLint("Wakelock")
8495
@Override
8596
public int onStartCommand(Intent intent, int flags, int startId) {
@@ -266,7 +277,7 @@ public List<TerminalSession> getSessions() {
266277
return mTerminalSessions;
267278
}
268279

269-
TerminalSession createTermSession(String executablePath, String[] arguments, String cwd, boolean failSafe) {
280+
public TerminalSession createTermSession(String executablePath, String[] arguments, String cwd, boolean failSafe) {
270281
TermuxConstants.TERMUX_HOME_DIR.mkdirs();
271282

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

305-
TerminalSession session = new TerminalSession(executablePath, cwd, args, env, this);
316+
TerminalSession session = new TerminalSession(executablePath, cwd, args, env, getTermuxSessionClient());
306317
mTerminalSessions.add(session);
307318
updateNotification();
308319

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

330-
@Override
331-
public void onTitleChanged(TerminalSession changedSession) {
332-
if (mSessionChangeCallback != null) mSessionChangeCallback.onTitleChanged(changedSession);
333-
}
334-
335-
@Override
336-
public void onSessionFinished(final TerminalSession finishedSession) {
337-
if (mSessionChangeCallback != null)
338-
mSessionChangeCallback.onSessionFinished(finishedSession);
341+
/** If {@link TermuxActivity} has not bound to the {@link TermuxService} yet or is destroyed, then
342+
* interface functions requiring the activity should not be available to the terminal sessions,
343+
* so we just return the {@link #mTermuxSessionClientBase}. Once {@link TermuxActivity} bind
344+
* callback is received, it should call {@link #setTermuxSessionClient} to set the
345+
* {@link TermuxService#mTermuxSessionClient} so that further terminal sessions are directly
346+
* passed the {@link TermuxSessionClient} object which fully implements the
347+
* {@link TerminalSessionClient} interface.
348+
*
349+
* @return Returns the {@link TermuxSessionClient} if {@link TermuxActivity} has bound with
350+
* {@link TermuxService}, otherwise {@link TermuxSessionClientBase}.
351+
*/
352+
public TermuxSessionClientBase getTermuxSessionClient() {
353+
if (mTermuxSessionClient != null)
354+
return mTermuxSessionClient;
355+
else
356+
return mTermuxSessionClientBase;
339357
}
340358

341-
@Override
342-
public void onTextChanged(TerminalSession changedSession) {
343-
if (mSessionChangeCallback != null) mSessionChangeCallback.onTextChanged(changedSession);
344-
}
359+
/** This should be called when {@link TermuxActivity#onServiceConnected} is called to set the
360+
* {@link TermuxService#mTermuxSessionClient} variable and update the {@link TerminalSession}
361+
* and {@link TerminalEmulator} clients in case they were passed {@link TermuxSessionClientBase}
362+
* earlier.
363+
*
364+
* @param termuxSessionClient The {@link TermuxSessionClient} object that fully
365+
* implements the {@link TerminalSessionClient} interface.
366+
*/
367+
public void setTermuxSessionClient(TermuxSessionClient termuxSessionClient) {
368+
mTermuxSessionClient = termuxSessionClient;
345369

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

351-
@Override
352-
public void onBell(TerminalSession session) {
353-
if (mSessionChangeCallback != null) mSessionChangeCallback.onBell(session);
354-
}
374+
/** This should be called when {@link TermuxActivity} has been destroyed so that the
375+
* {@link TermuxService} and {@link TerminalSession} and {@link TerminalEmulator} clients do not
376+
* hold an activity references.
377+
*/
378+
public void unsetTermuxSessionClient() {
379+
mTermuxSessionClient = null;
355380

356-
@Override
357-
public void onColorsChanged(TerminalSession session) {
358-
if (mSessionChangeCallback != null) mSessionChangeCallback.onColorsChanged(session);
381+
for (int i = 0; i < mTerminalSessions.size(); i++)
382+
mTerminalSessions.get(i).updateTerminalSessionClient(mTermuxSessionClientBase);
359383
}
360384

361385
public void onBackgroundJobExited(final BackgroundJob task) {

app/src/main/java/com/termux/app/settings/preferences/TermuxPreferenceConstants.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
*/
2727
public final class TermuxPreferenceConstants {
2828

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

3333

3434

app/src/main/java/com/termux/app/settings/preferences/TermuxSharedPreferences.java

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,17 @@ private static SharedPreferences getSharedPreferences(Context context) {
3333

3434

3535

36-
public boolean getShowExtraKeys() {
37-
return mSharedPreferences.getBoolean(TermuxPreferenceConstants.KEY_SHOW_EXTRA_KEYS, TermuxPreferenceConstants.DEFAULT_VALUE_SHOW_EXTRA_KEYS);
36+
public boolean getShowTerminalToolbar() {
37+
return mSharedPreferences.getBoolean(TermuxPreferenceConstants.KEY_SHOW_TERMINAL_TOOLBAR, TermuxPreferenceConstants.DEFAULT_VALUE_SHOW_TERMINAL_TOOLBAR);
3838
}
3939

40-
public void setShowExtraKeys(boolean value) {
41-
mSharedPreferences.edit().putBoolean(TermuxPreferenceConstants.KEY_SHOW_EXTRA_KEYS, value).apply();
40+
public void setShowTerminalToolbar(boolean value) {
41+
mSharedPreferences.edit().putBoolean(TermuxPreferenceConstants.KEY_SHOW_TERMINAL_TOOLBAR, value).apply();
4242
}
4343

44-
public boolean toggleShowExtraKeys() {
45-
boolean currentValue = getShowExtraKeys();
46-
setShowExtraKeys(!currentValue);
44+
public boolean toogleShowTerminalToolbar() {
45+
boolean currentValue = getShowTerminalToolbar();
46+
setShowTerminalToolbar(!currentValue);
4747
return !currentValue;
4848
}
4949

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

111-
/**
112-
* If value is not in the range [min, max], set it to either min or max.
113-
*/
114-
static int clamp(int value, int min, int max) {
115-
return Math.min(Math.max(value, min), max);
116-
}
117-
118111

119112

120113
public String getCurrentSession() {
@@ -152,4 +145,13 @@ public void setTerminalViewKeyLoggingEnabled(boolean value) {
152145
mSharedPreferences.edit().putBoolean(TermuxPreferenceConstants.KEY_TERMINAL_VIEW_KEY_LOGGING_ENABLED, value).apply();
153146
}
154147

148+
149+
150+
/**
151+
* If value is not in the range [min, max], set it to either min or max.
152+
*/
153+
static int clamp(int value, int min, int max) {
154+
return Math.min(Math.max(value, min), max);
155+
}
156+
155157
}

0 commit comments

Comments
 (0)