diff options
18 files changed, 231 insertions, 160 deletions
diff --git a/java/res/layout/hint_add_to_dictionary.xml b/java/res/layout/hint_add_to_dictionary.xml deleted file mode 100644 index d42908260..000000000 --- a/java/res/layout/hint_add_to_dictionary.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2012, 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. -*/ ---> - -<!-- This is derived from suggestion_word.xml without minWidth attribute and padding --> -<TextView - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:textSize="@dimen/config_suggestion_text_size" - android:gravity="center" - android:paddingLeft="0dp" - android:paddingTop="0dp" - android:paddingRight="0dp" - android:paddingBottom="0dp" - android:focusable="false" - android:clickable="false" - android:singleLine="true" - android:ellipsize="none" - style="?attr/suggestionWordStyle" /> diff --git a/java/res/layout/suggestions_strip.xml b/java/res/layout/suggestions_strip.xml index 2ffac179c..85d60e681 100644 --- a/java/res/layout/suggestions_strip.xml +++ b/java/res/layout/suggestions_strip.xml @@ -37,7 +37,7 @@ <include layout="@layout/suggestion_divider" /> <include - layout="@layout/hint_add_to_dictionary" + layout="@layout/suggestion_word" android:id="@+id/hint_add_to_dictionary" /> </LinearLayout> </merge> diff --git a/java/res/values-ne-rNP/strings.xml b/java/res/values-ne-rNP/strings.xml index c4792dc5a..168806e77 100644 --- a/java/res/values-ne-rNP/strings.xml +++ b/java/res/values-ne-rNP/strings.xml @@ -76,7 +76,7 @@ <string name="gesture_floating_preview_text" msgid="4443240334739381053">"गतिशील फ्लोटिङ पूर्वावलोकन"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"इशारा गर्दा सुझाव दिइएको शब्द हेर्नुहोस्"</string> <string name="gesture_space_aware" msgid="2078291600664682496">"वाक्यांश इशारा"</string> - <string name="gesture_space_aware_summary" msgid="4371385818348528538">"इशारा सत्र दैरान space दिखिल गर्न space key मा ग्लाइडि गर्नुहोस्"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"इशाराको बखतमा स्पेस कुञ्जीमा ग्लाईडिंग द्वारा आगत खाली ठाउँहरू"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : बचत गरियो"</string> <string name="spoken_use_headphones" msgid="896961781287283493">"हेडसेट प्लग इन गर्नुहोस्"</string> <string name="spoken_current_text_is" msgid="2485723011272583845">"वर्तमान पाठ %s हो"</string> diff --git a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java index 5bde668e1..672759aee 100644 --- a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java +++ b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java @@ -73,7 +73,7 @@ import java.util.concurrent.TimeUnit; * Because of the above reasons, this class doesn't extend {@link KeyboardView}. */ public final class EmojiPalettesView extends LinearLayout implements OnTabChangeListener, - ViewPager.OnPageChangeListener, View.OnTouchListener, + ViewPager.OnPageChangeListener, View.OnClickListener, View.OnTouchListener, EmojiPageKeyboardView.OnKeyEventListener { static final String TAG = EmojiPalettesView.class.getSimpleName(); private static final boolean DEBUG_PAGER = false; @@ -482,22 +482,31 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange final LinearLayout actionBar = (LinearLayout)findViewById(R.id.emoji_action_bar); mEmojiLayoutParams.setActionBarProperties(actionBar); + // deleteKey depends only on OnTouchListener. final ImageView deleteKey = (ImageView)findViewById(R.id.emoji_keyboard_delete); deleteKey.setTag(Constants.CODE_DELETE); deleteKey.setOnTouchListener(mDeleteKeyOnTouchListener); + + // alphabetKey, alphabetKey2, and spaceKey depend on {@link View.OnClickListener} as well as + // {@link View.OnTouchListener}. {@link View.OnTouchListener} is used as the trigger of + // key-press, while {@link View.OnClickListener} is used as the trigger of key-release which + // does not occur if the event is canceled by moving off the finger from the view. final ImageView alphabetKey = (ImageView)findViewById(R.id.emoji_keyboard_alphabet); alphabetKey.setBackgroundResource(mEmojiFunctionalKeyBackgroundId); - alphabetKey.setTag(Constants.CODE_SWITCH_ALPHA_SYMBOL); + alphabetKey.setTag(Constants.CODE_ALPHA_FROM_EMOJI); alphabetKey.setOnTouchListener(this); + alphabetKey.setOnClickListener(this); + final ImageView alphabetKey2 = (ImageView)findViewById(R.id.emoji_keyboard_alphabet2); + alphabetKey2.setBackgroundResource(mEmojiFunctionalKeyBackgroundId); + alphabetKey2.setTag(Constants.CODE_ALPHA_FROM_EMOJI); + alphabetKey2.setOnTouchListener(this); + alphabetKey2.setOnClickListener(this); final ImageView spaceKey = (ImageView)findViewById(R.id.emoji_keyboard_space); spaceKey.setBackgroundResource(mKeyBackgroundId); spaceKey.setTag(Constants.CODE_SPACE); spaceKey.setOnTouchListener(this); + spaceKey.setOnClickListener(this); mEmojiLayoutParams.setKeyProperties(spaceKey); - final ImageView alphabetKey2 = (ImageView)findViewById(R.id.emoji_keyboard_alphabet2); - alphabetKey2.setBackgroundResource(mEmojiFunctionalKeyBackgroundId); - alphabetKey2.setTag(Constants.CODE_SWITCH_ALPHA_SYMBOL); - alphabetKey2.setOnTouchListener(this); } @Override @@ -507,7 +516,6 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange updateEmojiCategoryPageIdView(); } - @Override public void onPageSelected(final int position) { final Pair<Integer, Integer> newPos = @@ -545,40 +553,62 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } } - // Called from {@link EmojiPageKeyboardView} through {@link View.OnTouchListener} interface to - // handle touch events from View-based elements such as the space bar. + /** + * Called from {@link EmojiPageKeyboardView} through {@link android.view.View.OnTouchListener} + * interface to handle touch events from View-based elements such as the space bar. + * Note that this method is used only for observing {@link MotionEvent#ACTION_DOWN} to trigger + * {@link KeyboardActionListener#onPressKey}. {@link KeyboardActionListener#onReleaseKey} will + * be covered by {@link #onClick} as long as the event is not canceled. + */ @Override public boolean onTouch(final View v, final MotionEvent event) { + if (event.getActionMasked() != MotionEvent.ACTION_DOWN) { + return false; + } final Object tag = v.getTag(); if (!(tag instanceof Integer)) { return false; } final int code = (Integer) tag; - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - mKeyboardActionListener.onPressKey( - code, 0 /* repeatCount */, true /* isSinglePointer */); - break; - case MotionEvent.ACTION_UP: - mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE); - mKeyboardActionListener.onReleaseKey(code, false /* withSliding */); - break; - } + mKeyboardActionListener.onPressKey( + code, 0 /* repeatCount */, true /* isSinglePointer */); + // It's important to return false here. Otherwise, {@link #onClick} and touch-down visual + // feedback stop working. return false; } - // Called from {@link EmojiPageKeyboardView} through - // {@link EmojiPageKeyboardView.OnKeyEventListener} interface to handle touch events from - // non-View-based elements like typical Emoji characters. + /** + * Called from {@link EmojiPageKeyboardView} through {@link android.view.View.OnClickListener} + * interface to handle non-canceled touch-up events from View-based elements such as the space + * bar. + */ + @Override + public void onClick(View v) { + final Object tag = v.getTag(); + if (!(tag instanceof Integer)) { + return; + } + final int code = (Integer) tag; + mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE); + mKeyboardActionListener.onReleaseKey(code, false /* withSliding */); + } + + /** + * Called from {@link EmojiPageKeyboardView} through + * {@link com.android.inputmethod.keyboard.internal.EmojiPageKeyboardView.OnKeyEventListener} + * interface to handle touch events from non-View-based elements such as Emoji buttons. + */ @Override public void onPressKey(final Key key) { final int code = key.getCode(); mKeyboardActionListener.onPressKey(code, 0 /* repeatCount */, true /* isSinglePointer */); } - // Called from {@link EmojiPageKeyboardView} through - // {@link EmojiPageKeyboardView.OnKeyEventListener} interface to handle touch events from - // non-View-based elements like typical Emoji characters. + /** + * Called from {@link EmojiPageKeyboardView} through + * {@link com.android.inputmethod.keyboard.internal.EmojiPageKeyboardView.OnKeyEventListener} + * interface to handle touch events from non-View-based elements such as Emoji buttons. + */ @Override public void onReleaseKey(final Key key) { mEmojiPalettesAdapter.addRecentKey(key); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java index dc815e57d..78809d53b 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java @@ -54,6 +54,7 @@ public final class KeyboardCodesSet { "key_shift_enter", "key_language_switch", "key_emoji", + "key_alpha_from_emoji", "key_unspecified", "key_left_parenthesis", "key_right_parenthesis", @@ -91,6 +92,7 @@ public final class KeyboardCodesSet { Constants.CODE_SHIFT_ENTER, Constants.CODE_LANGUAGE_SWITCH, Constants.CODE_EMOJI, + Constants.CODE_ALPHA_FROM_EMOJI, Constants.CODE_UNSPECIFIED, CODE_LEFT_PARENTHESIS, CODE_RIGHT_PARENTHESIS, @@ -119,6 +121,7 @@ public final class KeyboardCodesSet { DEFAULT[13], DEFAULT[14], DEFAULT[15], + DEFAULT[16], CODE_RIGHT_PARENTHESIS, CODE_LEFT_PARENTHESIS, CODE_GREATER_THAN_SIGN, diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java index 0c80ce206..ec0b5c95f 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -645,6 +645,8 @@ public final class KeyboardState { updateAlphabetShiftState(autoCaps, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE); } else if (code == Constants.CODE_EMOJI) { setEmojiKeyboard(); + } else if (code == Constants.CODE_ALPHA_FROM_EMOJI) { + setAlphabetKeyboard(); } } diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java index 0477133d7..0b396b1de 100644 --- a/java/src/com/android/inputmethod/latin/Constants.java +++ b/java/src/com/android/inputmethod/latin/Constants.java @@ -217,8 +217,9 @@ public final class Constants { public static final int CODE_EMOJI = -11; public static final int CODE_SHIFT_ENTER = -12; public static final int CODE_SYMBOL_SHIFT = -13; + public static final int CODE_ALPHA_FROM_EMOJI = -14; // Code value representing the code is not specified. - public static final int CODE_UNSPECIFIED = -14; + public static final int CODE_UNSPECIFIED = -15; public static boolean isLetterCode(final int code) { return code >= CODE_SPACE; @@ -241,6 +242,7 @@ public final class Constants { case CODE_UNSPECIFIED: return "unspec"; case CODE_TAB: return "tab"; case CODE_ENTER: return "enter"; + case CODE_ALPHA_FROM_EMOJI: return "alpha"; default: if (code < CODE_SPACE) return String.format("'\\u%02x'", code); if (code < 0x100) return String.format("'%c'", code); diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java index fb9517220..8a8a45f35 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java @@ -44,6 +44,10 @@ import java.util.concurrent.TimeUnit; public class DictionaryFacilitatorForSuggest { public static final String TAG = DictionaryFacilitatorForSuggest.class.getSimpleName(); + // HACK: This threshold is being used when adding a capitalized entry in the User History + // dictionary. + private static final int CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT = 140; + private final Context mContext; public final Locale mLocale; @@ -389,7 +393,26 @@ public class DictionaryFacilitatorForSuggest { if (maxFreq == 0) { return; } - final String secondWord = wasAutoCapitalized ? suggestion.toLowerCase(mLocale) : suggestion; + final String suggestionLowerCase = suggestion.toLowerCase(mLocale); + final String secondWord; + if (wasAutoCapitalized) { + secondWord = suggestionLowerCase; + } else { + // HACK: We'd like to avoid adding the capitalized form of common words to the User + // History dictionary in order to avoid suggesting them until the dictionary + // consolidation is done. + // TODO: Remove this hack when ready. + final int lowerCasefreqInMainDict = mMainDictionary != null ? + mMainDictionary.getFrequency(suggestionLowerCase) : + Dictionary.NOT_A_PROBABILITY; + if (maxFreq < lowerCasefreqInMainDict + && lowerCasefreqInMainDict >= CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT) { + // Use lower cased word as the word can be a distracter of the popular word. + secondWord = suggestionLowerCase; + } else { + secondWord = suggestion; + } + } // We demote unrecognized words (frequency < 0, below) by specifying them as "invalid". // We don't add words with 0-frequency (assuming they would be profanity etc.). final boolean isValid = maxFreq > 0; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index ba7503dae..e8ea5e39d 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -84,6 +84,7 @@ import com.android.inputmethod.latin.utils.IntentUtils; import com.android.inputmethod.latin.utils.JniUtils; import com.android.inputmethod.latin.utils.LatinImeLoggerUtils; import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import com.android.inputmethod.research.ResearchLogger; import java.io.FileDescriptor; @@ -192,9 +193,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (msg.arg2 == ARG2_WITH_TYPED_WORD) { final Pair<SuggestedWords, String> p = (Pair<SuggestedWords, String>) msg.obj; - latinIme.showSuggestionStripWithTypedWord(p.first, p.second); + // [IL]: this is the only place where the second arg is not + // suggestedWords.mTypedWord. + latinIme.showSuggestionStrip(p.first, p.second); } else { - latinIme.showSuggestionStrip((SuggestedWords) msg.obj); + final SuggestedWords suggestedWords = (SuggestedWords) msg.obj; + latinIme.showSuggestionStrip(suggestedWords, suggestedWords.mTypedWord); } } else { latinIme.showGesturePreviewAndSuggestionStrip((SuggestedWords) msg.obj, @@ -1010,9 +1014,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen false /* isObsoleteSuggestions */, false /* isPrediction */); // When in fullscreen mode, show completions generated by the application - setSuggestedWords(suggestedWords); - setAutoCorrectionIndicator(false); - setSuggestionStripShown(true); + setSuggestedWords(suggestedWords, true /* shouldShow */); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions); } @@ -1021,22 +1023,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private void setSuggestionStripShownInternal(final boolean shown, final boolean needsInputViewShown) { // TODO: Modify this if we support suggestions with hard keyboard - if (onEvaluateInputViewShown() && mSuggestionStripView != null) { - final boolean inputViewShown = mKeyboardSwitcher.isShowingMainKeyboardOrEmojiPalettes(); - final boolean shouldShowSuggestions = shown - && (needsInputViewShown ? inputViewShown : true); - if (isFullscreenMode()) { - mSuggestionStripView.setVisibility( - shouldShowSuggestions ? View.VISIBLE : View.GONE); - } else { - mSuggestionStripView.setVisibility( - shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE); - } + if (!onEvaluateInputViewShown() || null == mSuggestionStripView) { + return; + } + final boolean inputViewShown = mKeyboardSwitcher.isShowingMainKeyboardOrEmojiPalettes(); + final boolean shouldShowSuggestions = shown + && (needsInputViewShown ? inputViewShown : true); + if (shouldShowSuggestions) { + mSuggestionStripView.setVisibility(View.VISIBLE); + } else { + mSuggestionStripView.setVisibility(isFullscreenMode() ? View.GONE : View.INVISIBLE); } - } - - private void setSuggestionStripShown(final boolean shown) { - setSuggestionStripShownInternal(shown, /* needsInputViewShown */true); } private int getAdjustedBackingViewHeight() { @@ -1276,7 +1273,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // This method must run on the UI Thread. private void showGesturePreviewAndSuggestionStrip(final SuggestedWords suggestedWords, final boolean dismissGestureFloatingPreviewText) { - showSuggestionStrip(suggestedWords); + showSuggestionStrip(suggestedWords, suggestedWords.mTypedWord); final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); mainKeyboardView.showGestureFloatingPreviewText(suggestedWords); if (dismissGestureFloatingPreviewText) { @@ -1330,26 +1327,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } // TODO[IL]: Define a clear interface for this - public void setSuggestedWords(final SuggestedWords words) { - mInputLogic.mSuggestedWords = words; + public void setSuggestedWords(final SuggestedWords suggestedWords, final boolean shouldShow) { + mInputLogic.setSuggestedWords(suggestedWords); if (mSuggestionStripView != null) { - mSuggestionStripView.setSuggestions(words); - mKeyboardSwitcher.onAutoCorrectionStateChanged(words.mWillAutoCorrect); - } - } - - private void setAutoCorrectionIndicator(final boolean newAutoCorrectionIndicator) { - // Put a blue underline to a word in TextView which will be auto-corrected. - if (mInputLogic.mIsAutoCorrectionIndicatorOn != newAutoCorrectionIndicator - && mInputLogic.mWordComposer.isComposingWord()) { - mInputLogic.mIsAutoCorrectionIndicatorOn = newAutoCorrectionIndicator; - final CharSequence textWithUnderline = - mInputLogic.getTextWithUnderline(mInputLogic.mWordComposer.getTypedWord()); - // TODO: when called from an updateSuggestionStrip() call that results from a posted - // message, this is called outside any batch edit. Potentially, this may result in some - // janky flickering of the screen, although the display speed makes it unlikely in - // the practice. - mInputLogic.mConnection.setComposingText(textWithUnderline, 1); + mSuggestionStripView.setSuggestions(suggestedWords, + SubtypeLocaleUtils.isRtlLanguage(mSubtypeSwitcher.getCurrentSubtype())); + mKeyboardSwitcher.onAutoCorrectionStateChanged(suggestedWords.mWillAutoCorrect); + setSuggestionStripShownInternal(shouldShow, true /* needsInputViewShown */); } } @@ -1424,18 +1408,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - private void showSuggestionStripWithTypedWord(final SuggestedWords sourceSuggestedWords, + // TODO[IL]: Define a clean interface for this + public void showSuggestionStrip(final SuggestedWords sourceSuggestedWords, final String typedWord) { - // TODO: refactor this final SuggestedWords suggestedWords = sourceSuggestedWords.isEmpty() ? SuggestedWords.EMPTY : sourceSuggestedWords; - if (suggestedWords.isEmpty()) { - // No auto-correction is available, clear the cached values. - AccessibilityUtils.getInstance().setAutoCorrection(suggestedWords, typedWord); - setSuggestedWords(suggestedWords); - setAutoCorrectionIndicator(false); - return; - } final String autoCorrection; if (suggestedWords.mWillAutoCorrect) { autoCorrection = suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION); @@ -1444,21 +1421,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // because it may differ from mWordComposer.mTypedWord. autoCorrection = typedWord; } - mInputLogic.mWordComposer.setAutoCorrection(autoCorrection); - setSuggestedWords(suggestedWords); - setAutoCorrectionIndicator(suggestedWords.mWillAutoCorrect); - setSuggestionStripShown(isSuggestionsStripVisible()); - // An auto-correction is available, cache it in accessibility code so - // we can be speak it if the user touches a key that will insert it. + if (SuggestedWords.EMPTY != suggestedWords) { + mInputLogic.mWordComposer.setAutoCorrection(autoCorrection); + } + setSuggestedWords(suggestedWords, isSuggestionsStripVisible()); + // Cache the auto-correction in accessibility code so we can speak it if the user + // touches a key that will insert it. AccessibilityUtils.getInstance().setAutoCorrection(suggestedWords, typedWord); } - // TODO[IL]: Define a clean interface for this - public void showSuggestionStrip(final SuggestedWords suggestedWords) { - showSuggestionStripWithTypedWord(suggestedWords, suggestedWords.isEmpty() ? null - : suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD)); - } - // Called from {@link SuggestionStripView} through the {@link SuggestionStripView#Listener} // interface @Override @@ -1560,12 +1531,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void setNeutralSuggestionStrip() { final SettingsValues currentSettings = mSettings.getCurrent(); if (currentSettings.mBigramPredictionEnabled) { - setSuggestedWords(SuggestedWords.EMPTY); + setSuggestedWords(SuggestedWords.EMPTY, isSuggestionsStripVisible()); } else { - setSuggestedWords(currentSettings.mSpacingAndPunctuations.mSuggestPuncList); + setSuggestedWords(currentSettings.mSpacingAndPunctuations.mSuggestPuncList, + isSuggestionsStripVisible()); } - setAutoCorrectionIndicator(false); - setSuggestionStripShown(isSuggestionsStripVisible()); } public void unsetIsAutoCorrectionIndicatorOnAndCallShowSuggestionStrip( diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index bb34b7ba9..982a97a5e 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -39,6 +39,7 @@ public final class SuggestedWords { public static final SuggestedWords EMPTY = new SuggestedWords( EMPTY_WORD_INFO_LIST, false, false, false, false, false); + public final String mTypedWord; public final boolean mTypedWordValid; // Note: this INCLUDES cases where the word will auto-correct to itself. A good definition // of what this flag means would be "the top suggestion is strong enough to auto-correct", @@ -74,6 +75,7 @@ public final class SuggestedWords { mIsObsoleteSuggestions = isObsoleteSuggestions; mIsPrediction = isPrediction; mSequenceNumber = sequenceNumber; + mTypedWord = suggestedWordInfoList.isEmpty() ? null : getWord(INDEX_OF_TYPED_WORD); } public boolean isEmpty() { diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 43d75330d..ce3ef5374 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -349,6 +349,10 @@ public final class InputLogic { didAutoCorrect = handleNonSpecialCharacter(settingsValues, Constants.CODE_ENTER, x, y, spaceState, keyboardSwitcher, handler); break; + case Constants.CODE_ALPHA_FROM_EMOJI: + // Note: Switching back from Emoji keyboard to the main keyboard is being handled in + // {@link KeyboardState#onCodeInput(int,int)}. + break; default: didAutoCorrect = handleNonSpecialCharacter(settingsValues, code, x, y, spaceState, keyboardSwitcher, handler); @@ -478,6 +482,25 @@ public final class InputLogic { SuggestedWords.EMPTY, true /* dismissGestureFloatingPreviewText */); } + // TODO: on the long term, this method should become private, but it will be difficult. + // Especially, how do we deal with InputMethodService.onDisplayCompletions? + public void setSuggestedWords(final SuggestedWords suggestedWords) { + mSuggestedWords = suggestedWords; + final boolean newAutoCorrectionIndicator = suggestedWords.mWillAutoCorrect; + // Put a blue underline to a word in TextView which will be auto-corrected. + if (mIsAutoCorrectionIndicatorOn != newAutoCorrectionIndicator + && mWordComposer.isComposingWord()) { + mIsAutoCorrectionIndicatorOn = newAutoCorrectionIndicator; + final CharSequence textWithUnderline = + getTextWithUnderline(mWordComposer.getTypedWord()); + // TODO: when called from an updateSuggestionStrip() call that results from a posted + // message, this is called outside any batch edit. Potentially, this may result in some + // janky flickering of the screen, although the display speed makes it unlikely in + // the practice. + mConnection.setComposingText(textWithUnderline, 1); + } + } + /** * Handle inputting a code point to the editor. * @@ -1097,7 +1120,7 @@ public final class InputLogic { final SuggestedWords suggestedWords = holder.get(null, Constants.GET_SUGGESTED_WORDS_TIMEOUT); if (suggestedWords != null) { - mLatinIME.showSuggestionStrip(suggestedWords); + mLatinIME.showSuggestionStrip(suggestedWords, suggestedWords.mTypedWord); } } @@ -1599,8 +1622,10 @@ public final class InputLogic { final int indexOfLastSpace = batchInputText.lastIndexOf(Constants.CODE_SPACE) + 1; if (0 != indexOfLastSpace) { mConnection.commitText(batchInputText.substring(0, indexOfLastSpace), 1); - mLatinIME.showSuggestionStrip( - suggestedWords.getSuggestedWordsForLastWordOfPhraseGesture()); + final SuggestedWords suggestedWordsForLastWordOfPhraseGesture = + suggestedWords.getSuggestedWordsForLastWordOfPhraseGesture(); + mLatinIME.showSuggestionStrip(suggestedWordsForLastWordOfPhraseGesture, + suggestedWordsForLastWordOfPhraseGesture.mTypedWord); } final String lastWord = batchInputText.substring(indexOfLastSpace); mWordComposer.setBatchInputWord(lastWord); diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java index af04de435..3cd9d9555 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java @@ -28,6 +28,8 @@ import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.support.v4.view.GravityCompat; +import android.support.v4.view.ViewCompat; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; @@ -39,7 +41,6 @@ import android.text.style.UnderlineSpan; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; @@ -88,6 +89,7 @@ final class SuggestionStripLayoutHelper { private final Drawable mMoreSuggestionsHint; private static final String MORE_SUGGESTIONS_HINT = "\u2026"; private static final String LEFTWARDS_ARROW = "\u2190"; + private static final String RIGHTWARDS_ARROW = "\u2192"; private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); @@ -471,10 +473,13 @@ final class SuggestionStripLayoutHelper { final TextView hintView = (TextView)addToDictionaryStrip.findViewById( R.id.hint_add_to_dictionary); - hintView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); + hintView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL | GravityCompat.START); hintView.setTextColor(mColorAutoCorrect); + final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip) + == ViewCompat.LAYOUT_DIRECTION_RTL); + final String hintWithArrow = (isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW) + + hintText; final int hintWidth = width - wordWidth; - final String hintWithArrow = LEFTWARDS_ARROW + hintText; final float hintScaleX = getTextScaleX(hintWithArrow, hintWidth, hintView.getPaint()); hintView.setText(hintWithArrow); hintView.setTextScaleX(hintScaleX); diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index 32552ebe7..0ebf5cba5 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -18,6 +18,7 @@ package com.android.inputmethod.latin.suggestions; import android.content.Context; import android.content.res.Resources; +import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.LayoutInflater; @@ -26,6 +27,7 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; +import android.view.ViewParent; import android.widget.RelativeLayout; import android.widget.TextView; @@ -83,6 +85,13 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick showSuggestionsStrip(); } + public void setLayoutDirection(final boolean isRtlLanguage) { + final int layoutDirection = isRtlLanguage ? ViewCompat.LAYOUT_DIRECTION_RTL + : ViewCompat.LAYOUT_DIRECTION_LTR; + ViewCompat.setLayoutDirection(mSuggestionsStrip, layoutDirection); + ViewCompat.setLayoutDirection(mAddToDictionaryStrip, layoutDirection); + } + public void showSuggestionsStrip() { mSuggestionsStrip.setVisibility(VISIBLE); mAddToDictionaryStrip.setVisibility(INVISIBLE); @@ -153,8 +162,9 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick mMainKeyboardView = (MainKeyboardView)inputView.findViewById(R.id.keyboard_view); } - public void setSuggestions(final SuggestedWords suggestedWords) { + public void setSuggestions(final SuggestedWords suggestedWords, final boolean isRtlLanguage) { clear(); + mStripVisibilityGroup.setLayoutDirection(isRtlLanguage); mSuggestedWords = suggestedWords; mLayoutHelper.layout(mSuggestedWords, mSuggestionsStrip, this); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { @@ -189,10 +199,21 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick public void clear() { mSuggestionsStrip.removeAllViews(); + removeAllDebugInfoViews(); mStripVisibilityGroup.showSuggestionsStrip(); dismissMoreSuggestionsPanel(); } + private void removeAllDebugInfoViews() { + // The debug info views may be placed as children views of this {@link SuggestionStripView}. + for (final View debugInfoView : mDebugInfoViews) { + final ViewParent parent = debugInfoView.getParent(); + if (parent instanceof ViewGroup) { + ((ViewGroup)parent).removeView(debugInfoView); + } + } + } + private final MoreSuggestionsListener mMoreSuggestionsListener = new MoreSuggestionsListener() { @Override public void onSuggestionSelected(final int index, final SuggestedWordInfo wordInfo) { diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java index fdbe81ab6..0d0288923 100644 --- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java @@ -28,6 +28,7 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.latin.DictionaryFactory; import com.android.inputmethod.latin.R; +import java.util.Arrays; import java.util.HashMap; import java.util.Locale; @@ -334,4 +335,21 @@ public final class SubtypeLocaleUtils { final Locale locale = getSubtypeLocale(subtype); return StringUtils.capitalizeFirstCodePoint(locale.getLanguage(), locale); } + + // 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 = { + "ar", // Arabic + "fa", // Persian + "iw", // Hebrew + }; + static { + Arrays.sort(SORTED_RTL_LANGUAGES); + } + + public static boolean isRtlLanguage(final InputMethodSubtype subtype) { + final Locale locale = getSubtypeLocale(subtype); + final String language = locale.getLanguage(); + return Arrays.binarySearch(SORTED_RTL_LANGUAGES, language) >= 0; + } } diff --git a/native/jni/src/suggest/core/dictionary/suggestions_output_utils.cpp b/native/jni/src/suggest/core/dictionary/suggestions_output_utils.cpp index d219757da..b8106377c 100644 --- a/native/jni/src/suggest/core/dictionary/suggestions_output_utils.cpp +++ b/native/jni/src/suggest/core/dictionary/suggestions_output_utils.cpp @@ -58,12 +58,6 @@ const int SuggestionsOutputUtils::MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT = 16; ++outputWordIndex; } - // Initial value of the loop index for terminal nodes (words) - int doubleLetterTerminalIndex = -1; - DoubleLetterLevel doubleLetterLevel = NOT_A_DOUBLE_LETTER; - scoringPolicy->searchWordWithDoubleLetter(terminals, terminalSize, - &doubleLetterTerminalIndex, &doubleLetterLevel); - int maxScore = S_INT_MIN; // Force autocorrection for obvious long multi-word suggestions when the top suggestion is // a long multiple words suggestion. @@ -92,8 +86,8 @@ const int SuggestionsOutputUtils::MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT = 16; if (DEBUG_GEO_FULL) { terminalDicNode->dump("OUT:"); } - const float doubleLetterCost = scoringPolicy->getDoubleLetterDemotionDistanceCost( - terminalIndex, doubleLetterTerminalIndex, doubleLetterLevel); + const float doubleLetterCost = + scoringPolicy->getDoubleLetterDemotionDistanceCost(terminalDicNode); const float compoundDistance = terminalDicNode->getCompoundDistance(languageWeight) + doubleLetterCost; const bool isPossiblyOffensiveWord = diff --git a/native/jni/src/suggest/core/policy/scoring.h b/native/jni/src/suggest/core/policy/scoring.h index 5ae3d2146..783383450 100644 --- a/native/jni/src/suggest/core/policy/scoring.h +++ b/native/jni/src/suggest/core/policy/scoring.h @@ -34,14 +34,10 @@ class Scoring { int *const type, int *const freq) const = 0; virtual void safetyNetForMostProbableString(const int terminalSize, const int maxScore, int *const outputCodePoints, int *const frequencies) const = 0; - // TODO: Make more generic - virtual void searchWordWithDoubleLetter(DicNode *terminals, const int terminalSize, - int *doubleLetterTerminalIndex, DoubleLetterLevel *doubleLetterLevel) const = 0; virtual float getAdjustedLanguageWeight(DicTraverseSession *const traverseSession, DicNode *const terminals, const int size) const = 0; - virtual float getDoubleLetterDemotionDistanceCost(const int terminalIndex, - const int doubleLetterTerminalIndex, - const DoubleLetterLevel doubleLetterLevel) const = 0; + virtual float getDoubleLetterDemotionDistanceCost( + const DicNode *const terminalDicNode) const = 0; virtual bool doesAutoCorrectValidWord() const = 0; virtual bool autoCorrectsToMultiWordSuggestionIfTop() const = 0; virtual bool sameAsTyped(const DicTraverseSession *const traverseSession, diff --git a/native/jni/src/suggest/policyimpl/typing/typing_scoring.h b/native/jni/src/suggest/policyimpl/typing/typing_scoring.h index 186e3ba08..c777e7238 100644 --- a/native/jni/src/suggest/policyimpl/typing/typing_scoring.h +++ b/native/jni/src/suggest/policyimpl/typing/typing_scoring.h @@ -43,11 +43,6 @@ class TypingScoring : public Scoring { const int maxScore, int *const outputCodePoints, int *const frequencies) const { } - AK_FORCE_INLINE void searchWordWithDoubleLetter(DicNode *terminals, - const int terminalSize, int *doubleLetterTerminalIndex, - DoubleLetterLevel *doubleLetterLevel) const { - } - AK_FORCE_INLINE float getAdjustedLanguageWeight(DicTraverseSession *const traverseSession, DicNode *const terminals, const int size) const { return 1.0f; @@ -77,9 +72,8 @@ class TypingScoring : public Scoring { return static_cast<int>(score * SUGGEST_INTERFACE_OUTPUT_SCALE); } - AK_FORCE_INLINE float getDoubleLetterDemotionDistanceCost(const int terminalIndex, - const int doubleLetterTerminalIndex, - const DoubleLetterLevel doubleLetterLevel) const { + AK_FORCE_INLINE float getDoubleLetterDemotionDistanceCost( + const DicNode *const terminalDicNode) const { return 0.0f; } diff --git a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java index 939dedba1..25f57eba6 100644 --- a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java @@ -101,7 +101,6 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.NO_LANGUAGE, "azerty", null); ZZ_PC = AdditionalSubtypeUtils.createAdditionalSubtype( SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty", null); - } public void testAllFullDisplayName() { @@ -423,4 +422,27 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { public void testAdditionalSubtypeForSpacebarInFrench() { testsAdditionalSubtypesForSpacebar.runInLocale(mRes, Locale.FRENCH); } + + public void testIsRtlLanguage() { + // Known Right-to-Left language subtypes. + final InputMethodSubtype ARABIC = mRichImm + .findSubtypeByLocaleAndKeyboardLayoutSet("ar", "arabic"); + assertNotNull("Arabic", ARABIC); + final InputMethodSubtype FARSI = mRichImm + .findSubtypeByLocaleAndKeyboardLayoutSet("fa", "farsi"); + assertNotNull("Farsi", FARSI); + final InputMethodSubtype HEBREW = mRichImm + .findSubtypeByLocaleAndKeyboardLayoutSet("iw", "hebrew"); + assertNotNull("Hebrew", HEBREW); + + for (final InputMethodSubtype subtype : mSubtypesList) { + final String subtypeName = SubtypeLocaleUtils + .getSubtypeDisplayNameInSystemLocale(subtype); + if (subtype.equals(ARABIC) || subtype.equals(FARSI) || subtype.equals(HEBREW)) { + assertTrue(subtypeName, SubtypeLocaleUtils.isRtlLanguage(subtype)); + } else { + assertFalse(subtypeName, SubtypeLocaleUtils.isRtlLanguage(subtype)); + } + } + } } |