From d1f463eacfaac31a999f7eb1ecaa1668ed3038d4 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 27 Dec 2013 20:58:32 +0900 Subject: [PATCH] [IL69] Oust Keyboard from WordComposer#setComposingWord Bug: 8636060 Change-Id: I624a45500603dfad355ee3b8b794b2d895219c0b --- .../android/inputmethod/latin/LatinIME.java | 26 ++++++++++ .../inputmethod/latin/WordComposer.java | 17 ++++--- .../latin/inputlogic/InputLogic.java | 15 +++--- .../AndroidWordLevelSpellCheckerSession.java | 6 ++- .../latin/utils/CoordinateUtils.java | 41 +++++++++++++++- .../inputmethod/latin/WordComposerTests.java | 49 ++++++++++++------- tools/dicttool/Android.mk | 1 + 7 files changed, 120 insertions(+), 35 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 97fa90eec..21aefd3ab 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -59,6 +59,7 @@ import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.compat.InputMethodServiceCompatUtils; import com.android.inputmethod.dictionarypack.DictionaryPackConstants; +import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardActionListener; import com.android.inputmethod.keyboard.KeyboardId; @@ -79,6 +80,7 @@ import com.android.inputmethod.latin.suggestions.SuggestionStripView; import com.android.inputmethod.latin.utils.ApplicationUtils; import com.android.inputmethod.latin.utils.CapsModeUtils; import com.android.inputmethod.latin.utils.CompletionInfoUtils; +import com.android.inputmethod.latin.utils.CoordinateUtils; import com.android.inputmethod.latin.utils.IntentUtils; import com.android.inputmethod.latin.utils.JniUtils; import com.android.inputmethod.latin.utils.LatinImeLoggerUtils; @@ -1199,6 +1201,30 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return mSubtypeSwitcher.getCurrentSubtypeLocale(); } + /** + * @param codePoints code points to get coordinates for. + * @return x,y coordinates for this keyboard, as a flattened array. + */ + public int[] getCoordinatesForCurrentKeyboard(final int[] codePoints) { + return getCoordinatesForKeyboard(codePoints, mKeyboardSwitcher.getKeyboard()); + } + + public static int[] getCoordinatesForKeyboard(final int[] codePoints, final Keyboard keyboard) { + final int length = codePoints.length; + final int[] coordinates = CoordinateUtils.newCoordinateArray(length); + Key key; + for (int i = 0; i < length; ++i) { + if (keyboard != null && (key = keyboard.getKey(codePoints[i])) != null) { + CoordinateUtils.setXYInArray(coordinates, i, + key.getX() + key.getWidth() / 2, key.getY() + key.getHeight() / 2); + } else { + CoordinateUtils.setXYInArray(coordinates, i, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + } + } + return coordinates; + } + // Callback for the {@link SuggestionStripView}, to call when the "add to dictionary" hint is // pressed. @Override diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index a0e605625..0495a1e75 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -19,6 +19,7 @@ package com.android.inputmethod.latin; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.latin.utils.CoordinateUtils; import com.android.inputmethod.latin.utils.StringUtils; import java.util.Arrays; @@ -295,18 +296,20 @@ public final class WordComposer { /** * Set the currently composing word to the one passed as an argument. * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. - * @param word the char sequence to set as the composing word. + * @param codePoints the code points to set as the composing word. + * @param coordinates the x, y coordinates of the key in the CoordinateUtils format * @param previousWord the previous word, to use as context for suggestions. Can be null if * the context is nil (typically, at start of text). * @param keyboard the keyboard this is typed on, for coordinate info/proximity. */ - public void setComposingWord(final CharSequence word, final CharSequence previousWord, - final Keyboard keyboard) { + // TODO[IL]: the Keyboard argument is now unused. Remove it. + public void setComposingWord(final int[] codePoints, final int[] coordinates, + final CharSequence previousWord, final Keyboard keyboard) { reset(); - final int length = word.length(); - for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) { - final int codePoint = Character.codePointAt(word, i); - addKeyInfo(codePoint, keyboard); + final int length = codePoints.length; + for (int i = 0; i < length; ++i) { + add(codePoints[i], CoordinateUtils.xFromArray(coordinates, i), + CoordinateUtils.yFromArray(coordinates, i)); } mIsResumed = true; mPreviousWordForSuggestion = null == previousWord ? null : previousWord.toString(); diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index c417ae793..c715cb350 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -28,7 +28,6 @@ import android.view.inputmethod.EditorInfo; import com.android.inputmethod.compat.SuggestionSpanUtils; import com.android.inputmethod.event.EventInterpreter; -import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.Dictionary; @@ -1087,7 +1086,9 @@ public final class InputLogic { } } } - mWordComposer.setComposingWord(typedWord, + final int[] codePoints = StringUtils.toCodePointArray(typedWord); + mWordComposer.setComposingWord(codePoints, + mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), getNthPreviousWordForSuggestion(settingsValues.mSpacingAndPunctuations, // We want the previous word for suggestion. If we have chars in the word // before the cursor, then we want the word before that, hence 2; otherwise, @@ -1177,8 +1178,8 @@ public final class InputLogic { previousWord, committedWord.toString()); } } - final SpannableString textToCommit = - new SpannableString(originallyTypedWord + mLastComposedWord.mSeparatorString); + final String stringToCommit = originallyTypedWord + mLastComposedWord.mSeparatorString; + final SpannableString textToCommit = new SpannableString(stringToCommit); if (committedWord instanceof SpannableString) { final int lastCharIndex = textToCommit.length() - 1; // Add the auto-correction to the list of suggestions. @@ -1210,8 +1211,10 @@ public final class InputLogic { } else { // For languages without spaces, we revert the typed string but the cursor is flush // with the typed word, so we need to resume suggestions right away. - mWordComposer.setComposingWord(textToCommit, previousWord, - keyboardSwitcher.getKeyboard()); + final int[] codePoints = StringUtils.toCodePointArray(stringToCommit); + mWordComposer.setComposingWord(codePoints, + mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), + previousWord, keyboardSwitcher.getKeyboard()); mConnection.setComposingText(textToCommit, 1); } if (settingsValues.mIsInternal) { diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java index 98a0cfaa7..04ef718b2 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java @@ -30,6 +30,7 @@ import android.view.textservice.TextInfo; import com.android.inputmethod.compat.SuggestionsInfoCompatUtils; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.WordComposer; import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService.SuggestionsGatherer; @@ -312,7 +313,10 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { false /* reportAsTypo */); } final WordComposer composer = new WordComposer(); - composer.setComposingWord(text, null /* previousWord */, dictInfo.mKeyboard); + final int[] codePoints = StringUtils.toCodePointArray(text); + composer.setComposingWord(codePoints, + LatinIME.getCoordinatesForKeyboard(codePoints, dictInfo.mKeyboard), + null /* previousWord */, dictInfo.mKeyboard); // TODO: make a spell checker option to block offensive words or not final ArrayList suggestions = dictInfo.mDictionary.getSuggestions(composer, prevWord, diff --git a/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java b/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java index 72f2cd2d9..91a63501a 100644 --- a/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java @@ -16,17 +16,19 @@ package com.android.inputmethod.latin.utils; +import java.util.Arrays; + public final class CoordinateUtils { private static final int INDEX_X = 0; private static final int INDEX_Y = 1; - private static final int ARRAY_SIZE = INDEX_Y + 1; + private static final int ELEMENT_SIZE = INDEX_Y + 1; private CoordinateUtils() { // This utility class is not publicly instantiable. } public static int[] newInstance() { - return new int[ARRAY_SIZE]; + return new int[ELEMENT_SIZE]; } public static int x(final int[] coords) { @@ -46,4 +48,39 @@ public final class CoordinateUtils { destination[INDEX_X] = source[INDEX_X]; destination[INDEX_Y] = source[INDEX_Y]; } + + public static int[] newCoordinateArray(final int arraySize) { + return new int[ELEMENT_SIZE * arraySize]; + } + + public static int xFromArray(final int[] coordsArray, final int index) { + return coordsArray[ELEMENT_SIZE * index + INDEX_X]; + } + + public static int yFromArray(final int[] coordsArray, final int index) { + return coordsArray[ELEMENT_SIZE * index + INDEX_Y]; + } + + public static int[] coordinateFromArray(final int[] coordsArray, final int index) { + final int baseIndex = ELEMENT_SIZE * index; + return Arrays.copyOfRange(coordsArray, baseIndex, baseIndex + ELEMENT_SIZE); + } + + public static void setXYInArray(final int[] coordsArray, final int index, + final int x, final int y) { + final int baseIndex = ELEMENT_SIZE * index; + coordsArray[baseIndex + INDEX_X] = x; + coordsArray[baseIndex + INDEX_Y] = y; + } + + public static void setCoordinateInArray(final int[] coordsArray, final int index, + final int[] coords) { + final int baseIndex = ELEMENT_SIZE * index; + coordsArray[baseIndex + INDEX_X] = coords[INDEX_X]; + coordsArray[baseIndex + INDEX_Y] = coords[INDEX_Y]; + } + + public static void copyArray(final int[] destination, final int[] source) { + System.arraycopy(source, 0, destination, 0, source.length); + } } diff --git a/tests/src/com/android/inputmethod/latin/WordComposerTests.java b/tests/src/com/android/inputmethod/latin/WordComposerTests.java index 1336c6d1a..eb40c4c4a 100644 --- a/tests/src/com/android/inputmethod/latin/WordComposerTests.java +++ b/tests/src/com/android/inputmethod/latin/WordComposerTests.java @@ -19,6 +19,8 @@ package com.android.inputmethod.latin; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; +import com.android.inputmethod.latin.utils.StringUtils; + /** * Unit tests for WordComposer. */ @@ -33,8 +35,12 @@ public class WordComposerTests extends AndroidTestCase { // in UTF-16, whereas those outside the BMP need 4 bytes. // http://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane final String STR_WITHIN_BMP = "abcdef"; + final int[] CODEPOINTS_WITHIN_BMP = StringUtils.toCodePointArray(STR_WITHIN_BMP); + final int[] COORDINATES_WITHIN_BMP = + LatinIME.getCoordinatesForKeyboard(CODEPOINTS_WITHIN_BMP, null); final String PREVWORD = "prevword"; - wc.setComposingWord(STR_WITHIN_BMP, PREVWORD, null /* keyboard */); + wc.setComposingWord(CODEPOINTS_WITHIN_BMP, COORDINATES_WITHIN_BMP, + PREVWORD, null /* keyboard */); assertEquals(wc.size(), STR_WITHIN_BMP.codePointCount(0, STR_WITHIN_BMP.length())); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); @@ -62,10 +68,13 @@ public class WordComposerTests extends AndroidTestCase { // \uD861\uDED7 is 𨛗, a character outside the BMP final String STR_WITH_SUPPLEMENTARY_CHAR = "abcde\uD861\uDED7fgh"; - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null /* previousWord */, - null /* keyboard */); - assertEquals(wc.size(), STR_WITH_SUPPLEMENTARY_CHAR.codePointCount(0, - STR_WITH_SUPPLEMENTARY_CHAR.length())); + final int[] CODEPOINTS_WITH_SUPPLEMENTARY_CHAR = + StringUtils.toCodePointArray(STR_WITH_SUPPLEMENTARY_CHAR); + final int[] COORDINATES_WITH_SUPPLEMENTARY_CHAR = LatinIME.getCoordinatesForKeyboard( + CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */, null /* keyboard */); + assertEquals(wc.size(), CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); wc.setCursorPositionWithinWord(3); assertTrue(wc.isCursorFrontOrMiddleOfComposingWord()); @@ -75,44 +84,46 @@ public class WordComposerTests extends AndroidTestCase { assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); assertNull(wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, STR_WITHIN_BMP, null /* keyboard */); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + STR_WITHIN_BMP, null /* keyboard */); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7)); assertEquals(STR_WITHIN_BMP, wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, STR_WITH_SUPPLEMENTARY_CHAR, - null /* keyboard */); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + STR_WITH_SUPPLEMENTARY_CHAR, null /* keyboard */); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7)); assertEquals(STR_WITH_SUPPLEMENTARY_CHAR, wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, STR_WITHIN_BMP, null /* keyboard */); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + STR_WITHIN_BMP, null /* keyboard */); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-3)); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-1)); assertEquals(STR_WITHIN_BMP, wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null /* previousWord */, - null /* keyboard */); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */, null /* keyboard */); wc.setCursorPositionWithinWord(3); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-9)); assertNull(wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, STR_WITH_SUPPLEMENTARY_CHAR, - null /* keyboard */); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + STR_WITH_SUPPLEMENTARY_CHAR, null /* keyboard */); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-10)); assertEquals(STR_WITH_SUPPLEMENTARY_CHAR, wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null /* previousWord */, - null /* keyboard */); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */, null /* keyboard */); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-11)); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null /* previousWord */, - null /* keyboard */); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */, null /* keyboard */); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0)); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null /* previousWord */, - null /* keyboard */); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */, null /* keyboard */); wc.setCursorPositionWithinWord(2); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0)); } diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk index 95afb4cc1..b7b1fe6cd 100644 --- a/tools/dicttool/Android.mk +++ b/tools/dicttool/Android.mk @@ -43,6 +43,7 @@ USED_TARGETTED_UTILS := \ $(LATINIME_CORE_SOURCE_DIRECTORY)/settings/NativeSuggestOptions.java \ $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/ByteArrayDictBuffer.java \ $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/CollectionUtils.java \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/CoordinateUtils.java \ $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/FileUtils.java \ $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/JniUtils.java \ $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/LocaleUtils.java \