diff options
Diffstat (limited to 'java/src')
7 files changed, 134 insertions, 88 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 0d2e9f0ad..9be193ba7 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -272,8 +272,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { public final Drawable mPreviewBackground; public final Drawable mPreviewLeftBackground; public final Drawable mPreviewRightBackground; - public final int mPreviewBackgroundWidth; - public final int mPreviewBackgroundHeight; public final int mPreviewTextColor; public final int mPreviewOffset; public final int mPreviewHeight; @@ -283,6 +281,31 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { private final float mPreviewTextRatio; private final float mKeyLetterRatio; + // The graphical geometry of the key preview. + // <-width-> + // +-------+ ^ + // | | | + // |preview| height (visible) + // | | | + // + + ^ v + // \ / |offset + // +-\ /-+ v + // | +-+ | + // |parent | + // | key| + // +-------+ + // The background of a {@link TextView} being used for a key preview may have invisible + // paddings. To align the more keys keyboard panel's visible part with the visible part of + // the background, we need to record the width and height of key preview that don't include + // invisible paddings. + public int mPreviewVisibleWidth; + public int mPreviewVisibleHeight; + // The key preview may have an arbitrary offset and its background that may have a bottom + // padding. To align the more keys keyboard and the key preview we also need to record the + // offset between the top edge of parent key and the bottom of the visible part of key + // preview background. + public int mPreviewVisibleOffset; + public int mPreviewTextSize; public int mKeyLetterSize; public final int[] mCoordinates = new int[2]; @@ -298,10 +321,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { setAlpha(mPreviewBackground, PREVIEW_ALPHA); setAlpha(mPreviewLeftBackground, PREVIEW_ALPHA); setAlpha(mPreviewRightBackground, PREVIEW_ALPHA); - mPreviewBackgroundWidth = a.getDimensionPixelSize( - R.styleable.KeyboardView_keyPreviewBackgroundWidth, 0); - mPreviewBackgroundHeight = a.getDimensionPixelSize( - R.styleable.KeyboardView_keyPreviewBackgroundHeight, 0); mPreviewOffset = a.getDimensionPixelOffset( R.styleable.KeyboardView_keyPreviewOffset, 0); mPreviewHeight = a.getDimensionPixelSize( @@ -839,13 +858,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } @Override - public void showKeyPreview(PointerTracker tracker) { - if (mShowKeyPreviewPopup) { - showKey(tracker); - } - } - - @Override public void dismissKeyPreview(PointerTracker tracker) { mDrawingHandler.dismissKeyPreview(mDelayAfterPreview, tracker); } @@ -861,7 +873,10 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { keyPreview, ViewLayoutUtils.newLayoutParam(mPreviewPlacer, 0, 0)); } - private void showKey(PointerTracker tracker) { + @Override + public void showKeyPreview(PointerTracker tracker) { + if (!mShowKeyPreviewPopup) return; + final TextView previewText = tracker.getKeyPreviewText(); // If the key preview has no parent view yet, add it to the ViewGroup which can place // key preview absolutely in SoftInputWindow. @@ -878,8 +893,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { return; final KeyPreviewDrawParams params = mKeyPreviewDrawParams; - final int keyDrawX = key.mX + key.mVisualInsetsLeft; - final int keyDrawWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight; final String label = key.isShiftedLetterActivated() ? key.mHintLabel : key.mLabel; // What we show as preview should match what we show on a key top in onBufferDraw(). if (label != null) { @@ -902,13 +915,24 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { previewText.measure( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - final int previewWidth = Math.max(previewText.getMeasuredWidth(), keyDrawWidth - + previewText.getPaddingLeft() + previewText.getPaddingRight()); + final int keyDrawWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight; + final int previewWidth = previewText.getMeasuredWidth(); final int previewHeight = params.mPreviewHeight; + // The width and height of visible part of the key preview background. The content marker + // of the background 9-patch have to cover the visible part of the background. + params.mPreviewVisibleWidth = previewWidth - previewText.getPaddingLeft() + - previewText.getPaddingRight(); + params.mPreviewVisibleHeight = previewHeight - previewText.getPaddingTop() + - previewText.getPaddingBottom(); + // The distance between the top edge of the parent key and the bottom of the visible part + // of the key preview background. + params.mPreviewVisibleOffset = params.mPreviewOffset - previewText.getPaddingBottom(); getLocationInWindow(params.mCoordinates); - int previewX = keyDrawX - (previewWidth - keyDrawWidth) / 2 + params.mCoordinates[0]; - final int previewY = key.mY - previewHeight - + params.mCoordinates[1] + params.mPreviewOffset; + // The key preview is horizontally aligned with the center of the visible part of the + // parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and + // the left/right background is used if such background is specified. + int previewX = key.mX + key.mVisualInsetsLeft - (previewWidth - keyDrawWidth) / 2 + + params.mCoordinates[0]; if (previewX < 0) { previewX = 0; if (params.mPreviewLeftBackground != null) { @@ -920,6 +944,10 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { previewText.setBackgroundDrawable(params.mPreviewRightBackground); } } + // The key preview is placed vertically above the top edge of the parent key with an + // arbitrary offset. + final int previewY = key.mY - previewHeight + params.mPreviewOffset + + params.mCoordinates[1]; // Set the preview background state previewText.getBackground().setState( diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 84564c87a..aeca839f1 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -527,9 +527,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke final MoreKeysKeyboardView moreKeysKeyboardView = (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view); - final Keyboard parentKeyboard = getKeyboard(); - final Keyboard moreKeysKeyboard = new MoreKeysKeyboard.Builder( - this, parentKeyboard.mMoreKeysTemplate, parentKey, parentKeyboard).build(); + final Keyboard moreKeysKeyboard = new MoreKeysKeyboard.Builder(container, parentKey, this) + .build(); moreKeysKeyboardView.setKeyboard(moreKeysKeyboard); container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); @@ -598,10 +597,19 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mMoreKeysPanel = moreKeysPanel; mMoreKeysPanelPointerTrackerId = tracker.mPointerId; - final Keyboard keyboard = getKeyboard(); - final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint) ? tracker.getLastX() + final boolean keyPreviewEnabled = isKeyPreviewPopupEnabled() && !parentKey.noKeyPreview(); + // The more keys keyboard is usually horizontally aligned with the center of the parent key. + // If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more + // keys keyboard is placed at the touch point of the parent key. + final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint && !keyPreviewEnabled) + ? tracker.getLastX() : parentKey.mX + parentKey.mWidth / 2; - final int pointY = parentKey.mY - keyboard.mVerticalGap; + // The more keys keyboard is usually vertically aligned with the top edge of the parent key + // (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically + // aligned with the bottom edge of the visible part of the key preview. + final int pointY = parentKey.mY + (keyPreviewEnabled + ? mKeyPreviewDrawParams.mPreviewVisibleOffset + : -parentKey.mVerticalGap); moreKeysPanel.showMoreKeysPanel( this, this, pointX, pointY, mMoreKeysWindow, mKeyboardActionListener); final int translatedX = moreKeysPanel.translateX(tracker.getLastX()); diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java index 7154086e2..b6a06e136 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java @@ -18,6 +18,7 @@ package com.android.inputmethod.keyboard; import android.graphics.Paint; import android.graphics.drawable.Drawable; +import android.view.View; import com.android.inputmethod.keyboard.internal.KeySpecParser.MoreKeySpec; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; @@ -251,30 +252,38 @@ public class MoreKeysKeyboard extends Keyboard { } } - public Builder(KeyboardView view, int xmlId, Key parentKey, Keyboard parentKeyboard) { - super(view.getContext(), new MoreKeysKeyboardParams()); - load(xmlId, parentKeyboard.mId); + /** + * The builder of MoreKeysKeyboard. + * @param containerView the container of {@link MoreKeysKeyboardView}. + * @param parentKey the {@link Key} that invokes more keys keyboard. + * @param parentKeyboardView the {@link KeyboardView} that contains the parentKey. + */ + public Builder(View containerView, Key parentKey, KeyboardView parentKeyboardView) { + super(containerView.getContext(), new MoreKeysKeyboardParams()); + final Keyboard parentKeyboard = parentKeyboardView.getKeyboard(); + load(parentKeyboard.mMoreKeysTemplate, parentKeyboard.mId); // TODO: More keys keyboard's vertical gap is currently calculated heuristically. // Should revise the algorithm. mParams.mVerticalGap = parentKeyboard.mVerticalGap / 2; mParentKey = parentKey; - final int previewWidth = view.mKeyPreviewDrawParams.mPreviewBackgroundWidth; - final int previewHeight = view.mKeyPreviewDrawParams.mPreviewBackgroundHeight; final int width, height; - // Use pre-computed width and height if these values are available and more keys - // keyboard has only one key to mitigate visual flicker between key preview and more - // keys keyboard. - final boolean validKeyPreview = view.isKeyPreviewPopupEnabled() - && !parentKey.noKeyPreview() && (previewWidth > 0) && (previewHeight > 0); - final boolean singleMoreKeyWithPreview = validKeyPreview - && parentKey.mMoreKeys.length == 1; + final boolean singleMoreKeyWithPreview = parentKeyboardView.isKeyPreviewPopupEnabled() + && !parentKey.noKeyPreview() && parentKey.mMoreKeys.length == 1; if (singleMoreKeyWithPreview) { - width = previewWidth; - height = previewHeight + mParams.mVerticalGap; + // Use pre-computed width and height if this more keys keyboard has only one key to + // mitigate visual flicker between key preview and more keys keyboard. + // Caveats for the visual assets: To achieve this effect, both the key preview + // backgrounds and the more keys keyboard panel background have the exact same + // left/right/top paddings. The bottom paddings of both backgrounds don't need to + // be considered because the vertical positions of both backgrounds were already + // adjusted with their bottom paddings deducted. + width = parentKeyboardView.mKeyPreviewDrawParams.mPreviewVisibleWidth; + height = parentKeyboardView.mKeyPreviewDrawParams.mPreviewVisibleHeight + + mParams.mVerticalGap; } else { - width = getMaxKeyWidth(view, parentKey, mParams.mDefaultKeyWidth); + width = getMaxKeyWidth(parentKeyboardView, parentKey, mParams.mDefaultKeyWidth); height = parentKeyboard.mMostCommonKeyHeight; } final int dividerWidth; @@ -288,8 +297,9 @@ public class MoreKeysKeyboard extends Keyboard { dividerWidth = 0; } mParams.setParameters(parentKey.mMoreKeys.length, parentKey.getMoreKeysColumn(), - width, height, parentKey.mX + parentKey.mWidth / 2, view.getMeasuredWidth(), - parentKey.isFixedColumnOrderMoreKeys(), dividerWidth); + width, height, parentKey.mX + parentKey.mWidth / 2, + parentKeyboardView.getMeasuredWidth(), parentKey.isFixedColumnOrderMoreKeys(), + dividerWidth); } private static int getMaxKeyWidth(KeyboardView view, Key parentKey, int minKeyWidth) { diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java index e60fc9598..b4fa86dd5 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java @@ -141,10 +141,8 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel final MoreKeysKeyboard pane = (MoreKeysKeyboard)getKeyboard(); final int defaultCoordX = pane.getDefaultCoordX(); // The coordinates of panel's left-top corner in parentView's coordinate system. - final int x = pointX - defaultCoordX - container.getPaddingLeft() - + parentView.getPaddingLeft(); - final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom() - + parentView.getPaddingTop(); + final int x = pointX - defaultCoordX - container.getPaddingLeft(); + final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom(); window.setContentView(container); window.setWidth(container.getMeasuredWidth()); diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 37d9b6ac7..c62c3ddbc 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -606,7 +606,7 @@ public class PointerTracker { if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY); } - onUpEventInternal(lastX, lastY, eventTime); + onUpEventInternal(); onDownEventInternal(x, y, eventTime); } else { mKeyAlreadyProcessed = true; @@ -646,7 +646,7 @@ public class PointerTracker { } queue.remove(this); } - onUpEventInternal(x, y, eventTime); + onUpEventInternal(); } // Let this pointer tracker know that one of newer-than-this pointer trackers got an up event. @@ -655,24 +655,15 @@ public class PointerTracker { public void onPhantomUpEvent(int x, int y, long eventTime) { if (DEBUG_EVENT) printTouchEvent("onPhntEvent:", x, y, eventTime); - onUpEventInternal(x, y, eventTime); + onUpEventInternal(); mKeyAlreadyProcessed = true; } - private void onUpEventInternal(int x, int y, long eventTime) { + private void onUpEventInternal() { mTimerProxy.cancelKeyTimers(); mIsInSlidingKeyInput = false; - final int keyX, keyY; - if (isMajorEnoughMoveToBeOnNewKey(x, y, onMoveKey(x, y))) { - keyX = x; - keyY = y; - } else { - // Use previous fixed key coordinates. - keyX = mKeyX; - keyY = mKeyY; - } - final Key key = onUpKey(keyX, keyY, eventTime); - setReleasedKeyGraphics(key); + // Release the last pressed key. + setReleasedKeyGraphics(mCurrentKey); if (mIsShowingMoreKeysPanel) { mDrawingProxy.dismissMoreKeysPanel(); mIsShowingMoreKeysPanel = false; @@ -680,7 +671,7 @@ public class PointerTracker { if (mKeyAlreadyProcessed) return; if (!mIsRepeatableKey) { - detectAndSendKey(key, keyX, keyY); + detectAndSendKey(mCurrentKey, mKeyX, mKeyY); } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 796d4ac79..213c0ac82 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1026,13 +1026,25 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } public boolean getCurrentAutoCapsState() { + if (!mSettingsValues.mAutoCap) return false; + + final EditorInfo ei = getCurrentInputEditorInfo(); + if (ei == null) return false; + + final int inputType = ei.inputType; + if ((inputType & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) != 0) return true; + + final boolean noNeedToCheckCapsMode = (inputType & (InputType.TYPE_TEXT_FLAG_CAP_SENTENCES + | InputType.TYPE_TEXT_FLAG_CAP_WORDS)) == 0; + if (noNeedToCheckCapsMode) return false; + final InputConnection ic = getCurrentInputConnection(); - EditorInfo ei = getCurrentInputEditorInfo(); - if (mSettingsValues.mAutoCap && ic != null && ei != null - && ei.inputType != InputType.TYPE_NULL) { - return ic.getCursorCapsMode(ei.inputType) != 0; - } - return false; + if (ic == null) return false; + // TODO: This blocking IPC call is heavy. Consider doing this without using IPC calls. + // Note: getCursorCapsMode() returns the current capitalization mode that is any + // combination of CAP_MODE_CHARACTERS, CAP_MODE_WORDS, and CAP_MODE_SENTENCES. 0 means none + // of them. + return ic.getCursorCapsMode(inputType) != 0; } // "ic" may be null @@ -1478,22 +1490,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen sendKeyCodePoint(Keyboard.CODE_SPACE); } - if ((isAlphabet(primaryCode) + // NOTE: isCursorTouchingWord() is a blocking IPC call, so it often takes several + // dozen milliseconds. Avoid calling it as much as possible, since we are on the UI + // thread here. + if (!isComposingWord && (isAlphabet(primaryCode) || mSettingsValues.isSymbolExcludedFromWordSeparators(primaryCode)) && isSuggestionsRequested() && !isCursorTouchingWord()) { - if (!isComposingWord) { - // Reset entirely the composing state anyway, then start composing a new word unless - // the character is a single quote. The idea here is, single quote is not a - // separator and it should be treated as a normal character, except in the first - // position where it should not start composing a word. - isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != primaryCode); - // Here we don't need to reset the last composed word. It will be reset - // when we commit this one, if we ever do; if on the other hand we backspace - // it entirely and resume suggestions on the previous word, we'd like to still - // have touch coordinates for it. - resetComposingState(false /* alsoResetLastComposedWord */); - clearSuggestions(); - } + // Reset entirely the composing state anyway, then start composing a new word unless + // the character is a single quote. The idea here is, single quote is not a + // separator and it should be treated as a normal character, except in the first + // position where it should not start composing a word. + isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != primaryCode); + // Here we don't need to reset the last composed word. It will be reset + // when we commit this one, if we ever do; if on the other hand we backspace + // it entirely and resume suggestions on the previous word, we'd like to still + // have touch coordinates for it. + resetComposingState(false /* alsoResetLastComposedWord */); + clearSuggestions(); } if (isComposingWord) { mWordComposer.add( diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java index e64e7a685..8a29dcc13 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java @@ -149,10 +149,8 @@ public class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel { final MoreSuggestions pane = (MoreSuggestions)getKeyboard(); final int defaultCoordX = pane.mOccupiedWidth / 2; // The coordinates of panel's left-top corner in parentView's coordinate system. - final int x = pointX - defaultCoordX - container.getPaddingLeft() - + parentView.getPaddingLeft(); - final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom() - + parentView.getPaddingTop(); + final int x = pointX - defaultCoordX - container.getPaddingLeft(); + final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom(); window.setContentView(container); window.setWidth(container.getMeasuredWidth()); |