diff --git a/.cirrus.yml b/.cirrus.yml
index 72d9b530..8e6a5449 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -1,40 +1,20 @@
container:
image: cirrusci/android-sdk:28
- cpu: 4
+ cpu: 2
memory: 8G
task:
- name: Run tests
+ name: tests
script: ./gradlew test
task:
- name: Build release apk
+ name: debug-build
depends_on:
- - Run tests
+ - tests
- environment:
- KEYSTORE: ENCRYPTED[e3fa3d741db3c2929acabef0c954e995b7f86d8229f7796199ce6e15ae98cb8eae16b2e498b9daeafff35e1f3aba3f8f]
- KEYSTORE_PASSWORD: ENCRYPTED[2761e799baef14b1c822dfcbe5a40ba3ae8e8c13be25563baed28ff35f66e51fa725aa9dcd29c0698023cd04a8ebd604]
+ script: |
+ ./gradlew assembleDebug
- build_release_apk_script: |
- ./gradlew assembleRelease
-
- build_apksigner_script: |
- cd ../
- git clone https://github.com/fornwall/apksigner
- cd apksigner
- ./gradlew
- cp ./build/libs/apksigner-all.jar /tmp/apksigner.jar
-
- sign_release_apk_script: |
- echo "$KEYSTORE" | base64 -d > keystore.jks
- java -jar /tmp/apksigner.jar -p "$KEYSTORE_PASSWORD" keystore.jks \
- ./app/build/outputs/apk/release/app-release-unsigned.apk \
- ./termux-release-g${CIRRUS_CHANGE_IN_REPO:0:8}.apk
-
- release_artifacts:
- path: "./*.apk"
-
- unsigned_artifacts:
- path: "./app/build/outputs/apk/release/*.apk"
+ output_artifacts:
+ path: "./app/build/outputs/apk/debug/*.apk"
diff --git a/.gitignore b/.gitignore
index a7327fba..5f7ee3c3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,8 @@ build/
*.apk
*.so
.externalNativeBuild
+.cxx
+*.zip
# Crashlytics configuations
com_crashlytics_export_strings.xml
diff --git a/README.md b/README.md
index 3c865508..734fc6a4 100644
--- a/README.md
+++ b/README.md
@@ -5,8 +5,6 @@
[Termux](https://termux.com) is an Android terminal application and Linux environment.
-- [Termux on Google Play Store](https://play.google.com/store/apps/details?id=com.termux)
-- [Termux on F-Droid](https://f-droid.org/repository/browse/?fdid=com.termux)
- [Termux Reddit community](https://reddit.com/r/termux)
- [Termux Wiki](https://wiki.termux.com/wiki/)
- [Termux Twitter](http://twitter.com/termux/)
@@ -15,6 +13,22 @@ Note that this repository is for the app itself (the user interface and the
terminal emulation). For the packages installable inside the app, see
[termux/termux-packages](https://github.com/termux/termux-packages)
+## Installation
+
+Termux:Widget application can be obtained from:
+
+- [Google Play](https://play.google.com/store/apps/details?id=com.termux)
+- [F-Droid](https://f-droid.org/en/packages/com.termux/)
+- [Kali Nethunter Store](https://store.nethunter.com/en/packages/com.termux/)
+
+Additionally we offer development builds for those who want to try out latest
+features ready to be included in future versions. Such build can be obtained
+directly from [Cirrus CI artifacts](https://api.cirrus-ci.com/v1/artifact/github/termux/termux-app/debug-build/output/app/build/outputs/apk/debug/app-debug.apk).
+
+Signature keys of all offered builds are different. Before you switch the
+installation source, you will have to uninstall the Termux application and
+all currently installed plugins.
+
## Terminal resources
- [XTerm control sequences](http://invisible-island.net/xterm/ctlseqs/ctlseqs.html)
diff --git a/app/build.gradle b/app/build.gradle
index b3b1d12e..d56089c0 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,4 +1,6 @@
-apply plugin: 'com.android.application'
+plugins {
+ id "com.android.application"
+}
android {
compileSdkVersion 28
@@ -12,10 +14,30 @@ android {
defaultConfig {
applicationId "com.termux"
- minSdkVersion 21
+ minSdkVersion 24
targetSdkVersion 28
- versionCode 75
- versionName "0.75"
+ versionCode 84
+ versionName "0.84"
+
+ externalNativeBuild {
+ ndkBuild {
+ cFlags "-std=c11", "-Wall", "-Wextra", "-Werror", "-Os", "-fno-stack-protector", "-Wl,--gc-sections"
+ }
+ }
+
+ ndk {
+ abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
+ }
+
+ }
+
+ signingConfigs {
+ debug {
+ storeFile file('dev_keystore.jks')
+ keyAlias 'alias'
+ storePassword 'xrj45yWGLbsO7W0v'
+ keyPassword 'xrj45yWGLbsO7W0v'
+ }
}
buildTypes {
@@ -24,12 +46,22 @@ android {
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
+
+ debug {
+ signingConfig signingConfigs.debug
+ }
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ externalNativeBuild {
+ ndkBuild {
+ path "src/main/cpp/Android.mk"
+ }
+ }
}
dependencies {
@@ -41,3 +73,69 @@ task versionName {
print android.defaultConfig.versionName
}
}
+
+def downloadBootstrap(String arch, String expectedChecksum, int version) {
+ def digest = java.security.MessageDigest.getInstance("SHA-256")
+
+ def localUrl = "src/main/cpp/bootstrap-" + arch + ".zip"
+ def file = new File(projectDir, localUrl)
+ if (file.exists()) {
+ def buffer = new byte[8192]
+ def input = new FileInputStream(file)
+ while (true) {
+ def readBytes = input.read(buffer)
+ if (readBytes < 0) break
+ digest.update(buffer, 0, readBytes)
+ }
+ def checksum = new BigInteger(1, digest.digest()).toString(16)
+ if (checksum == expectedChecksum) {
+ return
+ } else {
+ logger.quiet("Deleting old local file with wrong hash: " + localUrl)
+ file.delete()
+ }
+ }
+
+ def remoteUrl = "https://bintray.com/termux/bootstrap/download_file?file_path=bootstrap-" + arch + "-v" + version + ".zip"
+ logger.quiet("Downloading " + remoteUrl + " ...")
+
+ file.parentFile.mkdirs()
+ def out = new BufferedOutputStream(new FileOutputStream(file))
+
+ def connection = new URL(remoteUrl).openConnection()
+ connection.setInstanceFollowRedirects(true)
+ def digestStream = new java.security.DigestInputStream(connection.inputStream, digest)
+ out << digestStream
+ out.close()
+
+ def checksum = new BigInteger(1, digest.digest()).toString(16)
+ if (checksum != expectedChecksum) {
+ file.delete()
+ throw new GradleException("Wrong checksum for " + remoteUrl + ": expected: " + expectedChecksum + ", actual: " + checksum)
+ }
+}
+
+clean {
+ doLast {
+ def tree = fileTree(new File(projectDir, 'src/main/cpp'))
+ tree.include 'bootstrap-*.zip'
+ tree.each { it.delete() }
+ }
+}
+
+task downloadBootstraps(){
+ doLast {
+ def version = 18
+ downloadBootstrap("aarch64", "1a4c08a696d452b58f69102428239ec0c07521c0ca9f48b23ef70ae0e5e3d4f8", version)
+ downloadBootstrap("arm", "bff11f2c7e9c1055a22fc5f20bb7507b75f6034e0f5d591ec6725b3407981b85", version)
+ downloadBootstrap("i686", "6fb93020db2807337d82a1537e24612400cacbd10cf4bccaeb0714d51e653da1", version)
+ downloadBootstrap("x86_64", "a6067e5decc486dcad190c1ed9e15366c798e5e7d9b9b9ee6b4b8231290524c3", version)
+ }
+}
+
+afterEvaluate {
+ android.applicationVariants.all { variant ->
+ variant.javaCompileProvider.get().dependsOn(downloadBootstraps)
+ }
+}
+
diff --git a/app/dev_keystore.jks b/app/dev_keystore.jks
new file mode 100644
index 00000000..174cc95a
Binary files /dev/null and b/app/dev_keystore.jks differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 17aecc5c..901c1bbe 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -8,17 +8,17 @@
+
-
+
+
+extern jbyte blob[];
+extern int blob_size;
+
+JNIEXPORT jbyteArray JNICALL Java_com_termux_app_TermuxInstaller_getZip(JNIEnv *env, __attribute__((__unused__)) jobject This)
+{
+ jbyteArray ret = (*env)->NewByteArray(env, blob_size);
+ (*env)->SetByteArrayRegion(env, ret, 0, blob_size, blob);
+ return ret;
+}
diff --git a/app/src/main/java/com/termux/app/BackgroundJob.java b/app/src/main/java/com/termux/app/BackgroundJob.java
index 11c89851..5fef2bd1 100644
--- a/app/src/main/java/com/termux/app/BackgroundJob.java
+++ b/app/src/main/java/com/termux/app/BackgroundJob.java
@@ -139,14 +139,14 @@ public final class BackgroundJob {
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;
+ if (!line.startsWith("#") && line.contains("//termux.net stable")) {
+ return true;
}
}
} catch (IOException e) {
Log.e(LOG_TAG, "Error trying to read sources.list", e);
}
- return true;
+ return false;
}
public static int getPid(Process p) {
diff --git a/app/src/main/java/com/termux/app/ExtraKeysView.java b/app/src/main/java/com/termux/app/ExtraKeysView.java
index d0d6f91d..e2f76dc3 100644
--- a/app/src/main/java/com/termux/app/ExtraKeysView.java
+++ b/app/src/main/java/com/termux/app/ExtraKeysView.java
@@ -354,9 +354,13 @@ public final class ExtraKeysView extends GridLayout {
if (Settings.System.getInt(getContext().getContentResolver(),
Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) != 0) {
- // Depending on DnD settings, value can be >1 but 0 means "disabled".
- if (Settings.Global.getInt(getContext().getContentResolver(), "zen_mode", 0) < 1) {
+ if (Build.VERSION.SDK_INT >= 28) {
finalButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
+ } else {
+ // Perform haptic feedback only if no total silence mode enabled.
+ if (Settings.Global.getInt(getContext().getContentResolver(), "zen_mode", 0) != 2) {
+ finalButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
+ }
}
}
@@ -401,8 +405,14 @@ public final class ExtraKeysView extends GridLayout {
}
return true;
- case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
+ v.setBackgroundColor(BUTTON_COLOR);
+ if (scheduledExecutor != null) {
+ scheduledExecutor.shutdownNow();
+ scheduledExecutor = null;
+ }
+ return true;
+ case MotionEvent.ACTION_UP:
v.setBackgroundColor(BUTTON_COLOR);
if (scheduledExecutor != null) {
scheduledExecutor.shutdownNow();
@@ -427,11 +437,7 @@ public final class ExtraKeysView extends GridLayout {
LayoutParams param = new GridLayout.LayoutParams();
param.width = 0;
- if(Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) { // special handle api 21
- param.height = (int)(37.5 * getResources().getDisplayMetrics().density + 0.5); // 37.5 equal to R.id.viewpager layout_height / rows in DP
- } else {
- param.height = 0;
- }
+ param.height = 0;
param.setMargins(0, 0, 0, 0);
param.columnSpec = GridLayout.spec(col, GridLayout.FILL, 1.f);
param.rowSpec = GridLayout.spec(row, GridLayout.FILL, 1.f);
diff --git a/app/src/main/java/com/termux/app/TermuxActivity.java b/app/src/main/java/com/termux/app/TermuxActivity.java
index 28f968ce..0fe5b5df 100644
--- a/app/src/main/java/com/termux/app/TermuxActivity.java
+++ b/app/src/main/java/com/termux/app/TermuxActivity.java
@@ -127,6 +127,8 @@ public final class TermuxActivity extends Activity implements ServiceConnection
*/
boolean mIsVisible;
+ boolean mIsUsingBlackUI;
+
final SoundPool mBellSoundPool = new SoundPool.Builder().setMaxStreams(1).setAudioAttributes(
new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION).build()).build();
@@ -186,28 +188,35 @@ public final class TermuxActivity extends Activity implements ServiceConnection
}
/** For processes to access shared internal storage (/sdcard) we need this permission. */
- @TargetApi(Build.VERSION_CODES.M)
public boolean ensureStoragePermissionGranted() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
- return true;
- } else {
- requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUESTCODE_PERMISSION_STORAGE);
- return false;
- }
- } else {
- // Always granted before Android 6.0.
+ if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
return true;
+ } else {
+ requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUESTCODE_PERMISSION_STORAGE);
+ return false;
}
}
@Override
public void onCreate(Bundle bundle) {
+ mSettings = new TermuxPreferences(this);
+ mIsUsingBlackUI = mSettings.isUsingBlackUI();
+ if (mIsUsingBlackUI) {
+ this.setTheme(R.style.Theme_Termux_Black);
+ } else {
+ this.setTheme(R.style.Theme_Termux);
+ }
+
super.onCreate(bundle);
- mSettings = new TermuxPreferences(this);
-
setContentView(R.layout.drawer_layout);
+
+ if (mIsUsingBlackUI) {
+ findViewById(R.id.left_drawer).setBackgroundColor(
+ getResources().getColor(android.R.color.background_dark)
+ );
+ }
+
mTerminalView = findViewById(R.id.terminal_view);
mTerminalView.setOnKeyListener(new TermuxViewClient(this));
@@ -434,7 +443,11 @@ public final class TermuxActivity extends Activity implements ServiceConnection
boolean sessionRunning = sessionAtRow.isRunning();
TextView firstLineView = row.findViewById(R.id.row_line);
-
+ if (mIsUsingBlackUI) {
+ firstLineView.setBackground(
+ getResources().getDrawable(R.drawable.selected_session_background_black)
+ );
+ }
String name = sessionAtRow.mSessionName;
String sessionTitle = sessionAtRow.getTitle();
@@ -454,7 +467,8 @@ public final class TermuxActivity extends Activity implements ServiceConnection
} else {
firstLineView.setPaintFlags(firstLineView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
- int color = sessionRunning || sessionAtRow.getExitStatus() == 0 ? Color.BLACK : Color.RED;
+ int defaultColor = mIsUsingBlackUI ? Color.WHITE : Color.BLACK;
+ int color = sessionRunning || sessionAtRow.getExitStatus() == 0 ? defaultColor : Color.RED;
firstLineView.setTextColor(color);
return row;
}
diff --git a/app/src/main/java/com/termux/app/TermuxInstaller.java b/app/src/main/java/com/termux/app/TermuxInstaller.java
index 74823b63..6e50b22d 100644
--- a/app/src/main/java/com/termux/app/TermuxInstaller.java
+++ b/app/src/main/java/com/termux/app/TermuxInstaller.java
@@ -4,7 +4,6 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
-import android.os.Build;
import android.os.Environment;
import android.os.UserManager;
import android.system.Os;
@@ -16,14 +15,12 @@ import com.termux.R;
import com.termux.terminal.EmulatorDebug;
import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.net.MalformedURLException;
-import java.net.URL;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@@ -38,7 +35,7 @@ import java.util.zip.ZipInputStream;
*
* (3) A staging folder, $STAGING_PREFIX, is {@link #deleteFolder(File)} if left over from broken installation below.
*
- * (4) The architecture is determined and an appropriate bootstrap zip url is determined in {@link #determineZipUrl()}.
+ * (4) The zip file is loaded from a shared library.
*
* (5) The zip, containing entries relative to the $PREFIX, is is downloaded and extracted by a zip input stream
* continuously encountering zip file entries:
@@ -82,8 +79,8 @@ final class TermuxInstaller {
final byte[] buffer = new byte[8096];
final List> symlinks = new ArrayList<>(50);
- final URL zipUrl = determineZipUrl();
- try (ZipInputStream zipInput = new ZipInputStream(zipUrl.openStream())) {
+ final byte[] zipBytes = loadZipBytes();
+ try (ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(zipBytes))) {
ZipEntry zipEntry;
while ((zipEntry = zipInput.getNextEntry()) != null) {
if (zipEntry.getName().equals("SYMLINKS.txt")) {
@@ -167,34 +164,13 @@ final class TermuxInstaller {
}
}
- /** Get bootstrap zip url for this systems cpu architecture. */
- private static URL determineZipUrl() throws MalformedURLException {
- String archName = determineTermuxArchName();
- 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);
+ public static byte[] loadZipBytes() {
+ // Only load the shared library when necessary to save memory usage.
+ System.loadLibrary("termux-bootstrap");
+ return getZip();
}
- private static String determineTermuxArchName() {
- // Note that we cannot use System.getProperty("os.arch") since that may give e.g. "aarch64"
- // while a 64-bit runtime may not be installed (like on the Samsung Galaxy S5 Neo).
- // Instead we search through the supported abi:s on the device, see:
- // http://developer.android.com/ndk/guides/abis.html
- // Note that we search for abi:s in preferred order (the ordering of the
- // Build.SUPPORTED_ABIS list) to avoid e.g. installing arm on an x86 system where arm
- // emulation is available.
- for (String androidArch : Build.SUPPORTED_ABIS) {
- switch (androidArch) {
- case "arm64-v8a": return "aarch64";
- case "armeabi-v7a": return "arm";
- case "x86_64": return "x86_64";
- case "x86": return "i686";
- }
- }
- throw new RuntimeException("Unable to determine arch from Build.SUPPORTED_ABIS = " +
- Arrays.toString(Build.SUPPORTED_ABIS));
- }
+ public static native byte[] getZip();
/** Delete a folder and all its content or throw. Don't follow symlinks. */
static void deleteFolder(File fileOrDirectory) throws IOException {
diff --git a/app/src/main/java/com/termux/app/TermuxPreferences.java b/app/src/main/java/com/termux/app/TermuxPreferences.java
index 16a996ed..f6095837 100644
--- a/app/src/main/java/com/termux/app/TermuxPreferences.java
+++ b/app/src/main/java/com/termux/app/TermuxPreferences.java
@@ -58,6 +58,7 @@ final class TermuxPreferences {
private static final String CURRENT_SESSION_KEY = "current_session";
private static final String SCREEN_ALWAYS_ON_KEY = "screen_always_on";
+ private String mUseDarkUI;
private boolean mScreenAlwaysOn;
private int mFontSize;
@@ -126,6 +127,10 @@ final class TermuxPreferences {
return mScreenAlwaysOn;
}
+ boolean isUsingBlackUI() {
+ return mUseDarkUI.toLowerCase().equals("true");
+ }
+
void setScreenAlwaysOn(Context context, boolean newValue) {
mScreenAlwaysOn = newValue;
PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(SCREEN_ALWAYS_ON_KEY, newValue).apply();
@@ -173,6 +178,8 @@ final class TermuxPreferences {
break;
}
+ mUseDarkUI = props.getProperty("use-black-ui", "false");
+
try {
JSONArray arr = new JSONArray(props.getProperty("extra-keys", "[['ESC', 'TAB', 'CTRL', 'ALT', '-', 'DOWN', 'UP']]"));
diff --git a/app/src/main/java/com/termux/app/TermuxService.java b/app/src/main/java/com/termux/app/TermuxService.java
index 3bc2583b..b17643fe 100644
--- a/app/src/main/java/com/termux/app/TermuxService.java
+++ b/app/src/main/java/com/termux/app/TermuxService.java
@@ -114,19 +114,17 @@ public final class TermuxService extends Service implements SessionChangedCallba
mWifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, EmulatorDebug.LOG_TAG);
mWifiLock.acquire();
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- String packageName = getPackageName();
- if (!pm.isIgnoringBatteryOptimizations(packageName)) {
- Intent whitelist = new Intent();
- whitelist.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
- whitelist.setData(Uri.parse("package:" + packageName));
- whitelist.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ String packageName = getPackageName();
+ if (!pm.isIgnoringBatteryOptimizations(packageName)) {
+ Intent whitelist = new Intent();
+ whitelist.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
+ whitelist.setData(Uri.parse("package:" + packageName));
+ whitelist.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- startActivity(whitelist);
- } catch (ActivityNotFoundException e) {
- Log.e(EmulatorDebug.LOG_TAG, "Failed to call ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS", e);
- }
+ try {
+ startActivity(whitelist);
+ } catch (ActivityNotFoundException e) {
+ Log.e(EmulatorDebug.LOG_TAG, "Failed to call ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS", e);
}
}
diff --git a/app/src/main/res/drawable/current_session.xml b/app/src/main/res/drawable/current_session.xml
index e118aa01..90dd2818 100644
--- a/app/src/main/res/drawable/current_session.xml
+++ b/app/src/main/res/drawable/current_session.xml
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/drawable/current_session_black.xml b/app/src/main/res/drawable/current_session_black.xml
new file mode 100644
index 00000000..6a926499
--- /dev/null
+++ b/app/src/main/res/drawable/current_session_black.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/selected_session_background_black.xml b/app/src/main/res/drawable/selected_session_background_black.xml
new file mode 100644
index 00000000..25b7506f
--- /dev/null
+++ b/app/src/main/res/drawable/selected_session_background_black.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/session_ripple.xml b/app/src/main/res/drawable/session_ripple.xml
index f38d75b6..9c4a1e79 100644
--- a/app/src/main/res/drawable/session_ripple.xml
+++ b/app/src/main/res/drawable/session_ripple.xml
@@ -4,4 +4,4 @@
-
-
\ No newline at end of file
+
diff --git a/app/src/main/res/drawable/session_ripple_black.xml b/app/src/main/res/drawable/session_ripple_black.xml
new file mode 100644
index 00000000..21423eb5
--- /dev/null
+++ b/app/src/main/res/drawable/session_ripple_black.xml
@@ -0,0 +1,7 @@
+
+
+ -
+
+
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index f7c5cc3a..1f352423 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,8 +1,6 @@
-
-
-
+
+
+
diff --git a/app/src/main/res/xml/backupscheme.xml b/app/src/main/res/xml/backupscheme.xml
deleted file mode 100644
index 07566b9c..00000000
--- a/app/src/main/res/xml/backupscheme.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/build.gradle b/build.gradle
index e8b19a7d..107f3030 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,7 +4,7 @@ buildscript {
google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.5.1'
+ classpath 'com.android.tools.build:gradle:3.5.2'
}
}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 87b738cb..5c2d1cf0 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index f23127f7..0ebb3108 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Sun Aug 25 01:57:11 CEST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
diff --git a/gradlew b/gradlew
index af6708ff..83f2acfd 100755
--- a/gradlew
+++ b/gradlew
@@ -1,5 +1,21 @@
#!/usr/bin/env sh
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
##############################################################################
##
## Gradle start up script for UN*X
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
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.
-DEFAULT_JVM_OPTS='"-Xmx64m"'
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
@@ -109,8 +125,8 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
diff --git a/gradlew.bat b/gradlew.bat
index 0f8d5937..24467a14 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,3 +1,19 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0
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.
-set DEFAULT_JVM_OPTS="-Xmx64m"
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
diff --git a/terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java b/terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java
index f778cf92..3d9d7c8c 100644
--- a/terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java
+++ b/terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java
@@ -1376,10 +1376,10 @@ public final class TerminalEmulator {
}
break;
case 'A': // "CSI${n}A" - Cursor up (CUU) ${n} rows.
- setCursorRow(Math.max(mTopMargin, mCursorRow - getArg0(1)));
+ setCursorRow(Math.max(0, mCursorRow - getArg0(1)));
break;
case 'B': // "CSI${n}B" - Cursor down (CUD) ${n} rows.
- setCursorRow(Math.min(mBottomMargin - 1, mCursorRow + getArg0(1)));
+ setCursorRow(Math.min(mRows - 1, mCursorRow + getArg0(1)));
break;
case 'C': // "CSI${n}C" - Cursor forward (CUF).
case 'a': // "CSI${n}a" - Horizontal position relative (HPR). From ISO-6428/ECMA-48.
diff --git a/terminal-emulator/src/test/java/com/termux/terminal/CursorAndScreenTest.java b/terminal-emulator/src/test/java/com/termux/terminal/CursorAndScreenTest.java
index 12635425..121cb223 100644
--- a/terminal-emulator/src/test/java/com/termux/terminal/CursorAndScreenTest.java
+++ b/terminal-emulator/src/test/java/com/termux/terminal/CursorAndScreenTest.java
@@ -133,8 +133,6 @@ public class CursorAndScreenTest extends TerminalTestCase {
withTerminalSized(3, 3).enterString("ABCDEFG\033[2AH").assertLinesAre("AHC", "DEF", "G ");
// If an attempt is made to move the cursor above the top margin, the cursor stops at the top margin:
withTerminalSized(3, 3).enterString("ABCDEFG\033[44AH").assertLinesAre("AHC", "DEF", "G ");
- // Set top margin and validate that cursor does not go above it:
- withTerminalSized(3, 3).enterString("\033[2rABCDEFG\033[44AH").assertLinesAre("ABC", "DHF", "G ");
}
public void testCursorDown() {
@@ -143,8 +141,6 @@ public class CursorAndScreenTest extends TerminalTestCase {
withTerminalSized(3, 3).enterString("AB\033[2BC").assertLinesAre("AB ", " ", " C");
// If an attempt is made to move the cursor below the bottom margin, the cursor stops at the bottom margin:
withTerminalSized(3, 3).enterString("AB\033[44BC").assertLinesAre("AB ", " ", " C");
- // Set bottom margin and validate that cursor does not go above it:
- withTerminalSized(3, 3).enterString("\033[1;2rAB\033[44BC").assertLinesAre("AB ", " C", " ");
}
public void testReportCursorPosition() {
diff --git a/terminal-emulator/src/test/java/com/termux/terminal/ScrollRegionTest.java b/terminal-emulator/src/test/java/com/termux/terminal/ScrollRegionTest.java
index 260a481a..bbb5e7ac 100644
--- a/terminal-emulator/src/test/java/com/termux/terminal/ScrollRegionTest.java
+++ b/terminal-emulator/src/test/java/com/termux/terminal/ScrollRegionTest.java
@@ -107,4 +107,24 @@ public class ScrollRegionTest extends TerminalTestCase {
assertLinesAre("1 ", "2 ", "3 ", "QQ", "YY");
}
+ /** See https://github.com/termux/termux-app/issues/1340 */
+ public void testScrollRegionDoesNotLimitCursorMovement() {
+ withTerminalSized(6, 4)
+ .enterString("\033[4;7r\033[3;1Haaa\033[Axxx")
+ .assertLinesAre(
+ " ",
+ " xxx",
+ "aaa ",
+ " "
+ );
+
+ withTerminalSized(6, 4)
+ .enterString("\033[1;3r\033[3;1Haaa\033[Bxxx")
+ .assertLinesAre(
+ " ",
+ " ",
+ "aaa ",
+ " xxx"
+ );
+ }
}