mirror of
https://github.com/fankes/termux-app.git
synced 2025-09-06 02:35:19 +08:00
Implement support for termux.properties
Also some symlink-to-storage improvements and experimenting with requesting read storage permission.
This commit is contained in:
@@ -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.
|
||||
*
|
||||
@@ -114,6 +120,11 @@ 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) {
|
||||
@@ -125,6 +136,16 @@ 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 void ensureStoragePermissionGranted() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1234);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
@@ -229,11 +250,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 +326,11 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
||||
mTerminalView.checkForTypeface();
|
||||
mTerminalView.checkForColors();
|
||||
|
||||
TermuxInstaller.setupStorageSymlink(this);
|
||||
ensureStoragePermissionGranted();
|
||||
|
||||
TermuxInstaller.setupStorageSymlinks(this);
|
||||
|
||||
mBellSoundId = mBellSoundPool.load(this, R.raw.bell, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -351,7 +387,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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -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;
|
||||
@@ -200,31 +201,50 @@ 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) {
|
||||
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(homeDir, "storage");
|
||||
|
||||
if (externalLink.exists()) {
|
||||
if (externalLink.getCanonicalPath().equals(externalDir.getPath())) {
|
||||
// Keeping existing link.
|
||||
if (storageDir.exists()) {
|
||||
if (storageDir.isDirectory()) {
|
||||
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;
|
||||
}
|
||||
storageDir.delete();
|
||||
}
|
||||
}
|
||||
|
||||
Os.symlink(externalDir.getAbsolutePath(), externalLink.getAbsolutePath());
|
||||
storageDir.mkdirs();
|
||||
|
||||
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 documentsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
|
||||
Os.symlink(documentsDir.getAbsolutePath(), new File(storageDir, "documents").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);
|
||||
}
|
||||
|
@@ -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();
|
||||
|
||||
}
|
||||
|
@@ -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,7 +491,7 @@ 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) {
|
||||
if (keyCode == KeyEvent.KEYCODE_ESCAPE || (keyCode == KeyEvent.KEYCODE_BACK && mOnKeyListener.shouldBackButtonBeMappedToEscape())) {
|
||||
// Handle the escape key ourselves to avoid the system from treating it as back key
|
||||
// and e.g. close keyboard.
|
||||
switch (event.getAction()) {
|
||||
@@ -518,7 +517,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);
|
||||
}
|
||||
|
||||
|
BIN
app/src/main/res/raw/bell.ogg
Normal file
BIN
app/src/main/res/raw/bell.ogg
Normal file
Binary file not shown.
Reference in New Issue
Block a user