diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin/suggestions')
5 files changed, 491 insertions, 238 deletions
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java index acd47450b..346aea34a 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java @@ -23,34 +23,27 @@ import android.graphics.drawable.Drawable; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.keyboard.KeyboardActionListener; import com.android.inputmethod.keyboard.internal.KeyboardBuilder; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.keyboard.internal.KeyboardParams; +import com.android.inputmethod.latin.Constants; 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.TypefaceUtils; public final class MoreSuggestions extends Keyboard { - public static final int SUGGESTION_CODE_BASE = 1024; - public final SuggestedWords mSuggestedWords; - public static abstract class MoreSuggestionsListener extends KeyboardActionListener.Adapter { - public abstract void onSuggestionSelected(final int index, final SuggestedWordInfo info); - } - MoreSuggestions(final MoreSuggestionsParam params, final SuggestedWords suggestedWords) { super(params); mSuggestedWords = suggestedWords; } private static final class MoreSuggestionsParam extends KeyboardParams { - private final int[] mWidths = new int[SuggestionStripView.MAX_SUGGESTIONS]; - private final int[] mRowNumbers = new int[SuggestionStripView.MAX_SUGGESTIONS]; - private final int[] mColumnOrders = new int[SuggestionStripView.MAX_SUGGESTIONS]; - private final int[] mNumColumnsInRow = new int[SuggestionStripView.MAX_SUGGESTIONS]; + private final int[] mWidths = new int[SuggestedWords.MAX_SUGGESTIONS]; + private final int[] mRowNumbers = new int[SuggestedWords.MAX_SUGGESTIONS]; + private final int[] mColumnOrders = new int[SuggestedWords.MAX_SUGGESTIONS]; + private final int[] mNumColumnsInRow = new int[SuggestedWords.MAX_SUGGESTIONS]; private static final int MAX_COLUMNS_IN_ROW = 3; private int mNumRows; public Drawable mDivider; @@ -66,16 +59,23 @@ public final class MoreSuggestions extends Keyboard { clearKeys(); mDivider = res.getDrawable(R.drawable.more_suggestions_divider); mDividerWidth = mDivider.getIntrinsicWidth(); - final float padding = res.getDimension(R.dimen.more_suggestions_key_horizontal_padding); + final float padding = res.getDimension( + R.dimen.config_more_suggestions_key_horizontal_padding); int row = 0; int index = fromIndex; int rowStartIndex = fromIndex; - final int size = Math.min(suggestedWords.size(), SuggestionStripView.MAX_SUGGESTIONS); + final int size = Math.min(suggestedWords.size(), SuggestedWords.MAX_SUGGESTIONS); while (index < size) { - final String word = suggestedWords.getWord(index); + final String word; + if (isIndexSubjectToAutoCorrection(suggestedWords, index)) { + // INDEX_OF_AUTO_CORRECTION and INDEX_OF_TYPED_WORD got swapped. + word = suggestedWords.getLabel(SuggestedWords.INDEX_OF_TYPED_WORD); + } else { + word = suggestedWords.getLabel(index); + } // TODO: Should take care of text x-scaling. - mWidths[index] = (int)(TypefaceUtils.getLabelWidth(word, paint) + padding); + mWidths[index] = (int)(TypefaceUtils.getStringWidth(word, paint) + padding); final int numColumn = index - rowStartIndex + 1; final int columnWidth = (maxWidth - mDividerWidth * (numColumn - 1)) / numColumn; @@ -171,6 +171,11 @@ public final class MoreSuggestions extends Keyboard { } } + static boolean isIndexSubjectToAutoCorrection(final SuggestedWords suggestedWords, + final int index) { + return suggestedWords.mWillAutoCorrect && index == SuggestedWords.INDEX_OF_AUTO_CORRECTION; + } + public static final class Builder extends KeyboardBuilder<MoreSuggestionsParam> { private final MoreSuggestionsView mPaneView; private SuggestedWords mSuggestedWords; @@ -188,7 +193,6 @@ public final class MoreSuggestions extends Keyboard { final int xmlId = R.xml.kbd_suggestions_pane_template; load(xmlId, parentKeyboard.mId); mParams.mVerticalGap = mParams.mTopPadding = parentKeyboard.mVerticalGap / 2; - mPaneView.updateKeyboardGeometry(mParams.mDefaultRowHeight); final int count = mParams.layout(suggestedWords, fromIndex, maxWidth, minWidth, maxRow, mPaneView.newLabelPaint(null /* key */), mResources); @@ -205,13 +209,17 @@ public final class MoreSuggestions extends Keyboard { final int x = params.getX(index); final int y = params.getY(index); final int width = params.getWidth(index); - final String word = mSuggestedWords.getWord(index); - final String info = mSuggestedWords.getDebugString(index); - final int indexInMoreSuggestions = index + SUGGESTION_CODE_BASE; - final Key key = new Key( - params, word, info, KeyboardIconsSet.ICON_UNDEFINED, indexInMoreSuggestions, - null /* outputText */, x, y, width, params.mDefaultRowHeight, - 0 /* labelFlags */, Key.BACKGROUND_TYPE_NORMAL); + final String word; + final String info; + if (isIndexSubjectToAutoCorrection(mSuggestedWords, index)) { + // INDEX_OF_AUTO_CORRECTION and INDEX_OF_TYPED_WORD got swapped. + word = mSuggestedWords.getLabel(SuggestedWords.INDEX_OF_TYPED_WORD); + info = mSuggestedWords.getDebugString(SuggestedWords.INDEX_OF_TYPED_WORD); + } else { + word = mSuggestedWords.getLabel(index); + info = mSuggestedWords.getDebugString(index); + } + final Key key = new MoreSuggestionKey(word, info, index, params); params.markAsEdgeKey(key, index); params.onAddKey(key); final int columnNumber = params.getColumnNumber(index); @@ -226,6 +234,19 @@ public final class MoreSuggestions extends Keyboard { } } + static final class MoreSuggestionKey extends Key { + public final int mSuggestedWordIndex; + + public MoreSuggestionKey(final String word, final String info, final int index, + final MoreSuggestionsParam params) { + super(word /* label */, KeyboardIconsSet.ICON_UNDEFINED, Constants.CODE_OUTPUT_TEXT, + word /* outputText */, info, 0 /* labelFlags */, Key.BACKGROUND_TYPE_NORMAL, + params.getX(index), params.getY(index), params.getWidth(index), + params.mDefaultRowHeight, params.mHorizontalGap, params.mVerticalGap); + mSuggestedWordIndex = index; + } + } + private static final class Divider extends Key.Spacer { private final Drawable mIcon; diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java index 0ebe37782..f7b6f919d 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java @@ -20,11 +20,14 @@ import android.content.Context; import android.util.AttributeSet; import android.util.Log; +import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardActionListener; import com.android.inputmethod.keyboard.MoreKeysKeyboardView; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SuggestedWords; -import com.android.inputmethod.latin.suggestions.MoreSuggestions.MoreSuggestionsListener; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.suggestions.MoreSuggestions.MoreSuggestionKey; /** * A view that renders a virtual {@link MoreSuggestions}. It handles rendering of keys and detecting @@ -33,6 +36,10 @@ import com.android.inputmethod.latin.suggestions.MoreSuggestions.MoreSuggestions public final class MoreSuggestionsView extends MoreKeysKeyboardView { private static final String TAG = MoreSuggestionsView.class.getSimpleName(); + public static abstract class MoreSuggestionsListener extends KeyboardActionListener.Adapter { + public abstract void onSuggestionSelected(final SuggestedWordInfo info); + } + public MoreSuggestionsView(final Context context, final AttributeSet attrs) { this(context, attrs, R.attr.moreKeysKeyboardViewStyle); } @@ -42,6 +49,21 @@ public final class MoreSuggestionsView extends MoreKeysKeyboardView { super(context, attrs, defStyle); } + // TODO: Remove redundant override method. + @Override + public void setKeyboard(final Keyboard keyboard) { + super.setKeyboard(keyboard); + // With accessibility mode off, {@link #mAccessibilityDelegate} is set to null at the + // above {@link MoreKeysKeyboardView#setKeyboard(Keyboard)} call. + // With accessibility mode on, {@link #mAccessibilityDelegate} is set to a + // {@link MoreKeysKeyboardAccessibilityDelegate} object at the above + // {@link MoreKeysKeyboardView#setKeyboard(Keyboard)} call. + if (mAccessibilityDelegate != null) { + mAccessibilityDelegate.setOpenAnnounce(R.string.spoken_open_more_suggestions); + mAccessibilityDelegate.setCloseAnnounce(R.string.spoken_close_more_suggestions); + } + } + @Override protected int getDefaultCoordX() { final MoreSuggestions pane = (MoreSuggestions)getKeyboard(); @@ -54,12 +76,17 @@ public final class MoreSuggestionsView extends MoreKeysKeyboardView { public void adjustVerticalCorrectionForModalMode() { // Set vertical correction to zero (Reset more keys keyboard sliding allowance - // {@link R#dimen.more_keys_keyboard_slide_allowance}). + // {@link R#dimen.config_more_keys_keyboard_slide_allowance}). mKeyDetector.setKeyboard(getKeyboard(), -getPaddingLeft(), -getPaddingTop()); } @Override - public void onCodeInput(final int code, final int x, final int y) { + protected void onKeyInput(final Key key, final int x, final int y) { + if (!(key instanceof MoreSuggestionKey)) { + Log.e(TAG, "Expected key is MoreSuggestionKey, but found " + + key.getClass().getName()); + return; + } final Keyboard keyboard = getKeyboard(); if (!(keyboard instanceof MoreSuggestions)) { Log.e(TAG, "Expected keyboard is MoreSuggestions, but found " @@ -67,7 +94,7 @@ public final class MoreSuggestionsView extends MoreKeysKeyboardView { return; } final SuggestedWords suggestedWords = ((MoreSuggestions)keyboard).mSuggestedWords; - final int index = code - MoreSuggestions.SUGGESTION_CODE_BASE; + final int index = ((MoreSuggestionKey)key).mSuggestedWordIndex; if (index < 0 || index >= suggestedWords.size()) { Log.e(TAG, "Selected suggestion has an illegal index: " + index); return; @@ -77,7 +104,6 @@ public final class MoreSuggestionsView extends MoreKeysKeyboardView { + mListener.getClass().getName()); return; } - ((MoreSuggestionsListener)mListener).onSuggestionSelected( - index, suggestedWords.getInfo(index)); + ((MoreSuggestionsListener)mListener).onSuggestionSelected(suggestedWords.getInfo(index)); } } diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java index faa5560e4..ad5aad747 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java @@ -28,6 +28,7 @@ import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.support.v4.view.ViewCompat; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; @@ -38,18 +39,20 @@ import android.text.style.StyleSpan; import android.text.style.UnderlineSpan; import android.util.AttributeSet; import android.view.Gravity; -import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; +import com.android.inputmethod.accessibility.AccessibilityUtils; 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; import com.android.inputmethod.latin.utils.ViewLayoutUtils; import java.util.ArrayList; @@ -64,7 +67,7 @@ final class SuggestionStripLayoutHelper { public final int mPadding; public final int mDividerWidth; public final int mSuggestionsStripHeight; - public final int mSuggestionsCountInStrip; + private final int mSuggestionsCountInStrip; public final int mMoreSuggestionsRowHeight; private int mMaxMoreSuggestionsRow; public final float mMinMoreSuggestionsWidth; @@ -89,21 +92,18 @@ 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(); - private final int mSuggestionStripOption; + private final int mSuggestionStripOptions; // These constants are the flag values of - // {@link R.styleable#SuggestionStripView_suggestionStripOption} attribute. + // {@link R.styleable#SuggestionStripView_suggestionStripOptions} attribute. private static final int AUTO_CORRECT_BOLD = 0x01; private static final int AUTO_CORRECT_UNDERLINE = 0x02; private static final int VALID_TYPED_WORD_BOLD = 0x04; - private final TextView mWordToSaveView; - private final TextView mLeftwardsArrowView; - private final TextView mHintToSaveView; - public SuggestionStripLayoutHelper(final Context context, final AttributeSet attrs, final int defStyle, final ArrayList<TextView> wordViews, final ArrayList<View> dividerViews, final ArrayList<TextView> debugInfoViews) { @@ -119,12 +119,13 @@ final class SuggestionStripLayoutHelper { mDividerWidth = dividerView.getMeasuredWidth(); final Resources res = wordView.getResources(); - mSuggestionsStripHeight = res.getDimensionPixelSize(R.dimen.suggestions_strip_height); + mSuggestionsStripHeight = res.getDimensionPixelSize( + R.dimen.config_suggestions_strip_height); final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SuggestionStripView, defStyle, R.style.SuggestionStripView); - mSuggestionStripOption = a.getInt( - R.styleable.SuggestionStripView_suggestionStripOption, 0); + mSuggestionStripOptions = a.getInt( + R.styleable.SuggestionStripView_suggestionStripOptions, 0); mAlphaObsoleted = ResourceUtils.getFraction(a, R.styleable.SuggestionStripView_alphaObsoleted, 1.0f); mColorValidTypedWord = a.getColor(R.styleable.SuggestionStripView_colorValidTypedWord, 0); @@ -145,20 +146,17 @@ final class SuggestionStripLayoutHelper { a.recycle(); mMoreSuggestionsHint = getMoreSuggestionsHint(res, - res.getDimension(R.dimen.more_suggestions_hint_text_size), mColorAutoCorrect); + res.getDimension(R.dimen.config_more_suggestions_hint_text_size), + mColorAutoCorrect); mCenterPositionInStrip = mSuggestionsCountInStrip / 2; // Assuming there are at least three suggestions. Also, note that the suggestions are // laid out according to script direction, so this is left of the center for LTR scripts // and right of the center for RTL scripts. mTypedWordPositionWhenAutocorrect = mCenterPositionInStrip - 1; mMoreSuggestionsBottomGap = res.getDimensionPixelOffset( - R.dimen.more_suggestions_bottom_gap); - mMoreSuggestionsRowHeight = res.getDimensionPixelSize(R.dimen.more_suggestions_row_height); - - final LayoutInflater inflater = LayoutInflater.from(context); - mWordToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null); - mLeftwardsArrowView = (TextView)inflater.inflate(R.layout.hint_add_to_dictionary, null); - mHintToSaveView = (TextView)inflater.inflate(R.layout.hint_add_to_dictionary, null); + R.dimen.config_more_suggestions_bottom_gap); + mMoreSuggestionsRowHeight = res.getDimensionPixelSize( + R.dimen.config_more_suggestions_row_height); } public int getMaxMoreSuggestionsRow() { @@ -203,23 +201,25 @@ final class SuggestionStripLayoutHelper { if (indexInSuggestedWords >= suggestedWords.size()) { return null; } - final String word = suggestedWords.getWord(indexInSuggestedWords); - final boolean isAutoCorrect = indexInSuggestedWords == 1 - && suggestedWords.willAutoCorrect(); - final boolean isTypedWordValid = indexInSuggestedWords == 0 - && suggestedWords.mTypedWordValid; - if (!isAutoCorrect && !isTypedWordValid) { + final String word = suggestedWords.getLabel(indexInSuggestedWords); + // TODO: don't use the index to decide whether this is the auto-correction/typed word, as + // this is brittle + final boolean isAutoCorrection = suggestedWords.mWillAutoCorrect + && indexInSuggestedWords == SuggestedWords.INDEX_OF_AUTO_CORRECTION; + final boolean isTypedWordValid = suggestedWords.mTypedWordValid + && indexInSuggestedWords == SuggestedWords.INDEX_OF_TYPED_WORD; + if (!isAutoCorrection && !isTypedWordValid) { return word; } final int len = word.length(); final Spannable spannedWord = new SpannableString(word); - final int option = mSuggestionStripOption; - if ((isAutoCorrect && (option & AUTO_CORRECT_BOLD) != 0) - || (isTypedWordValid && (option & VALID_TYPED_WORD_BOLD) != 0)) { + final int options = mSuggestionStripOptions; + if ((isAutoCorrection && (options & AUTO_CORRECT_BOLD) != 0) + || (isTypedWordValid && (options & VALID_TYPED_WORD_BOLD) != 0)) { spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } - if (isAutoCorrect && (option & AUTO_CORRECT_UNDERLINE) != 0) { + if (isAutoCorrection && (options & AUTO_CORRECT_UNDERLINE) != 0) { spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } return spannedWord; @@ -229,7 +229,7 @@ final class SuggestionStripLayoutHelper { final SuggestedWords suggestedWords) { final int indexToDisplayMostImportantSuggestion; final int indexToDisplaySecondMostImportantSuggestion; - if (suggestedWords.willAutoCorrect()) { + if (suggestedWords.mWillAutoCorrect) { indexToDisplayMostImportantSuggestion = SuggestedWords.INDEX_OF_AUTO_CORRECTION; indexToDisplaySecondMostImportantSuggestion = SuggestedWords.INDEX_OF_TYPED_WORD; } else { @@ -246,35 +246,36 @@ final class SuggestionStripLayoutHelper { return indexInSuggestedWords; } - private int getSuggestionTextColor(final int indexInSuggestedWords, - final SuggestedWords suggestedWords) { + private int getSuggestionTextColor(final SuggestedWords suggestedWords, + final int indexInSuggestedWords) { final int positionInStrip = getPositionInSuggestionStrip(indexInSuggestedWords, suggestedWords); - // TODO: Need to revisit this logic with bigram suggestions - final boolean isSuggested = (indexInSuggestedWords != SuggestedWords.INDEX_OF_TYPED_WORD); + // Use identity for strings, not #equals : it's the typed word if it's the same object + final boolean isTypedWord = suggestedWords.getInfo(indexInSuggestedWords).isKindOf( + SuggestedWordInfo.KIND_TYPED); final int color; - if (positionInStrip == mCenterPositionInStrip && suggestedWords.willAutoCorrect()) { + if (positionInStrip == mCenterPositionInStrip && suggestedWords.mWillAutoCorrect) { color = mColorAutoCorrect; - } else if (positionInStrip == mCenterPositionInStrip && suggestedWords.mTypedWordValid) { + } else if (isTypedWord && suggestedWords.mTypedWordValid) { color = mColorValidTypedWord; - } else if (isSuggested) { - color = mColorSuggested; - } else { + } else if (isTypedWord) { color = mColorTypedWord; + } else { + color = mColorSuggested; } if (LatinImeLogger.sDBG && suggestedWords.size() > 1) { // If we auto-correct, then the autocorrection is in slot 0 and the typed word // is in slot 1. if (positionInStrip == mCenterPositionInStrip && AutoCorrectionUtils.shouldBlockAutoCorrectionBySafetyNet( - suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION), - suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD))) { + suggestedWords.getLabel(SuggestedWords.INDEX_OF_AUTO_CORRECTION), + suggestedWords.getLabel(SuggestedWords.INDEX_OF_TYPED_WORD))) { return 0xFFFF0000; } } - if (suggestedWords.mIsObsoleteSuggestions && isSuggested) { + if (suggestedWords.mIsObsoleteSuggestions && !isTypedWord) { return applyAlpha(color, mAlphaObsoleted); } return color; @@ -292,54 +293,64 @@ final class SuggestionStripLayoutHelper { params.gravity = Gravity.CENTER; } - public void layout(final SuggestedWords suggestedWords, final ViewGroup stripView, - final ViewGroup placerView) { - if (suggestedWords.mIsPunctuationSuggestions) { - layoutPunctuationSuggestions(suggestedWords, stripView); - return; + /** + * Layout suggestions to the suggestions strip. And returns the number of suggestions displayed + * in the suggestions strip. + * + * @param suggestedWords suggestions to be shown in the suggestions strip. + * @param stripView the suggestions strip view. + * @param placerView the view where the debug info will be placed. + * @return the number of suggestions displayed in the suggestions strip + */ + public int layoutAndReturnSuggestionCountInStrip(final SuggestedWords suggestedWords, + final ViewGroup stripView, final ViewGroup placerView) { + if (suggestedWords.isPunctuationSuggestions()) { + return layoutPunctuationSuggestionsAndReturnSuggestionCountInStrip( + (PunctuationSuggestions)suggestedWords, stripView); } - final int countInStrip = mSuggestionsCountInStrip; - setupWordViewsTextAndColor(suggestedWords, countInStrip); + setupWordViewsTextAndColor(suggestedWords, mSuggestionsCountInStrip); final TextView centerWordView = mWordViews.get(mCenterPositionInStrip); - final int availableStripWidth = placerView.getWidth() - - placerView.getPaddingRight() - placerView.getPaddingLeft(); - final int centerWidth = getSuggestionWidth(mCenterPositionInStrip, availableStripWidth); - if (getTextScaleX(centerWordView.getText(), centerWidth, centerWordView.getPaint()) - < MIN_TEXT_XSCALE) { + final int stripWidth = stripView.getWidth(); + final int centerWidth = getSuggestionWidth(mCenterPositionInStrip, stripWidth); + final int countInStrip; + if (suggestedWords.size() == 1 || getTextScaleX(centerWordView.getText(), centerWidth, + centerWordView.getPaint()) < MIN_TEXT_XSCALE) { // Layout only the most relevant suggested word at the center of the suggestion strip // by consolidating all slots in the strip. - mMoreSuggestionsAvailable = (suggestedWords.size() > 1); - layoutWord(mCenterPositionInStrip, availableStripWidth - mPadding); + countInStrip = 1; + mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip); + layoutWord(mCenterPositionInStrip, stripWidth - mPadding); stripView.addView(centerWordView); setLayoutWeight(centerWordView, 1.0f, ViewGroup.LayoutParams.MATCH_PARENT); if (SuggestionStripView.DBG) { - layoutDebugInfo(mCenterPositionInStrip, placerView, availableStripWidth); + layoutDebugInfo(mCenterPositionInStrip, placerView, stripWidth); } - return; - } - - mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip); - int x = 0; - for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) { - if (positionInStrip != 0) { - final View divider = mDividerViews.get(positionInStrip); - // Add divider if this isn't the left most suggestion in suggestions strip. - addDivider(stripView, divider); - x += divider.getMeasuredWidth(); - } - - final int width = getSuggestionWidth(positionInStrip, availableStripWidth); - final TextView wordView = layoutWord(positionInStrip, width); - stripView.addView(wordView); - setLayoutWeight(wordView, getSuggestionWeight(positionInStrip), - ViewGroup.LayoutParams.MATCH_PARENT); - x += wordView.getMeasuredWidth(); - - if (SuggestionStripView.DBG) { - layoutDebugInfo(positionInStrip, placerView, x); + } else { + countInStrip = mSuggestionsCountInStrip; + mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip); + int x = 0; + for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) { + if (positionInStrip != 0) { + final View divider = mDividerViews.get(positionInStrip); + // Add divider if this isn't the left most suggestion in suggestions strip. + addDivider(stripView, divider); + x += divider.getMeasuredWidth(); + } + + final int width = getSuggestionWidth(positionInStrip, stripWidth); + final TextView wordView = layoutWord(positionInStrip, width); + stripView.addView(wordView); + setLayoutWeight(wordView, getSuggestionWeight(positionInStrip), + ViewGroup.LayoutParams.MATCH_PARENT); + x += wordView.getMeasuredWidth(); + + if (SuggestionStripView.DBG) { + layoutDebugInfo(positionInStrip, placerView, x); + } } } + return countInStrip; } /** @@ -370,13 +381,19 @@ final class SuggestionStripLayoutHelper { } else { wordView.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); } - - // Disable this suggestion if the suggestion is null or empty. - wordView.setEnabled(!TextUtils.isEmpty(word)); + // {@link StyleSpan} in a content description may cause an issue of TTS/TalkBack. + // Use a simple {@link String} to avoid the issue. + wordView.setContentDescription(TextUtils.isEmpty(word) ? null : word.toString()); final CharSequence text = getEllipsizedText(word, width, wordView.getPaint()); final float scaleX = getTextScaleX(word, width, wordView.getPaint()); wordView.setText(text); // TextView.setText() resets text scale x to 1.0. wordView.setTextScaleX(Math.max(scaleX, MIN_TEXT_XSCALE)); + // A <code>wordView</code> should be disabled when <code>word</code> is empty in order to + // make it unclickable. + // With accessibility touch exploration on, <code>wordView</code> should be enabled even + // when it is empty to avoid announcing as "disabled". + wordView.setEnabled(!TextUtils.isEmpty(word) + || AccessibilityUtils.getInstance().isTouchExplorationEnabled()); return wordView; } @@ -415,7 +432,9 @@ final class SuggestionStripLayoutHelper { final int countInStrip) { // Clear all suggestions first for (int positionInStrip = 0; positionInStrip < countInStrip; ++positionInStrip) { - mWordViews.get(positionInStrip).setText(null); + final TextView wordView = mWordViews.get(positionInStrip); + wordView.setText(null); + wordView.setTag(null); // Make this inactive for touches in {@link #layoutWord(int,int)}. if (SuggestionStripView.DBG) { mDebugInfoViews.get(positionInStrip).setText(null); @@ -431,7 +450,7 @@ final class SuggestionStripLayoutHelper { // {@link SuggestionStripView#onClick(View)}. wordView.setTag(indexInSuggestedWords); wordView.setText(getStyledSuggestedWord(suggestedWords, indexInSuggestedWords)); - wordView.setTextColor(getSuggestionTextColor(positionInStrip, suggestedWords)); + wordView.setTextColor(getSuggestionTextColor(suggestedWords, indexInSuggestedWords)); if (SuggestionStripView.DBG) { mDebugInfoViews.get(positionInStrip).setText( suggestedWords.getDebugString(indexInSuggestedWords)); @@ -439,9 +458,9 @@ final class SuggestionStripLayoutHelper { } } - private void layoutPunctuationSuggestions(final SuggestedWords suggestedWords, - final ViewGroup stripView) { - final int countInStrip = Math.min(suggestedWords.size(), PUNCTUATIONS_IN_STRIP); + private int layoutPunctuationSuggestionsAndReturnSuggestionCountInStrip( + final PunctuationSuggestions punctuationSuggestions, final ViewGroup stripView) { + final int countInStrip = Math.min(punctuationSuggestions.size(), PUNCTUATIONS_IN_STRIP); for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) { if (positionInStrip != 0) { // Add divider if this isn't the left most suggestion in suggestions strip. @@ -449,71 +468,69 @@ final class SuggestionStripLayoutHelper { } final TextView wordView = mWordViews.get(positionInStrip); - wordView.setEnabled(true); - wordView.setTextColor(mColorAutoCorrect); + final String punctuation = punctuationSuggestions.getLabel(positionInStrip); // {@link TextView#getTag()} is used to get the index in suggestedWords at // {@link SuggestionStripView#onClick(View)}. wordView.setTag(positionInStrip); - wordView.setText(suggestedWords.getWord(positionInStrip)); + wordView.setText(punctuation); + wordView.setContentDescription(punctuation); wordView.setTextScaleX(1.0f); wordView.setCompoundDrawables(null, null, null, null); + wordView.setTextColor(mColorAutoCorrect); stripView.addView(wordView); setLayoutWeight(wordView, 1.0f, mSuggestionsStripHeight); } - mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip); + mMoreSuggestionsAvailable = (punctuationSuggestions.size() > countInStrip); + return countInStrip; } - public void layoutAddToDictionaryHint(final String word, final ViewGroup stripView, - final int stripWidth, final CharSequence hintText, final OnClickListener listener) { + public void layoutAddToDictionaryHint(final String word, final ViewGroup addToDictionaryStrip) { + final int stripWidth = addToDictionaryStrip.getWidth(); final int width = stripWidth - mDividerWidth - mPadding * 2; - final TextView wordView = mWordToSaveView; + final TextView wordView = (TextView)addToDictionaryStrip.findViewById(R.id.word_to_save); wordView.setTextColor(mColorTypedWord); final int wordWidth = (int)(width * mCenterSuggestionWeight); - final CharSequence text = getEllipsizedText(word, wordWidth, wordView.getPaint()); + final CharSequence wordToSave = getEllipsizedText(word, wordWidth, wordView.getPaint()); final float wordScaleX = wordView.getTextScaleX(); - // {@link TextView#setTag()} is used to hold the word to be added to dictionary. The word - // will be extracted at {@link #getAddToDictionaryWord()}. - wordView.setTag(word); - wordView.setText(text); + wordView.setText(wordToSave); wordView.setTextScaleX(wordScaleX); - stripView.addView(wordView); setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); - stripView.addView(mDividerViews.get(0)); - - final TextView leftArrowView = mLeftwardsArrowView; - leftArrowView.setTextColor(mColorAutoCorrect); - leftArrowView.setText(LEFTWARDS_ARROW); - stripView.addView(leftArrowView); - - final TextView hintView = mHintToSaveView; - hintView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); + final TextView hintView = (TextView)addToDictionaryStrip.findViewById( + R.id.hint_add_to_dictionary); hintView.setTextColor(mColorAutoCorrect); - final int hintWidth = width - wordWidth - leftArrowView.getWidth(); - final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint()); - hintView.setText(hintText); + final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip) + == ViewCompat.LAYOUT_DIRECTION_RTL); + final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW; + final Resources res = addToDictionaryStrip.getResources(); + final boolean isRtlSystem = SubtypeLocaleUtils.isRtlLanguage(res.getConfiguration().locale); + final CharSequence hintText = res.getText(R.string.hint_add_to_dictionary); + final String hintWithArrow = (isRtlLanguage == isRtlSystem) + ? (arrow + hintText) : (hintText + arrow); + final int hintWidth = width - wordWidth; + hintView.setTextScaleX(1.0f); // Reset textScaleX. + final float hintScaleX = getTextScaleX(hintWithArrow, hintWidth, hintView.getPaint()); + hintView.setText(hintWithArrow); hintView.setTextScaleX(hintScaleX); - stripView.addView(hintView); setLayoutWeight( hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); - - wordView.setOnClickListener(listener); - leftArrowView.setOnClickListener(listener); - hintView.setOnClickListener(listener); - } - - public String getAddToDictionaryWord() { - // String tag is set at - // {@link #layoutAddToDictionaryHint(String,ViewGroup,int,CharSequence,OnClickListener}. - return (String)mWordToSaveView.getTag(); } - public boolean isAddToDictionaryShowing(final View v) { - return v == mWordToSaveView || v == mHintToSaveView || v == mLeftwardsArrowView; + public void layoutImportantNotice(final View importantNoticeStrip, + final String importantNoticeTitle) { + final TextView titleView = (TextView)importantNoticeStrip.findViewById( + R.id.important_notice_title); + final int width = titleView.getWidth() - titleView.getPaddingLeft() + - titleView.getPaddingRight(); + titleView.setTextColor(mColorAutoCorrect); + titleView.setText(importantNoticeTitle); + titleView.setTextScaleX(1.0f); // Reset textScaleX. + final float titleScaleX = getTextScaleX(importantNoticeTitle, width, titleView.getPaint()); + titleView.setTextScaleX(titleScaleX); } - private static void setLayoutWeight(final View v, final float weight, final int height) { + static void setLayoutWeight(final View v, final float weight, final int height) { final ViewGroup.LayoutParams lp = v.getLayoutParams(); if (lp instanceof LinearLayout.LayoutParams) { final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp; @@ -527,7 +544,7 @@ final class SuggestionStripLayoutHelper { final TextPaint paint) { paint.setTextScaleX(1.0f); final int width = getTextWidth(text, paint); - if (width <= maxWidth) { + if (width <= maxWidth || maxWidth <= 0) { return 1.0f; } return maxWidth / (float)width; diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index 75f17c559..8654e12a9 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -18,7 +18,13 @@ package com.android.inputmethod.latin.suggestions; import android.content.Context; import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.support.v4.view.ViewCompat; +import android.text.TextUtils; import android.util.AttributeSet; +import android.util.TypedValue; import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -26,11 +32,13 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; +import android.view.ViewParent; +import android.view.accessibility.AccessibilityEvent; +import android.widget.ImageButton; import android.widget.RelativeLayout; import android.widget.TextView; import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.MainKeyboardView; import com.android.inputmethod.keyboard.MoreKeysPanel; import com.android.inputmethod.latin.AudioAndHapticFeedbackManager; @@ -39,10 +47,10 @@ import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; -import com.android.inputmethod.latin.define.ProductionFlag; -import com.android.inputmethod.latin.suggestions.MoreSuggestions.MoreSuggestionsListener; -import com.android.inputmethod.latin.utils.CollectionUtils; -import com.android.inputmethod.research.ResearchLogger; +import com.android.inputmethod.latin.settings.Settings; +import com.android.inputmethod.latin.settings.SettingsValues; +import com.android.inputmethod.latin.suggestions.MoreSuggestionsView.MoreSuggestionsListener; +import com.android.inputmethod.latin.utils.ImportantNoticeUtils; import java.util.ArrayList; @@ -50,29 +58,82 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick OnLongClickListener { public interface Listener { public void addWordToUserDictionary(String word); - public void pickSuggestionManually(int index, SuggestedWordInfo word); + public void showImportantNoticeContents(); + public void pickSuggestionManually(SuggestedWordInfo word); + public void onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat); } - // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. - public static final int MAX_SUGGESTIONS = 18; - static final boolean DBG = LatinImeLogger.sDBG; + private static final float DEBUG_INFO_TEXT_SIZE_IN_DIP = 6.0f; private final ViewGroup mSuggestionsStrip; + private final ImageButton mVoiceKey; + private final ViewGroup mAddToDictionaryStrip; + private final View mImportantNoticeStrip; MainKeyboardView mMainKeyboardView; private final View mMoreSuggestionsContainer; private final MoreSuggestionsView mMoreSuggestionsView; private final MoreSuggestions.Builder mMoreSuggestionsBuilder; - private final ArrayList<TextView> mWordViews = CollectionUtils.newArrayList(); - private final ArrayList<TextView> mDebugInfoViews = CollectionUtils.newArrayList(); - private final ArrayList<View> mDividerViews = CollectionUtils.newArrayList(); + private final ArrayList<TextView> mWordViews = new ArrayList<>(); + private final ArrayList<TextView> mDebugInfoViews = new ArrayList<>(); + private final ArrayList<View> mDividerViews = new ArrayList<>(); Listener mListener; private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; + private int mSuggestionsCountInStrip; private final SuggestionStripLayoutHelper mLayoutHelper; + private final StripVisibilityGroup mStripVisibilityGroup; + + private static class StripVisibilityGroup { + private final View mSuggestionStripView; + private final View mSuggestionsStrip; + private final View mAddToDictionaryStrip; + private final View mImportantNoticeStrip; + + public StripVisibilityGroup(final View suggestionStripView, + final ViewGroup suggestionsStrip, final ViewGroup addToDictionaryStrip, + final View importantNoticeStrip) { + mSuggestionStripView = suggestionStripView; + mSuggestionsStrip = suggestionsStrip; + mAddToDictionaryStrip = addToDictionaryStrip; + mImportantNoticeStrip = importantNoticeStrip; + showSuggestionsStrip(); + } + + public void setLayoutDirection(final boolean isRtlLanguage) { + final int layoutDirection = isRtlLanguage ? ViewCompat.LAYOUT_DIRECTION_RTL + : ViewCompat.LAYOUT_DIRECTION_LTR; + ViewCompat.setLayoutDirection(mSuggestionStripView, layoutDirection); + ViewCompat.setLayoutDirection(mSuggestionsStrip, layoutDirection); + ViewCompat.setLayoutDirection(mAddToDictionaryStrip, layoutDirection); + ViewCompat.setLayoutDirection(mImportantNoticeStrip, layoutDirection); + } + + public void showSuggestionsStrip() { + mSuggestionsStrip.setVisibility(VISIBLE); + mAddToDictionaryStrip.setVisibility(INVISIBLE); + mImportantNoticeStrip.setVisibility(INVISIBLE); + } + + public void showAddToDictionaryStrip() { + mSuggestionsStrip.setVisibility(INVISIBLE); + mAddToDictionaryStrip.setVisibility(VISIBLE); + mImportantNoticeStrip.setVisibility(INVISIBLE); + } + + public void showImportantNoticeStrip() { + mSuggestionsStrip.setVisibility(INVISIBLE); + mAddToDictionaryStrip.setVisibility(INVISIBLE); + mImportantNoticeStrip.setVisibility(VISIBLE); + } + + public boolean isShowingAddToDictionaryStrip() { + return mAddToDictionaryStrip.getVisibility() == VISIBLE; + } + } /** * Construct a {@link SuggestionStripView} for showing suggestions to be picked by the user. @@ -91,15 +152,23 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick inflater.inflate(R.layout.suggestions_strip, this); mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip); - for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) { - final TextView word = (TextView)inflater.inflate(R.layout.suggestion_word, null); + mVoiceKey = (ImageButton)findViewById(R.id.suggestions_strip_voice_key); + mAddToDictionaryStrip = (ViewGroup)findViewById(R.id.add_to_dictionary_strip); + mImportantNoticeStrip = findViewById(R.id.important_notice_strip); + mStripVisibilityGroup = new StripVisibilityGroup(this, mSuggestionsStrip, + mAddToDictionaryStrip, mImportantNoticeStrip); + + for (int pos = 0; pos < SuggestedWords.MAX_SUGGESTIONS; pos++) { + final TextView word = new TextView(context, null, R.attr.suggestionWordStyle); word.setOnClickListener(this); word.setOnLongClickListener(this); mWordViews.add(word); final View divider = inflater.inflate(R.layout.suggestion_divider, null); - divider.setOnClickListener(this); mDividerViews.add(divider); - mDebugInfoViews.add((TextView)inflater.inflate(R.layout.suggestion_info, null)); + final TextView info = new TextView(context, null, R.attr.suggestionWordStyle); + info.setTextColor(Color.WHITE); + info.setTextSize(TypedValue.COMPLEX_UNIT_DIP, DEBUG_INFO_TEXT_SIZE_IN_DIP); + mDebugInfoViews.add(info); } mLayoutHelper = new SuggestionStripLayoutHelper( @@ -112,9 +181,16 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick final Resources res = context.getResources(); mMoreSuggestionsModalTolerance = res.getDimensionPixelOffset( - R.dimen.more_suggestions_modal_tolerance); + R.dimen.config_more_suggestions_modal_tolerance); mMoreSuggestionsSlidingDetector = new GestureDetector( context, mMoreSuggestionsSlidingListener); + + final TypedArray keyboardAttr = context.obtainStyledAttributes(attrs, + R.styleable.Keyboard, defStyle, R.style.SuggestionStripView); + final Drawable iconVoice = keyboardAttr.getDrawable(R.styleable.Keyboard_iconShortcutKey); + keyboardAttr.recycle(); + mVoiceKey.setImageDrawable(iconVoice); + mVoiceKey.setOnClickListener(this); } /** @@ -126,13 +202,20 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick mMainKeyboardView = (MainKeyboardView)inputView.findViewById(R.id.keyboard_view); } - public void setSuggestions(final SuggestedWords suggestedWords) { + public void updateVisibility(final boolean shouldBeVisible, final boolean isFullscreenMode) { + final int visibility = shouldBeVisible ? VISIBLE : (isFullscreenMode ? GONE : INVISIBLE); + setVisibility(visibility); + final SettingsValues currentSettingsValues = Settings.getInstance().getCurrent(); + mVoiceKey.setVisibility(currentSettingsValues.mShowsVoiceInputKey ? VISIBLE : INVISIBLE); + } + + 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) { - ResearchLogger.suggestionStripView_setSuggestions(mSuggestedWords); - } + mSuggestionsCountInStrip = mLayoutHelper.layoutAndReturnSuggestionCountInStrip( + mSuggestedWords, mSuggestionsStrip, this); + mStripVisibilityGroup.showSuggestionsStrip(); } public int setMoreSuggestionsHeight(final int remainingHeight) { @@ -140,14 +223,16 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick } public boolean isShowingAddToDictionaryHint() { - return mSuggestionsStrip.getChildCount() > 0 - && mLayoutHelper.isAddToDictionaryShowing(mSuggestionsStrip.getChildAt(0)); + return mStripVisibilityGroup.isShowingAddToDictionaryStrip(); } - public void showAddToDictionaryHint(final String word, final CharSequence hintText) { - clear(); - mLayoutHelper.layoutAddToDictionaryHint( - word, mSuggestionsStrip, getWidth(), hintText, this); + public void showAddToDictionaryHint(final String word) { + mLayoutHelper.layoutAddToDictionaryHint(word, mAddToDictionaryStrip); + // {@link TextView#setTag()} is used to hold the word to be added to dictionary. The word + // will be extracted at {@link #onClick(View)}. + mAddToDictionaryStrip.setTag(word); + mAddToDictionaryStrip.setOnClickListener(this); + mStripVisibilityGroup.showAddToDictionaryStrip(); } public boolean dismissAddToDictionaryHint() { @@ -158,31 +243,65 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick return false; } + // This method checks if we should show the important notice (checks on permanent storage if + // it has been shown once already or not, and if in the setup wizard). If applicable, it shows + // the notice. In all cases, it returns true if it was shown, false otherwise. + public boolean maybeShowImportantNoticeTitle() { + if (!ImportantNoticeUtils.shouldShowImportantNotice(getContext())) { + return false; + } + if (getWidth() <= 0) { + return false; + } + final String importantNoticeTitle = ImportantNoticeUtils.getNextImportantNoticeTitle( + getContext()); + if (TextUtils.isEmpty(importantNoticeTitle)) { + return false; + } + if (isShowingMoreSuggestionPanel()) { + dismissMoreSuggestionsPanel(); + } + mLayoutHelper.layoutImportantNotice(mImportantNoticeStrip, importantNoticeTitle); + mStripVisibilityGroup.showImportantNoticeStrip(); + mImportantNoticeStrip.setOnClickListener(this); + return true; + } + public void clear() { mSuggestionsStrip.removeAllViews(); - removeAllViews(); - addView(mSuggestionsStrip); - mMoreSuggestionsView.dismissMoreKeysPanel(); + 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) { - mListener.pickSuggestionManually(index, wordInfo); - mMoreSuggestionsView.dismissMoreKeysPanel(); + public void onSuggestionSelected(final SuggestedWordInfo wordInfo) { + mListener.pickSuggestionManually(wordInfo); + dismissMoreSuggestionsPanel(); } @Override public void onCancelInput() { - mMoreSuggestionsView.dismissMoreKeysPanel(); + dismissMoreSuggestionsPanel(); } }; private final MoreKeysPanel.Controller mMoreSuggestionsController = new MoreKeysPanel.Controller() { @Override - public void onDismissMoreKeysPanel(final MoreKeysPanel panel) { - mMainKeyboardView.onDismissMoreKeysPanel(panel); + public void onDismissMoreKeysPanel() { + mMainKeyboardView.onDismissMoreKeysPanel(); } @Override @@ -191,11 +310,19 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick } @Override - public void onCancelMoreKeysPanel(final MoreKeysPanel panel) { - mMoreSuggestionsView.dismissMoreKeysPanel(); + public void onCancelMoreKeysPanel() { + dismissMoreSuggestionsPanel(); } }; + public boolean isShowingMoreSuggestionPanel() { + return mMoreSuggestionsView.isShowingInParent(); + } + + public void dismissMoreSuggestionsPanel() { + mMoreSuggestionsView.dismissMoreKeysPanel(); + } + @Override public boolean onLongClick(final View view) { AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback( @@ -204,7 +331,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick } boolean showMoreSuggestions() { - final Keyboard parentKeyboard = KeyboardSwitcher.getInstance().getKeyboard(); + final Keyboard parentKeyboard = mMainKeyboardView.getKeyboard(); if (parentKeyboard == null) { return false; } @@ -212,11 +339,17 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick if (!layoutHelper.mMoreSuggestionsAvailable) { return false; } + // Dismiss another {@link MoreKeysPanel} that may be being showed, for example + // {@link MoreKeysKeyboardView}. + mMainKeyboardView.onDismissMoreKeysPanel(); + // Dismiss all key previews and sliding key input preview that may be being showed. + mMainKeyboardView.dismissAllKeyPreviews(); + mMainKeyboardView.dismissSlidingKeyInputPreview(); final int stripWidth = getWidth(); final View container = mMoreSuggestionsContainer; final int maxWidth = stripWidth - container.getPaddingLeft() - container.getPaddingRight(); final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder; - builder.layout(mSuggestedWords, layoutHelper.mSuggestionsCountInStrip, maxWidth, + builder.layout(mSuggestedWords, mSuggestionsCountInStrip, maxWidth, (int)(maxWidth * layoutHelper.mMinMoreSuggestionsWidth), layoutHelper.getMaxMoreSuggestionsRow(), parentKeyboard); mMoreSuggestionsView.setKeyboard(builder.build()); @@ -227,20 +360,16 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick final int pointY = -layoutHelper.mMoreSuggestionsBottomGap; moreKeysPanel.showMoreKeysPanel(this, mMoreSuggestionsController, pointX, pointY, mMoreSuggestionsListener); - mMoreSuggestionsMode = MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING; mOriginX = mLastX; mOriginY = mLastY; - for (int i = 0; i < layoutHelper.mSuggestionsCountInStrip; i++) { + for (int i = 0; i < mSuggestionsCountInStrip; i++) { mWordViews.get(i).setPressed(false); } return true; } - // Working variables for onLongClick and dispatchTouchEvent. - private int mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE; - private static final int MORE_SUGGESTIONS_IN_MODAL_MODE = 0; - private static final int MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING = 1; - private static final int MORE_SUGGESTIONS_IN_SLIDING_MODE = 2; + // Working variables for {@link #onLongClick(View)} and + // {@link onInterceptTouchEvent(MotionEvent)}. private int mLastX; private int mLastY; private int mOriginX; @@ -260,36 +389,45 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick }; @Override - public boolean dispatchTouchEvent(final MotionEvent me) { + public boolean onInterceptTouchEvent(final MotionEvent me) { if (!mMoreSuggestionsView.isShowingInParent()) { mLastX = (int)me.getX(); mLastY = (int)me.getY(); - if (mMoreSuggestionsSlidingDetector.onTouchEvent(me)) { - return true; - } - return super.dispatchTouchEvent(me); + return mMoreSuggestionsSlidingDetector.onTouchEvent(me); } final int action = me.getAction(); final int index = me.getActionIndex(); final int x = (int)me.getX(index); final int y = (int)me.getY(index); - - if (mMoreSuggestionsMode == MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING) { - if (Math.abs(x - mOriginX) >= mMoreSuggestionsModalTolerance - || mOriginY - y >= mMoreSuggestionsModalTolerance) { - // Decided to be in the sliding input mode only when the touch point has been moved - // upward. - mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_SLIDING_MODE; - } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) { - // Decided to be in the modal input mode - mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE; - mMoreSuggestionsView.adjustVerticalCorrectionForModalMode(); - } + if (Math.abs(x - mOriginX) >= mMoreSuggestionsModalTolerance + || mOriginY - y >= mMoreSuggestionsModalTolerance) { + // Decided to be in the sliding input mode only when the touch point has been moved + // upward. Further {@link MotionEvent}s will be delivered to + // {@link #onTouchEvent(MotionEvent)}. return true; } - // MORE_SUGGESTIONS_IN_SLIDING_MODE + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) { + // Decided to be in the modal input mode. + mMoreSuggestionsView.adjustVerticalCorrectionForModalMode(); + } + return false; + } + + @Override + public boolean dispatchPopulateAccessibilityEvent(final AccessibilityEvent event) { + // Don't populate accessibility event with suggested words and voice key. + return true; + } + + @Override + public boolean onTouchEvent(final MotionEvent me) { + // In the sliding input mode. {@link MotionEvent} should be forwarded to + // {@link MoreSuggestionsView}. + final int index = me.getActionIndex(); + final int x = (int)me.getX(index); + final int y = (int)me.getY(index); me.setLocation(mMoreSuggestionsView.translateX(x), mMoreSuggestionsView.translateY(y)); mMoreSuggestionsView.onTouchEvent(me); return true; @@ -297,31 +435,52 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick @Override public void onClick(final View view) { - if (mLayoutHelper.isAddToDictionaryShowing(view)) { - mListener.addWordToUserDictionary(mLayoutHelper.getAddToDictionaryWord()); - clear(); + AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback( + Constants.CODE_UNSPECIFIED, this); + if (view == mImportantNoticeStrip) { + mListener.showImportantNoticeContents(); return; } - - final Object tag = view.getTag(); - // Integer tag is set at - // {@link SuggestionStripLayoutHelper#setupWordViewsTextAndColor(SuggestedWords,int)} and - // {@link SuggestionStripLayoutHelper#layoutPunctuationSuggestions(SuggestedWords,ViewGroup} - if (!(tag instanceof Integer)) { + if (view == mVoiceKey) { + mListener.onCodeInput(Constants.CODE_SHORTCUT, + Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE, + false /* isKeyRepeat */); return; } - final int index = (Integer) tag; - if (index >= mSuggestedWords.size()) { + final Object tag = view.getTag(); + // {@link String} tag is set at {@link #showAddToDictionaryHint(String,CharSequence)}. + if (tag instanceof String) { + final String wordToSave = (String)tag; + mListener.addWordToUserDictionary(wordToSave); + clear(); return; } - final SuggestedWordInfo wordInfo = mSuggestedWords.getInfo(index); - mListener.pickSuggestionManually(index, wordInfo); + // {@link Integer} tag is set at + // {@link SuggestionStripLayoutHelper#setupWordViewsTextAndColor(SuggestedWords,int)} and + // {@link SuggestionStripLayoutHelper#layoutPunctuationSuggestions(SuggestedWords,ViewGroup} + if (tag instanceof Integer) { + final int index = (Integer) tag; + if (index >= mSuggestedWords.size()) { + return; + } + final SuggestedWordInfo wordInfo = mSuggestedWords.getInfo(index); + mListener.pickSuggestionManually(wordInfo); + } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - mMoreSuggestionsView.dismissMoreKeysPanel(); + dismissMoreSuggestionsPanel(); + } + + @Override + protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) { + // Called by the framework when the size is known. Show the important notice if applicable. + // This may be overriden by showing suggestions later, if applicable. + if (oldw <= 0 && w > 0) { + maybeShowImportantNoticeTitle(); + } } } diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java new file mode 100644 index 000000000..52708455e --- /dev/null +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin.suggestions; + +import com.android.inputmethod.latin.SuggestedWords; + +/** + * An object that gives basic control of a suggestion strip and some info on it. + */ +public interface SuggestionStripViewAccessor { + public void showAddToDictionaryHint(final String word); + public boolean isShowingAddToDictionaryHint(); + public void dismissAddToDictionaryHint(); + public void setNeutralSuggestionStrip(); + public void showSuggestionStrip(final SuggestedWords suggestedWords); +} |