diff options
6 files changed, 127 insertions, 16 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 18e712212..dbc2b9082 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -141,7 +141,6 @@ public final class BinaryDictionary extends Dictionary { mOutputTypes); final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList(); for (int j = 0; j < count; ++j) { - if (composerSize > 0 && mOutputScores[j] < 1) break; final int start = j * MAX_WORD_LENGTH; int len = 0; while (len < MAX_WORD_LENGTH && mOutputCodePoints[start + len] != 0) { diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java index e39aae958..3f7be99e5 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java @@ -22,6 +22,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.IBinder; import android.preference.PreferenceManager; +import android.util.Log; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; @@ -46,6 +47,8 @@ public final class RichInputMethodManager { private InputMethodManagerCompatWrapper mImmWrapper; private InputMethodInfo mInputMethodInfoOfThisIme; + private static final int INDEX_NOT_FOUND = -1; + public static RichInputMethodManager getInstance() { sInstance.checkInitialized(); return sInstance; @@ -98,11 +101,100 @@ public final class RichInputMethodManager { } public boolean switchToNextInputMethod(final IBinder token, final boolean onlyCurrentIme) { - final boolean result = mImmWrapper.switchToNextInputMethod(token, onlyCurrentIme); - if (!result) { - mImmWrapper.mImm.switchToLastInputMethod(token); + if (mImmWrapper.switchToNextInputMethod(token, onlyCurrentIme)) { + return true; + } + // Was not able to call {@link InputMethodManager#switchToNextInputMethodIBinder,boolean)} + // because the current device is running ICS or previous and lacks the API. + if (switchToNextInputSubtypeInThisIme(token, onlyCurrentIme)) { + return true; + } + return switchToNextInputMethodAndSubtype(token); + } + + private boolean switchToNextInputSubtypeInThisIme(final IBinder token, + final boolean onlyCurrentIme) { + final InputMethodManager imm = mImmWrapper.mImm; + final InputMethodSubtype currentSubtype = imm.getCurrentInputMethodSubtype(); + final List<InputMethodSubtype> enabledSubtypes = imm.getEnabledInputMethodSubtypeList( + mInputMethodInfoOfThisIme, true /* allowsImplicitlySelectedSubtypes */); + final int currentIndex = getSubtypeIndexInList(currentSubtype, enabledSubtypes); + if (currentIndex == INDEX_NOT_FOUND) { + Log.w(TAG, "Can't find current subtype in enabled subtypes: subtype=" + + SubtypeLocale.getSubtypeDisplayName(currentSubtype)); + return false; + } + final int nextIndex = (currentIndex + 1) % enabledSubtypes.size(); + if (nextIndex <= currentIndex && !onlyCurrentIme) { + // The current subtype is the last or only enabled one and it needs to switch to + // next IME. return false; } + final InputMethodSubtype nextSubtype = enabledSubtypes.get(nextIndex); + setInputMethodAndSubtype(token, nextSubtype); + return true; + } + + private boolean switchToNextInputMethodAndSubtype(final IBinder token) { + final InputMethodManager imm = mImmWrapper.mImm; + final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList(); + final int currentIndex = getImiIndexInList(mInputMethodInfoOfThisIme, enabledImis); + if (currentIndex == INDEX_NOT_FOUND) { + Log.w(TAG, "Can't find current IME in enabled IMEs: IME package=" + + mInputMethodInfoOfThisIme.getPackageName()); + return false; + } + final InputMethodInfo nextImi = getNextNonAuxiliaryIme(currentIndex, enabledImis); + final List<InputMethodSubtype> enabledSubtypes = imm.getEnabledInputMethodSubtypeList( + nextImi, true /* allowsImplicitlySelectedSubtypes */); + if (enabledSubtypes.isEmpty()) { + // The next IME has no subtype. + imm.setInputMethod(token, nextImi.getId()); + return true; + } + final InputMethodSubtype firstSubtype = enabledSubtypes.get(0); + imm.setInputMethodAndSubtype(token, nextImi.getId(), firstSubtype); + return true; + } + + private static int getImiIndexInList(final InputMethodInfo inputMethodInfo, + final List<InputMethodInfo> imiList) { + final int count = imiList.size(); + for (int index = 0; index < count; index++) { + final InputMethodInfo imi = imiList.get(index); + if (imi.equals(inputMethodInfo)) { + return index; + } + } + return INDEX_NOT_FOUND; + } + + // This method mimics {@link InputMethodManager#switchToNextInputMethod(IBinder,boolean)}. + private static InputMethodInfo getNextNonAuxiliaryIme(final int currentIndex, + final List<InputMethodInfo> imiList) { + final int count = imiList.size(); + for (int i = 1; i < count; i++) { + final int nextIndex = (currentIndex + i) % count; + final InputMethodInfo nextImi = imiList.get(nextIndex); + if (!isAuxiliaryIme(nextImi)) { + return nextImi; + } + } + return imiList.get(currentIndex); + } + + // Copied from {@link InputMethodInfo}. See how auxiliary of IME is determined. + private static boolean isAuxiliaryIme(final InputMethodInfo imi) { + final int count = imi.getSubtypeCount(); + if (count == 0) { + return false; + } + for (int index = 0; index < count; index++) { + final InputMethodSubtype subtype = imi.getSubtypeAt(index); + if (!subtype.isAuxiliary()) { + return false; + } + } return true; } @@ -136,24 +228,35 @@ public final class RichInputMethodManager { private static boolean checkIfSubtypeBelongsToList(final InputMethodSubtype subtype, final List<InputMethodSubtype> subtypes) { - for (final InputMethodSubtype ims : subtypes) { + return getSubtypeIndexInList(subtype, subtypes) != INDEX_NOT_FOUND; + } + + private static int getSubtypeIndexInList(final InputMethodSubtype subtype, + final List<InputMethodSubtype> subtypes) { + final int count = subtypes.size(); + for (int index = 0; index < count; index++) { + final InputMethodSubtype ims = subtypes.get(index); if (ims.equals(subtype)) { - return true; + return index; } } - return false; + return INDEX_NOT_FOUND; } public boolean checkIfSubtypeBelongsToThisIme(final InputMethodSubtype subtype) { - final InputMethodInfo myImi = mInputMethodInfoOfThisIme; - final int count = myImi.getSubtypeCount(); - for (int i = 0; i < count; i++) { - final InputMethodSubtype ims = myImi.getSubtypeAt(i); + return getSubtypeIndexInIme(subtype, mInputMethodInfoOfThisIme) != INDEX_NOT_FOUND; + } + + private static int getSubtypeIndexInIme(final InputMethodSubtype subtype, + final InputMethodInfo imi) { + final int count = imi.getSubtypeCount(); + for (int index = 0; index < count; index++) { + final InputMethodSubtype ims = imi.getSubtypeAt(index); if (ims.equals(subtype)) { - return true; + return index; } } - return false; + return INDEX_NOT_FOUND; } public InputMethodSubtype getCurrentInputMethodSubtype( diff --git a/native/jni/src/binary_format.h b/native/jni/src/binary_format.h index 2d2e19501..ad16039ef 100644 --- a/native/jni/src/binary_format.h +++ b/native/jni/src/binary_format.h @@ -66,6 +66,7 @@ class BinaryFormat { static int detectFormat(const uint8_t *const dict); static int getHeaderSize(const uint8_t *const dict); static int getFlags(const uint8_t *const dict); + static bool hasBlacklistedOrNotAWordFlag(const int flags); static void readHeaderValue(const uint8_t *const dict, const char *const key, int *outValue, const int outValueSize); static int readHeaderValueInt(const uint8_t *const dict, const char *const key); @@ -162,6 +163,10 @@ inline int BinaryFormat::getFlags(const uint8_t *const dict) { } } +inline bool BinaryFormat::hasBlacklistedOrNotAWordFlag(const int flags) { + return flags & (FLAG_IS_BLACKLISTED | FLAG_IS_NOT_A_WORD); +} + inline int BinaryFormat::getHeaderSize(const uint8_t *const dict) { switch (detectFormat(dict)) { case 1: diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h index f8d2df452..e8432546b 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node.h +++ b/native/jni/src/suggest/core/dicnode/dic_node.h @@ -210,8 +210,7 @@ class DicNode { } bool isImpossibleBigramWord() const { - const int probability = mDicNodeProperties.getProbability(); - if (probability == 0) { + if (mDicNodeProperties.hasBlacklistedOrNotAWordFlag()) { return true; } const int prevWordLen = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength() diff --git a/native/jni/src/suggest/core/dicnode/dic_node_properties.h b/native/jni/src/suggest/core/dicnode/dic_node_properties.h index 173ef35d0..63a6b1340 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node_properties.h +++ b/native/jni/src/suggest/core/dicnode/dic_node_properties.h @@ -19,6 +19,7 @@ #include <stdint.h> +#include "binary_format.h" #include "defines.h" namespace latinime { @@ -144,6 +145,10 @@ class DicNodeProperties { return mChildrenCount > 0 || mDepth != mLeavingDepth; } + bool hasBlacklistedOrNotAWordFlag() const { + return BinaryFormat::hasBlacklistedOrNotAWordFlag(mFlags); + } + private: // Caution!!! // Use a default copy constructor and an assign operator because shallow copies are ok diff --git a/native/jni/src/terminal_attributes.h b/native/jni/src/terminal_attributes.h index 144ae1452..92ef71c2c 100644 --- a/native/jni/src/terminal_attributes.h +++ b/native/jni/src/terminal_attributes.h @@ -72,7 +72,7 @@ class TerminalAttributes { } bool isBlacklistedOrNotAWord() const { - return mFlags & (BinaryFormat::FLAG_IS_BLACKLISTED | BinaryFormat::FLAG_IS_NOT_A_WORD); + return BinaryFormat::hasBlacklistedOrNotAWordFlag(mFlags); } private: |