Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a5da83ce2 | ||
|
|
97f01387b9 | ||
|
|
012ff83a06 | ||
|
|
a082c63849 | ||
|
|
8c27084086 | ||
|
|
f4fb45cbd6 | ||
|
|
0605fc4843 | ||
|
|
3bbd61f9d7 | ||
|
|
42fc0ea1cd | ||
|
|
6218d08037 | ||
|
|
10fe238ddb | ||
|
|
fe41cd486f | ||
|
|
bda80547ad | ||
|
|
70a786613d | ||
|
|
e4220a7ab1 | ||
|
|
bd45837d93 | ||
|
|
ddf5341b86 | ||
|
|
85a48a79a3 | ||
|
|
e3512c957d | ||
|
|
330301899a | ||
|
|
2a36b915cb | ||
|
|
c986a46fb9 | ||
|
|
ed8bd4b569 |
@@ -14,8 +14,8 @@ android {
|
|||||||
applicationId "com.termux"
|
applicationId "com.termux"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 66
|
versionCode 69
|
||||||
versionName "0.66"
|
versionName "0.69"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.termux.app.TermuxActivity"
|
android:name="com.termux.app.TermuxActivity"
|
||||||
|
android:label="@string/application_name"
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:resizeableActivity="true"
|
android:resizeableActivity="true"
|
||||||
@@ -37,14 +38,25 @@
|
|||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts" />
|
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="com.termux.app.TermuxFailsafeActivity"
|
||||||
|
android:label="@string/app_failsafe_mode" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.termux.app.TermuxHelpActivity"
|
android:name="com.termux.app.TermuxHelpActivity"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
|
|||||||
@@ -93,32 +93,54 @@ public final class BackgroundJob {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String[] buildEnvironment(boolean failSafe, String cwd) {
|
static String[] buildEnvironment(boolean failSafe, String cwd) {
|
||||||
new File(TermuxService.HOME_PATH).mkdirs();
|
new File(TermuxService.HOME_PATH).mkdirs();
|
||||||
|
|
||||||
if (cwd == null) cwd = TermuxService.HOME_PATH;
|
if (cwd == null) cwd = TermuxService.HOME_PATH;
|
||||||
|
|
||||||
final String termEnv = "TERM=xterm-256color";
|
List<String> environment = new ArrayList<>();
|
||||||
final String homeEnv = "HOME=" + TermuxService.HOME_PATH;
|
|
||||||
final String prefixEnv = "PREFIX=" + TermuxService.PREFIX_PATH;
|
environment.add("TERM=xterm-256color");
|
||||||
final String androidRootEnv = "ANDROID_ROOT=" + System.getenv("ANDROID_ROOT");
|
environment.add("HOME=" + TermuxService.HOME_PATH);
|
||||||
final String androidDataEnv = "ANDROID_DATA=" + System.getenv("ANDROID_DATA");
|
environment.add("PREFIX=" + TermuxService.PREFIX_PATH);
|
||||||
|
environment.add("ANDROID_ROOT=" + System.getenv("ANDROID_ROOT"));
|
||||||
|
environment.add("ANDROID_DATA=" + System.getenv("ANDROID_DATA"));
|
||||||
// EXTERNAL_STORAGE is needed for /system/bin/am to work on at least
|
// EXTERNAL_STORAGE is needed for /system/bin/am to work on at least
|
||||||
// Samsung S7 - see https://plus.google.com/110070148244138185604/posts/gp8Lk3aCGp3.
|
// Samsung S7 - see https://plus.google.com/110070148244138185604/posts/gp8Lk3aCGp3.
|
||||||
final String externalStorageEnv = "EXTERNAL_STORAGE=" + System.getenv("EXTERNAL_STORAGE");
|
environment.add("EXTERNAL_STORAGE=" + System.getenv("EXTERNAL_STORAGE"));
|
||||||
|
String androidRuntimeRoot = System.getenv("ANDROID_RUNTIME_ROOT");
|
||||||
|
// ANDROID_RUNTIME_ROOT is required for `am` to run on Android Q
|
||||||
|
if (androidRuntimeRoot != null) {
|
||||||
|
environment.add("ANDROID_RUNTIME_ROOT=" + androidRuntimeRoot);
|
||||||
|
}
|
||||||
if (failSafe) {
|
if (failSafe) {
|
||||||
// Keep the default path so that system binaries can be used in the failsafe session.
|
// Keep the default path so that system binaries can be used in the failsafe session.
|
||||||
final String pathEnv = "PATH=" + System.getenv("PATH");
|
environment.add("PATH= " + System.getenv("PATH"));
|
||||||
return new String[]{termEnv, homeEnv, prefixEnv, androidRootEnv, androidDataEnv, pathEnv, externalStorageEnv};
|
|
||||||
} else {
|
} else {
|
||||||
final String ldEnv = "LD_LIBRARY_PATH=" + TermuxService.PREFIX_PATH + "/lib";
|
if (shouldAddLdLibraryPath()) {
|
||||||
final String langEnv = "LANG=en_US.UTF-8";
|
environment.add("LD_LIBRARY_PATH=" + TermuxService.PREFIX_PATH + "/lib");
|
||||||
final String pathEnv = "PATH=" + TermuxService.PREFIX_PATH + "/bin:" + TermuxService.PREFIX_PATH + "/bin/applets";
|
|
||||||
final String pwdEnv = "PWD=" + cwd;
|
|
||||||
final String tmpdirEnv = "TMPDIR=" + TermuxService.PREFIX_PATH + "/tmp";
|
|
||||||
|
|
||||||
return new String[]{termEnv, homeEnv, prefixEnv, ldEnv, langEnv, pathEnv, pwdEnv, androidRootEnv, androidDataEnv, externalStorageEnv, tmpdirEnv};
|
|
||||||
}
|
}
|
||||||
|
environment.add("LANG=en_US.UTF-8");
|
||||||
|
environment.add("PATH=" + TermuxService.PREFIX_PATH + "/bin:" + TermuxService.PREFIX_PATH + "/bin/applets");
|
||||||
|
environment.add("PWD=" + cwd);
|
||||||
|
environment.add("TMPDIR=" + TermuxService.PREFIX_PATH + "/tmp");
|
||||||
|
}
|
||||||
|
|
||||||
|
return environment.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean shouldAddLdLibraryPath() {
|
||||||
|
try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(TermuxService.PREFIX_PATH + "/etc/apt/sources.list")))) {
|
||||||
|
String line;
|
||||||
|
while ((line = in.readLine()) != null) {
|
||||||
|
if (!line.startsWith("#") && line.contains("https://dl.bintray.com/termux/termux-packages-24")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(LOG_TAG, "Error trying to read sources.list", e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getPid(Process p) {
|
public static int getPid(Process p) {
|
||||||
|
|||||||
63
app/src/main/java/com/termux/app/BellUtil.java
Normal file
63
app/src/main/java/com/termux/app/BellUtil.java
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package com.termux.app;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.os.Vibrator;
|
||||||
|
|
||||||
|
public class BellUtil {
|
||||||
|
private static BellUtil instance = null;
|
||||||
|
private static final Object lock = new Object();
|
||||||
|
|
||||||
|
public static BellUtil with(Context context) {
|
||||||
|
if (instance == null) {
|
||||||
|
synchronized (lock) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new BellUtil((Vibrator) context.getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final long DURATION = 50;
|
||||||
|
private static final long MIN_PAUSE = 3 * DURATION;
|
||||||
|
|
||||||
|
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
private long lastBell = 0;
|
||||||
|
private final Runnable bellRunnable;
|
||||||
|
|
||||||
|
private BellUtil(final Vibrator vibrator) {
|
||||||
|
bellRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (vibrator != null) {
|
||||||
|
vibrator.vibrate(DURATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void doBell() {
|
||||||
|
long now = now();
|
||||||
|
long timeSinceLastBell = now - lastBell;
|
||||||
|
|
||||||
|
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
|
||||||
|
handler.postDelayed(bellRunnable, MIN_PAUSE - timeSinceLastBell);
|
||||||
|
lastBell = lastBell + MIN_PAUSE;
|
||||||
|
} else {
|
||||||
|
// the last bell was long ago, do it now
|
||||||
|
bellRunnable.run();
|
||||||
|
lastBell = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private long now() {
|
||||||
|
return SystemClock.uptimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -84,7 +84,7 @@ public final class ExtraKeysView extends GridLayout {
|
|||||||
} else {
|
} else {
|
||||||
// not a control char
|
// not a control char
|
||||||
TerminalSession session = terminalView.getCurrentSession();
|
TerminalSession session = terminalView.getCurrentSession();
|
||||||
if (session != null)
|
if (session != null && keyName.length() > 0)
|
||||||
session.write(keyName);
|
session.write(keyName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,6 +116,10 @@ public final class ExtraKeysView extends GridLayout {
|
|||||||
if (! state.isOn)
|
if (! state.isOn)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (state.button == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (state.button.isPressed())
|
if (state.button.isPressed())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
|||||||
if (session != null) {
|
if (session != null) {
|
||||||
if (session.isRunning()) {
|
if (session.isRunning()) {
|
||||||
String textToSend = editText.getText().toString();
|
String textToSend = editText.getText().toString();
|
||||||
if (textToSend.length() == 0) textToSend = "\n";
|
if (textToSend.length() == 0) textToSend = "\r";
|
||||||
session.write(textToSend);
|
session.write(textToSend);
|
||||||
} else {
|
} else {
|
||||||
removeFinishedSession(session);
|
removeFinishedSession(session);
|
||||||
@@ -367,9 +367,19 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
|||||||
showToast(toToastTitle(finishedSession) + " - exited", true);
|
showToast(toToastTitle(finishedSession) + " - exited", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
|
||||||
|
// On Android TV devices we need to use older behaviour because we may
|
||||||
|
// not be able to have multiple launcher icons.
|
||||||
if (mTermService.getSessions().size() > 1) {
|
if (mTermService.getSessions().size() > 1) {
|
||||||
removeFinishedSession(finishedSession);
|
removeFinishedSession(finishedSession);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Once we have a separate launcher icon for the failsafe session, it
|
||||||
|
// should be safe to auto-close session on exit code '0' or '130'.
|
||||||
|
if (finishedSession.getExitStatus() == 0 || finishedSession.getExitStatus() == 130) {
|
||||||
|
removeFinishedSession(finishedSession);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mListViewAdapter.notifyDataSetChanged();
|
mListViewAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
@@ -390,7 +400,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
|||||||
mBellSoundPool.play(mBellSoundId, 1.f, 1.f, 1, 0, 1.f);
|
mBellSoundPool.play(mBellSoundId, 1.f, 1.f, 1, 0, 1.f);
|
||||||
break;
|
break;
|
||||||
case TermuxPreferences.BELL_VIBRATE:
|
case TermuxPreferences.BELL_VIBRATE:
|
||||||
((Vibrator) getSystemService(VIBRATOR_SERVICE)).vibrate(50);
|
BellUtil.with(TermuxActivity.this).doBell();
|
||||||
break;
|
break;
|
||||||
case TermuxPreferences.BELL_IGNORE:
|
case TermuxPreferences.BELL_IGNORE:
|
||||||
// Ignore the bell character.
|
// Ignore the bell character.
|
||||||
@@ -465,7 +475,13 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
|||||||
TermuxInstaller.setupIfNeeded(TermuxActivity.this, () -> {
|
TermuxInstaller.setupIfNeeded(TermuxActivity.this, () -> {
|
||||||
if (mTermService == null) return; // Activity might have been destroyed.
|
if (mTermService == null) return; // Activity might have been destroyed.
|
||||||
try {
|
try {
|
||||||
addNewSession(false, null);
|
Bundle bundle = getIntent().getExtras();
|
||||||
|
boolean launchFailsafe = false;
|
||||||
|
if (bundle != null) {
|
||||||
|
launchFailsafe = bundle.getBoolean(TermuxFailsafeActivity.TERMUX_FAILSAFE_SESSION_ACTION, false);
|
||||||
|
}
|
||||||
|
clearTemporaryDirectory();
|
||||||
|
addNewSession(launchFailsafe, null);
|
||||||
} catch (WindowManager.BadTokenException e) {
|
} catch (WindowManager.BadTokenException e) {
|
||||||
// Activity finished - ignore.
|
// Activity finished - ignore.
|
||||||
}
|
}
|
||||||
@@ -478,6 +494,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
|||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
if (i != null && Intent.ACTION_RUN.equals(i.getAction())) {
|
if (i != null && Intent.ACTION_RUN.equals(i.getAction())) {
|
||||||
// Android 7.1 app shortcut from res/xml/shortcuts.xml.
|
// Android 7.1 app shortcut from res/xml/shortcuts.xml.
|
||||||
|
clearTemporaryDirectory();
|
||||||
addNewSession(false, null);
|
addNewSession(false, null);
|
||||||
} else {
|
} else {
|
||||||
switchToSession(getStoredCurrentSessionOrLast());
|
switchToSession(getStoredCurrentSessionOrLast());
|
||||||
@@ -572,18 +589,6 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
|||||||
new AlertDialog.Builder(this).setTitle(R.string.max_terminals_reached_title).setMessage(R.string.max_terminals_reached_message)
|
new AlertDialog.Builder(this).setTitle(R.string.max_terminals_reached_title).setMessage(R.string.max_terminals_reached_message)
|
||||||
.setPositiveButton(android.R.string.ok, null).show();
|
.setPositiveButton(android.R.string.ok, null).show();
|
||||||
} else {
|
} else {
|
||||||
if (mTermService.getSessions().size() == 0 && !mTermService.isWakelockEnabled()) {
|
|
||||||
File termuxTmpDir = new File(TermuxService.PREFIX_PATH + "/tmp");
|
|
||||||
if (termuxTmpDir.exists()) {
|
|
||||||
try {
|
|
||||||
TermuxInstaller.deleteFolder(termuxTmpDir);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
termuxTmpDir.mkdirs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String executablePath = (failSafe ? "/system/bin/sh" : null);
|
String executablePath = (failSafe ? "/system/bin/sh" : null);
|
||||||
TerminalSession newSession = mTermService.createTermSession(executablePath, null, null, failSafe);
|
TerminalSession newSession = mTermService.createTermSession(executablePath, null, null, failSafe);
|
||||||
if (sessionName != null) {
|
if (sessionName != null) {
|
||||||
@@ -828,4 +833,18 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clearTemporaryDirectory() {
|
||||||
|
if (mTermService.getSessions().size() == 0 && !mTermService.isWakelockEnabled()) {
|
||||||
|
File termuxTmpDir = new File(TermuxService.PREFIX_PATH + "/tmp");
|
||||||
|
if (termuxTmpDir.exists()) {
|
||||||
|
try {
|
||||||
|
TermuxInstaller.deleteFolder(termuxTmpDir);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
termuxTmpDir.mkdirs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
app/src/main/java/com/termux/app/TermuxFailsafeActivity.java
Normal file
19
app/src/main/java/com/termux/app/TermuxFailsafeActivity.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package com.termux.app;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
public final class TermuxFailsafeActivity extends Activity {
|
||||||
|
|
||||||
|
public static final String TERMUX_FAILSAFE_SESSION_ACTION = "com.termux.app.failsafe_session";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle bundle) {
|
||||||
|
super.onCreate(bundle);
|
||||||
|
Intent intent = new Intent(TermuxFailsafeActivity.this, TermuxActivity.class);
|
||||||
|
intent.putExtra(TERMUX_FAILSAFE_SESSION_ACTION, true);
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -170,7 +170,10 @@ final class TermuxInstaller {
|
|||||||
/** Get bootstrap zip url for this systems cpu architecture. */
|
/** Get bootstrap zip url for this systems cpu architecture. */
|
||||||
private static URL determineZipUrl() throws MalformedURLException {
|
private static URL determineZipUrl() throws MalformedURLException {
|
||||||
String archName = determineTermuxArchName();
|
String archName = determineTermuxArchName();
|
||||||
return new URL("https://termux.net/bootstrap/bootstrap-" + archName + ".zip");
|
String url = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
|
||||||
|
? "https://termux.org/bootstrap-" + archName + ".zip"
|
||||||
|
: "https://termux.net/bootstrap/bootstrap-" + archName + ".zip";
|
||||||
|
return new URL(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String determineTermuxArchName() {
|
private static String determineTermuxArchName() {
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public class TermuxOpenReceiver extends BroadcastReceiver {
|
|||||||
contentTypeToUse = contentTypeExtra;
|
contentTypeToUse = contentTypeExtra;
|
||||||
}
|
}
|
||||||
|
|
||||||
Uri uriToShare = Uri.withAppendedPath(Uri.parse("content://com.termux.files/"), filePath);
|
Uri uriToShare = Uri.parse("content://com.termux.files" + fileToShare.getAbsolutePath());
|
||||||
|
|
||||||
if (Intent.ACTION_SEND.equals(intentAction)) {
|
if (Intent.ACTION_SEND.equals(intentAction)) {
|
||||||
sendIntent.putExtra(Intent.EXTRA_STREAM, uriToShare);
|
sendIntent.putExtra(Intent.EXTRA_STREAM, uriToShare);
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ final class TermuxPreferences {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Toast.makeText(context, "Could not open the propertiey file termux.properties.", Toast.LENGTH_LONG).show();
|
Toast.makeText(context, "Could not open properties file termux.properties.", Toast.LENGTH_LONG).show();
|
||||||
Log.e("termux", "Error loading props", e);
|
Log.e("termux", "Error loading props", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -295,6 +295,12 @@ public final class TermuxService extends Service implements SessionChangedCallba
|
|||||||
TerminalSession session = new TerminalSession(executablePath, cwd, args, env, this);
|
TerminalSession session = new TerminalSession(executablePath, cwd, args, env, this);
|
||||||
mTerminalSessions.add(session);
|
mTerminalSessions.add(session);
|
||||||
updateNotification();
|
updateNotification();
|
||||||
|
|
||||||
|
// Make sure that terminal styling is always applied.
|
||||||
|
Intent stylingIntent = new Intent("com.termux.app.reload_style");
|
||||||
|
stylingIntent.putExtra("com.termux.app.reload_style", "styling");
|
||||||
|
sendBroadcast(stylingIntent);
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
|
android:textColorHighlight="@android:color/darker_gray"
|
||||||
android:paddingTop="0dp"
|
android:paddingTop="0dp"
|
||||||
android:textCursorDrawable="@null"
|
android:textCursorDrawable="@null"
|
||||||
android:paddingBottom="0dp"
|
android:paddingBottom="0dp"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="application_name">Termux</string>
|
<string name="application_name">Termux</string>
|
||||||
<string name="shared_user_label">Termux user</string>
|
<string name="shared_user_label">Termux user</string>
|
||||||
|
<string name="app_failsafe_mode">Termux (failsafe)</string>
|
||||||
<string name="new_session">New session</string>
|
<string name="new_session">New session</string>
|
||||||
<string name="new_session_failsafe">Failsafe</string>
|
<string name="new_session_failsafe">Failsafe</string>
|
||||||
<string name="toggle_soft_keyboard">Keyboard</string>
|
<string name="toggle_soft_keyboard">Keyboard</string>
|
||||||
@@ -48,5 +49,4 @@
|
|||||||
<string name="file_received_title">Save file in ~/downloads/</string>
|
<string name="file_received_title">Save file in ~/downloads/</string>
|
||||||
<string name="file_received_edit_button">Edit</string>
|
<string name="file_received_edit_button">Edit</string>
|
||||||
<string name="file_received_open_folder_button">Open folder</string>
|
<string name="file_received_open_folder_button">Open folder</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ buildscript {
|
|||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.3.0'
|
classpath 'com.android.tools.build:gradle:3.4.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
2
gradlew
vendored
2
gradlew
vendored
@@ -28,7 +28,7 @@ APP_NAME="Gradle"
|
|||||||
APP_BASE_NAME=`basename "$0"`
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
DEFAULT_JVM_OPTS=""
|
DEFAULT_JVM_OPTS='"-Xmx64m"'
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD="maximum"
|
MAX_FD="maximum"
|
||||||
|
|||||||
2
gradlew.bat
vendored
2
gradlew.bat
vendored
@@ -14,7 +14,7 @@ set APP_BASE_NAME=%~n0
|
|||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
set DEFAULT_JVM_OPTS=
|
set DEFAULT_JVM_OPTS="-Xmx64m"
|
||||||
|
|
||||||
@rem Find java.exe
|
@rem Find java.exe
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.termux.terminal;
|
package com.termux.terminal;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A circular buffer of {@link TerminalRow}:s which keeps notes about what is visible on a logical screen and the scroll
|
* A circular buffer of {@link TerminalRow}:s which keeps notes about what is visible on a logical screen and the scroll
|
||||||
* history.
|
* history.
|
||||||
@@ -422,4 +424,14 @@ public final class TerminalBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clearTranscript() {
|
||||||
|
if (mScreenFirstRow < mActiveTranscriptRows) {
|
||||||
|
Arrays.fill(mLines, mTotalRows + mScreenFirstRow - mActiveTranscriptRows, mTotalRows, null);
|
||||||
|
Arrays.fill(mLines, 0, mScreenFirstRow, null);
|
||||||
|
} else {
|
||||||
|
Arrays.fill(mLines, mScreenFirstRow - mActiveTranscriptRows, mScreenFirstRow, null);
|
||||||
|
}
|
||||||
|
mActiveTranscriptRows = 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1404,7 +1404,7 @@ public final class TerminalEmulator {
|
|||||||
case 'I': // Cursor Horizontal Forward Tabulation (CHT). Move the active position n tabs forward.
|
case 'I': // Cursor Horizontal Forward Tabulation (CHT). Move the active position n tabs forward.
|
||||||
setCursorCol(nextTabStop(getArg0(1)));
|
setCursorCol(nextTabStop(getArg0(1)));
|
||||||
break;
|
break;
|
||||||
case 'J': // "${CSI}${0,1,2}J" - Erase in Display (ED)
|
case 'J': // "${CSI}${0,1,2,3}J" - Erase in Display (ED)
|
||||||
// ED ignores the scrolling margins.
|
// ED ignores the scrolling margins.
|
||||||
switch (getArg0(0)) {
|
switch (getArg0(0)) {
|
||||||
case 0: // Erase from the active position to the end of the screen, inclusive (default).
|
case 0: // Erase from the active position to the end of the screen, inclusive (default).
|
||||||
@@ -1419,6 +1419,9 @@ public final class TerminalEmulator {
|
|||||||
// move..
|
// move..
|
||||||
blockClear(0, 0, mColumns, mRows);
|
blockClear(0, 0, mColumns, mRows);
|
||||||
break;
|
break;
|
||||||
|
case 3: // Delete all lines saved in the scrollback buffer (xterm etc)
|
||||||
|
mMainBuffer.clearTranscript();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
unknownSequence(b);
|
unknownSequence(b);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -46,4 +46,20 @@ public class ControlSequenceIntroducerTest extends TerminalTestCase {
|
|||||||
withTerminalSized(5, 2).enterString("abcde\033[2G\033[2b\n").assertLinesAre("aeede", " ");
|
withTerminalSized(5, 2).enterString("abcde\033[2G\033[2b\n").assertLinesAre("aeede", " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** CSI 3 J Clear scrollback (xterm, libvte; non-standard). */
|
||||||
|
public void testCsi3J() {
|
||||||
|
withTerminalSized(3, 2).enterString("a\r\nb\r\nc\r\nd");
|
||||||
|
assertEquals("a\nb\nc\nd", mTerminal.getScreen().getTranscriptText());
|
||||||
|
enterString("\033[3J");
|
||||||
|
assertEquals("c\nd", mTerminal.getScreen().getTranscriptText());
|
||||||
|
|
||||||
|
withTerminalSized(3, 2).enterString("Lorem_ipsum");
|
||||||
|
assertEquals("Lorem_ipsum", mTerminal.getScreen().getTranscriptText());
|
||||||
|
enterString("\033[3J");
|
||||||
|
assertEquals("ipsum", mTerminal.getScreen().getTranscriptText());
|
||||||
|
|
||||||
|
withTerminalSized(3, 2).enterString("w\r\nx\r\ny\r\nz\033[?1049h\033[3J\033[?1049l");
|
||||||
|
assertEquals("y\nz", mTerminal.getScreen().getTranscriptText());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -358,10 +358,12 @@ public final class TerminalView extends View {
|
|||||||
public void onScreenUpdated() {
|
public void onScreenUpdated() {
|
||||||
if (mEmulator == null) return;
|
if (mEmulator == null) return;
|
||||||
|
|
||||||
|
int rowsInHistory = mEmulator.getScreen().getActiveTranscriptRows();
|
||||||
|
if (mTopRow < -rowsInHistory) mTopRow = -rowsInHistory;
|
||||||
|
|
||||||
boolean skipScrolling = false;
|
boolean skipScrolling = false;
|
||||||
if (mIsSelectingText) {
|
if (mIsSelectingText) {
|
||||||
// Do not scroll when selecting text.
|
// Do not scroll when selecting text.
|
||||||
int rowsInHistory = mEmulator.getScreen().getActiveTranscriptRows();
|
|
||||||
int rowShift = mEmulator.getScrollCounter();
|
int rowShift = mEmulator.getScrollCounter();
|
||||||
if (-mTopRow + rowShift > rowsInHistory) {
|
if (-mTopRow + rowShift > rowsInHistory) {
|
||||||
// .. unless we're hitting the end of history transcript, in which
|
// .. unless we're hitting the end of history transcript, in which
|
||||||
|
|||||||
Reference in New Issue
Block a user