diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index c6dae3253..71e3eeeaf 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -16,10 +16,7 @@ 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; @@ -35,13 +32,10 @@ import android.preference.PreferenceManager; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; -import android.util.TypedValue; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; import android.view.inputmethod.InputMethodSubtype; import android.widget.TextView; @@ -53,6 +47,7 @@ import com.android.inputmethod.keyboard.internal.DrawingPreviewPlacerView; import com.android.inputmethod.keyboard.internal.GestureFloatingTextDrawingPreview; import com.android.inputmethod.keyboard.internal.GestureTrailsDrawingPreview; import com.android.inputmethod.keyboard.internal.KeyDrawParams; +import com.android.inputmethod.keyboard.internal.KeyPreviewChoreographer; import com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams; import com.android.inputmethod.keyboard.internal.NonDistinctMultitouchHelper; import com.android.inputmethod.keyboard.internal.SlidingKeyInputDrawingPreview; @@ -71,9 +66,6 @@ import com.android.inputmethod.latin.utils.UsabilityStudyLogUtils; import com.android.inputmethod.latin.utils.ViewLayoutUtils; import com.android.inputmethod.research.ResearchLogger; -import java.util.ArrayDeque; -import java.util.HashMap; -import java.util.HashSet; import java.util.WeakHashMap; /** @@ -161,18 +153,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack // Key preview private static final boolean FADE_OUT_KEY_TOP_LETTER_WHEN_KEY_IS_PRESSED = false; - // Free {@link TextView} pool that can be used for key preview. - private final ArrayDeque mFreeKeyPreviewTextViews = CollectionUtils.newArrayDeque(); - // Map from {@link Key} to {@link TextView} that is currently being displayed as key preview. - private final HashMap mShowingKeyPreviewTextViews = CollectionUtils.newHashMap(); private final KeyPreviewDrawParams mKeyPreviewDrawParams; - 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(); + private final KeyPreviewChoreographer mKeyPreviewChoreographer; // More keys keyboard private final Paint mBackgroundDimAlphaPaint = new Paint(); @@ -261,6 +243,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0); mKeyPreviewDrawParams = new KeyPreviewDrawParams(mainKeyboardViewAttr); + mKeyPreviewChoreographer = new KeyPreviewChoreographer(mKeyPreviewDrawParams); + final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId( R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0); mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean( @@ -477,60 +461,13 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack return mKeyPreviewDrawParams.isPopupEnabled(); } - private TextView getKeyPreviewTextView(final Key key) { - TextView previewTextView = mShowingKeyPreviewTextViews.remove(key); - if (previewTextView != null) { - return previewTextView; - } - previewTextView = mFreeKeyPreviewTextViews.poll(); - if (previewTextView != null) { - return previewTextView; - } - final Context context = getContext(); - final int previewLayoutId = mKeyPreviewDrawParams.mLayoutId; - if (previewLayoutId != 0) { - previewTextView = (TextView)LayoutInflater.from(context) - .inflate(previewLayoutId, null); - } else { - previewTextView = new TextView(context); - } - locatePreviewPlacerView(); - mDrawingPreviewPlacerView.addView( - previewTextView, ViewLayoutUtils.newLayoutParam(mDrawingPreviewPlacerView, 0, 0)); - return previewTextView; - } - // Implements {@link DrawingHandler.Callbacks} method. @Override public void dismissAllKeyPreviews() { - for (final Key key : new HashSet(mShowingKeyPreviewTextViews.keySet())) { - dismissKeyPreviewWithoutDelay(key); - } + mKeyPreviewChoreographer.dismissAllKeyPreviews(); PointerTracker.setReleasedKeyGraphicsToAllKeys(); } - // Background state set - private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = { - { // STATE_MIDDLE - EMPTY_STATE_SET, - { R.attr.state_has_morekeys } - }, - { // STATE_LEFT - { R.attr.state_left_edge }, - { R.attr.state_left_edge, R.attr.state_has_morekeys } - }, - { // STATE_RIGHT - { R.attr.state_right_edge }, - { R.attr.state_right_edge, R.attr.state_has_morekeys } - } - }; - private static final int STATE_MIDDLE = 0; - private static final int STATE_LEFT = 1; - private static final int STATE_RIGHT = 2; - 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. @@ -547,185 +484,33 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack return; } - final TextView previewTextView = getKeyPreviewTextView(key); - final KeyDrawParams drawParams = mKeyDrawParams; - previewTextView.setTextColor(drawParams.mPreviewTextColor); - final Drawable background = previewTextView.getBackground(); - final String label = key.getPreviewLabel(); - // What we show as preview should match what we show on a key top in onDraw(). - if (label != null) { - // TODO Should take care of temporaryShiftLabel here. - previewTextView.setCompoundDrawables(null, null, null, null); - previewTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, - key.selectPreviewTextSize(drawParams)); - previewTextView.setTypeface(key.selectPreviewTypeface(drawParams)); - previewTextView.setText(label); - } else { - previewTextView.setCompoundDrawables(null, null, null, - key.getPreviewIcon(keyboard.mIconsSet)); - previewTextView.setText(null); - } - - previewTextView.measure( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - final int keyDrawWidth = key.getDrawWidth(); - final int previewWidth = previewTextView.getMeasuredWidth(); - final int previewHeight = previewParams.mPreviewHeight; - previewParams.setGeometry(previewTextView); + final TextView previewTextView = mKeyPreviewChoreographer.getKeyPreviewTextView( + key, getContext()); + locatePreviewPlacerView(); + mDrawingPreviewPlacerView.addView( + previewTextView, ViewLayoutUtils.newLayoutParam(mDrawingPreviewPlacerView, 0, 0)); getLocationInWindow(mOriginCoords); - // 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. - final int statePosition; - int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2 - + CoordinateUtils.x(mOriginCoords); - if (previewX < 0) { - previewX = 0; - statePosition = STATE_LEFT; - } else if (previewX > getWidth() - previewWidth) { - previewX = getWidth() - previewWidth; - statePosition = STATE_RIGHT; - } else { - statePosition = STATE_MIDDLE; - } - // The key preview is placed vertically above the top edge of the parent key with an - // arbitrary offset. - final int previewY = key.getY() - previewHeight + previewParams.mPreviewOffset - + CoordinateUtils.y(mOriginCoords); - - if (background != null) { - final int hasMoreKeys = (key.getMoreKeys() != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL; - background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[statePosition][hasMoreKeys]); - } - ViewLayoutUtils.placeViewAt( - previewTextView, previewX, previewY, previewWidth, previewHeight); - - 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(mKeyPreviewDrawParams.mZoomInDuration); - 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. - final int zoomOutDuration = Math.min(mKeyPreviewDrawParams.mZoomOutDuration, - mKeyPreviewDrawParams.getLingerTimeout()); - zoomOutAnimation.setDuration(zoomOutDuration); - zoomOutAnimation.setInterpolator(ACCELERATE_INTERPOLATOR); - zoomOutAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(final Animator animation) { - dismissKeyPreviewWithoutDelay(key); - } - }); - return zoomOutAnimation; + mKeyPreviewChoreographer.placeKeyPreview(key, previewTextView, keyboard.mIconsSet, + mKeyDrawParams, getWidth(), mOriginCoords); + mKeyPreviewChoreographer.showKeyPreview(key, previewTextView, isHardwareAccelerated()); } // Implements {@link TimerHandler.Callbacks} method. - // TODO: Take this method out of this class. @Override public 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); - } + mKeyPreviewChoreographer.dismissKeyPreview(key, false /* withAnimation */); // To redraw key top letter. invalidateKey(key); } - // TODO: Take this method out of this class. @Override public void dismissKeyPreview(final Key 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(mKeyPreviewDrawParams.getLingerTimeout(), key); return; } - final Object tag = previewTextView.getTag(); - if (tag instanceof KeyPreviewAnimations) { - final KeyPreviewAnimations animation = (KeyPreviewAnimations)tag; - animation.startZoomOut(); - } + mKeyPreviewChoreographer.dismissKeyPreview(key, true /* withAnimation */); } public void setSlidingKeyInputPreviewEnabled(final boolean enabled) { @@ -1098,7 +883,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } // Don't draw key top letter when key preview is showing. if (FADE_OUT_KEY_TOP_LETTER_WHEN_KEY_IS_PRESSED - && mShowingKeyPreviewTextViews.containsKey(key)) { + && mKeyPreviewChoreographer.isShowingKeyPreview(key)) { // TODO: Fade out animation for the key top letter, and fade in animation for the key // background color when the user presses the key. return; diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java new file mode 100644 index 000000000..c1922b7c4 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.keyboard.internal; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.widget.TextView; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.CoordinateUtils; +import com.android.inputmethod.latin.utils.ViewLayoutUtils; + +import java.util.ArrayDeque; +import java.util.HashMap; +import java.util.HashSet; + +/** + * This class controls pop up key previews. This class decides: + * - what kind of key previews should be shown. + * - where key previews should be placed. + * - how key previews should be shown and dismissed. + */ +public final class KeyPreviewChoreographer { + // Free {@link TextView} pool that can be used for key preview. + private final ArrayDeque mFreeKeyPreviewTextViews = CollectionUtils.newArrayDeque(); + // Map from {@link Key} to {@link TextView} that is currently being displayed as key preview. + private final HashMap mShowingKeyPreviewTextViews = CollectionUtils.newHashMap(); + + private final KeyPreviewDrawParams mParams; + + public KeyPreviewChoreographer(final KeyPreviewDrawParams params) { + mParams = params; + } + + public TextView getKeyPreviewTextView(final Key key, final Context context) { + TextView previewTextView = mShowingKeyPreviewTextViews.remove(key); + if (previewTextView != null) { + return previewTextView; + } + previewTextView = mFreeKeyPreviewTextViews.poll(); + if (previewTextView != null) { + return previewTextView; + } + if (mParams.mLayoutId != 0) { + return (TextView)LayoutInflater.from(context).inflate(mParams.mLayoutId, null); + } + return new TextView(context); + } + + public boolean isShowingKeyPreview(final Key key) { + return mShowingKeyPreviewTextViews.containsKey(key); + } + + public void dismissAllKeyPreviews() { + for (final Key key : new HashSet(mShowingKeyPreviewTextViews.keySet())) { + dismissKeyPreview(key, false /* withAnimation */); + } + } + + public void dismissKeyPreview(final Key key, final boolean withAnimation) { + if (key == null) { + return; + } + final TextView previewTextView = mShowingKeyPreviewTextViews.get(key); + if (previewTextView == null) { + return; + } + final Object tag = previewTextView.getTag(); + if (withAnimation) { + if (tag instanceof KeyPreviewAnimations) { + final KeyPreviewAnimations animation = (KeyPreviewAnimations)tag; + animation.startZoomOut(); + } + return; + } + // Dismiss preview without animation. + if (tag instanceof Animator) { + ((Animator)tag).cancel(); + } + previewTextView.setTag(null); + previewTextView.setVisibility(View.INVISIBLE); + mFreeKeyPreviewTextViews.add(previewTextView); + } + + // Background state set + private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = { + { // STATE_MIDDLE + {}, + { R.attr.state_has_morekeys } + }, + { // STATE_LEFT + { R.attr.state_left_edge }, + { R.attr.state_left_edge, R.attr.state_has_morekeys } + }, + { // STATE_RIGHT + { R.attr.state_right_edge }, + { R.attr.state_right_edge, R.attr.state_has_morekeys } + } + }; + private static final int STATE_MIDDLE = 0; + private static final int STATE_LEFT = 1; + private static final int STATE_RIGHT = 2; + private static final int STATE_NORMAL = 0; + private static final int STATE_HAS_MOREKEYS = 1; + + public void placeKeyPreview(final Key key, final TextView previewTextView, + final KeyboardIconsSet iconsSet, final KeyDrawParams drawParams, + final int keyboardViewWidth, final int[] originCoords) { + previewTextView.setTextColor(drawParams.mPreviewTextColor); + final Drawable background = previewTextView.getBackground(); + final String label = key.getPreviewLabel(); + // What we show as preview should match what we show on a key top in onDraw(). + if (label != null) { + // TODO Should take care of temporaryShiftLabel here. + previewTextView.setCompoundDrawables(null, null, null, null); + previewTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, + key.selectPreviewTextSize(drawParams)); + previewTextView.setTypeface(key.selectPreviewTypeface(drawParams)); + previewTextView.setText(label); + } else { + previewTextView.setCompoundDrawables(null, null, null, key.getPreviewIcon(iconsSet)); + previewTextView.setText(null); + } + + previewTextView.measure( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + mParams.setGeometry(previewTextView); + final int previewWidth = previewTextView.getMeasuredWidth(); + final int previewHeight = mParams.mPreviewHeight; + final int keyDrawWidth = key.getDrawWidth(); + // 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. + final int statePosition; + int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2 + + CoordinateUtils.x(originCoords); + if (previewX < 0) { + previewX = 0; + statePosition = STATE_LEFT; + } else if (previewX > keyboardViewWidth - previewWidth) { + previewX = keyboardViewWidth - previewWidth; + statePosition = STATE_RIGHT; + } else { + statePosition = STATE_MIDDLE; + } + // The key preview is placed vertically above the top edge of the parent key with an + // arbitrary offset. + final int previewY = key.getY() - previewHeight + mParams.mPreviewOffset + + CoordinateUtils.y(originCoords); + + if (background != null) { + final int hasMoreKeys = (key.getMoreKeys() != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL; + background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[statePosition][hasMoreKeys]); + } + ViewLayoutUtils.placeViewAt( + previewTextView, previewX, previewY, previewWidth, previewHeight); + previewTextView.setPivotX(previewWidth / 2.0f); + previewTextView.setPivotY(previewHeight); + } + + public void showKeyPreview(final Key key, final TextView previewTextView, + final boolean withAnimation) { + if (!withAnimation) { + previewTextView.setVisibility(View.VISIBLE); + mShowingKeyPreviewTextViews.put(key, previewTextView); + return; + } + + // Show preview with animation. + 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 these parameters to resources or preferences. + 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(); + + private Animator createZoomInAniation(final Key key, final TextView previewTextView) { + final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat( + previewTextView, View.SCALE_X, KEY_PREVIEW_START_ZOOM_IN_SCALE, + KEY_PREVIEW_END_ZOOM_IN_SCALE); + final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat( + previewTextView, View.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(mParams.mZoomInDuration); + zoomInAnimation.setInterpolator(DECELERATE_INTERPOLATOR); + zoomInAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(final Animator animation) { + showKeyPreview(key, previewTextView, false /* withAnimation */); + } + }); + return zoomInAnimation; + } + + private Animator createZoomOutAnimation(final Key key, final TextView previewTextView) { + final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat( + previewTextView, View.SCALE_X, KEY_PREVIEW_END_ZOOM_OUT_SCALE); + final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat( + previewTextView, View.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. + final int zoomOutDuration = Math.min(mParams.mZoomOutDuration, mParams.getLingerTimeout()); + zoomOutAnimation.setDuration(zoomOutDuration); + zoomOutAnimation.setInterpolator(ACCELERATE_INTERPOLATOR); + zoomOutAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(final Animator animation) { + dismissKeyPreview(key, true /* withAnimation */); + } + }); + return zoomOutAnimation; + } + + 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(); + } + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java index d1899af28..ff493b198 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java @@ -26,6 +26,7 @@ public final class KeyPreviewDrawParams { public final int mLayoutId; public final int mPreviewOffset; public final int mPreviewHeight; + // TODO: Move those parameters to preferences. public final int mZoomInDuration; public final int mZoomOutDuration; private int mLingerTimeout;