diff --git a/app/src/main/java/com/termux/app/TermuxService.java b/app/src/main/java/com/termux/app/TermuxService.java
index 5cac2719d0..fe7abe74fa 100644
--- a/app/src/main/java/com/termux/app/TermuxService.java
+++ b/app/src/main/java/com/termux/app/TermuxService.java
@@ -63,12 +63,15 @@ class LocalBinder extends Binder {
/**
* The terminal 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()} }.
+ * 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 mTerminalSessions = new ArrayList<>();
+ /**
+ * The background jobs which this service manages.
+ */
final List mBackgroundTasks = new ArrayList<>();
/** The full implementation of the {@link TerminalSessionClient} interface to be used by {@link TerminalSession}
@@ -86,89 +89,49 @@ class LocalBinder extends Binder {
private PowerManager.WakeLock mWakeLock;
private WifiManager.WifiLock mWifiLock;
- /** If the user has executed the {@link TermuxConstants.TERMUX_APP.TERMUX_SERVICE#ACTION_STOP_SERVICE} intent. */
+ /** If the user has executed the {@link TERMUX_SERVICE#ACTION_STOP_SERVICE} intent. */
boolean mWantsToStop = false;
private static final String LOG_TAG = "TermuxService";
+ @Override
+ public void onCreate() {
+ Logger.logVerbose(LOG_TAG, "onCreate");
+ runStartForeground();
+ }
+
@SuppressLint("Wakelock")
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- String action = intent.getAction();
- if (TERMUX_SERVICE.ACTION_STOP_SERVICE.equals(action)) {
- mWantsToStop = true;
- for (int i = 0; i < mTerminalSessions.size(); i++)
- mTerminalSessions.get(i).finishIfRunning();
- stopSelf();
- } else if (TERMUX_SERVICE.ACTION_WAKE_LOCK.equals(action)) {
- if (mWakeLock == null) {
- PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TermuxConstants.TERMUX_APP_NAME.toLowerCase() + ":service-wakelock");
- mWakeLock.acquire();
-
- // http://tools.android.com/tech-docs/lint-in-studio-2-3#TOC-WifiManager-Leak
- WifiManager wm = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
- mWifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, TermuxConstants.TERMUX_APP_NAME.toLowerCase());
- mWifiLock.acquire();
-
- String packageName = getPackageName();
- if (!pm.isIgnoringBatteryOptimizations(packageName)) {
- Intent whitelist = new Intent();
- whitelist.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
- whitelist.setData(Uri.parse("package:" + packageName));
- whitelist.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- try {
- startActivity(whitelist);
- } catch (ActivityNotFoundException e) {
- Logger.logStackTraceWithMessage(LOG_TAG, "Failed to call ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS", e);
- }
- }
-
- updateNotification();
- }
- } else if (TERMUX_SERVICE.ACTION_WAKE_UNLOCK.equals(action)) {
- if (mWakeLock != null) {
- mWakeLock.release();
- mWakeLock = null;
+ Logger.logDebug(LOG_TAG, "onStartCommand");
- mWifiLock.release();
- mWifiLock = null;
-
- updateNotification();
- }
- } else if (TERMUX_SERVICE.ACTION_SERVICE_EXECUTE.equals(action)) {
- Uri executableUri = intent.getData();
- String executablePath = (executableUri == null ? null : executableUri.getPath());
-
- String[] arguments = (executableUri == null ? null : intent.getStringArrayExtra(TERMUX_SERVICE.EXTRA_ARGUMENTS));
- String cwd = intent.getStringExtra(TERMUX_SERVICE.EXTRA_WORKDIR);
-
- if (intent.getBooleanExtra(TERMUX_SERVICE.EXTRA_BACKGROUND, false)) {
- BackgroundJob task = new BackgroundJob(cwd, executablePath, arguments, this, intent.getParcelableExtra("pendingIntent"));
- mBackgroundTasks.add(task);
- updateNotification();
- } else {
- boolean failsafe = intent.getBooleanExtra(TERMUX_ACTIVITY.ACTION_FAILSAFE_SESSION, false);
- TerminalSession newSession = createTermSession(executablePath, arguments, cwd, failsafe);
-
- // Transform executable path to session name, e.g. "/bin/do-something.sh" => "do something.sh".
- if (executablePath != null) {
- int lastSlash = executablePath.lastIndexOf('/');
- String name = (lastSlash == -1) ? executablePath : executablePath.substring(lastSlash + 1);
- name = name.replace('-', ' ');
- newSession.mSessionName = name;
- }
+ // Run again in case service is already started and onCreate() is not called
+ runStartForeground();
- // Make the newly created session the current one to be displayed:
- TermuxAppSharedPreferences preferences = new TermuxAppSharedPreferences(this);
- preferences.setCurrentSession(newSession.mHandle);
+ String action = intent.getAction();
- // Launch the main Termux app, which will now show the current session:
- startActivity(new Intent(this, TermuxActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ if (action != null) {
+ switch (action) {
+ case TERMUX_SERVICE.ACTION_STOP_SERVICE:
+ Logger.logDebug(LOG_TAG, "ACTION_STOP_SERVICE intent received");
+ actionStopService();
+ break;
+ case TERMUX_SERVICE.ACTION_WAKE_LOCK:
+ Logger.logDebug(LOG_TAG, "ACTION_WAKE_LOCK intent received");
+ actionAcquireWakeLock();
+ break;
+ case TERMUX_SERVICE.ACTION_WAKE_UNLOCK:
+ Logger.logDebug(LOG_TAG, "ACTION_WAKE_UNLOCK intent received");
+ actionReleaseWakeLock(true);
+ break;
+ case TERMUX_SERVICE.ACTION_SERVICE_EXECUTE:
+ Logger.logDebug(LOG_TAG, "ACTION_SERVICE_EXECUTE intent received");
+ actionServiceExecute(intent);
+ break;
+ default:
+ Logger.logError(LOG_TAG, "Invalid action: \"" + action + "\"");
+ break;
}
- } else if (action != null) {
- Logger.logError(LOG_TAG, "Unknown TermuxService action: '" + action + "'");
}
// If this service really do get killed, there is no point restarting it automatically - let the user do on next
@@ -176,108 +139,194 @@ public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_NOT_STICKY;
}
+ @Override
+ public void onDestroy() {
+ Logger.logVerbose(LOG_TAG, "onDestroy");
+ File termuxTmpDir = TermuxConstants.TERMUX_TMP_DIR;
+
+ if (termuxTmpDir.exists()) {
+ try {
+ TermuxInstaller.deleteFolder(termuxTmpDir.getCanonicalFile());
+ } catch (Exception e) {
+ Logger.logStackTraceWithMessage(LOG_TAG, "Error while removing file at " + termuxTmpDir.getAbsolutePath(), e);
+ }
+
+ termuxTmpDir.mkdirs();
+ }
+
+ actionReleaseWakeLock(false);
+ finishAllTerminalSessions();
+ runStopForeground();
+ }
+
@Override
public IBinder onBind(Intent intent) {
+ Logger.logVerbose(LOG_TAG, "onBind");
return mBinder;
}
@Override
- public void onCreate() {
+ public boolean onUnbind(Intent intent) {
+ Logger.logVerbose(LOG_TAG, "onUnbind");
+
+ // Since we cannot rely on {@link TermuxActivity.onDestroy()} to always complete,
+ // we unset clients here as well if it failed, so that we do not leave service and session
+ // clients with references to the activity.
+ if(mTermuxSessionClient != null)
+ unsetTermuxSessionClient();
+ return false;
+ }
+
+ /** Make service run in foreground mode. */
+ private void runStartForeground() {
setupNotificationChannel();
startForeground(NOTIFICATION_ID, buildNotification());
}
- /** Update the shown foreground service notification after making any changes that affect it. */
- void updateNotification() {
- if (mWakeLock == null && mTerminalSessions.isEmpty() && mBackgroundTasks.isEmpty()) {
- // Exit if we are updating after the user disabled all locks with no sessions or tasks running.
- stopSelf();
+ /** Make service leave foreground mode. */
+ private void runStopForeground() {
+ stopForeground(true);
+ }
+
+ /** Request to stop service. */
+ private void requestStopService() {
+ Logger.logDebug(LOG_TAG, "Requesting to stop service");
+ runStopForeground();
+ stopSelf();
+ }
+
+
+
+ /** Process action to stop service. */
+ private void actionStopService() {
+ mWantsToStop = true;
+ finishAllTerminalSessions();
+ requestStopService();
+ }
+
+ /** Process action to acquire Power and Wi-Fi WakeLocks. */
+ @SuppressLint({"WakelockTimeout", "BatteryLife"})
+ private void actionAcquireWakeLock() {
+ if (mWakeLock == null) {
+ Logger.logDebug(LOG_TAG, "Acquiring WakeLocks");
+
+ PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TermuxConstants.TERMUX_APP_NAME.toLowerCase() + ":service-wakelock");
+ mWakeLock.acquire();
+
+ // http://tools.android.com/tech-docs/lint-in-studio-2-3#TOC-WifiManager-Leak
+ WifiManager wm = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
+ mWifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, TermuxConstants.TERMUX_APP_NAME.toLowerCase());
+ mWifiLock.acquire();
+
+ String packageName = getPackageName();
+ if (!pm.isIgnoringBatteryOptimizations(packageName)) {
+ Intent whitelist = new Intent();
+ whitelist.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
+ whitelist.setData(Uri.parse("package:" + packageName));
+ whitelist.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ try {
+ startActivity(whitelist);
+ } catch (ActivityNotFoundException e) {
+ Logger.logStackTraceWithMessage(LOG_TAG, "Failed to call ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS", e);
+ }
+ }
+
+ updateNotification();
+
+ Logger.logDebug(LOG_TAG, "WakeLocks acquired successfully");
} else {
- ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, buildNotification());
+ Logger.logDebug(LOG_TAG, "Ignoring acquiring WakeLocks since they are already held");
}
}
- private Notification buildNotification() {
- Intent notifyIntent = new Intent(this, TermuxActivity.class);
- // PendingIntent#getActivity(): "Note that the activity will be started outside of the context of an existing
- // activity, so you must use the Intent.FLAG_ACTIVITY_NEW_TASK launch flag in the Intent":
- notifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifyIntent, 0);
+ /** Process action to release Power and Wi-Fi WakeLocks. */
+ private void actionReleaseWakeLock(boolean updateNotification) {
+ if (mWakeLock == null && mWifiLock == null){
+ Logger.logDebug(LOG_TAG, "Ignoring releasing WakeLocks since none are already held");
+ return;
+ }
- int sessionCount = mTerminalSessions.size();
- int taskCount = mBackgroundTasks.size();
- String contentText = sessionCount + " session" + (sessionCount == 1 ? "" : "s");
- if (taskCount > 0) {
- contentText += ", " + taskCount + " task" + (taskCount == 1 ? "" : "s");
+ Logger.logDebug(LOG_TAG, "Releasing WakeLocks");
+
+ if (mWakeLock != null) {
+ mWakeLock.release();
+ mWakeLock = null;
}
- final boolean wakeLockHeld = mWakeLock != null;
- if (wakeLockHeld) contentText += " (wake lock held)";
+ if (mWifiLock != null) {
+ mWifiLock.release();
+ mWifiLock = null;
+ }
- Notification.Builder builder = new Notification.Builder(this);
- builder.setContentTitle(getText(R.string.application_name));
- builder.setContentText(contentText);
- builder.setSmallIcon(R.drawable.ic_service_notification);
- builder.setContentIntent(pendingIntent);
- builder.setOngoing(true);
+ if(updateNotification)
+ updateNotification();
- // If holding a wake or wifi lock consider the notification of high priority since it's using power,
- // otherwise use a low priority
- builder.setPriority((wakeLockHeld) ? Notification.PRIORITY_HIGH : Notification.PRIORITY_LOW);
+ Logger.logDebug(LOG_TAG, "WakeLocks released successfully");
+ }
- // No need to show a timestamp:
- builder.setShowWhen(false);
+ /** Process action to execute a shell command in a foreground session or in background. */
+ private void actionServiceExecute(Intent intent) {
+ Uri executableUri = intent.getData();
+ String executablePath = (executableUri == null ? null : executableUri.getPath());
- // Background color for small notification icon:
- builder.setColor(0xFF607D8B);
+ String[] arguments = (executableUri == null ? null : intent.getStringArrayExtra(TERMUX_SERVICE.EXTRA_ARGUMENTS));
+ String cwd = intent.getStringExtra(TERMUX_SERVICE.EXTRA_WORKDIR);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- builder.setChannelId(NOTIFICATION_CHANNEL_ID);
+ PendingIntent pendingIntent = intent.getParcelableExtra(TERMUX_SERVICE.EXTRA_PENDING_INTENT);
+
+ if (intent.getBooleanExtra(TERMUX_SERVICE.EXTRA_BACKGROUND, false)) {
+ executeBackgroundCommand(executablePath, arguments, cwd, pendingIntent);
+ } else {
+ executeForegroundCommand(intent, executablePath, arguments, cwd);
}
+ }
- Resources res = getResources();
- Intent exitIntent = new Intent(this, TermuxService.class).setAction(TERMUX_SERVICE.ACTION_STOP_SERVICE);
- builder.addAction(android.R.drawable.ic_delete, res.getString(R.string.notification_action_exit), PendingIntent.getService(this, 0, exitIntent, 0));
+ /** Execute a shell command in background with {@link BackgroundJob}. */
+ private void executeBackgroundCommand(String executablePath, String[] arguments, String cwd, PendingIntent pendingIntent) {
+ Logger.logDebug(LOG_TAG, "Starting background command");
- String newWakeAction = wakeLockHeld ? TERMUX_SERVICE.ACTION_WAKE_UNLOCK : TERMUX_SERVICE.ACTION_WAKE_LOCK;
- Intent toggleWakeLockIntent = new Intent(this, TermuxService.class).setAction(newWakeAction);
- String actionTitle = res.getString(wakeLockHeld ?
- R.string.notification_action_wake_unlock :
- R.string.notification_action_wake_lock);
- int actionIcon = wakeLockHeld ? android.R.drawable.ic_lock_idle_lock : android.R.drawable.ic_lock_lock;
- builder.addAction(actionIcon, actionTitle, PendingIntent.getService(this, 0, toggleWakeLockIntent, 0));
+ BackgroundJob task = new BackgroundJob(cwd, executablePath, arguments, this, pendingIntent);
+ mBackgroundTasks.add(task);
+ updateNotification();
+ }
- return builder.build();
+ /** Callback received when a {@link BackgroundJob} finishes. */
+ public void onBackgroundJobExited(final BackgroundJob task) {
+ mHandler.post(() -> {
+ mBackgroundTasks.remove(task);
+ updateNotification();
+ });
}
- @Override
- public void onDestroy() {
- File termuxTmpDir = TermuxConstants.TERMUX_TMP_DIR;
+ /** Execute a shell command in a foreground terminal session. */
+ private void executeForegroundCommand(Intent intent, String executablePath, String[] arguments, String cwd) {
+ Logger.logDebug(LOG_TAG, "Starting foreground command");
- if (termuxTmpDir.exists()) {
- try {
- TermuxInstaller.deleteFolder(termuxTmpDir.getCanonicalFile());
- } catch (Exception e) {
- Logger.logStackTraceWithMessage(LOG_TAG, "Error while removing file at " + termuxTmpDir.getAbsolutePath(), e);
- }
+ boolean failsafe = intent.getBooleanExtra(TERMUX_ACTIVITY.ACTION_FAILSAFE_SESSION, false);
+ TerminalSession newSession = createTerminalSession(executablePath, arguments, cwd, failsafe);
- termuxTmpDir.mkdirs();
+ // Transform executable path to session name, e.g. "/bin/do-something.sh" => "do something.sh".
+ if (executablePath != null) {
+ int lastSlash = executablePath.lastIndexOf('/');
+ String name = (lastSlash == -1) ? executablePath : executablePath.substring(lastSlash + 1);
+ name = name.replace('-', ' ');
+ newSession.mSessionName = name;
}
- if (mWakeLock != null) mWakeLock.release();
- if (mWifiLock != null) mWifiLock.release();
-
- stopForeground(true);
+ // Make the newly created session the current one to be displayed:
+ TermuxAppSharedPreferences preferences = new TermuxAppSharedPreferences(this);
+ preferences.setCurrentSession(newSession.mHandle);
- for (int i = 0; i < mTerminalSessions.size(); i++)
- mTerminalSessions.get(i).finishIfRunning();
+ // Launch the main Termux app, which will now show the current session:
+ startActivity(new Intent(this, TermuxActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
- public List getSessions() {
- return mTerminalSessions;
- }
- public TerminalSession createTermSession(String executablePath, String[] arguments, String cwd, boolean failSafe) {
+
+ /** Create a terminal session. */
+ public TerminalSession createTerminalSession(String executablePath, String[] arguments, String cwd, boolean failSafe) {
TermuxConstants.TERMUX_HOME_DIR.mkdirs();
if (cwd == null || cwd.isEmpty()) cwd = TermuxConstants.TERMUX_HOME_DIR_PATH;
@@ -325,19 +374,29 @@ public TerminalSession createTermSession(String executablePath, String[] argumen
return session;
}
- public int removeTermSession(TerminalSession sessionToRemove) {
+ /** 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.
- stopSelf();
+ 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
@@ -371,22 +430,70 @@ public void setTermuxSessionClient(TermuxSessionClient termuxSessionClient) {
mTerminalSessions.get(i).updateTerminalSessionClient(mTermuxSessionClient);
}
- /** 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.
+ /** 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() {
- mTermuxSessionClient = null;
-
for (int i = 0; i < mTerminalSessions.size(); i++)
mTerminalSessions.get(i).updateTerminalSessionClient(mTermuxSessionClientBase);
+
+ mTermuxSessionClient = null;
}
- public void onBackgroundJobExited(final BackgroundJob task) {
- mHandler.post(() -> {
- mBackgroundTasks.remove(task);
- updateNotification();
- });
+
+
+ private Notification buildNotification() {
+ Intent notifyIntent = new Intent(this, TermuxActivity.class);
+ // PendingIntent#getActivity(): "Note that the activity will be started outside of the context of an existing
+ // activity, so you must use the Intent.FLAG_ACTIVITY_NEW_TASK launch flag in the Intent":
+ notifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifyIntent, 0);
+
+ int sessionCount = mTerminalSessions.size();
+ int taskCount = mBackgroundTasks.size();
+ String contentText = sessionCount + " session" + (sessionCount == 1 ? "" : "s");
+ if (taskCount > 0) {
+ contentText += ", " + taskCount + " task" + (taskCount == 1 ? "" : "s");
+ }
+
+ final boolean wakeLockHeld = mWakeLock != null;
+ if (wakeLockHeld) contentText += " (wake lock held)";
+
+ Notification.Builder builder = new Notification.Builder(this);
+ builder.setContentTitle(getText(R.string.application_name));
+ builder.setContentText(contentText);
+ builder.setSmallIcon(R.drawable.ic_service_notification);
+ builder.setContentIntent(pendingIntent);
+ builder.setOngoing(true);
+
+ // If holding a wake or wifi lock consider the notification of high priority since it's using power,
+ // otherwise use a low priority
+ builder.setPriority((wakeLockHeld) ? Notification.PRIORITY_HIGH : Notification.PRIORITY_LOW);
+
+ // No need to show a timestamp:
+ builder.setShowWhen(false);
+
+ // Background color for small notification icon:
+ builder.setColor(0xFF607D8B);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ builder.setChannelId(NOTIFICATION_CHANNEL_ID);
+ }
+
+ Resources res = getResources();
+ Intent exitIntent = new Intent(this, TermuxService.class).setAction(TERMUX_SERVICE.ACTION_STOP_SERVICE);
+ builder.addAction(android.R.drawable.ic_delete, res.getString(R.string.notification_action_exit), PendingIntent.getService(this, 0, exitIntent, 0));
+
+ String newWakeAction = wakeLockHeld ? TERMUX_SERVICE.ACTION_WAKE_UNLOCK : TERMUX_SERVICE.ACTION_WAKE_LOCK;
+ Intent toggleWakeLockIntent = new Intent(this, TermuxService.class).setAction(newWakeAction);
+ String actionTitle = res.getString(wakeLockHeld ?
+ R.string.notification_action_wake_unlock :
+ R.string.notification_action_wake_lock);
+ int actionIcon = wakeLockHeld ? android.R.drawable.ic_lock_idle_lock : android.R.drawable.ic_lock_lock;
+ builder.addAction(actionIcon, actionTitle, PendingIntent.getService(this, 0, toggleWakeLockIntent, 0));
+
+ return builder.build();
}
private void setupNotificationChannel() {
@@ -402,7 +509,24 @@ private void setupNotificationChannel() {
manager.createNotificationChannel(channel);
}
+ /** Update the shown foreground service notification after making any changes that affect it. */
+ void updateNotification() {
+ if (mWakeLock == null && mTerminalSessions.isEmpty() && mBackgroundTasks.isEmpty()) {
+ // Exit if we are updating after the user disabled all locks with no sessions or tasks running.
+ requestStopService();
+ } else {
+ ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, buildNotification());
+ }
+ }
+
+
+
public boolean wantsToStop() {
return mWantsToStop;
}
+
+ public List getSessions() {
+ return mTerminalSessions;
+ }
+
}
diff --git a/app/src/main/java/com/termux/app/terminal/TermuxSessionClient.java b/app/src/main/java/com/termux/app/terminal/TermuxSessionClient.java
index 6222b0aa92..7997277367 100644
--- a/app/src/main/java/com/termux/app/terminal/TermuxSessionClient.java
+++ b/app/src/main/java/com/termux/app/terminal/TermuxSessionClient.java
@@ -153,9 +153,10 @@ void noteSessionInfo() {
final int indexOfSession = mActivity.getTermuxService().getSessions().indexOf(session);
mActivity.showToast(toToastTitle(session), false);
mActivity.terminalSessionListNotifyUpdated();
- final ListView lv = mActivity.findViewById(R.id.terminal_sessions_list);
- lv.setItemChecked(indexOfSession, true);
- lv.smoothScrollToPosition(indexOfSession);
+
+ final ListView termuxSessionsListView = mActivity.findViewById(R.id.terminal_sessions_list);
+ termuxSessionsListView.setItemChecked(indexOfSession, true);
+ termuxSessionsListView.smoothScrollToPosition(indexOfSession);
}
public void switchToSession(boolean forward) {
@@ -195,7 +196,7 @@ public void addNewSession(boolean failSafe, String sessionName) {
workingDirectory = currentSession.getCwd();
}
- TerminalSession newSession = mActivity.getTermuxService().createTermSession(null, null, workingDirectory, failSafe);
+ TerminalSession newSession = mActivity.getTermuxService().createTerminalSession(null, null, workingDirectory, failSafe);
if (sessionName != null) {
newSession.mSessionName = sessionName;
}
@@ -248,7 +249,7 @@ public void removeFinishedSession(TerminalSession finishedSession) {
// Return pressed with finished session - remove it.
TermuxService service = mActivity.getTermuxService();
- int index = service.removeTermSession(finishedSession);
+ int index = service.removeTerminalSession(finishedSession);
mActivity.terminalSessionListNotifyUpdated();
if (mActivity.getTermuxService().getSessions().isEmpty()) {
// There are no sessions to show, so finish the activity.