diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index cde9d869..0cb13414 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -10,6 +10,9 @@
+
+
+
diff --git a/app/build.gradle b/app/build.gradle
index 4e5a867e..7d8db540 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -5,8 +5,9 @@ android {
buildToolsVersion "25.0.2"
dependencies {
- compile 'com.android.support:support-annotations:25.2.0'
- compile "com.android.support:support-v4:25.2.0"
+ compile 'com.android.support:support-annotations:25.3.1'
+ compile "com.android.support:support-v4:25.3.1"
+ compile project(":view")
}
defaultConfig {
@@ -15,16 +16,6 @@ android {
targetSdkVersion 25
versionCode 48
versionName "0.48"
-
- externalNativeBuild {
- ndkBuild {
- cFlags "-std=c11", "-Wall", "-Wextra", "-Werror", "-Os", "-fno-stack-protector", "-Wl,--gc-sections"
- }
- }
-
- ndk {
- abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
- }
}
buildTypes {
@@ -34,12 +25,6 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
-
- externalNativeBuild {
- ndkBuild {
- path "src/main/jni/Android.mk"
- }
- }
}
dependencies {
diff --git a/app/src/androidTest/java/com/termux/ApplicationTest.java b/app/src/androidTest/java/com/termux/ApplicationTest.java
deleted file mode 100644
index b09163fc..00000000
--- a/app/src/androidTest/java/com/termux/ApplicationTest.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.termux;
-
-import android.app.Application;
-import android.test.ApplicationTestCase;
-
-/**
- * Testing Fundamentals
- */
-public class ApplicationTest extends ApplicationTestCase {
- public ApplicationTest() {
- super(Application.class);
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/termux/app/TermuxKeyListener.java b/app/src/main/java/com/termux/app/TermuxKeyListener.java
index 3e7e3758..4e5f91c3 100644
--- a/app/src/main/java/com/termux/app/TermuxKeyListener.java
+++ b/app/src/main/java/com/termux/app/TermuxKeyListener.java
@@ -256,6 +256,11 @@ public final class TermuxKeyListener implements TerminalKeyListener {
return false;
}
+ @Override
+ public boolean onLongPress(MotionEvent event) {
+ return false;
+ }
+
/** Handle dedicated volume buttons as virtual keys if applicable. */
private boolean handleVirtualKeys(int keyCode, KeyEvent event, boolean down) {
InputDevice inputDevice = event.getDevice();
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 48d890f1..f192dc96 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -30,10 +30,6 @@
URL copied to clipboard
Send text to:
- Paste
- Copy
- More…
-
Kill process (%d)
Really kill this session?
diff --git a/float/build.gradle b/float/build.gradle
new file mode 100644
index 00000000..8be67fb6
--- /dev/null
+++ b/float/build.gradle
@@ -0,0 +1,37 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.2"
+
+ dependencies {
+ compile 'com.android.support:support-annotations:25.3.1'
+ compile project(":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'
+}
diff --git a/float/proguard-rules.pro b/float/proguard-rules.pro
new file mode 100644
index 00000000..2e56e600
--- /dev/null
+++ b/float/proguard-rules.pro
@@ -0,0 +1,25 @@
+# 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
diff --git a/float/src/main/AndroidManifest.xml b/float/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..b46aca9d
--- /dev/null
+++ b/float/src/main/AndroidManifest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/float/src/main/java/com/termux/window/TermuxFloatActivity.java b/float/src/main/java/com/termux/window/TermuxFloatActivity.java
new file mode 100644
index 00000000..0535e75d
--- /dev/null
+++ b/float/src/main/java/com/termux/window/TermuxFloatActivity.java
@@ -0,0 +1,16 @@
+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();
+ }
+
+}
diff --git a/float/src/main/java/com/termux/window/TermuxFloatPermissionActivity.java b/float/src/main/java/com/termux/window/TermuxFloatPermissionActivity.java
new file mode 100644
index 00000000..a43b20ed
--- /dev/null
+++ b/float/src/main/java/com/termux/window/TermuxFloatPermissionActivity.java
@@ -0,0 +1,35 @@
+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();
+ }
+ }
+
+}
diff --git a/float/src/main/java/com/termux/window/TermuxFloatPrefs.java b/float/src/main/java/com/termux/window/TermuxFloatPrefs.java
new file mode 100644
index 00000000..ef9d7feb
--- /dev/null
+++ b/float/src/main/java/com/termux/window/TermuxFloatPrefs.java
@@ -0,0 +1,33 @@
+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);
+ }
+
+}
diff --git a/float/src/main/java/com/termux/window/TermuxFloatService.java b/float/src/main/java/com/termux/window/TermuxFloatService.java
new file mode 100644
index 00000000..d5d99d85
--- /dev/null
+++ b/float/src/main/java/com/termux/window/TermuxFloatService.java
@@ -0,0 +1,243 @@
+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)}.
+ *
+ * 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)) {
+ mVisibleWindow = false;
+ mFloatingWindow.setVisibility(View.GONE);
+ ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, buildNotification());
+ } else if (ACTION_SHOW.equals(action)) {
+ mFloatingWindow.setVisibility(View.VISIBLE);
+ mVisibleWindow = true;
+ ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, buildNotification());
+ }
+ return Service.START_NOT_STICKY;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mFloatingWindow != null) mFloatingWindow.closeFloatingWindow();
+ }
+
+ 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) {
+
+ }
+ });
+ }
+
+}
diff --git a/float/src/main/java/com/termux/window/TermuxFloatView.java b/float/src/main/java/com/termux/window/TermuxFloatView.java
new file mode 100644
index 00000000..2fc0e206
--- /dev/null
+++ b/float/src/main/java/com/termux/window/TermuxFloatView.java
@@ -0,0 +1,277 @@
+package com.termux.window;
+
+import com.termux.terminal.TerminalSession;
+import com.termux.view.TerminalKeyListener;
+import com.termux.view.TerminalView;
+
+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.KeyEvent;
+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;
+
+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;
+ private int initialX;
+ private int initialY;
+ private float initialTouchX;
+ private float initialTouchY;
+
+ boolean isInLongPressState;
+
+ 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 TerminalKeyListener() {
+ @Override
+ public float onScale(float scale) {
+ if (scale < 0.9f || scale > 1.1f) {
+ boolean increase = scale > 1.f;
+ ((TermuxFloatService) getContext()).changeFontSize(increase);
+ return 1.0f;
+ }
+ return scale;
+ }
+
+ @Override
+ public boolean onLongPress(MotionEvent event) {
+ updateLongPressMode(true);
+ initialX = layoutParams.x;
+ initialY = layoutParams.y;
+ initialTouchX = event.getRawX();
+ initialTouchY = event.getRawY();
+ return true;
+ }
+
+ @Override
+ public void onSingleTapUp(MotionEvent e) {
+ // Do nothing.
+ }
+
+ @Override
+ public boolean shouldBackButtonBeMappedToEscape() {
+ return true;
+ }
+
+ @Override
+ public void copyModeChanged(boolean copyMode) {
+
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent e, TerminalSession session) {
+ return false;
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent e) {
+ return false;
+ }
+
+ @Override
+ public boolean readControlKey() {
+ return false;
+ }
+
+ @Override
+ public boolean readAltKey() {
+ return false;
+ }
+
+ @Override
+ public boolean onCodePoint(int codePoint, boolean ctrlDown, TerminalSession session) {
+ return false;
+ }
+
+ });
+ }
+
+ @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;
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if ((event.getMetaState() & (KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON)) != 0) {
+ updateLongPressMode(true);
+ initialX = layoutParams.x;
+ initialY = layoutParams.y;
+ initialTouchX = event.getRawX();
+ initialTouchY = event.getRawY();
+ return true;
+ }
+ // FIXME: params.x and params.y are outdated when snapping to end of screen, where the movement stops but x
+ // and y are wrong.
+ float touchX = event.getRawX();
+ float touchY = event.getRawY();
+ boolean clickedInside = (touchX >= layoutParams.x) && (touchX <= (layoutParams.x + layoutParams.width)) && (touchY >= layoutParams.y)
+ && (touchY <= (layoutParams.y + layoutParams.height));
+ if (withFocus != clickedInside) {
+ changeFocus(clickedInside);
+ } else if (clickedInside) {
+ // When clicking inside, show keyboard if the user has hidden it:
+ showTouchKeyboard();
+ }
+ }
+ return false;
+ }
+
+ private void showTouchKeyboard() {
+ mTerminalView.post(new Runnable() {
+ @Override
+ public void run() {
+ imm.showSoftInput(mTerminalView, InputMethodManager.SHOW_IMPLICIT);
+ }
+ });
+ }
+
+ private void updateLongPressMode(boolean newValue) {
+ isInLongPressState = newValue;
+ setBackgroundResource(newValue ? R.drawable.floating_window_background_resize : R.drawable.floating_window_background);
+ setAlpha(newValue ? ALPHA_MOVING : ALPHA_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. */
+ private void changeFocus(boolean newFocus) {
+ withFocus = newFocus;
+ layoutParams.flags = computeLayoutFlags(withFocus);
+ mWindowManager.updateViewLayout(this, layoutParams);
+ setAlpha(newFocus ? ALPHA_FOCUS : ALPHA_NOT_FOCUS);
+ if (newFocus) showTouchKeyboard();
+ }
+
+ /** 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);
+ }
+
+}
diff --git a/float/src/main/res/drawable/floating_window_background.xml b/float/src/main/res/drawable/floating_window_background.xml
new file mode 100644
index 00000000..afbe84c5
--- /dev/null
+++ b/float/src/main/res/drawable/floating_window_background.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/float/src/main/res/drawable/floating_window_background_resize.xml b/float/src/main/res/drawable/floating_window_background_resize.xml
new file mode 100644
index 00000000..26a25fea
--- /dev/null
+++ b/float/src/main/res/drawable/floating_window_background_resize.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/float/src/main/res/layout/activity_main.xml b/float/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..8acbdd30
--- /dev/null
+++ b/float/src/main/res/layout/activity_main.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/float/src/main/res/layout/activity_permission.xml b/float/src/main/res/layout/activity_permission.xml
new file mode 100644
index 00000000..7027eb75
--- /dev/null
+++ b/float/src/main/res/layout/activity_permission.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/float/src/main/res/mipmap-hdpi/ic_launcher.png b/float/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..aa06923d
Binary files /dev/null and b/float/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/float/src/main/res/mipmap-hdpi/ic_launcher_round.png b/float/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 00000000..7eca6a5d
Binary files /dev/null and b/float/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/float/src/main/res/mipmap-hdpi/ic_service_notification.png b/float/src/main/res/mipmap-hdpi/ic_service_notification.png
new file mode 100644
index 00000000..52099fa0
Binary files /dev/null and b/float/src/main/res/mipmap-hdpi/ic_service_notification.png differ
diff --git a/float/src/main/res/mipmap-mdpi/ic_launcher.png b/float/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..c133a0cb
Binary files /dev/null and b/float/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/float/src/main/res/mipmap-mdpi/ic_launcher_round.png b/float/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 00000000..f2738993
Binary files /dev/null and b/float/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/float/src/main/res/mipmap-xhdpi/ic_launcher.png b/float/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..bc8ecf9f
Binary files /dev/null and b/float/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/float/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/float/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..00661c01
Binary files /dev/null and b/float/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/float/src/main/res/mipmap-xhdpi/ic_service_notification.png b/float/src/main/res/mipmap-xhdpi/ic_service_notification.png
new file mode 100644
index 00000000..7c172bc8
Binary files /dev/null and b/float/src/main/res/mipmap-xhdpi/ic_service_notification.png differ
diff --git a/float/src/main/res/mipmap-xxhdpi/ic_launcher.png b/float/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..742e5629
Binary files /dev/null and b/float/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/float/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/float/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..66d02400
Binary files /dev/null and b/float/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/float/src/main/res/mipmap-xxhdpi/ic_service_notification.png b/float/src/main/res/mipmap-xxhdpi/ic_service_notification.png
new file mode 100644
index 00000000..ecaf5e55
Binary files /dev/null and b/float/src/main/res/mipmap-xxhdpi/ic_service_notification.png differ
diff --git a/float/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/float/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..18c48661
Binary files /dev/null and b/float/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/float/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/float/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..747fa10f
Binary files /dev/null and b/float/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/float/src/main/res/mipmap-xxxhdpi/ic_service_notification.png b/float/src/main/res/mipmap-xxxhdpi/ic_service_notification.png
new file mode 100644
index 00000000..7a077ff5
Binary files /dev/null and b/float/src/main/res/mipmap-xxxhdpi/ic_service_notification.png differ
diff --git a/float/src/main/res/values/strings.xml b/float/src/main/res/values/strings.xml
new file mode 100644
index 00000000..f0af0581
--- /dev/null
+++ b/float/src/main/res/values/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Termux:Float
+ Long press on window to move or resize\n\nDouble tap and drag finger up or down to change font size
+ Drag to position and pinch to resize
+
+ This app requires permission to draw overlays.
+ Grant permission
+
+ Termux:Float
+ Touch to hide window.
+ Touch to show window.
+
+ Paste
+ Copy
+ More…
+
+
diff --git a/float/src/main/res/values/styles.xml b/float/src/main/res/values/styles.xml
new file mode 100644
index 00000000..6ce89c7b
--- /dev/null
+++ b/float/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
diff --git a/settings.gradle b/settings.gradle
index e7b4def4..860dae9a 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app'
+include ':app', ':terminal', ':view', ':float'
diff --git a/terminal/build.gradle b/terminal/build.gradle
new file mode 100644
index 00000000..e76e1ee6
--- /dev/null
+++ b/terminal/build.gradle
@@ -0,0 +1,47 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.2"
+
+ defaultConfig {
+ minSdkVersion 21
+ targetSdkVersion 25
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+
+ externalNativeBuild {
+ ndkBuild {
+ cFlags "-std=c11", "-Wall", "-Wextra", "-Werror", "-Os", "-fno-stack-protector", "-Wl,--gc-sections"
+ }
+ }
+
+ ndk {
+ abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
+ }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ externalNativeBuild {
+ ndkBuild {
+ path "src/main/jni/Android.mk"
+ }
+ }
+}
+
+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'
+}
diff --git a/terminal/proguard-rules.pro b/terminal/proguard-rules.pro
new file mode 100644
index 00000000..2e56e600
--- /dev/null
+++ b/terminal/proguard-rules.pro
@@ -0,0 +1,25 @@
+# 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
diff --git a/terminal/src/main/AndroidManifest.xml b/terminal/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..b931189d
--- /dev/null
+++ b/terminal/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/app/src/main/java/com/termux/terminal/ByteQueue.java b/terminal/src/main/java/com/termux/terminal/ByteQueue.java
similarity index 100%
rename from app/src/main/java/com/termux/terminal/ByteQueue.java
rename to terminal/src/main/java/com/termux/terminal/ByteQueue.java
diff --git a/app/src/main/java/com/termux/terminal/EmulatorDebug.java b/terminal/src/main/java/com/termux/terminal/EmulatorDebug.java
similarity index 100%
rename from app/src/main/java/com/termux/terminal/EmulatorDebug.java
rename to terminal/src/main/java/com/termux/terminal/EmulatorDebug.java
diff --git a/app/src/main/java/com/termux/terminal/JNI.java b/terminal/src/main/java/com/termux/terminal/JNI.java
similarity index 100%
rename from app/src/main/java/com/termux/terminal/JNI.java
rename to terminal/src/main/java/com/termux/terminal/JNI.java
diff --git a/app/src/main/java/com/termux/terminal/KeyHandler.java b/terminal/src/main/java/com/termux/terminal/KeyHandler.java
similarity index 100%
rename from app/src/main/java/com/termux/terminal/KeyHandler.java
rename to terminal/src/main/java/com/termux/terminal/KeyHandler.java
diff --git a/app/src/main/java/com/termux/terminal/TerminalBuffer.java b/terminal/src/main/java/com/termux/terminal/TerminalBuffer.java
similarity index 100%
rename from app/src/main/java/com/termux/terminal/TerminalBuffer.java
rename to terminal/src/main/java/com/termux/terminal/TerminalBuffer.java
diff --git a/app/src/main/java/com/termux/terminal/TerminalColorScheme.java b/terminal/src/main/java/com/termux/terminal/TerminalColorScheme.java
similarity index 100%
rename from app/src/main/java/com/termux/terminal/TerminalColorScheme.java
rename to terminal/src/main/java/com/termux/terminal/TerminalColorScheme.java
diff --git a/app/src/main/java/com/termux/terminal/TerminalColors.java b/terminal/src/main/java/com/termux/terminal/TerminalColors.java
similarity index 100%
rename from app/src/main/java/com/termux/terminal/TerminalColors.java
rename to terminal/src/main/java/com/termux/terminal/TerminalColors.java
diff --git a/app/src/main/java/com/termux/terminal/TerminalEmulator.java b/terminal/src/main/java/com/termux/terminal/TerminalEmulator.java
similarity index 100%
rename from app/src/main/java/com/termux/terminal/TerminalEmulator.java
rename to terminal/src/main/java/com/termux/terminal/TerminalEmulator.java
diff --git a/app/src/main/java/com/termux/terminal/TerminalOutput.java b/terminal/src/main/java/com/termux/terminal/TerminalOutput.java
similarity index 100%
rename from app/src/main/java/com/termux/terminal/TerminalOutput.java
rename to terminal/src/main/java/com/termux/terminal/TerminalOutput.java
diff --git a/app/src/main/java/com/termux/terminal/TerminalRow.java b/terminal/src/main/java/com/termux/terminal/TerminalRow.java
similarity index 100%
rename from app/src/main/java/com/termux/terminal/TerminalRow.java
rename to terminal/src/main/java/com/termux/terminal/TerminalRow.java
diff --git a/app/src/main/java/com/termux/terminal/TerminalSession.java b/terminal/src/main/java/com/termux/terminal/TerminalSession.java
similarity index 100%
rename from app/src/main/java/com/termux/terminal/TerminalSession.java
rename to terminal/src/main/java/com/termux/terminal/TerminalSession.java
diff --git a/app/src/main/java/com/termux/terminal/TextStyle.java b/terminal/src/main/java/com/termux/terminal/TextStyle.java
similarity index 100%
rename from app/src/main/java/com/termux/terminal/TextStyle.java
rename to terminal/src/main/java/com/termux/terminal/TextStyle.java
diff --git a/app/src/main/java/com/termux/terminal/WcWidth.java b/terminal/src/main/java/com/termux/terminal/WcWidth.java
similarity index 100%
rename from app/src/main/java/com/termux/terminal/WcWidth.java
rename to terminal/src/main/java/com/termux/terminal/WcWidth.java
diff --git a/app/src/main/jni/Android.mk b/terminal/src/main/jni/Android.mk
similarity index 100%
rename from app/src/main/jni/Android.mk
rename to terminal/src/main/jni/Android.mk
diff --git a/app/src/main/jni/termux.c b/terminal/src/main/jni/termux.c
similarity index 100%
rename from app/src/main/jni/termux.c
rename to terminal/src/main/jni/termux.c
diff --git a/app/src/test/java/com/termux/terminal/ByteQueueTest.java b/terminal/src/test/java/com/termux/terminal/ByteQueueTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/ByteQueueTest.java
rename to terminal/src/test/java/com/termux/terminal/ByteQueueTest.java
diff --git a/app/src/test/java/com/termux/terminal/ControlSequenceIntroducerTest.java b/terminal/src/test/java/com/termux/terminal/ControlSequenceIntroducerTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/ControlSequenceIntroducerTest.java
rename to terminal/src/test/java/com/termux/terminal/ControlSequenceIntroducerTest.java
diff --git a/app/src/test/java/com/termux/terminal/CursorAndScreenTest.java b/terminal/src/test/java/com/termux/terminal/CursorAndScreenTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/CursorAndScreenTest.java
rename to terminal/src/test/java/com/termux/terminal/CursorAndScreenTest.java
diff --git a/app/src/test/java/com/termux/terminal/DecSetTest.java b/terminal/src/test/java/com/termux/terminal/DecSetTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/DecSetTest.java
rename to terminal/src/test/java/com/termux/terminal/DecSetTest.java
diff --git a/app/src/test/java/com/termux/terminal/DeviceControlStringTest.java b/terminal/src/test/java/com/termux/terminal/DeviceControlStringTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/DeviceControlStringTest.java
rename to terminal/src/test/java/com/termux/terminal/DeviceControlStringTest.java
diff --git a/app/src/test/java/com/termux/terminal/HistoryTest.java b/terminal/src/test/java/com/termux/terminal/HistoryTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/HistoryTest.java
rename to terminal/src/test/java/com/termux/terminal/HistoryTest.java
diff --git a/app/src/test/java/com/termux/terminal/KeyHandlerTest.java b/terminal/src/test/java/com/termux/terminal/KeyHandlerTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/KeyHandlerTest.java
rename to terminal/src/test/java/com/termux/terminal/KeyHandlerTest.java
diff --git a/app/src/test/java/com/termux/terminal/OperatingSystemControlTest.java b/terminal/src/test/java/com/termux/terminal/OperatingSystemControlTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/OperatingSystemControlTest.java
rename to terminal/src/test/java/com/termux/terminal/OperatingSystemControlTest.java
diff --git a/app/src/test/java/com/termux/terminal/RectangularAreasTest.java b/terminal/src/test/java/com/termux/terminal/RectangularAreasTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/RectangularAreasTest.java
rename to terminal/src/test/java/com/termux/terminal/RectangularAreasTest.java
diff --git a/app/src/test/java/com/termux/terminal/ResizeTest.java b/terminal/src/test/java/com/termux/terminal/ResizeTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/ResizeTest.java
rename to terminal/src/test/java/com/termux/terminal/ResizeTest.java
diff --git a/app/src/test/java/com/termux/terminal/ScreenBufferTest.java b/terminal/src/test/java/com/termux/terminal/ScreenBufferTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/ScreenBufferTest.java
rename to terminal/src/test/java/com/termux/terminal/ScreenBufferTest.java
diff --git a/app/src/test/java/com/termux/terminal/ScrollRegionTest.java b/terminal/src/test/java/com/termux/terminal/ScrollRegionTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/ScrollRegionTest.java
rename to terminal/src/test/java/com/termux/terminal/ScrollRegionTest.java
diff --git a/app/src/test/java/com/termux/terminal/TerminalRowTest.java b/terminal/src/test/java/com/termux/terminal/TerminalRowTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/TerminalRowTest.java
rename to terminal/src/test/java/com/termux/terminal/TerminalRowTest.java
diff --git a/app/src/test/java/com/termux/terminal/TerminalTest.java b/terminal/src/test/java/com/termux/terminal/TerminalTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/TerminalTest.java
rename to terminal/src/test/java/com/termux/terminal/TerminalTest.java
diff --git a/app/src/test/java/com/termux/terminal/TerminalTestCase.java b/terminal/src/test/java/com/termux/terminal/TerminalTestCase.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/TerminalTestCase.java
rename to terminal/src/test/java/com/termux/terminal/TerminalTestCase.java
diff --git a/app/src/test/java/com/termux/terminal/TextStyleTest.java b/terminal/src/test/java/com/termux/terminal/TextStyleTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/TextStyleTest.java
rename to terminal/src/test/java/com/termux/terminal/TextStyleTest.java
diff --git a/app/src/test/java/com/termux/terminal/UnicodeInputTest.java b/terminal/src/test/java/com/termux/terminal/UnicodeInputTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/UnicodeInputTest.java
rename to terminal/src/test/java/com/termux/terminal/UnicodeInputTest.java
diff --git a/app/src/test/java/com/termux/terminal/WcWidthTest.java b/terminal/src/test/java/com/termux/terminal/WcWidthTest.java
similarity index 100%
rename from app/src/test/java/com/termux/terminal/WcWidthTest.java
rename to terminal/src/test/java/com/termux/terminal/WcWidthTest.java
diff --git a/view/build.gradle b/view/build.gradle
new file mode 100644
index 00000000..f20f5823
--- /dev/null
+++ b/view/build.gradle
@@ -0,0 +1,36 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.2"
+
+ dependencies {
+ compile 'com.android.support:support-annotations:25.3.1'
+ compile project(":terminal")
+ }
+
+ defaultConfig {
+ 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'
+}
diff --git a/view/proguard-rules.pro b/view/proguard-rules.pro
new file mode 100644
index 00000000..2e56e600
--- /dev/null
+++ b/view/proguard-rules.pro
@@ -0,0 +1,25 @@
+# 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
diff --git a/view/src/main/AndroidManifest.xml b/view/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a312303c
--- /dev/null
+++ b/view/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/app/src/main/java/com/termux/view/GestureAndScaleRecognizer.java b/view/src/main/java/com/termux/view/GestureAndScaleRecognizer.java
similarity index 100%
rename from app/src/main/java/com/termux/view/GestureAndScaleRecognizer.java
rename to view/src/main/java/com/termux/view/GestureAndScaleRecognizer.java
diff --git a/app/src/main/java/com/termux/view/TerminalKeyListener.java b/view/src/main/java/com/termux/view/TerminalKeyListener.java
similarity index 76%
rename from app/src/main/java/com/termux/view/TerminalKeyListener.java
rename to view/src/main/java/com/termux/view/TerminalKeyListener.java
index 0925c075..ae21f39a 100644
--- a/app/src/main/java/com/termux/view/TerminalKeyListener.java
+++ b/view/src/main/java/com/termux/view/TerminalKeyListener.java
@@ -14,10 +14,14 @@ import com.termux.terminal.TerminalSession;
*/
public interface TerminalKeyListener {
- /** Callback function on scale events according to {@link ScaleGestureDetector#getScaleFactor()}. */
+ /**
+ * Callback function on scale events according to {@link ScaleGestureDetector#getScaleFactor()}.
+ */
float onScale(float scale);
- /** On a single tap on the terminal if terminal mouse reporting not enabled. */
+ /**
+ * On a single tap on the terminal if terminal mouse reporting not enabled.
+ */
void onSingleTapUp(MotionEvent e);
boolean shouldBackButtonBeMappedToEscape();
@@ -34,4 +38,6 @@ public interface TerminalKeyListener {
boolean onCodePoint(int codePoint, boolean ctrlDown, TerminalSession session);
+ boolean onLongPress(MotionEvent event);
+
}
diff --git a/app/src/main/java/com/termux/view/TerminalRenderer.java b/view/src/main/java/com/termux/view/TerminalRenderer.java
similarity index 100%
rename from app/src/main/java/com/termux/view/TerminalRenderer.java
rename to view/src/main/java/com/termux/view/TerminalRenderer.java
diff --git a/app/src/main/java/com/termux/view/TerminalView.java b/view/src/main/java/com/termux/view/TerminalView.java
similarity index 99%
rename from app/src/main/java/com/termux/view/TerminalView.java
rename to view/src/main/java/com/termux/view/TerminalView.java
index f5af809e..f789d629 100644
--- a/app/src/main/java/com/termux/view/TerminalView.java
+++ b/view/src/main/java/com/termux/view/TerminalView.java
@@ -29,7 +29,6 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.widget.Scroller;
-import com.termux.R;
import com.termux.terminal.EmulatorDebug;
import com.termux.terminal.KeyHandler;
import com.termux.terminal.TerminalBuffer;
@@ -189,6 +188,7 @@ public final class TerminalView extends View {
@Override
public void onLongPress(MotionEvent e) {
+ if (mOnKeyListener.onLongPress(e)) return;
if (!mGestureRecognizer.isInProgress() && !mIsSelectingText) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
toggleSelectingText(e);
diff --git a/app/src/main/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png b/view/src/main/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
similarity index 100%
rename from app/src/main/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
rename to view/src/main/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
diff --git a/app/src/main/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png b/view/src/main/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
similarity index 100%
rename from app/src/main/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
rename to view/src/main/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
diff --git a/app/src/main/res/drawable/text_select_handle_left_material.xml b/view/src/main/res/drawable/text_select_handle_left_material.xml
similarity index 100%
rename from app/src/main/res/drawable/text_select_handle_left_material.xml
rename to view/src/main/res/drawable/text_select_handle_left_material.xml
diff --git a/app/src/main/res/drawable/text_select_handle_right_material.xml b/view/src/main/res/drawable/text_select_handle_right_material.xml
similarity index 100%
rename from app/src/main/res/drawable/text_select_handle_right_material.xml
rename to view/src/main/res/drawable/text_select_handle_right_material.xml
diff --git a/view/src/main/res/values/strings.xml b/view/src/main/res/values/strings.xml
new file mode 100644
index 00000000..cd03c618
--- /dev/null
+++ b/view/src/main/res/values/strings.xml
@@ -0,0 +1,5 @@
+
+ Paste
+ Copy
+ More…
+