diff options
Diffstat (limited to 'java/src')
11 files changed, 246 insertions, 257 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 518bc8e9e..f8e08b06a 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -79,8 +79,7 @@ public class Keyboard { public static final int CODE_CANCEL = -4; public static final int CODE_DELETE = -5; public static final int CODE_SETTINGS = -6; - public static final int CODE_SETTINGS_LONGPRESS = -7; - public static final int CODE_SHORTCUT = -8; + public static final int CODE_SHORTCUT = -7; // Code value representing the code is not specified. public static final int CODE_UNSPECIFIED = -99; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java index 905f779c0..864091289 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java @@ -70,4 +70,10 @@ public interface KeyboardActionListener { * Called when user released a finger outside any key. */ public void onCancelInput(); + + /** + * Send a non-"code input" custom request to the listener. + * @return true if the request has been consumed, false otherwise. + */ + public boolean onCustomRequest(int requestCode); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index aab58b52c..da3aa50c5 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -35,6 +35,7 @@ import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.RelativeLayout; import android.widget.TextView; import com.android.inputmethod.compat.FrameLayoutCompatUtils; @@ -349,8 +350,11 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { * @param keyboard the keyboard to display in this view */ public void setKeyboard(Keyboard keyboard) { - // Remove any pending messages, except dismissing preview + // Remove any pending dismissing preview mDrawingHandler.cancelAllShowKeyPreviews(); + if (mKeyboard != null) { + PointerTracker.dismissAllKeyPreviews(); + } mKeyboard = keyboard; LatinImeLogger.onSetKeyboard(keyboard); requestLayout(); @@ -788,14 +792,15 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { private void addKeyPreview(TextView keyPreview) { if (mPreviewPlacer == null) { - mPreviewPlacer = FrameLayoutCompatUtils.getPlacer( - (ViewGroup)getRootView().findViewById(android.R.id.content)); + mPreviewPlacer = new RelativeLayout(getContext()); + final ViewGroup windowContentView = + (ViewGroup)getRootView().findViewById(android.R.id.content); + windowContentView.addView(mPreviewPlacer); } - final ViewGroup placer = mPreviewPlacer; - placer.addView(keyPreview, FrameLayoutCompatUtils.newLayoutParam(placer, 0, 0)); + mPreviewPlacer.addView( + keyPreview, FrameLayoutCompatUtils.newLayoutParam(mPreviewPlacer, 0, 0)); } - // TODO: Introduce minimum duration for displaying key previews private void showKey(final int keyIndex, PointerTracker tracker) { final TextView previewText = tracker.getKeyPreviewText(); // If the key preview has no parent view yet, add it to the ViewGroup which can place @@ -914,5 +919,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { public void onDetachedFromWindow() { super.onDetachedFromWindow(); closing(); + if (mPreviewPlacer != null) { + mPreviewPlacer.removeAllViews(); + } } } diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java index abf28c73c..12aadcb5c 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java @@ -281,9 +281,6 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke */ @Override public void setKeyboard(Keyboard keyboard) { - if (getKeyboard() != null) { - PointerTracker.dismissAllKeyPreviews(); - } // Remove any pending messages, except dismissing preview mKeyTimerHandler.cancelKeyTimers(); super.setKeyboard(keyboard); diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 04096778b..dad37e728 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -23,6 +23,7 @@ import android.util.Log; import android.view.MotionEvent; import com.android.inputmethod.deprecated.VoiceProxy; +import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.Utils; @@ -99,9 +100,14 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { } } if (primaryCode == Keyboard.CODE_SETTINGS || primaryCode == Keyboard.CODE_SPACE) { - tracker.onLongPressed(); // Both long pressing settings key and space key invoke IME switcher dialog. - return invokeOnKey(Keyboard.CODE_SETTINGS_LONGPRESS); + if (getKeyboardActionListener().onCustomRequest( + LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) { + tracker.onLongPressed(); + return true; + } else { + return super.onLongPress(key, tracker); + } } else { return super.onLongPress(key, tracker); } diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index dc2d6e4b0..1f8119a0f 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -151,6 +151,8 @@ public class PointerTracker { public void onTextInput(CharSequence text) {} @Override public void onCancelInput() {} + @Override + public boolean onCustomRequest(int requestCode) { return false; } }; public static void init(boolean hasDistinctMultitouch, Context context) { diff --git a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java index dfaaa707c..fb932e3e8 100644 --- a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java @@ -79,6 +79,8 @@ public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel { public void onRelease(int primaryCode, boolean withSliding) { mParentKeyboardView.getKeyboardActionListener().onRelease(primaryCode, withSliding); } + @Override + public boolean onCustomRequest(int requestCode) { return false; } }; public PopupMiniKeyboardView(Context context, AttributeSet attrs) { diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java index 915e73ccb..d779c8565 100644 --- a/java/src/com/android/inputmethod/latin/CandidateView.java +++ b/java/src/com/android/inputmethod/latin/CandidateView.java @@ -38,6 +38,7 @@ import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; +import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.PopupWindow; @@ -50,8 +51,7 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import java.util.ArrayList; import java.util.List; -public class CandidateView extends LinearLayout implements OnClickListener { - +public class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener { public interface Listener { public boolean addWordToDictionary(String word); public void pickSuggestionManually(int index, CharSequence word); @@ -65,9 +65,6 @@ public class CandidateView extends LinearLayout implements OnClickListener { private static final boolean DBG = LatinImeLogger.sDBG; private final ViewGroup mCandidatesStrip; - private final ViewGroup mCandidatesPaneControl; - private final TextView mExpandCandidatesPane; - private final TextView mCloseCandidatesPane; private ViewGroup mCandidatesPane; private ViewGroup mCandidatesPaneContainer; private View mKeyboardView; @@ -89,7 +86,7 @@ public class CandidateView extends LinearLayout implements OnClickListener { private final SuggestionsStripParams mStripParams; private final SuggestionsPaneParams mPaneParams; - private static final float MIN_TEXT_XSCALE = 0.75f; + private static final float MIN_TEXT_XSCALE = 0.70f; private final UiHandler mHandler = new UiHandler(this); @@ -146,7 +143,6 @@ public class CandidateView extends LinearLayout implements OnClickListener { public final int mPadding; public final int mDividerWidth; public final int mDividerHeight; - public final int mControlWidth; public final int mCandidateStripHeight; protected final List<TextView> mWords; @@ -154,7 +150,7 @@ public class CandidateView extends LinearLayout implements OnClickListener { protected final List<TextView> mInfos; protected CandidateViewParams(List<TextView> words, List<View> dividers, - List<TextView> infos, View control) { + List<TextView> infos) { mWords = words; mDividers = dividers; mInfos = infos; @@ -165,7 +161,6 @@ public class CandidateView extends LinearLayout implements OnClickListener { divider.measure(WRAP_CONTENT, MATCH_PARENT); mDividerWidth = divider.getMeasuredWidth(); mDividerHeight = divider.getMeasuredHeight(); - mControlWidth = control.getMeasuredWidth(); final Resources res = word.getResources(); mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height); @@ -174,8 +169,8 @@ public class CandidateView extends LinearLayout implements OnClickListener { private static class SuggestionsPaneParams extends CandidateViewParams { public SuggestionsPaneParams(List<TextView> words, List<View> dividers, - List<TextView> infos, View control) { - super(words, dividers, infos, control); + List<TextView> infos) { + super(words, dividers, infos); } public int layout(SuggestedWords suggestions, ViewGroup paneView, int from, int textColor, @@ -259,12 +254,16 @@ 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 final Drawable mMoreCandidateHint; private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); @@ -278,21 +277,12 @@ 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 boolean mMoreSuggestionsAvailable; public SuggestionsStripParams(Context context, AttributeSet attrs, int defStyle, - List<TextView> words, List<View> dividers, List<TextView> infos, View control) { - super(words, dividers, infos, control); + List<TextView> words, List<View> dividers, List<TextView> infos) { + super(words, dividers, infos); final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle); mAutoCorrectHighlight = a.getInt(R.styleable.CandidateView_autoCorrectHighlight, 0); @@ -302,13 +292,20 @@ 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; + final Resources res = context.getResources(); + mMoreCandidateHint = res.getDrawable(R.drawable.more_suggestions_hint); + mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff); mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord); mPaint = new TextPaint(); - final float textSize = context.getResources().getDimension(R.dimen.candidate_text_size); + final float textSize = res.getDimension(R.dimen.candidate_text_size); mPaint.setTextSize(textSize); } @@ -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,113 @@ 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); + mMoreSuggestionsAvailable = (suggestions.size() > countInStrip); + 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); + if (index == mCenterCandidateIndex && mMoreSuggestionsAvailable) { + // TODO: This "more suggestions hint" should have nicely designed icon. + word.setCompoundDrawablesWithIntrinsicBounds( + null, null, null, mMoreCandidateHint); + } else { + word.setCompoundDrawables(null, null, null, null); + } + + // 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, stripWidth); + 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); + word.setCompoundDrawables(null, null, null, null); + stripView.addView(word); + setLayoutWeight(word, 1.0f, mCandidateStripHeight); + } + mMoreSuggestionsAvailable = false; + return countInStrip; } } @@ -548,13 +525,14 @@ 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); + word.setOnLongClickListener(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)); @@ -564,41 +542,9 @@ public class CandidateView extends LinearLayout implements OnClickListener { mWordToSave = (TextView)findViewById(R.id.word_to_save); mWordToSave.setOnClickListener(this); - final TypedArray keyboardViewAttr = context.obtainStyledAttributes( - attrs, R.styleable.KeyboardView, R.attr.keyboardViewStyle, R.style.KeyboardView); - final Drawable expandBackground = keyboardViewAttr.getDrawable( - R.styleable.KeyboardView_keyBackground); - final Drawable closeBackground = keyboardViewAttr.getDrawable( - R.styleable.KeyboardView_keyBackground); - final int keyTextColor = keyboardViewAttr.getColor( - R.styleable.KeyboardView_keyTextColor, 0xFF000000); - keyboardViewAttr.recycle(); - - mCandidatesPaneControl = (ViewGroup)findViewById(R.id.candidates_pane_control); - mExpandCandidatesPane = (TextView)findViewById(R.id.expand_candidates_pane); - mExpandCandidatesPane.setBackgroundDrawable(expandBackground); - mExpandCandidatesPane.setTextColor(keyTextColor); - mExpandCandidatesPane.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - expandCandidatesPane(); - } - }); - mCloseCandidatesPane = (TextView)findViewById(R.id.close_candidates_pane); - mCloseCandidatesPane.setBackgroundDrawable(closeBackground); - mCloseCandidatesPane.setTextColor(keyTextColor); - mCloseCandidatesPane.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - closeCandidatesPane(); - } - }); - mCandidatesPaneControl.measure(WRAP_CONTENT, WRAP_CONTENT); - - mStripParams = new SuggestionsStripParams(context, attrs, defStyle, - mWords, mDividers, mInfos, mCandidatesPaneControl); - mPaneParams = new SuggestionsPaneParams( - mWords, mDividers, mInfos, mCandidatesPaneControl); + mStripParams = new SuggestionsStripParams(context, attrs, defStyle, mWords, mDividers, + mInfos); + mPaneParams = new SuggestionsPaneParams(mWords, mDividers, mInfos); } /** @@ -619,7 +565,6 @@ public class CandidateView extends LinearLayout implements OnClickListener { if (suggestions == null) return; mSuggestions = suggestions; - mExpandCandidatesPane.setEnabled(false); if (mShowingAutoCorrectionInverted) { mHandler.postUpdateSuggestions(); } else { @@ -638,18 +583,10 @@ public class CandidateView extends LinearLayout implements OnClickListener { mSuggestions, mCandidatesStrip, mCandidatesPane, width); final int countInPane = mPaneParams.layout( mSuggestions, mCandidatesPane, countInStrip, mStripParams.getTextColor(), width); - - if (countInPane <= 0 && !DBG) { - mCandidatesPaneControl.setVisibility(GONE); - } else { - mCandidatesPaneControl.setVisibility(VISIBLE); - mExpandCandidatesPane.setVisibility(VISIBLE); - mExpandCandidatesPane.setEnabled(true); - } } 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 +632,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); @@ -741,20 +681,24 @@ public class CandidateView extends LinearLayout implements OnClickListener { } private void expandCandidatesPane() { - mExpandCandidatesPane.setVisibility(GONE); - mCloseCandidatesPane.setVisibility(VISIBLE); mCandidatesPaneContainer.setMinimumHeight(mKeyboardView.getMeasuredHeight()); mCandidatesPaneContainer.setVisibility(VISIBLE); mKeyboardView.setVisibility(GONE); } private void closeCandidatesPane() { - mExpandCandidatesPane.setVisibility(VISIBLE); - mCloseCandidatesPane.setVisibility(GONE); mCandidatesPaneContainer.setVisibility(GONE); mKeyboardView.setVisibility(VISIBLE); } + private void toggleCandidatesPane() { + if (mCandidatesPaneContainer.getVisibility() == VISIBLE) { + closeCandidatesPane(); + } else { + expandCandidatesPane(); + } + } + public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) { final CharSequence inverted = mStripParams.getInvertedText(autoCorrectedWord); if (inverted == null) @@ -772,7 +716,6 @@ public class CandidateView extends LinearLayout implements OnClickListener { mWordToSave.setText(word); mShowingAddToDictionary = true; mCandidatesStrip.setVisibility(GONE); - mCandidatesPaneControl.setVisibility(GONE); mTouchToSave.setVisibility(VISIBLE); } @@ -831,6 +774,15 @@ public class CandidateView extends LinearLayout implements OnClickListener { } @Override + public boolean onLongClick(View view) { + if (mStripParams.mMoreSuggestionsAvailable) { + toggleCandidatesPane(); + return true; + } + return false; + } + + @Override public void onClick(View view) { if (view == mWordToSave) { addToDictionary(((TextView)view).getText()); @@ -838,6 +790,11 @@ public class CandidateView extends LinearLayout implements OnClickListener { return; } + if (view == mCandidatesPane) { + closeCandidatesPane(); + return; + } + final Object tag = view.getTag(); if (!(tag instanceof Integer)) return; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 6c91c454c..a58815892 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -170,7 +170,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private WordComposer mWordComposer = new WordComposer(); private CharSequence mBestWord; private boolean mHasUncommittedTypedChars; - private boolean mHasDictionary; // Magic space: a space that should disappear on space/apostrophe insertion, move after the // punctuation on punctuation insertion, and become a real space on alpha char insertion. private boolean mJustAddedMagicSpace; // This indicates whether the last char is a magic space. @@ -430,8 +429,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public boolean postStartInputView(EditorInfo attribute) { if (hasMessages(MSG_CONFIRM_ORIENTATION_CHANGE) || hasMessages(MSG_START_INPUT_VIEW)) { removeMessages(MSG_START_INPUT_VIEW); - // Postpone onStartInputView 20ms afterward and see if orientation change has - // finished. + // Postpone onStartInputView by ACCUMULATE_START_INPUT_VIEW_DELAY and see if + // orientation change has finished. sendMessageDelayed(obtainMessage(MSG_START_INPUT_VIEW, attribute), ACCUMULATE_START_INPUT_VIEW_DELAY); return true; @@ -684,8 +683,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Delay updating suggestions because keyboard input view may not be shown at this point. mHandler.postUpdateSuggestions(); - updateCorrectionMode(); - inputView.setKeyPreviewPopupEnabled(mSettingsValues.mKeyPreviewPopupOn, mSettingsValues.mKeyPreviewPopupDismissDelay); inputView.setProximityCorrectionEnabled(true); @@ -1152,25 +1149,33 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } private void onSettingsKeyPressed() { - if (isShowingOptionDialog()) - return; + if (isShowingOptionDialog()) return; if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { showSubtypeSelectorAndSettings(); - } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) { + } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm, + false /* should exclude auxiliary subtypes */)) { showOptionsMenu(); } else { launchSettings(); } } - private void onSettingsKeyLongPressed() { - if (!isShowingOptionDialog()) { - if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) { + // Virtual codes representing custom requests. These are used in onCustomRequest() below. + public static final int CODE_SHOW_INPUT_METHOD_PICKER = 1; + + @Override + public boolean onCustomRequest(int requestCode) { + if (isShowingOptionDialog()) return false; + switch (requestCode) { + case CODE_SHOW_INPUT_METHOD_PICKER: + if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm, + true /* should include auxiliary subtypes */)) { mImm.showInputMethodPicker(); - } else { - launchSettings(); + return true; } + return false; } + return false; } private boolean isShowingOptionDialog() { @@ -1214,9 +1219,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar case Keyboard.CODE_SETTINGS: onSettingsKeyPressed(); break; - case Keyboard.CODE_SETTINGS_LONGPRESS: - onSettingsKeyLongPressed(); - break; case Keyboard.CODE_CAPSLOCK: switcher.toggleCapsLock(); break; @@ -1457,7 +1459,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // in Italian dov' should not be expanded to dove' because the elision // requires the last vowel to be removed. final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled - && !mInputTypeNoAutoCorrect && mHasDictionary; + && !mInputTypeNoAutoCorrect; if (shouldAutoCorrect && primaryCode != Keyboard.CODE_SINGLE_QUOTE) { pickedDefault = pickDefaultSuggestion(primaryCode); } else { @@ -1752,9 +1754,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar sendMagicSpace(); } - // We should show the hint if the user pressed the first entry AND either: + // We should show the "Touch again to save" hint if the user pressed the first entry + // AND either: // - There is no dictionary (we know that because we tried to load it => null != mSuggest - // AND mHasDictionary is false) + // AND mSuggest.hasMainDictionary() is false) // - There is a dictionary and the word is not in it // Please note that if mSuggest is null, it means that everything is off: suggestion // and correction, so we shouldn't try to show the hint @@ -1762,7 +1765,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // to do with the autocorrection setting. final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null // If there is no dictionary the hint should be shown. - && (!mHasDictionary + && (!mSuggest.hasMainDictionary() // If "suggestion" is not in the dictionary, the hint should be shown. || !AutoCorrection.isValidWord( mSuggest.getUnigramDictionaries(), suggestion, true)); @@ -1925,15 +1928,16 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } final CharSequence separator = ic.getTextBeforeCursor(1, 0); - ic.deleteSurroundingText(mCommittedLength + 1 /* separator */, 0); + ic.deleteSurroundingText(1, 0); + final CharSequence textToTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0); + ic.deleteSurroundingText(mCommittedLength, 0); // Re-insert "separator" only when the deleted character was word separator and the // composing text wasn't equal to the auto-corrected text which can be found before // the cursor. if (!TextUtils.isEmpty(separator) && mSettingsValues.isWordSeparator(separator.charAt(0)) - && !TextUtils.equals(mComposingStringBuilder, - ic.getTextBeforeCursor(mCommittedLength, 0))) { + && !TextUtils.equals(mComposingStringBuilder, textToTheLeft)) { ic.commitText(mComposingStringBuilder, 1); TextEntryState.acceptedTyped(mComposingStringBuilder); ic.commitText(separator, 1); @@ -2096,9 +2100,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void updateCorrectionMode() { // TODO: cleanup messy flags - mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false; final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled - && !mInputTypeNoAutoCorrect && mHasDictionary; + && !mInputTypeNoAutoCorrect; mCorrectionMode = (shouldAutoCorrect && mSettingsValues.mAutoCorrectEnabled) ? Suggest.CORRECTION_FULL : (shouldAutoCorrect ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE); @@ -2135,14 +2138,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } protected void launchSettings() { - launchSettings(Settings.class); + launchSettingsClass(Settings.class); } public void launchDebugSettings() { - launchSettings(DebugSettings.class); + launchSettingsClass(DebugSettings.class); } - protected void launchSettings(Class<? extends PreferenceActivity> settingsClass) { + protected void launchSettingsClass(Class<? extends PreferenceActivity> settingsClass) { handleClose(); Intent intent = new Intent(); intent.setClass(LatinIME.this, settingsClass); diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 933a94176..36a29e896 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -191,6 +191,8 @@ public class Suggest implements Dictionary.WordCallback { mCorrectionMode = mode; } + // The main dictionary could have been loaded asynchronously. Don't cache the return value + // of this method. public boolean hasMainDictionary() { return mMainDict != null; } diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 16a2b0e5f..c07793c33 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -111,35 +111,42 @@ public class Utils { } } - public static boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManagerCompatWrapper imm) { + public static boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManagerCompatWrapper imm, + boolean shouldIncludeAuxiliarySubtypes) { final List<InputMethodInfoCompatWrapper> enabledImis = imm.getEnabledInputMethodList(); - // Filters out IMEs that have auxiliary subtypes only (including either implicitly or - // explicitly enabled ones). - final ArrayList<InputMethodInfoCompatWrapper> filteredImis = - new ArrayList<InputMethodInfoCompatWrapper>(); + // Number of the filtered IMEs + int filteredImisCount = 0; - outerloop: for (InputMethodInfoCompatWrapper imi : enabledImis) { // We can return true immediately after we find two or more filtered IMEs. - if (filteredImis.size() > 1) return true; + if (filteredImisCount > 1) return true; final List<InputMethodSubtypeCompatWrapper> subtypes = imm.getEnabledInputMethodSubtypeList(imi, true); - // IMEs that have no subtypes should be included. + // IMEs that have no subtypes should be counted. if (subtypes.isEmpty()) { - filteredImis.add(imi); + ++filteredImisCount; continue; } - // IMEs that have one or more non-auxiliary subtypes should be included. + + int auxCount = 0; for (InputMethodSubtypeCompatWrapper subtype : subtypes) { - if (!subtype.isAuxiliary()) { - filteredImis.add(imi); - continue outerloop; + if (subtype.isAuxiliary()) { + ++auxCount; } } + final int nonAuxCount = subtypes.size() - auxCount; + + // IMEs that have one or more non-auxiliary subtypes should be counted. + // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary + // subtypes should be counted as well. + if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) { + ++filteredImisCount; + continue; + } } - return filteredImis.size() > 1 + return filteredImisCount > 1 // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled // input method subtype (The current IME should be LatinIME.) || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1; |