diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index e8e139da317914f689bfed9c372966a272b1e20d..ad4b296e123a7b71711d0b0f181a3ef930c085d4 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -109,6 +109,10 @@ <attr name="keyPreviewOffset" format="dimension" /> <!-- Height of the key press feedback popup. --> <attr name="keyPreviewHeight" format="dimension" /> + <!-- Duration of key preview popup zoom in animation in millisecond --> + <attr name="keyPreviewZoomInDuration" format="integer" /> + <!-- Duration of key preview popup zoom out animation in millisecond --> + <attr name="keyPreviewZoomOutDuration" format="integer" /> <!-- Delay after key releasing and key press feedback dismissing in millisecond --> <attr name="keyPreviewLingerTimeout" format="integer" /> <!-- Layout resource for more keys keyboard --> diff --git a/java/res/values/config.xml b/java/res/values/config.xml index 1b42d0b33c812cedfd8744851533f664851c2e46..669a6612cd8164e94267c22a0ba6d4c35653428a 100644 --- a/java/res/values/config.xml +++ b/java/res/values/config.xml @@ -52,6 +52,8 @@ <dimen name="config_key_hysteresis_distance_for_sliding_modifier">8.0dp</dimen> <integer name="config_touch_noise_threshold_time">40</integer> <dimen name="config_touch_noise_threshold_distance">12.6dp</dimen> + <integer name="config_key_preview_zoom_in_duration">35</integer> + <integer name="config_key_preview_zoom_out_duration">40</integer> <integer name="config_key_preview_linger_timeout">70</integer> <bool name="config_key_selection_by_dragging_finger">true</bool> <!-- Sliding key input preview parameters --> diff --git a/java/res/values/themes-common.xml b/java/res/values/themes-common.xml index 64e8c87b443694d1c524696d45e3ba5d8a1f50d0..56fac28cf830b6a6e4d5b29fc66f5d342d2c7711 100644 --- a/java/res/values/themes-common.xml +++ b/java/res/values/themes-common.xml @@ -77,6 +77,8 @@ <item name="ignoreAltCodeKeyTimeout">@integer/config_ignore_alt_code_key_timeout</item> <item name="keyPreviewLayout">@layout/key_preview</item> <item name="keyPreviewHeight">@dimen/key_preview_height</item> + <item name="keyPreviewZoomInDuration">@integer/config_key_preview_zoom_in_duration</item> + <item name="keyPreviewZoomOutDuration">@integer/config_key_preview_zoom_out_duration</item> <item name="keyPreviewLingerTimeout">@integer/config_key_preview_linger_timeout</item> <item name="moreKeysKeyboardLayout">@layout/more_keys_keyboard</item> <item name="showMoreKeysKeyboardAtTouchedPoint">@bool/config_show_more_keys_keyboard_at_touched_point</item> diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index e89699f422a3cfa80f9aee75c9e5d464a4ec3553..0fe2455613b898dbaea8ea84df0f1ef7895c46e4 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -16,7 +16,10 @@ package com.android.inputmethod.keyboard; +import android.animation.Animator; import android.animation.AnimatorInflater; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; import android.content.SharedPreferences; @@ -40,6 +43,8 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; import android.view.inputmethod.InputMethodSubtype; import android.widget.TextView; @@ -168,6 +173,15 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack private final KeyPreviewDrawParams mKeyPreviewDrawParams = new KeyPreviewDrawParams(); private boolean mShowKeyPreviewPopup = true; private int mKeyPreviewLingerTimeout; + private int mKeyPreviewZoomInDuration; + private int mKeyPreviewZoomOutDuration; + private static final float KEY_PREVIEW_START_ZOOM_IN_SCALE = 0.7f; + private static final float KEY_PREVIEW_END_ZOOM_IN_SCALE = 1.0f; + private static final float KEY_PREVIEW_END_ZOOM_OUT_SCALE = 0.7f; + private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR = + new AccelerateInterpolator(); + private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = + new DecelerateInterpolator(); // More keys keyboard private final Paint mBackgroundDimAlphaPaint = new Paint(); @@ -389,17 +403,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack if (mainKeyboardView == null) return; switch (msg.what) { case MSG_DISMISS_KEY_PREVIEW: - final Key key = (Key)msg.obj; - if (key != null) { - final TextView previewTextView = - mainKeyboardView.mShowingKeyPreviewTextViews.remove(key); - if (previewTextView != null) { - previewTextView.setVisibility(INVISIBLE); - mainKeyboardView.mFreeKeyPreviewTextViews.add(previewTextView); - } - // To redraw key top letter. - mainKeyboardView.invalidateKey(key); - } + mainKeyboardView.dismissKeyPreviewWithoutDelay((Key)msg.obj); break; case MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT: mainKeyboardView.showGestureFloatingPreviewText(SuggestedWords.EMPTY); @@ -413,6 +417,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack private void cancelAllDismissKeyPreviews() { removeMessages(MSG_DISMISS_KEY_PREVIEW); + final MainKeyboardView mainKeyboardView = getOuterInstance(); + if (mainKeyboardView == null) return; + mainKeyboardView.dismissAllKeyPreviews(); } public void dismissGestureFloatingPreviewText(final long delay) { @@ -487,6 +494,10 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack if (mKeyPreviewLayoutId == 0) { mShowKeyPreviewPopup = false; } + mKeyPreviewZoomInDuration = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_keyPreviewZoomInDuration, 0); + mKeyPreviewZoomOutDuration = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_keyPreviewZoomOutDuration, 0); final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId( R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0); mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean( @@ -712,11 +723,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack private void dismissAllKeyPreviews() { for (final Key key : new HashSet<Key>(mShowingKeyPreviewTextViews.keySet())) { - final TextView previewTextView = mShowingKeyPreviewTextViews.remove(key); - if (previewTextView != null) { - previewTextView.setVisibility(INVISIBLE); - mFreeKeyPreviewTextViews.add(previewTextView); - } + dismissKeyPreviewWithoutDelay(key); } PointerTracker.setReleasedKeyGraphicsToAllKeys(); } @@ -742,6 +749,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack private static final int STATE_NORMAL = 0; private static final int STATE_HAS_MOREKEYS = 1; + // TODO: Take this method out of this class. @Override public void showKeyPreview(final Key key) { // If key is invalid or IME is already closed, we must not show key preview. @@ -819,13 +827,129 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } ViewLayoutUtils.placeViewAt( previewTextView, previewX, previewY, previewWidth, previewHeight); - previewTextView.setVisibility(VISIBLE); - mShowingKeyPreviewTextViews.put(key, previewTextView); + + if (!isHardwareAccelerated()) { + previewTextView.setVisibility(VISIBLE); + mShowingKeyPreviewTextViews.put(key, previewTextView); + return; + } + previewTextView.setPivotX(previewWidth / 2.0f); + previewTextView.setPivotY(previewHeight); + + final Animator zoomIn = createZoomInAniation(key, previewTextView); + final Animator zoomOut = createZoomOutAnimation(key, previewTextView); + final KeyPreviewAnimations animation = new KeyPreviewAnimations(zoomIn, zoomOut); + previewTextView.setTag(animation); + animation.startZoomIn(); + } + + // TODO: Move this internal class out to a separate external class. + private static class KeyPreviewAnimations extends AnimatorListenerAdapter { + private final Animator mZoomIn; + private final Animator mZoomOut; + + public KeyPreviewAnimations(final Animator zoomIn, final Animator zoomOut) { + mZoomIn = zoomIn; + mZoomOut = zoomOut; + } + + public void startZoomIn() { + mZoomIn.start(); + } + + public void startZoomOut() { + if (mZoomIn.isRunning()) { + mZoomIn.addListener(this); + return; + } + mZoomOut.start(); + } + + @Override + public void onAnimationEnd(final Animator animation) { + mZoomOut.start(); + } + } + + // TODO: Take this method out of this class. + private Animator createZoomInAniation(final Key key, final TextView previewTextView) { + final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat( + previewTextView, SCALE_X, KEY_PREVIEW_START_ZOOM_IN_SCALE, + KEY_PREVIEW_END_ZOOM_IN_SCALE); + final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat( + previewTextView, SCALE_Y, KEY_PREVIEW_START_ZOOM_IN_SCALE, + KEY_PREVIEW_END_ZOOM_IN_SCALE); + final AnimatorSet zoomInAnimation = new AnimatorSet(); + zoomInAnimation.play(scaleXAnimation).with(scaleYAnimation); + // TODO: Implement preference option to control key preview animation duration. + zoomInAnimation.setDuration(mKeyPreviewZoomInDuration); + zoomInAnimation.setInterpolator(DECELERATE_INTERPOLATOR); + zoomInAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(final Animator animation) { + previewTextView.setVisibility(VISIBLE); + mShowingKeyPreviewTextViews.put(key, previewTextView); + } + }); + return zoomInAnimation; + } + + // TODO: Take this method out of this class. + private Animator createZoomOutAnimation(final Key key, final TextView previewTextView) { + final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat( + previewTextView, SCALE_X, KEY_PREVIEW_END_ZOOM_OUT_SCALE); + final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat( + previewTextView, SCALE_Y, KEY_PREVIEW_END_ZOOM_OUT_SCALE); + final AnimatorSet zoomOutAnimation = new AnimatorSet(); + zoomOutAnimation.play(scaleXAnimation).with(scaleYAnimation); + // TODO: Implement preference option to control key preview animation duration. + zoomOutAnimation.setDuration(mKeyPreviewZoomOutDuration); + zoomOutAnimation.setInterpolator(ACCELERATE_INTERPOLATOR); + zoomOutAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(final Animator animation) { + dismissKeyPreviewWithoutDelay(key); + } + }); + return zoomOutAnimation; + } + + // TODO: Take this method out of this class. + private void dismissKeyPreviewWithoutDelay(final Key key) { + if (key == null) { + return; + } + final TextView previewTextView = mShowingKeyPreviewTextViews.remove(key); + if (previewTextView != null) { + final Object tag = previewTextView.getTag(); + if (tag instanceof Animator) { + ((Animator)tag).cancel(); + } + previewTextView.setTag(null); + previewTextView.setVisibility(INVISIBLE); + mFreeKeyPreviewTextViews.add(previewTextView); + } + // To redraw key top letter. + invalidateKey(key); } + // TODO: Take this method out of this class. @Override public void dismissKeyPreview(final Key key) { - mDrawingHandler.dismissKeyPreview(mKeyPreviewLingerTimeout, key); + final TextView previewTextView = mShowingKeyPreviewTextViews.get(key); + if (previewTextView == null) { + return; + } + if (!isHardwareAccelerated()) { + // TODO: Implement preference option to control key preview method and duration. + mDrawingHandler.dismissKeyPreview(mKeyPreviewLingerTimeout, key); + return; + } + final Object tag = previewTextView.getTag(); + if (tag instanceof KeyPreviewAnimations) { + final KeyPreviewAnimations animation = (KeyPreviewAnimations)tag; + animation.startZoomOut(); + } } public void setSlidingKeyInputPreviewEnabled(final boolean enabled) { @@ -984,6 +1108,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack final int pointY = key.getY() + mKeyPreviewDrawParams.mPreviewVisibleOffset; moreKeysPanel.showMoreKeysPanel(this, this, pointX, pointY, mKeyboardActionListener); tracker.onShowMoreKeysPanel(moreKeysPanel); + // TODO: Implement zoom in animation of more keys panel. + dismissKeyPreviewWithoutDelay(key); } public boolean isInDraggingFinger() {