diff options
Diffstat (limited to 'java/src/com/android/inputmethod')
14 files changed, 214 insertions, 193 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 42105e2c3..335e52fef 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 getBigramProbabilityNative(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, @@ -358,8 +361,8 @@ public final class BinaryDictionary extends Dictionary { prevWordsInfo.mIsBeginningOfSentence, codePoints1); } - 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); @@ -371,14 +374,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); } @@ -399,9 +403,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/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 6199c7dfe..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. * @@ -426,10 +420,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { if (mBinaryDictionary == null) { return null; } - if (composer.size() == 0 && prevWordsInfo.mIsBeginningOfSentence - && !enableBeginningOfSentencePrediction()) { - return null; - } final ArrayList<SuggestedWordInfo> suggestions = mBinaryDictionary.getSuggestions(composer, prevWordsInfo, proximityInfo, blockOffensiveWords, additionalFeaturesOptions, sessionId, diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 7364fc979..9d03e8a43 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -110,6 +110,21 @@ public final class Suggest { 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. @@ -167,20 +182,6 @@ public final class Suggest { suggestionResults.first(), consideredWord, mAutoCorrectionThreshold); } - 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); - } - } - if (!TextUtils.isEmpty(typedWord)) { suggestionsContainer.add(0, new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_TYPED, @@ -188,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()) { @@ -237,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. 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 9462c385d..4d3f5b50b 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/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java index 845ddb377..c17e86892 100644 --- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java +++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java @@ -21,14 +21,13 @@ import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Bundle; import android.os.Process; -import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceFragment; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; +import android.preference.TwoStatePreference; -import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.DictionaryDumpBroadcastReceiver; import com.android.inputmethod.latin.DictionaryFacilitator; import com.android.inputmethod.latin.R; @@ -57,7 +56,7 @@ public final class DebugSettings extends PreferenceFragment public static final String PREF_KEY_LONGPRESS_TIMEOUT = "pref_key_longpress_timeout"; private boolean mServiceNeedsRestart = false; - private CheckBoxPreference mDebugMode; + private TwoStatePreference mDebugMode; @Override public void onCreate(Bundle icicle) { @@ -107,7 +106,7 @@ public final class DebugSettings extends PreferenceFragment res, R.fraction.config_key_preview_dismiss_end_scale)); mServiceNeedsRestart = false; - mDebugMode = (CheckBoxPreference) findPreference(PREF_DEBUG_MODE); + mDebugMode = (TwoStatePreference) findPreference(PREF_DEBUG_MODE); updateDebugMode(); } diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java index 235847799..fb1a210bb 100644 --- a/java/src/com/android/inputmethod/latin/settings/Settings.java +++ b/java/src/com/android/inputmethod/latin/settings/Settings.java @@ -39,8 +39,14 @@ import java.util.concurrent.locks.ReentrantLock; public final class Settings implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = Settings.class.getSimpleName(); + // Settings screens + public static final String SCREEN_INPUT = "screen_input"; + public static final String SCREEN_MULTI_LINGUAL = "screen_multi_lingual"; + public static final String SCREEN_GESTURE = "screen_gesture"; + public static final String SCREEN_CORRECTION = "screen_correction"; + public static final String SCREEN_ADVANCED = "screen_advanced"; + public static final String SCREEN_DEBUG = "screen_debug"; // In the same order as xml/prefs.xml - public static final String PREF_GENERAL_SETTINGS = "general_settings"; public static final String PREF_AUTO_CAP = "auto_cap"; public static final String PREF_VIBRATE_ON = "vibrate_on"; public static final String PREF_SOUND_ON = "sound_on"; @@ -48,13 +54,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang // PREF_VOICE_MODE_OBSOLETE is obsolete. Use PREF_VOICE_INPUT_KEY instead. public static final String PREF_VOICE_MODE_OBSOLETE = "voice_mode"; public static final String PREF_VOICE_INPUT_KEY = "pref_voice_input_key"; - public static final String PREF_CORRECTION_SETTINGS = "correction_settings"; public static final String PREF_EDIT_PERSONAL_DICTIONARY = "edit_personal_dictionary"; public static final String PREF_CONFIGURE_DICTIONARIES_KEY = "configure_dictionaries_key"; public static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold"; public static final String PREF_SHOW_SUGGESTIONS_SETTING = "show_suggestions_setting"; - public static final String PREF_MISC_SETTINGS = "misc_settings"; - public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings"; public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict"; public static final String PREF_KEY_USE_PERSONALIZED_DICTS = "pref_key_use_personalized_dicts"; public static final String PREF_KEY_USE_DOUBLE_SPACE_PERIOD = @@ -75,7 +78,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY = "pref_key_preview_popup_dismiss_delay"; public static final String PREF_BIGRAM_PREDICTIONS = "next_word_prediction"; - public static final String PREF_GESTURE_SETTINGS = "gesture_typing_settings"; public static final String PREF_GESTURE_INPUT = "gesture_input"; public static final String PREF_VIBRATION_DURATION_SETTINGS = "pref_vibration_duration_settings"; @@ -89,7 +91,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_INPUT_LANGUAGE = "input_language"; public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; - public static final String PREF_DEBUG_SETTINGS = "debug_settings"; public static final String PREF_KEY_IS_INTERNAL = "pref_key_is_internal"; public static final String PREF_ENABLE_METRICS_LOGGING = "pref_enable_metrics_logging"; @@ -105,8 +106,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang "pref_last_used_personalization_dict_wiped_time"; private static final String PREF_CORPUS_HANDLES_FOR_PERSONALIZATION = "pref_corpus_handles_for_personalization"; - public static final String PREF_SEND_FEEDBACK = "send_feedback"; - public static final String PREF_ABOUT_KEYBOARD = "about_keyboard"; // Emoji public static final String PREF_EMOJI_RECENT_KEYS = "emoji_recent_keys"; diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java index 5eb0377c7..689f878be 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java @@ -27,13 +27,15 @@ import android.content.res.Resources; import android.media.AudioManager; import android.os.Build; import android.os.Bundle; -import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.Preference; -import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; +import android.preference.TwoStatePreference; import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.dictionarypack.DictionarySettingsActivity; @@ -61,6 +63,10 @@ public final class SettingsFragment extends InputMethodSettingsFragment DBG_USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS || Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2; + private static final int NO_MENU_GROUP = Menu.NONE; // We don't care about menu grouping. + private static final int MENU_FEEDBACK = Menu.FIRST; // The first menu item id and order. + private static final int MENU_ABOUT = Menu.FIRST + 1; // The second menu item id and order. + private void setPreferenceEnabled(final String preferenceKey, final boolean enabled) { final Preference preference = findPreference(preferenceKey); if (preference != null) { @@ -93,6 +99,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment @Override public void onCreate(final Bundle icicle) { super.onCreate(icicle); + setHasOptionsMenu(true); setInputMethodSettingsCategoryTitle(R.string.language_selection_title); setSubtypeEnablerTitle(R.string.select_language); addPreferencesFromResource(R.xml.prefs); @@ -117,66 +124,48 @@ public final class SettingsFragment extends InputMethodSettingsFragment ensureConsistencyOfAutoCorrectionSettings(); - final PreferenceGroup generalSettings = - (PreferenceGroup) findPreference(Settings.PREF_GENERAL_SETTINGS); - final PreferenceGroup miscSettings = - (PreferenceGroup) findPreference(Settings.PREF_MISC_SETTINGS); - - final Preference debugSettings = findPreference(Settings.PREF_DEBUG_SETTINGS); - if (debugSettings != null) { - if (Settings.isInternal(prefs)) { - final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN); - debugSettingsIntent.setClassName( - context.getPackageName(), DebugSettingsActivity.class.getName()); - debugSettings.setIntent(debugSettingsIntent); - } else { - miscSettings.removePreference(debugSettings); - } - } - - final Preference feedbackSettings = findPreference(Settings.PREF_SEND_FEEDBACK); - final Preference aboutSettings = findPreference(Settings.PREF_ABOUT_KEYBOARD); - if (feedbackSettings != null) { - if (FeedbackUtils.isFeedbackFormSupported()) { - feedbackSettings.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(final Preference pref) { - FeedbackUtils.showFeedbackForm(getActivity()); - return true; - } - }); - aboutSettings.setTitle(FeedbackUtils.getAboutKeyboardTitleResId()); - aboutSettings.setIntent(FeedbackUtils.getAboutKeyboardIntent(getActivity())); - } else { - miscSettings.removePreference(feedbackSettings); - miscSettings.removePreference(aboutSettings); - } + 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 PreferenceScreen debugScreen = + (PreferenceScreen) findPreference(Settings.SCREEN_DEBUG); + + if (Settings.isInternal(prefs)) { + final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN); + debugSettingsIntent.setClassName( + context.getPackageName(), DebugSettingsActivity.class.getName()); + debugScreen.setIntent(debugSettingsIntent); + } else { + advancedScreen.removePreference(debugScreen); } final boolean showVoiceKeyOption = res.getBoolean( R.bool.config_enable_show_voice_key_option); if (!showVoiceKeyOption) { - removePreference(Settings.PREF_VOICE_INPUT_KEY, generalSettings); + removePreference(Settings.PREF_VOICE_INPUT_KEY, inputScreen); } - final PreferenceGroup advancedSettings = - (PreferenceGroup) findPreference(Settings.PREF_ADVANCED_SETTINGS); if (!AudioAndHapticFeedbackManager.getInstance().hasVibrator()) { - removePreference(Settings.PREF_VIBRATE_ON, generalSettings); - removePreference(Settings.PREF_VIBRATION_DURATION_SETTINGS, advancedSettings); + removePreference(Settings.PREF_VIBRATE_ON, inputScreen); + removePreference(Settings.PREF_VIBRATION_DURATION_SETTINGS, advancedScreen); } if (!Settings.ENABLE_SHOW_LANGUAGE_SWITCH_KEY_SETTINGS) { + removePreference(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, multiLingualScreen); removePreference( - Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, advancedSettings); - removePreference( - Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, advancedSettings); + Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, multiLingualScreen); } - // TODO: consolidate key preview dismiss delay with the key preview animation parameters. if (!Settings.readFromBuildConfigIfToShowKeyPreviewPopupOption(res)) { - removePreference(Settings.PREF_POPUP_ON, generalSettings); - removePreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, advancedSettings); + removePreference(Settings.PREF_POPUP_ON, inputScreen); + removePreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, advancedScreen); } else { // TODO: Cleanup this setup. final ListPreference keyPreviewPopupDismissDelay = @@ -199,18 +188,16 @@ public final class SettingsFragment extends InputMethodSettingsFragment } if (!res.getBoolean(R.bool.config_setup_wizard_available)) { - removePreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON, advancedSettings); + removePreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON, advancedScreen); } - final PreferenceGroup textCorrectionGroup = - (PreferenceGroup) findPreference(Settings.PREF_CORRECTION_SETTINGS); final PreferenceScreen dictionaryLink = (PreferenceScreen) findPreference(Settings.PREF_CONFIGURE_DICTIONARIES_KEY); final Intent intent = dictionaryLink.getIntent(); intent.setClassName(context.getPackageName(), DictionarySettingsActivity.class.getName()); final int number = context.getPackageManager().queryIntentActivities(intent, 0).size(); if (0 >= number) { - textCorrectionGroup.removePreference(dictionaryLink); + correctionScreen.removePreference(dictionaryLink); } if (ProductionFlag.IS_METRICS_LOGGING_SUPPORTED) { @@ -224,7 +211,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment enableMetricsLogging.setTitle(enableMetricsLoggingTitle); } } else { - removePreference(Settings.PREF_ENABLE_METRICS_LOGGING, textCorrectionGroup); + removePreference(Settings.PREF_ENABLE_METRICS_LOGGING, advancedScreen); } final Preference editPersonalDictionary = @@ -238,7 +225,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment } if (!Settings.readFromBuildConfigIfGestureInputEnabled(res)) { - removePreference(Settings.PREF_GESTURE_SETTINGS, getPreferenceScreen()); + getPreferenceScreen().removePreference(gestureScreen); } AdditionalFeaturesSettingUtils.addAdditionalFeaturesPreferences(context, this); @@ -261,8 +248,8 @@ public final class SettingsFragment extends InputMethodSettingsFragment voiceInputKeyOption.setSummary(isShortcutImeEnabled ? null : res.getText(R.string.voice_input_disabled_summary)); } - final CheckBoxPreference showSetupWizardIcon = - (CheckBoxPreference)findPreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON); + final TwoStatePreference showSetupWizardIcon = + (TwoStatePreference)findPreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON); if (showSetupWizardIcon != null) { showSetupWizardIcon.setChecked(Settings.readShowSetupWizardIcon(prefs, getActivity())); } @@ -476,4 +463,33 @@ public final class SettingsFragment extends InputMethodSettingsFragment userDictionaryPreference.setFragment(UserDictionaryList.class.getName()); } } + + @Override + public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + 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); + } + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + final int itemId = item.getItemId(); + if (itemId == MENU_FEEDBACK) { + FeedbackUtils.showFeedbackForm(getActivity()); + return true; + } + if (itemId == MENU_ABOUT) { + 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/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"); } |