diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin/RichInputConnection.java')
-rw-r--r-- | java/src/com/android/inputmethod/latin/RichInputConnection.java | 79 |
1 files changed, 53 insertions, 26 deletions
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index 744b0321a..834f747d9 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -19,6 +19,7 @@ package com.android.inputmethod.latin; import android.graphics.Color; import android.inputmethodservice.InputMethodService; import android.os.Build; +import android.os.Bundle; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; @@ -33,16 +34,18 @@ import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import com.android.inputmethod.compat.InputConnectionCompatUtils; +import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; +import com.android.inputmethod.latin.inputlogic.PrivateCommandPerformer; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.utils.CapsModeUtils; import com.android.inputmethod.latin.utils.DebugLogUtils; -import com.android.inputmethod.latin.utils.PrevWordsInfoUtils; +import com.android.inputmethod.latin.utils.NgramContextUtils; import com.android.inputmethod.latin.utils.ScriptUtils; import com.android.inputmethod.latin.utils.SpannableStringUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.TextRange; -import java.util.Arrays; +import javax.annotation.Nonnull; /** * Enrichment class for InputConnection to simplify interaction and add functionality. @@ -52,7 +55,7 @@ import java.util.Arrays; * all the time to find out what text is in the buffer, when we need it to determine caps mode * for example. */ -public final class RichInputConnection { +public final class RichInputConnection implements PrivateCommandPerformer { private static final String TAG = RichInputConnection.class.getSimpleName(); private static final boolean DBG = false; private static final boolean DEBUG_PREVIOUS_TEXT = false; @@ -89,7 +92,7 @@ public final class RichInputConnection { /** * This variable is a temporary object used in - * {@link #commitTextWithBackgroundColor(CharSequence, int, int)} to avoid object creation. + * {@link #commitTextWithBackgroundColor(CharSequence,int,int,int)} to avoid object creation. */ private SpannableStringBuilder mTempObjectForCommitText = new SpannableStringBuilder(); /** @@ -149,9 +152,8 @@ public final class RichInputConnection { } else { if (DBG) { throw new RuntimeException("Nest level too deep"); - } else { - Log.e(TAG, "Nest level too deep : " + mNestLevel); } + Log.e(TAG, "Nest level too deep : " + mNestLevel); } if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); @@ -349,10 +351,9 @@ public final class RichInputConnection { // If we have some composing text and a space before, then we should have // MODE_CHARACTERS and MODE_WORDS on. return (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_WORDS) & inputType; - } else { - // We have some composing text - we should be in MODE_CHARACTERS only. - return TextUtils.CAP_MODE_CHARACTERS & inputType; } + // We have some composing text - we should be in MODE_CHARACTERS only. + return TextUtils.CAP_MODE_CHARACTERS & inputType; } // TODO: this will generally work, but there may be cases where the buffer contains SOME // information but not enough to determine the caps mode accurately. This may happen after @@ -367,7 +368,9 @@ public final class RichInputConnection { } // This never calls InputConnection#getCapsMode - in fact, it's a static method that // never blocks or initiates IPC. - return CapsModeUtils.getCapsMode(mCommittedTextBeforeComposingText, inputType, + // TODO: don't call #toString() here. Instead, all accesses to + // mCommittedTextBeforeComposingText should be done on the main thread. + return CapsModeUtils.getCapsMode(mCommittedTextBeforeComposingText.toString(), inputType, spacingAndPunctuations, hasSpaceBefore); } @@ -593,11 +596,12 @@ public final class RichInputConnection { } @SuppressWarnings("unused") - public PrevWordsInfo getPrevWordsInfoFromNthPreviousWord( + @Nonnull + public NgramContext getNgramContextFromNthPreviousWord( final SpacingAndPunctuations spacingAndPunctuations, final int n) { mIC = mParent.getCurrentInputConnection(); if (null == mIC) { - return PrevWordsInfo.EMPTY_PREV_WORDS_INFO; + return NgramContext.EMPTY_PREV_WORDS_INFO; } final CharSequence prev = getTextBeforeCursor(LOOKBACK_CHARACTER_NUM, 0); if (DEBUG_PREVIOUS_TEXT && null != prev) { @@ -618,14 +622,10 @@ public final class RichInputConnection { } } } - return PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( + return NgramContextUtils.getNgramContextFromNthPreviousWord( prev, spacingAndPunctuations, n); } - private static boolean isSeparator(final int code, final int[] sortedSeparators) { - return Arrays.binarySearch(sortedSeparators, code) >= 0; - } - private static boolean isPartOfCompositionForScript(final int codePoint, final SpacingAndPunctuations spacingAndPunctuations, final int scriptId) { // We always consider word connectors part of compositions. @@ -740,17 +740,19 @@ public final class RichInputConnection { return TextUtils.equals(text, beforeText); } - public boolean revertDoubleSpacePeriod() { + public boolean revertDoubleSpacePeriod(final SpacingAndPunctuations spacingAndPunctuations) { if (DEBUG_BATCH_NESTING) checkBatchEdit(); // Here we test whether we indeed have a period and a space before us. This should not // be needed, but it's there just in case something went wrong. final CharSequence textBeforeCursor = getTextBeforeCursor(2, 0); - if (!TextUtils.equals(Constants.STRING_PERIOD_AND_SPACE, textBeforeCursor)) { + if (!TextUtils.equals(spacingAndPunctuations.mSentenceSeparatorAndSpace, + textBeforeCursor)) { // Theoretically we should not be coming here if there isn't ". " before the // cursor, but the application may be changing the text while we are typing, so // anything goes. We should not crash. - Log.d(TAG, "Tried to revert double-space combo but we didn't find " - + "\"" + Constants.STRING_PERIOD_AND_SPACE + "\" just before the cursor."); + Log.d(TAG, "Tried to revert double-space combo but we didn't find \"" + + spacingAndPunctuations.mSentenceSeparatorAndSpace + + "\" just before the cursor."); return false; } // Double-space results in ". ". A backspace to cancel this should result in a single @@ -847,17 +849,32 @@ public final class RichInputConnection { /** * Try to get the text from the editor to expose lies the framework may have been - * telling us. Concretely, when the device rotates, the frameworks tells us about where the - * cursor used to be initially in the editor at the time it first received the focus; this + * telling us. Concretely, when the device rotates and when the keyboard reopens in the same + * text field after having been closed with the back key, the frameworks tells us about where + * the cursor used to be initially in the editor at the time it first received the focus; this * may be completely different from the place it is upon rotation. Since we don't have any * means to get the real value, try at least to ask the text view for some characters and * detect the most damaging cases: when the cursor position is declared to be much smaller * than it really is. */ public void tryFixLyingCursorPosition() { + mIC = mParent.getCurrentInputConnection(); final CharSequence textBeforeCursor = getTextBeforeCursor( Constants.EDITOR_CONTENTS_CACHE_SIZE, 0); - if (null == textBeforeCursor) { + final CharSequence selectedText = null == mIC ? null : mIC.getSelectedText(0 /* flags */); + if (null == textBeforeCursor || + (!TextUtils.isEmpty(selectedText) && mExpectedSelEnd == mExpectedSelStart)) { + // If textBeforeCursor is null, we have no idea what kind of text field we have or if + // thinking about the "cursor position" actually makes any sense. In this case we + // remember a meaningless cursor position. Contrast this with an empty string, which is + // valid and should mean the cursor is at the start of the text. + // Also, if we expect we don't have a selection but we DO have non-empty selected text, + // then the framework lied to us about the cursor position. In this case, we should just + // revert to the most basic behavior possible for the next action (backspace in + // particular comes to mind), so we remember a meaningless cursor position which should + // result in degraded behavior from the next input. + // Interestingly, in either case, chances are any action the user takes next will result + // in a call to onUpdateSelection, which should set things right. mExpectedSelStart = mExpectedSelEnd = Constants.NOT_A_CURSOR_POSITION; } else { final int textLength = textBeforeCursor.length(); @@ -880,6 +897,15 @@ public final class RichInputConnection { } } + @Override + public boolean performPrivateCommand(final String action, final Bundle data) { + mIC = mParent.getCurrentInputConnection(); + if (mIC == null) { + return false; + } + return mIC.performPrivateCommand(action, data); + } + public int getExpectedSelectionStart() { return mExpectedSelStart; } @@ -949,7 +975,8 @@ public final class RichInputConnection { /** * @return {@code true} if the application reported that the monitor mode of - * {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} is currently enabled. + * {@link InputMethodService#onUpdateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo)} + * is currently enabled. */ public boolean isCursorAnchorInfoMonitorEnabled() { return mCursorAnchorInfoMonitorEnabled; |