Create termux-shared library package for all termux constants and shared utils

The termux plugins should use this library instead of hardcoding "com.termux" values in their source code.

The library can be included as a dependency by plugins and third party apps by including the following line in the build.gradle where x.xxx is the version number, once its published.

`implementation 'com.termux:termux-shared:x.xxx'`

The `TermuxConstants` class has been updated to `v0.17.0`, `TermuxPreferenceConstants` to `v0.9.0` and `TermuxPropertyConstants` to `v0.6.0`. Check their Changelog sections for info on changes.

Some typos and redundant code has also been fixed.
This commit is contained in:
agnostic-apollo 2021-04-07 11:31:30 +05:00
parent c9a476caf7
commit 682ce08314
73 changed files with 746 additions and 520 deletions

View File

@ -2,8 +2,6 @@ plugins {
id "com.android.application"
}
ext.markwon_version='4.6.2'
android {
compileSdkVersion project.properties.compileSdkVersion.toInteger()
ndkVersion project.properties.ndkVersion
@ -15,16 +13,13 @@ android {
implementation "androidx.preference:preference:1.1.1"
implementation "androidx.viewpager:viewpager:1.0.0"
implementation "com.google.guava:guava:24.1-jre"
implementation "io.noties.markwon:core:$markwon_version"
implementation "io.noties.markwon:ext-strikethrough:$markwon_version"
implementation "io.noties.markwon:linkify:$markwon_version"
implementation "io.noties.markwon:recycler:$markwon_version"
implementation project(":terminal-view")
implementation "io.noties.markwon:core:$markwonVersion"
implementation "io.noties.markwon:ext-strikethrough:$markwonVersion"
implementation "io.noties.markwon:linkify:$markwonVersion"
implementation "io.noties.markwon:recycler:$markwonVersion"
// Do not increment version higher than 2.5 or there
// will be runtime exceptions on android < 8
// due to missing classes like java.nio.file.Path.
implementation "commons-io:commons-io:2.5"
implementation project(":terminal-view")
implementation project(":termux-shared")
}
defaultConfig {
@ -99,7 +94,7 @@ android {
}
dependencies {
testImplementation "junit:junit:4.13.1"
testImplementation "junit:junit:4.13.2"
testImplementation "org.robolectric:robolectric:4.4"
}

View File

@ -12,13 +12,14 @@ import android.os.Build;
import android.os.IBinder;
import com.termux.R;
import com.termux.app.TermuxConstants.TERMUX_APP.RUN_COMMAND_SERVICE;
import com.termux.app.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
import com.termux.app.file.FileUtils;
import com.termux.app.utils.Logger;
import com.termux.app.utils.NotificationUtils;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.RUN_COMMAND_SERVICE;
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
import com.termux.shared.file.FileUtils;
import com.termux.shared.logger.Logger;
import com.termux.shared.notification.NotificationUtils;
import com.termux.app.utils.PluginUtils;
import com.termux.app.utils.DataUtils;
import com.termux.shared.data.DataUtils;
import com.termux.app.models.ExecutionCommand;
/**
@ -269,10 +270,6 @@ import com.termux.app.models.ExecutionCommand;
*/
public class RunCommandService extends Service {
private static final String NOTIFICATION_CHANNEL_ID = "termux_run_command_notification_channel";
private static final String NOTIFICATION_CHANNEL_NAME = TermuxConstants.TERMUX_APP_NAME + " RunCommandService";
public static final int NOTIFICATION_ID = 1338;
private static final String LOG_TAG = "RunCommandService";
class LocalBinder extends Binder {
@ -296,7 +293,7 @@ public class RunCommandService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
Logger.logDebug(LOG_TAG, "onStartCommand");
if(intent == null) return Service.START_NOT_STICKY;;
if(intent == null) return Service.START_NOT_STICKY;
// Run again in case service is already started and onCreate() is not called
runStartForeground();
@ -421,7 +418,7 @@ public class RunCommandService extends Service {
private void runStartForeground() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setupNotificationChannel();
startForeground(NOTIFICATION_ID, buildNotification());
startForeground(TermuxConstants.TERMUX_RUN_COMMAND_NOTIFICATION_ID, buildNotification());
}
}
@ -434,8 +431,8 @@ public class RunCommandService extends Service {
private Notification buildNotification() {
// Build the notification
Notification.Builder builder = NotificationUtils.geNotificationBuilder(this,
NOTIFICATION_CHANNEL_ID, Notification.PRIORITY_LOW,
NOTIFICATION_CHANNEL_NAME, null, null,
TermuxConstants.TERMUX_RUN_COMMAND_NOTIFICATION_CHANNEL_ID, Notification.PRIORITY_LOW,
TermuxConstants.TERMUX_RUN_COMMAND_NOTIFICATION_CHANNEL_NAME, null, null,
null, NotificationUtils.NOTIFICATION_MODE_SILENT);
if(builder == null) return null;
@ -454,8 +451,8 @@ public class RunCommandService extends Service {
private void setupNotificationChannel() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
NotificationUtils.setupNotificationChannel(this, NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
NotificationUtils.setupNotificationChannel(this, TermuxConstants.TERMUX_RUN_COMMAND_NOTIFICATION_CHANNEL_ID,
TermuxConstants.TERMUX_RUN_COMMAND_NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
}
}

View File

@ -31,22 +31,23 @@ import android.widget.ListView;
import android.widget.Toast;
import com.termux.R;
import com.termux.app.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY;
import com.termux.app.activities.HelpActivity;
import com.termux.app.activities.SettingsActivity;
import com.termux.app.crash.CrashUtils;
import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
import com.termux.shared.settings.preferences.TermuxAppSharedPreferences;
import com.termux.app.terminal.TermuxSessionsListViewController;
import com.termux.app.terminal.io.TerminalToolbarViewPager;
import com.termux.app.terminal.TermuxSessionClient;
import com.termux.app.terminal.TermuxViewClient;
import com.termux.app.terminal.io.extrakeys.ExtraKeysView;
import com.termux.app.settings.properties.TermuxSharedProperties;
import com.termux.app.utils.DialogUtils;
import com.termux.app.utils.Logger;
import com.termux.app.utils.TermuxUtils;
import com.termux.app.settings.properties.TermuxAppSharedProperties;
import com.termux.shared.interact.DialogUtils;
import com.termux.shared.logger.Logger;
import com.termux.shared.termux.TermuxUtils;
import com.termux.terminal.TerminalSession;
import com.termux.terminal.TerminalSessionClient;
import com.termux.app.utils.CrashUtils;
import com.termux.view.TerminalView;
import com.termux.view.TerminalViewClient;
@ -101,7 +102,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
/**
* Termux app shared properties manager, loaded from termux.properties
*/
private TermuxSharedProperties mProperties;
private TermuxAppSharedProperties mProperties;
/**
* The terminal extra keys view.
@ -116,7 +117,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
/**
* The {@link TermuxActivity} broadcast receiver for various things like terminal style configuration changes.
*/
private final BroadcastReceiver mTermuxActivityBroadcastReceiever = new TermuxActivityBroadcastReceiever();
private final BroadcastReceiver mTermuxActivityBroadcastReceiever = new TermuxActivityBroadcastReceiver();
/**
* The last toast shown, used cancel current toast before showing new in {@link #showToast(String, boolean)}.
@ -161,7 +162,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
// Load termux shared preferences and properties
mPreferences = new TermuxAppSharedPreferences(this);
mProperties = new TermuxSharedProperties(this);
mProperties = new TermuxAppSharedProperties(this);
setActivityTheme();
@ -327,7 +328,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
}
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
saveTerminalToolbarTextInput(savedInstanceState);
}
@ -383,6 +384,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
if(terminalToolbarViewPager == null) return;
final boolean showNow = mPreferences.toogleShowTerminalToolbar();
Logger.showToast(this, (showNow ? getString(R.string.msg_enabling_terminal_toolbar) : getString(R.string.msg_disabling_terminal_toolbar)), true);
terminalToolbarViewPager.setVisibility(showNow ? View.VISIBLE : View.GONE);
if (showNow && terminalToolbarViewPager.getCurrentItem() == 1) {
// Focus the text input view if just revealed.
@ -704,7 +706,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
return mPreferences;
}
public TermuxSharedProperties getProperties() {
public TermuxAppSharedProperties getProperties() {
return mProperties;
}
@ -718,7 +720,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
context.sendBroadcast(stylingIntent);
}
class TermuxActivityBroadcastReceiever extends BroadcastReceiver {
class TermuxActivityBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (mIsVisible) {
@ -755,7 +757,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
// TermuxActivity.this.recreate();
}
}
};
}

View File

@ -2,9 +2,9 @@ package com.termux.app;
import android.app.Application;
import com.termux.app.crash.CrashHandler;
import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
import com.termux.app.utils.Logger;
import com.termux.shared.crash.CrashHandler;
import com.termux.shared.settings.preferences.TermuxAppSharedPreferences;
import com.termux.shared.logger.Logger;
public class TermuxApplication extends Application {
@ -19,7 +19,7 @@ public class TermuxApplication extends Application {
}
private void setLogLevel() {
// Load the log level from shared preferences and set it to the {@link Loggger.CURRENT_LOG_LEVEL}
// Load the log level from shared preferences and set it to the {@link Logger.CURRENT_LOG_LEVEL}
TermuxAppSharedPreferences preferences = new TermuxAppSharedPreferences(getApplicationContext());
preferences.setLogLevel(null, preferences.getLogLevel());
Logger.logDebug("Starting Application");

View File

@ -11,8 +11,9 @@ import android.util.Pair;
import android.view.WindowManager;
import com.termux.R;
import com.termux.app.file.FileUtils;
import com.termux.app.utils.Logger;
import com.termux.shared.file.FileUtils;
import com.termux.shared.logger.Logger;
import com.termux.shared.termux.TermuxConstants;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;

View File

@ -13,7 +13,8 @@ import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.webkit.MimeTypeMap;
import com.termux.app.utils.Logger;
import com.termux.shared.logger.Logger;
import com.termux.shared.termux.TermuxConstants;
import java.io.File;
import java.io.FileNotFoundException;

View File

@ -20,17 +20,18 @@ import android.provider.Settings;
import android.widget.ArrayAdapter;
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.shared.termux.TermuxConstants;
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY;
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
import com.termux.shared.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.NotificationUtils;
import com.termux.app.utils.PermissionUtils;
import com.termux.app.shell.ShellUtils;
import com.termux.app.utils.DataUtils;
import com.termux.shared.logger.Logger;
import com.termux.shared.notification.NotificationUtils;
import com.termux.shared.packages.PermissionUtils;
import com.termux.shared.shell.ShellUtils;
import com.termux.shared.data.DataUtils;
import com.termux.app.models.ExecutionCommand;
import com.termux.app.models.ExecutionCommand.ExecutionState;
import com.termux.app.terminal.TermuxTask;
@ -38,7 +39,6 @@ import com.termux.terminal.TerminalEmulator;
import com.termux.terminal.TerminalSession;
import com.termux.terminal.TerminalSessionClient;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
@ -58,10 +58,6 @@ import javax.annotation.Nullable;
*/
public final class TermuxService extends Service {
private static final String NOTIFICATION_CHANNEL_ID = "termux_notification_channel";
private static final String NOTIFICATION_CHANNEL_NAME = TermuxConstants.TERMUX_APP_NAME + " App";
public static final int NOTIFICATION_ID = 1337;
private static int EXECUTION_ID = 1000;
/** This service is only bound from inside the same process and never uses IPC. */
@ -95,7 +91,7 @@ public final class TermuxService extends Service {
/** 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();;
final TermuxSessionClientBase mTermuxSessionClientBase = new TermuxSessionClientBase();
/** The wake lock and wifi lock are always acquired and released together. */
private PowerManager.WakeLock mWakeLock;
@ -183,7 +179,7 @@ public final class TermuxService extends Service {
/** Make service run in foreground mode. */
private void runStartForeground() {
setupNotificationChannel();
startForeground(NOTIFICATION_ID, buildNotification());
startForeground(TermuxConstants.TERMUX_APP_NOTIFICATION_ID, buildNotification());
}
/** Make service leave foreground mode. */
@ -366,7 +362,7 @@ public final class TermuxService extends Service {
if (newTermuxTask == null) {
Logger.logError(LOG_TAG, "Failed to execute new termux task command for:\n" + executionCommand.getCommandIdAndLabelLogString());
return null;
};
}
mTermuxTasks.add(newTermuxTask);
@ -436,7 +432,7 @@ public final class TermuxService extends Service {
if (newTermuxSession == null) {
Logger.logError(LOG_TAG, "Failed to execute new termux session command for:\n" + executionCommand.getCommandIdAndLabelLogString());
return null;
};
}
mTermuxSessions.add(newTermuxSession);
@ -593,13 +589,13 @@ public final class TermuxService extends Service {
// Set notification text
int sessionCount = getTermuxSessionsSize();
int taskCount = mTermuxTasks.size();
String notifiationText = sessionCount + " session" + (sessionCount == 1 ? "" : "s");
String notificationText = sessionCount + " session" + (sessionCount == 1 ? "" : "s");
if (taskCount > 0) {
notifiationText += ", " + taskCount + " task" + (taskCount == 1 ? "" : "s");
notificationText += ", " + taskCount + " task" + (taskCount == 1 ? "" : "s");
}
final boolean wakeLockHeld = mWakeLock != null;
if (wakeLockHeld) notifiationText += " (wake lock held)";
if (wakeLockHeld) notificationText += " (wake lock held)";
// Set notification priority
@ -610,8 +606,8 @@ public final class TermuxService extends Service {
// Build the notification
Notification.Builder builder = NotificationUtils.geNotificationBuilder(this,
NOTIFICATION_CHANNEL_ID, priority,
getText(R.string.application_name), notifiationText, null,
TermuxConstants.TERMUX_APP_NOTIFICATION_CHANNEL_ID, priority,
getText(R.string.application_name), notificationText, null,
pendingIntent, NotificationUtils.NOTIFICATION_MODE_SILENT);
if(builder == null) return null;
@ -647,8 +643,8 @@ public final class TermuxService extends Service {
private void setupNotificationChannel() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
NotificationUtils.setupNotificationChannel(this, NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
NotificationUtils.setupNotificationChannel(this, TermuxConstants.TERMUX_APP_NOTIFICATION_CHANNEL_ID,
TermuxConstants.TERMUX_APP_NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
}
/** Update the shown foreground service notification after making any changes that affect it. */
@ -657,7 +653,7 @@ public final class TermuxService extends Service {
// 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());
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(TermuxConstants.TERMUX_APP_NOTIFICATION_ID, buildNotification());
}
}

View File

@ -15,9 +15,9 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import com.termux.R;
import com.termux.app.TermuxConstants;
import com.termux.app.utils.MarkdownUtils;
import com.termux.app.utils.ShareUtils;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.markdown.MarkdownUtils;
import com.termux.shared.interact.ShareUtils;
import com.termux.app.models.ReportInfo;
import org.commonmark.node.FencedCodeBlock;

View File

@ -1,34 +0,0 @@
package com.termux.app.crash;
import android.content.Context;
import androidx.annotation.NonNull;
/**
* Catches uncaught exceptions and logs them.
*/
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private final Context context;
private final Thread.UncaughtExceptionHandler defaultUEH;
private CrashHandler(final Context context) {
this.context = context;
this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
}
public void uncaughtException(@NonNull Thread thread, @NonNull Throwable throwable) {
CrashUtils.logCrash(context,thread, throwable);
defaultUEH.uncaughtException(thread, throwable);
}
/**
* Set default uncaught crash handler of current thread to {@link CrashHandler}.
*/
public static void setCrashHandler(final Context context) {
if (!(Thread.getDefaultUncaughtExceptionHandler() instanceof CrashHandler)) {
Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(context));
}
}
}

View File

@ -11,8 +11,8 @@ import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import com.termux.R;
import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
import com.termux.app.utils.Logger;
import com.termux.shared.settings.preferences.TermuxAppSharedPreferences;
import com.termux.shared.logger.Logger;
public class DebuggingPreferencesFragment extends PreferenceFragmentCompat {

View File

@ -3,14 +3,12 @@ package com.termux.app.fragments.settings;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.preference.PreferenceDataStore;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import com.termux.R;
import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
import com.termux.shared.settings.preferences.TermuxAppSharedPreferences;
public class TerminalIOPreferencesFragment extends PreferenceFragmentCompat {

View File

@ -6,10 +6,10 @@ import android.net.Uri;
import androidx.annotation.NonNull;
import com.termux.app.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
import com.termux.app.utils.Logger;
import com.termux.app.utils.MarkdownUtils;
import com.termux.app.utils.DataUtils;
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
import com.termux.shared.logger.Logger;
import com.termux.shared.markdown.MarkdownUtils;
import com.termux.shared.data.DataUtils;
import java.util.ArrayList;
import java.util.List;
@ -112,7 +112,7 @@ public class ExecutionCommand {
/** The stdout of shell command. */
public String stdout;
/** The sterr of shell command. */
/** The stderr of shell command. */
public String stderr;
/** The exit code of shell command. */
public Integer exitCode;

View File

@ -1,30 +1,30 @@
package com.termux.app.models;
import com.termux.app.utils.MarkdownUtils;
import com.termux.app.utils.TermuxUtils;
import com.termux.shared.markdown.MarkdownUtils;
import com.termux.shared.termux.TermuxUtils;
import java.io.Serializable;
public class ReportInfo implements Serializable {
/** The user action that was being processed for which the report was generated. */
public UserAction userAction;
public final UserAction userAction;
/** The internal app component that sent the report. */
public String sender;
public final String sender;
/** The report title. */
public String reportTitle;
public final String reportTitle;
/** The markdown report text prefix. Will not be part of copy and share operations, etc. */
public String reportStringPrefix;
public final String reportStringPrefix;
/** The markdown report text. */
public String reportString;
public final String reportString;
/** The markdown report text suffix. Will not be part of copy and share operations, etc. */
public String reportStringSuffix;
public final String reportStringSuffix;
/** If set to {@code true}, then report, app and device info will be added to the report when
* markdown is generated.
*/
public boolean addReportInfoToMarkdown;
public final boolean addReportInfoToMarkdown;
/** The timestamp for the report. */
public String reportTimestammp;
public final String reportTimestamp;
public ReportInfo(UserAction userAction, String sender, String reportTitle, String reportStringPrefix, String reportString, String reportStringSuffix, boolean addReportInfoToMarkdown) {
this.userAction = userAction;
@ -34,7 +34,7 @@ public class ReportInfo implements Serializable {
this.reportString = reportString;
this.reportStringSuffix = reportStringSuffix;
this.addReportInfoToMarkdown = addReportInfoToMarkdown;
this.reportTimestammp = TermuxUtils.getCurrentTimeStamp();
this.reportTimestamp = TermuxUtils.getCurrentTimeStamp();
}
/**
@ -52,7 +52,7 @@ public class ReportInfo implements Serializable {
markdownString.append("## Report Info\n\n");
markdownString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("User Action", reportInfo.userAction, "-"));
markdownString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Sender", reportInfo.sender, "-"));
markdownString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Report Timestamp", reportInfo.reportTimestammp, "-"));
markdownString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Report Timestamp", reportInfo.reportTimestamp, "-"));
markdownString.append("\n##\n\n");
}

View File

@ -0,0 +1,99 @@
package com.termux.app.settings.properties;
import android.content.Context;
import com.termux.app.terminal.io.KeyboardShortcut;
import com.termux.app.terminal.io.extrakeys.ExtraKeysInfo;
import com.termux.shared.logger.Logger;
import com.termux.shared.settings.properties.SharedPropertiesParser;
import com.termux.shared.settings.properties.TermuxPropertyConstants;
import com.termux.shared.settings.properties.TermuxSharedProperties;
import org.json.JSONException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
public class TermuxAppSharedProperties extends TermuxSharedProperties implements SharedPropertiesParser {
private ExtraKeysInfo mExtraKeysInfo;
private List<KeyboardShortcut> mSessionShortcuts = new ArrayList<>();
private static final String LOG_TAG = "TermuxAppSharedProperties";
public TermuxAppSharedProperties(@Nonnull Context context) {
super(context);
}
/**
* Reload the termux properties from disk into an in-memory cache.
*/
@Override
public void loadTermuxPropertiesFromDisk() {
super.loadTermuxPropertiesFromDisk();
setExtraKeys();
setSessionShortcuts();
}
/**
* Set the terminal extra keys and style.
*/
private void setExtraKeys() {
mExtraKeysInfo = null;
try {
// The mMap stores the extra key and style string values while loading properties
// Check {@link #getExtraKeysInternalPropertyValueFromValue(String)} and
// {@link #getExtraKeysStyleInternalPropertyValueFromValue(String)}
String extrakeys = (String) getInternalPropertyValue(TermuxPropertyConstants.KEY_EXTRA_KEYS, true);
String extraKeysStyle = (String) getInternalPropertyValue(TermuxPropertyConstants.KEY_EXTRA_KEYS_STYLE, true);
mExtraKeysInfo = new ExtraKeysInfo(extrakeys, extraKeysStyle);
} catch (JSONException e) {
Logger.showToast(mContext, "Could not load and set the \"" + TermuxPropertyConstants.KEY_EXTRA_KEYS + "\" property from the properties file: " + e.toString(), true);
Logger.logStackTraceWithMessage(LOG_TAG, "Could not load and set the \"" + TermuxPropertyConstants.KEY_EXTRA_KEYS + "\" property from the properties file: ", e);
try {
mExtraKeysInfo = new ExtraKeysInfo(TermuxPropertyConstants.DEFAULT_IVALUE_EXTRA_KEYS, TermuxPropertyConstants.DEFAULT_IVALUE_EXTRA_KEYS_STYLE);
} catch (JSONException e2) {
Logger.showToast(mContext, "Can't create default extra keys",true);
Logger.logStackTraceWithMessage(LOG_TAG, "Could create default extra keys: ", e);
mExtraKeysInfo = null;
}
}
}
/**
* Set the terminal sessions shortcuts.
*/
private void setSessionShortcuts() {
if(mSessionShortcuts == null)
mSessionShortcuts = new ArrayList<>();
else
mSessionShortcuts.clear();
// The {@link TermuxPropertyConstants#MAP_SESSION_SHORTCUTS} stores the session shortcut key and action pair
for (Map.Entry<String, Integer> entry : TermuxPropertyConstants.MAP_SESSION_SHORTCUTS.entrySet()) {
// The mMap stores the code points for the session shortcuts while loading properties
Integer codePoint = (Integer) getInternalPropertyValue(entry.getKey(), true);
// If codePoint is null, then session shortcut did not exist in properties or was invalid
// as parsed by {@link #getCodePointForSessionShortcuts(String,String)}
// If codePoint is not null, then get the action for the MAP_SESSION_SHORTCUTS key and
// add the code point to sessionShortcuts
if (codePoint != null)
mSessionShortcuts.add(new KeyboardShortcut(codePoint, entry.getValue()));
}
}
public List<KeyboardShortcut> getSessionShortcuts() {
return mSessionShortcuts;
}
public ExtraKeysInfo getExtraKeysInfo() {
return mExtraKeysInfo;
}
}

View File

@ -3,11 +3,11 @@ package com.termux.app.terminal;
import androidx.annotation.NonNull;
import com.termux.R;
import com.termux.app.TermuxConstants;
import com.termux.shared.termux.TermuxConstants;
import com.termux.app.TermuxService;
import com.termux.app.utils.Logger;
import com.termux.shared.logger.Logger;
import com.termux.app.utils.PluginUtils;
import com.termux.app.shell.ShellUtils;
import com.termux.shared.shell.ShellUtils;
import com.termux.app.models.ExecutionCommand;
import com.termux.terminal.TerminalSession;

View File

@ -13,13 +13,13 @@ import android.text.TextUtils;
import android.widget.ListView;
import com.termux.R;
import com.termux.app.utils.DialogUtils;
import com.termux.shared.interact.DialogUtils;
import com.termux.app.TermuxActivity;
import com.termux.app.TermuxConstants;
import com.termux.shared.termux.TermuxConstants;
import com.termux.app.TermuxService;
import com.termux.app.settings.properties.TermuxPropertyConstants;
import com.termux.shared.settings.properties.TermuxPropertyConstants;
import com.termux.app.terminal.io.BellHandler;
import com.termux.app.utils.Logger;
import com.termux.shared.logger.Logger;
import com.termux.terminal.TerminalColors;
import com.termux.terminal.TerminalSession;
import com.termux.terminal.TextStyle;
@ -31,15 +31,15 @@ import java.util.Properties;
public class TermuxSessionClient extends TermuxSessionClientBase {
final TermuxActivity mActivity;
private final TermuxActivity mActivity;
private static final int MAX_SESSIONS = 8;
final SoundPool mBellSoundPool = new SoundPool.Builder().setMaxStreams(1).setAudioAttributes(
private final SoundPool mBellSoundPool = new SoundPool.Builder().setMaxStreams(1).setAudioAttributes(
new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION).build()).build();
int mBellSoundId;
private final int mBellSoundId;
private static final String LOG_TAG = "TermuxSessionClient";

View File

@ -1,6 +1,6 @@
package com.termux.app.terminal;
import com.termux.app.utils.Logger;
import com.termux.shared.logger.Logger;
import com.termux.terminal.TerminalSession;
import com.termux.terminal.TerminalSessionClient;

View File

@ -3,12 +3,12 @@ package com.termux.app.terminal;
import androidx.annotation.NonNull;
import com.termux.R;
import com.termux.app.TermuxConstants;
import com.termux.shared.termux.TermuxConstants;
import com.termux.app.TermuxService;
import com.termux.app.shell.StreamGobbler;
import com.termux.app.utils.Logger;
import com.termux.shared.shell.StreamGobbler;
import com.termux.shared.logger.Logger;
import com.termux.app.utils.PluginUtils;
import com.termux.app.shell.ShellUtils;
import com.termux.shared.shell.ShellUtils;
import com.termux.app.models.ExecutionCommand;
import com.termux.app.models.ExecutionCommand.ExecutionState;

View File

@ -20,17 +20,17 @@ import android.widget.Toast;
import com.termux.R;
import com.termux.app.TermuxActivity;
import com.termux.app.TermuxConstants;
import com.termux.shared.termux.TermuxConstants;
import com.termux.app.activities.ReportActivity;
import com.termux.app.models.ReportInfo;
import com.termux.app.models.UserAction;
import com.termux.app.terminal.io.KeyboardShortcut;
import com.termux.app.terminal.io.extrakeys.ExtraKeysView;
import com.termux.app.settings.properties.TermuxPropertyConstants;
import com.termux.app.utils.DataUtils;
import com.termux.app.utils.Logger;
import com.termux.app.utils.MarkdownUtils;
import com.termux.app.utils.TermuxUtils;
import com.termux.shared.settings.properties.TermuxPropertyConstants;
import com.termux.shared.data.DataUtils;
import com.termux.shared.logger.Logger;
import com.termux.shared.markdown.MarkdownUtils;
import com.termux.shared.termux.TermuxUtils;
import com.termux.terminal.KeyHandler;
import com.termux.terminal.TerminalEmulator;
import com.termux.terminal.TerminalSession;
@ -81,7 +81,7 @@ public class TermuxViewClient implements TerminalViewClient {
}
@Override
public boolean shouldEnforeCharBasedInput() {
public boolean shouldEnforceCharBasedInput() {
return mActivity.getProperties().isEnforcingCharBasedInput();
}
@ -301,7 +301,7 @@ public class TermuxViewClient implements TerminalViewClient {
}
List<KeyboardShortcut> shortcuts = mActivity.getProperties().getSessionShortcuts();
if (!shortcuts.isEmpty()) {
if (shortcuts != null && !shortcuts.isEmpty()) {
int codePointLowerCase = Character.toLowerCase(codePoint);
for (int i = shortcuts.size() - 1; i >= 0; i--) {
KeyboardShortcut shortcut = shortcuts.get(i);

View File

@ -47,7 +47,7 @@ public class BellHandler {
if (timeSinceLastBell < 0) {
// there is a next bell pending; don't schedule another one
} else if (timeSinceLastBell < MIN_PAUSE) {
// there was a bell recently, scheudle the next one
// there was a bell recently, schedule the next one
handler.postDelayed(bellRunnable, MIN_PAUSE - timeSinceLastBell);
lastBell = lastBell + MIN_PAUSE;
} else {

View File

@ -33,7 +33,7 @@ public class ExtraKeyButton {
* The information of the popup (triggered by swipe up).
*/
@Nullable
private ExtraKeyButton popup = null;
private ExtraKeyButton popup;
public ExtraKeyButton(ExtraKeysInfo.CharDisplayMap charDisplayMap, JSONObject config) throws JSONException {
this(charDisplayMap, config, null);

View File

@ -16,7 +16,7 @@ public class ExtraKeysInfo {
/**
* This corresponds to one of the CharMapDisplay below
*/
private String style = "default";
private String style;
public ExtraKeysInfo(String propertiesInfo, String style) throws JSONException {
this.style = style;

View File

@ -1,4 +1,4 @@
package com.termux.app.crash;
package com.termux.app.utils;
import android.app.Notification;
import android.app.NotificationManager;
@ -10,66 +10,33 @@ import androidx.annotation.Nullable;
import com.termux.R;
import com.termux.app.activities.ReportActivity;
import com.termux.app.file.FileUtils;
import com.termux.shared.notification.NotificationUtils;
import com.termux.shared.file.FileUtils;
import com.termux.app.models.ReportInfo;
import com.termux.app.models.UserAction;
import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
import com.termux.app.settings.preferences.TermuxPreferenceConstants;
import com.termux.app.utils.DataUtils;
import com.termux.app.utils.Logger;
import com.termux.app.utils.MarkdownUtils;
import com.termux.app.utils.NotificationUtils;
import com.termux.app.utils.TermuxUtils;
import com.termux.shared.settings.preferences.TermuxAppSharedPreferences;
import com.termux.shared.settings.preferences.TermuxPreferenceConstants;
import com.termux.shared.data.DataUtils;
import com.termux.shared.logger.Logger;
import com.termux.shared.termux.TermuxUtils;
import com.termux.app.TermuxConstants;
import com.termux.shared.termux.TermuxConstants;
import java.nio.charset.Charset;
public class CrashUtils {
private static final String NOTIFICATION_CHANNEL_ID_CRASH_REPORT_ERRORS = "termux_crash_reports_notification_channel";
private static final String NOTIFICATION_CHANNEL_NAME_CRASH_REPORT_ERRORS = TermuxConstants.TERMUX_APP_NAME + " Crash Reports";
private static final String LOG_TAG = "CrashUtils";
/**
* Log a crash in the crash log file at
* {@link TermuxConstants#TERMUX_CRASH_LOG_FILE_PATH}.
*
* @param context The {@link Context} for operations.
* @param thread The {@link Thread} in which the crash happened.
* @param thread The {@link Throwable} thrown for the crash.
*/
public static void logCrash(final Context context, final Thread thread, final Throwable throwable) {
StringBuilder reportString = new StringBuilder();
reportString.append("## Crash Details\n");
reportString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Crash Thread", thread.toString(), "-"));
reportString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Crash Timestamp", TermuxUtils.getCurrentTimeStamp(), "-"));
reportString.append("\n\n").append(Logger.getStackTracesMarkdownString("Stacktrace", Logger.getStackTraceStringArray(throwable)));
reportString.append("\n\n").append(TermuxUtils.getAppInfoMarkdownString(context, true));
reportString.append("\n\n").append(TermuxUtils.getDeviceInfoMarkdownString(context));
// Log report string to logcat
Logger.logError(reportString.toString());
// Write report string to crash log file
String errmsg = FileUtils.writeStringToFile(context, "crash log", TermuxConstants.TERMUX_CRASH_LOG_FILE_PATH, Charset.defaultCharset(), reportString.toString(), false);
if (errmsg != null) {
Logger.logError(LOG_TAG, errmsg);
}
}
/**
* Notify the user of a previous app crash by reading the crash info from the crash log file at
* {@link TermuxConstants#TERMUX_CRASH_LOG_FILE_PATH}.
* {@link TermuxConstants#TERMUX_CRASH_LOG_FILE_PATH}. The crash log file would have been
* created by {@link com.termux.shared.crash.CrashHandler}.
*
* If the crash log file exists and is not empty and
* {@link TermuxPreferenceConstants.TERMUX_APP#KEY_CRASH_REPORT_NOTIFICATIONS_ENABLED} is
* enabled, then a notification will be shown for the crash on the
* {@link #NOTIFICATION_CHANNEL_NAME_CRASH_REPORT_ERRORS} channel, otherwise nothing will be done.
* {@link TermuxConstants#TERMUX_CRASH_REPORTS_NOTIFICATION_CHANNEL_NAME} channel, otherwise nothing will be done.
*
* After reading from the crash log file, it will be moved to {@link TermuxConstants#TERMUX_CRASH_LOG_BACKUP_FILE_PATH}.
*
@ -140,23 +107,23 @@ public class CrashUtils {
}
/**
* Get {@link Notification.Builder} for {@link #NOTIFICATION_CHANNEL_ID_CRASH_REPORT_ERRORS}
* and {@link #NOTIFICATION_CHANNEL_NAME_CRASH_REPORT_ERRORS}.
* Get {@link Notification.Builder} for {@link TermuxConstants#TERMUX_CRASH_REPORTS_NOTIFICATION_CHANNEL_ID}
* and {@link TermuxConstants#TERMUX_CRASH_REPORTS_NOTIFICATION_CHANNEL_NAME}.
*
* @param context The {@link Context} for operations.
* @param title The title for the notification.
* @param notifiationText The second line text of the notification.
* @param notificationText The second line text of the notification.
* @param notificationBigText The full text of the notification that may optionally be styled.
* @param pendingIntent The {@link PendingIntent} which should be sent when notification is clicked.
* @param notificationMode The notification mode. It must be one of {@code NotificationUtils.NOTIFICATION_MODE_*}.
* @return Returns the {@link Notification.Builder}.
*/
@Nullable
public static Notification.Builder getCrashReportsNotificationBuilder(final Context context, final CharSequence title, final CharSequence notifiationText, final CharSequence notificationBigText, final PendingIntent pendingIntent, final int notificationMode) {
public static Notification.Builder getCrashReportsNotificationBuilder(final Context context, final CharSequence title, final CharSequence notificationText, final CharSequence notificationBigText, final PendingIntent pendingIntent, final int notificationMode) {
Notification.Builder builder = NotificationUtils.geNotificationBuilder(context,
NOTIFICATION_CHANNEL_ID_CRASH_REPORT_ERRORS, Notification.PRIORITY_HIGH,
title, notifiationText, notificationBigText, pendingIntent, notificationMode);
TermuxConstants.TERMUX_CRASH_REPORTS_NOTIFICATION_CHANNEL_ID, Notification.PRIORITY_HIGH,
title, notificationText, notificationBigText, pendingIntent, notificationMode);
if (builder == null) return null;
@ -176,14 +143,14 @@ public class CrashUtils {
}
/**
* Setup the notification channel for {@link #NOTIFICATION_CHANNEL_ID_CRASH_REPORT_ERRORS} and
* {@link #NOTIFICATION_CHANNEL_NAME_CRASH_REPORT_ERRORS}.
* Setup the notification channel for {@link TermuxConstants#TERMUX_CRASH_REPORTS_NOTIFICATION_CHANNEL_ID} and
* {@link TermuxConstants#TERMUX_CRASH_REPORTS_NOTIFICATION_CHANNEL_NAME}.
*
* @param context The {@link Context} for operations.
*/
public static void setupCrashReportsNotificationChannel(final Context context) {
NotificationUtils.setupNotificationChannel(context, NOTIFICATION_CHANNEL_ID_CRASH_REPORT_ERRORS,
NOTIFICATION_CHANNEL_NAME_CRASH_REPORT_ERRORS, NotificationManager.IMPORTANCE_HIGH);
NotificationUtils.setupNotificationChannel(context, TermuxConstants.TERMUX_CRASH_REPORTS_NOTIFICATION_CHANNEL_ID,
TermuxConstants.TERMUX_CRASH_REPORTS_NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
}
}

View File

@ -11,22 +11,24 @@ import android.os.Bundle;
import androidx.annotation.Nullable;
import com.termux.R;
import com.termux.app.TermuxConstants;
import com.termux.app.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
import com.termux.shared.notification.NotificationUtils;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
import com.termux.app.activities.ReportActivity;
import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
import com.termux.app.settings.preferences.TermuxPreferenceConstants.TERMUX_APP;
import com.termux.app.settings.properties.SharedProperties;
import com.termux.app.settings.properties.TermuxPropertyConstants;
import com.termux.shared.logger.Logger;
import com.termux.shared.settings.preferences.TermuxAppSharedPreferences;
import com.termux.shared.settings.preferences.TermuxPreferenceConstants.TERMUX_APP;
import com.termux.shared.settings.properties.SharedProperties;
import com.termux.shared.settings.properties.TermuxPropertyConstants;
import com.termux.app.models.ReportInfo;
import com.termux.app.models.ExecutionCommand;
import com.termux.app.models.UserAction;
import com.termux.shared.data.DataUtils;
import com.termux.shared.markdown.MarkdownUtils;
import com.termux.shared.termux.TermuxUtils;
public class PluginUtils {
private static final String NOTIFICATION_CHANNEL_ID_PLUGIN_COMMAND_ERRORS = "termux_plugin_command_errors_notification_channel";
private static final String NOTIFICATION_CHANNEL_NAME_PLUGIN_COMMAND_ERRORS = TermuxConstants.TERMUX_APP_NAME + " Plugin Commands Errors";
/** Required file permissions for the executable file of execute intent. Executable file must have read and execute permissions */
public static final String PLUGIN_EXECUTABLE_FILE_PERMISSIONS = "r-x"; // Default: "r-x"
/** Required file permissions for the working directory of execute intent. Working directory must have read and write permissions.
@ -95,7 +97,7 @@ public class PluginUtils {
*
* Otherwise if the {@link TERMUX_APP#KEY_PLUGIN_ERROR_NOTIFICATIONS_ENABLED} is
* enabled, then a flash and a notification will be shown for the error as well
* on the {@link #NOTIFICATION_CHANNEL_NAME_PLUGIN_COMMAND_ERRORS} channel instead of just logging
* on the {@link TermuxConstants#TERMUX_PLUGIN_COMMAND_ERRORS_NOTIFICATION_CHANNEL_NAME} channel instead of just logging
* the error.
*
* @param context The {@link Context} for operations.
@ -162,11 +164,11 @@ public class PluginUtils {
setupPluginCommandErrorsNotificationChannel(context);
// Use markdown in notification
CharSequence notifiationText = MarkdownUtils.getSpannedMarkdownText(context, executionCommand.errmsg);
//CharSequence notifiationText = executionCommand.errmsg;
CharSequence notificationText = MarkdownUtils.getSpannedMarkdownText(context, executionCommand.errmsg);
//CharSequence notificationText = executionCommand.errmsg;
// Build the notification
Notification.Builder builder = getPluginCommandErrorsNotificationBuilder(context, title, notifiationText, notifiationText, pendingIntent, NotificationUtils.NOTIFICATION_MODE_VIBRATE);
Notification.Builder builder = getPluginCommandErrorsNotificationBuilder(context, title, notificationText, notificationText, pendingIntent, NotificationUtils.NOTIFICATION_MODE_VIBRATE);
if(builder == null) return;
// Send the notification
@ -202,7 +204,6 @@ public class PluginUtils {
String truncatedStdout = null;
String truncatedStderr = null;
String truncatedErrmsg = null;
String stdoutOriginalLength = (stdout == null) ? null: String.valueOf(stdout.length());
String stderrOriginalLength = (stderr == null) ? null: String.valueOf(stderr.length());
@ -231,7 +232,7 @@ public class PluginUtils {
// Truncate errmsg to max TRANSACTION_SIZE_LIMIT_IN_BYTES / 4
// trim from end to preserve start of stacktraces
truncatedErrmsg = DataUtils.getTruncatedCommandOutput(errmsg, DataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES / 4, true, false, false);
String truncatedErrmsg = DataUtils.getTruncatedCommandOutput(errmsg, DataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES / 4, true, false, false);
if(truncatedErrmsg != null && truncatedErrmsg.length() < errmsg.length()){
Logger.logWarn(logTag, "Execution Result for Execution Command \"" + label + "\" errmsg length truncated from " + errmsgOriginalLength + " to " + truncatedErrmsg.length());
errmsg = truncatedErrmsg;
@ -262,23 +263,23 @@ public class PluginUtils {
/**
* Get {@link Notification.Builder} for {@link #NOTIFICATION_CHANNEL_ID_PLUGIN_COMMAND_ERRORS}
* and {@link #NOTIFICATION_CHANNEL_NAME_PLUGIN_COMMAND_ERRORS}.
* Get {@link Notification.Builder} for {@link TermuxConstants#TERMUX_PLUGIN_COMMAND_ERRORS_NOTIFICATION_CHANNEL_ID}
* and {@link TermuxConstants#TERMUX_PLUGIN_COMMAND_ERRORS_NOTIFICATION_CHANNEL_NAME}.
*
* @param context The {@link Context} for operations.
* @param title The title for the notification.
* @param notifiationText The second line text of the notification.
* @param notificationText The second line text of the notification.
* @param notificationBigText The full text of the notification that may optionally be styled.
* @param pendingIntent The {@link PendingIntent} which should be sent when notification is clicked.
* @param notificationMode The notification mode. It must be one of {@code NotificationUtils.NOTIFICATION_MODE_*}.
* @return Returns the {@link Notification.Builder}.
*/
@Nullable
public static Notification.Builder getPluginCommandErrorsNotificationBuilder(final Context context, final CharSequence title, final CharSequence notifiationText, final CharSequence notificationBigText, final PendingIntent pendingIntent, final int notificationMode) {
public static Notification.Builder getPluginCommandErrorsNotificationBuilder(final Context context, final CharSequence title, final CharSequence notificationText, final CharSequence notificationBigText, final PendingIntent pendingIntent, final int notificationMode) {
Notification.Builder builder = NotificationUtils.geNotificationBuilder(context,
NOTIFICATION_CHANNEL_ID_PLUGIN_COMMAND_ERRORS, Notification.PRIORITY_HIGH,
title, notifiationText, notificationBigText, pendingIntent, notificationMode);
TermuxConstants.TERMUX_PLUGIN_COMMAND_ERRORS_NOTIFICATION_CHANNEL_ID, Notification.PRIORITY_HIGH,
title, notificationText, notificationBigText, pendingIntent, notificationMode);
if(builder == null) return null;
@ -298,14 +299,14 @@ public class PluginUtils {
}
/**
* Setup the notification channel for {@link #NOTIFICATION_CHANNEL_ID_PLUGIN_COMMAND_ERRORS} and
* {@link #NOTIFICATION_CHANNEL_NAME_PLUGIN_COMMAND_ERRORS}.
* Setup the notification channel for {@link TermuxConstants#TERMUX_PLUGIN_COMMAND_ERRORS_NOTIFICATION_CHANNEL_ID} and
* {@link TermuxConstants#TERMUX_PLUGIN_COMMAND_ERRORS_NOTIFICATION_CHANNEL_NAME}.
*
* @param context The {@link Context} for operations.
*/
public static void setupPluginCommandErrorsNotificationChannel(final Context context) {
NotificationUtils.setupNotificationChannel(context, NOTIFICATION_CHANNEL_ID_PLUGIN_COMMAND_ERRORS,
NOTIFICATION_CHANNEL_NAME_PLUGIN_COMMAND_ERRORS, NotificationManager.IMPORTANCE_HIGH);
NotificationUtils.setupNotificationChannel(context, TermuxConstants.TERMUX_PLUGIN_COMMAND_ERRORS_NOTIFICATION_CHANNEL_ID,
TermuxConstants.TERMUX_PLUGIN_COMMAND_ERRORS_NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
}

View File

@ -12,7 +12,7 @@ import android.provider.DocumentsProvider;
import android.webkit.MimeTypeMap;
import com.termux.R;
import com.termux.app.TermuxConstants;
import com.termux.shared.termux.TermuxConstants;
import java.io.File;
import java.io.FileNotFoundException;
@ -63,9 +63,9 @@ public class TermuxDocumentsProvider extends DocumentsProvider {
};
@Override
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
public Cursor queryRoots(String[] projection) {
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
@SuppressWarnings("ConstantConditions") final String applicationName = getContext().getString(R.string.application_name);
final String applicationName = getContext().getString(R.string.application_name);
final MatrixCursor.RowBuilder row = result.newRow();
row.add(Root.COLUMN_ROOT_ID, getDocIdForFile(BASE_DIR));

View File

@ -9,11 +9,11 @@ import android.provider.OpenableColumns;
import android.util.Patterns;
import com.termux.R;
import com.termux.app.utils.DialogUtils;
import com.termux.app.TermuxConstants;
import com.termux.app.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
import com.termux.shared.interact.DialogUtils;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
import com.termux.app.TermuxService;
import com.termux.app.utils.Logger;
import com.termux.shared.logger.Logger;
import java.io.ByteArrayInputStream;
import java.io.File;

View File

@ -1,5 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="background_markdown_code_inline">#1F000000</color>
<color name="background_markdown_code_block">#0F000000</color>
</resources>

View File

@ -48,6 +48,9 @@
<string name="action_toggle_soft_keyboard">Keyboard</string>
<string name="msg_enabling_terminal_toolbar">Enabling Terminal Toolbar</string>
<string name="msg_disabling_terminal_toolbar">Disabling Terminal Toolbar</string>
<!-- Terminal Popup -->
@ -103,55 +106,6 @@
<!-- Termux FileUtils -->
<string name="error_executable_required">Executable required.</string>
<string name="error_null_or_empty_parameter">The %1$s is to \"%2$s\" null or empty.</string>
<string name="error_null_or_empty_regular_file_path">The regular file path is null or empty.</string>
<string name="error_null_or_empty_regular_file">The regular file is null or empty.</string>
<string name="error_null_or_empty_executable_file_path">The executable file path is null or empty.</string>
<string name="error_null_or_empty_executable_file">The executable file is null or empty.</string>
<string name="error_null_or_empty_directory_file_path">The directory file path is null or empty.</string>
<string name="error_null_or_empty_directory_file">The directory file is null or empty.</string>
<string name="error_file_not_found_at_path">The %1$s is not found at path \"%2$s\".</string>
<string name="error_no_regular_file_found">Regular file not found at %1$s path.</string>
<string name="error_not_a_regular_file">The %1$s at path \"%2$s\" is not a regular file.</string>
<string name="error_non_regular_file_found">Non-regular file found at %1$s path.</string>
<string name="error_non_directory_file_found">Non-directory file found at %1$s path.</string>
<string name="error_non_symlink_file_found">Non-symlink file found at %1$s path.</string>
<string name="error_file_not_an_allowed_file_type">The %1$s found at path \"%2$s\" is not one of allowed file types \"%3$s\".</string>
<string name="error_validate_file_existence_and_permissions_failed_with_exception">Validating file existence and permissions of %1$s at path \"%2$s\" failed.\nException: %3$s</string>
<string name="error_validate_directory_existence_and_permissions_failed_with_exception">Validating directory existence and permissions of %1$s at path \"%2$s\" failed.\nException: %3$s</string>
<string name="error_creating_file_failed">Creating %1$s at path \"%2$s\" failed.</string>
<string name="error_creating_file_failed_with_exception">Creating %1$s at path \"%2$s\" failed.\nException: %3$s</string>
<string name="error_cannot_overwrite_a_non_symlink_file_type">Cannot overwrite %1$s while creating symlink at \"%2$s\" to \"%3$s\" since destination file type \"%4$s\" is not a symlink.</string>
<string name="error_creating_symlink_file_failed_with_exception">Creating %1$s at path \"%2$s\" to \"%3$s\" failed.\nException: %4$s</string>
<string name="error_copying_or_moving_file_failed_with_exception">%1$s from \"%2$s\" to \"%3$s\" failed.\nException: %4$s</string>
<string name="error_copying_or_moving_file_to_same_path">%1$s from \"%2$s\" to \"%3$s\" cannot be done since they point to the same path.</string>
<string name="error_cannot_overwrite_a_different_file_type">Cannot overwrite %1$s while %2$s it from \"%3$s\" to \"%4$s\" since destination file type \"%5$s\" is different from source file type \"%6$s\".</string>
<string name="error_cannot_move_directory_to_sub_directory_of_itself">Cannot move %1$s from \"%2$s\" to \"%3$s\" since destination is a subdirectory of the source.</string>
<string name="error_file_still_exists_after_deleting">The %1$s still exists after deleting it from \"%2$s\".</string>
<string name="error_deleting_file_failed">Deleting %1$s at path \"%2$s\" failed.</string>
<string name="error_deleting_file_failed_with_exception">Deleting %1$s at path \"%2$s\" failed.\nException: %3$s</string>
<string name="error_clearing_directory_failed_with_exception">Clearing %1$s at path \"%2$s\" failed.\nException: %3$s</string>
<string name="error_reading_string_to_file_failed_with_exception">Reading string from %1$s at path \"%2$s\" failed.\nException: %3$s</string>
<string name="error_writing_string_to_file_failed_with_exception">Writing string to %1$s at path \"%2$s\" failed.\nException: %3$s</string>
<string name="error_unsupported_charset">Unsupported charset \"%1$s\"</string>
<string name="error_checking_if_charset_supported_failed">Checking if charset \"%1$s\" is suppoted failed.\nException: %2$s</string>
<string name="error_invalid_file_permissions_string_to_check">The file permission string to check is invalid.</string>
<string name="error_file_not_readable">The %1$s at path is not readable. Permission Denied.</string>
<string name="error_file_not_writable">The %1$s at path is not writable. Permission Denied.</string>
<string name="error_file_not_executable">The %1$s at path is not executable. Permission Denied.</string>
<!-- Termux Report And ShareUtils -->
<string name="action_copy">Copy</string>
<string name="action_share">Share</string>
@ -159,14 +113,6 @@
<string name="title_share_with">Share With</string>
<string name="title_report_text">Report Text</string>
<string name="msg_report_issue">If you think this report should be reported, then copy its text from the options menu (3-dots on top right) and post an issue on one of the following links at which the report belongs at.</string>
<!-- Termux PermissionUtils -->
<string name="message_sudo_please_grant_permissions">Please grant permissions on next screen</string>
<string name="error_display_over_other_apps_permission_not_granted">&TERMUX_APP_NAME; requires \"Display over other apps\" permission to start terminal sessions from background on Android >= 10. Grants it from Settings -> Apps -> &TERMUX_APP_NAME; -> Advanced</string>
<!-- Termux File Receiver -->
@ -185,15 +131,6 @@
<!-- Logging Category -->
<string name="logging_header">Logging</string>
<!-- Log Level -->
<string name="log_level_title">Log Level</string>
<string name="log_level_off">"Off"</string>
<string name="log_level_normal">"Normal"</string>
<string name="log_level_debug">"Debug"</string>
<string name="log_level_verbose">"Verbose"</string>
<string name="log_level_unknown">"*Unknown*"</string>
<string name="log_level_value">Logcat log level set to \"%1$s\"</string>
<!-- Terminal View Key Logging -->
<string name="terminal_view_key_logging_title">Terminal View Key Logging</string>
<string name="terminal_view_key_logging_off">Logs will not have entries for terminal view keys. (Default)</string>
@ -221,5 +158,4 @@
<string name="soft_keyboard_off">Soft keyboard will be disabled.</string>
<string name="soft_keyboard_on">Soft keyboard will be enabled. (Default)</string>
</resources>

View File

@ -1,6 +1,6 @@
package com.termux.app;
import com.termux.app.utils.DataUtils;
import com.termux.shared.data.DataUtils;
import org.junit.Assert;
import org.junit.Test;

View File

@ -19,3 +19,6 @@ minSdkVersion=24
targetSdkVersion=28
ndkVersion=22.0.7026061
compileSdkVersion=29
markwonVersion=4.6.2

View File

@ -1 +1 @@
include ':app', ':terminal-emulator', ':terminal-view'
include ':app', ':termux-shared', ':terminal-emulator', ':terminal-view'

View File

@ -50,7 +50,7 @@ tasks.withType(Test) {
}
dependencies {
testImplementation 'junit:junit:4.13.1'
testImplementation 'junit:junit:4.13.2'
}

View File

@ -249,7 +249,7 @@ public final class TerminalView extends View {
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
if (mClient.shouldEnforeCharBasedInput()) {
if (mClient.shouldEnforceCharBasedInput()) {
// Some keyboards seems do not reset the internal state on TYPE_NULL.
// Affects mostly Samsung stock keyboards.
// https://github.com/termux/termux-app/issues/686

View File

@ -30,7 +30,7 @@ public interface TerminalViewClient {
boolean shouldBackButtonBeMappedToEscape();
boolean shouldEnforeCharBasedInput();
boolean shouldEnforceCharBasedInput();
boolean shouldUseCtrlSpaceWorkaround();

1
termux-shared/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,67 @@
apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
android {
compileSdkVersion project.properties.compileSdkVersion.toInteger()
dependencies {
implementation "androidx.annotation:annotation:1.2.0"
implementation "com.google.guava:guava:24.1-jre"
implementation "io.noties.markwon:core:$markwonVersion"
implementation "io.noties.markwon:ext-strikethrough:$markwonVersion"
implementation "io.noties.markwon:linkify:$markwonVersion"
implementation "io.noties.markwon:recycler:$markwonVersion"
// Do not increment version higher than 2.5 or there
// will be runtime exceptions on android < 8
// due to missing classes like java.nio.file.Path.
implementation "commons-io:commons-io:2.5"
}
defaultConfig {
minSdkVersion project.properties.minSdkVersion.toInteger()
targetSdkVersion project.properties.targetSdkVersion.toInteger()
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
testImplementation "junit:junit:4.13.2"
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
publishing {
publications {
bar(MavenPublication) {
groupId 'com.termux'
artifactId 'termux-shared'
version '0.108'
artifact("$buildDir/outputs/aar/termux-shared-release.aar")
}
}
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/termux/termux-app")
credentials {
username = System.getenv("GH_USERNAME")
password = System.getenv("GH_TOKEN")
}
}
}
}

10
termux-shared/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,10 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
-dontobfuscate
#-renamesourcefileattribute SourceFile
#-keepattributes SourceFile,LineNumberTable

View File

@ -0,0 +1,26 @@
package com.termux.shared;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.termux.shared.test", appContext.getPackageName());
}
}

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.termux.shared">
</manifest>

View File

@ -0,0 +1,74 @@
package com.termux.shared.crash;
import android.content.Context;
import androidx.annotation.NonNull;
import com.termux.shared.file.FileUtils;
import com.termux.shared.logger.Logger;
import com.termux.shared.markdown.MarkdownUtils;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.termux.TermuxUtils;
import java.nio.charset.Charset;
/**
* Catches uncaught exceptions and logs them.
*/
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private final Context context;
private final Thread.UncaughtExceptionHandler defaultUEH;
private static final String LOG_TAG = "CrashUtils";
private CrashHandler(final Context context) {
this.context = context;
this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
}
public void uncaughtException(@NonNull Thread thread, @NonNull Throwable throwable) {
logCrash(context,thread, throwable);
defaultUEH.uncaughtException(thread, throwable);
}
/**
* Set default uncaught crash handler of current thread to {@link CrashHandler}.
*/
public static void setCrashHandler(final Context context) {
if (!(Thread.getDefaultUncaughtExceptionHandler() instanceof CrashHandler)) {
Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(context));
}
}
/**
* Log a crash in the crash log file at
* {@link TermuxConstants#TERMUX_CRASH_LOG_FILE_PATH}.
*
* @param context The {@link Context} for operations.
* @param thread The {@link Thread} in which the crash happened.
* @param throwable The {@link Throwable} thrown for the crash.
*/
public static void logCrash(final Context context, final Thread thread, final Throwable throwable) {
StringBuilder reportString = new StringBuilder();
reportString.append("## Crash Details\n");
reportString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Crash Thread", thread.toString(), "-"));
reportString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Crash Timestamp", TermuxUtils.getCurrentTimeStamp(), "-"));
reportString.append("\n\n").append(Logger.getStackTracesMarkdownString("Stacktrace", Logger.getStackTraceStringArray(throwable)));
reportString.append("\n\n").append(TermuxUtils.getAppInfoMarkdownString(context, true));
reportString.append("\n\n").append(TermuxUtils.getDeviceInfoMarkdownString(context));
// Log report string to logcat
Logger.logError(reportString.toString());
// Write report string to crash log file
String errmsg = FileUtils.writeStringToFile(context, "crash log", TermuxConstants.TERMUX_CRASH_LOG_FILE_PATH, Charset.defaultCharset(), reportString.toString(), false);
if (errmsg != null) {
Logger.logError(LOG_TAG, errmsg);
}
}
}

View File

@ -1,4 +1,4 @@
package com.termux.app.utils;
package com.termux.shared.data;
import android.os.Bundle;

View File

@ -1,4 +1,4 @@
package com.termux.app.file;
package com.termux.shared.file;
import android.content.Context;
import android.os.Build;
@ -7,12 +7,12 @@ import android.system.Os;
import androidx.annotation.NonNull;
import com.google.common.io.RecursiveDeleteOption;
import com.termux.R;
import com.termux.app.TermuxConstants;
import com.termux.app.file.filesystem.FileType;
import com.termux.app.file.filesystem.FileTypes;
import com.termux.app.utils.DataUtils;
import com.termux.app.utils.Logger;
import com.termux.shared.R;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.file.filesystem.FileType;
import com.termux.shared.file.filesystem.FileTypes;
import com.termux.shared.data.DataUtils;
import com.termux.shared.logger.Logger;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@ -1460,7 +1460,7 @@ public class FileUtils {
label = (label == null ? "" : label + " ");
if (filePath == null || filePath.isEmpty()) return;
if (!isValidPermissingString(permissionsToSet)) {
if (!isValidPermissionString(permissionsToSet)) {
Logger.logError(LOG_TAG, "Invalid permissionsToSet passed to setFilePermissions: \"" + permissionsToSet + "\"");
return;
}
@ -1531,7 +1531,7 @@ public class FileUtils {
label = (label == null ? "" : label + " ");
if (filePath == null || filePath.isEmpty()) return;
if (!isValidPermissingString(permissionsToSet)) {
if (!isValidPermissionString(permissionsToSet)) {
Logger.logError(LOG_TAG, "Invalid permissionsToSet passed to setMissingFilePermissions: \"" + permissionsToSet + "\"");
return;
}
@ -1585,7 +1585,7 @@ public class FileUtils {
label = (label == null ? "" : label + " ");
if (filePath == null || filePath.isEmpty()) return context.getString(R.string.error_null_or_empty_parameter, label + "file path", "checkMissingFilePermissions");
if (!isValidPermissingString(permissionsToCheck)) {
if (!isValidPermissionString(permissionsToCheck)) {
Logger.logError(LOG_TAG, "Invalid permissionsToCheck passed to checkMissingFilePermissions: \"" + permissionsToCheck + "\"");
return context.getString(R.string.error_invalid_file_permissions_string_to_check);
}
@ -1619,7 +1619,7 @@ public class FileUtils {
* @param string The {@link String} to check.
* @return Returns {@code true} if string exactly matches a permission string, otherwise {@code false}.
*/
public static boolean isValidPermissingString(final String string) {
public static boolean isValidPermissionString(final String string) {
if (string == null || string.isEmpty()) return false;
return Pattern.compile("^([r-])[w-][x-]$", 0).matcher(string).matches();
}

View File

@ -23,15 +23,13 @@
* questions.
*/
package com.termux.app.file.filesystem;
package com.termux.shared.file.filesystem;
import android.os.Build;
import android.system.StructStat;
import androidx.annotation.NonNull;
import com.termux.app.utils.Logger;
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;

View File

@ -23,7 +23,7 @@
* questions.
*/
package com.termux.app.file.filesystem;
package com.termux.shared.file.filesystem;
/**
* Container for device/inode to uniquely identify file.

View File

@ -24,7 +24,7 @@
* questions.
*/
package com.termux.app.file.filesystem;
package com.termux.shared.file.filesystem;
/**
* Defines the bits for use with the {@link FileAttributes#permissions()
@ -83,5 +83,6 @@ public enum FilePermission {
/**
* Execute/search permission, others.
*/
OTHERS_EXECUTE;
OTHERS_EXECUTE
}

View File

@ -23,9 +23,9 @@
* questions.
*/
package com.termux.app.file.filesystem;
package com.termux.shared.file.filesystem;
import static com.termux.app.file.filesystem.FilePermission.*;
import static com.termux.shared.file.filesystem.FilePermission.*;
import java.util.*;

View File

@ -23,7 +23,7 @@
* questions.
*/
package com.termux.app.file.filesystem;
package com.termux.shared.file.filesystem;
import androidx.annotation.NonNull;

View File

@ -1,4 +1,4 @@
package com.termux.app.file.filesystem;
package com.termux.shared.file.filesystem;
/** The {@link Enum} that defines file types. */
public enum FileType {

View File

@ -1,10 +1,10 @@
package com.termux.app.file.filesystem;
package com.termux.shared.file.filesystem;
import android.system.Os;
import androidx.annotation.NonNull;
import com.termux.app.utils.Logger;
import com.termux.shared.logger.Logger;
import java.io.File;

View File

@ -1,4 +1,4 @@
package com.termux.app.file.filesystem;
package com.termux.shared.file.filesystem;
import android.system.ErrnoException;
import android.system.Os;

View File

@ -26,7 +26,7 @@
*
*/
// AUTOMATICALLY GENERATED FILE - DO NOT EDIT
package com.termux.app.file.filesystem;
package com.termux.shared.file.filesystem;
// BEGIN Android-changed: Use constants from android.system.OsConstants. http://b/32203242
// Those constants are initialized by native code to ensure correctness on different architectures.

View File

@ -1,12 +1,11 @@
package com.termux.app.file.tests;
package com.termux.shared.file.tests;
import android.content.Context;
import androidx.annotation.NonNull;
import com.termux.app.TermuxConstants;
import com.termux.app.file.FileUtils;
import com.termux.app.utils.Logger;
import com.termux.shared.file.FileUtils;
import com.termux.shared.logger.Logger;
import java.io.File;
import java.nio.charset.Charset;

View File

@ -1,4 +1,4 @@
package com.termux.app.utils;
package com.termux.shared.interact;
import android.app.Activity;
import android.app.AlertDialog;

View File

@ -1,4 +1,4 @@
package com.termux.app.utils;
package com.termux.shared.interact;
import android.content.ClipData;
import android.content.ClipboardManager;
@ -7,7 +7,9 @@ import android.content.Intent;
import androidx.core.content.ContextCompat;
import com.termux.R;
import com.termux.shared.R;
import com.termux.shared.data.DataUtils;
import com.termux.shared.logger.Logger;
public class ShareUtils {

View File

@ -1,4 +1,4 @@
package com.termux.app.utils;
package com.termux.shared.logger;
import android.content.Context;
import android.os.Handler;
@ -6,8 +6,8 @@ import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import com.termux.R;
import com.termux.app.TermuxConstants;
import com.termux.shared.R;
import com.termux.shared.termux.TermuxConstants;
import java.io.IOException;
import java.io.PrintWriter;
@ -31,7 +31,7 @@ public class Logger {
public static void logMesssage(int logLevel, String tag, String message) {
public static void logMessage(int logLevel, String tag, String message) {
if(logLevel == Log.ERROR && CURRENT_LOG_LEVEL >= LOG_LEVEL_NORMAL)
Log.e(getFullTag(tag), message);
else if(logLevel == Log.WARN && CURRENT_LOG_LEVEL >= LOG_LEVEL_NORMAL)
@ -47,51 +47,51 @@ public class Logger {
public static void logError(String tag, String message) {
logMesssage(Log.ERROR, tag, message);
logMessage(Log.ERROR, tag, message);
}
public static void logError(String message) {
logMesssage(Log.ERROR, DEFAULT_LOG_TAG, message);
logMessage(Log.ERROR, DEFAULT_LOG_TAG, message);
}
public static void logWarn(String tag, String message) {
logMesssage(Log.WARN, tag, message);
logMessage(Log.WARN, tag, message);
}
public static void logWarn(String message) {
logMesssage(Log.WARN, DEFAULT_LOG_TAG, message);
logMessage(Log.WARN, DEFAULT_LOG_TAG, message);
}
public static void logInfo(String tag, String message) {
logMesssage(Log.INFO, tag, message);
logMessage(Log.INFO, tag, message);
}
public static void logInfo(String message) {
logMesssage(Log.INFO, DEFAULT_LOG_TAG, message);
logMessage(Log.INFO, DEFAULT_LOG_TAG, message);
}
public static void logDebug(String tag, String message) {
logMesssage(Log.DEBUG, tag, message);
logMessage(Log.DEBUG, tag, message);
}
public static void logDebug(String message) {
logMesssage(Log.DEBUG, DEFAULT_LOG_TAG, message);
logMessage(Log.DEBUG, DEFAULT_LOG_TAG, message);
}
public static void logVerbose(String tag, String message) {
logMesssage(Log.VERBOSE, tag, message);
logMessage(Log.VERBOSE, tag, message);
}
public static void logVerbose(String message) {
logMesssage(Log.VERBOSE, DEFAULT_LOG_TAG, message);
logMessage(Log.VERBOSE, DEFAULT_LOG_TAG, message);
}

View File

@ -1,4 +1,4 @@
package com.termux.app.utils;
package com.termux.shared.markdown;
import android.content.Context;
import android.graphics.Typeface;
@ -16,7 +16,7 @@ import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import com.google.common.base.Strings;
import com.termux.R;
import com.termux.shared.R;
import org.commonmark.ext.gfm.strikethrough.Strikethrough;
import org.commonmark.node.BlockQuote;
@ -38,8 +38,8 @@ import io.noties.markwon.linkify.LinkifyPlugin;
public class MarkdownUtils {
public static String backtick = "`";
public static Pattern backticksPattern = Pattern.compile("(" + backtick + "+)");
public static final String backtick = "`";
public static final Pattern backticksPattern = Pattern.compile("(" + backtick + "+)");
/**
* Get the markdown code {@link String} for a {@link String}. This ensures all backticks "`" are

View File

@ -1,4 +1,4 @@
package com.termux.app.utils;
package com.termux.shared.notification;
import android.app.Notification;
import android.app.NotificationChannel;
@ -9,10 +9,10 @@ import android.os.Build;
import androidx.annotation.Nullable;
import com.termux.app.RunCommandService;
import com.termux.app.TermuxService;
import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
import com.termux.app.settings.preferences.TermuxPreferenceConstants;
import com.termux.shared.logger.Logger;
import com.termux.shared.settings.preferences.TermuxAppSharedPreferences;
import com.termux.shared.settings.preferences.TermuxPreferenceConstants;
import com.termux.shared.termux.TermuxConstants;
public class NotificationUtils {
@ -52,6 +52,9 @@ public class NotificationUtils {
/**
* Try to get the next unique notification id that isn't already being used by the app.
*
* Termux app and its plugin must use unique notification ids from the same pool due to usage of android:sharedUserId.
* https://commonsware.com/blog/2017/06/07/jobscheduler-job-ids-libraries.html
*
* @param context The {@link Context} for operations.
* @return Returns the notification id that should be safe to use.
*/
@ -62,7 +65,7 @@ public class NotificationUtils {
int lastNotificationId = preferences.getLastNotificationId();
int nextNotificationId = lastNotificationId + 1;
while(nextNotificationId == TermuxService.NOTIFICATION_ID || nextNotificationId == RunCommandService.NOTIFICATION_ID) {
while(nextNotificationId == TermuxConstants.TERMUX_APP_NOTIFICATION_ID || nextNotificationId == TermuxConstants.TERMUX_RUN_COMMAND_NOTIFICATION_ID) {
nextNotificationId++;
}

View File

@ -1,4 +1,4 @@
package com.termux.app.utils;
package com.termux.shared.packages;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@ -6,6 +6,8 @@ import android.content.pm.PackageInfo;
import androidx.annotation.NonNull;
import com.termux.shared.logger.Logger;
public class PackageUtils {
/**

View File

@ -1,4 +1,4 @@
package com.termux.app.utils;
package com.termux.shared.packages;
import android.app.Activity;
import android.content.Context;
@ -10,9 +10,10 @@ import android.provider.Settings;
import androidx.core.content.ContextCompat;
import com.termux.R;
import com.termux.app.TermuxConstants;
import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
import com.termux.shared.R;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.logger.Logger;
import com.termux.shared.settings.preferences.TermuxAppSharedPreferences;
import java.util.Arrays;

View File

@ -1,10 +1,10 @@
package com.termux.app.settings.preferences;
package com.termux.shared.settings.preferences;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import com.termux.app.utils.Logger;
import com.termux.shared.logger.Logger;
import java.util.Set;

View File

@ -1,14 +1,14 @@
package com.termux.app.settings.preferences;
package com.termux.shared.settings.preferences;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.TypedValue;
import com.termux.app.TermuxConstants;
import com.termux.app.utils.Logger;
import com.termux.app.utils.TermuxUtils;
import com.termux.app.utils.DataUtils;
import com.termux.app.settings.preferences.TermuxPreferenceConstants.TERMUX_APP;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.logger.Logger;
import com.termux.shared.termux.TermuxUtils;
import com.termux.shared.data.DataUtils;
import com.termux.shared.settings.preferences.TermuxPreferenceConstants.TERMUX_APP;
import javax.annotation.Nonnull;

View File

@ -1,7 +1,7 @@
package com.termux.app.settings.preferences;
package com.termux.shared.settings.preferences;
/*
* Version: v0.8.0
* Version: v0.9.0
*
* Changelog
*
@ -37,13 +37,16 @@ package com.termux.app.settings.preferences;
* - 0.8.0 (2021-04-06)
* - Added following to `TERMUX_APP`:
* `KEY_CRASH_REPORT_NOTIFICATIONS_ENABLED` and `DEFAULT_VALUE_CRASH_REPORT_NOTIFICATIONS_ENABLED`.
*
* - 0.9.0 (2021-04-07)
* - Updated javadocs.
*/
/**
* A class that defines shared constants of the Shared preferences used by Termux app and its plugins.
* This class will be hosted by termux-app and should be imported by other termux plugin apps as is
* instead of copying constants to random classes. The 3rd party apps can also import it for
* interacting with termux apps. If changes are made to this file, increment the version number
* A class that defines shared constants of the SharedPreferences used by Termux app and its plugins.
* This class will be hosted by termux-shared lib and should be imported by other termux plugin
* apps as is instead of copying constants to random classes. The 3rd party apps can also import
* it for interacting with termux apps. If changes are made to this file, increment the version number
* and add an entry in the Changelog section above.
*/
public final class TermuxPreferenceConstants {

View File

@ -1,13 +1,13 @@
package com.termux.app.settings.preferences;
package com.termux.shared.settings.preferences;
import android.content.Context;
import android.content.SharedPreferences;
import com.termux.app.TermuxConstants;
import com.termux.app.settings.preferences.TermuxPreferenceConstants.TERMUX_TASKER_APP;
import com.termux.app.utils.DataUtils;
import com.termux.app.utils.Logger;
import com.termux.app.utils.TermuxUtils;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.settings.preferences.TermuxPreferenceConstants.TERMUX_TASKER_APP;
import com.termux.shared.data.DataUtils;
import com.termux.shared.logger.Logger;
import com.termux.shared.termux.TermuxUtils;
import javax.annotation.Nonnull;

View File

@ -1,11 +1,11 @@
package com.termux.app.settings.properties;
package com.termux.shared.settings.properties;
import android.content.Context;
import android.widget.Toast;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.primitives.Primitives;
import com.termux.app.utils.Logger;
import com.termux.shared.logger.Logger;
import java.io.File;
import java.io.FileInputStream;
@ -96,7 +96,7 @@ public class SharedProperties {
mSharedPropertiesParser = sharedPropertiesParser;
mProperties = new Properties();
mMap = new HashMap<String, Object>();
mMap = new HashMap<>();
}
/**
@ -115,7 +115,7 @@ public class SharedProperties {
if (properties == null)
properties = new Properties();
HashMap<String, Object> map = new HashMap<String, Object>();
HashMap<String, Object> map = new HashMap<>();
Properties newProperties = new Properties();
Set<String> propertiesList = mPropertiesList;
@ -187,7 +187,7 @@ public class SharedProperties {
*/
public Map<String, Object> getInternalProperties() {
synchronized (mLock) {
if (mMap == null) mMap = new HashMap<String, Object>();
if (mMap == null) mMap = new HashMap<>();
return getMapCopy(mMap);
}
}
@ -406,7 +406,7 @@ public class SharedProperties {
public static Map<String, Object> getMapCopy(Map<String, Object> map) {
if (map == null) return null;
return new HashMap<String, Object>(map);
return new HashMap<>(map);
}

View File

@ -1,4 +1,4 @@
package com.termux.app.settings.properties;
package com.termux.shared.settings.properties;
import android.content.Context;
@ -18,6 +18,6 @@ public interface SharedPropertiesParser {
* @param value The literal value for the property found is the properties file.
* @return Returns the {@link Object} object to store in the {@link HashMap <>} in-memory cache.
*/
public Object getInternalPropertyValueFromValue(Context context, String key, String value);
Object getInternalPropertyValueFromValue(Context context, String key, String value);
}

View File

@ -1,8 +1,8 @@
package com.termux.app.settings.properties;
package com.termux.shared.settings.properties;
import com.google.common.collect.ImmutableBiMap;
import com.termux.app.TermuxConstants;
import com.termux.app.utils.Logger;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.logger.Logger;
import java.io.File;
import java.util.Arrays;
@ -10,7 +10,7 @@ import java.util.HashSet;
import java.util.Set;
/*
* Version: v0.5.0
* Version: v0.6.0
*
* Changelog
*
@ -30,13 +30,16 @@ import java.util.Set;
*
* - 0.5.0 (2021-03-25)
* - Add `KEY_HIDE_SOFT_KEYBOARD_ON_STARTUP`.
*
* - 0.6.0 (2021-04-07)
* - Updated javadocs.
*/
/**
* A class that defines shared constants of the properties used by Termux app and its plugins.
* This class will be hosted by termux-app and should be imported by other termux plugin apps as is
* instead of copying constants to random classes. The 3rd party apps can also import it for
* interacting with termux apps. If changes are made to this file, increment the version number
* A class that defines shared constants of the SharedProperties used by Termux app and its plugins.
* This class will be hosted by termux-shared lib and should be imported by other termux plugin
* apps as is instead of copying constants to random classes. The 3rd party apps can also import
* it for interacting with termux apps. If changes are made to this file, increment the version number
* and add an entry in the Changelog section above.
*
* The properties are loaded from the first file found at

View File

@ -1,19 +1,13 @@
package com.termux.app.settings.properties;
package com.termux.shared.settings.properties;
import android.content.Context;
import android.content.res.Configuration;
import com.termux.app.terminal.io.extrakeys.ExtraKeysInfo;
import com.termux.app.terminal.io.KeyboardShortcut;
import com.termux.app.utils.Logger;
import com.termux.app.utils.DataUtils;
import org.json.JSONException;
import com.termux.shared.logger.Logger;
import com.termux.shared.data.DataUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@ -21,12 +15,9 @@ import javax.annotation.Nonnull;
public class TermuxSharedProperties implements SharedPropertiesParser {
private final Context mContext;
private final SharedProperties mSharedProperties;
private final File mPropertiesFile;
private ExtraKeysInfo mExtraKeysInfo;
private final List<KeyboardShortcut> mSessionShortcuts = new ArrayList<>();
protected final Context mContext;
protected final SharedProperties mSharedProperties;
protected final File mPropertiesFile;
private static final String LOG_TAG = "TermuxSharedProperties";
@ -44,53 +35,6 @@ public class TermuxSharedProperties implements SharedPropertiesParser {
mSharedProperties.loadPropertiesFromDisk();
dumpPropertiesToLog();
dumpInternalPropertiesToLog();
setExtraKeys();
setSessionShortcuts();
}
/**
* Set the terminal extra keys and style.
*/
private void setExtraKeys() {
mExtraKeysInfo = null;
try {
// The mMap stores the extra key and style string values while loading properties
// Check {@link #getExtraKeysInternalPropertyValueFromValue(String)} and
// {@link #getExtraKeysStyleInternalPropertyValueFromValue(String)}
String extrakeys = (String) getInternalPropertyValue(TermuxPropertyConstants.KEY_EXTRA_KEYS, true);
String extraKeysStyle = (String) getInternalPropertyValue(TermuxPropertyConstants.KEY_EXTRA_KEYS_STYLE, true);
mExtraKeysInfo = new ExtraKeysInfo(extrakeys, extraKeysStyle);
} catch (JSONException e) {
Logger.showToast(mContext, "Could not load and set the \"" + TermuxPropertyConstants.KEY_EXTRA_KEYS + "\" property from the properties file: " + e.toString(), true);
Logger.logStackTraceWithMessage(LOG_TAG, "Could not load and set the \"" + TermuxPropertyConstants.KEY_EXTRA_KEYS + "\" property from the properties file: ", e);
try {
mExtraKeysInfo = new ExtraKeysInfo(TermuxPropertyConstants.DEFAULT_IVALUE_EXTRA_KEYS, TermuxPropertyConstants.DEFAULT_IVALUE_EXTRA_KEYS_STYLE);
} catch (JSONException e2) {
Logger.showToast(mContext, "Can't create default extra keys",true);
Logger.logStackTraceWithMessage(LOG_TAG, "Could create default extra keys: ", e);
mExtraKeysInfo = null;
}
}
}
/**
* Set the terminal sessions shortcuts.
*/
private void setSessionShortcuts() {
mSessionShortcuts.clear();
// The {@link TermuxPropertyConstants#MAP_SESSION_SHORTCUTS} stores the session shortcut key and action pair
for (Map.Entry<String, Integer> entry : TermuxPropertyConstants.MAP_SESSION_SHORTCUTS.entrySet()) {
// The mMap stores the code points for the session shortcuts while loading properties
Integer codePoint = (Integer) getInternalPropertyValue(entry.getKey(), true);
// If codePoint is null, then session shortcut did not exist in properties or was invalid
// as parsed by {@link #getCodePointForSessionShortcuts(String,String)}
// If codePoint is not null, then get the action for the MAP_SESSION_SHORTCUTS key and
// add the code point to sessionShortcuts
if (codePoint != null)
mSessionShortcuts.add(new KeyboardShortcut(codePoint, entry.getValue()));
}
}
@ -473,18 +417,10 @@ public class TermuxSharedProperties implements SharedPropertiesParser {
return rangeTerminalToolbarHeightScaleFactorValue((float) getInternalPropertyValue(TermuxPropertyConstants.KEY_TERMINAL_TOOLBAR_HEIGHT_SCALE_FACTOR, true));
}
public List<KeyboardShortcut> getSessionShortcuts() {
return mSessionShortcuts;
}
public String getDefaultWorkingDirectory() {
return (String) getInternalPropertyValue(TermuxPropertyConstants.KEY_DEFAULT_WORKING_DIRECTORY, true);
}
public ExtraKeysInfo getExtraKeysInfo() {
return mExtraKeysInfo;
}

View File

@ -1,12 +1,12 @@
package com.termux.app.shell;
package com.termux.shared.shell;
import android.content.Context;
import com.termux.app.TermuxConstants;
import com.termux.app.file.FileUtils;
import com.termux.app.utils.Logger;
import com.termux.app.utils.PackageUtils;
import com.termux.app.utils.TermuxUtils;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.file.FileUtils;
import com.termux.shared.logger.Logger;
import com.termux.shared.packages.PackageUtils;
import com.termux.shared.termux.TermuxUtils;
import java.io.File;
import java.io.FileInputStream;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.termux.app.shell;
package com.termux.shared.shell;
import java.io.BufferedReader;
import java.io.IOException;
@ -28,7 +28,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.termux.app.utils.Logger;
import com.termux.shared.logger.Logger;
/**
* Thread utility class continuously reading from an InputStream

View File

@ -1,11 +1,11 @@
package com.termux.app;
package com.termux.shared.termux;
import android.annotation.SuppressLint;
import java.io.File;
/*
* Version: v0.16.0
* Version: v0.17.0
*
* Changelog
*
@ -118,13 +118,20 @@ import java.io.File;
* - Added `TERMUX_SUPPORT_EMAIL`, `TERMUX_SUPPORT_EMAIL_URL`, `TERMUX_SUPPORT_EMAIL_MAILTO_URL`,
* `TERMUX_REDDIT_SUBREDDIT`, `TERMUX_REDDIT_SUBREDDIT_URL`.
* - The `TERMUX_SUPPORT_EMAIL_URL` value must be fixed later when email has been set up.
*
* - 0.17.0 (2021-04-07)
* - Added `TERMUX_APP_NOTIFICATION_CHANNEL_ID`, `TERMUX_APP_NOTIFICATION_CHANNEL_NAME`, `TERMUX_APP_NOTIFICATION_ID`,
* `TERMUX_RUN_COMMAND_NOTIFICATION_CHANNEL_ID`, `TERMUX_RUN_COMMAND_NOTIFICATION_CHANNEL_NAME`, `TERMUX_RUN_COMMAND_NOTIFICATION_ID`,
* `TERMUX_PLUGIN_COMMAND_ERRORS_NOTIFICATION_CHANNEL_ID`, `TERMUX_PLUGIN_COMMAND_ERRORS_NOTIFICATION_CHANNEL_NAME`,
* `TERMUX_CRASH_REPORTS_NOTIFICATION_CHANNEL_ID`, `TERMUX_CRASH_REPORTS_NOTIFICATION_CHANNEL_NAME`.
* - Updated javadocs.
*/
/**
* A class that defines shared constants of the Termux app and its plugins.
* This class will be hosted by termux-app and should be imported by other termux plugin apps as is
* instead of copying constants to random classes. The 3rd party apps can also import it for
* interacting with termux apps. If changes are made to this file, increment the version number
* This class will be hosted by termux-shared lib and should be imported by other termux plugin
* apps as is instead of copying constants to random classes. The 3rd party apps can also import
* it for interacting with termux apps. If changes are made to this file, increment the version number
* and add an entry in the Changelog section above.
*
* Termux app default package name is "com.termux" and is used in {@link #TERMUX_PREFIX_DIR_PATH}.
@ -139,22 +146,25 @@ import java.io.File;
*
* Ideally the only places where changes should be required if changing package name are the following:
* - The {@link #TERMUX_PACKAGE_NAME} in {@link TermuxConstants}.
* - The "applicationId" in "build.gradle". This is package name that android and app stores will
* use and is also the final package name stored in "AndroidManifest.xml".
* - The "manifestPlaceholders" values for {@link #TERMUX_PACKAGE_NAME} and *_APP_NAME in "build.gradle".
* - The "ENTITY" values for {@link #TERMUX_PACKAGE_NAME} and *_APP_NAME in "strings.xml".
* - The "shortcut.xml" and "*_preferences.xml" files like in termux-app since dynamic variables don't
* - The "applicationId" in "build.gradle" of termux-app. This is package name that android and app
* stores will use and is also the final package name stored in "AndroidManifest.xml".
* - The "manifestPlaceholders" values for {@link #TERMUX_PACKAGE_NAME} and *_APP_NAME in
* "build.gradle" of termux-app.
* - The "ENTITY" values for {@link #TERMUX_PACKAGE_NAME} and *_APP_NAME in "strings.xml" of
* termux-app and of termux-shared.
* - The "shortcut.xml" and "*_preferences.xml" files of termux-app since dynamic variables don't
* work in it.
* - Optionally the "package" in "AndroidManifest.xml" if modifying project structure. This is
* package name for java classes project structure and is prefixed if activity and service
* names use dot (.) notation.
* - Optionally the "package" in "AndroidManifest.xml" if modifying project structure of termux-app.
* This is package name for java classes project structure and is prefixed if activity and service
* names use dot (.) notation. This is currently not advisable since this will break lot of
* stuff, including termux-* packages.
* - Optionally the *_PATH variables in {@link TermuxConstants} containing the string "termux".
*
* Check https://developer.android.com/studio/build/application-id for info on "package" in
* "AndroidManifest.xml" and "applicationId" in "build.gradle".
*
* {@link #TERMUX_PACKAGE_NAME} must be used in source code of Termux app and its plugins instead of
* hardcoded "com.termux" paths.
* The {@link #TERMUX_PACKAGE_NAME} must be used in source code of Termux app and its plugins instead
* of hardcoded "com.termux" paths.
*/
public final class TermuxConstants {
@ -551,6 +561,38 @@ public final class TermuxConstants {
/*
* Termux app and plugins notification variables.
*/
/** Termux app notification channel id used by {@link TERMUX_APP.TERMUX_SERVICE} */
public static final String TERMUX_APP_NOTIFICATION_CHANNEL_ID = "termux_notification_channel";
/** Termux app notification channel name used by {@link TERMUX_APP.TERMUX_SERVICE} */
public static final String TERMUX_APP_NOTIFICATION_CHANNEL_NAME = TermuxConstants.TERMUX_APP_NAME + " App";
/** Termux app unique notification id used by {@link TERMUX_APP.TERMUX_SERVICE} */
public static final int TERMUX_APP_NOTIFICATION_ID = 1337;
/** Termux app notification channel id used by {@link TERMUX_APP.RUN_COMMAND_SERVICE} */
public static final String TERMUX_RUN_COMMAND_NOTIFICATION_CHANNEL_ID = "termux_run_command_notification_channel";
/** Termux app notification channel name used by {@link TERMUX_APP.RUN_COMMAND_SERVICE} */
public static final String TERMUX_RUN_COMMAND_NOTIFICATION_CHANNEL_NAME = TermuxConstants.TERMUX_APP_NAME + " RunCommandService";
/** Termux app unique notification id used by {@link TERMUX_APP.RUN_COMMAND_SERVICE} */
public static final int TERMUX_RUN_COMMAND_NOTIFICATION_ID = 1338;
/** Termux app notification channel id used for plugin command errors */
public static final String TERMUX_PLUGIN_COMMAND_ERRORS_NOTIFICATION_CHANNEL_ID = "termux_plugin_command_errors_notification_channel";
/** Termux app notification channel name used for plugin command errors */
public static final String TERMUX_PLUGIN_COMMAND_ERRORS_NOTIFICATION_CHANNEL_NAME = TermuxConstants.TERMUX_APP_NAME + " Plugin Commands Errors";
/** Termux app notification channel id used for crash reports */
public static final String TERMUX_CRASH_REPORTS_NOTIFICATION_CHANNEL_ID = "termux_crash_reports_notification_channel";
/** Termux app notification channel name used for crash reports */
public static final String TERMUX_CRASH_REPORTS_NOTIFICATION_CHANNEL_NAME = TermuxConstants.TERMUX_APP_NAME + " Crash Reports";
/*
* Termux app and plugins miscellaneous variables.
*/
@ -647,30 +689,30 @@ public final class TermuxConstants {
/** The value for {@link #EXTRA_SESSION_ACTION} extra that will set the new session as
* the current session and will start {@link TermuxActivity} if its not running to bring
* the current session and will start {@link TERMUX_ACTIVITY} if its not running to bring
* the new session to foreground.
*/
public static final int VALUE_EXTRA_SESSION_ACTION_SWITCH_TO_NEW_SESSION_AND_OPEN_ACTIVITY = 0;
/** The value for {@link #EXTRA_SESSION_ACTION} extra that will keep any existing session
* as the current session and will start {@link TermuxActivity} if its not running to
* as the current session and will start {@link TERMUX_ACTIVITY} if its not running to
* bring the existing session to foreground. The new session will be added to the left
* sidebar in the sessions list.
*/
public static final int VALUE_EXTRA_SESSION_ACTION_KEEP_CURRENT_SESSION_AND_OPEN_ACTIVITY = 1;
/** The value for {@link #EXTRA_SESSION_ACTION} extra that will set the new session as
* the current session but will not start {@link TermuxActivity} if its not running
* the current session but will not start {@link TERMUX_ACTIVITY} if its not running
* and session(s) will be seen in Termux notification and can be clicked to bring new
* session to foreground. If the {@link TermuxActivity} is already running, then this
* session to foreground. If the {@link TERMUX_ACTIVITY} is already running, then this
* will behave like {@link #VALUE_EXTRA_SESSION_ACTION_KEEP_CURRENT_SESSION_AND_OPEN_ACTIVITY}.
*/
public static final int VALUE_EXTRA_SESSION_ACTION_SWITCH_TO_NEW_SESSION_AND_DONT_OPEN_ACTIVITY = 2;
/** The value for {@link #EXTRA_SESSION_ACTION} extra that will keep any existing session
* as the current session but will not start {@link TermuxActivity} if its not running
* as the current session but will not start {@link TERMUX_ACTIVITY} if its not running
* and session(s) will be seen in Termux notification and can be clicked to bring
* existing session to foreground. If the {@link TermuxActivity} is already running,
* existing session to foreground. If the {@link TERMUX_ACTIVITY} is already running,
* then this will behave like {@link #VALUE_EXTRA_SESSION_ACTION_KEEP_CURRENT_SESSION_AND_OPEN_ACTIVITY}.
*/
public static final int VALUE_EXTRA_SESSION_ACTION_KEEP_CURRENT_SESSION_AND_DONT_OPEN_ACTIVITY = 3;

View File

@ -1,4 +1,4 @@
package com.termux.app.utils;
package com.termux.shared.termux;
import android.annotation.SuppressLint;
import android.content.ComponentName;
@ -11,8 +11,10 @@ import androidx.annotation.NonNull;
import com.google.common.base.Joiner;
import com.termux.R;
import com.termux.app.TermuxConstants;
import com.termux.shared.R;
import com.termux.shared.logger.Logger;
import com.termux.shared.markdown.MarkdownUtils;
import com.termux.shared.packages.PackageUtils;
import java.io.BufferedReader;
import java.io.IOException;

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="background_markdown_code_inline">#1F000000</color>
<color name="background_markdown_code_block">#0F000000</color>
</resources>

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE resources [
<!ENTITY TERMUX_PACKAGE_NAME "com.termux">
<!ENTITY TERMUX_APP_NAME "Termux">
<!ENTITY TERMUX_API_APP_NAME "Termux:API">
<!ENTITY TERMUX_BOOT_APP_NAME "Termux:Boot">
<!ENTITY TERMUX_FLOAT_APP_NAME "Termux:Float">
<!ENTITY TERMUX_STYLING_APP_NAME "Termux:Styling">
<!ENTITY TERMUX_TASKER_APP_NAME "Termux:Tasker">
<!ENTITY TERMUX_WIDGET_APP_NAME "Termux:Widget">
]>
<resources>
<!-- FileUtils -->
<string name="error_executable_required">Executable required.</string>
<string name="error_null_or_empty_parameter">The %1$s is to \"%2$s\" null or empty.</string>
<string name="error_null_or_empty_regular_file_path">The regular file path is null or empty.</string>
<string name="error_null_or_empty_regular_file">The regular file is null or empty.</string>
<string name="error_null_or_empty_executable_file_path">The executable file path is null or empty.</string>
<string name="error_null_or_empty_executable_file">The executable file is null or empty.</string>
<string name="error_null_or_empty_directory_file_path">The directory file path is null or empty.</string>
<string name="error_null_or_empty_directory_file">The directory file is null or empty.</string>
<string name="error_file_not_found_at_path">The %1$s is not found at path \"%2$s\".</string>
<string name="error_no_regular_file_found">Regular file not found at %1$s path.</string>
<string name="error_not_a_regular_file">The %1$s at path \"%2$s\" is not a regular file.</string>
<string name="error_non_regular_file_found">Non-regular file found at %1$s path.</string>
<string name="error_non_directory_file_found">Non-directory file found at %1$s path.</string>
<string name="error_non_symlink_file_found">Non-symlink file found at %1$s path.</string>
<string name="error_file_not_an_allowed_file_type">The %1$s found at path \"%2$s\" is not one of allowed file types \"%3$s\".</string>
<string name="error_validate_file_existence_and_permissions_failed_with_exception">Validating file existence and permissions of %1$s at path \"%2$s\" failed.\nException: %3$s</string>
<string name="error_validate_directory_existence_and_permissions_failed_with_exception">Validating directory existence and permissions of %1$s at path \"%2$s\" failed.\nException: %3$s</string>
<string name="error_creating_file_failed">Creating %1$s at path \"%2$s\" failed.</string>
<string name="error_creating_file_failed_with_exception">Creating %1$s at path \"%2$s\" failed.\nException: %3$s</string>
<string name="error_cannot_overwrite_a_non_symlink_file_type">Cannot overwrite %1$s while creating symlink at \"%2$s\" to \"%3$s\" since destination file type \"%4$s\" is not a symlink.</string>
<string name="error_creating_symlink_file_failed_with_exception">Creating %1$s at path \"%2$s\" to \"%3$s\" failed.\nException: %4$s</string>
<string name="error_copying_or_moving_file_failed_with_exception">%1$s from \"%2$s\" to \"%3$s\" failed.\nException: %4$s</string>
<string name="error_copying_or_moving_file_to_same_path">%1$s from \"%2$s\" to \"%3$s\" cannot be done since they point to the same path.</string>
<string name="error_cannot_overwrite_a_different_file_type">Cannot overwrite %1$s while %2$s it from \"%3$s\" to \"%4$s\" since destination file type \"%5$s\" is different from source file type \"%6$s\".</string>
<string name="error_cannot_move_directory_to_sub_directory_of_itself">Cannot move %1$s from \"%2$s\" to \"%3$s\" since destination is a subdirectory of the source.</string>
<string name="error_file_still_exists_after_deleting">The %1$s still exists after deleting it from \"%2$s\".</string>
<string name="error_deleting_file_failed">Deleting %1$s at path \"%2$s\" failed.</string>
<string name="error_deleting_file_failed_with_exception">Deleting %1$s at path \"%2$s\" failed.\nException: %3$s</string>
<string name="error_clearing_directory_failed_with_exception">Clearing %1$s at path \"%2$s\" failed.\nException: %3$s</string>
<string name="error_reading_string_to_file_failed_with_exception">Reading string from %1$s at path \"%2$s\" failed.\nException: %3$s</string>
<string name="error_writing_string_to_file_failed_with_exception">Writing string to %1$s at path \"%2$s\" failed.\nException: %3$s</string>
<string name="error_unsupported_charset">Unsupported charset \"%1$s\"</string>
<string name="error_checking_if_charset_supported_failed">Checking if charset \"%1$s\" is suppoted failed.\nException: %2$s</string>
<string name="error_invalid_file_permissions_string_to_check">The file permission string to check is invalid.</string>
<string name="error_file_not_readable">The %1$s at path is not readable. Permission Denied.</string>
<string name="error_file_not_writable">The %1$s at path is not writable. Permission Denied.</string>
<string name="error_file_not_executable">The %1$s at path is not executable. Permission Denied.</string>
<!-- PermissionUtils -->
<string name="message_sudo_please_grant_permissions">Please grant permissions on next screen</string>
<string name="error_display_over_other_apps_permission_not_granted">&TERMUX_APP_NAME; requires \"Display over other apps\" permission to start terminal sessions from background on Android >= 10. Grants it from Settings -> Apps -> &TERMUX_APP_NAME; -> Advanced</string>
<!-- ShareUtils -->
<string name="title_share_with">Share With</string>
<!-- TermuxUtils -->
<string name="msg_report_issue">If you think this report should be reported, then copy its text from the options menu (3-dots on top right) and post an issue on one of the following links at which the report belongs at.</string>
<!-- Log Level -->
<string name="log_level_title">Log Level</string>
<string name="log_level_off">"Off"</string>
<string name="log_level_normal">"Normal"</string>
<string name="log_level_debug">"Debug"</string>
<string name="log_level_verbose">"Verbose"</string>
<string name="log_level_unknown">"*Unknown*"</string>
<string name="log_level_value">Logcat log level set to \"%1$s\"</string>
</resources>