From c239a34262358e51aedb15f2e315bbe9bcd57c4b Mon Sep 17 00:00:00 2001
From: Jean Chalard <jchalard@google.com>
Date: Thu, 15 Aug 2013 16:31:29 +0900
Subject: [PATCH] Support languages that don't use spaces.

Thai is an example.

Bug: 10138062
Change-Id: Ib9a8264c77ed42b4256432d7c8a60d08575dcdc7
---
 java/res/values-th/donottranslate.xml         |  23 ++++
 java/res/values/donottranslate.xml            |   4 +
 .../android/inputmethod/latin/LatinIME.java   |  81 +++++++++++---
 .../inputmethod/latin/settings/Settings.java  |   1 -
 .../latin/settings/SettingsValues.java        |   3 +
 .../inputmethod/latin/InputLogicTests.java    |  15 +++
 .../InputLogicTestsLanguageWithoutSpaces.java | 105 ++++++++++++++++++
 .../inputmethod/latin/InputTestsBase.java     |  15 ++-
 8 files changed, 226 insertions(+), 21 deletions(-)
 create mode 100644 java/res/values-th/donottranslate.xml
 create mode 100644 tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java

diff --git a/java/res/values-th/donottranslate.xml b/java/res/values-th/donottranslate.xml
new file mode 100644
index 0000000000..aeeebed152
--- /dev/null
+++ b/java/res/values-th/donottranslate.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Whether this language uses spaces -->
+    <bool name="current_language_has_spaces">false</bool>
+</resources>
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml
index e352f082b6..8983536af2 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -18,6 +18,8 @@
 */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- TODO: these settings depend on the language. They should be put either in the dictionary
+         header, or in the subtype maybe? -->
     <!-- Symbols that are suggested between words -->
     <string name="suggested_punctuations">!,?,\\,,:,;,\",(,),\',-,/,@,_</string>
     <!-- Symbols that are normally preceded by a space (used to add an auto-space before these) -->
@@ -29,6 +31,8 @@
     <string name="symbols_word_separators">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
     <!-- Word connectors -->
     <string name="symbols_word_connectors">\'-</string>
+    <!-- Whether this language uses spaces -->
+    <bool name="current_language_has_spaces">true</bool>
 
     <!--  Always show the suggestion strip -->
     <string name="prefs_suggestion_visibility_show_value">0</string>
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index ffe317161c..ee7478ca2b 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1948,7 +1948,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                     }
                 }
             }
-            if (currentSettings.isSuggestionsRequested(mDisplayOrientation)) {
+            if (currentSettings.isSuggestionsRequested(mDisplayOrientation)
+                    && currentSettings.mCurrentLanguageHasSpaces) {
                 restartSuggestionsOnWordBeforeCursorIfAtEndOfWord();
             }
             // We just removed a character. We need to update the auto-caps state.
@@ -1977,6 +1978,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
     private void handleCharacter(final int primaryCode, final int x,
             final int y, final int spaceState) {
+        // TODO: refactor this method to stop flipping isComposingWord around all the time, and
+        // make it shorter (possibly cut into several pieces). Also factor handleNonSpecialCharacter
+        // which has the same name as other handle* methods but is not the same.
         boolean isComposingWord = mWordComposer.isComposingWord();
 
         // TODO: remove isWordConnector() and use isUsuallyFollowedBySpace() instead.
@@ -1996,12 +2000,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             resetEntireInputState(mLastSelectionStart);
             isComposingWord = false;
         }
-        // NOTE: isCursorTouchingWord() is a blocking IPC call, so it often takes several
-        // dozen milliseconds. Avoid calling it as much as possible, since we are on the UI
-        // thread here.
-        if (!isComposingWord && currentSettings.isWordCodePoint(primaryCode)
+        // We want to find out whether to start composing a new word with this character. If so,
+        // we need to reset the composing state and switch isComposingWord. The order of the
+        // tests is important for good performance.
+        // We only start composing if we're not already composing.
+        if (!isComposingWord
+        // We only start composing if this is a word code point. Essentially that means it's a
+        // a letter or a word connector.
+                && currentSettings.isWordCodePoint(primaryCode)
+        // We never go into composing state if suggestions are not requested.
                 && currentSettings.isSuggestionsRequested(mDisplayOrientation) &&
-                !mConnection.isCursorTouchingWord(currentSettings)) {
+        // In languages with spaces, we only start composing a word when we are not already
+        // touching a word. In languages without spaces, the above conditions are sufficient.
+                (!mConnection.isCursorTouchingWord(currentSettings)
+                        || !currentSettings.mCurrentLanguageHasSpaces)) {
             // Reset entirely the composing state anyway, then start composing a new word unless
             // the character is a single quote. The idea here is, single quote is not a
             // separator and it should be treated as a normal character, except in the first
@@ -2089,16 +2101,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     private boolean handleSeparator(final int primaryCode, final int x, final int y,
             final int spaceState) {
         boolean didAutoCorrect = false;
+        final SettingsValues currentSettings = mSettings.getCurrent();
+        // We avoid sending spaces in languages without spaces if we were composing.
+        final boolean shouldAvoidSendingCode = Constants.CODE_SPACE == primaryCode
+                && !currentSettings.mCurrentLanguageHasSpaces && mWordComposer.isComposingWord();
         if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
             // If we are in the middle of a recorrection, we need to commit the recorrection
             // first so that we can insert the separator at the current cursor position.
             resetEntireInputState(mLastSelectionStart);
         }
-        final SettingsValues currentSettings = mSettings.getCurrent();
-        if (mWordComposer.isComposingWord()) {
+        if (mWordComposer.isComposingWord()) { // May have changed since we stored wasComposing
             if (currentSettings.mCorrectionEnabled) {
-                // TODO: maybe cache Strings in an <String> sparse array or something
-                commitCurrentAutoCorrection(new String(new int[]{primaryCode}, 0, 1));
+                final String separator = shouldAvoidSendingCode ? LastComposedWord.NOT_A_SEPARATOR
+                        : new String(new int[] { primaryCode }, 0, 1);
+                commitCurrentAutoCorrection(separator);
                 didAutoCorrect = true;
             } else {
                 commitTyped(new String(new int[]{primaryCode}, 0, 1));
@@ -2115,7 +2131,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
             ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord());
         }
-        sendKeyCodePoint(primaryCode);
+
+        if (!shouldAvoidSendingCode) {
+            sendKeyCodePoint(primaryCode);
+        }
 
         if (Constants.CODE_SPACE == primaryCode) {
             if (currentSettings.isSuggestionsRequested(mDisplayOrientation)) {
@@ -2260,11 +2279,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         // Get the word on which we should search the bigrams. If we are composing a word, it's
         // whatever is *before* the half-committed word in the buffer, hence 2; if we aren't, we
         // should just skip whitespace if any, so 1.
-        // TODO: this is slow (2-way IPC) - we should probably cache this instead.
         final SettingsValues currentSettings = mSettings.getCurrent();
-        final String prevWord =
-                mConnection.getNthPreviousWord(currentSettings.mWordSeparators,
-                mWordComposer.isComposingWord() ? 2 : 1);
+        final String prevWord;
+        if (currentSettings.mCurrentLanguageHasSpaces) {
+            // If we are typing in a language with spaces we can just look up the previous
+            // word from textview.
+            prevWord = mConnection.getNthPreviousWord(currentSettings.mWordSeparators,
+                    mWordComposer.isComposingWord() ? 2 : 1);
+        } else {
+            prevWord = LastComposedWord.NOT_A_COMPOSED_WORD == mLastComposedWord ? null
+                    : mLastComposedWord.mCommittedWord;
+        }
         return suggest.getSuggestedWords(mWordComposer, prevWord, keyboard.getProximityInfo(),
                 currentSettings.mBlockPotentiallyOffensive,
                 currentSettings.mCorrectionEnabled, sessionId);
@@ -2534,6 +2559,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         // recorrection. This is a temporary, stopgap measure that will be removed later.
         // TODO: remove this.
         if (mAppWorkAroundsUtils.isBrokenByRecorrection()) return;
+        // Recorrection is not supported in languages without spaces because we don't know
+        // how to segment them yet.
+        if (!mSettings.getCurrent().mCurrentLanguageHasSpaces) return;
         // If the cursor is not touching a word, or if there is a selection, return right away.
         if (mLastSelectionStart != mLastSelectionEnd) return;
         // If we don't know the cursor location, return.
@@ -2656,7 +2684,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) {
             mUserHistoryPredictionDictionary.cancelAddingUserHistory(previousWord, committedWord);
         }
-        mConnection.commitText(originallyTypedWord + mLastComposedWord.mSeparatorString, 1);
+        final String stringToCommit = originallyTypedWord + mLastComposedWord.mSeparatorString;
+        if (mSettings.getCurrent().mCurrentLanguageHasSpaces) {
+            // For languages with spaces, we revert to the typed string, but the cursor is still
+            // after the separator so we don't resume suggestions. If the user wants to correct
+            // the word, they have to press backspace again.
+            mConnection.commitText(stringToCommit, 1);
+        } 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(stringToCommit, mKeyboardSwitcher.getKeyboard());
+            mConnection.setComposingText(stringToCommit, 1);
+        }
         if (mSettings.isInternal()) {
             LatinImeLoggerUtils.onSeparator(mLastComposedWord.mSeparatorString,
                     Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
@@ -2674,7 +2713,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
     // This essentially inserts a space, and that's it.
     public void promotePhantomSpace() {
-        if (mSettings.getCurrent().shouldInsertSpacesAutomatically()
+        final SettingsValues currentSettings = mSettings.getCurrent();
+        if (currentSettings.shouldInsertSpacesAutomatically()
+                && currentSettings.mCurrentLanguageHasSpaces
                 && !mConnection.textBeforeCursorLooksLikeURL()) {
             if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
                 ResearchLogger.latinIME_promotePhantomSpace();
@@ -2887,6 +2928,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         return mSuggest.hasMainDictionary();
     }
 
+    // DO NOT USE THIS for any other purpose than testing. This can break the keyboard badly.
+    @UsedForTesting
+    /* package for test */ void replaceMainDictionaryForTest(final Locale locale) {
+        mSuggest.resetMainDict(this, locale, null);
+    }
+
     public void debugDumpStateAndCrashWithException(final String context) {
         final StringBuilder s = new StringBuilder(mAppWorkAroundsUtils.toString());
         s.append("\nAttributes : ").append(mSettings.getCurrent().mInputAttributes)
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index d432087d33..6257dffbea 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -27,7 +27,6 @@ import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
 import com.android.inputmethod.latin.InputAttributes;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
-import com.android.inputmethod.latin.utils.DebugLogUtils;
 import com.android.inputmethod.latin.utils.LocaleUtils;
 import com.android.inputmethod.latin.utils.ResourceUtils;
 import com.android.inputmethod.latin.utils.RunInLocale;
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index 195f9f8ef1..a0b744dd24 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -57,6 +57,7 @@ public final class SettingsValues {
     public final SuggestedWords mSuggestPuncList;
     public final String mWordSeparators;
     public final CharSequence mHintToSaveText;
+    public final boolean mCurrentLanguageHasSpaces;
 
     // From preferences, in the same order as xml/prefs.xml:
     public final boolean mAutoCap;
@@ -118,6 +119,7 @@ public final class SettingsValues {
         mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
         mWordSeparators = res.getString(R.string.symbols_word_separators);
         mHintToSaveText = res.getText(R.string.hint_add_to_dictionary);
+        mCurrentLanguageHasSpaces = res.getBoolean(R.bool.current_language_has_spaces);
 
         // Store the input attributes
         if (null == inputAttributes) {
@@ -186,6 +188,7 @@ public final class SettingsValues {
         mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
         mWordSeparators = "&\t \n()[]{}*&<>+=|.,;:!?/_\"";
         mHintToSaveText = "Touch again to save";
+        mCurrentLanguageHasSpaces = true;
         mInputAttributes = new InputAttributes(null, false /* isFullscreenMode */);
         mAutoCap = true;
         mVibrateOn = true;
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
index d27a7a9035..6cc4befaed 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
@@ -17,6 +17,7 @@
 package com.android.inputmethod.latin;
 
 import android.test.suitebuilder.annotation.LargeTest;
+import android.view.inputmethod.BaseInputConnection;
 
 @LargeTest
 public class InputLogicTests extends InputTestsBase {
@@ -290,5 +291,19 @@ public class InputLogicTests extends InputTestsBase {
         }
         assertEquals("delete whole composing word", "", mEditText.getText().toString());
     }
+
+    public void testResumeSuggestionOnBackspace() {
+        final String WORD_TO_TYPE = "and this ";
+        type(WORD_TO_TYPE);
+        assertEquals("resume suggestion on backspace", -1,
+                BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+        assertEquals("resume suggestion on backspace", -1,
+                BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+        type(Constants.CODE_DELETE);
+        assertEquals("resume suggestion on backspace", 4,
+                BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+        assertEquals("resume suggestion on backspace", 8,
+                BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+    }
     // TODO: Add some tests for non-BMP characters
 }
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java b/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java
new file mode 100644
index 0000000000..0f0ebafb99
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2013 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.test.suitebuilder.annotation.LargeTest;
+import android.view.inputmethod.BaseInputConnection;
+
+import com.android.inputmethod.latin.suggestions.SuggestionStripView;
+
+@LargeTest
+public class InputLogicTestsLanguageWithoutSpaces extends InputTestsBase {
+    public void testAutoCorrectForLanguageWithoutSpaces() {
+        final String STRING_TO_TYPE = "tgis is";
+        final String EXPECTED_RESULT = "thisis";
+        changeKeyboardLocaleAndDictLocale("th", "en_US");
+        type(STRING_TO_TYPE);
+        assertEquals("simple auto-correct for language without spaces", EXPECTED_RESULT,
+                mEditText.getText().toString());
+    }
+
+    public void testRevertAutoCorrectForLanguageWithoutSpaces() {
+        final String STRING_TO_TYPE = "tgis ";
+        final String EXPECTED_INTERMEDIATE_RESULT = "this";
+        final String EXPECTED_FINAL_RESULT = "tgis";
+        changeKeyboardLocaleAndDictLocale("th", "en_US");
+        type(STRING_TO_TYPE);
+        assertEquals("simple auto-correct for language without spaces",
+                EXPECTED_INTERMEDIATE_RESULT, mEditText.getText().toString());
+        type(Constants.CODE_DELETE);
+        assertEquals("simple auto-correct for language without spaces",
+                EXPECTED_FINAL_RESULT, mEditText.getText().toString());
+        // Check we are back to composing the word
+        assertEquals("don't resume suggestion on backspace", 0,
+                BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+        assertEquals("don't resume suggestion on backspace", 4,
+                BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+    }
+
+    public void testDontResumeSuggestionOnBackspace() {
+        final String WORD_TO_TYPE = "and this ";
+        changeKeyboardLocaleAndDictLocale("th", "en_US");
+        type(WORD_TO_TYPE);
+        assertEquals("don't resume suggestion on backspace", -1,
+                BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+        assertEquals("don't resume suggestion on backspace", -1,
+                BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+        type(" ");
+        type(Constants.CODE_DELETE);
+        assertEquals("don't resume suggestion on backspace", -1,
+                BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+        assertEquals("don't resume suggestion on backspace", -1,
+                BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+    }
+
+    public void testStartComposingInsideText() {
+        final String WORD_TO_TYPE = "abcdefgh ";
+        final int typedLength = WORD_TO_TYPE.length() - 1; // -1 because space gets eaten
+        final int CURSOR_POS = 4;
+        changeKeyboardLocaleAndDictLocale("th", "en_US");
+        type(WORD_TO_TYPE);
+        mLatinIME.onUpdateSelection(0, 0, typedLength, typedLength, -1, -1);
+        mInputConnection.setSelection(CURSOR_POS, CURSOR_POS);
+        mLatinIME.onUpdateSelection(typedLength, typedLength,
+                CURSOR_POS, CURSOR_POS, -1, -1);
+        sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+        runMessages();
+        assertEquals("start composing inside text", -1,
+                BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+        assertEquals("start composing inside text", -1,
+                BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+        type("xxxx");
+        assertEquals("start composing inside text", 4,
+                BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+        assertEquals("start composing inside text", 8,
+                BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+    }
+
+    public void testPredictions() {
+        final String WORD_TO_TYPE = "Barack ";
+        changeKeyboardLocaleAndDictLocale("th", "en_US");
+        type(WORD_TO_TYPE);
+        sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+        runMessages();
+        // Make sure there is no space
+        assertEquals("predictions in lang without spaces", "Barack",
+                mEditText.getText().toString());
+        // Test the first prediction is displayed
+        assertEquals("predictions in lang without spaces", "Obama",
+                mLatinIME.getFirstSuggestedWord());
+    }
+}
diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
index cc3e0d74d5..480570e62e 100644
--- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
@@ -46,6 +46,8 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
 
     // The message that sets the underline is posted with a 100 ms delay
     protected static final int DELAY_TO_WAIT_FOR_UNDERLINE = 200;
+    // The message that sets predictions is posted with a 100 ms delay
+    protected static final int DELAY_TO_WAIT_FOR_PREDICTIONS = 200;
 
     protected LatinIME mLatinIME;
     protected Keyboard mKeyboard;
@@ -233,9 +235,6 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
                 --remainingAttempts;
             }
         }
-        if (!mLatinIME.hasMainDictionary()) {
-            throw new RuntimeException("Can't initialize the main dictionary");
-        }
     }
 
     protected void changeLanguage(final String locale) {
@@ -247,6 +246,16 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
         waitForDictionaryToBeLoaded();
     }
 
+    protected void changeKeyboardLocaleAndDictLocale(final String keyboardLocale,
+            final String dictLocale) {
+        changeLanguage(keyboardLocale);
+        if (!keyboardLocale.equals(dictLocale)) {
+            mLatinIME.replaceMainDictionaryForTest(
+                    LocaleUtils.constructLocaleFromString(dictLocale));
+        }
+        waitForDictionaryToBeLoaded();
+    }
+
     protected void pickSuggestionManually(final int index, final String suggestion) {
         mLatinIME.pickSuggestionManually(index, new SuggestedWordInfo(suggestion, 1,
                 SuggestedWordInfo.KIND_CORRECTION, "main"));
-- 
GitLab