From 585fa0491a023788b9a877cfcff7460061e72db6 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Mon, 18 Nov 2013 19:20:32 +0900 Subject: [PATCH] Implement key preview zoom in/out animations Bug: 11518021 Change-Id: I139b18708055e0811234886578c5a30b8cc71fec --- java/res/values/attrs.xml | 4 + java/res/values/config.xml | 2 + java/res/values/themes-common.xml | 2 + .../keyboard/MainKeyboardView.java | 164 ++++++++++++++++-- 4 files changed, 153 insertions(+), 19 deletions(-) diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index e8e139da3..ad4b296e1 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -109,6 +109,10 @@ + + + + diff --git a/java/res/values/config.xml b/java/res/values/config.xml index 1b42d0b33..669a6612c 100644 --- a/java/res/values/config.xml +++ b/java/res/values/config.xml @@ -52,6 +52,8 @@ 8.0dp 40 12.6dp + 35 + 40 70 true diff --git a/java/res/values/themes-common.xml b/java/res/values/themes-common.xml index 64e8c87b4..56fac28cf 100644 --- a/java/res/values/themes-common.xml +++ b/java/res/values/themes-common.xml @@ -77,6 +77,8 @@ @integer/config_ignore_alt_code_key_timeout @layout/key_preview @dimen/key_preview_height + @integer/config_key_preview_zoom_in_duration + @integer/config_key_preview_zoom_out_duration @integer/config_key_preview_linger_timeout @layout/more_keys_keyboard @bool/config_show_more_keys_keyboard_at_touched_point diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index e89699f42..0fe245561 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(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() {