10th attempt to fix the privileged options problem: InputConnection is no longer cached within the app
This commit is contained in:
parent
9c63e66a1d
commit
903e756dc0
10 changed files with 104 additions and 56 deletions
|
|
@ -1,8 +1,10 @@
|
|||
package io.github.sspanak.tt9.hacks;
|
||||
|
||||
import android.content.Context;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import io.github.sspanak.tt9.ime.helpers.StandardInputType;
|
||||
import io.github.sspanak.tt9.util.sys.DeviceInfo;
|
||||
|
|
@ -10,9 +12,9 @@ import io.github.sspanak.tt9.util.sys.DeviceInfo;
|
|||
public class InputType extends StandardInputType {
|
||||
private final boolean isUs;
|
||||
|
||||
public InputType(Context context, InputConnection inputConnection, EditorInfo inputField) {
|
||||
super(inputConnection, inputField);
|
||||
isUs = isAppField(context != null ? context.getPackageName() : "", EditorInfo.TYPE_NULL);
|
||||
public InputType(@Nullable InputMethodService ims, EditorInfo inputField) {
|
||||
super(ims, inputField);
|
||||
isUs = isAppField(ims != null ? ims.getPackageName() : null, EditorInfo.TYPE_NULL);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package io.github.sspanak.tt9.ime;
|
|||
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
import io.github.sspanak.tt9.ime.helpers.SuggestionOps;
|
||||
import io.github.sspanak.tt9.ime.modes.InputMode;
|
||||
|
|
@ -19,10 +18,10 @@ abstract public class AbstractHandler extends InputMethodService {
|
|||
|
||||
// lifecycle
|
||||
abstract protected void onInit();
|
||||
abstract protected boolean onStart(InputConnection inputConnection, EditorInfo inputField);
|
||||
abstract protected boolean onStart(EditorInfo inputField);
|
||||
abstract protected void onFinishTyping();
|
||||
abstract protected void onStop();
|
||||
abstract protected void setInputField(InputConnection inputConnection, EditorInfo inputField);
|
||||
abstract protected void setInputField(EditorInfo inputField);
|
||||
|
||||
// UI
|
||||
abstract protected void createSuggestionBar();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package io.github.sspanak.tt9.ime;
|
||||
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
|
@ -37,10 +36,10 @@ abstract public class MainViewHandler extends HotkeyHandler {
|
|||
|
||||
|
||||
@Override
|
||||
protected boolean onStart(InputConnection connection, EditorInfo field) {
|
||||
protected boolean onStart(EditorInfo field) {
|
||||
resetNormalizedDimensions();
|
||||
dragResize = settings.getDragResize();
|
||||
return super.onStart(connection, field);
|
||||
return super.onStart(field);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import android.os.Handler;
|
|||
import android.os.Looper;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
|
|
@ -39,7 +38,7 @@ public class TraditionalT9 extends MainViewHandler {
|
|||
return false;
|
||||
}
|
||||
|
||||
setInputField(getCurrentInputConnection(), getCurrentInputEditorInfo());
|
||||
setInputField(getCurrentInputEditorInfo());
|
||||
return shouldBeVisible();
|
||||
}
|
||||
|
||||
|
|
@ -80,13 +79,13 @@ public class TraditionalT9 extends MainViewHandler {
|
|||
LOG_TAG,
|
||||
"===> Start Up; packageName: " + inputField.packageName + " inputType: " + inputField.inputType + " actionId: " + inputField.actionId + " imeOptions: " + inputField.imeOptions + " privateImeOptions: " + inputField.privateImeOptions + " extras: " + inputField.extras
|
||||
);
|
||||
onStart(getCurrentInputConnection(), inputField);
|
||||
onStart(inputField);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onStartInputView(EditorInfo inputField, boolean restarting) {
|
||||
onStart(getCurrentInputConnection(), inputField);
|
||||
onStart(inputField);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -130,13 +129,13 @@ public class TraditionalT9 extends MainViewHandler {
|
|||
|
||||
|
||||
@Override
|
||||
protected boolean onStart(InputConnection connection, EditorInfo field) {
|
||||
protected boolean onStart(EditorInfo field) {
|
||||
if (zombieChecks == 0 && !SystemSettings.isTT9Selected(this)) {
|
||||
startZombieCheck();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isDead || !super.onStart(connection, field)) {
|
||||
if (isDead || !super.onStart(field)) {
|
||||
setStatusIcon(mInputMode, mLanguage);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -151,7 +150,7 @@ public class TraditionalT9 extends MainViewHandler {
|
|||
initUi(mInputMode);
|
||||
}
|
||||
|
||||
InputType newInputType = new InputType(getApplicationContext(), connection, field);
|
||||
InputType newInputType = new InputType(this, field);
|
||||
|
||||
if (newInputType.isText()) {
|
||||
DataStore.loadWordPairs(DictionaryLoader.getInstance(this), LanguageCollection.getAll(settings.getEnabledLanguageIds()));
|
||||
|
|
@ -241,7 +240,7 @@ public class TraditionalT9 extends MainViewHandler {
|
|||
|
||||
protected void cleanUp() {
|
||||
super.cleanUp();
|
||||
setInputField(null, null);
|
||||
setInputField(null);
|
||||
backgroundTasks.removeCallbacksAndMessages(null);
|
||||
zombieChecks = SettingsStore.ZOMBIE_CHECK_MAX;
|
||||
zombieDetector.removeCallbacksAndMessages(null);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package io.github.sspanak.tt9.ime;
|
||||
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
|
@ -29,10 +29,10 @@ import io.github.sspanak.tt9.util.Text;
|
|||
public abstract class TypingHandler extends KeyPadHandler {
|
||||
// internal settings/data
|
||||
@NonNull protected AppHacks appHacks = new AppHacks(null, null, null);
|
||||
@NonNull protected InputType inputType = new InputType(null, null, null);
|
||||
@NonNull protected InputType inputType = new InputType(null, null);
|
||||
@NonNull protected TextField textField = new TextField(null, null, null);
|
||||
@NonNull protected TextSelection textSelection = new TextSelection(this,null);
|
||||
@NonNull protected SuggestionOps suggestionOps = new SuggestionOps(null, null, null, null, null);
|
||||
@NonNull protected TextSelection textSelection = new TextSelection(null);
|
||||
@NonNull protected SuggestionOps suggestionOps = new SuggestionOps(null, null, null, null, null, null);
|
||||
|
||||
// input
|
||||
@NonNull protected ArrayList<Integer> allowedInputModes = new ArrayList<>();
|
||||
|
|
@ -44,7 +44,7 @@ public abstract class TypingHandler extends KeyPadHandler {
|
|||
|
||||
|
||||
protected void createSuggestionBar() {
|
||||
suggestionOps = new SuggestionOps(settings, mainView, textField, this::onAcceptSuggestionsDelayed, this::onOK);
|
||||
suggestionOps = new SuggestionOps(this, settings, mainView, textField, this::onAcceptSuggestionsDelayed, this::onOK);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -53,10 +53,10 @@ public abstract class TypingHandler extends KeyPadHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean onStart(InputConnection connection, EditorInfo field) {
|
||||
boolean restart = textField.equals(connection, field);
|
||||
protected boolean onStart(EditorInfo field) {
|
||||
boolean restart = textField.equals(getCurrentInputConnection(), field);
|
||||
|
||||
setInputField(connection, field);
|
||||
setInputField(field);
|
||||
|
||||
// 1. In case we are back from Settings screen, update the language list
|
||||
// 2. If the connected app hints it is in a language different than the current one,
|
||||
|
|
@ -79,14 +79,15 @@ public abstract class TypingHandler extends KeyPadHandler {
|
|||
}
|
||||
|
||||
|
||||
protected void setInputField(InputConnection connection, EditorInfo field) {
|
||||
if (textField.equals(connection, field)) {
|
||||
protected void setInputField(EditorInfo field) {
|
||||
if (textField.equals(getCurrentInputConnection(), field)) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputType = new InputType(getApplicationContext(), connection, field);
|
||||
textField = new TextField(settings, connection, field);
|
||||
textSelection = new TextSelection(this, connection);
|
||||
InputMethodService context = field != null ? this : null;
|
||||
inputType = new InputType(context, field);
|
||||
textField = new TextField(context, settings, field);
|
||||
textSelection = new TextSelection(context);
|
||||
|
||||
// changing the TextField and notifying all interested classes is an atomic operation
|
||||
appHacks = new AppHacks(inputType, textField, textSelection);
|
||||
|
|
@ -105,7 +106,7 @@ public abstract class TypingHandler extends KeyPadHandler {
|
|||
protected void onFinishTyping() {
|
||||
suggestionOps.cancelDelayedAccept();
|
||||
mInputMode = InputMode.getInstance(null, null, null, null, InputMode.MODE_PASSTHROUGH);
|
||||
setInputField(null, null);
|
||||
setInputField(null);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package io.github.sspanak.tt9.ime.helpers;
|
||||
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
|
|
@ -14,19 +15,25 @@ import io.github.sspanak.tt9.util.sys.DeviceInfo;
|
|||
public class InputField {
|
||||
public static final int IME_ACTION_ENTER = EditorInfo.IME_MASK_ACTION + 1;
|
||||
|
||||
@Nullable protected final InputConnection connection;
|
||||
@Nullable protected final InputMethodService ims;
|
||||
@Nullable protected final EditorInfo field;
|
||||
|
||||
|
||||
protected InputField(@Nullable InputConnection inputConnection, @Nullable EditorInfo inputField) {
|
||||
connection = inputConnection;
|
||||
protected InputField(@Nullable InputMethodService ims, @Nullable EditorInfo inputField) {
|
||||
this.ims = ims;
|
||||
field = inputField;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
protected InputConnection getConnection() {
|
||||
return ims != null ? ims.getCurrentInputConnection() : null;
|
||||
}
|
||||
|
||||
|
||||
public boolean equals(InputConnection inputConnection, EditorInfo inputField) {
|
||||
return
|
||||
connection != null && connection == inputConnection
|
||||
inputConnection != null && inputConnection == getConnection()
|
||||
&& field != null && field == inputField;
|
||||
}
|
||||
|
||||
|
|
@ -73,6 +80,7 @@ public class InputField {
|
|||
* Note that it is up to the app to decide what to do or ignore the action ID.
|
||||
*/
|
||||
public boolean performAction(int actionId) {
|
||||
InputConnection connection = getConnection();
|
||||
return connection != null && actionId != EditorInfo.IME_ACTION_NONE && connection.performEditorAction(actionId);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
package io.github.sspanak.tt9.ime.helpers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.text.InputType;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
|
@ -16,18 +18,24 @@ import io.github.sspanak.tt9.ime.modes.InputMode;
|
|||
abstract public class StandardInputType {
|
||||
private static final int TYPE_MULTILINE_TEXT = EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
|
||||
|
||||
protected final InputConnection connection;
|
||||
@Nullable protected final InputMethodService ims;
|
||||
protected final EditorInfo field;
|
||||
|
||||
|
||||
protected StandardInputType(InputConnection inputConnection, EditorInfo inputField) {
|
||||
connection = inputConnection;
|
||||
protected StandardInputType(@Nullable InputMethodService ims, EditorInfo inputField) {
|
||||
this.ims = ims;
|
||||
field = inputField;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
protected InputConnection getConnection() {
|
||||
return ims != null ? ims.getCurrentInputConnection() : null;
|
||||
}
|
||||
|
||||
|
||||
public boolean isValid() {
|
||||
return field != null && connection != null;
|
||||
return field != null && getConnection() != null;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -193,7 +201,7 @@ abstract public class StandardInputType {
|
|||
* editor state.
|
||||
*/
|
||||
public int determineTextCase() {
|
||||
if (connection == null || field == null || field.inputType == InputType.TYPE_NULL) {
|
||||
if (getConnection() == null || field == null || field.inputType == InputType.TYPE_NULL) {
|
||||
return InputMode.CASE_UNDEFINED;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package io.github.sspanak.tt9.ime.helpers;
|
||||
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
|
|
@ -25,11 +26,11 @@ public class SuggestionOps {
|
|||
@NonNull private TextField textField;
|
||||
|
||||
|
||||
public SuggestionOps(@Nullable SettingsStore settings, @Nullable ResizableMainView mainView, @Nullable TextField textField, @Nullable ConsumerCompat<String> onDelayedAccept, @Nullable Runnable onSuggestionClick) {
|
||||
public SuggestionOps(@Nullable InputMethodService ims, @Nullable SettingsStore settings, @Nullable ResizableMainView mainView, @Nullable TextField textField, @Nullable ConsumerCompat<String> onDelayedAccept, @Nullable Runnable onSuggestionClick) {
|
||||
delayedAcceptHandler = new Handler(Looper.getMainLooper());
|
||||
this.onDelayedAccept = onDelayedAccept != null ? onDelayedAccept : s -> {};
|
||||
|
||||
this.textField = textField != null ? textField : new TextField(null, null, null);
|
||||
this.textField = textField != null ? textField : new TextField(ims, null, null);
|
||||
|
||||
if (settings != null && mainView != null && onSuggestionClick != null) {
|
||||
suggestionBar = new SuggestionsBar(settings, mainView, onSuggestionClick);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package io.github.sspanak.tt9.ime.helpers;
|
||||
|
||||
import android.graphics.Typeface;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.style.StyleSpan;
|
||||
|
|
@ -10,6 +11,7 @@ import android.view.inputmethod.EditorInfo;
|
|||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import io.github.sspanak.tt9.hacks.InputType;
|
||||
import io.github.sspanak.tt9.ime.modes.InputMode;
|
||||
|
|
@ -25,10 +27,10 @@ public class TextField extends InputField {
|
|||
private final boolean isNonText;
|
||||
|
||||
|
||||
public TextField(SettingsStore settings, InputConnection inputConnection, EditorInfo inputField) {
|
||||
super(inputConnection, inputField);
|
||||
public TextField(@Nullable InputMethodService ims, SettingsStore settings, EditorInfo inputField) {
|
||||
super(ims, inputField);
|
||||
|
||||
InputType inputType = new InputType(null, inputConnection, inputField);
|
||||
InputType inputType = new InputType(ims, inputField);
|
||||
isComposingSupported = !inputType.isNumeric() && !inputType.isLimited() && !inputType.isRustDesk() && (settings == null || settings.getAllowComposingText());
|
||||
isNonText = !inputType.isText();
|
||||
}
|
||||
|
|
@ -40,12 +42,14 @@ public class TextField extends InputField {
|
|||
|
||||
|
||||
@NonNull public String getStringAfterCursor(int numberOfChars) {
|
||||
InputConnection connection = getConnection();
|
||||
CharSequence chars = connection != null && numberOfChars > 0 ? connection.getTextAfterCursor(numberOfChars, 0) : null;
|
||||
return chars != null ? chars.toString() : "";
|
||||
}
|
||||
|
||||
|
||||
@NonNull public String getStringBeforeCursor(int numberOfChars) {
|
||||
InputConnection connection = getConnection();
|
||||
CharSequence chars = connection != null && numberOfChars > 0 ? connection.getTextBeforeCursor(numberOfChars, 0) : null;
|
||||
return chars != null ? chars.toString() : "";
|
||||
}
|
||||
|
|
@ -133,6 +137,7 @@ public class TextField extends InputField {
|
|||
* "deleteSurroundingText()" to delete a region of text or a Unicode character.
|
||||
*/
|
||||
public void deleteChars(int numberOfChars) {
|
||||
InputConnection connection = getConnection();
|
||||
if (numberOfChars <= 0 || connection == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -162,6 +167,7 @@ public class TextField extends InputField {
|
|||
* No action is taken when there is no such word.
|
||||
*/
|
||||
public void deletePrecedingSpace(String word) {
|
||||
InputConnection connection = getConnection();
|
||||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -187,6 +193,7 @@ public class TextField extends InputField {
|
|||
* there is no such word before the cursor.
|
||||
*/
|
||||
public void addPrecedingSpace(String word) {
|
||||
InputConnection connection = getConnection();
|
||||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -210,6 +217,7 @@ public class TextField extends InputField {
|
|||
* the given "text". Returns "true" if the operation was successful, "false" otherwise.
|
||||
*/
|
||||
public boolean recompose(String text) {
|
||||
InputConnection connection = getConnection();
|
||||
if (text == null || connection == null || !isComposingSupported) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -227,6 +235,7 @@ public class TextField extends InputField {
|
|||
* A fail-safe setter that appends text to the field, ignoring NULL input.
|
||||
*/
|
||||
public void setText(String text) {
|
||||
InputConnection connection = getConnection();
|
||||
if (text != null && connection != null) {
|
||||
connection.commitText(text, 1);
|
||||
}
|
||||
|
|
@ -245,6 +254,7 @@ public class TextField extends InputField {
|
|||
*/
|
||||
public void setComposingText(CharSequence text, int position) {
|
||||
composingText = text;
|
||||
InputConnection connection = getConnection();
|
||||
if (text != null && connection != null && isComposingSupported) {
|
||||
connection.setComposingText(text, position);
|
||||
}
|
||||
|
|
@ -275,6 +285,7 @@ public class TextField extends InputField {
|
|||
* Finish composing text or do nothing if the text field is invalid.
|
||||
*/
|
||||
public void finishComposingText() {
|
||||
InputConnection connection = getConnection();
|
||||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -332,7 +343,7 @@ public class TextField extends InputField {
|
|||
|
||||
public boolean moveCursor(boolean backward) {
|
||||
if (
|
||||
connection == null
|
||||
getConnection() == null
|
||||
|| (backward && getStringBeforeCursor(1).isEmpty())
|
||||
|| (!backward && getStringAfterCursor(1).isEmpty())
|
||||
) {
|
||||
|
|
@ -351,7 +362,8 @@ public class TextField extends InputField {
|
|||
|
||||
|
||||
public boolean sendDownUpKeyEvents(int keyCode, boolean shift, boolean ctrl) {
|
||||
if (connection != null) {
|
||||
InputConnection connection = getConnection();
|
||||
if (connection != null) {
|
||||
int metaState = shift ? KeyEvent.META_SHIFT_ON : 0;
|
||||
metaState |= ctrl ? KeyEvent.META_CTRL_ON : 0;
|
||||
KeyEvent downEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, keyCode, 0, metaState);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package io.github.sspanak.tt9.ime.helpers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.view.inputmethod.ExtractedText;
|
||||
import android.view.inputmethod.ExtractedTextRequest;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
|
@ -11,19 +11,22 @@ import androidx.annotation.Nullable;
|
|||
import io.github.sspanak.tt9.util.sys.Clipboard;
|
||||
|
||||
public class TextSelection {
|
||||
@Nullable private final InputConnection connection;
|
||||
private final Context context;
|
||||
@Nullable private final InputMethodService ims;
|
||||
private int currentStart = 0;
|
||||
private int currentEnd = 0;
|
||||
|
||||
|
||||
public TextSelection(Context context, @Nullable InputConnection connection) {
|
||||
this.context = context;
|
||||
this.connection = connection;
|
||||
public TextSelection(@Nullable InputMethodService ims) {
|
||||
this.ims = ims;
|
||||
detectCursorPosition();
|
||||
}
|
||||
|
||||
|
||||
private InputConnection getConnection() {
|
||||
return ims != null ? ims.getCurrentInputConnection() : null;
|
||||
}
|
||||
|
||||
|
||||
public void onSelectionUpdate(int start, int end) {
|
||||
currentStart = start;
|
||||
currentEnd = end;
|
||||
|
|
@ -36,6 +39,7 @@ public class TextSelection {
|
|||
|
||||
|
||||
public void clear() {
|
||||
InputConnection connection = getConnection();
|
||||
if (connection != null) {
|
||||
connection.setSelection(currentEnd, currentEnd);
|
||||
}
|
||||
|
|
@ -43,6 +47,7 @@ public class TextSelection {
|
|||
|
||||
|
||||
public void clear(boolean backward) {
|
||||
InputConnection connection = getConnection();
|
||||
if (connection != null) {
|
||||
connection.setSelection(
|
||||
backward ? Math.min(currentStart, currentEnd) : Math.max(currentStart, currentEnd),
|
||||
|
|
@ -58,6 +63,7 @@ public class TextSelection {
|
|||
|
||||
|
||||
public void selectAll() {
|
||||
InputConnection connection = getConnection();
|
||||
if (connection != null) {
|
||||
connection.performContextMenuAction(android.R.id.selectAll);
|
||||
}
|
||||
|
|
@ -65,6 +71,7 @@ public class TextSelection {
|
|||
|
||||
|
||||
public void selectNextChar(boolean backward) {
|
||||
InputConnection connection = getConnection();
|
||||
if (connection != null) {
|
||||
connection.setSelection(currentStart, currentEnd + (backward ? -1 : 1));
|
||||
}
|
||||
|
|
@ -72,6 +79,7 @@ public class TextSelection {
|
|||
|
||||
|
||||
public void selectNextWord(boolean backward) {
|
||||
InputConnection connection = getConnection();
|
||||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -81,12 +89,16 @@ public class TextSelection {
|
|||
|
||||
|
||||
public boolean copy() {
|
||||
if (ims == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CharSequence selectedText = getSelectedText();
|
||||
if (selectedText.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Clipboard.copy(context, selectedText);
|
||||
Clipboard.copy(ims, selectedText);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +111,11 @@ public class TextSelection {
|
|||
|
||||
|
||||
public void paste(@NonNull TextField textField) {
|
||||
String clipboardText = Clipboard.paste(context);
|
||||
if (ims == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String clipboardText = Clipboard.paste(ims);
|
||||
if (!clipboardText.isEmpty()) {
|
||||
textField.setText(clipboardText);
|
||||
}
|
||||
|
|
@ -107,6 +123,7 @@ public class TextSelection {
|
|||
|
||||
|
||||
private int getNextWordPosition(boolean backward) {
|
||||
InputConnection connection = getConnection();
|
||||
if (connection == null) {
|
||||
return currentEnd + (backward ? -1 : 1);
|
||||
}
|
||||
|
|
@ -135,6 +152,7 @@ public class TextSelection {
|
|||
|
||||
|
||||
private void detectCursorPosition() {
|
||||
InputConnection connection = getConnection();
|
||||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -148,6 +166,7 @@ public class TextSelection {
|
|||
|
||||
|
||||
private CharSequence getSelectedText() {
|
||||
InputConnection connection = getConnection();
|
||||
if (connection == null) {
|
||||
return "";
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue