Android: simplify the text input with SpannableStringBuilder

Also needed some change on the Text item to avoid sending ime callback
for intermediate states
This commit is contained in:
Olivier Goffart 2024-02-27 14:14:30 +01:00
parent 2b08de093a
commit 1fb162936e
2 changed files with 171 additions and 88 deletions

View file

@ -7,11 +7,13 @@ import android.view.inputmethod.InputConnection;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.text.Editable;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.view.inputmethod.InputMethodManager;
import android.app.Activity;
import android.widget.FrameLayout;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.ExtractedText;
class SlintInputView extends View {
private String mText = "";
@ -20,11 +22,38 @@ class SlintInputView extends View {
private String mPreedit = "";
private int mPreeditOffset;
private int mInputType = EditorInfo.TYPE_CLASS_TEXT;
private SpannableStringBuilder mEditable;
public class SlintEditable extends SpannableStringBuilder {
// private SlintInputView mInputView;
public SlintEditable() {
super(mText);
}
@Override
public SpannableStringBuilder replace(int start, int end, CharSequence tb, int tbstart, int tbend) {
super.replace(start, end, tb, tbstart, tbend);
mText = toString();
mCursorPosition = Selection.getSelectionStart(this);
mAnchorPosition = Selection.getSelectionEnd(this);
SlintAndroidJavaHelper.updateText(mText, mCursorPosition, mAnchorPosition, "", mCursorPosition);
return this;
}
@Override
public void setSpan(Object what, int start, int end, int flags) {
super.setSpan(what, start, end, flags);
mCursorPosition = Selection.getSelectionStart(this);
mAnchorPosition = Selection.getSelectionEnd(this);
}
}
public SlintInputView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
mEditable = new SlintEditable();
}
@Override
@ -38,73 +67,18 @@ class SlintInputView extends View {
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI;
outAttrs.initialSelStart = mCursorPosition;
outAttrs.initialSelEnd = mAnchorPosition;
return new BaseInputConnection(this, false) {
return new BaseInputConnection(this, true) {
@Override
public CharSequence getTextBeforeCursor(int n, int flags) {
return mText.substring(0, mCursorPosition);
}
@Override
public CharSequence getTextAfterCursor(int n, int flags) {
return mText.substring(mCursorPosition);
}
@Override
public CharSequence getSelectedText(int flags) {
if (mCursorPosition != mAnchorPosition) {
return mText.substring(mCursorPosition, mAnchorPosition);
}
return null;
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
mText = new StringBuilder(mText).delete(mCursorPosition, mAnchorPosition).insert(mCursorPosition, text)
.toString();
mPreedit = "";
if (newCursorPosition > 0) {
mCursorPosition = mCursorPosition + text.length() + newCursorPosition - 1;
} else {
mCursorPosition = mCursorPosition + newCursorPosition;
}
mAnchorPosition = mCursorPosition;
SlintAndroidJavaHelper.updateText(mText, mCursorPosition, mAnchorPosition, mPreedit, mPreeditOffset);
// return super.commitText(text, newCursorPosition);
return true;
}
@Override
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
mText = new StringBuilder(mText).delete(mCursorPosition - beforeLength, mAnchorPosition + afterLength)
.toString();
mCursorPosition = mCursorPosition - beforeLength;
mAnchorPosition = mCursorPosition;
SlintAndroidJavaHelper.updateText(mText, mCursorPosition, mAnchorPosition, mPreedit, mPreeditOffset);
return true;
}
@Override
public boolean setComposingText(CharSequence text, int newCursorPosition) {
mPreedit = text.toString();
mPreeditOffset = newCursorPosition;
SlintAndroidJavaHelper.updateText(mText, mCursorPosition, mAnchorPosition, mPreedit, mPreeditOffset);
return super.setComposingText(text, newCursorPosition);
}
@Override
public boolean setSelection(int start, int end) {
mCursorPosition = start;
mAnchorPosition = end;
SlintAndroidJavaHelper.updateText(mText, mCursorPosition, mAnchorPosition, mPreedit, mPreeditOffset);
return true;
public Editable getEditable() {
return mEditable;
}
};
}
public void setText(String text, int cursorPosition, int anchorPosition, String preedit, int preeditOffset,
int inputType) {
boolean restart = mInputType != inputType || !mText.equals(text);
boolean update_selection = mCursorPosition != cursorPosition || mAnchorPosition != anchorPosition;
boolean restart = mInputType != inputType || !mText.equals(text) || mCursorPosition != cursorPosition
|| mAnchorPosition != anchorPosition;
mText = text;
mCursorPosition = cursorPosition;
mAnchorPosition = anchorPosition;
@ -112,17 +86,12 @@ class SlintInputView extends View {
mPreeditOffset = preeditOffset;
mInputType = inputType;
InputMethodManager imm = (InputMethodManager) this.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (restart) {
mEditable = new SlintEditable();
Selection.setSelection(mEditable, cursorPosition, anchorPosition);
InputMethodManager imm = (InputMethodManager) this.getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.restartInput(this);
} else if (update_selection) {
ExtractedText extractedText = new ExtractedText();
extractedText.text = mText;
extractedText.startOffset = mPreeditOffset;
extractedText.selectionStart = mCursorPosition;
extractedText.selectionEnd = mAnchorPosition;
imm.updateExtractedText(this, 0, extractedText);
imm.updateSelection(this, cursorPosition, anchorPosition, cursorPosition, anchorPosition);
}
}