Merge "Some readability improvement"
diff --git a/java/res/anim/alt_code_key_while_typing_fadein.xml b/java/res/anim/alt_code_key_while_typing_fadein.xml
new file mode 100644
index 0000000..3f5fd5d
--- /dev/null
+++ b/java/res/anim/alt_code_key_while_typing_fadein.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, 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.
+*/
+-->
+
+<animator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:valueType="intType"
+    android:duration="100"
+    android:valueFrom="128"
+    android:valueTo="255" />
diff --git a/java/res/anim/alt_code_key_while_typing_fadeout.xml b/java/res/anim/alt_code_key_while_typing_fadeout.xml
new file mode 100644
index 0000000..ed4a6f2
--- /dev/null
+++ b/java/res/anim/alt_code_key_while_typing_fadeout.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, 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.
+*/
+-->
+
+<animator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:valueType="intType"
+    android:duration="70"
+    android:valueFrom="255"
+    android:valueTo="128" />
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml
index 078c63d..b1f7658 100644
--- a/java/res/values-af/strings.xml
+++ b/java/res/values-af/strings.xml
@@ -37,12 +37,9 @@
     <string name="misc_category" msgid="6894192814868233453">"Ander opsies"</string>
     <string name="advanced_settings" msgid="362895144495591463">"Gevorderde instellings"</string>
     <string name="advanced_settings_summary" msgid="4487980456152830271">"Opsies vir kundiges"</string>
-    <!-- no translation found for include_other_imes_in_language_switch_list (4533689960308565519) -->
-    <skip />
-    <!-- no translation found for include_other_imes_in_language_switch_list_summary (840637129103317635) -->
-    <skip />
-    <!-- no translation found for suppress_language_switch_key (8003788410354806368) -->
-    <skip />
+    <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Skakel oor na die ander invoermetodes"</string>
+    <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Taal-skakelsleutel dek ook ander invoermetodes"</string>
+    <string name="suppress_language_switch_key" msgid="8003788410354806368">"Onderdruk taalwissel-sleutel"</string>
     <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Sleutelopspringer-wagperiode"</string>
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Geen wagperiode nie"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Verstek"</string>
diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml
index 0375f66..bb0c493 100644
--- a/java/res/values-am/strings.xml
+++ b/java/res/values-am/strings.xml
@@ -37,12 +37,9 @@
     <string name="misc_category" msgid="6894192814868233453">"ሌሎች አማራጮች"</string>
     <string name="advanced_settings" msgid="362895144495591463">"የላቁ ቅንብሮች"</string>
     <string name="advanced_settings_summary" msgid="4487980456152830271">"ለብቁ ተጠቃሚዎች አማራጮች"</string>
-    <!-- no translation found for include_other_imes_in_language_switch_list (4533689960308565519) -->
-    <skip />
-    <!-- no translation found for include_other_imes_in_language_switch_list_summary (840637129103317635) -->
-    <skip />
-    <!-- no translation found for suppress_language_switch_key (8003788410354806368) -->
-    <skip />
+    <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"ወደ ሌሎች የግቤት ስልቶች ቀይር"</string>
+    <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"የቋንቋ መቀየሪያ ቁልፍ ሌሎች የግቤት ስልቶችንም ይሸፍናል"</string>
+    <string name="suppress_language_switch_key" msgid="8003788410354806368">"የቋንቋ መቀየሪያ ቁልፍ አፍን"</string>
     <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"የቁልፍ ብቅ ባይ መዘግየትን ያስወገዳል"</string>
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"የዘገየ የለም"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ነባሪ"</string>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
index b68feda..dabbd4d 100644
--- a/java/res/values-iw/strings.xml
+++ b/java/res/values-iw/strings.xml
@@ -37,12 +37,9 @@
     <string name="misc_category" msgid="6894192814868233453">"אפשרויות אחרות"</string>
     <string name="advanced_settings" msgid="362895144495591463">"הגדרות מתקדמות"</string>
     <string name="advanced_settings_summary" msgid="4487980456152830271">"אפשרויות למומחים"</string>
-    <!-- no translation found for include_other_imes_in_language_switch_list (4533689960308565519) -->
-    <skip />
-    <!-- no translation found for include_other_imes_in_language_switch_list_summary (840637129103317635) -->
-    <skip />
-    <!-- no translation found for suppress_language_switch_key (8003788410354806368) -->
-    <skip />
+    <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"עבור לשיטות קלט אחרות"</string>
+    <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"מתג החלפת השפה מכסה גם שיטות קלט אחרות"</string>
+    <string name="suppress_language_switch_key" msgid="8003788410354806368">"הסתר את מתג החלפת השפה"</string>
     <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"עיכוב סגירת חלון קופץ של מקש"</string>
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"ללא עיכוב"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ברירת מחדל"</string>
diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml
index cb9293a..3646a85 100644
--- a/java/res/values-zu/strings.xml
+++ b/java/res/values-zu/strings.xml
@@ -37,12 +37,9 @@
     <string name="misc_category" msgid="6894192814868233453">"Okunye okukhethwa kukho"</string>
     <string name="advanced_settings" msgid="362895144495591463">"Izilungiselelo ezithuthukisiwe"</string>
     <string name="advanced_settings_summary" msgid="4487980456152830271">"Izinketho zezingcwenti"</string>
-    <!-- no translation found for include_other_imes_in_language_switch_list (4533689960308565519) -->
-    <skip />
-    <!-- no translation found for include_other_imes_in_language_switch_list_summary (840637129103317635) -->
-    <skip />
-    <!-- no translation found for suppress_language_switch_key (8003788410354806368) -->
-    <skip />
+    <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Shintshela kwezinye izindlela zokungena"</string>
+    <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Ukhiye wokushintsha ilimi ubandakanya ezinye izindlela zokungenayo"</string>
+    <string name="suppress_language_switch_key" msgid="8003788410354806368">"Ukhiye wokushintshela wokuvimbela ulimi"</string>
     <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Ukuvela kokhiye cashisa ukulibazisa"</string>
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Cha ukulibazisa"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Okuzenzakalelayo"</string>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index e56778a..e619ad0 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -134,6 +134,9 @@
         <attr name="spacebarTextShadowColor" format="color" />
         <!-- Fadeout animator for spacebar language label. -->
         <attr name="languageOnSpacebarFadeoutAnimator" format="reference" />
+        <!-- Fadeout and fadein animator for altCodeWhileTyping keys. -->
+        <attr name="altCodeKeyWhileTypingFadeoutAnimator" format="reference" />
+        <attr name="altCodeKeyWhileTypingFadeinAnimator" format="reference" />
         <!-- Key detection hysteresis distance. -->
         <attr name="keyHysteresisDistance" format="dimension" />
         <!-- Touch noise threshold time in millisecond -->
@@ -153,7 +156,7 @@
         <!-- Long press timeout of space key in millisecond. -->
         <attr name="longPressSpaceKeyTimeout" format="integer" />
         <!-- Ignore special key timeout while typing in millisecond. -->
-        <attr name="ignoreSpecialKeyTimeout" format="integer" />
+        <attr name="ignoreAltCodeKeyTimeout" format="integer" />
         <!-- More keys keyboard will shown at touched point. -->
         <attr name="showMoreKeysKeyboardAtTouchedPoint" format="boolean" />
     </declare-styleable>
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index a02b84f..c51800f 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -65,7 +65,7 @@
     <!-- Long pressing space will invoke IME switcher if > 0, never invoke IME switcher if == 0 -->
     <integer name="config_long_press_space_key_timeout">
             @integer/config_long_press_key_timeout</integer>
-    <integer name="config_ignore_special_key_timeout">700</integer>
+    <integer name="config_ignore_alt_code_key_timeout">700</integer>
     <!-- Showing more keys keyboard, just above the touched point if true, aligned to the key if
          false -->
     <bool name="config_show_more_keys_keyboard_at_touched_point">false</bool>
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index 741ad99..7d8b7dd 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -76,9 +76,11 @@
         <item name="longPressKeyTimeout">@integer/config_long_press_key_timeout</item>
         <item name="longPressShiftKeyTimeout">@integer/config_long_press_shift_key_timeout</item>
         <item name="longPressSpaceKeyTimeout">@integer/config_long_press_space_key_timeout</item>
-        <item name="ignoreSpecialKeyTimeout">@integer/config_ignore_special_key_timeout</item>
+        <item name="ignoreAltCodeKeyTimeout">@integer/config_ignore_alt_code_key_timeout</item>
         <item name="showMoreKeysKeyboardAtTouchedPoint">@bool/config_show_more_keys_keyboard_at_touched_point</item>
         <item name="languageOnSpacebarFadeoutAnimator">@anim/language_on_spacebar_fadeout</item>
+        <item name="altCodeKeyWhileTypingFadeoutAnimator">@anim/alt_code_key_while_typing_fadeout</item>
+        <item name="altCodeKeyWhileTypingFadeinAnimator">@anim/alt_code_key_while_typing_fadein</item>
     </style>
     <style
         name="LatinKeyboardView"
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 44c6a49..cdf07ed 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -41,6 +41,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 
@@ -225,7 +226,7 @@
         public int GRID_WIDTH;
         public int GRID_HEIGHT;
 
-        public final ArrayList<Key> mKeys = new ArrayList<Key>();
+        public final HashSet<Key> mKeys = new HashSet<Key>();
         public final ArrayList<Key> mShiftKeys = new ArrayList<Key>();
         public final ArrayList<Key> mAltCodeKeysWhileTyping = new ArrayList<Key>();
         public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 4c65522..847174c 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -95,6 +95,8 @@
     // The maximum key label width in the proportion to the key width.
     private static final float MAX_LABEL_RATIO = 0.90f;
 
+    private final static int ALPHA_OPAQUE = 255;
+
     // Main keyboard
     private Keyboard mKeyboard;
     private final KeyDrawParams mKeyDrawParams;
@@ -201,6 +203,7 @@
         public int mKeyHintLetterSize;
         public int mKeyShiftedLetterHintSize;
         public int mKeyHintLabelSize;
+        public int mAnimAlpha;
 
         public KeyDrawParams(TypedArray a) {
             mKeyBackground = a.getDrawable(R.styleable.KeyboardView_keyBackground);
@@ -256,6 +259,12 @@
             mKeyShiftedLetterHintSize = (int)(keyHeight * mKeyShiftedLetterHintRatio);
             mKeyHintLabelSize = (int)(keyHeight * mKeyHintLabelRatio);
         }
+
+        public void brendAlpha(Paint paint) {
+            final int color = paint.getColor();
+            paint.setARGB((paint.getAlpha() * mAnimAlpha) / ALPHA_OPAQUE,
+                    Color.red(color), Color.green(color), Color.blue(color));
+        }
     }
 
     /* package */ static class KeyPreviewDrawParams {
@@ -343,7 +352,6 @@
 
         mPaint.setAntiAlias(true);
         mPaint.setTextAlign(Align.CENTER);
-        mPaint.setAlpha(255);
     }
 
     // Read fraction value in TypedArray as float.
@@ -492,6 +500,7 @@
         final int keyDrawY = key.mY + getPaddingTop();
         canvas.translate(keyDrawX, keyDrawY);
 
+        params.mAnimAlpha = ALPHA_OPAQUE;
         if (!key.isSpacer()) {
             onDrawKeyBackground(key, canvas, params);
         }
@@ -535,6 +544,9 @@
 
         // Draw key label.
         final Drawable icon = key.getIcon(mKeyboard.mIconsSet);
+        if (icon != null) {
+            icon.setAlpha(params.mAnimAlpha);
+        }
         float positionX = centerX;
         if (key.mLabel != null) {
             final String label = key.mLabel;
@@ -589,6 +601,7 @@
                 // Make label invisible
                 paint.setColor(Color.TRANSPARENT);
             }
+            params.brendAlpha(paint);
             canvas.drawText(label, 0, label.length(), positionX, baseline, paint);
             // Turn off drop shadow and reset x-scale.
             paint.setShadowLayer(0, 0, 0, 0);
@@ -633,6 +646,7 @@
                 hintSize = params.mKeyHintLetterSize;
             }
             paint.setColor(hintColor);
+            params.brendAlpha(paint);
             paint.setTextSize(hintSize);
             final float hintX, hintY;
             if (key.hasHintLabel()) {
@@ -701,6 +715,7 @@
 
         paint.setTextSize(params.mKeyHintLetterSize);
         paint.setColor(params.mKeyHintLabelColor);
+        params.brendAlpha(paint);
         paint.setTextAlign(Align.CENTER);
         final float hintX = keyWidth - params.mKeyHintLetterPadding
                 - getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2;
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index e320330..97f4d07 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -98,6 +98,11 @@
     private final Drawable mAutoCorrectionSpacebarLedIcon;
     private static final int SPACE_LED_LENGTH_PERCENT = 80;
 
+    // Stuff to draw altCodeWhileTyping keys.
+    private ValueAnimator mAltCodeKeyWhileTypingFadeoutAnimator;
+    private ValueAnimator mAltCodeKeyWhileTypingFadeinAnimator;
+    private int mAltCodeKeyWhileTypingAnimAlpha;
+
     // More keys keyboard
     private PopupWindow mMoreKeysWindow;
     private MoreKeysPanel mMoreKeysPanel;
@@ -122,7 +127,7 @@
         private static final int MSG_REPEAT_KEY = 1;
         private static final int MSG_LONGPRESS_KEY = 2;
         private static final int MSG_DOUBLE_TAP = 3;
-        private static final int MSG_KEY_TYPED = 4;
+        private static final int MSG_TYPING_STATE_EXPIRED = 4;
 
         private final KeyTimerParams mParams;
         private boolean mInKeyRepeat;
@@ -148,6 +153,18 @@
                     KeyboardSwitcher.getInstance().onLongPressTimeout(msg.arg1);
                 }
                 break;
+            case MSG_TYPING_STATE_EXPIRED:
+                final ValueAnimator fadeout = keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator;
+                if (fadeout != null && fadeout.isStarted()) {
+                    fadeout.cancel();
+                }
+                // TODO: Start the fade in animation with an initial value that is the same as the
+                // final value when the above fade out animation gets cancelled.
+                final ValueAnimator fadein = keyboardView.mAltCodeKeyWhileTypingFadeinAnimator;
+                if (fadein != null && !fadein.isStarted()) {
+                    fadein.start();
+                }
+                break;
             }
         }
 
@@ -222,14 +239,30 @@
         }
 
         @Override
-        public void startKeyTypedTimer() {
-            removeMessages(MSG_KEY_TYPED);
-            sendMessageDelayed(obtainMessage(MSG_KEY_TYPED), mParams.mIgnoreSpecialKeyTimeout);
+        public void startTypingStateTimer() {
+            final boolean isTyping = isTypingState();
+            removeMessages(MSG_TYPING_STATE_EXPIRED);
+            sendMessageDelayed(
+                    obtainMessage(MSG_TYPING_STATE_EXPIRED), mParams.mIgnoreAltCodeKeyTimeout);
+            final LatinKeyboardView keyboardView = getOuterInstance();
+            if (isTyping) {
+                return;
+            }
+            final ValueAnimator fadein = keyboardView.mAltCodeKeyWhileTypingFadeinAnimator;
+            if (fadein != null && fadein.isStarted()) {
+                fadein.cancel();
+            }
+            // TODO: Start the fade out animation with an initial value that is the same as the
+            // final value when the above fade in animation gets cancelled.
+            final ValueAnimator fadeout = keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator;
+            if (fadeout != null && !fadeout.isStarted()) {
+                fadeout.start();
+            }
         }
 
         @Override
-        public boolean isTyping() {
-            return hasMessages(MSG_KEY_TYPED);
+        public boolean isTypingState() {
+            return hasMessages(MSG_TYPING_STATE_EXPIRED);
         }
 
         @Override
@@ -288,7 +321,7 @@
         public final int mLongPressKeyTimeout;
         public final int mLongPressShiftKeyTimeout;
         public final int mLongPressSpaceKeyTimeout;
-        public final int mIgnoreSpecialKeyTimeout;
+        public final int mIgnoreAltCodeKeyTimeout;
 
         KeyTimerParams() {
             mKeyRepeatStartTimeout = 0;
@@ -296,7 +329,7 @@
             mLongPressKeyTimeout = 0;
             mLongPressShiftKeyTimeout = 0;
             mLongPressSpaceKeyTimeout = 0;
-            mIgnoreSpecialKeyTimeout = 0;
+            mIgnoreAltCodeKeyTimeout = 0;
         }
 
         public KeyTimerParams(TypedArray latinKeyboardViewAttr) {
@@ -310,8 +343,8 @@
                     R.styleable.LatinKeyboardView_longPressShiftKeyTimeout, 0);
             mLongPressSpaceKeyTimeout = latinKeyboardViewAttr.getInt(
                     R.styleable.LatinKeyboardView_longPressSpaceKeyTimeout, 0);
-            mIgnoreSpecialKeyTimeout = latinKeyboardViewAttr.getInt(
-                    R.styleable.LatinKeyboardView_ignoreSpecialKeyTimeout, 0);
+            mIgnoreAltCodeKeyTimeout = latinKeyboardViewAttr.getInt(
+                    R.styleable.LatinKeyboardView_ignoreAltCodeKeyTimeout, 0);
         }
     }
 
@@ -342,6 +375,10 @@
                 R.styleable.LatinKeyboardView_spacebarTextShadowColor, 0);
         final int languageOnSpacebarFadeoutAnimatorResId = a.getResourceId(
                 R.styleable.LatinKeyboardView_languageOnSpacebarFadeoutAnimator, 0);
+        final int altCodeKeyWhileTypingFadeoutAnimatorResId = a.getResourceId(
+                R.styleable.LatinKeyboardView_altCodeKeyWhileTypingFadeoutAnimator, 0);
+        final int altCodeKeyWhileTypingFadeinAnimatorResId = a.getResourceId(
+                R.styleable.LatinKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0);
 
         final KeyTimerParams keyTimerParams = new KeyTimerParams(a);
         mPointerTrackerParams = new PointerTrackerParams(a);
@@ -357,7 +394,7 @@
 
         PointerTracker.setParameters(mPointerTrackerParams);
 
-        ValueAnimator animator = loadValueAnimator(context, languageOnSpacebarFadeoutAnimatorResId);
+        final ValueAnimator animator = loadValueAnimator(languageOnSpacebarFadeoutAnimatorResId);
         if (animator != null) {
             animator.addUpdateListener(new AnimatorUpdateListener() {
                 @Override
@@ -377,11 +414,47 @@
             animator.end();
         }
         mLanguageOnSpacebarFadeoutAnimator = animator;
+
+        final ValueAnimator fadeout = loadValueAnimator(altCodeKeyWhileTypingFadeoutAnimatorResId);
+        if (fadeout != null) {
+            fadeout.addUpdateListener(new AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    mAltCodeKeyWhileTypingAnimAlpha = (Integer)animation.getAnimatedValue();
+                    updateAltCodeKeyWhileTyping();
+                }
+            });
+            fadeout.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator a) {
+                    final ValueAnimator valueAnimator = (ValueAnimator)a;
+                }
+            });
+        }
+        mAltCodeKeyWhileTypingFadeoutAnimator = fadeout;
+
+        final ValueAnimator fadein = loadValueAnimator(altCodeKeyWhileTypingFadeinAnimatorResId);
+        if (fadein != null) {
+            fadein.addUpdateListener(new AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    mAltCodeKeyWhileTypingAnimAlpha = (Integer)animation.getAnimatedValue();
+                    updateAltCodeKeyWhileTyping();
+                }
+            });
+            fadein.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator a) {
+                    final ValueAnimator valueAnimator = (ValueAnimator)a;
+                }
+            });
+        }
+        mAltCodeKeyWhileTypingFadeinAnimator = fadein;
     }
 
-    private static ValueAnimator loadValueAnimator(Context context, int resId) {
+    private ValueAnimator loadValueAnimator(int resId) {
         if (resId == 0) return null;
-        return (ValueAnimator)AnimatorInflater.loadAnimator(context, resId);
+        return (ValueAnimator)AnimatorInflater.loadAnimator(getContext(), resId);
     }
 
     public void setKeyboardActionListener(KeyboardActionListener listener) {
@@ -437,6 +510,8 @@
         final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
         mSpacebarTextSize = keyHeight * mSpacebarTextRatio;
         mSpacebarLocale = keyboard.mId.mLocale;
+        mSpacebarTextAlpha = ALPHA_OPAQUE;
+        mAltCodeKeyWhileTypingAnimAlpha = ALPHA_OPAQUE;
     }
 
     /**
@@ -797,6 +872,14 @@
         invalidateKey(shortcutKey);
     }
 
+    private void updateAltCodeKeyWhileTyping() {
+        final Keyboard keyboard = getKeyboard();
+        if (keyboard == null) return;
+        for (final Key key : keyboard.mAltCodeKeysWhileTyping) {
+            invalidateKey(key);
+        }
+    }
+
     public void startDisplayLanguageOnSpacebar(boolean subtypeChanged,
             boolean needsToDisplayLanguage) {
         final ValueAnimator animator = mLanguageOnSpacebarFadeoutAnimator;
@@ -825,6 +908,9 @@
 
     @Override
     protected void onDrawKeyTopVisuals(Key key, Canvas canvas, Paint paint, KeyDrawParams params) {
+        if (key.altCodeWhileTyping() && key.isEnabled()) {
+            params.mAnimAlpha = mAltCodeKeyWhileTypingAnimAlpha;
+        }
         if (key.mCode == Keyboard.CODE_SPACE) {
             drawSpacebar(key, canvas, paint);
 
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 607b33b..ed88971 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -68,8 +68,8 @@
     }
 
     public interface TimerProxy {
-        public void startKeyTypedTimer();
-        public boolean isTyping();
+        public void startTypingStateTimer();
+        public boolean isTypingState();
         public void startKeyRepeatTimer(PointerTracker tracker);
         public void startLongPressTimer(PointerTracker tracker);
         public void startLongPressTimer(int code);
@@ -81,9 +81,9 @@
 
         public static class Adapter implements TimerProxy {
             @Override
-            public void startKeyTypedTimer() {}
+            public void startTypingStateTimer() {}
             @Override
-            public boolean isTyping() { return false; }
+            public boolean isTypingState() { return false; }
             @Override
             public void startKeyRepeatTimer(PointerTracker tracker) {}
             @Override
@@ -251,25 +251,26 @@
     // primaryCode is different from {@link Key#mCode}.
     private void callListenerOnCodeInput(Key key, int primaryCode, int x, int y) {
         final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
-        final boolean alterCode = key.altCodeWhileTyping() && mTimerProxy.isTyping();
-        final int code = alterCode ? key.mAltCode : primaryCode;
+        final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState();
+        final int code = altersCode ? key.mAltCode : primaryCode;
         if (DEBUG_LISTENER) {
             Log.d(TAG, "onCodeInput: " + Keyboard.printableCode(code) + " text=" + key.mOutputText
                     + " x=" + x + " y=" + y
-                    + " ignoreModifier=" + ignoreModifierKey + " alterCode=" + alterCode
+                    + " ignoreModifier=" + ignoreModifierKey + " altersCode=" + altersCode
                     + " enabled=" + key.isEnabled());
         }
         if (ignoreModifierKey) {
             return;
         }
-        if (key.isEnabled()) {
+        // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state.
+        if (key.isEnabled() || altersCode) {
             if (code == Keyboard.CODE_OUTPUT_TEXT) {
                 mListener.onTextInput(key.mOutputText);
             } else if (code != Keyboard.CODE_UNSPECIFIED) {
                 mListener.onCodeInput(code, x, y);
             }
             if (!key.altCodeWhileTyping() && !key.isModifier()) {
-                mTimerProxy.startKeyTypedTimer();
+                mTimerProxy.startTypingStateTimer();
             }
         }
     }
@@ -322,10 +323,11 @@
 
     private void setReleasedKeyGraphics(Key key) {
         mDrawingProxy.dismissKeyPreview(this);
-        if (key == null || !key.isEnabled()) {
+        if (key == null) {
             return;
         }
 
+        // Even if the key is disabled, update the key release graphics just in case.
         updateReleaseKeyGraphics(key);
 
         if (key.isShift()) {
@@ -351,7 +353,14 @@
     }
 
     private void setPressedKeyGraphics(Key key) {
-        if (key == null || !key.isEnabled()) {
+        if (key == null) {
+            return;
+        }
+
+        // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state.
+        final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState();
+        final boolean needsToUpdateGraphics = key.isEnabled() || altersCode;
+        if (!needsToUpdateGraphics) {
             return;
         }
 
@@ -368,7 +377,7 @@
             }
         }
 
-        if (key.altCodeWhileTyping() && mTimerProxy.isTyping()) {
+        if (key.altCodeWhileTyping() && mTimerProxy.isTypingState()) {
             final int altCode = key.mAltCode;
             final Key altKey = mKeyboard.getKey(altCode);
             if (altKey != null) {
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index e2a4830..61d75e2 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -124,40 +124,40 @@
         final float[] sweetSpotCenterXs;
         final float[] sweetSpotCenterYs;
         final float[] sweetSpotRadii;
-        final boolean calculateSweetSpotParams;
+
+        for (int i = 0; i < keyCount; ++i) {
+            final Key key = keys[i];
+            keyXCoordinates[i] = key.mX;
+            keyYCoordinates[i] = key.mY;
+            keyWidths[i] = key.mWidth;
+            keyHeights[i] = key.mHeight;
+            keyCharCodes[i] = key.mCode;
+        }
+
         if (touchPositionCorrection != null && touchPositionCorrection.isValid()) {
             sweetSpotCenterXs = new float[keyCount];
             sweetSpotCenterYs = new float[keyCount];
             sweetSpotRadii = new float[keyCount];
-            calculateSweetSpotParams = true;
             for (int i = 0; i < keyCount; i++) {
                 final Key key = keys[i];
-                keyXCoordinates[i] = key.mX;
-                keyYCoordinates[i] = key.mY;
-                keyWidths[i] = key.mWidth;
-                keyHeights[i] = key.mHeight;
-                keyCharCodes[i] = key.mCode;
-                if (calculateSweetSpotParams) {
-                    final Rect hitBox = key.mHitBox;
-                    final int row = hitBox.top / mKeyHeight;
-                    if (row < touchPositionCorrection.mRadii.length) {
-                        final float hitBoxCenterX = (hitBox.left + hitBox.right) * 0.5f;
-                        final float hitBoxCenterY = (hitBox.top + hitBox.bottom) * 0.5f;
-                        final float hitBoxWidth = hitBox.right - hitBox.left;
-                        final float hitBoxHeight = hitBox.bottom - hitBox.top;
-                        final float x = touchPositionCorrection.mXs[row];
-                        final float y = touchPositionCorrection.mYs[row];
-                        final float radius = touchPositionCorrection.mRadii[row];
-                        sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth;
-                        sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight;
-                        sweetSpotRadii[i] = radius * (float) Math.sqrt(
-                                hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight);
-                    }
+                final Rect hitBox = key.mHitBox;
+                final int row = hitBox.top / mKeyHeight;
+                if (row < touchPositionCorrection.mRadii.length) {
+                    final float hitBoxCenterX = (hitBox.left + hitBox.right) * 0.5f;
+                    final float hitBoxCenterY = (hitBox.top + hitBox.bottom) * 0.5f;
+                    final float hitBoxWidth = hitBox.right - hitBox.left;
+                    final float hitBoxHeight = hitBox.bottom - hitBox.top;
+                    final float x = touchPositionCorrection.mXs[row];
+                    final float y = touchPositionCorrection.mYs[row];
+                    final float radius = touchPositionCorrection.mRadii[row];
+                    sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth;
+                    sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight;
+                    sweetSpotRadii[i] = radius * (float) Math.sqrt(
+                            hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight);
                 }
             }
         } else {
             sweetSpotCenterXs = sweetSpotCenterYs = sweetSpotRadii = null;
-            calculateSweetSpotParams = false;
         }
 
         mNativeProximityInfo = setProximityInfoNative(mLocaleStr, MAX_PROXIMITY_CHARS_SIZE,
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 201e0f4..6b231f8 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -16,9 +16,11 @@
 
 package com.android.inputmethod.latin;
 
+import android.text.TextUtils;
 import android.view.inputmethod.CompletionInfo;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -71,7 +73,9 @@
         return "SuggestedWords:"
                 + " mTypedWordValid=" + mTypedWordValid
                 + " mHasAutoCorrectionCandidate=" + mHasAutoCorrectionCandidate
-                + " mIsPunctuationSuggestions=" + mIsPunctuationSuggestions;
+                + " mAllowsToBeAutoCorrected=" + mAllowsToBeAutoCorrected
+                + " mIsPunctuationSuggestions=" + mIsPunctuationSuggestions
+                + " words=" + Arrays.toString(mSuggestedWordInfoList.toArray());
     }
 
     public static ArrayList<SuggestedWordInfo> getFromCharSequenceList(
@@ -141,5 +145,14 @@
         public boolean isObsoleteSuggestedWord () {
             return mPreviousSuggestedWord;
         }
+
+        @Override
+        public String toString() {
+            if (TextUtils.isEmpty(mDebugString)) {
+                return mWord.toString();
+            } else {
+                return mWord.toString() + " (" + mDebugString.toString() + ")";
+            }
+        }
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 3324a37..5f6be68 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -143,7 +143,7 @@
             codes = keyDetector.newCodeArray();
             keyDetector.getKeyAndNearbyCodes(x, y, codes);
             keyX = keyDetector.getTouchX(x);
-            keyY = keyDetector.getTouchX(y);
+            keyY = keyDetector.getTouchY(y);
         }
         add(primaryCode, codes, keyX, keyY);
     }