467 lines
20 KiB
Java
467 lines
20 KiB
Java
package io.flutter.plugin.editing;
|
|
|
|
import android.content.ClipData;
|
|
import android.content.ClipboardManager;
|
|
import android.content.Context;
|
|
import android.net.Uri;
|
|
import android.os.Bundle;
|
|
import android.text.DynamicLayout;
|
|
import android.text.Editable;
|
|
import android.text.Layout;
|
|
import android.text.Selection;
|
|
import android.text.TextPaint;
|
|
import android.view.KeyEvent;
|
|
import android.view.View;
|
|
import android.view.inputmethod.BaseInputConnection;
|
|
import android.view.inputmethod.CursorAnchorInfo;
|
|
import android.view.inputmethod.EditorInfo;
|
|
import android.view.inputmethod.ExtractedText;
|
|
import android.view.inputmethod.ExtractedTextRequest;
|
|
import android.view.inputmethod.InputContentInfo;
|
|
import android.view.inputmethod.InputMethodManager;
|
|
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
|
|
import io.flutter.Log;
|
|
import io.flutter.embedding.engine.FlutterJNI;
|
|
import io.flutter.embedding.engine.systemchannels.TextInputChannel;
|
|
import io.flutter.plugin.editing.ListenableEditingState;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.FileNotFoundException;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.util.HashMap;
|
|
|
|
/* loaded from: classes6.dex */
|
|
public class InputConnectionAdaptor extends BaseInputConnection implements ListenableEditingState.EditingStateWatcher {
|
|
private static final String TAG = "InputConnectionAdaptor";
|
|
private int batchEditNestDepth;
|
|
private FlutterTextUtils flutterTextUtils;
|
|
private final KeyboardDelegate keyboardDelegate;
|
|
private final int mClient;
|
|
private CursorAnchorInfo.Builder mCursorAnchorInfoBuilder;
|
|
private final ListenableEditingState mEditable;
|
|
private final EditorInfo mEditorInfo;
|
|
private ExtractedTextRequest mExtractRequest;
|
|
private ExtractedText mExtractedText;
|
|
private final View mFlutterView;
|
|
private InputMethodManager mImm;
|
|
private final Layout mLayout;
|
|
private boolean mMonitorCursorUpdate;
|
|
private final TextInputChannel textInputChannel;
|
|
|
|
/* loaded from: classes6.dex */
|
|
public interface KeyboardDelegate {
|
|
boolean handleEvent(KeyEvent keyEvent);
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection
|
|
public Editable getEditable() {
|
|
return this.mEditable;
|
|
}
|
|
|
|
public InputConnectionAdaptor(View view, int i, TextInputChannel textInputChannel, KeyboardDelegate keyboardDelegate, ListenableEditingState listenableEditingState, EditorInfo editorInfo, FlutterJNI flutterJNI) {
|
|
super(view, true);
|
|
this.mMonitorCursorUpdate = false;
|
|
this.mExtractedText = new ExtractedText();
|
|
this.batchEditNestDepth = 0;
|
|
this.mFlutterView = view;
|
|
this.mClient = i;
|
|
this.textInputChannel = textInputChannel;
|
|
this.mEditable = listenableEditingState;
|
|
listenableEditingState.addEditingStateListener(this);
|
|
this.mEditorInfo = editorInfo;
|
|
this.keyboardDelegate = keyboardDelegate;
|
|
this.flutterTextUtils = new FlutterTextUtils(flutterJNI);
|
|
this.mLayout = new DynamicLayout(listenableEditingState, new TextPaint(), Integer.MAX_VALUE, Layout.Alignment.ALIGN_NORMAL, 1.0f, BitmapDescriptorFactory.HUE_RED, false);
|
|
this.mImm = (InputMethodManager) view.getContext().getSystemService("input_method");
|
|
}
|
|
|
|
public InputConnectionAdaptor(View view, int i, TextInputChannel textInputChannel, KeyboardDelegate keyboardDelegate, ListenableEditingState listenableEditingState, EditorInfo editorInfo) {
|
|
this(view, i, textInputChannel, keyboardDelegate, listenableEditingState, editorInfo, new FlutterJNI());
|
|
}
|
|
|
|
private ExtractedText getExtractedText(ExtractedTextRequest extractedTextRequest) {
|
|
this.mExtractedText.startOffset = 0;
|
|
this.mExtractedText.partialStartOffset = -1;
|
|
this.mExtractedText.partialEndOffset = -1;
|
|
this.mExtractedText.selectionStart = this.mEditable.getSelectionStart();
|
|
this.mExtractedText.selectionEnd = this.mEditable.getSelectionEnd();
|
|
this.mExtractedText.text = (extractedTextRequest == null || (extractedTextRequest.flags & 1) == 0) ? this.mEditable.toString() : this.mEditable;
|
|
return this.mExtractedText;
|
|
}
|
|
|
|
private CursorAnchorInfo getCursorAnchorInfo() {
|
|
CursorAnchorInfo.Builder builder = this.mCursorAnchorInfoBuilder;
|
|
if (builder == null) {
|
|
this.mCursorAnchorInfoBuilder = new CursorAnchorInfo.Builder();
|
|
} else {
|
|
builder.reset();
|
|
}
|
|
this.mCursorAnchorInfoBuilder.setSelectionRange(this.mEditable.getSelectionStart(), this.mEditable.getSelectionEnd());
|
|
int composingStart = this.mEditable.getComposingStart();
|
|
int composingEnd = this.mEditable.getComposingEnd();
|
|
if (composingStart >= 0 && composingEnd > composingStart) {
|
|
this.mCursorAnchorInfoBuilder.setComposingText(composingStart, this.mEditable.toString().subSequence(composingStart, composingEnd));
|
|
} else {
|
|
this.mCursorAnchorInfoBuilder.setComposingText(-1, "");
|
|
}
|
|
return this.mCursorAnchorInfoBuilder.build();
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean beginBatchEdit() {
|
|
this.mEditable.beginBatchEdit();
|
|
this.batchEditNestDepth++;
|
|
return super.beginBatchEdit();
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean endBatchEdit() {
|
|
boolean endBatchEdit = super.endBatchEdit();
|
|
this.batchEditNestDepth--;
|
|
this.mEditable.endBatchEdit();
|
|
return endBatchEdit;
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean commitText(CharSequence charSequence, int i) {
|
|
return super.commitText(charSequence, i);
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean deleteSurroundingText(int i, int i2) {
|
|
if (this.mEditable.getSelectionStart() == -1) {
|
|
return true;
|
|
}
|
|
return super.deleteSurroundingText(i, i2);
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean deleteSurroundingTextInCodePoints(int i, int i2) {
|
|
return super.deleteSurroundingTextInCodePoints(i, i2);
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean setComposingRegion(int i, int i2) {
|
|
return super.setComposingRegion(i, i2);
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean setComposingText(CharSequence charSequence, int i) {
|
|
boolean composingText;
|
|
beginBatchEdit();
|
|
if (charSequence.length() == 0) {
|
|
composingText = super.commitText(charSequence, i);
|
|
} else {
|
|
composingText = super.setComposingText(charSequence, i);
|
|
}
|
|
endBatchEdit();
|
|
return composingText;
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean finishComposingText() {
|
|
return super.finishComposingText();
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public ExtractedText getExtractedText(ExtractedTextRequest extractedTextRequest, int i) {
|
|
boolean z = (i & 1) != 0;
|
|
if (z == (this.mExtractRequest == null)) {
|
|
Log.d(TAG, "The input method toggled text monitoring ".concat(z ? "on" : "off"));
|
|
}
|
|
this.mExtractRequest = z ? extractedTextRequest : null;
|
|
return getExtractedText(extractedTextRequest);
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean requestCursorUpdates(int i) {
|
|
if ((i & 1) != 0) {
|
|
this.mImm.updateCursorAnchorInfo(this.mFlutterView, getCursorAnchorInfo());
|
|
}
|
|
boolean z = (i & 2) != 0;
|
|
if (z != this.mMonitorCursorUpdate) {
|
|
Log.d(TAG, "The input method toggled cursor monitoring ".concat(z ? "on" : "off"));
|
|
}
|
|
this.mMonitorCursorUpdate = z;
|
|
return true;
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean clearMetaKeyStates(int i) {
|
|
return super.clearMetaKeyStates(i);
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public void closeConnection() {
|
|
super.closeConnection();
|
|
this.mEditable.removeEditingStateListener(this);
|
|
while (this.batchEditNestDepth > 0) {
|
|
endBatchEdit();
|
|
this.batchEditNestDepth--;
|
|
}
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean setSelection(int i, int i2) {
|
|
beginBatchEdit();
|
|
boolean selection = super.setSelection(i, i2);
|
|
endBatchEdit();
|
|
return selection;
|
|
}
|
|
|
|
private static int clampIndexToEditable(int i, Editable editable) {
|
|
int max = Math.max(0, Math.min(editable.length(), i));
|
|
if (max != i) {
|
|
Log.d("flutter", "Text selection index was clamped (" + i + "->" + max + ") to remain in bounds. This may not be your fault, as some keyboards may select outside of bounds.");
|
|
}
|
|
return max;
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean sendKeyEvent(KeyEvent keyEvent) {
|
|
return this.keyboardDelegate.handleEvent(keyEvent);
|
|
}
|
|
|
|
public boolean handleKeyEvent(KeyEvent keyEvent) {
|
|
if (keyEvent.getAction() == 0) {
|
|
if (keyEvent.getKeyCode() == 21) {
|
|
return handleHorizontalMovement(true, keyEvent.isShiftPressed());
|
|
}
|
|
if (keyEvent.getKeyCode() == 22) {
|
|
return handleHorizontalMovement(false, keyEvent.isShiftPressed());
|
|
}
|
|
if (keyEvent.getKeyCode() == 19) {
|
|
return handleVerticalMovement(true, keyEvent.isShiftPressed());
|
|
}
|
|
if (keyEvent.getKeyCode() == 20) {
|
|
return handleVerticalMovement(false, keyEvent.isShiftPressed());
|
|
}
|
|
if ((keyEvent.getKeyCode() == 66 || keyEvent.getKeyCode() == 160) && (this.mEditorInfo.inputType & 131072) == 0) {
|
|
performEditorAction(this.mEditorInfo.imeOptions & 255);
|
|
return true;
|
|
}
|
|
int selectionStart = Selection.getSelectionStart(this.mEditable);
|
|
int selectionEnd = Selection.getSelectionEnd(this.mEditable);
|
|
int unicodeChar = keyEvent.getUnicodeChar();
|
|
if (selectionStart < 0 || selectionEnd < 0 || unicodeChar == 0) {
|
|
return false;
|
|
}
|
|
int min = Math.min(selectionStart, selectionEnd);
|
|
int max = Math.max(selectionStart, selectionEnd);
|
|
beginBatchEdit();
|
|
if (min != max) {
|
|
this.mEditable.delete(min, max);
|
|
}
|
|
this.mEditable.insert(min, (CharSequence) String.valueOf((char) unicodeChar));
|
|
int i = min + 1;
|
|
setSelection(i, i);
|
|
endBatchEdit();
|
|
return true;
|
|
}
|
|
if (keyEvent.getAction() != 1 || (keyEvent.getKeyCode() != 59 && keyEvent.getKeyCode() != 60)) {
|
|
return false;
|
|
}
|
|
int selectionEnd2 = Selection.getSelectionEnd(this.mEditable);
|
|
setSelection(selectionEnd2, selectionEnd2);
|
|
return true;
|
|
}
|
|
|
|
private boolean handleHorizontalMovement(boolean z, boolean z2) {
|
|
int min;
|
|
int selectionStart = Selection.getSelectionStart(this.mEditable);
|
|
int selectionEnd = Selection.getSelectionEnd(this.mEditable);
|
|
if (selectionStart < 0 || selectionEnd < 0) {
|
|
return false;
|
|
}
|
|
if (z) {
|
|
min = Math.max(this.flutterTextUtils.getOffsetBefore(this.mEditable, selectionEnd), 0);
|
|
} else {
|
|
min = Math.min(this.flutterTextUtils.getOffsetAfter(this.mEditable, selectionEnd), this.mEditable.length());
|
|
}
|
|
if (selectionStart == selectionEnd && !z2) {
|
|
setSelection(min, min);
|
|
return true;
|
|
}
|
|
setSelection(selectionStart, min);
|
|
return true;
|
|
}
|
|
|
|
private boolean handleVerticalMovement(boolean z, boolean z2) {
|
|
int selectionStart = Selection.getSelectionStart(this.mEditable);
|
|
int selectionEnd = Selection.getSelectionEnd(this.mEditable);
|
|
boolean z3 = false;
|
|
if (selectionStart < 0 || selectionEnd < 0) {
|
|
return false;
|
|
}
|
|
if (selectionStart == selectionEnd && !z2) {
|
|
z3 = true;
|
|
}
|
|
beginBatchEdit();
|
|
if (z3) {
|
|
if (z) {
|
|
Selection.moveUp(this.mEditable, this.mLayout);
|
|
} else {
|
|
Selection.moveDown(this.mEditable, this.mLayout);
|
|
}
|
|
int selectionStart2 = Selection.getSelectionStart(this.mEditable);
|
|
setSelection(selectionStart2, selectionStart2);
|
|
} else {
|
|
if (z) {
|
|
Selection.extendUp(this.mEditable, this.mLayout);
|
|
} else {
|
|
Selection.extendDown(this.mEditable, this.mLayout);
|
|
}
|
|
setSelection(Selection.getSelectionStart(this.mEditable), Selection.getSelectionEnd(this.mEditable));
|
|
}
|
|
endBatchEdit();
|
|
return true;
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean performContextMenuAction(int i) {
|
|
beginBatchEdit();
|
|
boolean doPerformContextMenuAction = doPerformContextMenuAction(i);
|
|
endBatchEdit();
|
|
return doPerformContextMenuAction;
|
|
}
|
|
|
|
private boolean doPerformContextMenuAction(int i) {
|
|
if (i == 16908319) {
|
|
setSelection(0, this.mEditable.length());
|
|
return true;
|
|
}
|
|
if (i == 16908320) {
|
|
int selectionStart = Selection.getSelectionStart(this.mEditable);
|
|
int selectionEnd = Selection.getSelectionEnd(this.mEditable);
|
|
if (selectionStart != selectionEnd) {
|
|
int min = Math.min(selectionStart, selectionEnd);
|
|
int max = Math.max(selectionStart, selectionEnd);
|
|
((ClipboardManager) this.mFlutterView.getContext().getSystemService("clipboard")).setPrimaryClip(ClipData.newPlainText("text label?", this.mEditable.subSequence(min, max)));
|
|
this.mEditable.delete(min, max);
|
|
setSelection(min, min);
|
|
}
|
|
return true;
|
|
}
|
|
if (i == 16908321) {
|
|
int selectionStart2 = Selection.getSelectionStart(this.mEditable);
|
|
int selectionEnd2 = Selection.getSelectionEnd(this.mEditable);
|
|
if (selectionStart2 != selectionEnd2) {
|
|
((ClipboardManager) this.mFlutterView.getContext().getSystemService("clipboard")).setPrimaryClip(ClipData.newPlainText("text label?", this.mEditable.subSequence(Math.min(selectionStart2, selectionEnd2), Math.max(selectionStart2, selectionEnd2))));
|
|
}
|
|
return true;
|
|
}
|
|
if (i != 16908322) {
|
|
return false;
|
|
}
|
|
ClipData primaryClip = ((ClipboardManager) this.mFlutterView.getContext().getSystemService("clipboard")).getPrimaryClip();
|
|
if (primaryClip != null) {
|
|
CharSequence coerceToText = primaryClip.getItemAt(0).coerceToText(this.mFlutterView.getContext());
|
|
int max2 = Math.max(0, Selection.getSelectionStart(this.mEditable));
|
|
int max3 = Math.max(0, Selection.getSelectionEnd(this.mEditable));
|
|
int min2 = Math.min(max2, max3);
|
|
int max4 = Math.max(max2, max3);
|
|
if (min2 != max4) {
|
|
this.mEditable.delete(min2, max4);
|
|
}
|
|
this.mEditable.insert(min2, coerceToText);
|
|
int length = min2 + coerceToText.length();
|
|
setSelection(length, length);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean performPrivateCommand(String str, Bundle bundle) {
|
|
this.textInputChannel.performPrivateCommand(this.mClient, str, bundle);
|
|
return true;
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean performEditorAction(int i) {
|
|
if (i == 0) {
|
|
this.textInputChannel.unspecifiedAction(this.mClient);
|
|
} else if (i == 1) {
|
|
this.textInputChannel.newline(this.mClient);
|
|
} else if (i == 2) {
|
|
this.textInputChannel.go(this.mClient);
|
|
} else if (i == 3) {
|
|
this.textInputChannel.search(this.mClient);
|
|
} else if (i == 4) {
|
|
this.textInputChannel.send(this.mClient);
|
|
} else if (i == 5) {
|
|
this.textInputChannel.next(this.mClient);
|
|
} else if (i == 7) {
|
|
this.textInputChannel.previous(this.mClient);
|
|
} else {
|
|
this.textInputChannel.done(this.mClient);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override // android.view.inputmethod.BaseInputConnection, android.view.inputmethod.InputConnection
|
|
public boolean commitContent(InputContentInfo inputContentInfo, int i, Bundle bundle) {
|
|
if ((i & 1) != 0) {
|
|
try {
|
|
inputContentInfo.requestPermission();
|
|
if (inputContentInfo.getDescription().getMimeTypeCount() > 0) {
|
|
inputContentInfo.requestPermission();
|
|
Uri contentUri = inputContentInfo.getContentUri();
|
|
String mimeType = inputContentInfo.getDescription().getMimeType(0);
|
|
Context context = this.mFlutterView.getContext();
|
|
if (contentUri != null) {
|
|
try {
|
|
InputStream openInputStream = context.getContentResolver().openInputStream(contentUri);
|
|
if (openInputStream != null) {
|
|
byte[] readStreamFully = readStreamFully(openInputStream, 65536);
|
|
HashMap hashMap = new HashMap();
|
|
hashMap.put("mimeType", mimeType);
|
|
hashMap.put("data", readStreamFully);
|
|
hashMap.put("uri", contentUri.toString());
|
|
this.textInputChannel.commitContent(this.mClient, hashMap);
|
|
inputContentInfo.releasePermission();
|
|
return true;
|
|
}
|
|
} catch (FileNotFoundException unused) {
|
|
inputContentInfo.releasePermission();
|
|
return false;
|
|
}
|
|
}
|
|
inputContentInfo.releasePermission();
|
|
}
|
|
} catch (Exception unused2) {
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private byte[] readStreamFully(InputStream inputStream, int i) {
|
|
int i2;
|
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
|
byte[] bArr = new byte[i];
|
|
while (true) {
|
|
try {
|
|
i2 = inputStream.read(bArr);
|
|
} catch (IOException unused) {
|
|
i2 = -1;
|
|
}
|
|
if (i2 != -1) {
|
|
byteArrayOutputStream.write(bArr, 0, i2);
|
|
} else {
|
|
return byteArrayOutputStream.toByteArray();
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override // io.flutter.plugin.editing.ListenableEditingState.EditingStateWatcher
|
|
public void didChangeEditingState(boolean z, boolean z2, boolean z3) {
|
|
this.mImm.updateSelection(this.mFlutterView, this.mEditable.getSelectionStart(), this.mEditable.getSelectionEnd(), this.mEditable.getComposingStart(), this.mEditable.getComposingEnd());
|
|
ExtractedTextRequest extractedTextRequest = this.mExtractRequest;
|
|
if (extractedTextRequest != null) {
|
|
this.mImm.updateExtractedText(this.mFlutterView, extractedTextRequest.token, getExtractedText(this.mExtractRequest));
|
|
}
|
|
if (this.mMonitorCursorUpdate) {
|
|
this.mImm.updateCursorAnchorInfo(this.mFlutterView, getCursorAnchorInfo());
|
|
}
|
|
}
|
|
}
|