diff options
14 files changed, 504 insertions, 303 deletions
diff --git a/java/src/com/android/inputmethod/event/InputTransaction.java b/java/src/com/android/inputmethod/event/InputTransaction.java index 2e9014f20..4fe9b403e 100644 --- a/java/src/com/android/inputmethod/event/InputTransaction.java +++ b/java/src/com/android/inputmethod/event/InputTransaction.java @@ -40,6 +40,7 @@ public class InputTransaction { // Outputs private int mRequiredShiftUpdate = SHIFT_NO_UPDATE; + private boolean mRequiresUpdateSuggestions = false; public InputTransaction(final SettingsValues settingsValues, final Event event, final long timestamp, final int spaceState, final int shiftState) { @@ -50,10 +51,34 @@ public class InputTransaction { mShiftState = shiftState; } + /** + * Indicate that this transaction requires some type of shift update. + * @param updateType What type of shift update this requires. + */ public void requireShiftUpdate(final int updateType) { mRequiredShiftUpdate = Math.max(mRequiredShiftUpdate, updateType); } + + /** + * Gets what type of shift update this transaction requires. + * @return The shift update type. + */ public int getRequiredShiftUpdate() { return mRequiredShiftUpdate; } + + /** + * Indicate that this transaction requires updating the suggestions. + */ + public void setRequiresUpdateSuggestions() { + mRequiresUpdateSuggestions = true; + } + + /** + * Find out whether this transaction requires updating the suggestions. + * @return Whether this transaction requires updating the suggestions. + */ + public boolean requiresUpdateSuggestions() { + return mRequiresUpdateSuggestions; + } } diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 8246c924b..03425ef1f 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -60,7 +60,7 @@ import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.latin.settings.DebugSettings; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.CoordinateUtils; -import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; +import com.android.inputmethod.latin.utils.SpacebarLanguageUtils; import com.android.inputmethod.latin.utils.TypefaceUtils; import com.android.inputmethod.latin.utils.UsabilityStudyLogUtils; import com.android.inputmethod.research.ResearchLogger; @@ -918,14 +918,13 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack // Layout language name on spacebar. private String layoutLanguageOnSpacebar(final Paint paint, final InputMethodSubtype subtype, final int width) { - // Choose appropriate language name to fit into the width. - final String fullText = SubtypeLocaleUtils.getFullDisplayName(subtype); + final String fullText = SpacebarLanguageUtils.getFullDisplayName(subtype); if (fitsTextIntoWidth(width, fullText, paint)) { return fullText; } - final String middleText = SubtypeLocaleUtils.getMiddleDisplayName(subtype); + final String middleText = SpacebarLanguageUtils.getMiddleDisplayName(subtype); if (fitsTextIntoWidth(width, middleText, paint)) { return middleText; } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 0c0be82df..53e6232b6 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -38,7 +38,6 @@ import android.net.ConnectivityManager; import android.os.Debug; import android.os.IBinder; import android.os.Message; -import android.os.SystemClock; import android.preference.PreferenceManager; import android.text.InputType; import android.text.TextUtils; @@ -1230,7 +1229,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final InputTransaction completeInputTransaction = mInputLogic.onCodeInput(mSettings.getCurrent(), event, mKeyboardSwitcher.getKeyboardShiftMode(), mHandler); - updateShiftModeAfterInputTransaction(completeInputTransaction.getRequiredShiftUpdate()); + updateStateAfterInputTransaction(completeInputTransaction); mKeyboardSwitcher.onCodeInput(codePoint); } @@ -1450,7 +1449,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final InputTransaction completeInputTransaction = mInputLogic.onPickSuggestionManually( mSettings.getCurrent(), index, suggestionInfo, mKeyboardSwitcher.getKeyboardShiftMode(), mHandler); - updateShiftModeAfterInputTransaction(completeInputTransaction.getRequiredShiftUpdate()); + updateStateAfterInputTransaction(completeInputTransaction); } @Override @@ -1488,8 +1487,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - private void updateShiftModeAfterInputTransaction(final int requiredShiftUpdate) { - switch (requiredShiftUpdate) { + /** + * After an input transaction has been executed, some state must be updated. This includes + * the shift state of the keyboard and suggestions. This method looks at the finished + * inputTransaction to find out what is necessary and updates the state accordingly. + * @param inputTransaction The transaction that has been executed. + */ + private void updateStateAfterInputTransaction(final InputTransaction inputTransaction) { + switch (inputTransaction.getRequiredShiftUpdate()) { case InputTransaction.SHIFT_UPDATE_LATER: mHandler.postUpdateShiftState(); break; @@ -1498,6 +1503,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen break; default: // SHIFT_NO_UPDATE } + if (inputTransaction.requiresUpdateSuggestions()) { + mHandler.postUpdateSuggestionStrip(); + } } private void hapticAndAudioFeedback(final int code, final int repeatCount) { diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index e2cdbb39c..ec6bd289a 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -130,8 +130,11 @@ public final class InputLogic { // so we try using some heuristics to find out about these and fix them. mConnection.tryFixLyingCursorPosition(); cancelDoubleSpacePeriodCountdown(); - mInputLogicHandler.destroy(); - mInputLogicHandler = new InputLogicHandler(mLatinIME, this); + if (InputLogicHandler.NULL_HANDLER == mInputLogicHandler) { + mInputLogicHandler = new InputLogicHandler(mLatinIME, this); + } else { + mInputLogicHandler.reset(); + } } /** @@ -142,8 +145,7 @@ public final class InputLogic { mConnection.finishComposingText(); } resetComposingState(true /* alsoResetLastComposedWord */); - mInputLogicHandler.destroy(); - mInputLogicHandler = InputLogicHandler.NULL_HANDLER; + mInputLogicHandler.reset(); } /** @@ -403,7 +405,7 @@ public final class InputLogic { // A special key, like delete, shift, emoji, or the settings key. switch (event.mKeyCode) { case Constants.CODE_DELETE: - handleBackspace(inputTransaction, handler); + handleBackspace(inputTransaction); LatinImeLogger.logOnDelete(event.mX, event.mY); break; case Constants.CODE_SHIFT: @@ -672,7 +674,7 @@ public final class InputLogic { commitTyped(inputTransaction.mSettingsValues, LastComposedWord.NOT_A_SEPARATOR); } } - handleNonSeparator(inputTransaction.mSettingsValues, inputTransaction, handler); + handleNonSeparator(inputTransaction.mSettingsValues, inputTransaction); } return didAutoCorrect; } @@ -683,9 +685,7 @@ public final class InputLogic { * @param inputTransaction The transaction in progress. */ private void handleNonSeparator(final SettingsValues settingsValues, - final InputTransaction inputTransaction, - // TODO: Remove this argument - final LatinIME.UIHandler handler) { + final InputTransaction inputTransaction) { final int codePoint = inputTransaction.mEvent.mCodePoint; // TODO: refactor this method to stop flipping isComposingWord around all the time, and // make it shorter (possibly cut into several pieces). Also factor handleNonSpecialCharacter @@ -761,7 +761,7 @@ public final class InputLogic { // In case the "add to dictionary" hint was still displayed. mSuggestionStripViewAccessor.dismissAddToDictionaryHint(); } - handler.postUpdateSuggestionStrip(); + inputTransaction.setRequiresUpdateSuggestions(); if (settingsValues.mIsInternal) { LatinImeLoggerUtils.onNonSeparator((char)codePoint, inputTransaction.mEvent.mX, inputTransaction.mEvent.mY); @@ -843,7 +843,7 @@ public final class InputLogic { } startDoubleSpacePeriodCountdown(inputTransaction); - handler.postUpdateSuggestionStrip(); + inputTransaction.setRequiresUpdateSuggestions(); } else { if (swapWeakSpace) { swapSwapperAndSpace(inputTransaction); @@ -879,9 +879,7 @@ public final class InputLogic { * Handle a press on the backspace key. * @param inputTransaction The transaction in progress. */ - private void handleBackspace(final InputTransaction inputTransaction, - // TODO: remove this argument - final LatinIME.UIHandler handler) { + private void handleBackspace(final InputTransaction inputTransaction) { mSpaceState = SpaceState.NONE; mDeleteCount++; @@ -910,7 +908,7 @@ public final class InputLogic { mWordComposer.deleteLast(inputTransaction.mEvent); } mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); - handler.postUpdateSuggestionStrip(); + inputTransaction.setRequiresUpdateSuggestions(); if (!mWordComposer.isComposingWord()) { // If we just removed the last character, auto-caps mode may have changed so we // need to re-evaluate. @@ -921,7 +919,7 @@ public final class InputLogic { if (inputTransaction.mSettingsValues.mIsInternal) { LatinImeLoggerUtils.onAutoCorrectionCancellation(); } - revertCommit(inputTransaction.mSettingsValues, handler); + revertCommit(inputTransaction); return; } if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) { @@ -1400,11 +1398,9 @@ public final class InputLogic { * * This is triggered upon pressing backspace just after a commit with auto-correction. * - * @param settingsValues the current settings values. + * @param inputTransaction The transaction in progress. */ - private void revertCommit(final SettingsValues settingsValues, - // TODO: remove this argument - final LatinIME.UIHandler handler) { + private void revertCommit(final InputTransaction inputTransaction) { final String previousWord = mLastComposedWord.mPrevWord; final CharSequence originallyTypedWord = mLastComposedWord.mTypedWord; final CharSequence committedWord = mLastComposedWord.mCommittedWord; @@ -1448,7 +1444,8 @@ public final class InputLogic { // Given this, we add it to the list of suggestions, otherwise we discard it. if (span instanceof SuggestionSpan) { final SuggestionSpan suggestionSpan = (SuggestionSpan)span; - if (!suggestionSpan.getLocale().equals(settingsValues.mLocale.toString())) { + if (!suggestionSpan.getLocale().equals( + inputTransaction.mSettingsValues.mLocale.toString())) { continue; } for (final String suggestion : suggestionSpan.getSuggestions()) { @@ -1463,11 +1460,11 @@ public final class InputLogic { } } // Add the suggestion list to the list of suggestions. - textToCommit.setSpan(new SuggestionSpan(settingsValues.mLocale, + textToCommit.setSpan(new SuggestionSpan(inputTransaction.mSettingsValues.mLocale, suggestions.toArray(new String[suggestions.size()]), 0 /* flags */), 0 /* start */, lastCharIndex /* end */, 0 /* flags */); } - if (settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces) { + if (inputTransaction.mSettingsValues.mSpacingAndPunctuations.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. @@ -1480,7 +1477,7 @@ public final class InputLogic { mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), previousWord); mConnection.setComposingText(textToCommit, 1); } - if (settingsValues.mIsInternal) { + if (inputTransaction.mSettingsValues.mIsInternal) { LatinImeLoggerUtils.onSeparator(mLastComposedWord.mSeparatorString, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); } @@ -1493,7 +1490,7 @@ public final class InputLogic { // separator. mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; // We have a separator between the word and the cursor: we should show predictions. - handler.postUpdateSuggestionStrip(); + inputTransaction.setRequiresUpdateSuggestions(); } /** diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java index db96de305..42f0d7c00 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java @@ -43,7 +43,7 @@ class InputLogicHandler implements Handler.Callback { // is initialized, though probably only the monkey can actually do this. public static final InputLogicHandler NULL_HANDLER = new InputLogicHandler() { @Override - public void destroy() {} + public void reset() {} @Override public boolean handleMessage(final Message msg) { return true; } @Override @@ -75,8 +75,8 @@ class InputLogicHandler implements Handler.Callback { mInputLogic = inputLogic; } - public void destroy() { - mNonUIThreadHandler.getLooper().quit(); + public void reset() { + mNonUIThreadHandler.removeCallbacksAndMessages(null); } /** diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index a07e8eb6a..6a52481b9 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -268,6 +268,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService // if it doesn't. See documentation for binarySearch. final int insertIndex = positionIndex >= 0 ? positionIndex : -positionIndex - 1; + // Weak <- insertIndex == 0, ..., insertIndex == mLength -> Strong if (insertIndex == 0 && mLength >= mMaxLength) { // In the future, we may want to keep track of the best suggestion score even if // we are asked for 0 suggestions. In this case, we can use the following @@ -285,11 +286,6 @@ public final class AndroidSpellCheckerService extends SpellCheckerService // } return true; } - if (insertIndex >= mMaxLength) { - // We found a suggestion, but its score is too weak to be kept considering - // the suggestion limit. - return true; - } final String wordString = new String(word, wordOffset, wordLength); if (mLength < mMaxLength) { @@ -297,12 +293,13 @@ public final class AndroidSpellCheckerService extends SpellCheckerService ++mLength; System.arraycopy(mScores, insertIndex, mScores, insertIndex + 1, copyLen); mSuggestions.add(insertIndex, wordString); + mScores[insertIndex] = score; } else { - System.arraycopy(mScores, 1, mScores, 0, insertIndex); + System.arraycopy(mScores, 1, mScores, 0, insertIndex - 1); mSuggestions.add(insertIndex, wordString); mSuggestions.remove(0); + mScores[insertIndex - 1] = score; } - mScores[insertIndex] = score; return true; } diff --git a/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java b/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java new file mode 100644 index 000000000..89837c641 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2014 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.utils; + +import android.view.inputmethod.InputMethodSubtype; + +import java.util.Locale; + +public final class SpacebarLanguageUtils { + private SpacebarLanguageUtils() { + // Intentional empty constructor for utility class. + } + + // InputMethodSubtype's display name for spacebar text in its locale. + // isAdditionalSubtype (T=true, F=false) + // locale layout | Middle Full + // ------ ------- - --------- ---------------------- + // en_US qwerty F English English (US) exception + // en_GB qwerty F English English (UK) exception + // es_US spanish F Español Español (EE.UU.) exception + // fr azerty F Français Français + // fr_CA qwerty F Français Français (Canada) + // fr_CH swiss F Français Français (Suisse) + // de qwertz F Deutsch Deutsch + // de_CH swiss T Deutsch Deutsch (Schweiz) + // zz qwerty F QWERTY QWERTY + // fr qwertz T Français Français + // de qwerty T Deutsch Deutsch + // en_US azerty T English English (US) + // zz azerty T AZERTY AZERTY + // Get InputMethodSubtype's full display name in its locale. + public static String getFullDisplayName(final InputMethodSubtype subtype) { + if (SubtypeLocaleUtils.isNoLanguage(subtype)) { + return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype); + } + return SubtypeLocaleUtils.getSubtypeLocaleDisplayName(subtype.getLocale()); + } + + // Get InputMethodSubtype's middle display name in its locale. + public static String getMiddleDisplayName(final InputMethodSubtype subtype) { + if (SubtypeLocaleUtils.isNoLanguage(subtype)) { + return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype); + } + final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype); + return SubtypeLocaleUtils.getSubtypeLocaleDisplayName(locale.getLanguage()); + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java index 4f556f972..2452864d5 100644 --- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java @@ -292,41 +292,6 @@ public final class SubtypeLocaleUtils { return keyboardLayoutSet; } - // InputMethodSubtype's display name for spacebar text in its locale. - // isAdditionalSubtype (T=true, F=false) - // locale layout | Middle Full - // ------ ------- - --------- ---------------------- - // en_US qwerty F English English (US) exception - // en_GB qwerty F English English (UK) exception - // es_US spanish F Español Español (EE.UU.) exception - // fr azerty F Français Français - // fr_CA qwerty F Français Français (Canada) - // fr_CH swiss F Français Français (Suisse) - // de qwertz F Deutsch Deutsch - // de_CH swiss T Deutsch Deutsch (Schweiz) - // zz qwerty F QWERTY QWERTY - // fr qwertz T Français Français - // de qwerty T Deutsch Deutsch - // en_US azerty T English English (US) - // zz azerty T AZERTY AZERTY - - // Get InputMethodSubtype's full display name in its locale. - public static String getFullDisplayName(final InputMethodSubtype subtype) { - if (isNoLanguage(subtype)) { - return getKeyboardLayoutSetDisplayName(subtype); - } - return getSubtypeLocaleDisplayName(subtype.getLocale()); - } - - // Get InputMethodSubtype's middle display name in its locale. - public static String getMiddleDisplayName(final InputMethodSubtype subtype) { - if (isNoLanguage(subtype)) { - return getKeyboardLayoutSetDisplayName(subtype); - } - final Locale locale = getSubtypeLocale(subtype); - return getSubtypeLocaleDisplayName(locale.getLanguage()); - } - // TODO: Get this information from the framework instead of maintaining here by ourselves. // Sorted list of known Right-To-Left language codes. private static final String[] SORTED_RTL_LANGUAGES = { diff --git a/native/jni/src/suggest/core/result/suggestions_output_utils.cpp b/native/jni/src/suggest/core/result/suggestions_output_utils.cpp index d07f5ca41..83140f1ab 100644 --- a/native/jni/src/suggest/core/result/suggestions_output_utils.cpp +++ b/native/jni/src/suggest/core/result/suggestions_output_utils.cpp @@ -17,11 +17,11 @@ #include "suggest/core/result/suggestions_output_utils.h" #include <algorithm> +#include <vector> #include "suggest/core/dicnode/dic_node.h" #include "suggest/core/dicnode/dic_node_utils.h" #include "suggest/core/dictionary/binary_dictionary_shortcut_iterator.h" -#include "suggest/core/dictionary/dictionary.h" #include "suggest/core/dictionary/error_type_utils.h" #include "suggest/core/policy/scoring.h" #include "suggest/core/result/suggestion_results.h" @@ -31,110 +31,113 @@ namespace latinime { const int SuggestionsOutputUtils::MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT = 16; -// TODO: Split this method. /* static */ void SuggestionsOutputUtils::outputSuggestions( const Scoring *const scoringPolicy, DicTraverseSession *traverseSession, SuggestionResults *const outSuggestionResults) { #if DEBUG_EVALUATE_MOST_PROBABLE_STRING const int terminalSize = 0; #else - const int terminalSize = std::min(MAX_RESULTS, - static_cast<int>(traverseSession->getDicTraverseCache()->terminalSize())); + const int terminalSize = traverseSession->getDicTraverseCache()->terminalSize(); #endif - DicNode terminals[MAX_RESULTS]; // Avoiding non-POD variable length array - + std::vector<DicNode> terminals(terminalSize); for (int index = terminalSize - 1; index >= 0; --index) { traverseSession->getDicTraverseCache()->popTerminal(&terminals[index]); } const float languageWeight = scoringPolicy->getAdjustedLanguageWeight( - traverseSession, terminals, terminalSize); + traverseSession, terminals.data(), terminalSize); // Force autocorrection for obvious long multi-word suggestions when the top suggestion is // a long multiple words suggestion. // TODO: Implement a smarter auto-commit method for handling multi-word suggestions. - // traverseSession->isPartiallyCommited() always returns false because we never auto partial - // commit for now. - const bool forceCommitMultiWords = (terminalSize > 0) ? - scoringPolicy->autoCorrectsToMultiWordSuggestionIfTop() - && (traverseSession->isPartiallyCommited() - || (traverseSession->getInputSize() - >= MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT - && terminals[0].hasMultipleWords())) : false; + const bool forceCommitMultiWords = scoringPolicy->autoCorrectsToMultiWordSuggestionIfTop() + && (traverseSession->getInputSize() >= MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT + && !terminals.empty() && terminals.front().hasMultipleWords()); // TODO: have partial commit work even with multiple pointers. const bool outputSecondWordFirstLetterInputIndex = traverseSession->isOnlyOnePointerUsed(0 /* pointerId */); const bool boostExactMatches = traverseSession->getDictionaryStructurePolicy()-> getHeaderStructurePolicy()->shouldBoostExactMatches(); - int codePoints[MAX_WORD_LENGTH]; // Output suggestion results here - for (int terminalIndex = 0; terminalIndex < terminalSize; ++terminalIndex) { - DicNode *terminalDicNode = &terminals[terminalIndex]; - if (DEBUG_GEO_FULL) { - terminalDicNode->dump("OUT:"); - } - const float doubleLetterCost = - scoringPolicy->getDoubleLetterDemotionDistanceCost(terminalDicNode); - const float compoundDistance = terminalDicNode->getCompoundDistance(languageWeight) - + doubleLetterCost; - const bool isPossiblyOffensiveWord = - traverseSession->getDictionaryStructurePolicy()->getProbability( - terminalDicNode->getProbability(), NOT_A_PROBABILITY) <= 0; - const bool isExactMatch = - ErrorTypeUtils::isExactMatch(terminalDicNode->getContainedErrorTypes()); - const bool isFirstCharUppercase = terminalDicNode->isFirstCharUppercase(); - // Heuristic: We exclude probability=0 first-char-uppercase words from exact match. - // (e.g. "AMD" and "and") - const bool isSafeExactMatch = isExactMatch - && !(isPossiblyOffensiveWord && isFirstCharUppercase); - const int outputTypeFlags = - (isPossiblyOffensiveWord ? Dictionary::KIND_FLAG_POSSIBLY_OFFENSIVE : 0) - | ((isSafeExactMatch && boostExactMatches) ? Dictionary::KIND_FLAG_EXACT_MATCH : 0); - - // Entries that are blacklisted or do not represent a word should not be output. - const bool isValidWord = !terminalDicNode->isBlacklistedOrNotAWord(); - - // Increase output score of top typing suggestion to ensure autocorrection. - // TODO: Better integration with java side autocorrection logic. - const int finalScore = scoringPolicy->calculateFinalScore( - compoundDistance, traverseSession->getInputSize(), - terminalDicNode->getContainedErrorTypes(), - (forceCommitMultiWords && terminalDicNode->hasMultipleWords()) - || (isValidWord && scoringPolicy->doesAutoCorrectValidWord()), - boostExactMatches); - - // Don't output invalid words. However, we still need to submit their shortcuts if any. - if (isValidWord) { - terminalDicNode->outputResult(codePoints); - const int indexToPartialCommit = outputSecondWordFirstLetterInputIndex ? - terminalDicNode->getSecondWordFirstInputIndex( - traverseSession->getProximityInfoState(0)) : - NOT_AN_INDEX; - outSuggestionResults->addSuggestion(codePoints, - terminalDicNode->getTotalNodeCodePointCount(), - finalScore, Dictionary::KIND_CORRECTION | outputTypeFlags, - indexToPartialCommit, computeFirstWordConfidence(terminalDicNode)); - } - - if (!terminalDicNode->hasMultipleWords()) { - BinaryDictionaryShortcutIterator shortcutIt( - traverseSession->getDictionaryStructurePolicy()->getShortcutsStructurePolicy(), - traverseSession->getDictionaryStructurePolicy() - ->getShortcutPositionOfPtNode(terminalDicNode->getPtNodePos())); - // Shortcut is not supported for multiple words suggestions. - // TODO: Check shortcuts during traversal for multiple words suggestions. - const bool sameAsTyped = scoringPolicy->sameAsTyped(traverseSession, terminalDicNode); - const int shortcutBaseScore = scoringPolicy->doesAutoCorrectValidWord() ? - scoringPolicy->calculateFinalScore(compoundDistance, - traverseSession->getInputSize(), - terminalDicNode->getContainedErrorTypes(), - true /* forceCommit */, boostExactMatches) : finalScore; - outputShortcuts(&shortcutIt, shortcutBaseScore, sameAsTyped, outSuggestionResults); - } + for (auto &terminalDicNode : terminals) { + outputSuggestionsOfDicNode(scoringPolicy, traverseSession, &terminalDicNode, + languageWeight, boostExactMatches, forceCommitMultiWords, + outputSecondWordFirstLetterInputIndex, outSuggestionResults); } scoringPolicy->getMostProbableString(traverseSession, languageWeight, outSuggestionResults); } +/* static */ void SuggestionsOutputUtils::outputSuggestionsOfDicNode( + const Scoring *const scoringPolicy, DicTraverseSession *traverseSession, + const DicNode *const terminalDicNode, const float languageWeight, + const bool boostExactMatches, const bool forceCommitMultiWords, + const bool outputSecondWordFirstLetterInputIndex, + SuggestionResults *const outSuggestionResults) { + if (DEBUG_GEO_FULL) { + terminalDicNode->dump("OUT:"); + } + const float doubleLetterCost = + scoringPolicy->getDoubleLetterDemotionDistanceCost(terminalDicNode); + const float compoundDistance = terminalDicNode->getCompoundDistance(languageWeight) + + doubleLetterCost; + const bool isPossiblyOffensiveWord = + traverseSession->getDictionaryStructurePolicy()->getProbability( + terminalDicNode->getProbability(), NOT_A_PROBABILITY) <= 0; + const bool isExactMatch = + ErrorTypeUtils::isExactMatch(terminalDicNode->getContainedErrorTypes()); + const bool isFirstCharUppercase = terminalDicNode->isFirstCharUppercase(); + // Heuristic: We exclude probability=0 first-char-uppercase words from exact match. + // (e.g. "AMD" and "and") + const bool isSafeExactMatch = isExactMatch + && !(isPossiblyOffensiveWord && isFirstCharUppercase); + const int outputTypeFlags = + (isPossiblyOffensiveWord ? Dictionary::KIND_FLAG_POSSIBLY_OFFENSIVE : 0) + | ((isSafeExactMatch && boostExactMatches) ? Dictionary::KIND_FLAG_EXACT_MATCH : 0); + + // Entries that are blacklisted or do not represent a word should not be output. + const bool isValidWord = !terminalDicNode->isBlacklistedOrNotAWord(); + + // Increase output score of top typing suggestion to ensure autocorrection. + // TODO: Better integration with java side autocorrection logic. + const int finalScore = scoringPolicy->calculateFinalScore( + compoundDistance, traverseSession->getInputSize(), + terminalDicNode->getContainedErrorTypes(), + (forceCommitMultiWords && terminalDicNode->hasMultipleWords()) + || (isValidWord && scoringPolicy->doesAutoCorrectValidWord()), + boostExactMatches); + + // Don't output invalid words. However, we still need to submit their shortcuts if any. + if (isValidWord) { + int codePoints[MAX_WORD_LENGTH]; + terminalDicNode->outputResult(codePoints); + const int indexToPartialCommit = outputSecondWordFirstLetterInputIndex ? + terminalDicNode->getSecondWordFirstInputIndex( + traverseSession->getProximityInfoState(0)) : + NOT_AN_INDEX; + outSuggestionResults->addSuggestion(codePoints, + terminalDicNode->getTotalNodeCodePointCount(), + finalScore, Dictionary::KIND_CORRECTION | outputTypeFlags, + indexToPartialCommit, computeFirstWordConfidence(terminalDicNode)); + } + + // Output shortcuts. + // Shortcut is not supported for multiple words suggestions. + // TODO: Check shortcuts during traversal for multiple words suggestions. + if (!terminalDicNode->hasMultipleWords()) { + BinaryDictionaryShortcutIterator shortcutIt( + traverseSession->getDictionaryStructurePolicy()->getShortcutsStructurePolicy(), + traverseSession->getDictionaryStructurePolicy() + ->getShortcutPositionOfPtNode(terminalDicNode->getPtNodePos())); + const bool sameAsTyped = scoringPolicy->sameAsTyped(traverseSession, terminalDicNode); + const int shortcutBaseScore = scoringPolicy->doesAutoCorrectValidWord() ? + scoringPolicy->calculateFinalScore(compoundDistance, + traverseSession->getInputSize(), + terminalDicNode->getContainedErrorTypes(), + true /* forceCommit */, boostExactMatches) : finalScore; + outputShortcuts(&shortcutIt, shortcutBaseScore, sameAsTyped, outSuggestionResults); + } +} + /* static */ int SuggestionsOutputUtils::computeFirstWordConfidence( const DicNode *const terminalDicNode) { // Get the number of spaces in the first suggestion diff --git a/native/jni/src/suggest/core/result/suggestions_output_utils.h b/native/jni/src/suggest/core/result/suggestions_output_utils.h index 26d4b4012..73cdb9561 100644 --- a/native/jni/src/suggest/core/result/suggestions_output_utils.h +++ b/native/jni/src/suggest/core/result/suggestions_output_utils.h @@ -41,11 +41,15 @@ class SuggestionsOutputUtils { // Inputs longer than this will autocorrect if the suggestion is multi-word static const int MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT; - static int computeFirstWordConfidence(const DicNode *const terminalDicNode); - + static void outputSuggestionsOfDicNode(const Scoring *const scoringPolicy, + DicTraverseSession *traverseSession, const DicNode *const terminalDicNode, + const float languageWeight, const bool boostExactMatches, + const bool forceCommitMultiWords, const bool outputSecondWordFirstLetterInputIndex, + SuggestionResults *const outSuggestionResults); static void outputShortcuts(BinaryDictionaryShortcutIterator *const shortcutIt, const int finalScore, const bool sameAsTyped, SuggestionResults *const outSuggestionResults); + static int computeFirstWordConfidence(const DicNode *const terminalDicNode); }; } // namespace latinime #endif // LATINIME_SUGGESTIONS_OUTPUT_UTILS diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.cpp b/native/jni/src/suggest/core/session/dic_traverse_session.cpp index 5070491f4..77b634e07 100644 --- a/native/jni/src/suggest/core/session/dic_traverse_session.cpp +++ b/native/jni/src/suggest/core/session/dic_traverse_session.cpp @@ -68,7 +68,6 @@ void DicTraverseSession::resetCache(const int thresholdForNextActiveDicNodes, co mDicNodesCache.reset(thresholdForNextActiveDicNodes /* nextActiveSize */, maxWords /* terminalSize */); mMultiBigramMap.clear(); - mPartiallyCommited = false; } void DicTraverseSession::initializeProximityInfoStates(const int *const inputCodePoints, diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.h b/native/jni/src/suggest/core/session/dic_traverse_session.h index b718fb57a..9e5d902dd 100644 --- a/native/jni/src/suggest/core/session/dic_traverse_session.h +++ b/native/jni/src/suggest/core/session/dic_traverse_session.h @@ -61,7 +61,7 @@ class DicTraverseSession { AK_FORCE_INLINE DicTraverseSession(JNIEnv *env, jstring localeStr, bool usesLargeCache) : mPrevWordPtNodePos(NOT_A_DICT_POS), mProximityInfo(nullptr), mDictionary(nullptr), mSuggestOptions(nullptr), mDicNodesCache(usesLargeCache), - mMultiBigramMap(), mInputSize(0), mPartiallyCommited(false), mMaxPointerCount(1), + mMultiBigramMap(), mInputSize(0), mMaxPointerCount(1), mMultiWordCostMultiplier(1.0f) { // NOTE: mProximityInfoStates is an array of instances. // No need to initialize it explicitly here. @@ -95,8 +95,6 @@ class DicTraverseSession { return &mProximityInfoStates[id]; } int getInputSize() const { return mInputSize; } - void setPartiallyCommited() { mPartiallyCommited = true; } - bool isPartiallyCommited() const { return mPartiallyCommited; } bool isOnlyOnePointerUsed(int *pointerId) const { // Not in the dictionary word @@ -188,7 +186,6 @@ class DicTraverseSession { ProximityInfoState mProximityInfoStates[MAX_POINTER_COUNT_G]; int mInputSize; - bool mPartiallyCommited; int mMaxPointerCount; ///////////////////////////////// diff --git a/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguagetUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguagetUtilsTests.java new file mode 100644 index 000000000..ff1103e4f --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguagetUtilsTests.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2011 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.utils; + +import android.content.Context; +import android.content.res.Resources; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.inputmethod.latin.RichInputMethodManager; + +import java.util.ArrayList; +import java.util.Locale; + +@SmallTest +public class SpacebarLanguagetUtilsTests extends AndroidTestCase { + // All input method subtypes of LatinIME. + private final ArrayList<InputMethodSubtype> mSubtypesList = CollectionUtils.newArrayList(); + + private RichInputMethodManager mRichImm; + private Resources mRes; + + InputMethodSubtype EN_US; + InputMethodSubtype EN_GB; + InputMethodSubtype ES_US; + InputMethodSubtype FR; + InputMethodSubtype FR_CA; + InputMethodSubtype FR_CH; + InputMethodSubtype DE; + InputMethodSubtype DE_CH; + InputMethodSubtype ZZ; + InputMethodSubtype DE_QWERTY; + InputMethodSubtype FR_QWERTZ; + InputMethodSubtype EN_US_AZERTY; + InputMethodSubtype EN_UK_DVORAK; + InputMethodSubtype ES_US_COLEMAK; + InputMethodSubtype ZZ_AZERTY; + InputMethodSubtype ZZ_PC; + + @Override + protected void setUp() throws Exception { + super.setUp(); + final Context context = getContext(); + RichInputMethodManager.init(context); + mRichImm = RichInputMethodManager.getInstance(); + mRes = context.getResources(); + SubtypeLocaleUtils.init(context); + + final InputMethodInfo imi = mRichImm.getInputMethodInfoOfThisIme(); + final int subtypeCount = imi.getSubtypeCount(); + for (int index = 0; index < subtypeCount; index++) { + final InputMethodSubtype subtype = imi.getSubtypeAt(index); + mSubtypesList.add(subtype); + } + + EN_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + Locale.US.toString(), "qwerty"); + EN_GB = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + Locale.UK.toString(), "qwerty"); + ES_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "es_US", "spanish"); + FR = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + Locale.FRENCH.toString(), "azerty"); + FR_CA = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + Locale.CANADA_FRENCH.toString(), "qwerty"); + FR_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "fr_CH", "swiss"); + DE = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + Locale.GERMAN.toString(), "qwertz"); + DE_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "de_CH", "swiss"); + ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + SubtypeLocaleUtils.NO_LANGUAGE, "qwerty"); + DE_QWERTY = AdditionalSubtypeUtils.createAdditionalSubtype( + Locale.GERMAN.toString(), "qwerty", null); + FR_QWERTZ = AdditionalSubtypeUtils.createAdditionalSubtype( + Locale.FRENCH.toString(), "qwertz", null); + EN_US_AZERTY = AdditionalSubtypeUtils.createAdditionalSubtype( + Locale.US.toString(), "azerty", null); + EN_UK_DVORAK = AdditionalSubtypeUtils.createAdditionalSubtype( + Locale.UK.toString(), "dvorak", null); + ES_US_COLEMAK = AdditionalSubtypeUtils.createAdditionalSubtype( + "es_US", "colemak", null); + ZZ_AZERTY = AdditionalSubtypeUtils.createAdditionalSubtype( + SubtypeLocaleUtils.NO_LANGUAGE, "azerty", null); + ZZ_PC = AdditionalSubtypeUtils.createAdditionalSubtype( + SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty", null); + } + + public void testAllFullDisplayNameForSpacebar() { + for (final InputMethodSubtype subtype : mSubtypesList) { + final String subtypeName = SubtypeLocaleUtils + .getSubtypeDisplayNameInSystemLocale(subtype); + final String spacebarText = SpacebarLanguageUtils.getFullDisplayName(subtype); + final String languageName = SubtypeLocaleUtils + .getSubtypeLocaleDisplayName(subtype.getLocale()); + if (SubtypeLocaleUtils.isNoLanguage(subtype)) { + assertFalse(subtypeName, spacebarText.contains(languageName)); + } else { + assertTrue(subtypeName, spacebarText.contains(languageName)); + } + } + } + + public void testAllMiddleDisplayNameForSpacebar() { + for (final InputMethodSubtype subtype : mSubtypesList) { + final String subtypeName = SubtypeLocaleUtils + .getSubtypeDisplayNameInSystemLocale(subtype); + final String spacebarText = SpacebarLanguageUtils.getMiddleDisplayName(subtype); + if (SubtypeLocaleUtils.isNoLanguage(subtype)) { + assertEquals(subtypeName, + SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype), spacebarText); + } else { + final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype); + assertEquals(subtypeName, + SubtypeLocaleUtils.getSubtypeLocaleDisplayName(locale.getLanguage()), + spacebarText); + } + } + } + + // InputMethodSubtype's display name for spacebar text in its locale. + // isAdditionalSubtype (T=true, F=false) + // locale layout | Middle Full + // ------ ------- - --------- ---------------------- + // en_US qwerty F English English (US) exception + // en_GB qwerty F English English (UK) exception + // es_US spanish F Español Español (EE.UU.) exception + // fr azerty F Français Français + // fr_CA qwerty F Français Français (Canada) + // fr_CH swiss F Français Français (Suisse) + // de qwertz F Deutsch Deutsch + // de_CH swiss F Deutsch Deutsch (Schweiz) + // zz qwerty F QWERTY QWERTY + // fr qwertz T Français Français + // de qwerty T Deutsch Deutsch + // en_US azerty T English English (US) + // zz azerty T AZERTY AZERTY + + private final RunInLocale<Void> testsPredefinedSubtypesForSpacebar = new RunInLocale<Void>() { + @Override + protected Void job(final Resources res) { + assertEquals("en_US", "English (US)", + SpacebarLanguageUtils.getFullDisplayName(EN_US)); + assertEquals("en_GB", "English (UK)", + SpacebarLanguageUtils.getFullDisplayName(EN_GB)); + assertEquals("es_US", "Español (EE.UU.)", + SpacebarLanguageUtils.getFullDisplayName(ES_US)); + assertEquals("fr", "Français", + SpacebarLanguageUtils.getFullDisplayName(FR)); + assertEquals("fr_CA", "Français (Canada)", + SpacebarLanguageUtils.getFullDisplayName(FR_CA)); + assertEquals("fr_CH", "Français (Suisse)", + SpacebarLanguageUtils.getFullDisplayName(FR_CH)); + assertEquals("de", "Deutsch", + SpacebarLanguageUtils.getFullDisplayName(DE)); + assertEquals("de_CH", "Deutsch (Schweiz)", + SpacebarLanguageUtils.getFullDisplayName(DE_CH)); + assertEquals("zz", "QWERTY", + SpacebarLanguageUtils.getFullDisplayName(ZZ)); + + assertEquals("en_US", "English", + SpacebarLanguageUtils.getMiddleDisplayName(EN_US)); + assertEquals("en_GB", "English", + SpacebarLanguageUtils.getMiddleDisplayName(EN_GB)); + assertEquals("es_US", "Español", + SpacebarLanguageUtils.getMiddleDisplayName(ES_US)); + assertEquals("fr", "Français", + SpacebarLanguageUtils.getMiddleDisplayName(FR)); + assertEquals("fr_CA", "Français", + SpacebarLanguageUtils.getMiddleDisplayName(FR_CA)); + assertEquals("fr_CH", "Français", + SpacebarLanguageUtils.getMiddleDisplayName(FR_CH)); + assertEquals("de", "Deutsch", + SpacebarLanguageUtils.getMiddleDisplayName(DE)); + assertEquals("de_CH", "Deutsch", + SpacebarLanguageUtils.getMiddleDisplayName(DE_CH)); + assertEquals("zz", "QWERTY", + SpacebarLanguageUtils.getMiddleDisplayName(ZZ)); + return null; + } + }; + + private final RunInLocale<Void> testsAdditionalSubtypesForSpacebar = new RunInLocale<Void>() { + @Override + protected Void job(final Resources res) { + assertEquals("fr qwertz", "Français", + SpacebarLanguageUtils.getFullDisplayName(FR_QWERTZ)); + assertEquals("de qwerty", "Deutsch", + SpacebarLanguageUtils.getFullDisplayName(DE_QWERTY)); + assertEquals("en_US azerty", "English (US)", + SpacebarLanguageUtils.getFullDisplayName(EN_US_AZERTY)); + assertEquals("en_UK dvorak", "English (UK)", + SpacebarLanguageUtils.getFullDisplayName(EN_UK_DVORAK)); + assertEquals("es_US colemak", "Español (EE.UU.)", + SpacebarLanguageUtils.getFullDisplayName(ES_US_COLEMAK)); + assertEquals("zz azerty", "AZERTY", + SpacebarLanguageUtils.getFullDisplayName(ZZ_AZERTY)); + assertEquals("zz pc", "PC", + SpacebarLanguageUtils.getFullDisplayName(ZZ_PC)); + + assertEquals("fr qwertz", "Français", + SpacebarLanguageUtils.getMiddleDisplayName(FR_QWERTZ)); + assertEquals("de qwerty", "Deutsch", + SpacebarLanguageUtils.getMiddleDisplayName(DE_QWERTY)); + assertEquals("en_US azerty", "English", + SpacebarLanguageUtils.getMiddleDisplayName(EN_US_AZERTY)); + assertEquals("en_UK dvorak", "English", + SpacebarLanguageUtils.getMiddleDisplayName(EN_UK_DVORAK)); + assertEquals("es_US colemak", "Español", + SpacebarLanguageUtils.getMiddleDisplayName(ES_US_COLEMAK)); + assertEquals("zz azerty", "AZERTY", + SpacebarLanguageUtils.getMiddleDisplayName(ZZ_AZERTY)); + assertEquals("zz pc", "PC", + SpacebarLanguageUtils.getMiddleDisplayName(ZZ_PC)); + return null; + } + }; + + public void testPredefinedSubtypesForSpacebarInEnglish() { + testsPredefinedSubtypesForSpacebar.runInLocale(mRes, Locale.ENGLISH); + } + + public void testAdditionalSubtypeForSpacebarInEnglish() { + testsAdditionalSubtypesForSpacebar.runInLocale(mRes, Locale.ENGLISH); + } + + public void testPredefinedSubtypesForSpacebarInFrench() { + testsPredefinedSubtypesForSpacebar.runInLocale(mRes, Locale.FRENCH); + } + + public void testAdditionalSubtypeForSpacebarInFrench() { + testsAdditionalSubtypesForSpacebar.runInLocale(mRes, Locale.FRENCH); + } +} diff --git a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java index eb8a61a16..ee345905c 100644 --- a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java @@ -123,12 +123,23 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { assertEquals("en_US", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(EN_US)); assertEquals("en_GB", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(EN_GB)); assertEquals("es_US", "spanish", SubtypeLocaleUtils.getKeyboardLayoutSetName(ES_US)); - assertEquals("fr ", "azerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR)); + assertEquals("fr", "azerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR)); assertEquals("fr_CA", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_CA)); assertEquals("fr_CH", "swiss", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_CH)); - assertEquals("de ", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE)); + assertEquals("de", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE)); assertEquals("de_CH", "swiss", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE_CH)); - assertEquals("zz ", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ)); + assertEquals("zz", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ)); + + assertEquals("de qwerty", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE_QWERTY)); + assertEquals("fr qwertz", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_QWERTZ)); + assertEquals("en_US azerty", "azerty", + SubtypeLocaleUtils.getKeyboardLayoutSetName(EN_US_AZERTY)); + assertEquals("en_UK dvorak", "dvorak", + SubtypeLocaleUtils.getKeyboardLayoutSetName(EN_UK_DVORAK)); + assertEquals("es_US colemak", "colemak", + SubtypeLocaleUtils.getKeyboardLayoutSetName(ES_US_COLEMAK)); + assertEquals("zz azerty", "azerty", + SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ_AZERTY)); } // InputMethodSubtype's display name in system locale (en_US). @@ -161,17 +172,17 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_GB)); assertEquals("es_US", "Spanish (US)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ES_US)); - assertEquals("fr ", "French", + assertEquals("fr", "French", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR)); assertEquals("fr_CA", "French (Canada)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CA)); assertEquals("fr_CH", "French (Switzerland)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CH)); - assertEquals("de ", "German", + assertEquals("de", "German", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE)); assertEquals("de_CH", "German (Switzerland)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_CH)); - assertEquals("zz ", "Alphabet (QWERTY)", + assertEquals("zz", "Alphabet (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ)); return null; } @@ -183,17 +194,19 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { final RunInLocale<Void> tests = new RunInLocale<Void>() { @Override protected Void job(final Resources res) { - assertEquals("fr qwertz", "French (QWERTZ)", + assertEquals("fr qwertz", "French (QWERTZ)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_QWERTZ)); - assertEquals("de qwerty", "German (QWERTY)", + assertEquals("de qwerty", "German (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_QWERTY)); assertEquals("en_US azerty", "English (US) (AZERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_US_AZERTY)); - assertEquals("en_UK dvorak", "English (UK) (Dvorak)", + assertEquals("en_UK dvorak","English (UK) (Dvorak)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_UK_DVORAK)); - assertEquals("es_US colemak","Spanish (US) (Colemak)", + assertEquals("es_US colemak", "Spanish (US) (Colemak)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ES_US_COLEMAK)); - assertEquals("zz pc", "Alphabet (PC)", + assertEquals("zz azerty", "Alphabet (AZERTY)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_AZERTY)); + assertEquals("zz pc", "Alphabet (PC)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_PC)); return null; } @@ -231,17 +244,17 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_GB)); assertEquals("es_US", "Espagnol (États-Unis)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ES_US)); - assertEquals("fr ", "Français", + assertEquals("fr", "Français", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR)); assertEquals("fr_CA", "Français (Canada)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CA)); assertEquals("fr_CH", "Français (Suisse)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CH)); - assertEquals("de ", "Allemand", + assertEquals("de", "Allemand", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE)); assertEquals("de_CH", "Allemand (Suisse)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_CH)); - assertEquals("zz ", "Alphabet latin (QWERTY)", + assertEquals("zz", "Alphabet latin (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ)); return null; } @@ -253,17 +266,19 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { final RunInLocale<Void> tests = new RunInLocale<Void>() { @Override protected Void job(final Resources res) { - assertEquals("fr qwertz", "Français (QWERTZ)", + assertEquals("fr qwertz", "Français (QWERTZ)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_QWERTZ)); - assertEquals("de qwerty", "Allemand (QWERTY)", + assertEquals("de qwerty", "Allemand (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_QWERTY)); assertEquals("en_US azerty", "Anglais (États-Unis) (AZERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_US_AZERTY)); assertEquals("en_UK dvorak", "Anglais (Royaume-Uni) (Dvorak)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_UK_DVORAK)); - assertEquals("es_US colemak","Espagnol (États-Unis) (Colemak)", + assertEquals("es_US colemak", "Espagnol (États-Unis) (Colemak)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ES_US_COLEMAK)); - assertEquals("zz pc", "Alphabet latin (PC)", + assertEquals("zz azerty", "Alphabet latin (AZERTY)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_AZERTY)); + assertEquals("zz pc", "Alphabet latin (PC)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_PC)); return null; } @@ -271,126 +286,6 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { tests.runInLocale(mRes, Locale.FRENCH); } - public void testAllFullDisplayNameForSpacebar() { - for (final InputMethodSubtype subtype : mSubtypesList) { - final String subtypeName = SubtypeLocaleUtils - .getSubtypeDisplayNameInSystemLocale(subtype); - final String spacebarText = SubtypeLocaleUtils.getFullDisplayName(subtype); - final String languageName = SubtypeLocaleUtils - .getSubtypeLocaleDisplayName(subtype.getLocale()); - if (SubtypeLocaleUtils.isNoLanguage(subtype)) { - assertFalse(subtypeName, spacebarText.contains(languageName)); - } else { - assertTrue(subtypeName, spacebarText.contains(languageName)); - } - } - } - - public void testAllMiddleDisplayNameForSpacebar() { - for (final InputMethodSubtype subtype : mSubtypesList) { - final String subtypeName = SubtypeLocaleUtils - .getSubtypeDisplayNameInSystemLocale(subtype); - final String spacebarText = SubtypeLocaleUtils.getMiddleDisplayName(subtype); - if (SubtypeLocaleUtils.isNoLanguage(subtype)) { - assertEquals(subtypeName, - SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype), spacebarText); - } else { - final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype); - assertEquals(subtypeName, - SubtypeLocaleUtils.getSubtypeLocaleDisplayName(locale.getLanguage()), - spacebarText); - } - } - } - - // InputMethodSubtype's display name for spacebar text in its locale. - // isAdditionalSubtype (T=true, F=false) - // locale layout | Middle Full - // ------ ------- - --------- ---------------------- - // en_US qwerty F English English (US) exception - // en_GB qwerty F English English (UK) exception - // es_US spanish F Español Español (EE.UU.) exception - // fr azerty F Français Français - // fr_CA qwerty F Français Français (Canada) - // fr_CH swiss F Français Français (Suisse) - // de qwertz F Deutsch Deutsch - // de_CH swiss F Deutsch Deutsch (Schweiz) - // zz qwerty F QWERTY QWERTY - // fr qwertz T Français Français - // de qwerty T Deutsch Deutsch - // en_US azerty T English English (US) - // zz azerty T AZERTY AZERTY - - private final RunInLocale<Void> testsPredefinedSubtypesForSpacebar = new RunInLocale<Void>() { - @Override - protected Void job(final Resources res) { - assertEquals("en_US", "English (US)", SubtypeLocaleUtils.getFullDisplayName(EN_US)); - assertEquals("en_GB", "English (UK)", SubtypeLocaleUtils.getFullDisplayName(EN_GB)); - assertEquals("es_US", "Español (EE.UU.)", - SubtypeLocaleUtils.getFullDisplayName(ES_US)); - assertEquals("fr ", "Français", SubtypeLocaleUtils.getFullDisplayName(FR)); - assertEquals("fr_CA", "Français (Canada)", - SubtypeLocaleUtils.getFullDisplayName(FR_CA)); - assertEquals("fr_CH", "Français (Suisse)", - SubtypeLocaleUtils.getFullDisplayName(FR_CH)); - assertEquals("de ", "Deutsch", SubtypeLocaleUtils.getFullDisplayName(DE)); - assertEquals("de_CH", "Deutsch (Schweiz)", - SubtypeLocaleUtils.getFullDisplayName(DE_CH)); - assertEquals("zz ", "QWERTY", SubtypeLocaleUtils.getFullDisplayName(ZZ)); - - assertEquals("en_US", "English", SubtypeLocaleUtils.getMiddleDisplayName(EN_US)); - assertEquals("en_GB", "English", SubtypeLocaleUtils.getMiddleDisplayName(EN_GB)); - assertEquals("es_US", "Español", SubtypeLocaleUtils.getMiddleDisplayName(ES_US)); - assertEquals("fr ", "Français", SubtypeLocaleUtils.getMiddleDisplayName(FR)); - assertEquals("fr_CA", "Français", SubtypeLocaleUtils.getMiddleDisplayName(FR_CA)); - assertEquals("fr_CH", "Français", SubtypeLocaleUtils.getMiddleDisplayName(FR_CH)); - assertEquals("de ", "Deutsch", SubtypeLocaleUtils.getMiddleDisplayName(DE)); - assertEquals("de_CH", "Deutsch", SubtypeLocaleUtils.getMiddleDisplayName(DE_CH)); - assertEquals("zz ", "QWERTY", SubtypeLocaleUtils.getMiddleDisplayName(ZZ)); - return null; - } - }; - - private final RunInLocale<Void> testsAdditionalSubtypesForSpacebar = new RunInLocale<Void>() { - @Override - protected Void job(final Resources res) { - assertEquals("fr qwertz", "Français", - SubtypeLocaleUtils.getFullDisplayName(FR_QWERTZ)); - assertEquals("de qwerty", "Deutsch", - SubtypeLocaleUtils.getFullDisplayName(DE_QWERTY)); - assertEquals("en_US azerty", "English (US)", - SubtypeLocaleUtils.getFullDisplayName(EN_US_AZERTY)); - assertEquals("zz azerty", "AZERTY", - SubtypeLocaleUtils.getFullDisplayName(ZZ_AZERTY)); - - assertEquals("fr qwertz", "Français", - SubtypeLocaleUtils.getMiddleDisplayName(FR_QWERTZ)); - assertEquals("de qwerty", "Deutsch", - SubtypeLocaleUtils.getMiddleDisplayName(DE_QWERTY)); - assertEquals("en_US azerty", "English", - SubtypeLocaleUtils.getMiddleDisplayName(EN_US_AZERTY)); - assertEquals("zz azerty", "AZERTY", - SubtypeLocaleUtils.getMiddleDisplayName(ZZ_AZERTY)); - return null; - } - }; - - public void testPredefinedSubtypesForSpacebarInEnglish() { - testsPredefinedSubtypesForSpacebar.runInLocale(mRes, Locale.ENGLISH); - } - - public void testAdditionalSubtypeForSpacebarInEnglish() { - testsAdditionalSubtypesForSpacebar.runInLocale(mRes, Locale.ENGLISH); - } - - public void testPredefinedSubtypesForSpacebarInFrench() { - testsPredefinedSubtypesForSpacebar.runInLocale(mRes, Locale.FRENCH); - } - - public void testAdditionalSubtypeForSpacebarInFrench() { - testsAdditionalSubtypesForSpacebar.runInLocale(mRes, Locale.FRENCH); - } - public void testIsRtlLanguage() { // Known Right-to-Left language subtypes. final InputMethodSubtype ARABIC = mRichImm |