Implement support for termux.properties

Also some symlink-to-storage improvements and experimenting with
requesting read storage permission.
This commit is contained in:
Fredrik Fornwall
2015-12-23 01:43:41 +01:00
parent f907684ef2
commit 2326c52199
5 changed files with 104 additions and 35 deletions

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.
*
@@ -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;
}
}
}
};

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;
@@ -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);
}

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,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);
}

Binary file not shown.