diff options
Diffstat (limited to 'java/src/com')
16 files changed, 190 insertions, 171 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 81825934f..702efb3d7 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -451,7 +451,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack locatePreviewPlacerView(); getLocationInWindow(mOriginCoords); - mKeyPreviewChoreographer.placeKeyPreviewAndShow(key, keyboard.mIconsSet, mKeyDrawParams, + mKeyPreviewChoreographer.placeAndShowKeyPreview(key, keyboard.mIconsSet, mKeyDrawParams, getWidth(), mOriginCoords, mDrawingPreviewPlacerView, isHardwareAccelerated()); } @@ -554,11 +554,11 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack // though there may be some chances that the value is zero. <code>width == 0</code> // will cause zero-division error at // {@link MoreKeysKeyboardParams#setParameters(int,int,int,int,int,int,boolean,int)}. - final boolean singleMoreKeyWithPreview = mKeyPreviewDrawParams.isPopupEnabled() + final boolean isSingleMoreKeyWithPreview = mKeyPreviewDrawParams.isPopupEnabled() && !key.noKeyPreview() && moreKeys.length == 1 && mKeyPreviewDrawParams.getVisibleWidth() > 0; final MoreKeysKeyboard.Builder builder = new MoreKeysKeyboard.Builder( - context, key, getKeyboard(), singleMoreKeyWithPreview, + context, key, getKeyboard(), isSingleMoreKeyWithPreview, mKeyPreviewDrawParams.getVisibleWidth(), mKeyPreviewDrawParams.getVisibleHeight(), newLabelPaint(key)); moreKeysKeyboard = builder.build(); diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java index 353e07cf7..e0184d7f1 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java @@ -261,13 +261,13 @@ public final class MoreKeysKeyboard extends Keyboard { * @param context the context of {@link MoreKeysKeyboardView}. * @param key the {@link Key} that invokes more keys keyboard. * @param keyboard the {@link Keyboard} that contains the parentKey. - * @param singleMoreKeyWithPreview true if the <code>key</code> has only one more key - * and key popup preview is enabled. + * @param isSingleMoreKeyWithPreview true if the <code>key</code> has just a single + * "more key" and its key popup preview is enabled. * @param keyPreviewDrawParams the parameter to place key preview. - * @param paintToMeasure the {@link Paint} object to measure a more key width + * @param paintToMeasure the {@link Paint} object to measure a "more key" width */ public Builder(final Context context, final Key key, final Keyboard keyboard, - final boolean singleMoreKeyWithPreview, final int keyPreviewVisibleWidth, + final boolean isSingleMoreKeyWithPreview, final int keyPreviewVisibleWidth, final int keyPreviewVisibleHeight, final Paint paintToMeasure) { super(context, new MoreKeysKeyboardParams()); load(keyboard.mMoreKeysTemplate, keyboard.mId); @@ -275,10 +275,11 @@ public final class MoreKeysKeyboard extends Keyboard { // TODO: More keys keyboard's vertical gap is currently calculated heuristically. // Should revise the algorithm. mParams.mVerticalGap = keyboard.mVerticalGap / 2; + // This {@link MoreKeysKeyboard} is invoked from the <code>key</code>. mParentKey = key; final int keyWidth, rowHeight; - if (singleMoreKeyWithPreview) { + if (isSingleMoreKeyWithPreview) { // Use pre-computed width and height if this more keys keyboard has only one key to // mitigate visual flicker between key preview and more keys keyboard. // Caveats for the visual assets: To achieve this effect, both the key preview diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java index 6fc300beb..cd29c8d17 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java @@ -105,7 +105,7 @@ public final class KeyPreviewChoreographer { mFreeKeyPreviewViews.add(keyPreviewView); } - public void placeKeyPreviewAndShow(final Key key, final KeyboardIconsSet iconsSet, + public void placeAndShowKeyPreview(final Key key, final KeyboardIconsSet iconsSet, final KeyDrawParams drawParams, final int keyboardViewWidth, final int[] keyboardOrigin, final ViewGroup placerView, final boolean withAnimation) { final KeyPreviewView keyPreviewView = getKeyPreviewView(key, placerView); diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 0c196f2a3..95e1340ed 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -64,11 +64,12 @@ public final class BinaryDictionary extends Dictionary { public static final int NOT_A_VALID_TIMESTAMP = -1; // Format to get unigram flags from native side via getWordPropertyNative(). - private static final int FORMAT_WORD_PROPERTY_OUTPUT_FLAG_COUNT = 4; + private static final int FORMAT_WORD_PROPERTY_OUTPUT_FLAG_COUNT = 5; private static final int FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX = 0; private static final int FORMAT_WORD_PROPERTY_IS_BLACKLISTED_INDEX = 1; private static final int FORMAT_WORD_PROPERTY_HAS_BIGRAMS_INDEX = 2; private static final int FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX = 3; + private static final int FORMAT_WORD_PROPERTY_IS_BEGINNING_OF_SENTENCE_INDEX = 4; // Format to get probability and historical info from native side via getWordPropertyNative(). public static final int FORMAT_WORD_PROPERTY_OUTPUT_PROBABILITY_INFO_COUNT = 4; @@ -176,10 +177,12 @@ public final class BinaryDictionary extends Dictionary { private static native int getNgramProbabilityNative(long dict, int[] word0, boolean isBeginningOfSentence, int[] word1); private static native void getWordPropertyNative(long dict, int[] word, - int[] outCodePoints, boolean[] outFlags, int[] outProbabilityInfo, - ArrayList<int[]> outBigramTargets, ArrayList<int[]> outBigramProbabilityInfo, - ArrayList<int[]> outShortcutTargets, ArrayList<Integer> outShortcutProbabilities); - private static native int getNextWordNative(long dict, int token, int[] outCodePoints); + boolean isBeginningOfSentence, int[] outCodePoints, boolean[] outFlags, + int[] outProbabilityInfo, ArrayList<int[]> outBigramTargets, + ArrayList<int[]> outBigramProbabilityInfo, ArrayList<int[]> outShortcutTargets, + ArrayList<Integer> outShortcutProbabilities); + private static native int getNextWordNative(long dict, int token, int[] outCodePoints, + boolean[] outIsBeginningOfSentence); private static native void getSuggestionsNative(long dict, long proximityInfo, long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times, int[] pointerIds, int[] inputCodePoints, int inputSize, int[] suggestOptions, @@ -360,8 +363,8 @@ public final class BinaryDictionary extends Dictionary { isBeginningOfSentenceArray[0], wordCodePoints); } - public WordProperty getWordProperty(final String word) { - if (TextUtils.isEmpty(word)) { + public WordProperty getWordProperty(final String word, final boolean isBeginningOfSentence) { + if (word == null) { return null; } final int[] codePoints = StringUtils.toCodePointArray(word); @@ -373,14 +376,15 @@ public final class BinaryDictionary extends Dictionary { final ArrayList<int[]> outBigramProbabilityInfo = new ArrayList<>(); final ArrayList<int[]> outShortcutTargets = new ArrayList<>(); final ArrayList<Integer> outShortcutProbabilities = new ArrayList<>(); - getWordPropertyNative(mNativeDict, codePoints, outCodePoints, outFlags, outProbabilityInfo, - outBigramTargets, outBigramProbabilityInfo, outShortcutTargets, - outShortcutProbabilities); + getWordPropertyNative(mNativeDict, codePoints, isBeginningOfSentence, outCodePoints, + outFlags, outProbabilityInfo, outBigramTargets, outBigramProbabilityInfo, + outShortcutTargets, outShortcutProbabilities); return new WordProperty(codePoints, outFlags[FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX], outFlags[FORMAT_WORD_PROPERTY_IS_BLACKLISTED_INDEX], outFlags[FORMAT_WORD_PROPERTY_HAS_BIGRAMS_INDEX], - outFlags[FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX], outProbabilityInfo, + outFlags[FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX], + outFlags[FORMAT_WORD_PROPERTY_IS_BEGINNING_OF_SENTENCE_INDEX], outProbabilityInfo, outBigramTargets, outBigramProbabilityInfo, outShortcutTargets, outShortcutProbabilities); } @@ -401,9 +405,12 @@ public final class BinaryDictionary extends Dictionary { */ public GetNextWordPropertyResult getNextWordProperty(final int token) { final int[] codePoints = new int[Constants.DICTIONARY_MAX_WORD_LENGTH]; - final int nextToken = getNextWordNative(mNativeDict, token, codePoints); + final boolean[] isBeginningOfSentence = new boolean[1]; + final int nextToken = getNextWordNative(mNativeDict, token, codePoints, + isBeginningOfSentence); final String word = StringUtils.getStringFromNullTerminatedCodePointArray(codePoints); - return new GetNextWordPropertyResult(getWordProperty(word), nextToken); + return new GetNextWordPropertyResult( + getWordProperty(word, isBeginningOfSentence[0]), nextToken); } // Add a unigram entry to binary dictionary with unigram attributes in native code. diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java index 2f1aca6a3..b8feb2278 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java @@ -487,7 +487,7 @@ public class DictionaryFacilitator { public SuggestionResults getSuggestionResults(final WordComposer composer, final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo, final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, - final int sessionId, final ArrayList<SuggestedWordInfo> rawSuggestions) { + final int sessionId) { final Dictionaries dictionaries = mDictionaries; final SuggestionResults suggestionResults = new SuggestionResults(dictionaries.mLocale, SuggestedWords.MAX_SUGGESTIONS); @@ -501,21 +501,13 @@ public class DictionaryFacilitator { languageWeight); if (null == dictionarySuggestions) continue; suggestionResults.addAll(dictionarySuggestions); - if (null != rawSuggestions) { - rawSuggestions.addAll(dictionarySuggestions); + if (null != suggestionResults.mRawSuggestions) { + suggestionResults.mRawSuggestions.addAll(dictionarySuggestions); } } return suggestionResults; } - public boolean isValidMainDictWord(final String word) { - final Dictionary mainDict = mDictionaries.getDict(Dictionary.TYPE_MAIN); - if (TextUtils.isEmpty(word) || mainDict == null) { - return false; - } - return mainDict.isValidWord(word); - } - public boolean isValidWord(final String word, final boolean ignoreCase) { if (TextUtils.isEmpty(word)) { return false; diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 1884e41e4..37879cf68 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -122,12 +122,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { return mBinaryDictionary.isValidDictionary(); } - // TODO: Remove and always enable beginning of sentence prediction. Currently, this is enabled - // only for ContextualDictionary. - protected boolean enableBeginningOfSentencePrediction() { - return false; - } - /** * Creates a new expandable binary dictionary. * diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 670d856e3..9d03e8a43 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -100,30 +100,43 @@ public final class Suggest { ? typedWord.substring(0, typedWord.length() - trailingSingleQuotesCount) : typedWord; - final ArrayList<SuggestedWordInfo> rawSuggestions; - if (ProductionFlag.INCLUDE_RAW_SUGGESTIONS) { - rawSuggestions = new ArrayList<>(); - } else { - rawSuggestions = null; - } final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults( wordComposer, prevWordsInfo, proximityInfo, blockOffensiveWords, - additionalFeaturesOptions, SESSION_TYPING, rawSuggestions); + additionalFeaturesOptions, SESSION_TYPING); + final boolean isPrediction = !wordComposer.isComposingWord(); + final boolean shouldMakeSuggestionsAllUpperCase = wordComposer.isAllUpperCase() + && !wordComposer.isResumed(); final boolean isOnlyFirstCharCapitalized = wordComposer.isOrWillBeOnlyFirstCharCapitalized(); + + final ArrayList<SuggestedWordInfo> suggestionsContainer = + new ArrayList<>(suggestionResults); + final int suggestionsCount = suggestionsContainer.size(); + if (isOnlyFirstCharCapitalized || shouldMakeSuggestionsAllUpperCase + || 0 != trailingSingleQuotesCount) { + for (int i = 0; i < suggestionsCount; ++i) { + final SuggestedWordInfo wordInfo = suggestionsContainer.get(i); + final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo( + wordInfo, suggestionResults.mLocale, shouldMakeSuggestionsAllUpperCase, + isOnlyFirstCharCapitalized, trailingSingleQuotesCount); + suggestionsContainer.set(i, transformedWordInfo); + } + } + SuggestedWordInfo.removeDups(typedWord, suggestionsContainer); + // If resumed, then we don't want to upcase everything: resuming on a fully-capitalized // words is rarely done to switch to another fully-capitalized word, but usually to a // normal, non-capitalized suggestion. - final boolean isAllUpperCase = wordComposer.isAllUpperCase() && !wordComposer.isResumed(); final String firstSuggestion; final String whitelistedWord; if (suggestionResults.isEmpty()) { whitelistedWord = firstSuggestion = null; } else { final SuggestedWordInfo firstSuggestedWordInfo = getTransformedSuggestedWordInfo( - suggestionResults.first(), suggestionResults.mLocale, isAllUpperCase, - isOnlyFirstCharCapitalized, trailingSingleQuotesCount); + suggestionResults.first(), suggestionResults.mLocale, + shouldMakeSuggestionsAllUpperCase, isOnlyFirstCharCapitalized, + trailingSingleQuotesCount); firstSuggestion = firstSuggestedWordInfo.mWord; if (!firstSuggestedWordInfo.isKindOf(SuggestedWordInfo.KIND_WHITELIST)) { whitelistedWord = null; @@ -132,8 +145,6 @@ public final class Suggest { } } - final boolean isPrediction = !wordComposer.isComposingWord(); - // We allow auto-correction if we have a whitelisted word, or if the word is not a valid // word of more than 1 char, except if the first suggestion is the same as the typed string // because in this case if it's strong enough to auto-correct that will mistakenly designate @@ -171,19 +182,6 @@ public final class Suggest { suggestionResults.first(), consideredWord, mAutoCorrectionThreshold); } - final ArrayList<SuggestedWordInfo> suggestionsContainer = - new ArrayList<>(suggestionResults); - final int suggestionsCount = suggestionsContainer.size(); - if (isOnlyFirstCharCapitalized || isAllUpperCase || 0 != trailingSingleQuotesCount) { - for (int i = 0; i < suggestionsCount; ++i) { - final SuggestedWordInfo wordInfo = suggestionsContainer.get(i); - final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo( - wordInfo, suggestionResults.mLocale, isAllUpperCase, - isOnlyFirstCharCapitalized, trailingSingleQuotesCount); - suggestionsContainer.set(i, transformedWordInfo); - } - } - if (!TextUtils.isEmpty(typedWord)) { suggestionsContainer.add(0, new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_TYPED, @@ -191,7 +189,6 @@ public final class Suggest { SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */, SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */)); } - SuggestedWordInfo.removeDups(suggestionsContainer); final ArrayList<SuggestedWordInfo> suggestionsList; if (DBG && !suggestionsContainer.isEmpty()) { @@ -200,12 +197,13 @@ public final class Suggest { suggestionsList = suggestionsContainer; } - callback.onGetSuggestedWords(new SuggestedWords(suggestionsList, rawSuggestions, + callback.onGetSuggestedWords(new SuggestedWords(suggestionsList, + suggestionResults.mRawSuggestions, // TODO: this first argument is lying. If this is a whitelisted word which is an // actual word, it says typedWordValid = false, which looks wrong. We should either // rename the attribute or change the value. !isPrediction && !allowsToBeAutoCorrected /* typedWordValid */, - hasAutoCorrection, /* willAutoCorrect */ + hasAutoCorrection /* willAutoCorrect */, false /* isObsoleteSuggestions */, isPrediction, sequenceNumber)); } @@ -216,15 +214,9 @@ public final class Suggest { final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, final int sessionId, final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { - final ArrayList<SuggestedWordInfo> rawSuggestions; - if (ProductionFlag.INCLUDE_RAW_SUGGESTIONS) { - rawSuggestions = new ArrayList<>(); - } else { - rawSuggestions = null; - } final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults( wordComposer, prevWordsInfo, proximityInfo, blockOffensiveWords, - additionalFeaturesOptions, sessionId, rawSuggestions); + additionalFeaturesOptions, sessionId); final ArrayList<SuggestedWordInfo> suggestionsContainer = new ArrayList<>(suggestionResults); final int suggestionsCount = suggestionsContainer.size(); @@ -245,7 +237,7 @@ public final class Suggest { final SuggestedWordInfo rejected = suggestionsContainer.remove(0); suggestionsContainer.add(1, rejected); } - SuggestedWordInfo.removeDups(suggestionsContainer); + SuggestedWordInfo.removeDups(null /* typedWord */, suggestionsContainer); // For some reason some suggestions with MIN_VALUE are making their way here. // TODO: Find a more robust way to detect distractors. @@ -257,7 +249,8 @@ public final class Suggest { // In the batch input mode, the most relevant suggested word should act as a "typed word" // (typedWordValid=true), not as an "auto correct word" (willAutoCorrect=false). - callback.onGetSuggestedWords(new SuggestedWords(suggestionsContainer, rawSuggestions, + callback.onGetSuggestedWords(new SuggestedWords(suggestionsContainer, + suggestionResults.mRawSuggestions, true /* typedWordValid */, false /* willAutoCorrect */, false /* isObsoleteSuggestions */, diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index 72461e17a..f22af7991 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -316,10 +316,6 @@ public class SuggestedWords { return mDebugString; } - public int codePointCount() { - return mCodePointCount; - } - public int codePointAt(int i) { return mWord.codePointAt(i); } @@ -333,23 +329,29 @@ public class SuggestedWords { } } - // TODO: Consolidate this method and StringUtils.removeDupes() in the future. - public static void removeDups(ArrayList<SuggestedWordInfo> candidates) { - if (candidates.size() <= 1) { + // This will always remove the higher index if a duplicate is found. + public static void removeDups(final String typedWord, + ArrayList<SuggestedWordInfo> candidates) { + if (candidates.isEmpty()) { return; } - int i = 1; - while (i < candidates.size()) { - final SuggestedWordInfo cur = candidates.get(i); - for (int j = 0; j < i; ++j) { - final SuggestedWordInfo previous = candidates.get(j); - if (cur.mWord.equals(previous.mWord)) { - candidates.remove(cur.mScore < previous.mScore ? i : j); - --i; - break; - } + if (!TextUtils.isEmpty(typedWord)) { + removeSuggestedWordInfoFrom(typedWord, candidates, -1 /* startIndexExclusive */); + } + for (int i = 0; i < candidates.size(); ++i) { + removeSuggestedWordInfoFrom(candidates.get(i).mWord, candidates, + i /* startIndexExclusive */); + } + } + + private static void removeSuggestedWordInfoFrom(final String word, + final ArrayList<SuggestedWordInfo> candidates, final int startIndexExclusive) { + for (int i = startIndexExclusive + 1; i < candidates.size(); ++i) { + final SuggestedWordInfo previous = candidates.get(i); + if (word.equals(previous.mWord)) { + candidates.remove(i); + --i; } - ++i; } } } diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 32c6942f7..c9d0dcf60 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -728,14 +728,13 @@ public final class InputLogic { mConnection.setComposingText(getTextWithUnderline( mWordComposer.getTypedWord()), 1); } else { - final boolean swapWeakSpace = maybeStripSpace(inputTransaction, - inputTransaction.mEvent.isSuggestionStripPress()); + final boolean swapWeakSpace = tryStripSpaceAndReturnWhetherShouldSwapInstead( + inputTransaction, inputTransaction.mEvent.isSuggestionStripPress()); - sendKeyCodePoint(settingsValues, codePoint); - - if (swapWeakSpace) { - swapSwapperAndSpace(inputTransaction); + if (swapWeakSpace && trySwapSwapperAndSpace(inputTransaction)) { mSpaceState = SpaceState.WEAK; + } else { + sendKeyCodePoint(settingsValues, codePoint); } // In case the "add to dictionary" hint was still displayed. mSuggestionStripViewAccessor.dismissAddToDictionaryHint(); @@ -780,7 +779,8 @@ public final class InputLogic { } } - final boolean swapWeakSpace = maybeStripSpace(inputTransaction, isFromSuggestionStrip); + final boolean swapWeakSpace = tryStripSpaceAndReturnWhetherShouldSwapInstead( + inputTransaction, isFromSuggestionStrip); final boolean isInsideDoubleQuoteOrAfterDigit = Constants.CODE_DOUBLE_QUOTE == codePoint && mConnection.isInsideDoubleQuoteOrAfterDigit(); @@ -804,16 +804,14 @@ public final class InputLogic { promotePhantomSpace(settingsValues); } - if (!shouldAvoidSendingCode) { - sendKeyCodePoint(settingsValues, codePoint); - } - - if (Constants.CODE_SPACE == codePoint) { - if (maybeDoubleSpacePeriod(inputTransaction)) { - inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); - inputTransaction.setRequiresUpdateSuggestions(); - mSpaceState = SpaceState.DOUBLE; - } else if (!mSuggestedWords.isPunctuationSuggestions()) { + if (tryPerformDoubleSpacePeriod(inputTransaction)) { + mSpaceState = SpaceState.DOUBLE; + inputTransaction.setRequiresUpdateSuggestions(); + } else if (swapWeakSpace && trySwapSwapperAndSpace(inputTransaction)) { + mSpaceState = SpaceState.SWAP_PUNCTUATION; + mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); + } else if (Constants.CODE_SPACE == codePoint) { + if (!mSuggestedWords.isPunctuationSuggestions()) { mSpaceState = SpaceState.WEAK; } @@ -821,11 +819,12 @@ public final class InputLogic { if (wasComposingWord || mSuggestedWords.isEmpty()) { inputTransaction.setRequiresUpdateSuggestions(); } + + if (!shouldAvoidSendingCode) { + sendKeyCodePoint(settingsValues, codePoint); + } } else { - if (swapWeakSpace) { - swapSwapperAndSpace(inputTransaction); - mSpaceState = SpaceState.SWAP_PUNCTUATION; - } else if ((SpaceState.PHANTOM == inputTransaction.mSpaceState + if ((SpaceState.PHANTOM == inputTransaction.mSpaceState && settingsValues.isUsuallyFollowedBySpace(codePoint)) || (Constants.CODE_DOUBLE_QUOTE == codePoint && isInsideDoubleQuoteOrAfterDigit)) { @@ -843,6 +842,8 @@ public final class InputLogic { mSpaceState = SpaceState.PHANTOM; } + sendKeyCodePoint(settingsValues, codePoint); + // Set punctuation right away. onUpdateSelection will fire but tests whether it is // already displayed or not, so it's okay. mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); @@ -1008,16 +1009,18 @@ public final class InputLogic { * This method will check that there are two characters before the cursor and that the first * one is a space before it does the actual swapping. * @param inputTransaction The transaction in progress. + * @return true if the swap has been performed, false if it was prevented by preliminary checks. */ - private void swapSwapperAndSpace(final InputTransaction inputTransaction) { - final CharSequence lastTwo = mConnection.getTextBeforeCursor(2, 0); - // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called. - if (lastTwo != null && lastTwo.length() == 2 && lastTwo.charAt(0) == Constants.CODE_SPACE) { - mConnection.deleteSurroundingText(2, 0); - final String text = lastTwo.charAt(1) + " "; - mConnection.commitText(text, 1); - inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); + private boolean trySwapSwapperAndSpace(final InputTransaction inputTransaction) { + final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor(); + if (Constants.CODE_SPACE != codePointBeforeCursor) { + return false; } + mConnection.deleteSurroundingText(1, 0); + final String text = inputTransaction.mEvent.getTextToCommit() + " "; + mConnection.commitText(text, 1); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); + return true; } /* @@ -1026,8 +1029,8 @@ public final class InputLogic { * @param isFromSuggestionStrip Whether this code point is coming from the suggestion strip. * @return whether we should swap the space instead of removing it. */ - private boolean maybeStripSpace(final InputTransaction inputTransaction, - final boolean isFromSuggestionStrip) { + private boolean tryStripSpaceAndReturnWhetherShouldSwapInstead( + final InputTransaction inputTransaction, final boolean isFromSuggestionStrip) { final int codePoint = inputTransaction.mEvent.mCodePoint; if (Constants.CODE_ENTER == codePoint && SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) { @@ -1068,37 +1071,42 @@ public final class InputLogic { * period-space sequence of characters. This typically happens when the user presses space * twice in a row quickly. * This method will check that the double-space-to-period is active in settings, that the - * two spaces have been input close enough together, and that the previous character allows - * for the transformation to take place. If all of these conditions are fulfilled, this - * method applies the transformation and returns true. Otherwise, it does nothing and - * returns false. + * two spaces have been input close enough together, that the typed character is a space + * and that the previous character allows for the transformation to take place. If all of + * these conditions are fulfilled, this method applies the transformation and returns true. + * Otherwise, it does nothing and returns false. * * @param inputTransaction The transaction in progress. * @return true if we applied the double-space-to-period transformation, false otherwise. */ - private boolean maybeDoubleSpacePeriod(final InputTransaction inputTransaction) { - if (!inputTransaction.mSettingsValues.mUseDoubleSpacePeriod) return false; - if (!isDoubleSpacePeriodCountdownActive(inputTransaction)) return false; - // We only do this when we see two spaces and an accepted code point before the cursor. - // The code point may be a surrogate pair but the two spaces may not, so we need 4 chars. - final CharSequence lastThree = mConnection.getTextBeforeCursor(4, 0); - if (null == lastThree) return false; - final int length = lastThree.length(); - if (length < 3) return false; - if (lastThree.charAt(length - 1) != Constants.CODE_SPACE) return false; - if (lastThree.charAt(length - 2) != Constants.CODE_SPACE) return false; - // We know there are spaces in pos -1 and -2, and we have at least three chars. - // If we have only three chars, isSurrogatePairs can't return true as charAt(1) is a space, - // so this is fine. + private boolean tryPerformDoubleSpacePeriod(final InputTransaction inputTransaction) { + // Check the setting, the typed character and the countdown. If any of the conditions is + // not fulfilled, return false. + if (!inputTransaction.mSettingsValues.mUseDoubleSpacePeriod + || Constants.CODE_SPACE != inputTransaction.mEvent.mCodePoint + || !isDoubleSpacePeriodCountdownActive(inputTransaction)) { + return false; + } + // We only do this when we see one space and an accepted code point before the cursor. + // The code point may be a surrogate pair but the space may not, so we need 3 chars. + final CharSequence lastTwo = mConnection.getTextBeforeCursor(3, 0); + if (null == lastTwo) return false; + final int length = lastTwo.length(); + if (length < 2) return false; + if (lastTwo.charAt(length - 1) != Constants.CODE_SPACE) return false; + // We know there is a space in pos -1, and we have at least two chars. If we have only two + // chars, isSurrogatePairs can't return true as charAt(1) is a space, so this is fine. final int firstCodePoint = - Character.isSurrogatePair(lastThree.charAt(0), lastThree.charAt(1)) ? - Character.codePointAt(lastThree, 0) : lastThree.charAt(length - 3); + Character.isSurrogatePair(lastTwo.charAt(0), lastTwo.charAt(1)) ? + Character.codePointAt(lastTwo, length - 3) : lastTwo.charAt(length - 2); if (canBeFollowedByDoubleSpacePeriod(firstCodePoint)) { cancelDoubleSpacePeriodCountdown(); - mConnection.deleteSurroundingText(2, 0); + mConnection.deleteSurroundingText(1, 0); final String textToInsert = inputTransaction.mSettingsValues.mSpacingAndPunctuations .mSentenceSeparatorAndSpace; mConnection.commitText(textToInsert, 1); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); + inputTransaction.setRequiresUpdateSuggestions(); return true; } return false; diff --git a/java/src/com/android/inputmethod/latin/makedict/WordProperty.java b/java/src/com/android/inputmethod/latin/makedict/WordProperty.java index 31cb59756..cd78e2235 100644 --- a/java/src/com/android/inputmethod/latin/makedict/WordProperty.java +++ b/java/src/com/android/inputmethod/latin/makedict/WordProperty.java @@ -70,8 +70,8 @@ public final class WordProperty implements Comparable<WordProperty> { // Construct word property using information from native code. // This represents invalid word when the probability is BinaryDictionary.NOT_A_PROBABILITY. public WordProperty(final int[] codePoints, final boolean isNotAWord, - final boolean isBlacklisted, final boolean hasBigram, - final boolean hasShortcuts, final int[] probabilityInfo, + final boolean isBlacklisted, final boolean hasBigram, final boolean hasShortcuts, + final boolean isBeginningOfSentence, final int[] probabilityInfo, final ArrayList<int[]> bigramTargets, final ArrayList<int[]> bigramProbabilityInfo, final ArrayList<int[]> shortcutTargets, final ArrayList<Integer> shortcutProbabilities) { @@ -79,7 +79,7 @@ public final class WordProperty implements Comparable<WordProperty> { mProbabilityInfo = createProbabilityInfoFromArray(probabilityInfo); mShortcutTargets = new ArrayList<>(); mBigrams = new ArrayList<>(); - mIsBeginningOfSentence = false; + mIsBeginningOfSentence = isBeginningOfSentence; mIsNotAWord = isNotAWord; mIsBlacklistEntry = isBlacklisted; mHasShortcuts = hasShortcuts; diff --git a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java b/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java index a96018fe9..ac55b9333 100644 --- a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java +++ b/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java @@ -43,11 +43,6 @@ public class ContextualDictionary extends ExpandableBinaryDictionary { } @Override - protected boolean enableBeginningOfSentencePrediction() { - return true; - } - - @Override public boolean isValidWord(final String word) { // Strings out of this dictionary should not be considered existing words. return false; diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java index aede003d4..a98b0f156 100644 --- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java @@ -75,7 +75,13 @@ public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBas return; } if (null != prevWord) { - userHistoryDictionary.addNgramEntry(prevWordsInfo, word, frequency, timestamp); + if (prevWordsInfo.mPrevWordsInfo[0].mIsBeginningOfSentence) { + // Beginning-of-Sentence n-gram entry is treated as a n-gram entry of invalid word. + userHistoryDictionary.addNgramEntry(prevWordsInfo, word, + FREQUENCY_FOR_WORDS_NOT_IN_DICTS, timestamp); + } else { + userHistoryDictionary.addNgramEntry(prevWordsInfo, word, frequency, timestamp); + } } } } diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java index 9d824121c..689f878be 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java @@ -126,9 +126,17 @@ public final class SettingsFragment extends InputMethodSettingsFragment final PreferenceScreen inputScreen = (PreferenceScreen) findPreference(Settings.SCREEN_INPUT); + final PreferenceScreen multiLingualScreen = + (PreferenceScreen) findPreference(Settings.SCREEN_MULTI_LINGUAL); + final PreferenceScreen gestureScreen = + (PreferenceScreen) findPreference(Settings.SCREEN_GESTURE); + final PreferenceScreen correctionScreen = + (PreferenceScreen) findPreference(Settings.SCREEN_CORRECTION); final PreferenceScreen advancedScreen = (PreferenceScreen) findPreference(Settings.SCREEN_ADVANCED); - final Preference debugScreen = findPreference(Settings.SCREEN_DEBUG); + final PreferenceScreen debugScreen = + (PreferenceScreen) findPreference(Settings.SCREEN_DEBUG); + if (Settings.isInternal(prefs)) { final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN); debugSettingsIntent.setClassName( @@ -149,8 +157,6 @@ public final class SettingsFragment extends InputMethodSettingsFragment removePreference(Settings.PREF_VIBRATION_DURATION_SETTINGS, advancedScreen); } if (!Settings.ENABLE_SHOW_LANGUAGE_SWITCH_KEY_SETTINGS) { - final PreferenceScreen multiLingualScreen = - (PreferenceScreen) findPreference(Settings.SCREEN_MULTI_LINGUAL); removePreference(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, multiLingualScreen); removePreference( Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, multiLingualScreen); @@ -185,8 +191,6 @@ public final class SettingsFragment extends InputMethodSettingsFragment removePreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON, advancedScreen); } - final PreferenceScreen correctionScreen = - (PreferenceScreen) findPreference(Settings.SCREEN_CORRECTION); final PreferenceScreen dictionaryLink = (PreferenceScreen) findPreference(Settings.PREF_CONFIGURE_DICTIONARIES_KEY); final Intent intent = dictionaryLink.getIntent(); @@ -221,7 +225,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment } if (!Settings.readFromBuildConfigIfGestureInputEnabled(res)) { - removePreference(Settings.SCREEN_GESTURE, getPreferenceScreen()); + getPreferenceScreen().removePreference(gestureScreen); } AdditionalFeaturesSettingUtils.addAdditionalFeaturesPreferences(context, this); @@ -462,13 +466,14 @@ public final class SettingsFragment extends InputMethodSettingsFragment @Override public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { - if (!FeedbackUtils.isFeedbackFormSupported()) { - return; + if (FeedbackUtils.isFeedbackFormSupported()) { + menu.add(NO_MENU_GROUP, MENU_FEEDBACK /* itemId */, MENU_FEEDBACK /* order */, + R.string.send_feedback); + } + final int aboutResId = FeedbackUtils.getAboutKeyboardTitleResId(); + if (aboutResId != 0) { + menu.add(NO_MENU_GROUP, MENU_ABOUT /* itemId */, MENU_ABOUT /* order */, aboutResId); } - menu.add(NO_MENU_GROUP, MENU_FEEDBACK /* itemId */, MENU_FEEDBACK /* order */, - R.string.send_feedback); - menu.add(NO_MENU_GROUP, MENU_ABOUT /* itemId */, MENU_ABOUT /* order */, - FeedbackUtils.getAboutKeyboardTitleResId()); } @Override @@ -479,8 +484,11 @@ public final class SettingsFragment extends InputMethodSettingsFragment return true; } if (itemId == MENU_ABOUT) { - startActivity(FeedbackUtils.getAboutKeyboardIntent(getActivity())); - return true; + final Intent aboutIntent = FeedbackUtils.getAboutKeyboardIntent(getActivity()); + if (aboutIntent != null) { + startActivity(aboutIntent); + return true; + } } return super.onOptionsItemSelected(item); } diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java index 46f5cdee0..ad5aad747 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java @@ -49,6 +49,7 @@ import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.PunctuationSuggestions; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.utils.AutoCorrectionUtils; import com.android.inputmethod.latin.utils.ResourceUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; @@ -250,8 +251,8 @@ final class SuggestionStripLayoutHelper { final int positionInStrip = getPositionInSuggestionStrip(indexInSuggestedWords, suggestedWords); // Use identity for strings, not #equals : it's the typed word if it's the same object - final boolean isTypedWord = - suggestedWords.getWord(indexInSuggestedWords) == suggestedWords.mTypedWord; + final boolean isTypedWord = suggestedWords.getInfo(indexInSuggestedWords).isKindOf( + SuggestedWordInfo.KIND_TYPED); final int color; if (positionInStrip == mCenterPositionInStrip && suggestedWords.mWillAutoCorrect) { diff --git a/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java b/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java index c66007537..34f59e8bc 100644 --- a/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java @@ -31,6 +31,7 @@ public class CombinedFormatUtils { public static final String HISTORICAL_INFO_TAG = "historicalInfo"; public static final String HISTORICAL_INFO_SEPARATOR = ":"; public static final String WORD_TAG = "word"; + public static final String BEGINNING_OF_SENTENCE_TAG = "beginning_of_sentence"; public static final String NOT_A_WORD_TAG = "not_a_word"; public static final String BLACKLISTED_TAG = "blacklisted"; @@ -56,6 +57,9 @@ public class CombinedFormatUtils { builder.append(" " + WORD_TAG + "=" + wordProperty.mWord); builder.append(","); builder.append(formatProbabilityInfo(wordProperty.mProbabilityInfo)); + if (wordProperty.mIsBeginningOfSentence) { + builder.append("," + BEGINNING_OF_SENTENCE_TAG + "=true"); + } if (wordProperty.mIsNotAWord) { builder.append("," + NOT_A_WORD_TAG + "=true"); } diff --git a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java index 0b362c48a..5c109a68c 100644 --- a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java +++ b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java @@ -17,7 +17,9 @@ package com.android.inputmethod.latin.utils; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.define.ProductionFlag; +import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.Locale; @@ -29,6 +31,7 @@ import java.util.TreeSet; */ public final class SuggestionResults extends TreeSet<SuggestedWordInfo> { public final Locale mLocale; + public final ArrayList<SuggestedWordInfo> mRawSuggestions; private final int mCapacity; public SuggestionResults(final Locale locale, final int capacity) { @@ -40,6 +43,11 @@ public final class SuggestionResults extends TreeSet<SuggestedWordInfo> { super(comparator); mLocale = locale; mCapacity = capacity; + if (ProductionFlag.INCLUDE_RAW_SUGGESTIONS) { + mRawSuggestions = new ArrayList<>(); + } else { + mRawSuggestions = null; + } } @Override |