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() {