Loading api/current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -43411,6 +43411,7 @@ package android.view.inputmethod { method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public boolean commitText(java.lang.CharSequence, int); method public boolean deleteSurroundingText(int, int); method public boolean deleteSurroundingTextInCodePoints(int, int); method public boolean endBatchEdit(); method public boolean finishComposingText(); method public static int getComposingSpanEnd(android.text.Spannable); Loading Loading @@ -43576,6 +43577,7 @@ package android.view.inputmethod { method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public abstract boolean commitText(java.lang.CharSequence, int); method public abstract boolean deleteSurroundingText(int, int); method public abstract boolean deleteSurroundingTextInCodePoints(int, int); method public abstract boolean endBatchEdit(); method public abstract boolean finishComposingText(); method public abstract int getCursorCapsMode(int); Loading Loading @@ -43606,6 +43608,7 @@ package android.view.inputmethod { method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public boolean commitText(java.lang.CharSequence, int); method public boolean deleteSurroundingText(int, int); method public boolean deleteSurroundingTextInCodePoints(int, int); method public boolean endBatchEdit(); method public boolean finishComposingText(); method public int getCursorCapsMode(int); api/system-current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -45807,6 +45807,7 @@ package android.view.inputmethod { method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public boolean commitText(java.lang.CharSequence, int); method public boolean deleteSurroundingText(int, int); method public boolean deleteSurroundingTextInCodePoints(int, int); method public boolean endBatchEdit(); method public boolean finishComposingText(); method public static int getComposingSpanEnd(android.text.Spannable); Loading Loading @@ -45972,6 +45973,7 @@ package android.view.inputmethod { method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public abstract boolean commitText(java.lang.CharSequence, int); method public abstract boolean deleteSurroundingText(int, int); method public abstract boolean deleteSurroundingTextInCodePoints(int, int); method public abstract boolean endBatchEdit(); method public abstract boolean finishComposingText(); method public abstract int getCursorCapsMode(int); Loading Loading @@ -46002,6 +46004,7 @@ package android.view.inputmethod { method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public boolean commitText(java.lang.CharSequence, int); method public boolean deleteSurroundingText(int, int); method public boolean deleteSurroundingTextInCodePoints(int, int); method public boolean endBatchEdit(); method public boolean finishComposingText(); method public int getCursorCapsMode(int); api/test-current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -43427,6 +43427,7 @@ package android.view.inputmethod { method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public boolean commitText(java.lang.CharSequence, int); method public boolean deleteSurroundingText(int, int); method public boolean deleteSurroundingTextInCodePoints(int, int); method public boolean endBatchEdit(); method public boolean finishComposingText(); method public static int getComposingSpanEnd(android.text.Spannable); Loading Loading @@ -43592,6 +43593,7 @@ package android.view.inputmethod { method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public abstract boolean commitText(java.lang.CharSequence, int); method public abstract boolean deleteSurroundingText(int, int); method public abstract boolean deleteSurroundingTextInCodePoints(int, int); method public abstract boolean endBatchEdit(); method public abstract boolean finishComposingText(); method public abstract int getCursorCapsMode(int); Loading Loading @@ -43622,6 +43624,7 @@ package android.view.inputmethod { method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public boolean commitText(java.lang.CharSequence, int); method public boolean deleteSurroundingText(int, int); method public boolean deleteSurroundingTextInCodePoints(int, int); method public boolean endBatchEdit(); method public boolean finishComposingText(); method public int getCursorCapsMode(int); core/java/android/view/inputmethod/BaseInputConnection.java +162 −1 Original line number Diff line number Diff line Loading @@ -229,7 +229,7 @@ public class BaseInputConnection implements InputConnection { b = tmp; } // ignore the composing text. // Ignore the composing text. int ca = getComposingSpanStart(content); int cb = getComposingSpanEnd(content); if (cb < ca) { Loading Loading @@ -265,6 +265,167 @@ public class BaseInputConnection implements InputConnection { return true; } private static int INVALID_INDEX = -1; private static int findIndexBackward(final CharSequence cs, final int from, final int numCodePoints) { int currentIndex = from; boolean waitingHighSurrogate = false; final int N = cs.length(); if (currentIndex < 0 || N < currentIndex) { return INVALID_INDEX; // The starting point is out of range. } if (numCodePoints < 0) { return INVALID_INDEX; // Basically this should not happen. } int remainingCodePoints = numCodePoints; while (true) { if (remainingCodePoints == 0) { return currentIndex; // Reached to the requested length in code points. } --currentIndex; if (currentIndex < 0) { if (waitingHighSurrogate) { return INVALID_INDEX; // An invalid surrogate pair is found. } return 0; // Reached to the beginning of the text w/o any invalid surrogate pair. } final char c = cs.charAt(currentIndex); if (waitingHighSurrogate) { if (!java.lang.Character.isHighSurrogate(c)) { return INVALID_INDEX; // An invalid surrogate pair is found. } waitingHighSurrogate = false; --remainingCodePoints; continue; } if (!java.lang.Character.isSurrogate(c)) { --remainingCodePoints; continue; } if (java.lang.Character.isHighSurrogate(c)) { return INVALID_INDEX; // A invalid surrogate pair is found. } waitingHighSurrogate = true; } } private static int findIndexForward(final CharSequence cs, final int from, final int numCodePoints) { int currentIndex = from; boolean waitingLowSurrogate = false; final int N = cs.length(); if (currentIndex < 0 || N < currentIndex) { return INVALID_INDEX; // The starting point is out of range. } if (numCodePoints < 0) { return INVALID_INDEX; // Basically this should not happen. } int remainingCodePoints = numCodePoints; while (true) { if (remainingCodePoints == 0) { return currentIndex; // Reached to the requested length in code points. } if (currentIndex >= N) { if (waitingLowSurrogate) { return INVALID_INDEX; // An invalid surrogate pair is found. } return N; // Reached to the end of the text w/o any invalid surrogate pair. } final char c = cs.charAt(currentIndex); if (waitingLowSurrogate) { if (!java.lang.Character.isLowSurrogate(c)) { return INVALID_INDEX; // An invalid surrogate pair is found. } --remainingCodePoints; waitingLowSurrogate = false; ++currentIndex; continue; } if (!java.lang.Character.isSurrogate(c)) { --remainingCodePoints; ++currentIndex; continue; } if (java.lang.Character.isLowSurrogate(c)) { return INVALID_INDEX; // A invalid surrogate pair is found. } waitingLowSurrogate = true; ++currentIndex; } } /** * The default implementation performs the deletion around the current selection position of the * editable text. * @param beforeLength The number of characters before the cursor to be deleted, in code points. * If this is greater than the number of existing characters between the beginning of the * text and the cursor, then this method does not fail but deletes all the characters in * that range. * @param afterLength The number of characters after the cursor to be deleted, in code points. * If this is greater than the number of existing characters between the cursor and * the end of the text, then this method does not fail but deletes all the characters in * that range. */ public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) { if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength + " / " + afterLength); final Editable content = getEditable(); if (content == null) return false; beginBatchEdit(); int a = Selection.getSelectionStart(content); int b = Selection.getSelectionEnd(content); if (a > b) { int tmp = a; a = b; b = tmp; } // Ignore the composing text. int ca = getComposingSpanStart(content); int cb = getComposingSpanEnd(content); if (cb < ca) { int tmp = ca; ca = cb; cb = tmp; } if (ca != -1 && cb != -1) { if (ca < a) a = ca; if (cb > b) b = cb; } if (a >= 0 && b >= 0) { final int start = findIndexBackward(content, a, Math.max(beforeLength, 0)); if (start != INVALID_INDEX) { final int end = findIndexForward(content, b, Math.max(afterLength, 0)); if (end != INVALID_INDEX) { final int numDeleteBefore = a - start; if (numDeleteBefore > 0) { content.delete(start, a); } final int numDeleteAfter = end - b; if (numDeleteAfter > 0) { content.delete(b - numDeleteBefore, end - numDeleteBefore); } } } // NOTE: You may think we should return false here if start and/or end is INVALID_INDEX, // but the truth is that IInputConnectionWrapper running in the middle of IPC calls // always returns true to the IME without waiting for the completion of this method as // IInputConnectionWrapper#isAtive() returns true. This is actually why some methods // including this method look like asynchronous calls from the IME. } endBatchEdit(); return true; } /** * The default implementation removes the composing state from the * current editable text. In addition, only if dummy mode, a key event is Loading core/java/android/view/inputmethod/InputConnection.java +27 −0 Original line number Diff line number Diff line Loading @@ -347,6 +347,33 @@ public interface InputConnection { */ public boolean deleteSurroundingText(int beforeLength, int afterLength); /** * A variant of {@link #deleteSurroundingText(int, int)}. Major differences are: * * <ul> * <li>The lengths are supplied in code points, not in Java chars or in glyphs.</> * <li>This method does nothing if there are one or more invalid surrogate pairs in the * requested range.</li> * </ul> * * <p><strong>Editor authors:</strong> In addition to the requirement in * {@link #deleteSurroundingText(int, int)}, make sure to do nothing when one ore more invalid * surrogate pairs are found in the requested range.</p> * * @see #deleteSurroundingText(int, int) * * @param beforeLength The number of characters before the cursor to be deleted, in code points. * If this is greater than the number of existing characters between the beginning of the * text and the cursor, then this method does not fail but deletes all the characters in * that range. * @param afterLength The number of characters after the cursor to be deleted, in code points. * If this is greater than the number of existing characters between the cursor and * the end of the text, then this method does not fail but deletes all the characters in * that range. * @return true on success, false if the input connection is no longer valid. */ public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength); /** * Replace the currently composing text with the given text, and * set the new cursor position. Any composing text set previously Loading Loading
api/current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -43411,6 +43411,7 @@ package android.view.inputmethod { method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public boolean commitText(java.lang.CharSequence, int); method public boolean deleteSurroundingText(int, int); method public boolean deleteSurroundingTextInCodePoints(int, int); method public boolean endBatchEdit(); method public boolean finishComposingText(); method public static int getComposingSpanEnd(android.text.Spannable); Loading Loading @@ -43576,6 +43577,7 @@ package android.view.inputmethod { method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public abstract boolean commitText(java.lang.CharSequence, int); method public abstract boolean deleteSurroundingText(int, int); method public abstract boolean deleteSurroundingTextInCodePoints(int, int); method public abstract boolean endBatchEdit(); method public abstract boolean finishComposingText(); method public abstract int getCursorCapsMode(int); Loading Loading @@ -43606,6 +43608,7 @@ package android.view.inputmethod { method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public boolean commitText(java.lang.CharSequence, int); method public boolean deleteSurroundingText(int, int); method public boolean deleteSurroundingTextInCodePoints(int, int); method public boolean endBatchEdit(); method public boolean finishComposingText(); method public int getCursorCapsMode(int);
api/system-current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -45807,6 +45807,7 @@ package android.view.inputmethod { method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public boolean commitText(java.lang.CharSequence, int); method public boolean deleteSurroundingText(int, int); method public boolean deleteSurroundingTextInCodePoints(int, int); method public boolean endBatchEdit(); method public boolean finishComposingText(); method public static int getComposingSpanEnd(android.text.Spannable); Loading Loading @@ -45972,6 +45973,7 @@ package android.view.inputmethod { method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public abstract boolean commitText(java.lang.CharSequence, int); method public abstract boolean deleteSurroundingText(int, int); method public abstract boolean deleteSurroundingTextInCodePoints(int, int); method public abstract boolean endBatchEdit(); method public abstract boolean finishComposingText(); method public abstract int getCursorCapsMode(int); Loading Loading @@ -46002,6 +46004,7 @@ package android.view.inputmethod { method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public boolean commitText(java.lang.CharSequence, int); method public boolean deleteSurroundingText(int, int); method public boolean deleteSurroundingTextInCodePoints(int, int); method public boolean endBatchEdit(); method public boolean finishComposingText(); method public int getCursorCapsMode(int);
api/test-current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -43427,6 +43427,7 @@ package android.view.inputmethod { method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public boolean commitText(java.lang.CharSequence, int); method public boolean deleteSurroundingText(int, int); method public boolean deleteSurroundingTextInCodePoints(int, int); method public boolean endBatchEdit(); method public boolean finishComposingText(); method public static int getComposingSpanEnd(android.text.Spannable); Loading Loading @@ -43592,6 +43593,7 @@ package android.view.inputmethod { method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public abstract boolean commitText(java.lang.CharSequence, int); method public abstract boolean deleteSurroundingText(int, int); method public abstract boolean deleteSurroundingTextInCodePoints(int, int); method public abstract boolean endBatchEdit(); method public abstract boolean finishComposingText(); method public abstract int getCursorCapsMode(int); Loading Loading @@ -43622,6 +43624,7 @@ package android.view.inputmethod { method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo); method public boolean commitText(java.lang.CharSequence, int); method public boolean deleteSurroundingText(int, int); method public boolean deleteSurroundingTextInCodePoints(int, int); method public boolean endBatchEdit(); method public boolean finishComposingText(); method public int getCursorCapsMode(int);
core/java/android/view/inputmethod/BaseInputConnection.java +162 −1 Original line number Diff line number Diff line Loading @@ -229,7 +229,7 @@ public class BaseInputConnection implements InputConnection { b = tmp; } // ignore the composing text. // Ignore the composing text. int ca = getComposingSpanStart(content); int cb = getComposingSpanEnd(content); if (cb < ca) { Loading Loading @@ -265,6 +265,167 @@ public class BaseInputConnection implements InputConnection { return true; } private static int INVALID_INDEX = -1; private static int findIndexBackward(final CharSequence cs, final int from, final int numCodePoints) { int currentIndex = from; boolean waitingHighSurrogate = false; final int N = cs.length(); if (currentIndex < 0 || N < currentIndex) { return INVALID_INDEX; // The starting point is out of range. } if (numCodePoints < 0) { return INVALID_INDEX; // Basically this should not happen. } int remainingCodePoints = numCodePoints; while (true) { if (remainingCodePoints == 0) { return currentIndex; // Reached to the requested length in code points. } --currentIndex; if (currentIndex < 0) { if (waitingHighSurrogate) { return INVALID_INDEX; // An invalid surrogate pair is found. } return 0; // Reached to the beginning of the text w/o any invalid surrogate pair. } final char c = cs.charAt(currentIndex); if (waitingHighSurrogate) { if (!java.lang.Character.isHighSurrogate(c)) { return INVALID_INDEX; // An invalid surrogate pair is found. } waitingHighSurrogate = false; --remainingCodePoints; continue; } if (!java.lang.Character.isSurrogate(c)) { --remainingCodePoints; continue; } if (java.lang.Character.isHighSurrogate(c)) { return INVALID_INDEX; // A invalid surrogate pair is found. } waitingHighSurrogate = true; } } private static int findIndexForward(final CharSequence cs, final int from, final int numCodePoints) { int currentIndex = from; boolean waitingLowSurrogate = false; final int N = cs.length(); if (currentIndex < 0 || N < currentIndex) { return INVALID_INDEX; // The starting point is out of range. } if (numCodePoints < 0) { return INVALID_INDEX; // Basically this should not happen. } int remainingCodePoints = numCodePoints; while (true) { if (remainingCodePoints == 0) { return currentIndex; // Reached to the requested length in code points. } if (currentIndex >= N) { if (waitingLowSurrogate) { return INVALID_INDEX; // An invalid surrogate pair is found. } return N; // Reached to the end of the text w/o any invalid surrogate pair. } final char c = cs.charAt(currentIndex); if (waitingLowSurrogate) { if (!java.lang.Character.isLowSurrogate(c)) { return INVALID_INDEX; // An invalid surrogate pair is found. } --remainingCodePoints; waitingLowSurrogate = false; ++currentIndex; continue; } if (!java.lang.Character.isSurrogate(c)) { --remainingCodePoints; ++currentIndex; continue; } if (java.lang.Character.isLowSurrogate(c)) { return INVALID_INDEX; // A invalid surrogate pair is found. } waitingLowSurrogate = true; ++currentIndex; } } /** * The default implementation performs the deletion around the current selection position of the * editable text. * @param beforeLength The number of characters before the cursor to be deleted, in code points. * If this is greater than the number of existing characters between the beginning of the * text and the cursor, then this method does not fail but deletes all the characters in * that range. * @param afterLength The number of characters after the cursor to be deleted, in code points. * If this is greater than the number of existing characters between the cursor and * the end of the text, then this method does not fail but deletes all the characters in * that range. */ public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) { if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength + " / " + afterLength); final Editable content = getEditable(); if (content == null) return false; beginBatchEdit(); int a = Selection.getSelectionStart(content); int b = Selection.getSelectionEnd(content); if (a > b) { int tmp = a; a = b; b = tmp; } // Ignore the composing text. int ca = getComposingSpanStart(content); int cb = getComposingSpanEnd(content); if (cb < ca) { int tmp = ca; ca = cb; cb = tmp; } if (ca != -1 && cb != -1) { if (ca < a) a = ca; if (cb > b) b = cb; } if (a >= 0 && b >= 0) { final int start = findIndexBackward(content, a, Math.max(beforeLength, 0)); if (start != INVALID_INDEX) { final int end = findIndexForward(content, b, Math.max(afterLength, 0)); if (end != INVALID_INDEX) { final int numDeleteBefore = a - start; if (numDeleteBefore > 0) { content.delete(start, a); } final int numDeleteAfter = end - b; if (numDeleteAfter > 0) { content.delete(b - numDeleteBefore, end - numDeleteBefore); } } } // NOTE: You may think we should return false here if start and/or end is INVALID_INDEX, // but the truth is that IInputConnectionWrapper running in the middle of IPC calls // always returns true to the IME without waiting for the completion of this method as // IInputConnectionWrapper#isAtive() returns true. This is actually why some methods // including this method look like asynchronous calls from the IME. } endBatchEdit(); return true; } /** * The default implementation removes the composing state from the * current editable text. In addition, only if dummy mode, a key event is Loading
core/java/android/view/inputmethod/InputConnection.java +27 −0 Original line number Diff line number Diff line Loading @@ -347,6 +347,33 @@ public interface InputConnection { */ public boolean deleteSurroundingText(int beforeLength, int afterLength); /** * A variant of {@link #deleteSurroundingText(int, int)}. Major differences are: * * <ul> * <li>The lengths are supplied in code points, not in Java chars or in glyphs.</> * <li>This method does nothing if there are one or more invalid surrogate pairs in the * requested range.</li> * </ul> * * <p><strong>Editor authors:</strong> In addition to the requirement in * {@link #deleteSurroundingText(int, int)}, make sure to do nothing when one ore more invalid * surrogate pairs are found in the requested range.</p> * * @see #deleteSurroundingText(int, int) * * @param beforeLength The number of characters before the cursor to be deleted, in code points. * If this is greater than the number of existing characters between the beginning of the * text and the cursor, then this method does not fail but deletes all the characters in * that range. * @param afterLength The number of characters after the cursor to be deleted, in code points. * If this is greater than the number of existing characters between the cursor and * the end of the text, then this method does not fail but deletes all the characters in * that range. * @return true on success, false if the input connection is no longer valid. */ public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength); /** * Replace the currently composing text with the given text, and * set the new cursor position. Any composing text set previously Loading