mirror of
https://github.com/fankes/termux-app.git
synced 2025-09-06 10:45:23 +08:00
Merge branch 'maoabc-master'
This commit is contained in:
@@ -4,7 +4,6 @@ import android.app.Activity;
|
|||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
@@ -21,10 +20,7 @@ import java.io.File;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
@@ -8,14 +8,14 @@ import android.content.Context;
|
|||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.accessibility.AccessibilityManager;
|
|
||||||
import android.view.ActionMode;
|
import android.view.ActionMode;
|
||||||
import android.view.HapticFeedbackConstants;
|
import android.view.HapticFeedbackConstants;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
@@ -25,9 +25,16 @@ import android.view.Menu;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewConfiguration;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewParent;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.view.accessibility.AccessibilityManager;
|
||||||
import android.view.inputmethod.BaseInputConnection;
|
import android.view.inputmethod.BaseInputConnection;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.view.inputmethod.InputConnection;
|
import android.view.inputmethod.InputConnection;
|
||||||
|
import android.widget.PopupWindow;
|
||||||
import android.widget.Scroller;
|
import android.widget.Scroller;
|
||||||
|
|
||||||
import com.termux.terminal.EmulatorDebug;
|
import com.termux.terminal.EmulatorDebug;
|
||||||
@@ -35,6 +42,7 @@ import com.termux.terminal.KeyHandler;
|
|||||||
import com.termux.terminal.TerminalBuffer;
|
import com.termux.terminal.TerminalBuffer;
|
||||||
import com.termux.terminal.TerminalEmulator;
|
import com.termux.terminal.TerminalEmulator;
|
||||||
import com.termux.terminal.TerminalSession;
|
import com.termux.terminal.TerminalSession;
|
||||||
|
import com.termux.terminal.WcWidth;
|
||||||
|
|
||||||
/** View displaying and interacting with a {@link TerminalSession}. */
|
/** View displaying and interacting with a {@link TerminalSession}. */
|
||||||
public final class TerminalView extends View {
|
public final class TerminalView extends View {
|
||||||
@@ -54,11 +62,14 @@ public final class TerminalView extends View {
|
|||||||
/** The top row of text to display. Ranges from -activeTranscriptRows to 0. */
|
/** The top row of text to display. Ranges from -activeTranscriptRows to 0. */
|
||||||
int mTopRow;
|
int mTopRow;
|
||||||
|
|
||||||
boolean mIsSelectingText = false, mIsDraggingLeftSelection, mInitialTextSelection;
|
boolean mIsSelectingText = false;
|
||||||
int mSelX1 = -1, mSelX2 = -1, mSelY1 = -1, mSelY2 = -1;
|
int mSelX1 = -1, mSelX2 = -1, mSelY1 = -1, mSelY2 = -1;
|
||||||
float mSelectionDownX, mSelectionDownY;
|
|
||||||
private ActionMode mActionMode;
|
private ActionMode mActionMode;
|
||||||
private BitmapDrawable mLeftSelectionHandle, mRightSelectionHandle;
|
Drawable mSelectHandleLeft;
|
||||||
|
Drawable mSelectHandleRight;
|
||||||
|
final int[] mTempCoords = new int[2];
|
||||||
|
Rect mTempRect;
|
||||||
|
private SelectionModifierCursorController mSelectionModifierCursorController;
|
||||||
|
|
||||||
float mScaleFactor = 1.f;
|
float mScaleFactor = 1.f;
|
||||||
final GestureAndScaleRecognizer mGestureRecognizer;
|
final GestureAndScaleRecognizer mGestureRecognizer;
|
||||||
@@ -102,7 +113,7 @@ public final class TerminalView extends View {
|
|||||||
public boolean onSingleTapUp(MotionEvent e) {
|
public boolean onSingleTapUp(MotionEvent e) {
|
||||||
if (mEmulator == null) return true;
|
if (mEmulator == null) return true;
|
||||||
if (mIsSelectingText) {
|
if (mIsSelectingText) {
|
||||||
toggleSelectingText(null);
|
stopTextSelectionMode();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
requestFocus();
|
requestFocus();
|
||||||
@@ -117,7 +128,7 @@ public final class TerminalView extends View {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onScroll(MotionEvent e, float distanceX, float distanceY) {
|
public boolean onScroll(MotionEvent e, float distanceX, float distanceY) {
|
||||||
if (mEmulator == null || mIsSelectingText) return true;
|
if (mEmulator == null) return true;
|
||||||
if (mEmulator.isMouseTrackingActive() && e.isFromSource(InputDevice.SOURCE_MOUSE)) {
|
if (mEmulator.isMouseTrackingActive() && e.isFromSource(InputDevice.SOURCE_MOUSE)) {
|
||||||
// If moving with mouse pointer while pressing button, report that instead of scroll.
|
// If moving with mouse pointer while pressing button, report that instead of scroll.
|
||||||
// This means that we never report moving with button press-events for touch input,
|
// This means that we never report moving with button press-events for touch input,
|
||||||
@@ -144,7 +155,7 @@ public final class TerminalView extends View {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onFling(final MotionEvent e2, float velocityX, float velocityY) {
|
public boolean onFling(final MotionEvent e2, float velocityX, float velocityY) {
|
||||||
if (mEmulator == null || mIsSelectingText) return true;
|
if (mEmulator == null) return true;
|
||||||
// Do not start scrolling until last fling has been taken care of:
|
// Do not start scrolling until last fling has been taken care of:
|
||||||
if (!mScroller.isFinished()) return true;
|
if (!mScroller.isFinished()) return true;
|
||||||
|
|
||||||
@@ -195,7 +206,7 @@ public final class TerminalView extends View {
|
|||||||
if (mClient.onLongPress(e)) return;
|
if (mClient.onLongPress(e)) return;
|
||||||
if (!mIsSelectingText) {
|
if (!mIsSelectingText) {
|
||||||
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||||
toggleSelectingText(e);
|
startSelectingText(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -287,6 +298,7 @@ public final class TerminalView extends View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sendTextToTerminal(CharSequence text) {
|
void sendTextToTerminal(CharSequence text) {
|
||||||
|
stopTextSelectionMode();
|
||||||
final int textLengthInChars = text.length();
|
final int textLengthInChars = text.length();
|
||||||
for (int i = 0; i < textLengthInChars; i++) {
|
for (int i = 0; i < textLengthInChars; i++) {
|
||||||
char firstChar = text.charAt(i);
|
char firstChar = text.charAt(i);
|
||||||
@@ -368,7 +380,7 @@ public final class TerminalView extends View {
|
|||||||
if (-mTopRow + rowShift > rowsInHistory) {
|
if (-mTopRow + rowShift > rowsInHistory) {
|
||||||
// .. unless we're hitting the end of history transcript, in which
|
// .. unless we're hitting the end of history transcript, in which
|
||||||
// case we abort text selection and scroll to end.
|
// case we abort text selection and scroll to end.
|
||||||
toggleSelectingText(null);
|
stopTextSelectionMode();
|
||||||
} else {
|
} else {
|
||||||
skipScrolling = true;
|
skipScrolling = true;
|
||||||
mTopRow -= rowShift;
|
mTopRow -= rowShift;
|
||||||
@@ -475,55 +487,7 @@ public final class TerminalView extends View {
|
|||||||
final int action = ev.getAction();
|
final int action = ev.getAction();
|
||||||
|
|
||||||
if (mIsSelectingText) {
|
if (mIsSelectingText) {
|
||||||
int cy = (int) (ev.getY() / mRenderer.mFontLineSpacing) + mTopRow;
|
updateFloatingToolbarVisibility(ev);
|
||||||
int cx = (int) (ev.getX() / mRenderer.mFontWidth);
|
|
||||||
|
|
||||||
switch (action) {
|
|
||||||
case MotionEvent.ACTION_UP:
|
|
||||||
mInitialTextSelection = false;
|
|
||||||
break;
|
|
||||||
case MotionEvent.ACTION_DOWN:
|
|
||||||
int distanceFromSel1 = Math.abs(cx - mSelX1) + Math.abs(cy - mSelY1);
|
|
||||||
int distanceFromSel2 = Math.abs(cx - mSelX2) + Math.abs(cy - mSelY2);
|
|
||||||
mIsDraggingLeftSelection = distanceFromSel1 <= distanceFromSel2;
|
|
||||||
mSelectionDownX = ev.getX();
|
|
||||||
mSelectionDownY = ev.getY();
|
|
||||||
break;
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
|
||||||
if (mInitialTextSelection) break;
|
|
||||||
float deltaX = ev.getX() - mSelectionDownX;
|
|
||||||
float deltaY = ev.getY() - mSelectionDownY;
|
|
||||||
int deltaCols = (int) Math.ceil(deltaX / mRenderer.mFontWidth);
|
|
||||||
int deltaRows = (int) Math.ceil(deltaY / mRenderer.mFontLineSpacing);
|
|
||||||
mSelectionDownX += deltaCols * mRenderer.mFontWidth;
|
|
||||||
mSelectionDownY += deltaRows * mRenderer.mFontLineSpacing;
|
|
||||||
if (mIsDraggingLeftSelection) {
|
|
||||||
mSelX1 += deltaCols;
|
|
||||||
mSelY1 += deltaRows;
|
|
||||||
} else {
|
|
||||||
mSelX2 += deltaCols;
|
|
||||||
mSelY2 += deltaRows;
|
|
||||||
}
|
|
||||||
|
|
||||||
mSelX1 = Math.min(mEmulator.mColumns, Math.max(0, mSelX1));
|
|
||||||
mSelX2 = Math.min(mEmulator.mColumns, Math.max(0, mSelX2));
|
|
||||||
|
|
||||||
if (mSelY1 == mSelY2 && mSelX1 > mSelX2 || mSelY1 > mSelY2) {
|
|
||||||
// Switch handles.
|
|
||||||
mIsDraggingLeftSelection = !mIsDraggingLeftSelection;
|
|
||||||
int tmpX1 = mSelX1, tmpY1 = mSelY1;
|
|
||||||
mSelX1 = mSelX2;
|
|
||||||
mSelY1 = mSelY2;
|
|
||||||
mSelX2 = tmpX1;
|
|
||||||
mSelY2 = tmpY1;
|
|
||||||
}
|
|
||||||
|
|
||||||
mActionMode.invalidateContentRect();
|
|
||||||
invalidate();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
mGestureRecognizer.onTouchEvent(ev);
|
mGestureRecognizer.onTouchEvent(ev);
|
||||||
return true;
|
return true;
|
||||||
} else if (ev.isFromSource(InputDevice.SOURCE_MOUSE)) {
|
} else if (ev.isFromSource(InputDevice.SOURCE_MOUSE)) {
|
||||||
@@ -561,7 +525,7 @@ public final class TerminalView extends View {
|
|||||||
Log.i(EmulatorDebug.LOG_TAG, "onKeyPreIme(keyCode=" + keyCode + ", event=" + event + ")");
|
Log.i(EmulatorDebug.LOG_TAG, "onKeyPreIme(keyCode=" + keyCode + ", event=" + event + ")");
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
if (mIsSelectingText) {
|
if (mIsSelectingText) {
|
||||||
toggleSelectingText(null);
|
stopTextSelectionMode();
|
||||||
return true;
|
return true;
|
||||||
} else if (mClient.shouldBackButtonBeMappedToEscape()) {
|
} else if (mClient.shouldBackButtonBeMappedToEscape()) {
|
||||||
// Intercept back button to treat it as escape:
|
// Intercept back button to treat it as escape:
|
||||||
@@ -581,6 +545,7 @@ public final class TerminalView extends View {
|
|||||||
if (LOG_KEY_EVENTS)
|
if (LOG_KEY_EVENTS)
|
||||||
Log.i(EmulatorDebug.LOG_TAG, "onKeyDown(keyCode=" + keyCode + ", isSystem()=" + event.isSystem() + ", event=" + event + ")");
|
Log.i(EmulatorDebug.LOG_TAG, "onKeyDown(keyCode=" + keyCode + ", isSystem()=" + event.isSystem() + ", event=" + event + ")");
|
||||||
if (mEmulator == null) return true;
|
if (mEmulator == null) return true;
|
||||||
|
stopTextSelectionMode();
|
||||||
|
|
||||||
if (mClient.onKeyDown(keyCode, event, mTermSession)) {
|
if (mClient.onKeyDown(keyCode, event, mTermSession)) {
|
||||||
invalidate();
|
invalidate();
|
||||||
@@ -770,35 +735,17 @@ public final class TerminalView extends View {
|
|||||||
} else {
|
} else {
|
||||||
mRenderer.render(mEmulator, canvas, mTopRow, mSelY1, mSelY2, mSelX1, mSelX2);
|
mRenderer.render(mEmulator, canvas, mTopRow, mSelY1, mSelY2, mSelX1, mSelX2);
|
||||||
|
|
||||||
if (mIsSelectingText) {
|
|
||||||
final int gripHandleWidth = mLeftSelectionHandle.getIntrinsicWidth();
|
|
||||||
final int gripHandleMargin = gripHandleWidth / 4; // See the png.
|
|
||||||
|
|
||||||
int right = Math.round((mSelX1) * mRenderer.mFontWidth) + gripHandleMargin;
|
SelectionModifierCursorController selectionController = getSelectionController();
|
||||||
int top = (mSelY1 + 1 - mTopRow) * mRenderer.mFontLineSpacing + mRenderer.mFontLineSpacingAndAscent;
|
if (selectionController != null && selectionController.isActive()) {
|
||||||
mLeftSelectionHandle.setBounds(right - gripHandleWidth, top, right, top + mLeftSelectionHandle.getIntrinsicHeight());
|
selectionController.updatePosition();
|
||||||
mLeftSelectionHandle.draw(canvas);
|
|
||||||
|
|
||||||
int left = Math.round((mSelX2 + 1) * mRenderer.mFontWidth) - gripHandleMargin;
|
|
||||||
top = (mSelY2 + 1 - mTopRow) * mRenderer.mFontLineSpacing + mRenderer.mFontLineSpacingAndAscent;
|
|
||||||
mRightSelectionHandle.setBounds(left, top, left + gripHandleWidth, top + mRightSelectionHandle.getIntrinsicHeight());
|
|
||||||
mRightSelectionHandle.draw(canvas);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Toggle text selection mode in the view. */
|
/** Toggle text selection mode in the view. */
|
||||||
@TargetApi(23)
|
@TargetApi(23)
|
||||||
public void toggleSelectingText(MotionEvent ev) {
|
public void startSelectingText(MotionEvent ev) {
|
||||||
mIsSelectingText = !mIsSelectingText;
|
|
||||||
mClient.copyModeChanged(mIsSelectingText);
|
|
||||||
|
|
||||||
if (mIsSelectingText) {
|
|
||||||
if (mLeftSelectionHandle == null) {
|
|
||||||
mLeftSelectionHandle = (BitmapDrawable) getContext().getDrawable(R.drawable.text_select_handle_left_material);
|
|
||||||
mRightSelectionHandle = (BitmapDrawable) getContext().getDrawable(R.drawable.text_select_handle_right_material);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cx = (int) (ev.getX() / mRenderer.mFontWidth);
|
int cx = (int) (ev.getX() / mRenderer.mFontWidth);
|
||||||
final boolean eventFromMouse = ev.isFromSource(InputDevice.SOURCE_MOUSE);
|
final boolean eventFromMouse = ev.isFromSource(InputDevice.SOURCE_MOUSE);
|
||||||
// Offset for finger:
|
// Offset for finger:
|
||||||
@@ -818,11 +765,406 @@ public final class TerminalView extends View {
|
|||||||
mSelX2++;
|
mSelX2++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
startTextSelectionMode();
|
||||||
|
}
|
||||||
|
|
||||||
mInitialTextSelection = true;
|
public TerminalSession getCurrentSession() {
|
||||||
mIsDraggingLeftSelection = true;
|
return mTermSession;
|
||||||
mSelectionDownX = ev.getX();
|
}
|
||||||
mSelectionDownY = ev.getY();
|
|
||||||
|
private CharSequence getText() {
|
||||||
|
return mEmulator.getScreen().getSelectedText(0, mTopRow, mEmulator.mColumns, mTopRow + mEmulator.mRows);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow();
|
||||||
|
|
||||||
|
if (mSelectionModifierCursorController != null) {
|
||||||
|
getViewTreeObserver().addOnTouchModeChangeListener(mSelectionModifierCursorController);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDetachedFromWindow() {
|
||||||
|
super.onDetachedFromWindow();
|
||||||
|
|
||||||
|
if (mSelectionModifierCursorController != null) {
|
||||||
|
getViewTreeObserver().removeOnTouchModeChangeListener(mSelectionModifierCursorController);
|
||||||
|
mSelectionModifierCursorController.onDetached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int getCursorX(float x) {
|
||||||
|
return (int) (x / mRenderer.mFontWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getCursorY(float y) {
|
||||||
|
return (int) (((y - 40) / mRenderer.mFontLineSpacing) + mTopRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getPointX(int cx) {
|
||||||
|
if (cx > mEmulator.mColumns) {
|
||||||
|
cx = mEmulator.mColumns;
|
||||||
|
}
|
||||||
|
return Math.round(cx * mRenderer.mFontWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getPointY(int cy) {
|
||||||
|
return Math.round((cy - mTopRow) * mRenderer.mFontLineSpacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A CursorController instance can be used to control a cursor in the text.
|
||||||
|
* It is not used outside of {@link TerminalView}.
|
||||||
|
*/
|
||||||
|
private interface CursorController extends ViewTreeObserver.OnTouchModeChangeListener {
|
||||||
|
/**
|
||||||
|
* Makes the cursor controller visible on screen. Will be drawn by {@link #draw(Canvas)}.
|
||||||
|
* See also {@link #hide()}.
|
||||||
|
*/
|
||||||
|
void show();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the cursor controller from screen.
|
||||||
|
* See also {@link #show()}.
|
||||||
|
*/
|
||||||
|
void hide();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the CursorController is currently visible
|
||||||
|
*/
|
||||||
|
boolean isActive();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the controller's position.
|
||||||
|
*/
|
||||||
|
void updatePosition(HandleView handle, int x, int y);
|
||||||
|
|
||||||
|
void updatePosition();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller
|
||||||
|
* a chance to become active and/or visible.
|
||||||
|
*
|
||||||
|
* @param event The touch event
|
||||||
|
*/
|
||||||
|
boolean onTouchEvent(MotionEvent event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the view is detached from window. Perform house keeping task, such as
|
||||||
|
* stopping Runnable thread that would otherwise keep a reference on the context, thus
|
||||||
|
* preventing the activity to be recycled.
|
||||||
|
*/
|
||||||
|
void onDetached();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class HandleView extends View {
|
||||||
|
private Drawable mDrawable;
|
||||||
|
private PopupWindow mContainer;
|
||||||
|
private int mPointX;
|
||||||
|
private int mPointY;
|
||||||
|
private CursorController mController;
|
||||||
|
private boolean mIsDragging;
|
||||||
|
private float mTouchToWindowOffsetX;
|
||||||
|
private float mTouchToWindowOffsetY;
|
||||||
|
private float mHotspotX;
|
||||||
|
private float mHotspotY;
|
||||||
|
private float mTouchOffsetY;
|
||||||
|
private int mLastParentX;
|
||||||
|
private int mLastParentY;
|
||||||
|
|
||||||
|
int mHandleWidth;
|
||||||
|
private final int mOrigOrient;
|
||||||
|
private int mOrientation;
|
||||||
|
|
||||||
|
|
||||||
|
public static final int LEFT = 0;
|
||||||
|
public static final int RIGHT = 2;
|
||||||
|
private int mHandleHeight;
|
||||||
|
|
||||||
|
private long mLastTime;
|
||||||
|
|
||||||
|
public HandleView(CursorController controller, int orientation) {
|
||||||
|
super(TerminalView.this.getContext());
|
||||||
|
mController = controller;
|
||||||
|
mContainer = new PopupWindow(TerminalView.this.getContext(), null,
|
||||||
|
android.R.attr.textSelectHandleWindowStyle);
|
||||||
|
mContainer.setSplitTouchEnabled(true);
|
||||||
|
mContainer.setClippingEnabled(false);
|
||||||
|
mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
|
||||||
|
mContainer.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
|
||||||
|
this.mOrigOrient = orientation;
|
||||||
|
setOrientation(orientation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrientation(int orientation) {
|
||||||
|
mOrientation = orientation;
|
||||||
|
int handleWidth = 0;
|
||||||
|
switch (orientation) {
|
||||||
|
case LEFT: {
|
||||||
|
if (mSelectHandleLeft == null) {
|
||||||
|
|
||||||
|
mSelectHandleLeft = getContext().getDrawable(
|
||||||
|
R.drawable.text_select_handle_left_material);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
mDrawable = mSelectHandleLeft;
|
||||||
|
handleWidth = mDrawable.getIntrinsicWidth();
|
||||||
|
mHotspotX = (handleWidth * 3) / 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RIGHT: {
|
||||||
|
if (mSelectHandleRight == null) {
|
||||||
|
mSelectHandleRight = getContext().getDrawable(
|
||||||
|
R.drawable.text_select_handle_right_material);
|
||||||
|
}
|
||||||
|
mDrawable = mSelectHandleRight;
|
||||||
|
handleWidth = mDrawable.getIntrinsicWidth();
|
||||||
|
mHotspotX = handleWidth / 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mHandleHeight = mDrawable.getIntrinsicHeight();
|
||||||
|
|
||||||
|
mHandleWidth = handleWidth;
|
||||||
|
mTouchOffsetY = -mHandleHeight * 0.3f;
|
||||||
|
mHotspotY = 0;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeOrientation(int orientation) {
|
||||||
|
if (mOrientation != orientation) {
|
||||||
|
setOrientation(orientation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
setMeasuredDimension(mDrawable.getIntrinsicWidth(),
|
||||||
|
mDrawable.getIntrinsicHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show() {
|
||||||
|
if (!isPositionVisible()) {
|
||||||
|
hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mContainer.setContentView(this);
|
||||||
|
final int[] coords = mTempCoords;
|
||||||
|
TerminalView.this.getLocationInWindow(coords);
|
||||||
|
coords[0] += mPointX;
|
||||||
|
coords[1] += mPointY;
|
||||||
|
mContainer.showAtLocation(TerminalView.this, 0, coords[0], coords[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hide() {
|
||||||
|
mIsDragging = false;
|
||||||
|
mContainer.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShowing() {
|
||||||
|
return mContainer.isShowing();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkChangedOrientation() {
|
||||||
|
if (!mIsDragging) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long millis = SystemClock.currentThreadTimeMillis();
|
||||||
|
if (millis - mLastTime < 50) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mLastTime = millis;
|
||||||
|
|
||||||
|
final TerminalView hostView = TerminalView.this;
|
||||||
|
final int left = hostView.getLeft();
|
||||||
|
final int right = hostView.getWidth();
|
||||||
|
final int top = hostView.getTop();
|
||||||
|
final int bottom = hostView.getHeight();
|
||||||
|
|
||||||
|
if (mTempRect == null) {
|
||||||
|
mTempRect = new Rect();
|
||||||
|
}
|
||||||
|
final Rect clip = mTempRect;
|
||||||
|
clip.left = left + TerminalView.this.getPaddingLeft();
|
||||||
|
clip.top = top + TerminalView.this.getPaddingTop();
|
||||||
|
clip.right = right - TerminalView.this.getPaddingRight();
|
||||||
|
clip.bottom = bottom - TerminalView.this.getPaddingBottom();
|
||||||
|
|
||||||
|
final ViewParent parent = hostView.getParent();
|
||||||
|
if (parent == null || !parent.getChildVisibleRect(hostView, clip, null)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int[] coords = mTempCoords;
|
||||||
|
hostView.getLocationInWindow(coords);
|
||||||
|
final int posX = coords[0] + mPointX;
|
||||||
|
if (posX < clip.left) {
|
||||||
|
changeOrientation(RIGHT);
|
||||||
|
} else if (posX + mHandleWidth > clip.right) {
|
||||||
|
changeOrientation(LEFT);
|
||||||
|
} else {
|
||||||
|
changeOrientation(mOrigOrient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPositionVisible() {
|
||||||
|
// Always show a dragging handle.
|
||||||
|
if (mIsDragging) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final TerminalView hostView = TerminalView.this;
|
||||||
|
final int left = 0;
|
||||||
|
final int right = hostView.getWidth();
|
||||||
|
final int top = 0;
|
||||||
|
final int bottom = hostView.getHeight();
|
||||||
|
|
||||||
|
if (mTempRect == null) {
|
||||||
|
mTempRect = new Rect();
|
||||||
|
}
|
||||||
|
final Rect clip = mTempRect;
|
||||||
|
clip.left = left + TerminalView.this.getPaddingLeft();
|
||||||
|
clip.top = top + TerminalView.this.getPaddingTop();
|
||||||
|
clip.right = right - TerminalView.this.getPaddingRight();
|
||||||
|
clip.bottom = bottom - TerminalView.this.getPaddingBottom();
|
||||||
|
|
||||||
|
final ViewParent parent = hostView.getParent();
|
||||||
|
if (parent == null || !parent.getChildVisibleRect(hostView, clip, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int[] coords = mTempCoords;
|
||||||
|
hostView.getLocationInWindow(coords);
|
||||||
|
final int posX = coords[0] + mPointX + (int) mHotspotX;
|
||||||
|
final int posY = coords[1] + mPointY + (int) mHotspotY;
|
||||||
|
|
||||||
|
return posX >= clip.left && posX <= clip.right &&
|
||||||
|
posY >= clip.top && posY <= clip.bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void moveTo(int x, int y) {
|
||||||
|
mPointX = x;
|
||||||
|
mPointY = y;
|
||||||
|
checkChangedOrientation();
|
||||||
|
if (isPositionVisible()) {
|
||||||
|
int[] coords = null;
|
||||||
|
if (mContainer.isShowing()) {
|
||||||
|
coords = mTempCoords;
|
||||||
|
TerminalView.this.getLocationInWindow(coords);
|
||||||
|
int x1 = coords[0] + mPointX;
|
||||||
|
int y1 = coords[1] + mPointY;
|
||||||
|
mContainer.update(x1, y1,
|
||||||
|
getWidth(), getHeight());
|
||||||
|
} else {
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mIsDragging) {
|
||||||
|
if (coords == null) {
|
||||||
|
coords = mTempCoords;
|
||||||
|
TerminalView.this.getLocationInWindow(coords);
|
||||||
|
}
|
||||||
|
if (coords[0] != mLastParentX || coords[1] != mLastParentY) {
|
||||||
|
mTouchToWindowOffsetX += coords[0] - mLastParentX;
|
||||||
|
mTouchToWindowOffsetY += coords[1] - mLastParentY;
|
||||||
|
mLastParentX = coords[0];
|
||||||
|
mLastParentY = coords[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isShowing()) {
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(Canvas c) {
|
||||||
|
final int drawWidth = mDrawable.getIntrinsicWidth();
|
||||||
|
int height = mDrawable.getIntrinsicHeight();
|
||||||
|
mDrawable.setBounds(0, 0, drawWidth, height);
|
||||||
|
mDrawable.draw(c);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent ev) {
|
||||||
|
updateFloatingToolbarVisibility(ev);
|
||||||
|
switch (ev.getActionMasked()) {
|
||||||
|
case MotionEvent.ACTION_DOWN: {
|
||||||
|
final float rawX = ev.getRawX();
|
||||||
|
final float rawY = ev.getRawY();
|
||||||
|
mTouchToWindowOffsetX = rawX - mPointX;
|
||||||
|
mTouchToWindowOffsetY = rawY - mPointY;
|
||||||
|
final int[] coords = mTempCoords;
|
||||||
|
TerminalView.this.getLocationInWindow(coords);
|
||||||
|
mLastParentX = coords[0];
|
||||||
|
mLastParentY = coords[1];
|
||||||
|
mIsDragging = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_MOVE: {
|
||||||
|
final float rawX = ev.getRawX();
|
||||||
|
final float rawY = ev.getRawY();
|
||||||
|
|
||||||
|
final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
|
||||||
|
final float newPosY = rawY - mTouchToWindowOffsetY + mHotspotY + mTouchOffsetY;
|
||||||
|
|
||||||
|
mController.updatePosition(this, Math.round(newPosX), Math.round(newPosY));
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
mIsDragging = false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isDragging() {
|
||||||
|
return mIsDragging;
|
||||||
|
}
|
||||||
|
|
||||||
|
void positionAtCursor(final int cx, final int cy) {
|
||||||
|
int left = (int) (getPointX(cx) - mHotspotX);
|
||||||
|
int bottom = getPointY(cy + 1);
|
||||||
|
moveTo(left, bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class SelectionModifierCursorController implements CursorController {
|
||||||
|
private final int mHandleHeight;
|
||||||
|
// The cursor controller images
|
||||||
|
private HandleView mStartHandle, mEndHandle;
|
||||||
|
// Whether selection anchors are active
|
||||||
|
private boolean mIsShowing;
|
||||||
|
|
||||||
|
SelectionModifierCursorController() {
|
||||||
|
mStartHandle = new HandleView(this, HandleView.LEFT);
|
||||||
|
mEndHandle = new HandleView(this, HandleView.RIGHT);
|
||||||
|
|
||||||
|
mHandleHeight = Math.max(mStartHandle.mHandleHeight, mEndHandle.mHandleHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show() {
|
||||||
|
mIsShowing = true;
|
||||||
|
updatePosition();
|
||||||
|
mStartHandle.show();
|
||||||
|
mEndHandle.show();
|
||||||
|
|
||||||
final ActionMode.Callback callback = new ActionMode.Callback() {
|
final ActionMode.Callback callback = new ActionMode.Callback() {
|
||||||
@Override
|
@Override
|
||||||
@@ -864,7 +1206,7 @@ public final class TerminalView extends View {
|
|||||||
showContextMenu();
|
showContextMenu();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
toggleSelectingText(null);
|
stopTextSelectionMode();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -873,7 +1215,6 @@ public final class TerminalView extends View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mActionMode = startActionMode(new ActionMode.Callback2() {
|
mActionMode = startActionMode(new ActionMode.Callback2() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||||
@@ -901,24 +1242,277 @@ public final class TerminalView extends View {
|
|||||||
int x2 = Math.round(mSelX2 * mRenderer.mFontWidth);
|
int x2 = Math.round(mSelX2 * mRenderer.mFontWidth);
|
||||||
int y1 = Math.round((mSelY1 - mTopRow) * mRenderer.mFontLineSpacing);
|
int y1 = Math.round((mSelY1 - mTopRow) * mRenderer.mFontLineSpacing);
|
||||||
int y2 = Math.round((mSelY2 + 1 - mTopRow) * mRenderer.mFontLineSpacing);
|
int y2 = Math.round((mSelY2 + 1 - mTopRow) * mRenderer.mFontLineSpacing);
|
||||||
outRect.set(Math.min(x1, x2), y1, Math.max(x1, x2), y2);
|
|
||||||
|
|
||||||
|
if (x1 > x2) {
|
||||||
|
int tmp = x1;
|
||||||
|
x1 = x2;
|
||||||
|
x2 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
outRect.set(x1, y1 + mHandleHeight, x2, y2 + mHandleHeight);
|
||||||
}
|
}
|
||||||
}, ActionMode.TYPE_FLOATING);
|
}, ActionMode.TYPE_FLOATING);
|
||||||
|
|
||||||
invalidate();
|
}
|
||||||
} else {
|
|
||||||
|
public void hide() {
|
||||||
|
mStartHandle.hide();
|
||||||
|
mEndHandle.hide();
|
||||||
|
mIsShowing = false;
|
||||||
|
if (mActionMode != null) {
|
||||||
|
// This will hide the mSelectionModifierCursorController
|
||||||
mActionMode.finish();
|
mActionMode.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return mIsShowing;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void updatePosition(HandleView handle, int x, int y) {
|
||||||
|
|
||||||
|
TerminalBuffer screen = mEmulator.getScreen();
|
||||||
|
final int scrollRows = screen.getActiveRows() - mEmulator.mRows;
|
||||||
|
if (handle == mStartHandle) {
|
||||||
|
mSelX1 = getCursorX(x);
|
||||||
|
mSelY1 = getCursorY(y);
|
||||||
|
if (mSelX1 < 0) {
|
||||||
|
mSelX1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSelY1 < -scrollRows) {
|
||||||
|
mSelY1 = -scrollRows;
|
||||||
|
|
||||||
|
} else if (mSelY1 > mEmulator.mRows - 1) {
|
||||||
|
mSelY1 = mEmulator.mRows - 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (mSelY1 > mSelY2) {
|
||||||
|
mSelY1 = mSelY2;
|
||||||
|
}
|
||||||
|
if (mSelY1 == mSelY2 && mSelX1 > mSelX2) {
|
||||||
|
mSelX1 = mSelX2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mEmulator.isAlternateBufferActive()) {
|
||||||
|
if (mSelY1 <= mTopRow) {
|
||||||
|
mTopRow--;
|
||||||
|
if (mTopRow < -scrollRows) {
|
||||||
|
mTopRow = -scrollRows;
|
||||||
|
}
|
||||||
|
} else if (mSelY1 >= mTopRow + mEmulator.mRows) {
|
||||||
|
mTopRow++;
|
||||||
|
if (mTopRow > 0) {
|
||||||
|
mTopRow = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mSelX1 = getValidCurX(screen, mSelY1, mSelX1);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
mSelX2 = getCursorX(x);
|
||||||
|
mSelY2 = getCursorY(y);
|
||||||
|
if (mSelX2 < 0) {
|
||||||
|
mSelX2 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (mSelY2 < -scrollRows) {
|
||||||
|
mSelY2 = -scrollRows;
|
||||||
|
} else if (mSelY2 > mEmulator.mRows - 1) {
|
||||||
|
mSelY2 = mEmulator.mRows - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSelY1 > mSelY2) {
|
||||||
|
mSelY2 = mSelY1;
|
||||||
|
}
|
||||||
|
if (mSelY1 == mSelY2 && mSelX1 > mSelX2) {
|
||||||
|
mSelX2 = mSelX1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mEmulator.isAlternateBufferActive()) {
|
||||||
|
if (mSelY2 <= mTopRow) {
|
||||||
|
mTopRow--;
|
||||||
|
if (mTopRow < -scrollRows) {
|
||||||
|
mTopRow = -scrollRows;
|
||||||
|
}
|
||||||
|
} else if (mSelY2 >= mTopRow + mEmulator.mRows) {
|
||||||
|
mTopRow++;
|
||||||
|
if (mTopRow > 0) {
|
||||||
|
mTopRow = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mSelX2 = getValidCurX(screen, mSelY2, mSelX2);
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int getValidCurX(TerminalBuffer screen, int cy, int cx) {
|
||||||
|
String line = screen.getSelectedText(0, cy, cx, cy);
|
||||||
|
if (!TextUtils.isEmpty(line)) {
|
||||||
|
int col = 0;
|
||||||
|
for (int i = 0, len = line.length(); i < len; i++) {
|
||||||
|
char ch1 = line.charAt(i);
|
||||||
|
if (ch1 == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wc;
|
||||||
|
if (Character.isHighSurrogate(ch1) && i + 1 < len) {
|
||||||
|
char ch2 = line.charAt(++i);
|
||||||
|
wc = WcWidth.width(Character.toCodePoint(ch1, ch2));
|
||||||
|
} else {
|
||||||
|
wc = WcWidth.width(ch1);
|
||||||
|
}
|
||||||
|
|
||||||
|
final int cend = col + wc;
|
||||||
|
if (cx > col && cx < cend) {
|
||||||
|
return cend;
|
||||||
|
}
|
||||||
|
if (cend == col) {
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
col = cend;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updatePosition() {
|
||||||
|
if (!isActive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mStartHandle.positionAtCursor(mSelX1, mSelY1);
|
||||||
|
|
||||||
|
mEndHandle.positionAtCursor(mSelX2 + 1, mSelY2); //bug
|
||||||
|
|
||||||
|
if (mActionMode != null) {
|
||||||
|
mActionMode.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true iff this controller is currently used to move the selection start.
|
||||||
|
*/
|
||||||
|
public boolean isSelectionStartDragged() {
|
||||||
|
return mStartHandle.isDragging();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSelectionEndDragged() {
|
||||||
|
return mEndHandle.isDragging();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onTouchModeChanged(boolean isInTouchMode) {
|
||||||
|
if (!isInTouchMode) {
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDetached() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectionModifierCursorController getSelectionController() {
|
||||||
|
if (mSelectionModifierCursorController == null) {
|
||||||
|
mSelectionModifierCursorController = new SelectionModifierCursorController();
|
||||||
|
|
||||||
|
final ViewTreeObserver observer = getViewTreeObserver();
|
||||||
|
if (observer != null) {
|
||||||
|
observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mSelectionModifierCursorController;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideSelectionModifierCursorController() {
|
||||||
|
if (mSelectionModifierCursorController != null && mSelectionModifierCursorController.isActive()) {
|
||||||
|
mSelectionModifierCursorController.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void startTextSelectionMode() {
|
||||||
|
if (!requestFocus()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSelectionController().show();
|
||||||
|
|
||||||
|
mIsSelectingText = true;
|
||||||
|
|
||||||
|
mClient.copyModeChanged(mIsSelectingText);
|
||||||
|
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopTextSelectionMode() {
|
||||||
|
if (mIsSelectingText) {
|
||||||
|
hideSelectionModifierCursorController();
|
||||||
mSelX1 = mSelY1 = mSelX2 = mSelY2 = -1;
|
mSelX1 = mSelY1 = mSelX2 = mSelY2 = -1;
|
||||||
|
mIsSelectingText = false;
|
||||||
|
|
||||||
|
mClient.copyModeChanged(mIsSelectingText);
|
||||||
|
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TerminalSession getCurrentSession() {
|
|
||||||
return mTermSession;
|
private final Runnable mShowFloatingToolbar = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (mActionMode != null) {
|
||||||
|
mActionMode.hide(0); // hide off.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void hideFloatingToolbar(int duration) {
|
||||||
|
if (mActionMode != null) {
|
||||||
|
removeCallbacks(mShowFloatingToolbar);
|
||||||
|
mActionMode.hide(duration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private CharSequence getText() {
|
private void showFloatingToolbar() {
|
||||||
return mEmulator.getScreen().getSelectedText(0, mTopRow, mEmulator.mColumns, mTopRow +mEmulator.mRows);
|
if (mActionMode != null) {
|
||||||
|
int delay = ViewConfiguration.getDoubleTapTimeout();
|
||||||
|
postDelayed(mShowFloatingToolbar, delay);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateFloatingToolbarVisibility(MotionEvent event) {
|
||||||
|
if (mActionMode != null) {
|
||||||
|
switch (event.getActionMasked()) {
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
hideFloatingToolbar(-1);
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_UP: // fall through
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
showFloatingToolbar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user