Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02af113dda | ||
|
|
fc4ef838bf | ||
|
|
86bd3ca21b | ||
|
|
367398bafb | ||
|
|
dd502e55f8 | ||
|
|
798125ef7a | ||
|
|
5126f06e06 | ||
|
|
0bdbf314ef | ||
|
|
2deb9899bd | ||
|
|
694ccc38c4 | ||
|
|
c949940374 | ||
|
|
d09f70de1e | ||
|
|
ac338ce2c5 | ||
|
|
092a83a688 | ||
|
|
3533b13de8 | ||
|
|
d68a0f05be | ||
|
|
9e5293a08e | ||
|
|
3f04a0a0d5 | ||
|
|
e558f824c5 | ||
|
|
8ff72ddd8b | ||
|
|
3e05356a69 | ||
|
|
82673d3f82 | ||
|
|
f2757fdb76 | ||
|
|
81fb669d0e | ||
|
|
4a45b1b617 | ||
|
|
62b08b3cf1 | ||
|
|
1e83ea3151 | ||
|
|
9c42fdb3d6 | ||
|
|
42e3163e92 | ||
|
|
68912139f6 | ||
|
|
edc92bbcbb | ||
|
|
d7520642de | ||
|
|
adae111d5c | ||
|
|
dc9272790b | ||
|
|
05ea2ea238 | ||
|
|
ad293562bc | ||
|
|
f9a565d1e0 | ||
|
|
5b3909cb73 | ||
|
|
7913e765d5 | ||
|
|
ed3a3269d8 | ||
|
|
dc3994d2cf | ||
|
|
c972377bd1 | ||
|
|
1be5139253 |
@@ -12,8 +12,8 @@ android:
|
|||||||
components:
|
components:
|
||||||
- platform-tools
|
- platform-tools
|
||||||
- tools
|
- tools
|
||||||
- build-tools-25.0.3
|
- build-tools-27.0.1
|
||||||
- android-25
|
- android-27
|
||||||
- extra-android-m2repository
|
- extra-android-m2repository
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ Termux app
|
|||||||
|
|
||||||
* [Termux on Google Play Store](https://play.google.com/store/apps/details?id=com.termux)
|
* [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 on F-Droid](https://f-droid.org/repository/browse/?fdid=com.termux)
|
||||||
* [Termux Help](http://termux.com/help/)
|
* [Termux Facebook](https://facebook.com/termux/)
|
||||||
* [Termux Google+ community](http://termux.com/community/)
|
* [Termux Google+ community](http://termux.com/community/)
|
||||||
|
* [Termux Help](http://termux.com/help/)
|
||||||
|
* [Termux Twitter](http://twitter.com/termux/)
|
||||||
|
* [Termux Wiki](https://wiki.termux.com/wiki/)
|
||||||
|
|
||||||
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)
|
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)
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 25
|
compileSdkVersion 27
|
||||||
buildToolsVersion "25.0.3"
|
buildToolsVersion "27.0.1"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'com.android.support:support-annotations:25.3.1'
|
implementation 'com.android.support:support-annotations:27.0.0'
|
||||||
compile "com.android.support:support-v4:25.3.1"
|
implementation "com.android.support:support-core-ui:27.0.0"
|
||||||
compile project(":terminal-view")
|
implementation project(":terminal-view")
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.termux"
|
applicationId "com.termux"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 27
|
||||||
versionCode 51
|
versionCode 56
|
||||||
versionName "0.51"
|
versionName "0.56"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@@ -28,5 +28,5 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testCompile 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
}
|
}
|
||||||
|
|||||||
10
app/proguard-rules.pro
vendored
10
app/proguard-rules.pro
vendored
@@ -7,11 +7,5 @@
|
|||||||
# For more details, see
|
# For more details, see
|
||||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
# Add any project specific keep options here:
|
-renamesourcefileattribute SourceFile
|
||||||
|
-keepattributes SourceFile,LineNumberTable
|
||||||
# If your project uses WebView with JS, uncomment the following
|
|
||||||
# and specify the fully qualified class name to the JavaScript interface
|
|
||||||
# class:
|
|
||||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
|
||||||
# public *;
|
|
||||||
#}
|
|
||||||
|
|||||||
@@ -76,6 +76,18 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".HomeActivity"
|
||||||
|
android:targetActivity="com.termux.app.TermuxActivity">
|
||||||
|
|
||||||
|
<!-- Launch activity automatically on boot on Android Things devices -->
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.IOT_LAUNCHER"/>
|
||||||
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name=".filepicker.TermuxDocumentsProvider"
|
android:name=".filepicker.TermuxDocumentsProvider"
|
||||||
android:authorities="com.termux.documents"
|
android:authorities="com.termux.documents"
|
||||||
@@ -99,6 +111,7 @@
|
|||||||
android:grantUriPermissions="true"
|
android:grantUriPermissions="true"
|
||||||
android:name="com.termux.app.TermuxOpenReceiver$ContentProvider" />
|
android:name="com.termux.app.TermuxOpenReceiver$ContentProvider" />
|
||||||
|
|
||||||
|
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -157,7 +157,6 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
|||||||
|
|
||||||
void checkForFontAndColors() {
|
void checkForFontAndColors() {
|
||||||
try {
|
try {
|
||||||
// Hard-coded paths since this file is used also in Termux:Float.
|
|
||||||
@SuppressLint("SdCardPath") File fontFile = new File("/data/data/com.termux/files/home/.termux/font.ttf");
|
@SuppressLint("SdCardPath") File fontFile = new File("/data/data/com.termux/files/home/.termux/font.ttf");
|
||||||
@SuppressLint("SdCardPath") File colorsFile = new File("/data/data/com.termux/files/home/.termux/colors.properties");
|
@SuppressLint("SdCardPath") File colorsFile = new File("/data/data/com.termux/files/home/.termux/colors.properties");
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public final class TermuxHelpActivity extends Activity {
|
|||||||
mWebView.setWebViewClient(new WebViewClient() {
|
mWebView.setWebViewClient(new WebViewClient() {
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||||
if (url.startsWith("https://termux.com")) {
|
if (url.startsWith("https://wiki.termux.com")) {
|
||||||
// Inline help.
|
// Inline help.
|
||||||
setContentView(progressLayout);
|
setContentView(progressLayout);
|
||||||
return false;
|
return false;
|
||||||
@@ -60,7 +60,7 @@ public final class TermuxHelpActivity extends Activity {
|
|||||||
setContentView(mWebView);
|
setContentView(mWebView);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mWebView.loadUrl("https://termux.com/help.html");
|
mWebView.loadUrl("https://wiki.termux.com/wiki/Main_Page");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ import java.util.zip.ZipInputStream;
|
|||||||
* (4) The architecture is determined and an appropriate bootstrap zip url is determined in {@link #determineZipUrl()}.
|
* (4) The architecture is determined and an appropriate bootstrap zip url is determined in {@link #determineZipUrl()}.
|
||||||
* <p/>
|
* <p/>
|
||||||
* (5) The zip, containing entries relative to the $PREFIX, is is downloaded and extracted by a zip input stream
|
* (5) The zip, containing entries relative to the $PREFIX, is is downloaded and extracted by a zip input stream
|
||||||
* continously encountering zip file entries:
|
* continuously encountering zip file entries:
|
||||||
* <p/>
|
* <p/>
|
||||||
* (5.1) If the zip entry encountered is SYMLINKS.txt, go through it and remember all symlinks to setup.
|
* (5.1) If the zip entry encountered is SYMLINKS.txt, go through it and remember all symlinks to setup.
|
||||||
* <p/>
|
* <p/>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import android.content.Intent;
|
|||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.MatrixCursor;
|
import android.database.MatrixCursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Environment;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
@@ -18,6 +19,7 @@ import com.termux.terminal.EmulatorDebug;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public class TermuxOpenReceiver extends BroadcastReceiver {
|
public class TermuxOpenReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
@@ -171,6 +173,16 @@ public class TermuxOpenReceiver extends BroadcastReceiver {
|
|||||||
@Override
|
@Override
|
||||||
public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException {
|
public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException {
|
||||||
File file = new File(uri.getPath());
|
File file = new File(uri.getPath());
|
||||||
|
try {
|
||||||
|
String path = file.getCanonicalPath();
|
||||||
|
String storagePath = Environment.getExternalStorageDirectory().getCanonicalPath();
|
||||||
|
// See https://support.google.com/faqs/answer/7496913:
|
||||||
|
if (!(path.startsWith(TermuxService.FILES_PATH) || path.startsWith(storagePath))) {
|
||||||
|
throw new IllegalArgumentException("Invalid path: " + path);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
}
|
||||||
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
|
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.termux.app;
|
|||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
@@ -11,10 +12,10 @@ import android.content.res.Resources;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.support.v4.content.WakefulBroadcastReceiver;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
|
|
||||||
@@ -41,6 +42,8 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public final class TermuxService extends Service implements SessionChangedCallback {
|
public final class TermuxService extends Service implements SessionChangedCallback {
|
||||||
|
|
||||||
|
private static final String NOTIFICATION_CHANNEL_ID = "termux_notification_channel";
|
||||||
|
|
||||||
/** Note that this is a symlink on the Android M preview. */
|
/** Note that this is a symlink on the Android M preview. */
|
||||||
@SuppressLint("SdCardPath")
|
@SuppressLint("SdCardPath")
|
||||||
public static final String FILES_PATH = "/data/data/com.termux/files";
|
public static final String FILES_PATH = "/data/data/com.termux/files";
|
||||||
@@ -153,11 +156,6 @@ public final class TermuxService extends Service implements SessionChangedCallba
|
|||||||
Log.e(EmulatorDebug.LOG_TAG, "Unknown TermuxService action: '" + action + "'");
|
Log.e(EmulatorDebug.LOG_TAG, "Unknown TermuxService action: '" + action + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & START_FLAG_REDELIVERY) == 0) {
|
|
||||||
// Service is started by WBR, not restarted by system, so release the WakeLock from WBR.
|
|
||||||
WakefulBroadcastReceiver.completeWakefulIntent(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this service really do get killed, there is no point restarting it automatically - let the user do on next
|
// If this service really do get killed, there is no point restarting it automatically - let the user do on next
|
||||||
// start of {@link Term):
|
// start of {@link Term):
|
||||||
return Service.START_NOT_STICKY;
|
return Service.START_NOT_STICKY;
|
||||||
@@ -170,6 +168,7 @@ public final class TermuxService extends Service implements SessionChangedCallba
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
|
setupNotificationChannel();
|
||||||
startForeground(NOTIFICATION_ID, buildNotification());
|
startForeground(NOTIFICATION_ID, buildNotification());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,8 +207,8 @@ public final class TermuxService extends Service implements SessionChangedCallba
|
|||||||
builder.setOngoing(true);
|
builder.setOngoing(true);
|
||||||
|
|
||||||
// If holding a wake or wifi lock consider the notification of high priority since it's using power,
|
// If holding a wake or wifi lock consider the notification of high priority since it's using power,
|
||||||
// otherwise use a minimal priority since this is just a background service notification:
|
// otherwise use a low priority
|
||||||
builder.setPriority((wakeLockHeld) ? Notification.PRIORITY_HIGH : Notification.PRIORITY_MIN);
|
builder.setPriority((wakeLockHeld) ? Notification.PRIORITY_HIGH : Notification.PRIORITY_LOW);
|
||||||
|
|
||||||
// No need to show a timestamp:
|
// No need to show a timestamp:
|
||||||
builder.setShowWhen(false);
|
builder.setShowWhen(false);
|
||||||
@@ -217,6 +216,10 @@ public final class TermuxService extends Service implements SessionChangedCallba
|
|||||||
// Background color for small notification icon:
|
// Background color for small notification icon:
|
||||||
builder.setColor(0xFF000000);
|
builder.setColor(0xFF000000);
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
builder.setChannelId(NOTIFICATION_CHANNEL_ID);
|
||||||
|
}
|
||||||
|
|
||||||
Resources res = getResources();
|
Resources res = getResources();
|
||||||
Intent exitIntent = new Intent(this, TermuxService.class).setAction(ACTION_STOP_SERVICE);
|
Intent exitIntent = new Intent(this, TermuxService.class).setAction(ACTION_STOP_SERVICE);
|
||||||
builder.addAction(android.R.drawable.ic_delete, res.getString(R.string.notification_action_exit), PendingIntent.getService(this, 0, exitIntent, 0));
|
builder.addAction(android.R.drawable.ic_delete, res.getString(R.string.notification_action_exit), PendingIntent.getService(this, 0, exitIntent, 0));
|
||||||
@@ -341,4 +344,17 @@ public final class TermuxService extends Service implements SessionChangedCallba
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupNotificationChannel() {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
|
||||||
|
|
||||||
|
String channelName = "Termux";
|
||||||
|
String channelDescription = "Notifications from Termux";
|
||||||
|
int importance = NotificationManager.IMPORTANCE_LOW;
|
||||||
|
|
||||||
|
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName,importance);
|
||||||
|
channel.setDescription(channelDescription);
|
||||||
|
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
manager.createNotificationChannel(channel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:2.3.2'
|
classpath 'com.android.tools.build:gradle:3.0.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
|
maven {
|
||||||
|
url "https://maven.google.com"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
5
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,5 @@
|
|||||||
#Mon Mar 06 01:34:12 CET 2017
|
distributionUrl=https\://services.gradle.org/distributions/gradle-4.3.1-bin.zip
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
6
gradlew
vendored
6
gradlew
vendored
@@ -33,11 +33,11 @@ DEFAULT_JVM_OPTS=""
|
|||||||
# 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"
|
||||||
|
|
||||||
warn ( ) {
|
warn () {
|
||||||
echo "$*"
|
echo "$*"
|
||||||
}
|
}
|
||||||
|
|
||||||
die ( ) {
|
die () {
|
||||||
echo
|
echo
|
||||||
echo "$*"
|
echo "$*"
|
||||||
echo
|
echo
|
||||||
@@ -155,7 +155,7 @@ if $cygwin ; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Escape application args
|
# Escape application args
|
||||||
save ( ) {
|
save () {
|
||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
echo " "
|
echo " "
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// Start https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle
|
// Start https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle
|
||||||
apply plugin: 'com.github.dcendents.android-maven'
|
|
||||||
group = publishedGroupId // Maven Group ID for the artifact
|
group = publishedGroupId // Maven Group ID for the artifact
|
||||||
install {
|
install {
|
||||||
repositories.mavenInstaller {
|
repositories.mavenInstaller {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "com.jfrog.bintray" version "1.7"
|
id "com.jfrog.bintray" version "1.7.3"
|
||||||
id "com.github.dcendents.android-maven" version "1.5"
|
id "com.github.dcendents.android-maven" version "2.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
@@ -13,16 +13,16 @@ ext {
|
|||||||
libraryDescription = 'The terminal emulator used in Termux'
|
libraryDescription = 'The terminal emulator used in Termux'
|
||||||
siteUrl = 'https://github.com/termux/termux'
|
siteUrl = 'https://github.com/termux/termux'
|
||||||
gitUrl = 'https://github.com/termux/termux.git'
|
gitUrl = 'https://github.com/termux/termux.git'
|
||||||
libraryVersion = '0.50'
|
libraryVersion = '0.52'
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 25
|
compileSdkVersion 27
|
||||||
buildToolsVersion "25.0.3"
|
buildToolsVersion "27.0.1"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 27
|
||||||
|
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
ndkBuild {
|
ndkBuild {
|
||||||
@@ -56,7 +56,7 @@ tasks.withType(Test) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testCompile 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: '../scripts/bintray-publish.gradle'
|
apply from: '../scripts/bintray-publish.gradle'
|
||||||
|
|||||||
@@ -223,6 +223,7 @@ public final class TerminalEmulator {
|
|||||||
|
|
||||||
private byte mUtf8ToFollow, mUtf8Index;
|
private byte mUtf8ToFollow, mUtf8Index;
|
||||||
private final byte[] mUtf8InputBuffer = new byte[4];
|
private final byte[] mUtf8InputBuffer = new byte[4];
|
||||||
|
private int mLastEmittedCodePoint = -1;
|
||||||
|
|
||||||
public final TerminalColors mColors = new TerminalColors();
|
public final TerminalColors mColors = new TerminalColors();
|
||||||
|
|
||||||
@@ -419,10 +420,11 @@ public final class TerminalEmulator {
|
|||||||
mUtf8Index = mUtf8ToFollow = 0;
|
mUtf8Index = mUtf8ToFollow = 0;
|
||||||
|
|
||||||
if (codePoint >= 0x80 && codePoint <= 0x9F) {
|
if (codePoint >= 0x80 && codePoint <= 0x9F) {
|
||||||
// Sequence decoded to a C1 control character which is the same as escape followed by
|
// Sequence decoded to a C1 control character which we ignore. They are
|
||||||
// ((code & 0x7F) + 0x40).
|
// not used nowadays and increases the risk of messing up the terminal state
|
||||||
processCodePoint(/* escape (hexadecimal=0x1B, octal=033): */27);
|
// on binary input. XTerm does not allow them in utf-8:
|
||||||
processCodePoint((codePoint & 0x7F) + 0x40);
|
// "It is not possible to use a C1 control obtained from decoding the
|
||||||
|
// UTF-8 text" - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||||
} else {
|
} else {
|
||||||
switch (Character.getType(codePoint)) {
|
switch (Character.getType(codePoint)) {
|
||||||
case Character.UNASSIGNED:
|
case Character.UNASSIGNED:
|
||||||
@@ -1190,12 +1192,20 @@ public final class TerminalEmulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void doLinefeed() {
|
private void doLinefeed() {
|
||||||
|
boolean belowScrollingRegion = mCursorRow >= mBottomMargin;
|
||||||
int newCursorRow = mCursorRow + 1;
|
int newCursorRow = mCursorRow + 1;
|
||||||
if (newCursorRow >= mBottomMargin) {
|
if (belowScrollingRegion) {
|
||||||
scrollDownOneLine();
|
// Move down (but not scroll) as long as we are above the last row.
|
||||||
newCursorRow = mBottomMargin - 1;
|
if (mCursorRow != mRows - 1) {
|
||||||
|
setCursorRow(newCursorRow);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (newCursorRow == mBottomMargin) {
|
||||||
|
scrollDownOneLine();
|
||||||
|
newCursorRow = mBottomMargin - 1;
|
||||||
|
}
|
||||||
|
setCursorRow(newCursorRow);
|
||||||
}
|
}
|
||||||
setCursorRow(newCursorRow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void continueSequence(int state) {
|
private void continueSequence(int state) {
|
||||||
@@ -1508,6 +1518,11 @@ public final class TerminalEmulator {
|
|||||||
case '`': // Horizontal position absolute (HPA - http://www.vt100.net/docs/vt510-rm/HPA).
|
case '`': // Horizontal position absolute (HPA - http://www.vt100.net/docs/vt510-rm/HPA).
|
||||||
setCursorColRespectingOriginMode(getArg0(1) - 1);
|
setCursorColRespectingOriginMode(getArg0(1) - 1);
|
||||||
break;
|
break;
|
||||||
|
case 'b': // Repeat the preceding graphic character Ps times (REP).
|
||||||
|
if (mLastEmittedCodePoint == -1) break;
|
||||||
|
final int numRepeat = getArg0(1);
|
||||||
|
for (int i = 0; i < numRepeat; i++) emitCodePoint(mLastEmittedCodePoint);
|
||||||
|
break;
|
||||||
case 'c': // Primary Device Attributes (http://www.vt100.net/docs/vt510-rm/DA1) if argument is missing or zero.
|
case 'c': // Primary Device Attributes (http://www.vt100.net/docs/vt510-rm/DA1) if argument is missing or zero.
|
||||||
// The important part that may still be used by some (tmux stores this value but does not currently use it)
|
// The important part that may still be used by some (tmux stores this value but does not currently use it)
|
||||||
// is the first response parameter identifying the terminal service class, where we send 64 for "vt420".
|
// is the first response parameter identifying the terminal service class, where we send 64 for "vt420".
|
||||||
@@ -1564,7 +1579,7 @@ public final class TerminalEmulator {
|
|||||||
break;
|
break;
|
||||||
case 'r': // "CSI${top};${bottom}r" - set top and bottom Margins (DECSTBM).
|
case 'r': // "CSI${top};${bottom}r" - set top and bottom Margins (DECSTBM).
|
||||||
{
|
{
|
||||||
// http://www.vt100.net/docs/vt510-rm/DECSTBM
|
// https://vt100.net/docs/vt510-rm/DECSTBM.html
|
||||||
// The top margin defaults to 1, the bottom margin defaults to mRows.
|
// The top margin defaults to 1, the bottom margin defaults to mRows.
|
||||||
// The escape sequence numbers top 1..23, but we number top 0..22.
|
// The escape sequence numbers top 1..23, but we number top 0..22.
|
||||||
// The escape sequence numbers bottom 2..24, and so do we (because we use a zero based numbering
|
// The escape sequence numbers bottom 2..24, and so do we (because we use a zero based numbering
|
||||||
@@ -1573,6 +1588,7 @@ public final class TerminalEmulator {
|
|||||||
// Also require that top + 2 <= bottom.
|
// Also require that top + 2 <= bottom.
|
||||||
mTopMargin = Math.max(0, Math.min(getArg0(1) - 1, mRows - 2));
|
mTopMargin = Math.max(0, Math.min(getArg0(1) - 1, mRows - 2));
|
||||||
mBottomMargin = Math.max(mTopMargin + 2, Math.min(getArg1(mRows), mRows));
|
mBottomMargin = Math.max(mTopMargin + 2, Math.min(getArg1(mRows), mRows));
|
||||||
|
|
||||||
// DECSTBM moves the cursor to column 1, line 1 of the page respecting origin mode.
|
// DECSTBM moves the cursor to column 1, line 1 of the page respecting origin mode.
|
||||||
setCursorPosition(0, 0);
|
setCursorPosition(0, 0);
|
||||||
}
|
}
|
||||||
@@ -2090,6 +2106,7 @@ public final class TerminalEmulator {
|
|||||||
* @param codePoint The code point of the character to display
|
* @param codePoint The code point of the character to display
|
||||||
*/
|
*/
|
||||||
private void emitCodePoint(int codePoint) {
|
private void emitCodePoint(int codePoint) {
|
||||||
|
mLastEmittedCodePoint = codePoint;
|
||||||
if (mUseLineDrawingUsesG0 ? mUseLineDrawingG0 : mUseLineDrawingG1) {
|
if (mUseLineDrawingUsesG0 ? mUseLineDrawingG0 : mUseLineDrawingG1) {
|
||||||
// http://www.vt100.net/docs/vt102-ug/table5-15.html.
|
// http://www.vt100.net/docs/vt102-ug/table5-15.html.
|
||||||
switch (codePoint) {
|
switch (codePoint) {
|
||||||
|
|||||||
@@ -35,4 +35,15 @@ public class ControlSequenceIntroducerTest extends TerminalTestCase {
|
|||||||
withTerminalSized(3, 2).enterString("\033[0;38;2;255;255;255;48;2;0;0;0;1;2;3;4;5;7;8;9mabc").assertLinesAre("abc", " ");
|
withTerminalSized(3, 2).enterString("\033[0;38;2;255;255;255;48;2;0;0;0;1;2;3;4;5;7;8;9mabc").assertLinesAre("abc", " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** CSI Ps b Repeat the preceding graphic character Ps times (REP). */
|
||||||
|
public void testRepeat() {
|
||||||
|
withTerminalSized(3, 2).enterString("a\033[b").assertLinesAre("aa ", " ");
|
||||||
|
withTerminalSized(3, 2).enterString("a\033[2b").assertLinesAre("aaa", " ");
|
||||||
|
// When no char has been output we ignore REP:
|
||||||
|
withTerminalSized(3, 2).enterString("\033[b").assertLinesAre(" ", " ");
|
||||||
|
// This shows that REP outputs the last emitted code point and not the one relative to the
|
||||||
|
// current cursor position:
|
||||||
|
withTerminalSized(5, 2).enterString("abcde\033[2G\033[2b\n").assertLinesAre("aeede", " ");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,4 +98,13 @@ public class ScrollRegionTest extends TerminalTestCase {
|
|||||||
withTerminalSized(2, 5).enterString("1\r\n2\r\n3\r\n4\r\n5").assertLinesAre("1 ", "2 ", "3 ", "4 ", "5 ");
|
withTerminalSized(2, 5).enterString("1\r\n2\r\n3\r\n4\r\n5").assertLinesAre("1 ", "2 ", "3 ", "4 ", "5 ");
|
||||||
enterString("\033[3r").enterString("\033[2T").assertLinesAre("1 ", "2 ", " ", " ", "3 ");
|
enterString("\033[3r").enterString("\033[2T").assertLinesAre("1 ", "2 ", " ", " ", "3 ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testScrollDownBelowScrollRegion() {
|
||||||
|
withTerminalSized(2, 5).enterString("1\r\n2\r\n3\r\n4\r\n5").assertLinesAre("1 ", "2 ", "3 ", "4 ", "5 ");
|
||||||
|
enterString("\033[1;3r"); // DECSTBM margins.
|
||||||
|
enterString("\033[4;1H"); // Place cursor just below bottom margin.
|
||||||
|
enterString("QQ\r\nRR\r\n\r\n\r\nYY");
|
||||||
|
assertLinesAre("1 ", "2 ", "3 ", "QQ", "YY");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public class TerminalRowTest extends TestCase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
row = new TerminalRow(COLUMNS, TextStyle.NORMAL);
|
row = new TerminalRow(COLUMNS, TextStyle.NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ public abstract class TerminalTestCase extends TestCase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
mOutput = new MockTerminalOutput();
|
mOutput = new MockTerminalOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "com.jfrog.bintray" version "1.7"
|
id "com.jfrog.bintray" version "1.7.3"
|
||||||
id "com.github.dcendents.android-maven" version "1.5"
|
id "com.github.dcendents.android-maven" version "2.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
@@ -13,21 +13,21 @@ ext {
|
|||||||
libraryDescription = 'The terminal view used in Termux'
|
libraryDescription = 'The terminal view used in Termux'
|
||||||
siteUrl = 'https://github.com/termux/termux'
|
siteUrl = 'https://github.com/termux/termux'
|
||||||
gitUrl = 'https://github.com/termux/termux.git'
|
gitUrl = 'https://github.com/termux/termux.git'
|
||||||
libraryVersion = '0.49'
|
libraryVersion = '0.50'
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 25
|
compileSdkVersion 27
|
||||||
buildToolsVersion "25.0.3"
|
buildToolsVersion "27.0.1"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'com.android.support:support-annotations:25.3.1'
|
implementation 'com.android.support:support-annotations:27.0.0'
|
||||||
compile project(":terminal-emulator")
|
api project(":terminal-emulator")
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 27
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testCompile 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: '../scripts/bintray-publish.gradle'
|
apply from: '../scripts/bintray-publish.gradle'
|
||||||
|
|||||||
@@ -834,6 +834,10 @@ public final class TerminalView extends View {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||||
|
if (!mIsSelectingText) {
|
||||||
|
// Fix issue where the dialog is pressed while being dismissed.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case 1:
|
case 1:
|
||||||
String selectedText = mEmulator.getSelectedText(mSelX1, mSelY1, mSelX2, mSelY2).trim();
|
String selectedText = mEmulator.getSelectedText(mSelX1, mSelY1, mSelX2, mSelY2).trim();
|
||||||
|
|||||||
Reference in New Issue
Block a user