I've created a custom editor for vertical Mongolian text. The circled views show my my custom editor. They keyboards at the bottom are system keyboards.
When a system keyboard inputs text into it in landscape orientation, though, the keyboard will likely show an extracted text view rather than my custom editor view. The circled view below is the extracted text view (which is not getting updated by my custom editor).
I need to somehow send updates from my view to the input method manager. This is stated in the InputConnection
documentation:
Editor authors: as a general rule, try to comply with the fields in request for how many chars to return, but if performance or convenience dictates otherwise, please feel free to do what is most appropriate for your case. Also, if the
GET_EXTRACTED_TEXT_MONITOR
flag is set, you should be callingInputMethodManager.updateExtractedText(View, int, ExtractedText)
whenever you callInputMethodManager.updateSelection(View, int, int, int, int)
.
I've been exploring the source code related to extracted text
but I'm lost.
Here is the closest I've gotten. This is a method inside my custom editor.
private void reportExtractedText() {
// TODO we should be modifying this based on an ExtractedTextRequest
ExtractedText et = new ExtractedText();
final CharSequence content = getText();
final int length = content.length();
et.partialStartOffset = 0;
et.partialEndOffset = length;
et.startOffset = 0;
et.selectionStart = getSelectionStart();
et.selectionEnd = getSelectionEnd();
et.flags = 0;
et.text = content.subSequence(0, length);
// FIXME: should be returning this from the ExtractedTextRequest
int requestToken = 0;
InputMethodManager imm = (InputMethodManager) getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) return;
imm.updateExtractedText(this, requestToken, et);
}
When I am inside my editor I don't have a reference to the ExtractedTextRequest
, which should be used to modify what I include in my extracted text update.
Here is another method inside my BaseInputConnection
subclass (slightly modified from here). I have access to the ExtractedTextRequest
but this is not where I am calling the updates from. It will cause the extracted text view to show the initial text correctly, but the updates still don't get applied. This method is called by the InputMethodService
and can also be called by custom input methods.
@Override
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
if (request == null)
return null;
if ((flags & GET_EXTRACTED_TEXT_MONITOR) != 0)
mExtractedTextRequest = request; // mExtractedTextRequest currently doing nothing
Editable editable = getEditable();
if (editable == null) {
return null;
}
int selStart = Selection.getSelectionStart(editable);
int selEnd = Selection.getSelectionEnd(editable);
ExtractedText extract = new ExtractedText();
extract.flags = 0;
extract.partialStartOffset = -1;
extract.partialEndOffset = -1;
extract.selectionStart = selStart;
extract.selectionEnd = selEnd;
extract.startOffset = 0;
if ((request.flags & GET_TEXT_WITH_STYLES) != 0) {
extract.text = new SpannableString(editable);
} else {
extract.text = editable.toString();
}
return extract;
}
I added a more generic MCVE here.
The key to updating the extracted text view is to set the
ExtractedTextRequest
token. Without the token the updates don't take effect. Thanks to this answer for help with the token.We can the token in the input connection's
getExtractedText()
withrequest.token
and then add a method to the custom view to set it:That allows me to use the token when I call
InputMethodManager.updateExtractedText()
from within my custom view.You can view my full code here: