Compare commits

...

17 Commits
v0.22 ... v0.23

Author SHA1 Message Date
Fredrik Fornwall
c3aa9d9662 Updated storage handling
Let the user run termux-setup-storage, which will ensure that storage
permission has been granted and setup $HOME/storage/ folder with
symlinks to storage folders.
2015-12-28 01:37:00 +01:00
Fredrik Fornwall
47634ca237 Update AS configuration 2015-12-28 01:17:40 +01:00
Fredrik Fornwall
d9ec1bf40b Add .idea/dictionaries/ to .gitignore 2015-12-28 00:41:21 +01:00
Fredrik Fornwall
bc1b742a36 Remove bundled help in favour of online help 2015-12-28 00:40:51 +01:00
Fredrik Fornwall
86e2945069 Make it possible to reload settings at runtime 2015-12-27 15:35:03 +01:00
Fredrik Fornwall
961e06379b Avoid prompting for storage permission for now 2015-12-27 13:46:20 +01:00
Fredrik Fornwall
468185efb3 Transition to https://termux.net for bootstrap
The initial bootstrap zip was previously downloaded from
http://apt.termux.com, which lacked security and was not behind a CDN.

By moving to https://termux.net we improve security (as it's https)
and reliability (as it's using a CDN).

Fixes https://github.com/termux/termux-packages/issues/89.
2015-12-27 08:17:29 +01:00
Fredrik Fornwall
e006e36dd0 Do not eat escape key events in onKeyPreIme()
The original reason for intercepting the escape key in onKeyPreIme()
was to prevent the escape key as being treated as the Back key before
reaching onKeyDown().

This seems no long necessary, and may mess up handling the ...+1
combination for escape on the Google Pixel C keyboard (see #27).
2015-12-25 21:10:48 +01:00
Fredrik Fornwall
dd38965c46 Use $PREFIX/storage for symlinks. Rix null check. 2015-12-24 09:29:14 +01:00
Fredrik Fornwall
79d56b778d Update gradle to 2.10 2015-12-23 01:44:51 +01:00
Fredrik Fornwall
2326c52199 Implement support for termux.properties
Also some symlink-to-storage improvements and experimenting with
requesting read storage permission.
2015-12-23 01:43:41 +01:00
Fredrik Fornwall
f907684ef2 Read support for customizing through properties
By using the file $HOME/.config/termux/termux.properties it will
be possible to configure the behaviour of:

- The bell character.
- Tapping the terminal.
- The back key.
2015-12-23 01:39:49 +01:00
Fredrik Fornwall
9d37461ac7 Fix lint warnings 2015-12-23 01:12:47 +01:00
Fredrik Fornwall
4de0f98fa4 Fix lint warning 2015-12-23 01:08:23 +01:00
Fredrik Fornwall
f153a72592 TerminalView: Make theming work for non-activities 2015-12-20 14:37:00 +01:00
Fredrik Fornwall
b0f4efb0bc Bump version to 0.23 2015-12-20 14:26:08 +01:00
Fredrik Fornwall
5c03c2d77e Change theme for file picker 2015-12-20 14:25:07 +01:00
19 changed files with 261 additions and 298 deletions

1
.gitignore vendored
View File

@@ -30,6 +30,7 @@ local.properties
.idea/modules.xml
.idea/scopes/scope_settings.xml
.idea/vcs.xml
.idea/dictionaries/
*.iml
# OS-specific files

1
.idea/gradle.xml generated
View File

@@ -3,6 +3,7 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="disableWrapperSourceDistributionNotification" value="true" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="1.8" />

View File

@@ -18,8 +18,8 @@ android {
applicationId "com.termux"
minSdkVersion 21
targetSdkVersion 23
versionCode 22
versionName "0.22"
versionCode 23
versionName "0.23"
}
buildTypes {

View File

@@ -39,12 +39,14 @@
<activity
android:name="com.termux.app.TermuxHelpActivity"
android:exported="false"
android:label="@string/application_help" />
android:theme="@android:style/Theme.Material.Light.DarkActionBar"
android:parentActivityName=".app.TermuxActivity"
android:label="@string/application_name" />
<activity
android:name="com.termux.filepicker.TermuxFilePickerActivity"
android:label="@string/application_name"
android:theme="@android:style/Theme.Material"
android:theme="@android:style/Theme.Material.Light.DarkActionBar"
android:noHistory="true">
<intent-filter>
<!--

View File

@@ -1,229 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Termux Help</title>
<style>
html { font-family: 'sans-serif-light', sans-serif; height: 100%; margin: auto; padding: 0; color: black; background-color: white; }
.page { max-width: 820px; margin: auto; padding: 0 1em; }
body { margin-left: auto; margin-right: auto; margin-top: 0; padding: 0; width: 100%; }
p { font-size: 16px; line-height: 1.3em; }
ul.index { padding-left: 0; }
.index li { list-style-type: none; line-height: 1.8em; }
dt { margin-left: 1em; list-style-type: bullet; }
a, a:visited { color: #0000EE }
</style>
</head>
<body>
<div class="page help">
<h1 id="index">Termux Help</h1>
<ul class="index">
<li><a href="#introduction">Introduction</a></li>
<li><a href="#user_interface">User interface</a></li>
<li><a href="#touch_keyboard">Using a touch keyboard</a></li>
<li><a href="#hardware_keyboard">Using a hardware keyboard</a></li>
<li><a href="#package_management">Package management</a></li>
<li><a href="#text_editing">Text editing</a></li>
<li><a href="#using_ssh">Using SSH</a></li>
<li><a href="#interactive_shells">Interactive shells</a></li>
<li><a href="#termux_android">Termux and Android</a></li>
<li><a href="#add_on_api">Add-on: API</a></li>
<li><a href="#add_on_float">Add-on: Float</a></li>
<li><a href="#add_on_styling">Add-on: Styling</a></li>
<li><a href="#add_on_widget">Add-on: Widget</a></li>
<li><a href="#source_and_licenses">Source and licenses</a>
</ul>
<h2 id="introduction">Introduction</h2>
<p>Termux is a terminal emulator for Android combined with a collection of packages for command line software. This help
explains both the terminal interface and the packaging tool available from inside the terminal.</p>
<p>Want to ask a question, report a bug or have an idea for a new package or feature?
Visit the <a href="https://plus.google.com/communities/101692629528551299417">Google+ Termux Community</a>!</p>
<h2 id="user_interface">User interface</h2>
<p>At launch Termux shows a terminal interface, whose text size can be adjusted by pinch zooming or double tapping
and pulling the content towards or from you.</p>
<p>Besides the terminal (with keyboard shortcuts explained below) there are three additional interface elements available:
A <strong>context menu</strong>, <strong>navigation drawer</strong>
and <strong>notification</strong>.</p>
<p>The <strong>context menu</strong> can be shown by long pressing anywhere on the terminal. It provides menu entries for:</p>
<ul>
<li>Selecting and pasting text.</li>
<li>Sharing text from the terminal to other apps (e.g. email or SMS)</li>
<li>Resetting the terminal if it gets stuck.</li>
<li>Switching the terminal to full-screen.</li>
<li>Hangup (exiting the current terminal session).</li>
<li>Styling the terminal by selecting a font and a color scheme.</li>
<li>Showing this help page.</li>
</ul>
<p>The <strong>navigation drawer</strong> is revealed by swiping from the left part of the screen. It has three
elements:</p>
<ul>
<li>A list of sessions. Clicking on a session shows it in the terminal while long pressing allows you to specify a session title.</li>
<li>A button to toggle visibility of the touch keyboard.</li>
<li>A button to create new terminal sessions (long press for creating a named session or a fail-safe one).</li>
</ul>
<p>The <strong>notification</strong>, available when a terminal session is running, is available by pulling down the notification menu.
Pressing the notification leads to the most current terminal session. The notification may also be expanded
(by pinch-zooming or performing a single-finger glide) to expose three actions:</p>
<ul>
<li>Exiting all running terminal sessions.</li>
<li>Use a wake lock to avoid entering sleep mode.</li>
<li>Use a high performance wifi lock to maximize wifi performance.</li>
</ul>
<p>With a wake or wifi lock held the notification and Termux background processes will be available even if no terminal
session is running, which allows server and other background processes to run more reliably.</p>
<h2 id="touch_keyboard">Using a touch keyboard</h2>
<p>Using the Ctrl key is necessary for working with a terminal - but most touch keyboards
does not include one. For that purpose Termux uses the <em>Volume down</em> button to emulate
the Ctrl key. For example, pressing <em>Volume down+L</em> on a touch keyboard sends the same input as
pressing <em>Ctrl+L</em> on a hardware keyboard. The result of using Ctrl in combination
with a key depends on which program is used, but for many command line tools the following
shortcuts works:</p>
<ul>
<li>Ctrl+A → Move cursor to the beginning of line.</li>
<li>Ctrl+C → Abort (send SIGINT to) current process.</li>
<li>Ctrl+D → Logout of a terminal session.</li>
<li>Ctrl+E → Move cursor to the end of line.</li>
<li>Ctrl+K → Delete from cursor to the end of line.</li>
<li>Ctrl+L → Clear the terminal.</li>
<li>Ctrl+Z → Suspend (send SIGTSTP to) current process.</li>
</ul>
<p>The <em>Volume up</em> key also serves as a special key to produce certain input:</p>
<ul>
<li>Volume Up+L → | (the pipe character).</li>
<li>Volume Up+E → Escape key.</li>
<li>Volume Up+T → Tab key.</li>
<li>Volume Up+1 → F1 (and Volume Up+2 → F2, etc).</li>
<li>Volume Up+B → Alt+B, back a word when using readline.</li>
<li>Volume Up+F → Alt+F, forward a word when using readline.</li>
<li>Volume Up+W → Up arrow key.</li>
<li>Volume Up+A → Left arrow key.</li>
<li>Volume Up+S → Down arrow key.</li>
<li>Volume Up+D → Right arrow key.</li>
</ul>
<h2 id="hardware_keyboard">Using a hardware keyboard</h2>
<p>The following shortcuts are available when using Termux with a hardware (e.g. bluetooth) keyboard by combining them with <em>Ctrl+Shift</em>:</p>
<ul>
<li>'C' → Create new session</li>
<li>'R' → Rename current session</li>
<li>Down arrow (or 'N') → Next session</li>
<li>Up arrow (or 'P') → Previous session</li>
<li>Right arrow → Open drawer</li>
<li>Left arrow → Close drawer</li>
<li>'F' → Toggle full screen</li>
<li>'M' → Show menu</li>
<li>'V' → Paste</li>
<li>+/- → Adjust text size</li>
<li>1-9 → Go to numbered session</li>
</ul>
<h2 id="package_management">Package management</h2>
<p>A minimal base system consisting of the Apt package manager and the busybox collection of system utilities
is installed when first starting Termux. Additional packages are available using the apt command:</p>
<dl>
<dt>apt update</dt><dd>Updates the list of available packages. This commands needs to be run initially directly after installation
and regularly afterwards to receive updates.</dd>
<dt>apt search &lt;query&gt;</dt><dd>Search among available packages.</dd>
<dt>apt install &lt;package&gt;</dt><dd>Install a new package.</dd>
<dt>apt upgrade</dt><dd>Upgrade outdated packages. For Apt to know about newer packages you will need to update the package index, so you will normally want to run <em>apt update</em> before upgrading.</dd>
<dt>apt show &lt;package&gt;</dt><dd>Show information about a package.</dd>
<dt>apt list</dt><dd>List all available packages.</dd>
<dt>apt list --installed</dt><dd>List all installed packages.</dd>
<dt>apt remove &lt;package&gt;</dt><dd>Remove an installed package.</dd>
</dl>
<p>Apt as a package manager uses a package format named <em>dpkg</em>. Normally direct use of dpkg is not necessary, but the
following two commands may be of use:</p>
<dl>
<dt>dpkg -L &lt;package&gt;</dt>
<dd>List installed files of a package.</dd>
<dt>dpkg --verify</dt>
<dd>Verify the integrity of installed packages.</dd>
</dl>
<p>View the apt manual page (execute <em>apt install man</em> to install a man page viewer first) for more information.</p>
<h2 id="text_editing">Text editing</h2>
<p>By default the busybox version of <em>vi</em> is available. This is a barebone and somewhat unfriendly editor -
install <a href="http://www.nano-editor.org/dist/v2.2/nano.html">nano</a> for a more straight-forward editor and
<a href="http://vimdoc.sourceforge.net/htmldoc/usr_toc.html">vim</a> for a more powerful one.</p>
<h2 id="using_ssh">Using SSH</h2>
<p>By installing the <strong>openssh</strong> package (by executing <em>apt install openssh</em>) you may SSH into remote systems,
optionally putting private keys or configuration under $HOME/.ssh/.</p>
<p>If you wish to use an SSH agent to avoid entering passwords, the Termux openssh package provides
a wrapper script named <strong>ssha</strong> (note the 'a' at the end) for ssh which:</p>
<ol>
<li>Starts the ssh agent if necessary (or connect to it if already running).</li>
<li>Runs <strong>ssh-add</strong> if necessary.</li>
<li>Runs <strong>ssh</strong> with the provided arguments.</li>
</ol>
<p>This means that the agent will prompt for a key password at first run, but remember the authorization for subsequent ones.</p>
<h2 id="interactive_shells">Interactive shells</h2>
<p>The base system that is installed when first starting Termux uses the <em>bash</em> shell while zsh is available as
an installable alternative:</p>
<ul>
<li>bash - the default shell on most Linux distributions, with resources such as
<a href="http://www.tldp.org/LDP/Bash-Beginners-Guide/html/">Bash Guide for Beginners</a>,
the <a href="https://www.gnu.org/software/bash/manual/bash.html">Bash Reference Manual</a>
or the <a href="http://www.tldp.org/LDP/abs/html/">Advanced Bash-Scripting Guide</a> available.</li>
<li>zsh - a powerful shell with information available at
<a href="http://zsh.sourceforge.net/Guide/zshguide.html">A User's Guide to the Z-Shell</a>, the
<a href="http://zsh.sourceforge.net/Doc/Release/zsh_toc.html">Z Shell Manual</a> or
<a href="http://www.rayninfo.co.uk/tips/zshtips.html">ZSH Tips by ZZapper</a>.
After installing zsh through <em>apt install zsh</em>, execute <em>chsh -s zsh</em> to set it as the default login shell when starting Termux
(and change back with <em>chsh -s bash</em> if necessary).</li>
</ul>
<h2 id="termux_android">Termux and Android</h2>
<p>Termux is designed to cope with the restrictions of running as an ordinary Android app without requiring root, which
leads to several differences between Termux and a traditional desktop system. The file system layout is drastically different:</p>
<ul>
<li>Common folders such as /bin, /usr/, /var and /etc does not exist.</li>
<li>The Android system provides a basic non-standard file system hierarchy, where e.g. /system/bin contains some system binaries.</li>
<li>The user folder $HOME is inside the private file area exposed to Termux as an ordinary Android app.
Uninstalling Termux will cause this file area to be wiped - so save important files outside this area such as in /sdcard
or use a version control system such as <em>git</em>.</li>
<li>Termux installs its packages in a folder exposed through the $PREFIX environment variable (with e.g. binaries in $PREFIX/bin,
and configuration in $PREFIX/etc).</li>
<li>Shared libraries are installed in $PREFIX/lib, which are available from binaries due to Termux setting the $LD_LIBRARY_PATH
environment variable. These may clash with Android system binaries in /system/bin, which may force LD_LIBRARY_PATH to be
cleared before running system binaries.</li>
</ul>
<p>Besides the file system being different, Termux is running as a single-user system without root - each Android app is running as
its own Linux user, so running commands inside Termux may not interfere with other installed applications.</p>
<p>Running as non-root implies that ports below 1024 cannot be bound to. Many packages have been configured to have compatible
default values - the ftpd, httpd, and sshd servers default to 8021, 8080 and 8022, respectively.</p>
<h2 id="add_on_api">Add-on: API</h2>
<p>The API add-on exposes Android system functionality such as SMS messages, GPS location or the Text-to-speech functionality through command line tools.</p>
<ul><li><a href="http://play.google.com/store/apps/details?id=com.termux.api">See more and install from Google Play</a></li></ul>
<h2 id="add_on_float">Add-on: Float</h2>
<p>The Float add-on consists of a floating terminal window visible while running other apps.</p>
<ul><li><a href="http://play.google.com/store/apps/details?id=com.termux.window">See more and install from Google Play</a></li></ul>
<h2 id="add_on_styling">Add-on: Styling</h2>
<p>The Styling add-on provides color schemes and fonts to beabeautify and customize the appearance of the Termux terminal.</p>
<ul><li><a href="http://play.google.com/store/apps/details?id=com.termux.styling">See more and install from Google Play</a></li></ul>
<h2 id="add_on_widget">Add-on: Widget</h2>
<p>The Widget add-on brings a widget to your homescreen, providing links to run scripts in your $HOME/.shortcuts/ folder.</p>
<ul><li><a href="http://play.google.com/store/apps/details?id=com.termux.widget">See more and install from Google Play</a></li></ul>
<h2 id="source_and_licenses">Source and licenses</h2>
<p>Termux uses terminal emulation code from <a href="https://github.com/jackpal/Android-Terminal-Emulator">Terminal Emulator for Android</a>
which is under the <a href="https://raw.githubusercontent.com/jackpal/Android-Terminal-Emulator/master/NOTICE">Apache License, Version 2.0</a>.
Packages available through Termux are distributed under their respective licenses with scripts and patches used to build them
<a href="https://github.com/termux/termux-packages">available on github</a>.</p>
</div>
</body>
</html>

View File

@@ -1,19 +1,8 @@
package com.termux.app;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.termux.R;
import com.termux.drawer.DrawerLayout;
import com.termux.terminal.TerminalSession;
import com.termux.terminal.TerminalSession.SessionChangedCallback;
import com.termux.view.TerminalKeyListener;
import com.termux.view.TerminalView;
import android.Manifest;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
@@ -27,11 +16,15 @@ import android.content.DialogInterface.OnShowListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.media.AudioAttributes;
import android.media.SoundPool;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Vibrator;
@@ -64,6 +57,19 @@ import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.termux.R;
import com.termux.drawer.DrawerLayout;
import com.termux.terminal.TerminalSession;
import com.termux.terminal.TerminalSession.SessionChangedCallback;
import com.termux.view.TerminalKeyListener;
import com.termux.view.TerminalView;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A terminal emulator activity.
*
@@ -86,10 +92,12 @@ public final class TermuxActivity extends Activity implements ServiceConnection
private static final int MAX_SESSIONS = 8;
private static final int REQUESTCODE_PERMISSION_STORAGE = 1234;
private static final String RELOAD_STYLE_ACTION = "com.termux.app.reload_style";
/** The main view of the activity showing the terminal. */
@NonNull TerminalView mTerminalView;
/** The main view of the activity showing the terminal. Initialized in onCreate(). */
@SuppressWarnings("NullableProblems") @NonNull TerminalView mTerminalView;
final FullScreenHelper mFullScreenHelper = new FullScreenHelper(this);
@@ -114,17 +122,43 @@ public final class TermuxActivity extends Activity implements ServiceConnection
*/
boolean mIsVisible;
private SoundPool mBellSoundPool = new SoundPool.Builder().setMaxStreams(1).setAudioAttributes(
new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION).build()).build();
private int mBellSoundId;
private final BroadcastReceiver mBroadcastReceiever = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (mIsVisible) {
String whatToReload = intent.getStringExtra(RELOAD_STYLE_ACTION);
if ("storage".equals(whatToReload)) {
if (ensureStoragePermissionGranted()) TermuxInstaller.setupStorageSymlinks(TermuxActivity.this);
return;
}
if (whatToReload == null || "colors".equals(whatToReload)) mTerminalView.checkForColors();
if (whatToReload == null || "font".equals(whatToReload)) mTerminalView.checkForTypeface();
if (whatToReload == null || "settings".equals(whatToReload)) mSettings.reloadFromProperties(TermuxActivity.this);
}
}
};
/** 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(android.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.
return true;
}
}
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
@@ -229,11 +263,22 @@ public final class TermuxActivity extends Activity implements ServiceConnection
@Override
public void onSingleTapUp(MotionEvent e) {
// Toggle keyboard visibility if tapping with a finger:
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);
switch (mSettings.mTapBehaviour) {
case TermuxPreferences.TAP_TOGGLE_KEYBOARD:
// Toggle keyboard visibility if tapping with a finger:
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);
break;
case TermuxPreferences.TAP_SHOW_MENU:
mTerminalView.showContextMenu();
break;
}
}
@Override
public boolean shouldBackButtonBeMappedToEscape() {
return mSettings.mBackIsEscape;
}
});
findViewById(R.id.new_session_button).setOnClickListener(new OnClickListener() {
@@ -294,7 +339,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
mTerminalView.checkForTypeface();
mTerminalView.checkForColors();
TermuxInstaller.setupStorageSymlink(this);
mBellSoundId = mBellSoundPool.load(this, R.raw.bell, 1);
}
/**
@@ -351,7 +396,17 @@ public final class TermuxActivity extends Activity implements ServiceConnection
@Override
public void onBell(TerminalSession session) {
if (mIsVisible) ((Vibrator) getSystemService(VIBRATOR_SERVICE)).vibrate(50);
if (mIsVisible) {
switch (mSettings.mBellBehaviour) {
case TermuxPreferences.BELL_BEEP:
mBellSoundPool.play(mBellSoundId, 1.f, 1.f, 1, 0, 1.f);
break;
case TermuxPreferences.BELL_VIBRATE:
((Vibrator) getSystemService(VIBRATOR_SERVICE)).vibrate(50);
break;
}
}
}
};
@@ -727,6 +782,13 @@ public final class TermuxActivity extends Activity implements ServiceConnection
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
if (requestCode == REQUESTCODE_PERMISSION_STORAGE && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
TermuxInstaller.setupStorageSymlinks(this);
}
}
void toggleImmersive() {
boolean newValue = !mSettings.isFullScreen();
mSettings.setFullScreen(this, newValue);

View File

@@ -5,33 +5,63 @@ import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
/** Basic embedded browser for viewing the bundled help page. */
/** Basic embedded browser for viewing help pages. */
public final class TermuxHelpActivity extends Activity {
private WebView mWebView;
private ProgressBar mProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final RelativeLayout progressLayout = new RelativeLayout(this);
RelativeLayout.LayoutParams lParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
lParams.addRule(RelativeLayout.CENTER_IN_PARENT);
mProgressBar = new ProgressBar(this);
mProgressBar.setIndeterminate(true);
mProgressBar.setLayoutParams(lParams);
progressLayout.addView(mProgressBar);
mWebView = new WebView(this);
setContentView(mWebView);
WebSettings settings = mWebView.getSettings();
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setAppCacheEnabled(false);
setContentView(progressLayout);
mWebView.clearCache(true);
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("https://termux.com")) {
// Inline help.
setContentView(progressLayout);
return false;
}
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
} catch (ActivityNotFoundException e) {
// TODO: Android TV does not have a system browser - but needs better method of getting back
// than navigating deep here.
// Android TV does not have a system browser.
setContentView(progressLayout);
return false;
}
return true;
}
@Override
public void onPageFinished(WebView view, String url) {
setContentView(mWebView);
}
});
mWebView.loadUrl("file:///android_asset/help.html");
mWebView.loadUrl("https://termux.com/help.html");
}
@Override

View File

@@ -7,6 +7,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnDismissListener;
import android.os.Environment;
import android.system.Os;
import android.util.Log;
import android.util.Pair;
@@ -184,7 +185,7 @@ final class TermuxInstaller {
} else if (arch.equals("x86_64")) {
arch = "i686";
}
return new URL("http://apt.termux.com/bootstrap/bootstrap-" + arch + ".zip");
return new URL("https://termux.net/bootstrap/bootstrap-" + arch + ".zip");
}
/** Delete a folder and all its content or throw. */
@@ -200,33 +201,48 @@ final class TermuxInstaller {
}
}
public static void setupStorageSymlink(final Context context) {
final File[] dirs = context.getExternalFilesDirs(null);
if (dirs == null || dirs.length < 2) return;
public static void setupStorageSymlinks(final Context context) {
final String LOG_TAG = "termux-storage";
new Thread() {
public void run() {
try {
final File externalDir = dirs[1];
File homeDir = new File(TermuxService.HOME_PATH);
homeDir.mkdirs();
File externalLink = new File(homeDir, "storage");
File storageDir = new File(TermuxService.HOME_PATH, "storage");
if (externalLink.exists()) {
if (externalLink.getCanonicalPath().equals(externalDir.getPath())) {
// Keeping existing link.
return;
} else {
// Removing old link to give place to new.
if (!externalLink.delete()) {
Log.e("termux", "Unable to remove old $HOME/storage to give place for new");
return;
}
}
if (storageDir.exists() && !storageDir.delete()) {
Log.e(LOG_TAG, "Could not delete old $HOME/storage");
return;
}
Os.symlink(externalDir.getAbsolutePath(), externalLink.getAbsolutePath());
if (!storageDir.mkdirs()) {
Log.e(LOG_TAG, "Unable to mkdirs() for $HOME/storage");
return;
}
File sharedDir = Environment.getExternalStorageDirectory();
Os.symlink(sharedDir.getAbsolutePath(), new File(storageDir, "shared").getAbsolutePath());
File downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
Os.symlink(downloadsDir.getAbsolutePath(), new File(storageDir, "downloads").getAbsolutePath());
File dcimDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
Os.symlink(dcimDir.getAbsolutePath(), new File(storageDir, "dcim").getAbsolutePath());
File picturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
Os.symlink(picturesDir.getAbsolutePath(), new File(storageDir, "pictures").getAbsolutePath());
File musicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
Os.symlink(musicDir.getAbsolutePath(), new File(storageDir, "music").getAbsolutePath());
File moviesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
Os.symlink(moviesDir.getAbsolutePath(), new File(storageDir, "movies").getAbsolutePath());
final File[] dirs = context.getExternalFilesDirs(null);
if (dirs != null && dirs.length >= 2) {
final File externalDir = dirs[1];
Os.symlink(externalDir.getAbsolutePath(), new File(storageDir, "external").getAbsolutePath());
}
} catch (Exception e) {
Log.e("termux", "Error setting up link", e);
Log.e(LOG_TAG, "Error setting up link", e);
}
}
}.start();

View File

@@ -5,12 +5,38 @@ import com.termux.terminal.TerminalSession;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.annotation.IntDef;
import android.util.Log;
import android.util.TypedValue;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Properties;
final class TermuxPreferences {
@IntDef({BELL_VIBRATE, BELL_BEEP, BELL_IGNORE})
@Retention(RetentionPolicy.SOURCE)
public @interface AsciiBellBehaviour {}
static final int BELL_VIBRATE = 1;
static final int BELL_BEEP = 2;
static final int BELL_IGNORE = 3;
@IntDef({TAP_TOGGLE_KEYBOARD, TAP_SHOW_MENU, TAP_IGNORE})
@Retention(RetentionPolicy.SOURCE)
public @interface TapTerminalBehaviour {}
static final int TAP_TOGGLE_KEYBOARD = 1;
static final int TAP_SHOW_MENU = 2;
static final int TAP_IGNORE = 3;
private final int MIN_FONTSIZE;
private static final int MAX_FONTSIZE = 256;
private static final String FULLSCREEN_KEY = "fullscreen";
private static final String FONTSIZE_KEY = "fontsize";
private static final String CURRENT_SESSION_KEY = "current_session";
@@ -19,7 +45,16 @@ final class TermuxPreferences {
private boolean mFullScreen;
private int mFontSize;
@AsciiBellBehaviour
int mBellBehaviour = BELL_VIBRATE;
@TapTerminalBehaviour
int mTapBehaviour = TAP_TOGGLE_KEYBOARD;
boolean mBackIsEscape = true;
TermuxPreferences(Context context) {
reloadFromProperties(context);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
float dipInPixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, context.getResources().getDisplayMetrics());
@@ -86,4 +121,49 @@ final class TermuxPreferences {
PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(SHOW_WELCOME_DIALOG_KEY, false).apply();
}
public void reloadFromProperties(Context context) {
try {
File propsFile = new File(TermuxService.HOME_PATH + "/.config/termux/termux.properties");
if (propsFile.isFile() && propsFile.canRead()) {
Properties props = new Properties();
try (FileInputStream in = new FileInputStream(propsFile)) {
props.load(in);
}
switch (props.getProperty("bell-character", "vibrate")) {
case "beep":
mBellBehaviour = BELL_BEEP;
break;
case "ignore":
mBellBehaviour = BELL_IGNORE;
break;
default: // "vibrate".
mBellBehaviour = BELL_VIBRATE;
break;
}
switch (props.getProperty("tap-screen", "toggle-keyboard")) {
case "show-menu":
mTapBehaviour = TAP_SHOW_MENU;
break;
case "ignore":
mTapBehaviour = TAP_IGNORE;
break;
default: // "toggle-keyboard".
mTapBehaviour = TAP_TOGGLE_KEYBOARD;
break;
}
mBackIsEscape = !"back".equals(props.getProperty("back-key", "escape"));
} else {
mBellBehaviour = BELL_VIBRATE;
mTapBehaviour = TAP_TOGGLE_KEYBOARD;
mBackIsEscape = true;
}
} catch (Exception e) {
Toast.makeText(context, "Error loading properties: " + e.getMessage(), Toast.LENGTH_LONG).show();
Log.e("termux", "Error loading props", e);
}
}
}

View File

@@ -138,11 +138,11 @@ public class DrawerLayout extends ViewGroup {
private final ChildAccessibilityDelegate mChildAccessibilityDelegate = new ChildAccessibilityDelegate();
private int mMinDrawerMargin;
private final int mMinDrawerMargin;
private int mScrimColor = DEFAULT_SCRIM_COLOR;
private float mScrimOpacity;
private Paint mScrimPaint = new Paint();
private final Paint mScrimPaint = new Paint();
private final ViewDragHelper mLeftDragger;
private final ViewDragHelper mRightDragger;

View File

@@ -57,7 +57,7 @@ public class ViewDragHelper {
/**
* Edge flag indicating that the left edge should be affected.
*/
public static final int EDGE_LEFT = 1 << 0;
public static final int EDGE_LEFT = 1 /*1 << 0*/;
/**
* Edge flag indicating that the right edge should be affected.
@@ -82,7 +82,7 @@ public class ViewDragHelper {
/**
* Indicates that a check should occur along the horizontal axis
*/
public static final int DIRECTION_HORIZONTAL = 1 << 0;
public static final int DIRECTION_HORIZONTAL = 1 /*1 << 0*/;
/**
* Indicates that a check should occur along the vertical axis

View File

@@ -33,8 +33,7 @@ public final class TerminalEmulator {
private static final boolean LOG_ESCAPE_SEQUENCES = false;
public static final int MOUSE_LEFT_BUTTON = 0;
public static final int MOUSE_MIDDLE_BUTTON = 1;
public static final int MOUSE_RIGHT_BUTTON = 2;
/** Mouse moving while having left mouse button pressed. */
public static final int MOUSE_LEFT_BUTTON_MOVED = 32;
public static final int MOUSE_WHEELUP_BUTTON = 64;

View File

@@ -6,6 +6,8 @@ import android.view.ScaleGestureDetector;
/**
* Input and scale listener which may be set on a {@link TerminalView} through
* {@link TerminalView#setOnKeyListener(TerminalKeyListener)}.
*
* TODO: Rename to TerminalViewClient.
*/
public interface TerminalKeyListener {
@@ -17,4 +19,6 @@ public interface TerminalKeyListener {
/** On a single tap on the terminal if terminal mouse reporting not enabled. */
void onSingleTapUp(MotionEvent e);
boolean shouldBackButtonBeMappedToEscape();
}

View File

@@ -12,7 +12,6 @@ import com.termux.terminal.TerminalEmulator;
import com.termux.terminal.TerminalSession;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Typeface;
@@ -492,9 +491,8 @@ public final class TerminalView extends View {
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (LOG_KEY_EVENTS) Log.i(EmulatorDebug.LOG_TAG, "onKeyPreIme(keyCode=" + keyCode + ", event=" + event + ")");
if (keyCode == KeyEvent.KEYCODE_ESCAPE || keyCode == KeyEvent.KEYCODE_BACK) {
// Handle the escape key ourselves to avoid the system from treating it as back key
// and e.g. close keyboard.
if (keyCode == KeyEvent.KEYCODE_BACK && mOnKeyListener.shouldBackButtonBeMappedToEscape()) {
// Intercept back button to treat it as escape:
switch (event.getAction()) {
case KeyEvent.ACTION_DOWN:
return onKeyDown(keyCode, event);
@@ -518,7 +516,7 @@ public final class TerminalView extends View {
if (handleVirtualKeys(keyCode, event, true)) {
invalidate();
return true;
} else if (event.isSystem() && keyCode != KeyEvent.KEYCODE_BACK) {
} else if (event.isSystem() && (!mOnKeyListener.shouldBackButtonBeMappedToEscape() || keyCode != KeyEvent.KEYCODE_BACK)) {
return super.onKeyDown(keyCode, event);
}
@@ -717,10 +715,10 @@ public final class TerminalView extends View {
@Override
public void run() {
try {
File fontFile = new File(getContext().getFilesDir().getPath() + "/home/.termux/font.ttf");
File fontFile = new File("/data/data/com.termux/files/home/.termux/font.ttf");
final Typeface newTypeface = fontFile.exists() ? Typeface.createFromFile(fontFile) : Typeface.MONOSPACE;
if (newTypeface != mRenderer.mTypeface) {
((Activity) getContext()).runOnUiThread(new Runnable() {
post(new Runnable() {
@Override
public void run() {
try {
@@ -745,14 +743,14 @@ public final class TerminalView extends View {
@Override
public void run() {
try {
File colorsFile = new File(getContext().getFilesDir().getPath() + "/home/.termux/colors.properties");
File colorsFile = new File("/data/data/com.termux/files/home/.termux/colors.properties");
final Properties props = colorsFile.isFile() ? new Properties() : null;
if (props != null) {
try (InputStream in = new FileInputStream(colorsFile)) {
props.load(in);
}
}
((Activity) getContext()).runOnUiThread(new Runnable() {
post(new Runnable() {
@Override
public void run() {
try {

Binary file not shown.

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="application_name">Termux</string>
<string name="application_help">Termux help</string>
<string name="shared_user_label">Termux user</string>
<string name="new_session">New session</string>
<string name="new_session_normal_unnamed">Normal - unnamed</string>

View File

@@ -15,7 +15,7 @@ public class OperatingSystemControlTest extends TerminalTestCase {
withTerminalSized(10, 10);
enterString("\033]0;Hello, world\007");
assertEquals("Hello, world", mTerminal.getTitle());
expectedTitleChanges.add(new ChangedTitle((String) null, "Hello, world"));
expectedTitleChanges.add(new ChangedTitle(null, "Hello, world"));
assertEquals(expectedTitleChanges, mOutput.titleChanges);
enterString("\033]0;Goodbye, world\007");

Binary file not shown.

View File

@@ -1,6 +1,6 @@
#Sat Nov 28 23:59:10 CET 2015
#Wed Dec 23 01:44:47 CET 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip