Remove float/

The Termux:Float app has a new home at:

https://github.com/termux/termux-float
This commit is contained in:
Fredrik Fornwall 2017-04-04 23:39:05 +02:00
parent 4aefa5049b
commit 0ac55cd77a
30 changed files with 1 additions and 977 deletions

View File

@ -1,37 +0,0 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
dependencies {
compile 'com.android.support:support-annotations:25.3.1'
compile project(":terminal-view")
}
defaultConfig {
applicationId "com.termux.window"
minSdkVersion 21
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
testCompile 'junit:junit:4.12'
}

View File

@ -1,25 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/fornwall/lib/android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# 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 *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.termux.window"
android:sharedUserId="com.termux">
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application
android:allowBackup="true"
android:extractNativeLibs="false"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:theme="@android:style/Theme.NoDisplay"
android:noHistory="true"
android:name=".TermuxFloatActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:theme="@android:style/Theme.Material"
android:name=".TermuxFloatPermissionActivity" />
<service android:name=".TermuxFloatService" android:exported="false"/>
</application>
</manifest>

View File

@ -1,18 +0,0 @@
package com.termux.window;
import android.app.Activity;
import android.content.Intent;
/**
* Simple activity which immediately launches {@link TermuxFloatService} and exits.
*/
public class TermuxFloatActivity extends Activity {
@Override
protected void onResume() {
super.onResume();
startService(new Intent(this, TermuxFloatService.class));
finish();
}
}

View File

@ -1,35 +0,0 @@
package com.termux.window;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;
@TargetApi(23)
public class TermuxFloatPermissionActivity extends Activity {
public static int OVERLAY_PERMISSION_REQ_CODE = 1234;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_permission);
}
public void onOkButton(View view) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
startService(new Intent(this, TermuxFloatService.class));
finish();
}
}
}

View File

@ -1,33 +0,0 @@
package com.termux.window;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.view.WindowManager;
public class TermuxFloatPrefs {
private static final String PREF_X = "window_x";
private static final String PREF_Y = "window_y";
private static final String PREF_WIDTH = "window_width";
private static final String PREF_HEIGHT = "window_height";
public static void saveWindowSize(Context context, int width, int height) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putInt(PREF_WIDTH, width).putInt(PREF_HEIGHT, height).apply();
}
public static void saveWindowPosition(Context context, int x, int y) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putInt(PREF_X, x).putInt(PREF_Y, y).apply();
}
public static void applySavedGeometry(Context context, WindowManager.LayoutParams layout) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
layout.x = prefs.getInt(PREF_X, 200);
layout.y = prefs.getInt(PREF_Y, 200);
layout.width = prefs.getInt(PREF_WIDTH, 500);
layout.height = prefs.getInt(PREF_HEIGHT, 800);
}
}

View File

@ -1,248 +0,0 @@
package com.termux.window;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.IBinder;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.termux.terminal.EmulatorDebug;
import com.termux.terminal.TerminalSession;
import java.io.File;
import java.io.IOException;
public class TermuxFloatService extends Service {
public static final String ACTION_HIDE = "com.termux.float.hide";
public static final String ACTION_SHOW = "com.termux.float.show";
/**
* Note that this is a symlink on the Android M preview.
*/
@SuppressLint("SdCardPath")
public static final String FILES_PATH = "/data/data/com.termux/files";
public static final String PREFIX_PATH = FILES_PATH + "/usr";
public static final String HOME_PATH = FILES_PATH + "/home";
/**
* The notification id supplied to {@link #startForeground(int, Notification)}.
* <p/>
* Note that the javadoc for that method says it cannot be zero.
*/
private static final int NOTIFICATION_ID = 0xdead1337;
private static final int MIN_FONTSIZE = 16;
private static final int DEFAULT_FONTSIZE = 24;
private static final String FONTSIZE_KEY = "fontsize";
private TermuxFloatView mFloatingWindow;
private int mFontSize;
private boolean mVisibleWindow = true;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@SuppressLint({"InflateParams"})
@Override
public void onCreate() {
super.onCreate();
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
try {
mFontSize = Integer.parseInt(prefs.getString(FONTSIZE_KEY, Integer.toString(DEFAULT_FONTSIZE)));
} catch (NumberFormatException | ClassCastException e) {
mFontSize = DEFAULT_FONTSIZE;
}
TermuxFloatView floatingWindow = (TermuxFloatView) ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.activity_main, null);
floatingWindow.initializeFloatingWindow();
floatingWindow.mTerminalView.setTextSize(mFontSize);
TerminalSession session = createTermSession();
floatingWindow.mTerminalView.attachSession(session);
try {
floatingWindow.launchFloatingWindow();
} catch (Exception e) {
// Settings.canDrawOverlays() does not work (always returns false, perhaps due to sharedUserId?).
// So instead we catch the exception and prompt here.
startActivity(new Intent(this, TermuxFloatPermissionActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
stopSelf();
return;
}
mFloatingWindow = floatingWindow;
Toast toast = Toast.makeText(this, R.string.initial_instruction_toast, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
TextView v = (TextView) toast.getView().findViewById(android.R.id.message);
if (v != null) v.setGravity(Gravity.CENTER);
toast.show();
startForeground(NOTIFICATION_ID, buildNotification());
}
private Notification buildNotification() {
final Resources res = getResources();
final String contentTitle = res.getString(R.string.notification_title);
final String contentText = res.getString(mVisibleWindow ? R.string.notification_message_visible : R.string.notification_message_hidden);
final String intentAction = mVisibleWindow ? ACTION_HIDE : ACTION_SHOW;
Intent actionIntent = new Intent(this, TermuxFloatService.class).setAction(intentAction);
Notification.Builder builder = new Notification.Builder(this).setContentTitle(contentTitle).setContentText(contentText)
.setPriority(Notification.PRIORITY_MIN).setSmallIcon(R.mipmap.ic_service_notification)
.setColor(0xFF000000)
.setContentIntent(PendingIntent.getService(this, 0, actionIntent, 0))
.setOngoing(true).setShowWhen(false);
//final int messageId = mVisibleWindow ? R.string.toggle_hide : R.string.toggle_show;
//builder.addAction(android.R.drawable.ic_menu_preferences, res.getString(messageId), PendingIntent.getService(this, 0, actionIntent, 0));
return builder.build();
}
@SuppressLint("Wakelock")
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getAction();
if (ACTION_HIDE.equals(action)) {
setVisible(false);
} else if (ACTION_SHOW.equals(action)) {
setVisible(true);
} else if (!mVisibleWindow) {
// Show window if hidden when launched through launcher icon.
setVisible(true);
}
return Service.START_NOT_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mFloatingWindow != null) mFloatingWindow.closeFloatingWindow();
}
private void setVisible(boolean newVisibility) {
mVisibleWindow = newVisibility;
mFloatingWindow.setVisibility(newVisibility ? View.VISIBLE : View.GONE);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, buildNotification());
}
public void changeFontSize(boolean increase) {
mFontSize += (increase ? 1 : -1) * 2;
mFontSize = Math.max(MIN_FONTSIZE, mFontSize);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.edit().putString(FONTSIZE_KEY, Integer.toString(mFontSize)).apply();
mFloatingWindow.mTerminalView.setTextSize(mFontSize);
}
// XXX: Keep in sync with TermuxService.java.
@SuppressLint("SdCardPath")
TerminalSession createTermSession() {
new File(HOME_PATH).mkdirs();
String termEnv = "TERM=xterm-256color";
String homeEnv = "HOME=" + HOME_PATH;
String prefixEnv = "PREFIX=" + PREFIX_PATH;
String[] env;
String ps1Env = "PS1=$ ";
String ldEnv = "LD_LIBRARY_PATH=" + PREFIX_PATH + "/lib";
String langEnv = "LANG=en_US.UTF-8";
String pathEnv = "PATH=" + PREFIX_PATH + "/bin:" + PREFIX_PATH + "/bin/applets:" + System.getenv("PATH");
env = new String[]{termEnv, homeEnv, prefixEnv, ps1Env, ldEnv, langEnv, pathEnv};
String executablePath = null;
String[] args;
String shellName = null;
File shell = new File(HOME_PATH, ".termux/shell");
if (shell.exists()) {
try {
File canonicalFile = shell.getCanonicalFile();
if (canonicalFile.isFile() && canonicalFile.canExecute()) {
executablePath = canonicalFile.getAbsolutePath();
String[] parts = executablePath.split("/");
shellName = "-" + parts[parts.length - 1];
} else {
Log.w(EmulatorDebug.LOG_TAG, "$HOME/.termux/shell points to non-executable shell: " + canonicalFile.getAbsolutePath());
}
} catch (IOException e) {
Log.e(EmulatorDebug.LOG_TAG, "Error checking $HOME/.termux/shell", e);
}
}
if (executablePath == null) {
// Try bash, zsh and ash in that order:
for (String shellBinary : new String[]{"bash", "zsh", "ash"}) {
File shellFile = new File(PREFIX_PATH + "/bin/" + shellBinary);
if (shellFile.canExecute()) {
executablePath = shellFile.getAbsolutePath();
shellName = "-" + shellBinary;
break;
}
}
}
if (executablePath == null) {
// Fall back to system shell as last resort:
executablePath = "/system/bin/sh";
shellName = "-sh";
}
args = new String[]{shellName};
return new TerminalSession(executablePath, HOME_PATH, args, env, new TerminalSession.SessionChangedCallback() {
@Override
public void onTitleChanged(TerminalSession changedSession) {
// Ignore for now.
}
@Override
public void onTextChanged(TerminalSession changedSession) {
mFloatingWindow.mTerminalView.onScreenUpdated();
}
@Override
public void onSessionFinished(TerminalSession finishedSession) {
stopSelf();
}
@Override
public void onClipboardText(TerminalSession pastingSession, String text) {
mFloatingWindow.showToast("Clipboard set:\n\"" + text + "\"", true);
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setPrimaryClip(new ClipData(null, new String[]{"text/plain"}, new ClipData.Item(text)));
}
@Override
public void onBell(TerminalSession riningSession) {
((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50);
}
@Override
public void onColorsChanged(TerminalSession session) {
}
});
}
}

View File

@ -1,224 +0,0 @@
package com.termux.window;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.termux.view.TerminalView;
public class TermuxFloatView extends LinearLayout {
public static final float ALPHA_FOCUS = 0.9f;
public static final float ALPHA_NOT_FOCUS = 0.7f;
public static final float ALPHA_MOVING = 0.5f;
private int DISPLAY_WIDTH, DISPLAY_HEIGHT;
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
WindowManager mWindowManager;
InputMethodManager imm;
TerminalView mTerminalView;
/**
* The last toast shown, used cancel current toast before showing new in {@link #showToast(String, boolean)}.
*/
Toast mLastToast;
private boolean withFocus = true;
int initialX;
int initialY;
float initialTouchX;
float initialTouchY;
boolean isInLongPressState;
final int[] location = new int[2];
final ScaleGestureDetector mScaleDetector = new ScaleGestureDetector(getContext(), new OnScaleGestureListener() {
private static final int MIN_SIZE = 50;
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
int widthChange = (int) (detector.getCurrentSpanX() - detector.getPreviousSpanX());
int heightChange = (int) (detector.getCurrentSpanY() - detector.getPreviousSpanY());
layoutParams.width += widthChange;
layoutParams.height += heightChange;
layoutParams.width = Math.max(MIN_SIZE, layoutParams.width);
layoutParams.height = Math.max(MIN_SIZE, layoutParams.height);
mWindowManager.updateViewLayout(TermuxFloatView.this, layoutParams);
TermuxFloatPrefs.saveWindowSize(getContext(), layoutParams.width, layoutParams.height);
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
// Do nothing.
}
});
public TermuxFloatView(Context context, AttributeSet attrs) {
super(context, attrs);
setAlpha(ALPHA_FOCUS);
}
private static int computeLayoutFlags(boolean withFocus) {
if (withFocus) {
return 0;
} else {
return WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
}
}
public void initializeFloatingWindow() {
mTerminalView = (TerminalView) findViewById(R.id.terminal_view);
mTerminalView.setOnKeyListener(new TermuxFloatViewClient(this));
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Point displaySize = new Point();
getDisplay().getSize(displaySize);
DISPLAY_WIDTH = displaySize.x;
DISPLAY_HEIGHT = displaySize.y;
// mTerminalView.checkForFontAndColors();
}
@SuppressLint("RtlHardcoded")
public void launchFloatingWindow() {
int widthAndHeight = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
layoutParams.flags = computeLayoutFlags(true);
layoutParams.width = widthAndHeight;
layoutParams.height = widthAndHeight;
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
layoutParams.format = PixelFormat.RGBA_8888;
layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
TermuxFloatPrefs.applySavedGeometry(getContext(), layoutParams);
mWindowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
mWindowManager.addView(this, layoutParams);
imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
showTouchKeyboard();
}
/**
* Intercept touch events to obtain and loose focus on touch events.
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (isInLongPressState) return true;
getLocationOnScreen(location);
int x = location[0];
int y = location[1];
float touchX = event.getRawX();
float touchY = event.getRawY();
boolean clickedInside = (touchX >= x) && (touchX <= (x + layoutParams.width)) && (touchY >= y) && (touchY <= (y + layoutParams.height));
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (!clickedInside) changeFocus(false);
break;
case MotionEvent.ACTION_UP:
if (clickedInside) {
changeFocus(true);
showTouchKeyboard();
}
break;
}
return false;
}
void showTouchKeyboard() {
mTerminalView.post(new Runnable() {
@Override
public void run() {
imm.showSoftInput(mTerminalView, InputMethodManager.SHOW_IMPLICIT);
}
});
}
void updateLongPressMode(boolean newValue) {
isInLongPressState = newValue;
setBackgroundResource(newValue ? R.drawable.floating_window_background_resize : R.drawable.floating_window_background);
setAlpha(newValue ? ALPHA_MOVING : (withFocus ? ALPHA_FOCUS : ALPHA_NOT_FOCUS));
if (newValue) {
Toast toast = Toast.makeText(getContext(), R.string.after_long_press, Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
}
/**
* Motion events should only be dispatched here when {@link #onInterceptTouchEvent(MotionEvent)} returns true.
*/
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isInLongPressState) {
mScaleDetector.onTouchEvent(event);
if (mScaleDetector.isInProgress()) return true;
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
layoutParams.x = Math.min(DISPLAY_WIDTH - layoutParams.width, Math.max(0, initialX + (int) (event.getRawX() - initialTouchX)));
layoutParams.y = Math.min(DISPLAY_HEIGHT - layoutParams.height, Math.max(0, initialY + (int) (event.getRawY() - initialTouchY)));
mWindowManager.updateViewLayout(TermuxFloatView.this, layoutParams);
TermuxFloatPrefs.saveWindowPosition(getContext(), layoutParams.x, layoutParams.y);
break;
case MotionEvent.ACTION_UP:
updateLongPressMode(false);
break;
}
return true;
}
return super.onTouchEvent(event);
}
/**
* Visually indicate focus and show the soft input as needed.
*/
void changeFocus(boolean newFocus) {
if (newFocus == withFocus) {
if (newFocus) showTouchKeyboard();
return;
}
withFocus = newFocus;
layoutParams.flags = computeLayoutFlags(withFocus);
mWindowManager.updateViewLayout(this, layoutParams);
setAlpha(newFocus ? ALPHA_FOCUS : ALPHA_NOT_FOCUS);
}
/**
* Show a toast and dismiss the last one if still visible.
*/
void showToast(String text, boolean longDuration) {
if (mLastToast != null) mLastToast.cancel();
mLastToast = Toast.makeText(getContext(), text, longDuration ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT);
mLastToast.setGravity(Gravity.TOP, 0, 0);
mLastToast.show();
}
public void closeFloatingWindow() {
mWindowManager.removeView(this);
}
}

View File

@ -1,219 +0,0 @@
package com.termux.window;
import android.content.Context;
import android.media.AudioManager;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.inputmethod.InputMethodManager;
import com.termux.terminal.KeyHandler;
import com.termux.terminal.TerminalEmulator;
import com.termux.terminal.TerminalSession;
import com.termux.view.TerminalViewClient;
public class TermuxFloatViewClient implements TerminalViewClient {
private final TermuxFloatView view;
/**
* Keeping track of the special keys acting as Ctrl and Fn for the soft keyboard and other hardware keys.
*/
boolean mVirtualControlKeyDown, mVirtualFnKeyDown;
public TermuxFloatViewClient(TermuxFloatView view) {
this.view = view;
}
@Override
public float onScale(float scale) {
if (scale < 0.9f || scale > 1.1f) {
boolean increase = scale > 1.f;
((TermuxFloatService) view.getContext()).changeFontSize(increase);
return 1.0f;
}
return scale;
}
@Override
public boolean onLongPress(MotionEvent event) {
view.updateLongPressMode(true);
view.getLocationOnScreen(view.location);
view.initialX = view.location[0];
view.initialY = view.location[1];
view.initialTouchX = event.getRawX();
view.initialTouchY = event.getRawY();
return true;
}
@Override
public void onSingleTapUp(MotionEvent e) {
// Do nothing.
}
@Override
public boolean shouldBackButtonBeMappedToEscape() {
return false;
}
@Override
public void copyModeChanged(boolean copyMode) {
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent e, TerminalSession session) {
if (handleVirtualKeys(keyCode, e, true)) return true;
if (e.isCtrlPressed() && e.isAltPressed()) {
// Get the unmodified code point:
int unicodeChar = e.getUnicodeChar(0);
if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN || unicodeChar == 'n'/* next */) {
// TODO: Toggle minimized or not.
} else if (unicodeChar == 'f'/* full screen */) {
// TODO: Toggle full screen.
} else if (unicodeChar == 'k'/* keyboard */) {
InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
return true;
}
return false;
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent e) {
return handleVirtualKeys(keyCode, e, false);
}
@Override
public boolean readControlKey() {
return mVirtualControlKeyDown;
}
@Override
public boolean readAltKey() {
return false;
}
@Override
public boolean onCodePoint(int codePoint, boolean ctrlDown, TerminalSession session) {
if (mVirtualFnKeyDown) {
int resultingKeyCode = -1;
int resultingCodePoint = -1;
boolean altDown = false;
int lowerCase = Character.toLowerCase(codePoint);
switch (lowerCase) {
// Arrow keys.
case 'w':
resultingKeyCode = KeyEvent.KEYCODE_DPAD_UP;
break;
case 'a':
resultingKeyCode = KeyEvent.KEYCODE_DPAD_LEFT;
break;
case 's':
resultingKeyCode = KeyEvent.KEYCODE_DPAD_DOWN;
break;
case 'd':
resultingKeyCode = KeyEvent.KEYCODE_DPAD_RIGHT;
break;
// Page up and down.
case 'p':
resultingKeyCode = KeyEvent.KEYCODE_PAGE_UP;
break;
case 'n':
resultingKeyCode = KeyEvent.KEYCODE_PAGE_DOWN;
break;
// Some special keys:
case 't':
resultingKeyCode = KeyEvent.KEYCODE_TAB;
break;
case 'i':
resultingKeyCode = KeyEvent.KEYCODE_INSERT;
break;
case 'h':
resultingCodePoint = '~';
break;
// Special characters to input.
case 'u':
resultingCodePoint = '_';
break;
case 'l':
resultingCodePoint = '|';
break;
// Function keys.
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
resultingKeyCode = (codePoint - '1') + KeyEvent.KEYCODE_F1;
break;
case '0':
resultingKeyCode = KeyEvent.KEYCODE_F10;
break;
// Other special keys.
case 'e':
resultingCodePoint = /*Escape*/ 27;
break;
case '.':
resultingCodePoint = /*^.*/ 28;
break;
case 'b': // alt+b, jumping backward in readline.
case 'f': // alf+f, jumping forward in readline.
case 'x': // alt+x, common in emacs.
resultingCodePoint = lowerCase;
altDown = true;
break;
// Volume control.
case 'v':
resultingCodePoint = -1;
AudioManager audio = (AudioManager) view.getContext().getSystemService(Context.AUDIO_SERVICE);
audio.adjustSuggestedStreamVolume(AudioManager.ADJUST_SAME, AudioManager.USE_DEFAULT_STREAM_TYPE, AudioManager.FLAG_SHOW_UI);
break;
}
if (resultingKeyCode != -1) {
TerminalEmulator term = session.getEmulator();
session.write(KeyHandler.getCode(resultingKeyCode, 0, term.isCursorKeysApplicationMode(), term.isKeypadApplicationMode()));
} else if (resultingCodePoint != -1) {
session.writeCodePoint(altDown, resultingCodePoint);
}
return true;
}
return false;
}
/**
* Handle dedicated volume buttons as virtual keys if applicable.
*/
private boolean handleVirtualKeys(int keyCode, KeyEvent event, boolean down) {
InputDevice inputDevice = event.getDevice();
if (inputDevice != null && inputDevice.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
// Do not steal dedicated buttons from a full external keyboard.
return false;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
mVirtualControlKeyDown = down;
return true;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
mVirtualFnKeyDown = down;
return true;
}
return false;
}
}

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Background for the window, used to draw a border -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<stroke
android:width="1px"
android:color="@android:color/white" />
<solid android:color="#FF000000" />
</shape>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<stroke
android:width="1px"
android:color="@android:color/holo_red_light" />
<solid android:color="#FF000000" />
</shape>

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<com.termux.window.TermuxFloatView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/window_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/floating_window_background"
android:padding="1px" >
<com.termux.view.TerminalView
android:id="@+id/terminal_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:focusable="true"
android:focusableInTouchMode="true"
android:scrollbars="vertical" />
</com.termux.window.TermuxFloatView>

View File

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:gravity="center"
android:layout_height="match_parent">
<TextView
android:layout_gravity="center"
android:text="@string/draw_overlay_permission_explanation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_marginTop="24dp"
android:text="@string/grant_permission"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onOkButton"/>
</LinearLayout>
</LinearLayout>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 983 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Termux:Float</string>
<string name="initial_instruction_toast">Long press on window to move or resize\n\nDouble tap and drag finger up or down to change font size</string>
<string name="after_long_press">Drag to position and pinch to resize</string>
<string name="draw_overlay_permission_explanation">This app requires permission to draw overlays.</string>
<string name="grant_permission">Grant permission</string>
<string name="notification_title">Termux:Float</string>
<string name="notification_message_visible">Touch to hide window.</string>
<string name="notification_message_hidden">Touch to show window.</string>
<string name="paste_text">Paste</string>
<string name="copy_text">Copy</string>
<string name="text_selection_more">More…</string>
</resources>

View File

@ -1,20 +0,0 @@
<resources>
<!--
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Light">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style>
</resources>

View File

@ -1 +1 @@
include ':app', ':terminal-emulator', ':terminal-view', ':float'
include ':app', ':terminal-emulator', ':terminal-view'