diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index 635b216c8a3b7bd06ea503ac4f6cfc499cd895fe..dc4a4549a95a80a8f9c11da3d1a76d911c3d55d1 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -40,7 +40,7 @@
     <integer name="config_delay_update_suggestions">100</integer>
     <integer name="config_delay_update_old_suggestions">300</integer>
     <integer name="config_delay_update_shift_state">100</integer>
-    <integer name="config_duration_of_fadeout_language_on_spacebar">50</integer>
+    <integer name="config_duration_of_fadeout_language_on_spacebar">200</integer>
     <integer name="config_final_fadeout_percentage_of_language_on_spacebar">50</integer>
     <integer name="config_more_keys_keyboard_fadein_anim_time">0</integer>
     <integer name="config_more_keys_keyboard_fadeout_anim_time">100</integer>
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 599adf21b4f4b741f356a638ef2b5612411adf45..cd80b9087b413d66d58b7659a16f78ff985e8033 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -179,15 +179,12 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions {
                 SettingsValues.isKeyPreviewPopupEnabled(mPrefs, mResources),
                 SettingsValues.getKeyPreviewPopupDismissDelay(mPrefs, mResources));
         mKeyboardView.updateAutoCorrectionState(mIsAutoCorrectionActive);
-        // If the cached keyboard had been switched to another keyboard while the language was
-        // displayed on its spacebar, it might have had arbitrary text fade factor. In such
-        // case, we should reset the text fade factor. It is also applicable to shortcut key.
-        mKeyboardView.updateSpacebar(0.0f,
-                mSubtypeSwitcher.needsToDisplayLanguage(keyboard.mId.mLocale));
         mKeyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady());
+        final boolean needsToDisplayLanguage = mSubtypeSwitcher.needsToDisplayLanguage(
+                keyboard.mId.mLocale);
         final boolean localeChanged = (oldKeyboard == null)
                 || !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
-        mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
+        mKeyboardView.startDisplayLanguageOnSpacebar(localeChanged, needsToDisplayLanguage);
     }
 
     public Keyboard getKeyboard() {
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 0a0307500405e026303bfa845af783cdb85eb4b6..54560eeec6e6393a72e89d64f6152ec8ff1b7fa2 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -16,8 +16,10 @@
 
 package com.android.inputmethod.keyboard;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -75,6 +77,9 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
     private Key mSpaceKey;
     private Drawable mSpaceIcon;
     // Stuff to draw language name on spacebar.
+    private ValueAnimator mLanguageOnSpacebarAnimator;
+    private float mFinalFadeoutFactorOfLanguageOnSpacebar;
+    private int mDelayBeforeFadeoutLanguageOnSpacebar;
     private boolean mNeedsToDisplayLanguage;
     private Locale mSpacebarLocale;
     private float mSpacebarTextFadeFactor = 0.0f;
@@ -347,6 +352,26 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
         a.recycle();
 
         PointerTracker.setParameters(mPointerTrackerParams);
+
+        // TODO: These resources should be attributes of LatinKeyboardView.
+        final Resources res = getResources();
+        mFinalFadeoutFactorOfLanguageOnSpacebar = res.getInteger(
+                R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f;
+        mDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger(
+                R.integer.config_delay_before_fadeout_language_on_spacebar);
+        final int durationOfFadeoutLanguageOnSpacebar = res.getInteger(
+                R.integer.config_duration_of_fadeout_language_on_spacebar);
+        mLanguageOnSpacebarAnimator = ValueAnimator.ofFloat(
+                1.0f, mFinalFadeoutFactorOfLanguageOnSpacebar);
+        mLanguageOnSpacebarAnimator.setStartDelay(mDelayBeforeFadeoutLanguageOnSpacebar);
+        mLanguageOnSpacebarAnimator.setDuration(durationOfFadeoutLanguageOnSpacebar);
+        mLanguageOnSpacebarAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                mSpacebarTextFadeFactor = (Float)animation.getAnimatedValue();
+                invalidateKey(mSpaceKey);
+            }
+        });
     }
 
     public void setKeyboardActionListener(KeyboardActionListener listener) {
@@ -762,9 +787,23 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
         invalidateKey(shortcutKey);
     }
 
-    public void updateSpacebar(float fadeFactor, boolean needsToDisplayLanguage) {
-        mSpacebarTextFadeFactor = fadeFactor;
+    public void startDisplayLanguageOnSpacebar(boolean localeChanged,
+            boolean needsToDisplayLanguage) {
+        mLanguageOnSpacebarAnimator.cancel();
         mNeedsToDisplayLanguage = needsToDisplayLanguage;
+        if (mDelayBeforeFadeoutLanguageOnSpacebar == 0) {
+            // The language is never displayed when the delay is zero.
+            mSpacebarTextFadeFactor = 0.0f;
+        } else if (localeChanged || mDelayBeforeFadeoutLanguageOnSpacebar < 0) {
+            // The language is always displayed when the delay is negative.
+            mSpacebarTextFadeFactor = 1.0f;
+        } else {
+            mSpacebarTextFadeFactor = mFinalFadeoutFactorOfLanguageOnSpacebar;
+        }
+        if (localeChanged && mDelayBeforeFadeoutLanguageOnSpacebar > 0 && mNeedsToDisplayLanguage) {
+            // The fadeout animation will start when the delay is positive.
+            mLanguageOnSpacebarAnimator.start();
+        }
         invalidateKey(mSpaceKey);
     }
 
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index d96b858eb4dd99bfb5ba39229cafbbda1f2bd554..22d1a40259eec1446a60e26869d995caddaee62f 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -241,18 +241,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
     public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> {
         private static final int MSG_UPDATE_SHIFT_STATE = 1;
         private static final int MSG_VOICE_RESULTS = 2;
-        private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 3;
-        private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 4;
-        private static final int MSG_SPACE_TYPED = 5;
-        private static final int MSG_SET_BIGRAM_PREDICTIONS = 6;
-        private static final int MSG_PENDING_IMS_CALLBACK = 7;
-        private static final int MSG_UPDATE_SUGGESTIONS = 8;
-
-        private int mDelayBeforeFadeoutLanguageOnSpacebar;
+        private static final int MSG_SPACE_TYPED = 4;
+        private static final int MSG_SET_BIGRAM_PREDICTIONS = 5;
+        private static final int MSG_PENDING_IMS_CALLBACK = 6;
+        private static final int MSG_UPDATE_SUGGESTIONS = 7;
+
         private int mDelayUpdateSuggestions;
         private int mDelayUpdateShiftState;
-        private int mDurationOfFadeoutLanguageOnSpacebar;
-        private float mFinalFadeoutFactorOfLanguageOnSpacebar;
         private long mDoubleSpacesTurnIntoPeriodTimeout;
 
         public UIHandler(LatinIME outerInstance) {
@@ -261,16 +256,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
 
         public void onCreate() {
             final Resources res = getOuterInstance().getResources();
-            mDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger(
-                    R.integer.config_delay_before_fadeout_language_on_spacebar);
             mDelayUpdateSuggestions =
                     res.getInteger(R.integer.config_delay_update_suggestions);
             mDelayUpdateShiftState =
                     res.getInteger(R.integer.config_delay_update_shift_state);
-            mDurationOfFadeoutLanguageOnSpacebar = res.getInteger(
-                    R.integer.config_duration_of_fadeout_language_on_spacebar);
-            mFinalFadeoutFactorOfLanguageOnSpacebar = res.getInteger(
-                    R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f;
             mDoubleSpacesTurnIntoPeriodTimeout = res.getInteger(
                     R.integer.config_double_spaces_turn_into_period_timeout);
         }
@@ -279,7 +268,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
         public void handleMessage(Message msg) {
             final LatinIME latinIme = getOuterInstance();
             final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher;
-            final LatinKeyboardView inputView = switcher.getKeyboardView();
             switch (msg.what) {
             case MSG_UPDATE_SUGGESTIONS:
                 latinIme.updateSuggestions();
@@ -295,17 +283,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
                 latinIme.mVoiceProxy.handleVoiceResults(latinIme.preferCapitalization()
                         || (keyboard != null && keyboard.isShiftedOrShiftLocked()));
                 break;
-            case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
-                setSpacebarTextFadeFactor(inputView,
-                        (1.0f + mFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
-                        (Keyboard)msg.obj);
-                sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
-                        mDurationOfFadeoutLanguageOnSpacebar);
-                break;
-            case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
-                setSpacebarTextFadeFactor(inputView, mFinalFadeoutFactorOfLanguageOnSpacebar,
-                        (Keyboard)msg.obj);
-                break;
             }
         }
 
@@ -344,41 +321,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
             sendMessage(obtainMessage(MSG_VOICE_RESULTS));
         }
 
-        private static void setSpacebarTextFadeFactor(LatinKeyboardView inputView,
-                float fadeFactor, Keyboard oldKeyboard) {
-            if (inputView == null) return;
-            final Keyboard keyboard = inputView.getKeyboard();
-            if (keyboard == oldKeyboard) {
-                inputView.updateSpacebar(fadeFactor,
-                        SubtypeSwitcher.getInstance().needsToDisplayLanguage(
-                                keyboard.mId.mLocale));
-            }
-        }
-
-        public void startDisplayLanguageOnSpacebar(boolean localeChanged) {
-            final LatinIME latinIme = getOuterInstance();
-            removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR);
-            removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
-            final LatinKeyboardView inputView = latinIme.mKeyboardSwitcher.getKeyboardView();
-            if (inputView != null) {
-                final Keyboard keyboard = latinIme.mKeyboardSwitcher.getKeyboard();
-                // The language is always displayed when the delay is negative.
-                final boolean needsToDisplayLanguage = localeChanged
-                        || mDelayBeforeFadeoutLanguageOnSpacebar < 0;
-                // The language is never displayed when the delay is zero.
-                if (mDelayBeforeFadeoutLanguageOnSpacebar != 0) {
-                    setSpacebarTextFadeFactor(inputView,
-                            needsToDisplayLanguage ? 1.0f : mFinalFadeoutFactorOfLanguageOnSpacebar,
-                                    keyboard);
-                }
-                // The fadeout animation will start when the delay is positive.
-                if (localeChanged && mDelayBeforeFadeoutLanguageOnSpacebar > 0) {
-                    sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
-                            mDelayBeforeFadeoutLanguageOnSpacebar);
-                }
-            }
-        }
-
         public void startDoubleSpacesTimer() {
             removeMessages(MSG_SPACE_TYPED);
             sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED), mDoubleSpacesTurnIntoPeriodTimeout);