From 60a004f78e73b5208c2a0a79454dabfbc0e1aa33 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" <takaoka@google.com> Date: Fri, 5 Aug 2011 02:54:52 -0700 Subject: [PATCH] Fixed count suggestions strip Bug: 5023981 Change-Id: I434d23bdfb653989866d3822c978cd929a2b553c --- java/res/values-sw600dp-land/dimens.xml | 1 - java/res/values-sw768dp-land/dimens.xml | 1 - java/res/values/attrs.xml | 1 + java/res/values/dimens.xml | 1 + java/res/values/donottranslate.xml | 2 +- java/res/values/styles.xml | 2 + .../inputmethod/latin/CandidateView.java | 250 ++++++++---------- 7 files changed, 116 insertions(+), 142 deletions(-) diff --git a/java/res/values-sw600dp-land/dimens.xml b/java/res/values-sw600dp-land/dimens.xml index 5d4967ffea..c75fcc0d16 100644 --- a/java/res/values-sw600dp-land/dimens.xml +++ b/java/res/values-sw600dp-land/dimens.xml @@ -51,5 +51,4 @@ <fraction name="key_uppercase_letter_ratio">29%</fraction> <dimen name="candidate_strip_padding">40.0mm</dimen> - <integer name="candidate_count_in_strip">5</integer> </resources> diff --git a/java/res/values-sw768dp-land/dimens.xml b/java/res/values-sw768dp-land/dimens.xml index 18837fecc6..0cfdffdddd 100644 --- a/java/res/values-sw768dp-land/dimens.xml +++ b/java/res/values-sw768dp-land/dimens.xml @@ -59,5 +59,4 @@ <dimen name="key_preview_offset_ics">0.05in</dimen> <dimen name="candidate_strip_padding">40.0mm</dimen> - <integer name="candidate_count_in_strip">5</integer> </resources> diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index ab522719f3..172ca2f253 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -116,6 +116,7 @@ <attr name="colorAutoCorrect" format="color" /> <attr name="colorSuggested" format="color" /> <attr name="candidateCountInStrip" format="integer" /> + <attr name="centerCandidatePercentile" format="integer" /> </declare-styleable> <declare-styleable name="Keyboard"> diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml index a66caa7bdb..44e091403b 100644 --- a/java/res/values/dimens.xml +++ b/java/res/values/dimens.xml @@ -86,6 +86,7 @@ <dimen name="candidate_padding">6dip</dimen> <dimen name="candidate_text_size">18dip</dimen> <integer name="candidate_count_in_strip">3</integer> + <integer name="center_candidate_percentile">40</integer> <!-- If the screen height in landscape is larger than the below value, then the keyboard will not go into extract (fullscreen) mode. --> diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml index 9727746e7a..fb28766e7f 100644 --- a/java/res/values/donottranslate.xml +++ b/java/res/values/donottranslate.xml @@ -19,7 +19,7 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- Symbols that are suggested between words --> - <string name="suggested_punctuations">!?,\u0022\u0027:();-/@_</string> + <string name="suggested_punctuations">!?,\u0022:;()\u0027-/@_</string> <!-- Symbols that should be swapped with a magic space --> <string name="magic_space_swapping_symbols">.,;:!?)]}\u0022</string> <!-- Symbols that should strip a magic space --> diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml index 9f91ef57cc..1ebd2cee14 100644 --- a/java/res/values/styles.xml +++ b/java/res/values/styles.xml @@ -90,6 +90,7 @@ <item name="colorAutoCorrect">#FFFCAE00</item> <item name="colorSuggested">#FFFCAE00</item> <item name="candidateCountInStrip">@integer/candidate_count_in_strip</item> + <item name="centerCandidatePercentile">@integer/center_candidate_percentile</item> </style> <!-- Theme "Basic high contrast" --> <style name="KeyboardView.HighContrast" parent="KeyboardView"> @@ -192,6 +193,7 @@ <item name="colorAutoCorrect">#FF3DC8FF</item> <item name="colorSuggested">#FFFFFFFF</item> <item name="candidateCountInStrip">@integer/candidate_count_in_strip</item> + <item name="centerCandidatePercentile">@integer/center_candidate_percentile</item> </style> <style name="PopupMiniKeyboardAnimation"> <item name="android:windowEnterAnimation">@anim/mini_keyboard_fadein</item> diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java index 915e73ccbc..db54ef6cff 100644 --- a/java/src/com/android/inputmethod/latin/CandidateView.java +++ b/java/src/com/android/inputmethod/latin/CandidateView.java @@ -259,12 +259,15 @@ public class CandidateView extends LinearLayout implements OnClickListener { private static class SuggestionsStripParams extends CandidateViewParams { private static final int DEFAULT_CANDIDATE_COUNT_IN_STRIP = 3; + private static final int DEFAULT_CENTER_CANDIDATE_PERCENTILE = 40; private static final int PUNCTUATIONS_IN_STRIP = 6; private final int mColorTypedWord; private final int mColorAutoCorrect; private final int mColorSuggestedCandidate; private final int mCandidateCountInStrip; + private final float mCenterCandidateWeight; + private final int mCenterCandidateIndex; private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); @@ -278,17 +281,6 @@ public class CandidateView extends LinearLayout implements OnClickListener { private final int mAutoCorrectHighlight; private final ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(); - private SuggestedWords mSuggestedWords; - - private int mCountInStrip; - // True if the mCountInStrip suggestions can fit in suggestion strip in equally divided - // width without squeezing the text. - private boolean mCanUseFixedWidthColumns; - private int mMaxWidth; - private int mAvailableWidthForWords; - private int mConstantWidthForPaddings; - private int mVariableWidthForWords; - private float mScaleX; public SuggestionsStripParams(Context context, AttributeSet attrs, int defStyle, List<TextView> words, List<View> dividers, List<TextView> infos, View control) { @@ -302,8 +294,13 @@ public class CandidateView extends LinearLayout implements OnClickListener { mCandidateCountInStrip = a.getInt( R.styleable.CandidateView_candidateCountInStrip, DEFAULT_CANDIDATE_COUNT_IN_STRIP); + mCenterCandidateWeight = a.getInt( + R.styleable.CandidateView_centerCandidatePercentile, + DEFAULT_CENTER_CANDIDATE_PERCENTILE) / 100.0f; a.recycle(); + mCenterCandidateIndex = mCandidateCountInStrip / 2; + mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff); mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord); @@ -328,35 +325,38 @@ public class CandidateView extends LinearLayout implements OnClickListener { return spannedWord; } - private int getWordPosition(int index) { - if (index >= 2) { + private static boolean willAutoCorrect(SuggestedWords suggestions) { + return !suggestions.mTypedWordValid && suggestions.mHasMinimalSuggestion; + } + + private int getWordPosition(int index, SuggestedWords suggestions) { + // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more + // suggestions. + final int centerPos = willAutoCorrect(suggestions) ? 1 : 0; + if (index == mCenterCandidateIndex) { + return centerPos; + } else if (index == centerPos) { + return mCenterCandidateIndex; + } else { return index; } - final boolean willAutoCorrect = !mSuggestedWords.mTypedWordValid - && mSuggestedWords.mHasMinimalSuggestion; - return willAutoCorrect ? 1 - index : index; } - private int getCandidateTextColor(int pos) { - final SuggestedWords suggestions = mSuggestedWords; - final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion - && ((pos == 1 && !suggestions.mTypedWordValid) - || (pos == 0 && suggestions.mTypedWordValid)); + private int getCandidateTextColor(int index, SuggestedWords suggestions, int pos) { // TODO: Need to revisit this logic with bigram suggestions final boolean isSuggestedCandidate = (pos != 0); - final boolean isPunctuationSuggestions = suggestions.isPunctuationSuggestions(); final int color; - if (isPunctuationSuggestions) { - color = mColorTypedWord; - } else if (isAutoCorrect) { + if (index == mCenterCandidateIndex && willAutoCorrect(suggestions)) { color = mColorAutoCorrect; } else if (isSuggestedCandidate) { color = mColorSuggestedCandidate; } else { color = mColorTypedWord; } - final SuggestedWordInfo info = suggestions.getInfo(pos); + + final SuggestedWordInfo info = (pos < suggestions.size()) + ? suggestions.getInfo(pos) : null; if (info != null && info.isPreviousSuggestedWord()) { return applyAlpha(color, 0.5f); } else { @@ -381,136 +381,105 @@ public class CandidateView extends LinearLayout implements OnClickListener { public int layout(SuggestedWords suggestions, ViewGroup stripView, ViewGroup paneView, int stripWidth) { - mSuggestedWords = suggestions; - final int maxCount = suggestions.isPunctuationSuggestions() - ? PUNCTUATIONS_IN_STRIP : mCandidateCountInStrip; - final int size = suggestions.size(); - setupTexts(suggestions, size); - mCountInStrip = Math.min(maxCount, size); - mScaleX = 1.0f; - calculateParameters(size, stripWidth); - - int infoX = 0; - for (int index = 0; index < mCountInStrip; index++) { - final int pos = getWordPosition(index); - final TextView word = mWords.get(pos); - final View divider = mDividers.get(pos); - final TextPaint paint = word.getPaint(); - // TODO: Reorder candidates in strip as appropriate. The center candidate should - // hold the word when space is typed (valid typed word or auto corrected word). - word.setTextColor(getCandidateTextColor(pos)); + if (suggestions.isPunctuationSuggestions()) { + return layoutPunctuationSuggestions(suggestions, stripView); + } + + final int countInStrip = mCandidateCountInStrip; + setupTexts(suggestions, countInStrip); + final int maxWidth = (suggestions.size() <= countInStrip) + ? stripWidth : stripWidth - mControlWidth; + + int x = 0; + for (int index = 0; index < countInStrip; index++) { + final int pos = getWordPosition(index, suggestions); + + if (index != 0) { + final View divider = mDividers.get(pos); + // Add divider if this isn't the left most suggestion in candidate strip. + stripView.addView(divider); + } + final CharSequence styled = mTexts.get(pos); + final TextView word = mWords.get(pos); + // Disable this candidate if the suggestion is null or empty. + word.setEnabled(!TextUtils.isEmpty(styled)); + word.setTextColor(getCandidateTextColor(index, suggestions, pos)); + final int width = getCandidateWidth(index, maxWidth); + final CharSequence text = getEllipsizedText(styled, width, word.getPaint()); + final float scaleX = word.getTextScaleX(); + word.setText(text); // TextView.setText() resets text scale x to 1.0. + word.setTextScaleX(scaleX); + stripView.addView(word); + setLayoutWeight(word, getCandidateWeight(index), mCandidateStripHeight); - final TextView info; if (DBG) { - final CharSequence debugInfo = getDebugInfo(mSuggestedWords, index); + final CharSequence debugInfo = getDebugInfo(suggestions, pos); if (debugInfo != null) { - info = mInfos.get(index); + final TextView info = mInfos.get(pos); info.setText(debugInfo); - } else { - info = null; - } - } else { - info = null; - } - - final CharSequence text; - final float scaleX; - if (index == 0 && mCountInStrip == 1) { - text = getEllipsizedText(styled, mMaxWidth, paint); - scaleX = paint.getTextScaleX(); - } else { - text = styled; - scaleX = mScaleX; - } - word.setText(text); - word.setTextScaleX(scaleX); - if (index != 0) { - // Add divider if this isn't the left most suggestion in candidate strip. - stripView.addView(divider); - } - stripView.addView(word); - if (mCanUseFixedWidthColumns) { - setLayoutWeight(word, 1.0f, mCandidateStripHeight); - } else { - final int width = getTextWidth(text, paint) + mPadding; - setLayoutWeight(word, width, mCandidateStripHeight); - } - if (info != null) { paneView.addView(info); info.measure(WRAP_CONTENT, WRAP_CONTENT); - final int width = info.getMeasuredWidth(); + final int infoWidth = info.getMeasuredWidth(); final int y = info.getMeasuredHeight(); - FrameLayoutCompatUtils.placeViewAt(info, infoX, 0, width, y); - infoX += width * 2; + FrameLayoutCompatUtils.placeViewAt(info, x, 0, infoWidth, y); + x += infoWidth * 2; } + } } - return mCountInStrip; + return countInStrip; } - private void calculateParameters(int size, int maxWidth) { - do { - mMaxWidth = maxWidth; - if (size > mCountInStrip) { - mMaxWidth -= mControlWidth; - } - - tryLayout(); - - if (mCanUseFixedWidthColumns) { - return; - } - if (mVariableWidthForWords <= mAvailableWidthForWords) { - return; - } - - final float scaleX = mAvailableWidthForWords / (float)mVariableWidthForWords; - if (scaleX >= MIN_TEXT_XSCALE) { - mScaleX = scaleX; - return; - } + private int getCandidateWidth(int index, int maxWidth) { + final int paddings = mPadding * mCandidateCountInStrip; + final int dividers = mDividerWidth * (mCandidateCountInStrip - 1); + final int availableWidth = maxWidth - paddings - dividers; + return (int)(availableWidth * getCandidateWeight(index)); + } - mCountInStrip--; - } while (mCountInStrip > 1); - } - - private void tryLayout() { - final int maxCount = mCountInStrip; - final int dividers = mDividerWidth * (maxCount - 1); - mConstantWidthForPaddings = dividers + mPadding * maxCount; - mAvailableWidthForWords = mMaxWidth - mConstantWidthForPaddings; - - mPaint.setTextScaleX(mScaleX); - final int maxFixedWidthForWord = (mMaxWidth - dividers) / maxCount - mPadding; - mCanUseFixedWidthColumns = true; - mVariableWidthForWords = 0; - for (int i = 0; i < maxCount; i++) { - final int width = getTextWidth(mTexts.get(i), mPaint); - if (width > maxFixedWidthForWord) - mCanUseFixedWidthColumns = false; - mVariableWidthForWords += width; + private float getCandidateWeight(int index) { + if (index == mCenterCandidateIndex) { + return mCenterCandidateWeight; + } else { + // TODO: Revisit this for cases of 5 or more suggestions + return (1.0f - mCenterCandidateWeight) / (mCandidateCountInStrip - 1); } } - private void setupTexts(SuggestedWords suggestions, int count) { + private void setupTexts(SuggestedWords suggestions, int countInStrip) { mTexts.clear(); - for (int i = 0; i < count; i++) { - final CharSequence word = suggestions.getWord(i); - final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion - && ((i == 1 && !suggestions.mTypedWordValid) - || (i == 0 && suggestions.mTypedWordValid)); + final int count = Math.min(suggestions.size(), countInStrip); + for (int pos = 0; pos < count; pos++) { + final CharSequence word = suggestions.getWord(pos); + final boolean isAutoCorrect = pos == 1 && willAutoCorrect(suggestions); final CharSequence styled = getStyledCandidateWord(word, isAutoCorrect); mTexts.add(styled); } + for (int pos = count; pos < countInStrip; pos++) { + // Make this inactive for touches in layout(). + mTexts.add(null); + } } - @Override - public String toString() { - return String.format( - "count=%d width=%d avail=%d fixcol=%s scaleX=%4.2f const=%d var=%d", - mCountInStrip, mMaxWidth, mAvailableWidthForWords, mCanUseFixedWidthColumns, - mScaleX, mConstantWidthForPaddings, mVariableWidthForWords); + private int layoutPunctuationSuggestions(SuggestedWords suggestions, ViewGroup stripView) { + final int countInStrip = Math.min(suggestions.size(), PUNCTUATIONS_IN_STRIP); + for (int index = 0; index < countInStrip; index++) { + if (index != 0) { + // Add divider if this isn't the left most suggestion in candidate strip. + stripView.addView(mDividers.get(index)); + } + + final TextView word = mWords.get(index); + word.setEnabled(true); + word.setTextColor(mColorTypedWord); + final CharSequence text = suggestions.getWord(index); + word.setText(text); + word.setTextScaleX(1.0f); + stripView.addView(word); + setLayoutWeight(word, 1.0f, mCandidateStripHeight); + } + return countInStrip; } } @@ -548,13 +517,13 @@ public class CandidateView extends LinearLayout implements OnClickListener { mPreviewPopup.setBackgroundDrawable(null); mCandidatesStrip = (ViewGroup)findViewById(R.id.candidates_strip); - for (int i = 0; i < MAX_SUGGESTIONS; i++) { + for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) { final TextView word = (TextView)inflater.inflate(R.layout.candidate_word, null); - word.setTag(i); + word.setTag(pos); word.setOnClickListener(this); mWords.add(word); final View divider = inflater.inflate(R.layout.candidate_divider, null); - divider.setTag(i); + divider.setTag(pos); divider.setOnClickListener(this); mDividers.add(divider); mInfos.add((TextView)inflater.inflate(R.layout.candidate_info, null)); @@ -649,7 +618,7 @@ public class CandidateView extends LinearLayout implements OnClickListener { } private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) { - if (DBG) { + if (DBG && pos < suggestions.size()) { final SuggestedWordInfo wordInfo = suggestions.getInfo(pos); if (wordInfo != null) { final CharSequence debugInfo = wordInfo.getDebugString(); @@ -695,14 +664,17 @@ public class CandidateView extends LinearLayout implements OnClickListener { TextPaint paint) { paint.setTextScaleX(1.0f); final int width = getTextWidth(text, paint); - final float scaleX = Math.min(maxWidth / (float)width, 1.0f); + if (width <= maxWidth) { + return text; + } + final float scaleX = maxWidth / (float)width; if (scaleX >= MIN_TEXT_XSCALE) { paint.setTextScaleX(scaleX); return text; } // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To get - // squeezed and ellipsezed text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE). + // squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE). final CharSequence ellipsized = TextUtils.ellipsize( text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE); paint.setTextScaleX(MIN_TEXT_XSCALE); -- GitLab