private void checkReCorrectionOnStart() { if (mReCorrectionEnabled && isPredictionOn()) { // First get the cursor position. This is required by setOldSuggestions(), so that // it can pass the correct range to setComposingRegion(). At this point, we don't // have valid values for mLastSelectionStart/Stop because onUpdateSelection() has // not been called yet. InputConnection ic = getCurrentInputConnection(); if (ic == null) return; ExtractedTextRequest etr = new ExtractedTextRequest(); etr.token = 0; // anything is fine here ExtractedText et = ic.getExtractedText(etr, 0); if (et == null) return; mLastSelectionStart = et.startOffset + et.selectionStart; mLastSelectionEnd = et.startOffset + et.selectionEnd; // Then look for possible corrections in a delayed fashion if (!TextUtils.isEmpty(et.text) && isCursorTouchingWord()) { postUpdateOldSuggestions(); } } }
/** * Formats the recognised text by adding white spaces at the beginning or at the end, and * by making the first char upper case if necessary. */ private String format(ExtractedText et, String result) { int pos = et.selectionStart - 1; while (pos > 0 && Character.isWhitespace(et.text.charAt(pos))) { pos--; } if (pos == -1 || mUpperCaseChars.contains(et.text.charAt(pos))) { result = Character.toUpperCase(result.charAt(0)) + result.substring(1); } if (et.selectionStart - 1 > 0 && !Character.isWhitespace(et.text.charAt(et.selectionStart - 1))) { result = " " + result; } if (et.selectionEnd < et.text.length() && !Character.isWhitespace(et.text.charAt(et.selectionEnd))) { result = result + " "; } return result; }
@Override public boolean replace(String str1, String str2) { boolean success = false; mInputConnection.beginBatchEdit(); ExtractedText extractedText = mInputConnection.getExtractedText(new ExtractedTextRequest(), 0); if (extractedText != null) { CharSequence beforeCursor = extractedText.text; //CharSequence beforeCursor = mInputConnection.getTextBeforeCursor(MAX_SELECTABLE_CONTEXT, 0); Log.i("replace: " + beforeCursor); int index = beforeCursor.toString().lastIndexOf(str1); Log.i("replace: " + index); if (index > 0) { mInputConnection.setSelection(index, index); mInputConnection.deleteSurroundingText(0, str1.length()); if (!str2.isEmpty()) { mInputConnection.commitText(str2, 0); } success = true; } mInputConnection.endBatchEdit(); } return success; }
/** Selection should change after onUpdateSelection. */ public void testSelectionUpdate(){ EditorInfo ei = getSampleEditorInfo(); ei.imeOptions |= EditorInfo.IME_ACTION_NONE; ExtractedText et = getSampleExtractedText(); et.selectionStart = 3; et.selectionEnd = 3; autoStub(mDisplayManager, mInputConnection, ei, et); createBindAndStart(ei); // Check selection, update and check again. verifyDisplayContentMatches("Hello world!", 3, 3); mIME.onUpdateSelection(3, 3, 3, 6, 0, 0); verifyDisplayContentMatches("Hello world!", 3, 6); finishUnbindAndDestroy(); }
/** A routing key press on the button should invoke the default action. */ public void testRouteActionLabel() { EditorInfo ei = getSampleEditorInfo(); ExtractedText et = getSampleExtractedText(); ArgumentCaptor<DisplayManager.Content> content = ArgumentCaptor.forClass(DisplayManager.Content.class); autoStub(mDisplayManager, mFeedbackManager, mInputConnection, ei, et); doReturn(true).when(mIME).sendDefaultEditorAction(anyBoolean()); createBindAndStart(ei); // Grab and verify the populated content. verify(mDisplayManager).setContent(content.capture()); assertEquals("Hello world! [Execute]", content.getValue().getText().toString()); // Send a routing event back. // Default action should be sent, with no feedback from the IME. Mockito.reset(mFeedbackManager); mIME.route(16, content.getValue()); verify(mIME).sendDefaultEditorAction(anyBoolean()); verify(mFeedbackManager, never()).emitFeedback(anyInt()); verify(mFeedbackManager, never()).emitOnFailure(eq(false), anyInt()); finishUnbindAndDestroy(); }
/** * If the default action cannot be invoked, the IME should emit failure * feedback. */ public void testRouteActionLabelFail() { EditorInfo ei = getSampleEditorInfo(); ExtractedText et = getSampleExtractedText(); ArgumentCaptor<DisplayManager.Content> content = ArgumentCaptor.forClass(DisplayManager.Content.class); autoStub(mDisplayManager, mFeedbackManager, mInputConnection, ei, et); doReturn(false).when(mIME).sendDefaultEditorAction(anyBoolean()); createBindAndStart(ei); // Grab and verify the populated content. verify(mDisplayManager).setContent(content.capture()); assertEquals("Hello world! [Execute]", content.getValue().getText().toString()); // Send a routing event back. // Default action should be sent, and feedback should be emitted. Mockito.reset(mFeedbackManager); mIME.route(16, content.getValue()); verify(mIME).sendDefaultEditorAction(anyBoolean()); verify(mFeedbackManager).emitFeedback( FeedbackManager.TYPE_COMMAND_FAILED); finishUnbindAndDestroy(); }
/** If the routing key is within the text, the cursor should move. */ public void testRouteMoveCursor() { EditorInfo ei = getSampleEditorInfo(); ei.label = "Label"; ExtractedText et = getSampleExtractedText(); ArgumentCaptor<DisplayManager.Content> content = ArgumentCaptor.forClass(DisplayManager.Content.class); autoStub(mDisplayManager, mFeedbackManager, mInputConnection, ei, et); when(mInputConnection.setSelection(3, 3)).thenReturn(true); createBindAndStart(ei); // Grab and verify the populated content. verify(mDisplayManager).setContent(content.capture()); assertEquals("Label: Hello world! [Execute]", content.getValue().getText().toString()); // Send a routing event back. // The selection should change, and no feedback should be emitted. Mockito.reset(mFeedbackManager); mIME.route(10, content.getValue()); verify(mFeedbackManager, never()).emitFeedback(anyInt()); verify(mFeedbackManager, never()).emitOnFailure(eq(false), anyInt()); finishUnbindAndDestroy(); }
/** * If the routing key is within the text, but moving fails, feedback * should be emitted. */ public void testRouteMoveCursorFail() { EditorInfo ei = getSampleEditorInfo(); ei.label = "Label"; ExtractedText et = getSampleExtractedText(); ArgumentCaptor<DisplayManager.Content> content = ArgumentCaptor.forClass(DisplayManager.Content.class); autoStub(mDisplayManager, mFeedbackManager, mInputConnection, ei, et); when(mInputConnection.setSelection(3, 3)).thenReturn(false); createBindAndStart(ei); // Grab and verify the populated content. verify(mDisplayManager).setContent(content.capture()); assertEquals("Label: Hello world! [Execute]", content.getValue().getText().toString()); // Send a routing event back. // The selection should change, and no feedback should be emitted. Mockito.reset(mFeedbackManager); mIME.route(10, content.getValue()); verify(mFeedbackManager).emitFeedback( FeedbackManager.TYPE_COMMAND_FAILED); finishUnbindAndDestroy(); }
/** * If a routing key press occurs anywhere else, the IME should emit * feedback. */ public void testRouteOutOfBounds() { EditorInfo ei = getSampleEditorInfo(); ei.label = "Label"; ExtractedText et = getSampleExtractedText(); ArgumentCaptor<DisplayManager.Content> content = ArgumentCaptor.forClass(DisplayManager.Content.class); autoStub(mDisplayManager, mFeedbackManager, mInputConnection, ei, et); createBindAndStart(ei); // Grab and verify the populated content. verify(mDisplayManager).setContent(content.capture()); assertEquals("Label: Hello world! [Execute]", content.getValue().getText().toString()); // Send a routing event back. // The selection should change, and no feedback should be emitted. Mockito.reset(mFeedbackManager); mIME.route(1, content.getValue()); verify(mFeedbackManager).emitFeedback( FeedbackManager.TYPE_NAVIGATE_OUT_OF_BOUNDS); finishUnbindAndDestroy(); }
/** Default action when no custom action is specified. */ public void testSendDefaultAction() { EditorInfo ei = getSampleEditorInfo(); ExtractedText et = getSampleExtractedText(); autoStub(mFeedbackManager, mInputConnection, ei, et); doReturn(true).when(mIME).sendDefaultEditorAction(anyBoolean()); createBindAndStart(ei); Mockito.reset(mFeedbackManager); assertTrue(mIME.sendDefaultAction()); verify(mFeedbackManager, never()).emitFeedback(anyInt()); verify(mFeedbackManager, never()).emitOnFailure(eq(false), anyInt()); finishUnbindAndDestroy(); }
/** Default action when a custom action is specified. */ public void testSendDefaultActionCustom() { EditorInfo ei = getSampleEditorInfo(); ei.actionId = 1337; ExtractedText et = getSampleExtractedText(); autoStub(mFeedbackManager, mInputConnection, ei, et); when(mInputConnection.performEditorAction(1337)).thenReturn(true); createBindAndStart(ei); Mockito.reset(mFeedbackManager); assertTrue(mIME.sendDefaultAction()); verify(mFeedbackManager, never()).emitFeedback(anyInt()); verify(mFeedbackManager, never()).emitOnFailure(eq(false), anyInt()); finishUnbindAndDestroy(); }
/** * Tests that {@link #sendDefaultAction} returns false on failure. * At the moment, no feedback is emitted in this method. */ public void testSendDefaultActionFail() { EditorInfo ei = getSampleEditorInfo(); ExtractedText et = getSampleExtractedText(); autoStub(mFeedbackManager, mInputConnection, ei, et); doReturn(false).when(mIME).sendDefaultEditorAction(anyBoolean()); createBindAndStart(ei); Mockito.reset(mFeedbackManager); assertFalse(mIME.sendDefaultAction()); verify(mFeedbackManager, never()).emitFeedback(anyInt()); verify(mFeedbackManager, never()).emitOnFailure(eq(false), anyInt()); finishUnbindAndDestroy(); }
/** Tests when moving by character granularity fails. */ public void testMoveCursorCharacterGranularityFail() { EditorInfo ei = getSampleEditorInfo(); ExtractedText et = getSampleExtractedText(); autoStub(mFeedbackManager, mInputConnection, ei, et); when(mInputConnection.sendKeyEvent(isA(KeyEvent.class))) .thenReturn(false); createBindAndStart(ei); Mockito.reset(mFeedbackManager); mIME.moveCursor(BrailleIME.DIRECTION_FORWARD, AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER); verify(mInputConnection).sendKeyEvent(keyEventMatches( KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT)); verify(mFeedbackManager).emitFeedback( FeedbackManager.TYPE_COMMAND_FAILED); finishUnbindAndDestroy(); }
/** Tests sending an Android key code. */ public void testSendAndroidKey() { EditorInfo ei = getSampleEditorInfo(); ExtractedText et = getSampleExtractedText(); autoStub(mFeedbackManager, mInputConnection, ei, et); when(mInputConnection.sendKeyEvent(isA(KeyEvent.class))) .thenReturn(true); createBindAndStart(ei); Mockito.reset(mFeedbackManager); mIME.sendAndroidKey(KeyEvent.KEYCODE_ENTER); verify(mInputConnection).sendKeyEvent(keyEventMatches( KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)); verify(mInputConnection).sendKeyEvent(keyEventMatches( KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER)); verify(mFeedbackManager, never()).emitFeedback(anyInt()); verify(mFeedbackManager, never()).emitOnFailure(eq(false), anyInt()); finishUnbindAndDestroy(); }
/** Tests feedback when sending an Android key code fails. */ public void testSendAndroidKeyFail() { EditorInfo ei = getSampleEditorInfo(); ExtractedText et = getSampleExtractedText(); autoStub(mFeedbackManager, mInputConnection, ei, et); when(mInputConnection.sendKeyEvent(isA(KeyEvent.class))) .thenReturn(false); createBindAndStart(ei); Mockito.reset(mFeedbackManager); mIME.sendAndroidKey(KeyEvent.KEYCODE_ENTER); verify(mInputConnection).sendKeyEvent(keyEventMatches( KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)); verify(mFeedbackManager).emitFeedback( FeedbackManager.TYPE_COMMAND_FAILED); finishUnbindAndDestroy(); }
/** Tests that text is committed when a Braille key is entered. */ public void testHandleBrailleKey() { EditorInfo ei = getSampleEditorInfo(); ExtractedText et = getSampleExtractedText(); autoStub(mBrailleTranslator, mFeedbackManager, mInputConnection, ei, et); when(mBrailleTranslator.backTranslate(new byte[] {0x1b})) .thenReturn("g"); when(mInputConnection.commitText("g", 1)).thenReturn(true); createBindAndStart(ei); Mockito.reset(mFeedbackManager); assertTrue(mIME.handleBrailleKey(0x1b)); verify(mFeedbackManager, never()).emitFeedback(anyInt()); verify(mFeedbackManager, never()).emitOnFailure(eq(false), anyInt()); finishUnbindAndDestroy(); }
/** Tests feedback when committing a Braille key fails. */ public void testHandleBrailleKeyFail() { EditorInfo ei = getSampleEditorInfo(); ExtractedText et = getSampleExtractedText(); autoStub(mBrailleTranslator, mFeedbackManager, mInputConnection, ei, et); when(mBrailleTranslator.backTranslate(new byte[] {0x1b})) .thenReturn("g"); when(mInputConnection.commitText("g", 1)).thenReturn(false); createBindAndStart(ei); Mockito.reset(mFeedbackManager); assertTrue(mIME.handleBrailleKey(0x1b)); verify(mFeedbackManager).emitFeedback( FeedbackManager.TYPE_COMMAND_FAILED); finishUnbindAndDestroy(); }
/** * Injects objects into their usual places in the mocks and stubs. * Simplifies boilerplate stubbing. */ private void autoStub(Object... objects) { for (Object o : objects) { if (o == mBrailleTranslator) { when(mHost.getBrailleTranslator()) .thenReturn(mBrailleTranslator); } else if (o == mDisplayManager) { when(mHost.getDisplayManager()).thenReturn(mDisplayManager); } else if (o == mFeedbackManager) { when(mHost.getFeedbackManager()).thenReturn(mFeedbackManager); } else if (o == mInputConnection) { when(mIME.getCurrentInputConnection()) .thenReturn(mInputConnection); } else if (o instanceof EditorInfo) { when(mIME.getCurrentInputEditorInfo()) .thenReturn((EditorInfo) o); } else if (o instanceof ExtractedText) { when(mInputConnection.getExtractedText( isA(ExtractedTextRequest.class), anyInt())) .thenReturn((ExtractedText) o); } else { throw new UnsupportedOperationException( "can't auto-stub " + o.toString()); } } }
private void deleteWordRight(InputConnection conn) { ExtractedText text = conn.getExtractedText(req, 0); if (text == null) return; int end = text.selectionEnd; String str = text.text.toString(); int len = str.length(); for (; end < len; end++) { if (!Character.isSpace(str.charAt(end))) break; } for (; end < len; end++) { if (Character.isSpace(str.charAt(end))) break; } conn.deleteSurroundingText(0, end - text.selectionEnd); }
private void deleteWordLeft(InputConnection conn) { // TODO: what is the correct word deleting policy? // delete until next space? until next different character type? ExtractedText text = conn.getExtractedText(req, 0); if (text == null) return; int end = text.selectionEnd - 1; String str = text.text.toString(); for (; end >= 0; end--) { if (!Character.isSpace(str.charAt(end))) break; } for (; end >= 0; end--) { if (Character.isSpace(str.charAt(end))) break; } end++; conn.deleteSurroundingText(text.selectionEnd - end, 0); }
private void wordRight(InputConnection conn) { boolean shift = pressedKeys.contains(KeyEvent.KEYCODE_SHIFT_LEFT); ExtractedText text = conn.getExtractedText(req, 0); if (text == null) return; int end = text.selectionEnd; String str = text.text.toString(); int len = str.length(); for (; end < len; end++) { if (!Character.isSpace(str.charAt(end))) break; } for (; end < len; end++) { if (Character.isSpace(str.charAt(end))) break; } int start = shift ? text.selectionStart : end; Log.d("wifikeyboard", "start = " + start + " end = " + end); conn.setSelection(start, end); }
private void wordLeft(InputConnection conn) { boolean shift = pressedKeys.contains(KeyEvent.KEYCODE_SHIFT_LEFT); ExtractedText text = conn.getExtractedText(req, 0); if (text == null) return; int end = text.selectionEnd - 1; String str = text.text.toString(); for (; end >= 0; end--) { if (!Character.isSpace(str.charAt(end))) break; } for (; end >= 0; end--) { if (Character.isSpace(str.charAt(end))) break; } end++; int start = shift ? text.selectionStart : end; Log.d("wifikeyboard", "start = " + start + " end = " + end); conn.setSelection(start, end); }
private void keyEnd(InputConnection conn) { boolean control = pressedKeys.contains(KEY_CONTROL); boolean shift = pressedKeys.contains(KeyEvent.KEYCODE_SHIFT_LEFT); ExtractedText text = conn.getExtractedText(req, 0); if (text == null) return; int end; if (control) { end = text.text.length(); } else { end = text.text.toString().indexOf('\n', text.selectionEnd); if (end == -1) end = text.text.length(); } int start = shift ? text.selectionStart : end; Log.d("wifikeyboard", "start = " + start + " end = " + end); conn.setSelection(start, end); }
private void keyHome(InputConnection conn) { boolean control = pressedKeys.contains(KEY_CONTROL); boolean shift = pressedKeys.contains(KeyEvent.KEYCODE_SHIFT_LEFT); ExtractedText text = conn.getExtractedText(req, 0); if (text == null) return; int end; if (control) { end = 0; } else { end = text.text.toString().lastIndexOf('\n', text.selectionEnd - 1); end++; } int start = shift ? text.selectionStart : end; Log.d("wifikeyboard", "start = " + start + " end = " + end); conn.setSelection(start, end); }
@Override public Op moveAbs(final int pos) { return new Op("moveAbs " + pos) { @Override public Op run() { Op undo = null; mInputConnection.beginBatchEdit(); ExtractedText et = getExtractedText(); if (et != null) { int charPos = pos; if (pos < 0) { //-1 == end of text charPos = et.text.length() + pos + 1; } undo = getOpSetSelection(charPos, charPos, et.selectionStart, et.selectionEnd).run(); } mInputConnection.endBatchEdit(); return undo; } }; }
/** * mInputConnection.performContextMenuAction(android.R.id.selectAll) does not create a selection */ @Override public Op selectAll() { return new Op("selectAll") { @Override public Op run() { Op undo = null; mInputConnection.beginBatchEdit(); final ExtractedText et = getExtractedText(); if (et != null) { undo = getOpSetSelection(0, et.text.length(), et.selectionStart, et.selectionEnd).run(); } mInputConnection.endBatchEdit(); return undo; } }; }
@Override public Op select(final String query) { return new Op("select " + query) { @Override public Op run() { Op undo = null; mInputConnection.beginBatchEdit(); ExtractedText et = getExtractedText(); if (et != null) { Pair<Integer, CharSequence> queryResult = lastIndexOf(query.replace(F_SELECTION, getSelectedText()), et); if (queryResult.first >= 0) { undo = getOpSetSelection(queryResult.first, queryResult.first + queryResult.second.length(), et.selectionStart, et.selectionEnd).run(); } } mInputConnection.endBatchEdit(); return undo; } }; }
@Override public Op selectReBefore(final String regex) { return new Op("selectReBefore") { @Override public Op run() { Op undo = null; mInputConnection.beginBatchEdit(); final ExtractedText et = getExtractedText(); if (et != null) { CharSequence input = et.text.subSequence(0, et.selectionStart); // 0 == last match Pair<Integer, Integer> pos = matchNth(Pattern.compile(regex), input, 0); if (pos != null) { undo = getOpSetSelection(pos.first, pos.second, et.selectionStart, et.selectionEnd).run(); } } mInputConnection.endBatchEdit(); return undo; } }; }
@Override public Op selectReAfter(final String regex, final int n) { return new Op("selectReAfter") { @Override public Op run() { Op undo = null; mInputConnection.beginBatchEdit(); final ExtractedText et = getExtractedText(); if (et != null) { CharSequence input = et.text.subSequence(et.selectionEnd, et.text.length()); Pair<Integer, Integer> pos = matchNth(Pattern.compile(regex), input, n); if (pos != null) { undo = getOpSetSelection(et.selectionEnd + pos.first, et.selectionEnd + pos.second, et.selectionStart, et.selectionEnd).run(); } } mInputConnection.endBatchEdit(); return undo; } }; }
@Override public Op selectRe(final String regex, final boolean applyToSelection) { return new Op("selectRe") { @Override public Op run() { Op undo = null; mInputConnection.beginBatchEdit(); final ExtractedText et = getExtractedText(); if (et != null) { if (applyToSelection || et.selectionStart == et.selectionEnd) { Pair<Integer, Integer> pos = matchAtPos(Pattern.compile(regex), et.text, et.selectionStart, et.selectionEnd); if (pos != null) { undo = getOpSetSelection(pos.first, pos.second, et.selectionStart, et.selectionEnd).run(); } } } mInputConnection.endBatchEdit(); return undo; } }; }
private void updateSelection(TextInputState textInputState) { if (textInputState == null) return; assertOnImeThread(); if (mNumNestedBatchEdits != 0) return; Range selection = textInputState.selection(); Range composition = textInputState.composition(); // As per Guidelines in // https://developer.android.com/reference/android/view/inputmethod/InputConnection.html // #getExtractedText(android.view.inputmethod.ExtractedTextRequest,%20int) // States that if the GET_EXTRACTED_TEXT_MONITOR flag is set, // you should be calling updateExtractedText(View, int, ExtractedText) // whenever you call updateSelection(View, int, int, int, int). if (mShouldUpdateExtractedText) { final ExtractedText extractedText = convertToExtractedText(textInputState); mImeAdapter.updateExtractedText(mCurrentExtractedTextRequestToken, extractedText); } mImeAdapter.updateSelection( selection.start(), selection.end(), composition.start(), composition.end()); }
/** * Try to replace the current word with its substitution. */ private void replaceText(InputConnection con) { ExtractedText txt = con.getExtractedText(new ExtractedTextRequest(), 0); if (txt != null) { int end = txt.text.toString().indexOf(" ", txt.selectionEnd); if (end == -1) { end = txt.text.length(); } int start = txt.text.toString().lastIndexOf(" ", txt.selectionEnd - 1); start++; String sel = txt.text.subSequence(start, end).toString(); String rep = myService.replacements.get(sel); if (rep != null) { con.setComposingRegion(start, end); con.setComposingText(rep, 1); con.finishComposingText(); } else { String err = myService.getResources().getString( R.string.err_no_replacement, sel); Toast.makeText(myService, err, Toast.LENGTH_SHORT).show(); } } }
private static int getCursorPosition(InputConnection connection) { ExtractedText extracted = connection.getExtractedText( new ExtractedTextRequest(), 0); if (extracted == null) { return -1; } return extracted.startOffset + extracted.selectionStart; }
private void checkConsistencyForDebug() { final ExtractedTextRequest r = new ExtractedTextRequest(); r.hintMaxChars = 0; r.hintMaxLines = 0; r.token = 1; r.flags = 0; final ExtractedText et = mIC.getExtractedText(r, 0); final CharSequence beforeCursor = getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0); final StringBuilder internal = new StringBuilder(mCommittedTextBeforeComposingText) .append(mComposingText); if (null == et || null == beforeCursor) return; final int actualLength = Math.min(beforeCursor.length(), internal.length()); if (internal.length() > actualLength) { internal.delete(0, internal.length() - actualLength); } final String reference = (beforeCursor.length() <= actualLength) ? beforeCursor.toString() : beforeCursor.subSequence(beforeCursor.length() - actualLength, beforeCursor.length()).toString(); if (et.selectionStart != mExpectedSelStart || !(reference.equals(internal.toString()))) { final String context = "Expected selection start = " + mExpectedSelStart + "\nActual selection start = " + et.selectionStart + "\nExpected text = " + internal.length() + " " + internal + "\nActual text = " + reference.length() + " " + reference; ((LatinIME)mParent).debugDumpStateAndCrashWithException(context); } else { Log.e(TAG, DebugLogUtils.getStackTrace(2)); Log.e(TAG, "Exp <> Actual : " + mExpectedSelStart + " <> " + et.selectionStart); } }
public static String getAllInputText(InputConnection inputConnection) { String allText = ""; try { ExtractedText extractedText = inputConnection.getExtractedText(new ExtractedTextRequest(), 0); if (extractedText != null) { allText = extractedText.text.toString(); } } catch (Exception e) { e.printStackTrace(); } return allText; }
@Override public boolean select(String str) { boolean success = false; mInputConnection.beginBatchEdit(); ExtractedText extractedText = mInputConnection.getExtractedText(new ExtractedTextRequest(), 0); CharSequence beforeCursor = extractedText.text; int index = beforeCursor.toString().lastIndexOf(str); if (index > 0) { mInputConnection.setSelection(index, index + str.length()); success = true; } mInputConnection.endBatchEdit(); return success; }