diff options
author | 2011-04-13 14:12:24 +0900 | |
---|---|---|
committer | 2011-04-13 18:59:33 +0900 | |
commit | 7a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92 (patch) | |
tree | 0975cb3d2df4eced4c836078291306761f136991 /java/src | |
parent | 47d2ef69d3f94e68bf675967ce3140cbb6179279 (diff) | |
download | latinime-7a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92.tar.gz latinime-7a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92.tar.xz latinime-7a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92.zip |
Fast key preview
Previously the key preview was implemented by PopupWindow. The key
preview popup window would be dismissed and shown each time the key
was released and pressed. It turned out that it was taking several
milliseconds.
This change implements the key preview by a simple TextView which will
be layout-ed at absolute coordinates within the screen FrameLayout.
And dismissing and showing the key preview is implemented by the
TextView's visibility.
This implementation needs careful coordination of candidates.xml
layout and LatinIME.onComputeInsets to control suggestion strip
visibility.
Bug: 4179964
Change-Id: Id6347cb35b91eb14ab20dd2f312e58b54b6625a7
Diffstat (limited to 'java/src')
5 files changed, 60 insertions, 117 deletions
diff --git a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java index e02aac704..1ea7236f9 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java @@ -19,20 +19,9 @@ package com.android.inputmethod.compat; import com.android.inputmethod.latin.SubtypeSwitcher; import android.inputmethodservice.InputMethodService; -import android.view.View; import android.view.inputmethod.InputMethodSubtype; -import android.widget.HorizontalScrollView; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; public class InputMethodServiceCompatWrapper extends InputMethodService { - private static final Method METHOD_HorizontalScrollView_setOverScrollMode = - CompatUtils.getMethod(HorizontalScrollView.class, "setOverScrollMode", int.class); - private static final Field FIELD_View_OVER_SCROLL_NEVER = - CompatUtils.getField(View.class, "OVER_SCROLL_NEVER"); - private static final Integer View_OVER_SCROLL_NEVER = - (Integer)CompatUtils.getFieldValue(null, null, FIELD_View_OVER_SCROLL_NEVER); // CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED needs to be false if the API level is 10 // or previous. Note that InputMethodSubtype was added in the API level 11. // For the API level 11 or later, LatinIME should override onCurrentInputMethodSubtypeChanged(). @@ -66,13 +55,6 @@ public class InputMethodServiceCompatWrapper extends InputMethodService { } } - protected static void setOverScrollModeNever(HorizontalScrollView scrollView) { - if (View_OVER_SCROLL_NEVER != null) { - CompatUtils.invoke(scrollView, null, METHOD_HorizontalScrollView_setOverScrollMode, - View_OVER_SCROLL_NEVER); - } - } - ////////////////////////////////////// // Functions using API v11 or later // ////////////////////////////////////// diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 7b570d7ed..71863803b 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -45,8 +45,8 @@ import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.view.WindowManager; +import android.view.ViewGroup; +import android.widget.FrameLayout; import android.widget.PopupWindow; import android.widget.TextView; @@ -110,14 +110,12 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { // Key preview popup private boolean mInForeground; private TextView mPreviewText; - private PopupWindow mPreviewPopup; private int mPreviewTextSizeLarge; - private int[] mOffsetInWindow; + private final int[] mOffsetInWindow = new int[2]; private int mOldPreviewKeyIndex = KeyDetector.NOT_A_KEY; private boolean mShowPreview = true; private int mPopupPreviewOffsetX; private int mPopupPreviewOffsetY; - private int mWindowY; private int mPopupPreviewDisplayedY; private final int mDelayBeforePreview; private final int mDelayAfterPreview; @@ -125,7 +123,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { // Popup mini keyboard private PopupWindow mMiniKeyboardPopup; private KeyboardView mMiniKeyboardView; - private View mMiniKeyboardParent; private final WeakHashMap<Key, View> mMiniKeyboardCache = new WeakHashMap<Key, View>(); private int mMiniKeyboardOriginX; private int mMiniKeyboardOriginY; @@ -204,7 +201,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { showKey(msg.arg1, (PointerTracker)msg.obj); break; case MSG_DISMISS_PREVIEW: - mPreviewPopup.dismiss(); + mPreviewText.setVisibility(View.INVISIBLE); break; case MSG_REPEAT_KEY: { final PointerTracker tracker = (PointerTracker)msg.obj; @@ -227,12 +224,11 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { public void popupPreview(long delay, int keyIndex, PointerTracker tracker) { removeMessages(MSG_POPUP_PREVIEW); - if (mPreviewPopup.isShowing() && mPreviewText.getVisibility() == VISIBLE) { + if (mPreviewText.getVisibility() == VISIBLE) { // Show right away, if it's already visible and finger is moving around showKey(keyIndex, tracker); } else { - sendMessageDelayed(obtainMessage(MSG_POPUP_PREVIEW, keyIndex, 0, tracker), - delay); + sendMessageDelayed(obtainMessage(MSG_POPUP_PREVIEW, keyIndex, 0, tracker), delay); } } @@ -241,9 +237,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { } public void dismissPreview(long delay) { - if (mPreviewPopup.isShowing()) { - sendMessageDelayed(obtainMessage(MSG_DISMISS_PREVIEW), delay); - } + sendMessageDelayed(obtainMessage(MSG_DISMISS_PREVIEW), delay); } public void cancelDismissPreview() { @@ -366,24 +360,17 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { final Resources res = getResources(); - mPreviewPopup = new PopupWindow(context); if (previewLayout != 0) { mPreviewText = (TextView) LayoutInflater.from(context).inflate(previewLayout, null); mPreviewTextSizeLarge = (int) res.getDimension(R.dimen.key_preview_text_size_large); - mPreviewPopup.setContentView(mPreviewText); - mPreviewPopup.setBackgroundDrawable(null); } else { mShowPreview = false; } - mPreviewPopup.setTouchable(false); - mPreviewPopup.setAnimationStyle(R.style.KeyPreviewAnimation); - mPreviewPopup.setClippingEnabled(false); mDelayBeforePreview = res.getInteger(R.integer.config_delay_before_preview); mDelayAfterPreview = res.getInteger(R.integer.config_delay_after_preview); mKeyLabelHorizontalPadding = (int)res.getDimension( R.dimen.key_label_horizontal_alignment_padding); - mMiniKeyboardParent = this; mMiniKeyboardPopup = new PopupWindow(context); mMiniKeyboardPopup.setBackgroundDrawable(null); mMiniKeyboardPopup.setAnimationStyle(R.style.MiniKeyboardAnimation); @@ -583,7 +570,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { public void setPopupOffset(int x, int y) { mPopupPreviewOffsetX = x; mPopupPreviewOffsetY = y; - mPreviewPopup.dismiss(); } /** @@ -915,8 +901,16 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { } } - // TODO Must fix popup preview on xlarge layout + // TODO: Introduce minimum duration for displaying key previews + // TODO: Display up to two key previews when the user presses two keys at the same time private void showKey(final int keyIndex, PointerTracker tracker) { + // If the preview popup has no parent view yet, add it to the screen FrameLayout. + if (mPreviewText.getParent() == null) { + final FrameLayout screenContent = (FrameLayout) getRootView() + .findViewById(android.R.id.content); + screenContent.addView(mPreviewText, new FrameLayout.LayoutParams(0, 0)); + } + Key key = tracker.getKey(keyIndex); // If keyIndex is invalid or IME is already closed, we must not show key preview. // Trying to show preview PopupWindow while root window is closed causes @@ -948,7 +942,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), keyDrawWidth + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight()); final int popupHeight = mPreviewHeight; - LayoutParams lp = mPreviewText.getLayoutParams(); + final ViewGroup.LayoutParams lp = mPreviewText.getLayoutParams(); if (lp != null) { lp.width = popupWidth; lp.height = popupHeight; @@ -958,47 +952,23 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { int popupPreviewY = key.mY - popupHeight + mPreviewOffset; mHandler.cancelDismissPreview(); - if (mOffsetInWindow == null) { - mOffsetInWindow = new int[2]; - getLocationInWindow(mOffsetInWindow); - mOffsetInWindow[0] += mPopupPreviewOffsetX; // Offset may be zero - mOffsetInWindow[1] += mPopupPreviewOffsetY; // Offset may be zero - int[] windowLocation = new int[2]; - getLocationOnScreen(windowLocation); - mWindowY = windowLocation[1]; - } + getLocationInWindow(mOffsetInWindow); + mOffsetInWindow[0] += mPopupPreviewOffsetX; // Offset may be zero + mOffsetInWindow[1] += mPopupPreviewOffsetY; // Offset may be zero + // Set the preview background state mPreviewText.getBackground().setState( key.mPopupCharacters != null ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET); popupPreviewX += mOffsetInWindow[0]; popupPreviewY += mOffsetInWindow[1]; - // If the popup cannot be shown above the key, put it on the side - if (popupPreviewY + mWindowY < 0) { - // If the key you're pressing is on the left side of the keyboard, show the popup on - // the right, offset by enough to see at least one key to the left/right. - if (keyDrawX + keyDrawWidth <= getWidth() / 2) { - popupPreviewX += (int) (keyDrawWidth * 2.5); - } else { - popupPreviewX -= (int) (keyDrawWidth * 2.5); - } - popupPreviewY += popupHeight; - } - - try { - if (mPreviewPopup.isShowing()) { - mPreviewPopup.update(popupPreviewX, popupPreviewY, popupWidth, popupHeight); - } else { - mPreviewPopup.setWidth(popupWidth); - mPreviewPopup.setHeight(popupHeight); - mPreviewPopup.showAtLocation(mMiniKeyboardParent, Gravity.NO_GRAVITY, - popupPreviewX, popupPreviewY); - } - } catch (WindowManager.BadTokenException e) { - // Swallow the exception which will be happened when IME is already closed. - Log.w(TAG, "LatinIME is already closed when tried showing key preview."); + // Place the key preview. + // TODO: Adjust position of key previews which touch screen edges + if (lp instanceof ViewGroup.MarginLayoutParams) { + ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)lp; + mlp.setMargins(popupPreviewX, popupPreviewY, 0, 0); } - // Record popup preview position to display mini-keyboard later at the same positon + // Record popup preview position to display mini-keyboard later at the same position mPopupPreviewDisplayedY = popupPreviewY; mPreviewText.setVisibility(VISIBLE); } @@ -1114,7 +1084,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { final Keyboard keyboard = new MiniKeyboardBuilder(this, mKeyboard.getPopupKeyboardResId(), popupKey).build(); miniKeyboardView.setKeyboard(keyboard); - miniKeyboardView.mMiniKeyboardParent = this; container.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); @@ -1349,7 +1318,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { } public void closing() { - mPreviewPopup.dismiss(); + mPreviewText.setVisibility(View.GONE); mHandler.cancelAllMessages(); dismissPopupKeyboard(); diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index eb5335ffd..add38cf45 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -549,7 +549,6 @@ public class PointerTracker { final Key key = getKey(keyIndex); if (key != null && !key.mEnabled) return; - updateKeyGraphics(keyIndex); // The modifier key, such as shift key, should not be shown as preview when multi-touch is // supported. On the other hand, if multi-touch is not supported, the modifier key should // be shown as preview. If accessibility is turned on, the modifier key should be shown as @@ -559,6 +558,7 @@ public class PointerTracker { } else { mProxy.showPreview(keyIndex, this); } + updateKeyGraphics(keyIndex); } private void startLongPressTimer(int keyIndex) { diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java index 5719b9012..6fb80adf0 100644 --- a/java/src/com/android/inputmethod/latin/CandidateView.java +++ b/java/src/com/android/inputmethod/latin/CandidateView.java @@ -133,7 +133,6 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo ViewGroup.LayoutParams.WRAP_CONTENT); mPreviewPopup.setContentView(mPreviewText); mPreviewPopup.setBackgroundDrawable(null); - mPreviewPopup.setAnimationStyle(R.style.KeyPreviewAnimation); mConfigCandidateHighlightFontColorEnabled = res.getBoolean(R.bool.config_candidate_highlight_font_color_enabled); mColorNormal = res.getColor(R.color.candidate_normal); diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 6a858fe99..7664a48fb 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -56,7 +56,6 @@ import android.util.DisplayMetrics; import android.util.Log; import android.util.PrintWriterPrinter; import android.util.Printer; -import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -70,8 +69,6 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; -import android.widget.FrameLayout; -import android.widget.HorizontalScrollView; import android.widget.LinearLayout; import java.io.FileDescriptor; @@ -143,6 +140,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar }; private View mCandidateViewContainer; + private int mCandidateStripHeight; private CandidateView mCandidateView; private Suggest mSuggest; private CompletionInfo[] mApplicationSpecifiedCompletions; @@ -528,12 +526,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar LayoutInflater inflater = getLayoutInflater(); LinearLayout container = (LinearLayout)inflater.inflate(R.layout.candidates, null); mCandidateViewContainer = container; - if (container.getPaddingRight() != 0) { - HorizontalScrollView scrollView = - (HorizontalScrollView) container.findViewById(R.id.candidates_scroll_view); - setOverScrollModeNever(scrollView); - container.setGravity(Gravity.CENTER_HORIZONTAL); - } + mCandidateStripHeight = (int)mResources.getDimension(R.dimen.candidate_strip_height); mCandidateView = (CandidateView) container.findViewById(R.id.candidates); mCandidateView.setService(this); setCandidatesViewShown(true); @@ -581,8 +574,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar switcher.updateShiftState(); } - setCandidatesViewShownInternal(isCandidateStripVisible(), - false /* needsInputViewShown */ ); + setCandidatesViewShownInternal(isCandidateStripVisible(), false /* needsInputViewShown */ ); // Delay updating suggestions because keyboard input view may not be shown at this point. mHandler.postUpdateSuggestions(); @@ -872,10 +864,21 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } private void setCandidatesViewShownInternal(boolean shown, boolean needsInputViewShown) { - // TODO: Remove this if we support candidates with hard keyboard + // TODO: Modify this if we support candidates with hard keyboard if (onEvaluateInputViewShown()) { - super.setCandidatesViewShown(shown - && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true)); + final boolean shouldShowCandidates = shown + && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true); + if (isExtractViewShown()) { + // No need to have extra space to show the key preview. + mCandidateViewContainer.setMinimumHeight(0); + super.setCandidatesViewShown(shown); + } else { + // We must control the visibility of the suggestion strip in order to avoid clipped + // key previews, even when we don't show the suggestion strip. + mCandidateViewContainer.setVisibility( + shouldShowCandidates ? View.VISIBLE : View.INVISIBLE); + super.setCandidatesViewShown(true); + } } } @@ -887,35 +890,25 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar @Override public void onComputeInsets(InputMethodService.Insets outInsets) { super.onComputeInsets(outInsets); - if (!isFullscreenMode()) { - outInsets.contentTopInsets = outInsets.visibleTopInsets; - } - KeyboardView inputView = mKeyboardSwitcher.getInputView(); + final KeyboardView inputView = mKeyboardSwitcher.getInputView(); // Need to set touchable region only if input view is being shown if (inputView != null && mKeyboardSwitcher.isInputViewShown()) { - final int x = 0; - int y = 0; - final int width = inputView.getWidth(); - int height = inputView.getHeight() + EXTENDED_TOUCHABLE_REGION_HEIGHT; - if (mCandidateViewContainer != null) { - ViewParent candidateParent = mCandidateViewContainer.getParent(); - if (candidateParent instanceof FrameLayout) { - FrameLayout fl = (FrameLayout) candidateParent; - if (fl != null) { - // Check frame layout's visibility - if (fl.getVisibility() == View.INVISIBLE) { - y = fl.getHeight(); - height += y; - } else if (fl.getVisibility() == View.VISIBLE) { - height += fl.getHeight(); - } - } - } + final int containerHeight = mCandidateViewContainer.getHeight(); + int touchY = containerHeight; + if (mCandidateViewContainer.getVisibility() == View.VISIBLE) { + touchY -= mCandidateStripHeight; } + outInsets.contentTopInsets = touchY; + outInsets.visibleTopInsets = touchY; + final int touchWidth = inputView.getWidth(); + final int touchHeight = inputView.getHeight() + containerHeight + // Extend touchable region below the keyboard. + + EXTENDED_TOUCHABLE_REGION_HEIGHT; if (DEBUG) { - Log.d(TAG, "Touchable region " + x + ", " + y + ", " + width + ", " + height); + Log.d(TAG, "Touchable region: y=" + touchY + " width=" + touchWidth + + " height=" + touchHeight); } - setTouchableRegionCompat(outInsets, x, y, width, height); + setTouchableRegionCompat(outInsets, 0, touchY, touchWidth, touchHeight); } } |