aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
authorJean Chalard <jchalard@google.com>2012-06-08 19:44:38 +0900
committerJean Chalard <jchalard@google.com>2012-06-08 20:04:09 +0900
commit02308bec632a5df23325c916bffec5def16b22b4 (patch)
treef1484c41e80772762e5cf019a207bc4c80c31bcb /java/src
parent5475b38328171a0841ae18074bd45380ec567e90 (diff)
downloadlatinime-02308bec632a5df23325c916bffec5def16b22b4.tar.gz
latinime-02308bec632a5df23325c916bffec5def16b22b4.tar.xz
latinime-02308bec632a5df23325c916bffec5def16b22b4.zip
Merge RichInputConnection with EditingUtils
Change-Id: I9982ff325bef56694402caef28a77683c52ccd71
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/latin/EditingUtils.java218
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java21
-rw-r--r--java/src/com/android/inputmethod/latin/ResearchLogger.java5
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java188
4 files changed, 192 insertions, 240 deletions
diff --git a/java/src/com/android/inputmethod/latin/EditingUtils.java b/java/src/com/android/inputmethod/latin/EditingUtils.java
deleted file mode 100644
index 479b3bf5a..000000000
--- a/java/src/com/android/inputmethod/latin/EditingUtils.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.inputmethod.latin;
-
-import android.view.inputmethod.ExtractedText;
-import android.view.inputmethod.ExtractedTextRequest;
-import android.view.inputmethod.InputConnection;
-
-import java.util.regex.Pattern;
-
-/**
- * Utility methods to deal with editing text through an InputConnection.
- */
-public class EditingUtils {
- /**
- * Number of characters we want to look back in order to identify the previous word
- */
- // Provision for a long word pair and a separator
- private static final int LOOKBACK_CHARACTER_NUM = BinaryDictionary.MAX_WORD_LENGTH * 2 + 1;
- private static final int INVALID_CURSOR_POSITION = -1;
-
- private EditingUtils() {
- // Unintentional empty constructor for singleton.
- }
-
- private static int getCursorPosition(InputConnection connection) {
- if (null == connection) return INVALID_CURSOR_POSITION;
- final ExtractedText extracted = connection.getExtractedText(new ExtractedTextRequest(), 0);
- if (extracted == null) {
- return INVALID_CURSOR_POSITION;
- }
- return extracted.startOffset + extracted.selectionStart;
- }
-
- /**
- * @param connection connection to the current text field.
- * @param separators characters which may separate words
- * @return the word that surrounds the cursor, including up to one trailing
- * separator. For example, if the field contains "he|llo world", where |
- * represents the cursor, then "hello " will be returned.
- */
- public static String getWordAtCursor(InputConnection connection, String separators) {
- // getWordRangeAtCursor returns null if the connection is null
- Range r = getWordRangeAtCursor(connection, separators, 0);
- return (r == null) ? null : r.mWord;
- }
-
- /**
- * Represents a range of text, relative to the current cursor position.
- */
- public static class Range {
- /** Characters before selection start */
- public final int mCharsBefore;
-
- /**
- * Characters after selection start, including one trailing word
- * separator.
- */
- public final int mCharsAfter;
-
- /** The actual characters that make up a word */
- public final String mWord;
-
- public Range(int charsBefore, int charsAfter, String word) {
- if (charsBefore < 0 || charsAfter < 0) {
- throw new IndexOutOfBoundsException();
- }
- this.mCharsBefore = charsBefore;
- this.mCharsAfter = charsAfter;
- this.mWord = word;
- }
- }
-
- /**
- * Returns the text surrounding the cursor.
- *
- * @param connection the InputConnection to the TextView
- * @param sep a string of characters that split words.
- * @param additionalPrecedingWordsCount the number of words before the current word that should
- * be included in the returned range
- * @return a range containing the text surrounding the cursor
- */
- public static Range getWordRangeAtCursor(InputConnection connection, String sep,
- int additionalPrecedingWordsCount) {
- if (connection == null || sep == null) {
- return null;
- }
- CharSequence before = connection.getTextBeforeCursor(1000, 0);
- CharSequence after = connection.getTextAfterCursor(1000, 0);
- if (before == null || after == null) {
- return null;
- }
-
- // Going backward, alternate skipping non-separators and separators until enough words
- // have been read.
- int start = before.length();
- boolean isStoppingAtWhitespace = true; // toggles to indicate what to stop at
- while (true) { // see comments below for why this is guaranteed to halt
- while (start > 0) {
- final int codePoint = Character.codePointBefore(before, start);
- if (isStoppingAtWhitespace == isSeparator(codePoint, sep)) {
- break; // inner loop
- }
- --start;
- if (Character.isSupplementaryCodePoint(codePoint)) {
- --start;
- }
- }
- // isStoppingAtWhitespace is true every other time through the loop,
- // so additionalPrecedingWordsCount is guaranteed to become < 0, which
- // guarantees outer loop termination
- if (isStoppingAtWhitespace && (--additionalPrecedingWordsCount < 0)) {
- break; // outer loop
- }
- isStoppingAtWhitespace = !isStoppingAtWhitespace;
- }
-
- // Find last word separator after the cursor
- int end = -1;
- while (++end < after.length()) {
- final int codePoint = Character.codePointAt(after, end);
- if (isSeparator(codePoint, sep)) {
- break;
- }
- if (Character.isSupplementaryCodePoint(codePoint)) {
- ++end;
- }
- }
-
- int cursor = getCursorPosition(connection);
- if (start >= 0 && cursor + end <= after.length() + before.length()) {
- String word = before.toString().substring(start, before.length())
- + after.toString().substring(0, end);
- return new Range(before.length() - start, end, word);
- }
-
- return null;
- }
-
- private static boolean isSeparator(int code, String sep) {
- return sep.indexOf(code) != -1;
- }
-
- private static final Pattern spaceRegex = Pattern.compile("\\s+");
-
- public static CharSequence getPreviousWord(InputConnection connection,
- String sentenceSeperators) {
- //TODO: Should fix this. This could be slow!
- if (null == connection) return null;
- CharSequence prev = connection.getTextBeforeCursor(LOOKBACK_CHARACTER_NUM, 0);
- return getPreviousWord(prev, sentenceSeperators);
- }
-
- // Get the word before the whitespace preceding the non-whitespace preceding the cursor.
- // Also, it won't return words that end in a separator.
- // Example :
- // "abc def|" -> abc
- // "abc def |" -> abc
- // "abc def. |" -> abc
- // "abc def . |" -> def
- // "abc|" -> null
- // "abc |" -> null
- // "abc. def|" -> null
- public static CharSequence getPreviousWord(CharSequence prev, String sentenceSeperators) {
- if (prev == null) return null;
- String[] w = spaceRegex.split(prev);
-
- // If we can't find two words, or we found an empty word, return null.
- if (w.length < 2 || w[w.length - 2].length() <= 0) return null;
-
- // If ends in a separator, return null
- char lastChar = w[w.length - 2].charAt(w[w.length - 2].length() - 1);
- if (sentenceSeperators.contains(String.valueOf(lastChar))) return null;
-
- return w[w.length - 2];
- }
-
- public static CharSequence getThisWord(InputConnection connection, String sentenceSeperators) {
- if (null == connection) return null;
- final CharSequence prev = connection.getTextBeforeCursor(LOOKBACK_CHARACTER_NUM, 0);
- return getThisWord(prev, sentenceSeperators);
- }
-
- // Get the word immediately before the cursor, even if there is whitespace between it and
- // the cursor - but not if there is punctuation.
- // Example :
- // "abc def|" -> def
- // "abc def |" -> def
- // "abc def. |" -> null
- // "abc def . |" -> null
- public static CharSequence getThisWord(CharSequence prev, String sentenceSeperators) {
- if (prev == null) return null;
- String[] w = spaceRegex.split(prev);
-
- // No word : return null
- if (w.length < 1 || w[w.length - 1].length() <= 0) return null;
-
- // If ends in a separator, return null
- char lastChar = w[w.length - 1].charAt(w[w.length - 1].length() - 1);
- if (sentenceSeperators.contains(String.valueOf(lastChar))) return null;
-
- return w[w.length - 1];
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 5b499e4be..656f6d7b3 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -783,7 +783,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
ResearchLogger.latinIME_onUpdateSelection(mLastSelectionStart, mLastSelectionEnd,
oldSelStart, oldSelEnd, newSelStart, newSelEnd, composingSpanStart,
composingSpanEnd, mExpectingUpdateSelection,
- expectingUpdateSelectionFromLogger, getCurrentInputConnection());
+ expectingUpdateSelectionFromLogger, mConnection);
if (expectingUpdateSelectionFromLogger) {
return;
}
@@ -1760,11 +1760,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
// TODO: May need a better way of retrieving previous word
- final CharSequence prevWord;
- // TODO: move getPreviousWord to AutoInputConnection
- prevWord = EditingUtils.getPreviousWord(mConnection.getInputConnection(),
- mSettingsValues.mWordSeparators);
-
+ final CharSequence prevWord = mConnection.getPreviousWord(mSettingsValues.mWordSeparators);
final CharSequence typedWord = mWordComposer.getTypedWord();
// getSuggestedWords handles gracefully a null value of prevWord
final SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer,
@@ -1993,8 +1989,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final SuggestedWords suggestedWords;
if (mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
- final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(),
- mSettingsValues.mWordSeparators);
+ final CharSequence prevWord = mConnection.getThisWord(mSettingsValues.mWordSeparators);
if (!TextUtils.isEmpty(prevWord)) {
suggestedWords = mSuggest.getBigramPredictions(prevWord);
} else {
@@ -2031,10 +2026,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
if (mUserHistoryDictionary != null) {
- final CharSequence prevWord;
- // TODO: move getPreviousWord to AutoInputConnection
- prevWord = EditingUtils.getPreviousWord(mConnection.getInputConnection(),
- mSettingsValues.mWordSeparators);
+ final CharSequence prevWord
+ = mConnection.getPreviousWord(mSettingsValues.mWordSeparators);
final String secondWord;
if (mWordComposer.isAutoCapitalized() && !mWordComposer.isMostlyCaps()) {
secondWord = suggestion.toString().toLowerCase(
@@ -2093,9 +2086,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Bail out if word before cursor is 0-length or a single non letter (like an apostrophe)
// Example: " -|" gets rejected here but "e-|" and "e|" are okay
- // TODO: move getWordAtCursor inside AutoInputConnection
- CharSequence word = EditingUtils.getWordAtCursor(mConnection.getInputConnection(),
- mSettingsValues.mWordSeparators);
+ CharSequence word = mConnection.getWordAtCursor(mSettingsValues.mWordSeparators);
// We don't suggest on leading single quotes, so we have to remove them from the word if
// it starts with single quotes.
while (!TextUtils.isEmpty(word) && Keyboard.CODE_SINGLE_QUOTE == word.charAt(0)) {
diff --git a/java/src/com/android/inputmethod/latin/ResearchLogger.java b/java/src/com/android/inputmethod/latin/ResearchLogger.java
index a7e7738d8..f27d07074 100644
--- a/java/src/com/android/inputmethod/latin/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/latin/ResearchLogger.java
@@ -612,12 +612,13 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final int lastSelectionEnd, final int oldSelStart, final int oldSelEnd,
final int newSelStart, final int newSelEnd, final int composingSpanStart,
final int composingSpanEnd, final boolean expectingUpdateSelection,
- final boolean expectingUpdateSelectionFromLogger, final InputConnection connection) {
+ final boolean expectingUpdateSelectionFromLogger,
+ final RichInputConnection connection) {
final Object[] values = {
lastSelectionStart, lastSelectionEnd, oldSelStart, oldSelEnd, newSelStart,
newSelEnd, composingSpanStart, composingSpanEnd, expectingUpdateSelection,
expectingUpdateSelectionFromLogger,
- EditingUtils.getWordRangeAtCursor(connection, WHITESPACE_SEPARATORS, 1).mWord
+ connection.getWordRangeAtCursor(WHITESPACE_SEPARATORS, 1).mWord
};
getInstance().writeEvent(EVENTKEYS_LATINIME_ONUPDATESELECTION, values);
}
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 449d08e9b..c9ee09396 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -20,14 +20,23 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
+import java.util.regex.Pattern;
+
/**
* Wrapper for InputConnection to simplify interaction
*/
public class RichInputConnection {
private static final String TAG = RichInputConnection.class.getSimpleName();
private static final boolean DBG = false;
+ // Provision for a long word pair and a separator
+ private static final int LOOKBACK_CHARACTER_NUM = BinaryDictionary.MAX_WORD_LENGTH * 2 + 1;
+ private static final Pattern spaceRegex = Pattern.compile("\\s+");
+ private static final int INVALID_CURSOR_POSITION = -1;
+
InputConnection mIC;
int mNestLevel;
public RichInputConnection() {
@@ -35,11 +44,6 @@ public class RichInputConnection {
mNestLevel = 0;
}
- // TODO: remove this method - the whole point of this class is void if mIC is escaping
- public InputConnection getInputConnection() {
- return mIC;
- }
-
public void beginBatchEdit(final InputConnection newInputConnection) {
if (++mNestLevel == 1) {
mIC = newInputConnection;
@@ -119,4 +123,178 @@ public class RichInputConnection {
if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
if (null != mIC) mIC.commitCompletion(completionInfo);
}
+
+ public CharSequence getPreviousWord(final String sentenceSeperators) {
+ //TODO: Should fix this. This could be slow!
+ if (null == mIC) return null;
+ CharSequence prev = mIC.getTextBeforeCursor(LOOKBACK_CHARACTER_NUM, 0);
+ return getPreviousWord(prev, sentenceSeperators);
+ }
+
+ /**
+ * Represents a range of text, relative to the current cursor position.
+ */
+ public static class Range {
+ /** Characters before selection start */
+ public final int mCharsBefore;
+
+ /**
+ * Characters after selection start, including one trailing word
+ * separator.
+ */
+ public final int mCharsAfter;
+
+ /** The actual characters that make up a word */
+ public final String mWord;
+
+ public Range(int charsBefore, int charsAfter, String word) {
+ if (charsBefore < 0 || charsAfter < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ this.mCharsBefore = charsBefore;
+ this.mCharsAfter = charsAfter;
+ this.mWord = word;
+ }
+ }
+
+ private static boolean isSeparator(int code, String sep) {
+ return sep.indexOf(code) != -1;
+ }
+
+ // Get the word before the whitespace preceding the non-whitespace preceding the cursor.
+ // Also, it won't return words that end in a separator.
+ // Example :
+ // "abc def|" -> abc
+ // "abc def |" -> abc
+ // "abc def. |" -> abc
+ // "abc def . |" -> def
+ // "abc|" -> null
+ // "abc |" -> null
+ // "abc. def|" -> null
+ public static CharSequence getPreviousWord(CharSequence prev, String sentenceSeperators) {
+ if (prev == null) return null;
+ String[] w = spaceRegex.split(prev);
+
+ // If we can't find two words, or we found an empty word, return null.
+ if (w.length < 2 || w[w.length - 2].length() <= 0) return null;
+
+ // If ends in a separator, return null
+ char lastChar = w[w.length - 2].charAt(w[w.length - 2].length() - 1);
+ if (sentenceSeperators.contains(String.valueOf(lastChar))) return null;
+
+ return w[w.length - 2];
+ }
+
+ public CharSequence getThisWord(String sentenceSeperators) {
+ if (null == mIC) return null;
+ final CharSequence prev = mIC.getTextBeforeCursor(LOOKBACK_CHARACTER_NUM, 0);
+ return getThisWord(prev, sentenceSeperators);
+ }
+
+ // Get the word immediately before the cursor, even if there is whitespace between it and
+ // the cursor - but not if there is punctuation.
+ // Example :
+ // "abc def|" -> def
+ // "abc def |" -> def
+ // "abc def. |" -> null
+ // "abc def . |" -> null
+ public static CharSequence getThisWord(CharSequence prev, String sentenceSeperators) {
+ if (prev == null) return null;
+ String[] w = spaceRegex.split(prev);
+
+ // No word : return null
+ if (w.length < 1 || w[w.length - 1].length() <= 0) return null;
+
+ // If ends in a separator, return null
+ char lastChar = w[w.length - 1].charAt(w[w.length - 1].length() - 1);
+ if (sentenceSeperators.contains(String.valueOf(lastChar))) return null;
+
+ return w[w.length - 1];
+ }
+
+ /**
+ * @param separators characters which may separate words
+ * @return the word that surrounds the cursor, including up to one trailing
+ * separator. For example, if the field contains "he|llo world", where |
+ * represents the cursor, then "hello " will be returned.
+ */
+ public String getWordAtCursor(String separators) {
+ // getWordRangeAtCursor returns null if the connection is null
+ Range r = getWordRangeAtCursor(separators, 0);
+ return (r == null) ? null : r.mWord;
+ }
+
+ private int getCursorPosition() {
+ if (null == mIC) return INVALID_CURSOR_POSITION;
+ final ExtractedText extracted = mIC.getExtractedText(new ExtractedTextRequest(), 0);
+ if (extracted == null) {
+ return INVALID_CURSOR_POSITION;
+ }
+ return extracted.startOffset + extracted.selectionStart;
+ }
+
+ /**
+ * Returns the text surrounding the cursor.
+ *
+ * @param sep a string of characters that split words.
+ * @param additionalPrecedingWordsCount the number of words before the current word that should
+ * be included in the returned range
+ * @return a range containing the text surrounding the cursor
+ */
+ public Range getWordRangeAtCursor(String sep, int additionalPrecedingWordsCount) {
+ if (mIC == null || sep == null) {
+ return null;
+ }
+ CharSequence before = mIC.getTextBeforeCursor(1000, 0);
+ CharSequence after = mIC.getTextAfterCursor(1000, 0);
+ if (before == null || after == null) {
+ return null;
+ }
+
+ // Going backward, alternate skipping non-separators and separators until enough words
+ // have been read.
+ int start = before.length();
+ boolean isStoppingAtWhitespace = true; // toggles to indicate what to stop at
+ while (true) { // see comments below for why this is guaranteed to halt
+ while (start > 0) {
+ final int codePoint = Character.codePointBefore(before, start);
+ if (isStoppingAtWhitespace == isSeparator(codePoint, sep)) {
+ break; // inner loop
+ }
+ --start;
+ if (Character.isSupplementaryCodePoint(codePoint)) {
+ --start;
+ }
+ }
+ // isStoppingAtWhitespace is true every other time through the loop,
+ // so additionalPrecedingWordsCount is guaranteed to become < 0, which
+ // guarantees outer loop termination
+ if (isStoppingAtWhitespace && (--additionalPrecedingWordsCount < 0)) {
+ break; // outer loop
+ }
+ isStoppingAtWhitespace = !isStoppingAtWhitespace;
+ }
+
+ // Find last word separator after the cursor
+ int end = -1;
+ while (++end < after.length()) {
+ final int codePoint = Character.codePointAt(after, end);
+ if (isSeparator(codePoint, sep)) {
+ break;
+ }
+ if (Character.isSupplementaryCodePoint(codePoint)) {
+ ++end;
+ }
+ }
+
+ int cursor = getCursorPosition();
+ if (start >= 0 && cursor + end <= after.length() + before.length()) {
+ String word = before.toString().substring(start, before.length())
+ + after.toString().substring(0, end);
+ return new Range(before.length() - start, end, word);
+ }
+
+ return null;
+ }
+
}