Merge "Simplify latin IME settings page." into honeycomb
diff --git a/java/res/drawable-xlarge/btn_center_default.9.png b/java/res/drawable-xlarge/btn_center_default.9.png
new file mode 100755
index 0000000..d5ec36b
--- /dev/null
+++ b/java/res/drawable-xlarge/btn_center_default.9.png
Binary files differ
diff --git a/java/res/drawable-xlarge/btn_center_pressed.9.png b/java/res/drawable-xlarge/btn_center_pressed.9.png
new file mode 100755
index 0000000..593a679
--- /dev/null
+++ b/java/res/drawable-xlarge/btn_center_pressed.9.png
Binary files differ
diff --git a/java/res/drawable-xlarge/btn_center_selected.9.png b/java/res/drawable-xlarge/btn_center_selected.9.png
new file mode 100644
index 0000000..f1914a8
--- /dev/null
+++ b/java/res/drawable-xlarge/btn_center_selected.9.png
Binary files differ
diff --git a/java/res/drawable-xlarge/caution.png b/java/res/drawable-xlarge/caution.png
new file mode 100755
index 0000000..eaef534
--- /dev/null
+++ b/java/res/drawable-xlarge/caution.png
Binary files differ
diff --git a/java/res/drawable-xlarge/mic_base.png b/java/res/drawable-xlarge/mic_base.png
new file mode 100644
index 0000000..53e29ff
--- /dev/null
+++ b/java/res/drawable-xlarge/mic_base.png
Binary files differ
diff --git a/java/res/drawable-xlarge/mic_full.png b/java/res/drawable-xlarge/mic_full.png
new file mode 100644
index 0000000..e3e3dfa
--- /dev/null
+++ b/java/res/drawable-xlarge/mic_full.png
Binary files differ
diff --git a/java/res/drawable-xlarge/mic_slash.png b/java/res/drawable-xlarge/mic_slash.png
new file mode 100644
index 0000000..1dd05c5
--- /dev/null
+++ b/java/res/drawable-xlarge/mic_slash.png
Binary files differ
diff --git a/java/res/drawable-xlarge/vs_dialog_blue.9.png b/java/res/drawable-xlarge/vs_dialog_blue.9.png
new file mode 100644
index 0000000..cf27e8f
--- /dev/null
+++ b/java/res/drawable-xlarge/vs_dialog_blue.9.png
Binary files differ
diff --git a/java/res/drawable-xlarge/vs_dialog_red.9.png b/java/res/drawable-xlarge/vs_dialog_red.9.png
new file mode 100644
index 0000000..6c08d5a
--- /dev/null
+++ b/java/res/drawable-xlarge/vs_dialog_red.9.png
Binary files differ
diff --git a/java/res/drawable-xlarge/vs_dialog_yellow.9.png b/java/res/drawable-xlarge/vs_dialog_yellow.9.png
new file mode 100644
index 0000000..2fb06c2
--- /dev/null
+++ b/java/res/drawable-xlarge/vs_dialog_yellow.9.png
Binary files differ
diff --git a/java/res/drawable-xlarge/vs_popup_mic_edge.png b/java/res/drawable-xlarge/vs_popup_mic_edge.png
new file mode 100644
index 0000000..4ff6337
--- /dev/null
+++ b/java/res/drawable-xlarge/vs_popup_mic_edge.png
Binary files differ
diff --git a/java/res/drawable/background_voice.xml b/java/res/drawable/background_voice.xml
new file mode 100644
index 0000000..3b6137d
--- /dev/null
+++ b/java/res/drawable/background_voice.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, 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.
+*/
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <gradient
+        android:startColor="#ff000000"
+        android:endColor="#ff000e29"
+        android:angle="90" />
+</shape>
\ No newline at end of file
diff --git a/java/res/drawable/btn_center.xml b/java/res/drawable/btn_center.xml
new file mode 100644
index 0000000..9998b56
--- /dev/null
+++ b/java/res/drawable/btn_center.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, 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.
+*/
+-->
+
+<selector
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+    <item
+        android:state_window_focused="false"
+        android:state_enabled="true"
+        android:drawable="@drawable/btn_center_default" />
+    <item
+        android:state_pressed="true"
+        android:drawable="@drawable/btn_center_pressed" />
+    <item
+        android:state_focused="true"
+        android:state_enabled="true"
+        android:drawable="@drawable/btn_center_selected" />
+    <item
+        android:state_enabled="true"
+        android:drawable="@drawable/btn_center_default" />
+    <item
+        android:drawable="@drawable/btn_center_default" />
+</selector>
\ No newline at end of file
diff --git a/java/res/drawable/btn_center_default.9.png b/java/res/drawable/btn_center_default.9.png
new file mode 100755
index 0000000..d5ec36b
--- /dev/null
+++ b/java/res/drawable/btn_center_default.9.png
Binary files differ
diff --git a/java/res/drawable/btn_center_pressed.9.png b/java/res/drawable/btn_center_pressed.9.png
new file mode 100755
index 0000000..593a679
--- /dev/null
+++ b/java/res/drawable/btn_center_pressed.9.png
Binary files differ
diff --git a/java/res/drawable/btn_center_selected.9.png b/java/res/drawable/btn_center_selected.9.png
new file mode 100644
index 0000000..f1914a8
--- /dev/null
+++ b/java/res/drawable/btn_center_selected.9.png
Binary files differ
diff --git a/java/res/drawable/caution.png b/java/res/drawable/caution.png
new file mode 100755
index 0000000..eaef534
--- /dev/null
+++ b/java/res/drawable/caution.png
Binary files differ
diff --git a/java/res/drawable/mic_base.png b/java/res/drawable/mic_base.png
new file mode 100644
index 0000000..53e29ff
--- /dev/null
+++ b/java/res/drawable/mic_base.png
Binary files differ
diff --git a/java/res/drawable/mic_full.png b/java/res/drawable/mic_full.png
new file mode 100644
index 0000000..e3e3dfa
--- /dev/null
+++ b/java/res/drawable/mic_full.png
Binary files differ
diff --git a/java/res/drawable/mic_slash.png b/java/res/drawable/mic_slash.png
new file mode 100644
index 0000000..1dd05c5
--- /dev/null
+++ b/java/res/drawable/mic_slash.png
Binary files differ
diff --git a/java/res/drawable/vs_dialog_blue.9.png b/java/res/drawable/vs_dialog_blue.9.png
new file mode 100644
index 0000000..cf27e8f
--- /dev/null
+++ b/java/res/drawable/vs_dialog_blue.9.png
Binary files differ
diff --git a/java/res/drawable/vs_dialog_red.9.png b/java/res/drawable/vs_dialog_red.9.png
new file mode 100644
index 0000000..6c08d5a
--- /dev/null
+++ b/java/res/drawable/vs_dialog_red.9.png
Binary files differ
diff --git a/java/res/drawable/vs_dialog_yellow.9.png b/java/res/drawable/vs_dialog_yellow.9.png
new file mode 100644
index 0000000..2fb06c2
--- /dev/null
+++ b/java/res/drawable/vs_dialog_yellow.9.png
Binary files differ
diff --git a/java/res/drawable/vs_popup_mic_edge.png b/java/res/drawable/vs_popup_mic_edge.png
new file mode 100644
index 0000000..4ff6337
--- /dev/null
+++ b/java/res/drawable/vs_popup_mic_edge.png
Binary files differ
diff --git a/java/res/layout/recognition_status.xml b/java/res/layout/recognition_status.xml
index ea2d9ee..b2c9f4a 100644
--- a/java/res/layout/recognition_status.xml
+++ b/java/res/layout/recognition_status.xml
@@ -16,83 +16,70 @@
 ** See the License for the specific language governing permissions and 
 ** limitations under the License.
 */
---> 
-
-
-<LinearLayout 
-      xmlns:android="http://schemas.android.com/apk/res/android"
-      android:orientation="vertical"
-      android:layout_height="wrap_content"
-      android:layout_width="wrap_content"
-      android:background="@android:color/black"
-      android:paddingBottom="0dip"
-      android:paddingLeft="0dip"
-      android:paddingRight="0dip"
->
-
-    <LinearLayout 
-       xmlns:android="http://schemas.android.com/apk/res/android"
-       android:id="@+id/main_image"
-       android:orientation="vertical"
-       android:background="@drawable/voice_ime_background"
-                 android:scaleType="fitXY"
-                 android:layout_width="match_parent"
-                 android:layout_height="180dip"
-                 android:paddingBottom="2dip"
-                 android:paddingTop="2dip"
-    >
-
-    <TextView android:id="@+id/text"
-        android:text="@string/voice_initializing"
+-->
+<RelativeLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_marginTop="15dip"
-        android:textSize="28sp"
-        android:textColor="#ffffff"
-        android:layout_gravity="center_horizontal"
-    />
-
-    <ImageView android:id="@+id/image"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_marginTop="20dip"
-        android:layout_gravity="center_horizontal"
-        android:src="@drawable/mic_slash_holo"
-    />
-
-    <ProgressBar android:id="@+id/progress"
-        android:layout_height="60dip"
-        android:layout_width="60dip"
-        android:layout_gravity="center"
-        android:visibility="gone"
-        android:indeterminate="true"
-        android:indeterminateOnly="false"
-    />
-
-
-
-    </LinearLayout>
-
-    <LinearLayout android:id="@+id/button"
-        android:orientation="vertical"
-        android:background="@drawable/ok_cancel"
-        android:scaleType="fitXY"
         android:layout_width="match_parent"
-        android:layout_height="42dip"
-        android:paddingLeft="1dip"
-        android:paddingRight="1dip"
-    >
-
-    <TextView android:id="@+id/button_text"
-        android:text="@string/cancel"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_marginTop="7dip"
-        android:textSize="19sp"
-        android:textColor="#ffffff"
-        android:layout_gravity="center_horizontal"
-    />
+        android:background="@drawable/background_voice">
+    <LinearLayout
+            xmlns:android="http://schemas.android.com/apk/res/android"
+            android:id="@+id/popup_layout"
+            android:orientation="vertical"
+            android:layout_height="0dip"
+            android:layout_width="500dip"
+            android:layout_centerInParent="true"
+            android:background="@drawable/vs_dialog_red">
+        <TextView
+                android:id="@+id/text"
+                android:text="@string/voice_error"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:singleLine="true"
+                android:layout_marginTop="10dip"
+                android:textSize="28sp"
+                android:textColor="#ffffff"
+                android:layout_gravity="center"
+                android:visibility="invisible"/>
+        <RelativeLayout
+                android:layout_height="0dip"
+                android:layout_width="match_parent"
+                android:layout_weight="1.0">
+            <com.android.inputmethod.voice.SoundIndicator
+                    android:id="@+id/sound_indicator"
+                    android:src="@drawable/mic_full"
+                    android:background="@drawable/mic_base"
+                    android:adjustViewBounds="true"
+                    android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:layout_centerInParent="true"
+                    android:visibility="gone"/>
+            <ImageView
+                    android:id="@+id/image"
+                    android:src="@drawable/mic_slash"
+                    android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:layout_centerInParent="true"
+                    android:visibility="visible"/>
+            <ProgressBar
+                    android:id="@+id/progress"
+                    android:indeterminate="true"
+                    android:indeterminateOnly="false"
+                    android:layout_height="60dip"
+                    android:layout_width="60dip"
+                    android:layout_centerInParent="true"
+                    android:visibility="gone"/>
+        </RelativeLayout>
+        <Button
+                android:id="@+id/button"
+                android:layout_width="match_parent"
+                android:layout_height="54dip"
+                android:singleLine="true"
+                android:focusable="true"
+                android:text="@string/cancel"
+                android:layout_gravity="center_horizontal"
+                android:background="@drawable/btn_center"
+                android:textColor="#ffffff"
+                android:textSize="19sp" />
     </LinearLayout>
-
-</LinearLayout>
-
+</RelativeLayout>
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index d5844b5..5d48d6b 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -133,14 +133,17 @@
     private Resources mResources;
     private SharedPreferences mPrefs;
 
+    // These variables are initialized according to the {@link EditorInfo#inputType}.
+    private boolean mAutoSpace;
+    private boolean mInputTypeNoAutoCorrect;
+    private boolean mIsSettingsSuggestionStripOn;
+    private boolean mApplicationSpecifiedCompletionOn;
+
     private final StringBuilder mComposing = new StringBuilder();
     private WordComposer mWord = new WordComposer();
     private CharSequence mBestWord;
     private boolean mHasValidSuggestions;
-    private boolean mIsSettingsSuggestionStripOn;
-    private boolean mApplicationSpecifiedCompletionOn;
     private boolean mHasDictionary;
-    private boolean mAutoSpace;
     private boolean mJustAddedAutoSpace;
     private boolean mAutoCorrectEnabled;
     private boolean mReCorrectionEnabled;
@@ -164,9 +167,6 @@
     private int mLastSelectionEnd;
     private SuggestedWords mSuggestPuncList;
 
-    // Input type is such that we should not auto-correct
-    private boolean mInputTypeNoAutoCorrect;
-
     // Indicates whether the suggestion strip is to be on in landscape
     private boolean mJustAccepted;
     private boolean mJustReverted;
@@ -464,7 +464,7 @@
 
         mConfigurationChanging = true;
         super.onConfigurationChanged(conf);
-        mVoiceConnector.onConfigurationChanged(mConfigurationChanging);
+        mVoiceConnector.onConfigurationChanged(conf);
         mConfigurationChanging = false;
     }
 
@@ -515,24 +515,62 @@
 
         if (mRefreshKeyboardRequired) {
             mRefreshKeyboardRequired = false;
-            onKeyboardLanguageChanged();
+            onRefreshKeyboard();
         }
 
         TextEntryState.newSession(this);
 
-        // Most such things we decide below in the switch statement, but we need to know
-        // now whether this is a password text field, because we need to know now (before
-        // the switch statement) whether we want to enable the voice button.
-        int variation = attribute.inputType & InputType.TYPE_MASK_VARIATION;
-        mVoiceConnector.resetVoiceStates(isPasswordVariation(variation));
+        // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
+        // know now whether this is a password text field, because we need to know now whether we
+        // want to enable the voice button.
+        mVoiceConnector.resetVoiceStates(isPasswordVariation(
+                attribute.inputType & InputType.TYPE_MASK_VARIATION));
+
+        final int mode = initializeInputAttributesAndGetMode(attribute.inputType);
+
+        inputView.closing();
+        mEnteredText = null;
+        mComposing.setLength(0);
+        mHasValidSuggestions = false;
+        mDeleteCount = 0;
+        mJustAddedAutoSpace = false;
+
+        loadSettings(attribute);
+        if (mSubtypeSwitcher.isKeyboardMode()) {
+            switcher.loadKeyboard(mode, attribute.imeOptions,
+                    mVoiceConnector.isVoiceButtonEnabled(),
+                    mVoiceConnector.isVoiceButtonOnPrimary());
+            switcher.updateShiftState();
+        }
+
+        setCandidatesViewShownInternal(isCandidateStripVisible(),
+                false /* needsInputViewShown */ );
+        // Delay updating suggestions because keyboard input view may not be shown at this point.
+        mHandler.postUpdateSuggestions();
+
+        updateCorrectionMode();
+
+        inputView.setPreviewEnabled(mPopupOn);
+        inputView.setProximityCorrectionEnabled(true);
+        // If we just entered a text field, maybe it has some old text that requires correction
+        checkReCorrectionOnStart();
+        inputView.setForeground(true);
+
+        mVoiceConnector.onStartInputView(inputView.getWindowToken());
+
+        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
+    }
+
+    private int initializeInputAttributesAndGetMode(int inputType) {
+        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
+        mAutoSpace = false;
         mInputTypeNoAutoCorrect = false;
         mIsSettingsSuggestionStripOn = false;
         mApplicationSpecifiedCompletionOn = false;
         mApplicationSpecifiedCompletions = null;
-        mEnteredText = null;
 
         final int mode;
-        switch (attribute.inputType & InputType.TYPE_MASK_CLASS) {
+        switch (inputType & InputType.TYPE_MASK_CLASS) {
             case InputType.TYPE_CLASS_NUMBER:
             case InputType.TYPE_CLASS_DATETIME:
                 mode = KeyboardId.MODE_NUMBER;
@@ -567,7 +605,7 @@
                     mode = KeyboardId.MODE_WEB;
                     // If it's a browser edit field and auto correct is not ON explicitly, then
                     // disable auto correction, but keep suggestions on.
-                    if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
+                    if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
                         mInputTypeNoAutoCorrect = true;
                     }
                 } else {
@@ -575,16 +613,16 @@
                 }
 
                 // If NO_SUGGESTIONS is set, don't do prediction.
-                if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
+                if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
                     mIsSettingsSuggestionStripOn = false;
                     mInputTypeNoAutoCorrect = true;
                 }
                 // If it's not multiline and the autoCorrect flag is not set, then don't correct
-                if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
-                        (attribute.inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
+                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
+                        (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
                     mInputTypeNoAutoCorrect = true;
                 }
-                if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
+                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
                     mIsSettingsSuggestionStripOn = false;
                     mApplicationSpecifiedCompletionOn = isFullscreenMode();
                 }
@@ -593,40 +631,7 @@
                 mode = KeyboardId.MODE_TEXT;
                 break;
         }
-        inputView.closing();
-        mComposing.setLength(0);
-        mHasValidSuggestions = false;
-        mDeleteCount = 0;
-        mJustAddedAutoSpace = false;
-
-        loadSettings(attribute);
-        if (mSubtypeSwitcher.isKeyboardMode()) {
-            switcher.loadKeyboard(mode, attribute.imeOptions,
-                    mVoiceConnector.isVoiceButtonEnabled(),
-                    mVoiceConnector.isVoiceButtonOnPrimary());
-            switcher.updateShiftState();
-        }
-
-        setCandidatesViewShownInternal(isCandidateStripVisible(),
-                false /* needsInputViewShown */ );
-        // Delay updating suggestions because keyboard input view may not be shown at this point.
-        mHandler.postUpdateSuggestions();
-
-        // If the dictionary is not big enough, don't auto correct
-        mHasDictionary = mSuggest.hasMainDictionary();
-
-        updateCorrectionMode();
-
-        inputView.setPreviewEnabled(mPopupOn);
-        inputView.setProximityCorrectionEnabled(true);
-        mIsSettingsSuggestionStripOn &= (mCorrectionMode > 0 || isShowingSuggestionsStrip());
-        // If we just entered a text field, maybe it has some old text that requires correction
-        checkReCorrectionOnStart();
-        inputView.setForeground(true);
-
-        mVoiceConnector.onStartInputView(inputView.getWindowToken());
-
-        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
+        return mode;
     }
 
     private void checkReCorrectionOnStart() {
@@ -1395,7 +1400,8 @@
     }
 
     private boolean isSuggestionsRequested() {
-        return mIsSettingsSuggestionStripOn;
+        return mIsSettingsSuggestionStripOn
+                && (mCorrectionMode > 0 || isShowingSuggestionsStrip());
     }
 
     private boolean isShowingPunctuationList() {
@@ -1813,7 +1819,6 @@
         final int length = mComposing.length();
         if (!mHasValidSuggestions && length > 0) {
             final InputConnection ic = getCurrentInputConnection();
-            mHasValidSuggestions = true;
             mJustReverted = true;
             final CharSequence punctuation = ic.getTextBeforeCursor(1, 0);
             if (deleteChar) ic.deleteSurroundingText(1, 0);
@@ -1823,14 +1828,19 @@
                 toDelete--;
             }
             ic.deleteSurroundingText(toDelete, 0);
-            if (deleteChar) {
+            // Re-insert punctuation only when the deleted character was word separator and the
+            // composing text wasn't equal to the auto-corrected text.
+            if (deleteChar
+                    && !TextUtils.isEmpty(punctuation) && isWordSeparator(punctuation.charAt(0))
+                    && !TextUtils.equals(mComposing, toTheLeft)) {
                 ic.commitText(mComposing, 1);
                 TextEntryState.acceptedTyped(mComposing);
-                if (!TextUtils.isEmpty(punctuation) && isWordSeparator(punctuation.charAt(0))) {
-                    ic.commitText(punctuation, 1);
-                    TextEntryState.typedCharacter(punctuation.charAt(0), true);
-                }
+                ic.commitText(punctuation, 1);
+                TextEntryState.typedCharacter(punctuation.charAt(0), true);
+                // Clear composing text
+                mComposing.setLength(0);
             } else {
+                mHasValidSuggestions = true;
                 ic.setComposingText(mComposing, 1);
                 TextEntryState.backspace();
             }
@@ -1863,9 +1873,9 @@
         return mWord.isFirstCharCapitalized();
     }
 
-    // Notify that Language has been changed and toggleLanguage will update KeyboaredID according
-    // to new Language.
-    public void onKeyboardLanguageChanged() {
+    // Notify that language or mode have been changed and toggleLanguage will update KeyboaredID
+    // according to new language or mode.
+    public void onRefreshKeyboard() {
         toggleLanguage(true, true);
     }
 
@@ -1876,8 +1886,9 @@
         }
         // Reload keyboard because the current language has been changed.
         KeyboardSwitcher switcher = mKeyboardSwitcher;
-        final int mode = switcher.getKeyboardMode();
         final EditorInfo attribute = getCurrentInputEditorInfo();
+        final int mode = initializeInputAttributesAndGetMode((attribute != null)
+                ? attribute.inputType : 0);
         final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
         switcher.loadKeyboard(mode, imeOptions, mVoiceConnector.isVoiceButtonEnabled(),
                 mVoiceConnector.isVoiceButtonOnPrimary());
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index b765fad..a9bd114 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -187,7 +187,7 @@
             // fallback to the default locale and mode.
             Log.w(TAG, "Couldn't get the current subtype.");
             newLocale = "en_US";
-            newMode =KEYBOARD_MODE;
+            newMode = KEYBOARD_MODE;
         } else {
             newLocale = newSubtype.getLocale();
             newMode = newSubtype.getMode();
@@ -217,8 +217,8 @@
                     mVoiceInput.cancel();
                 }
             }
-            if (languageChanged) {
-                mService.onKeyboardLanguageChanged();
+            if (modeChanged || languageChanged) {
+                mService.onRefreshKeyboard();
             }
         } else if (isVoiceMode()) {
             // If needsToShowWarningDialog is true, voice input need to show warning before
@@ -439,7 +439,7 @@
     private void triggerVoiceIME() {
         if (!mService.isInputViewShown()) return;
         VoiceIMEConnector.getInstance().startListening(false,
-                KeyboardSwitcher.getInstance().getInputView().getWindowToken(), false);
+                KeyboardSwitcher.getInstance().getInputView().getWindowToken());
     }
 
     //////////////////////////////////////
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 5398b77..0fbbcdd 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -124,7 +124,7 @@
                 addWord(previousSuggestions.getWord(pos));
             mIsCompletions = false;
             mTypedWordValid = false;
-            mHasMinimalSuggestion = (previousSize > 1);
+            mHasMinimalSuggestion = false;
             return this;
         }
 
diff --git a/java/src/com/android/inputmethod/voice/RecognitionView.java b/java/src/com/android/inputmethod/voice/RecognitionView.java
index d6d0721..98db936 100644
--- a/java/src/com/android/inputmethod/voice/RecognitionView.java
+++ b/java/src/com/android/inputmethod/voice/RecognitionView.java
@@ -16,9 +16,6 @@
 
 package com.android.inputmethod.voice;
 
-import com.android.inputmethod.latin.R;
-
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -29,20 +26,21 @@
 import android.graphics.PathEffect;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
-import android.util.TypedValue;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.view.ViewGroup.MarginLayoutParams;
+import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
+import com.android.inputmethod.latin.R;
+
 import java.io.ByteArrayOutputStream;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.ShortBuffer;
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -58,79 +56,55 @@
     private View mView;
     private Context mContext;
 
-    private ImageView mImage;
     private TextView mText;
-    private View mButton;
-    private TextView mButtonText;
+    private ImageView mImage;
     private View mProgress;
+    private SoundIndicator mSoundIndicator;
+    private Button mButton;
 
     private Drawable mInitializing;
     private Drawable mError;
-    private List<Drawable> mSpeakNow;
 
-    private float mVolume = 0.0f;
-    private int mLevel = 0;
+    private static final int INIT = 0;
+    private static final int LISTENING = 1;
+    private static final int WORKING = 2;
+    private static final int READY = 3;
+    
+    private int mState = INIT;
 
-    private enum State {LISTENING, WORKING, READY}
-    private State mState = State.READY;
+    private final View mPopupLayout;
 
-    private float mMinMicrophoneLevel;
-    private float mMaxMicrophoneLevel;
-
-    /** Updates the microphone icon to show user their volume.*/
-    private Runnable mUpdateVolumeRunnable = new Runnable() {
-        @Override
-        public void run() {
-            if (mState != State.LISTENING) {
-                return;
-            }
-
-            final float min = mMinMicrophoneLevel;
-            final float max = mMaxMicrophoneLevel;
-            final int maxLevel = mSpeakNow.size() - 1;
-
-            int index = (int) ((mVolume - min) / (max - min) * maxLevel);
-            final int level = Math.min(Math.max(0, index), maxLevel);
-
-            if (level != mLevel) {
-                mImage.setImageDrawable(mSpeakNow.get(level));
-                mLevel = level;
-            }
-            mUiHandler.postDelayed(mUpdateVolumeRunnable, 50);
-        }
-      };
+    private final Drawable mListeningBorder;
+    private final Drawable mWorkingBorder;
+    private final Drawable mErrorBorder;
 
     public RecognitionView(Context context, OnClickListener clickListener) {
         mUiHandler = new Handler();
 
-        mView = LayoutInflater.from(context).inflate(R.layout.recognition_status, null);
-        ContentResolver cr = context.getContentResolver();
-        mMinMicrophoneLevel = SettingsUtil.getSettingsFloat(
-                cr, SettingsUtil.LATIN_IME_MIN_MICROPHONE_LEVEL, 15.f);
-        mMaxMicrophoneLevel = SettingsUtil.getSettingsFloat(
-                cr, SettingsUtil.LATIN_IME_MAX_MICROPHONE_LEVEL, 30.f);
+        LayoutInflater inflater = (LayoutInflater) context.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+
+        mView = inflater.inflate(R.layout.recognition_status, null);
+
+        mPopupLayout= mView.findViewById(R.id.popup_layout);
 
         // Pre-load volume level images
         Resources r = context.getResources();
 
-        mSpeakNow = new ArrayList<Drawable>();
-        mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level0));
-        mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level1));
-        mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level2));
-        mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level3));
-        mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level4));
-        mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level5));
-        mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level6));
+        mListeningBorder = r.getDrawable(R.drawable.vs_dialog_red);
+        mWorkingBorder = r.getDrawable(R.drawable.vs_dialog_blue);
+        mErrorBorder = r.getDrawable(R.drawable.vs_dialog_yellow);
 
         mInitializing = r.getDrawable(R.drawable.mic_slash);
         mError = r.getDrawable(R.drawable.caution);
 
         mImage = (ImageView) mView.findViewById(R.id.image);
-        mButton = mView.findViewById(R.id.button);
+        mProgress = mView.findViewById(R.id.progress);
+        mSoundIndicator = (SoundIndicator) mView.findViewById(R.id.sound_indicator);
+
+        mButton = (Button) mView.findViewById(R.id.button);
         mButton.setOnClickListener(clickListener);
         mText = (TextView) mView.findViewById(R.id.text);
-        mButtonText = (TextView) mView.findViewById(R.id.button_text);
-        mProgress = mView.findViewById(R.id.progress);
 
         mContext = context;
     }
@@ -144,9 +118,9 @@
             @Override
             public void run() {
                 // Restart the spinner
-                if (mState == State.WORKING) {
-                    ((ProgressBar)mProgress).setIndeterminate(false);
-                    ((ProgressBar)mProgress).setIndeterminate(true);
+                if (mState == WORKING) {
+                    ((ProgressBar) mProgress).setIndeterminate(false);
+                    ((ProgressBar) mProgress).setIndeterminate(true);
                 }
             }
         });
@@ -156,48 +130,48 @@
         mUiHandler.post(new Runnable() {
             @Override
             public void run() {
-                prepareDialog(false, mContext.getText(R.string.voice_initializing), mInitializing,
-                        mContext.getText(R.string.cancel)); 
+                mState = INIT;
+                prepareDialog(mContext.getText(R.string.voice_initializing), mInitializing,
+                        mContext.getText(R.string.cancel));
             }
           });
     }
 
     public void showListening() {
+        Log.d(TAG, "#showListening");
         mUiHandler.post(new Runnable() {
             @Override
             public void run() {
-                mState = State.LISTENING;
-                prepareDialog(false, mContext.getText(R.string.voice_listening), mSpeakNow.get(0),
+                mState = LISTENING;
+                prepareDialog(mContext.getText(R.string.voice_listening), null,
                         mContext.getText(R.string.cancel));
             }
           });
-        mUiHandler.postDelayed(mUpdateVolumeRunnable, 50);
     }
 
-    public void updateVoiceMeter(final float rmsdB) {
-        mVolume = rmsdB;
+    public void updateVoiceMeter(float rmsdB) {
+        mSoundIndicator.setRmsdB(rmsdB);
     }
 
     public void showError(final String message) {
         mUiHandler.post(new Runnable() {
             @Override
             public void run() {
-                mState = State.READY;
-                prepareDialog(false, message, mError, mContext.getText(R.string.ok));
+                mState = READY;
+                prepareDialog(message, mError, mContext.getText(R.string.ok));
             }
-          });
+        });
     }
 
     public void showWorking(
         final ByteArrayOutputStream waveBuffer,
         final int speechStartPosition,
         final int speechEndPosition) {
-
         mUiHandler.post(new Runnable() {
             @Override
             public void run() {
-                mState = State.WORKING;
-                prepareDialog(true, mContext.getText(R.string.voice_working), null, mContext
+                mState = WORKING;
+                prepareDialog(mContext.getText(R.string.voice_working), null, mContext
                         .getText(R.string.cancel));
                 final ShortBuffer buf = ByteBuffer.wrap(waveBuffer.toByteArray()).order(
                         ByteOrder.nativeOrder()).asShortBuffer();
@@ -205,21 +179,71 @@
                 waveBuffer.reset();
                 showWave(buf, speechStartPosition / 2, speechEndPosition / 2);
             }
-          });
+        });
     }
     
-    private void prepareDialog(boolean spinVisible, CharSequence text, Drawable image,
+    private void prepareDialog(CharSequence text, Drawable image,
             CharSequence btnTxt) {
-        if (spinVisible) {
-            mProgress.setVisibility(View.VISIBLE);
-            mImage.setVisibility(View.GONE);
-        } else {
-            mProgress.setVisibility(View.GONE);
-            mImage.setImageDrawable(image);
-            mImage.setVisibility(View.VISIBLE);
+        switch (mState) {
+            case INIT:
+                mText.setVisibility(View.GONE);
+
+                mProgress.setVisibility(View.GONE);
+
+                mImage.setVisibility(View.VISIBLE);
+                mImage.setImageResource(R.drawable.mic_slash);
+
+                mSoundIndicator.setVisibility(View.GONE);
+                mSoundIndicator.stop();
+
+                mPopupLayout.setBackgroundDrawable(mListeningBorder);
+                break;
+            case LISTENING:
+                mText.setVisibility(View.VISIBLE);
+                mText.setText(text);
+
+                mProgress.setVisibility(View.GONE);
+
+                mImage.setVisibility(View.GONE);
+
+                mSoundIndicator.setVisibility(View.VISIBLE);
+                mSoundIndicator.start();
+
+                mPopupLayout.setBackgroundDrawable(mListeningBorder);
+                break;
+            case WORKING:
+
+                mText.setVisibility(View.VISIBLE);
+                mText.setText(text);
+
+                mProgress.setVisibility(View.VISIBLE);
+
+                mImage.setVisibility(View.VISIBLE);
+
+                mSoundIndicator.setVisibility(View.GONE);
+                mSoundIndicator.stop();
+
+                mPopupLayout.setBackgroundDrawable(mWorkingBorder);
+                break;
+            case READY:
+                mText.setVisibility(View.VISIBLE);
+                mText.setText(text);
+
+                mProgress.setVisibility(View.GONE);
+
+                mImage.setVisibility(View.VISIBLE);
+                mImage.setImageResource(R.drawable.caution);
+
+                mSoundIndicator.setVisibility(View.GONE);
+                mSoundIndicator.stop();
+
+                mPopupLayout.setBackgroundDrawable(mErrorBorder);
+                break;
+             default:
+                 Log.w(TAG, "Unknown state " + mState);
         }
-        mText.setText(text);
-        mButtonText.setText(btnTxt);
+        mPopupLayout.requestLayout();
+        mButton.setText(btnTxt);
     }
 
     /**
@@ -246,7 +270,7 @@
      */
     private void showWave(ShortBuffer waveBuffer, int startPosition, int endPosition) {
         final int w = ((View) mImage.getParent()).getWidth();
-        final int h = mImage.getHeight();
+        final int h = ((View) mImage.getParent()).getHeight();
         if (w <= 0 || h <= 0) {
             // view is not visible this time. Skip drawing.
             return;
@@ -257,7 +281,7 @@
         paint.setColor(0xFFFFFFFF); // 0xAARRGGBB
         paint.setAntiAlias(true);
         paint.setStyle(Paint.Style.STROKE);
-        paint.setAlpha(0x90);
+        paint.setAlpha(80);
 
         final PathEffect effect = new CornerPathEffect(3);
         paint.setPathEffect(effect);
@@ -279,7 +303,7 @@
 
         final int count = (endIndex - startIndex) / numSamplePerWave;
         final float deltaX = 1.0f * w / count;
-        int yMax = h / 2 - 8;
+        int yMax = h / 2;
         Path path = new Path();
         c.translate(0, yMax);
         float x = 0;
@@ -293,37 +317,20 @@
             path.lineTo(x, y);
         }
         if (deltaX > 4) {
-            paint.setStrokeWidth(3);
+            paint.setStrokeWidth(2);
         } else {
-            paint.setStrokeWidth(Math.max(1, (int) (deltaX -.05)));
+            paint.setStrokeWidth(Math.max(0, (int) (deltaX -.05)));
         }
         c.drawPath(path, paint);
         mImage.setImageBitmap(b);
-        mImage.setVisibility(View.VISIBLE);
-        MarginLayoutParams mProgressParams = (MarginLayoutParams)mProgress.getLayoutParams();
-        mProgressParams.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
-                -h , mContext.getResources().getDisplayMetrics());
-
-        // Tweak the padding manually to fill out the whole view horizontally.
-        // TODO: Do this in the xml layout instead.
-        ((View) mImage.getParent()).setPadding(4, ((View) mImage.getParent()).getPaddingTop(), 3,
-                ((View) mImage.getParent()).getPaddingBottom());
-        mProgress.setLayoutParams(mProgressParams);
     }
 
-
     public void finish() {
         mUiHandler.post(new Runnable() {
             @Override
             public void run() {
-                mState = State.READY;
-                exitWorking();
+                mSoundIndicator.stop();
             }
-          });
-    }
-
-    private void exitWorking() {
-        mProgress.setVisibility(View.GONE);
-        mImage.setVisibility(View.VISIBLE);
+        });
     }
 }
diff --git a/java/src/com/android/inputmethod/voice/SoundIndicator.java b/java/src/com/android/inputmethod/voice/SoundIndicator.java
new file mode 100644
index 0000000..543290b
--- /dev/null
+++ b/java/src/com/android/inputmethod/voice/SoundIndicator.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2011 Google Inc.
+ *
+ * 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.voice;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import com.android.inputmethod.latin.R;
+
+/**
+ * A widget which shows the volume of audio using a microphone icon
+ */
+public class SoundIndicator extends ImageView {
+    @SuppressWarnings("unused")
+    private static final String TAG = "SoundIndicator";
+
+    private static final float UP_SMOOTHING_FACTOR = 0.9f;
+    private static final float DOWN_SMOOTHING_FACTOR = 0.4f;
+
+    private static final float AUDIO_METER_MIN_DB = 7.0f;
+    private static final float AUDIO_METER_DB_RANGE = 20.0f;
+
+    private static final long FRAME_DELAY = 50;
+
+    private Bitmap mDrawingBuffer;
+    private Canvas mBufferCanvas;
+    private Bitmap mEdgeBitmap;
+    private float mLevel = 0.0f;
+    private Drawable mFrontDrawable;
+    private Paint mClearPaint;
+    private Paint mMultPaint;
+    private int mEdgeBitmapOffset;
+
+    private Handler mHandler;
+
+    private Runnable mDrawFrame = new Runnable() {
+        public void run() {
+            invalidate();
+            mHandler.postDelayed(mDrawFrame, FRAME_DELAY);
+        }
+    };
+
+    public SoundIndicator(Context context) {
+        this(context, null);
+    }
+
+    public SoundIndicator(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mFrontDrawable = getDrawable();
+        BitmapDrawable edgeDrawable =
+                (BitmapDrawable) context.getResources().getDrawable(R.drawable.vs_popup_mic_edge);
+        mEdgeBitmap = edgeDrawable.getBitmap();
+        mEdgeBitmapOffset = mEdgeBitmap.getHeight() / 2;
+
+        mDrawingBuffer =
+                Bitmap.createBitmap(mFrontDrawable.getIntrinsicWidth(),
+                        mFrontDrawable.getIntrinsicHeight(), Config.ARGB_8888);
+
+        mBufferCanvas = new Canvas(mDrawingBuffer);
+
+        // Initialize Paints.
+        mClearPaint = new Paint();
+        mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+
+        mMultPaint = new Paint();
+        mMultPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
+
+        mHandler = new Handler();
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        //super.onDraw(canvas);
+
+        float w = getWidth();
+        float h = getHeight();
+
+        // Clear the buffer canvas
+        mBufferCanvas.drawRect(0, 0, w, h, mClearPaint);
+
+        // Set its clip so we don't draw the front image all the way to the top
+        Rect clip = new Rect(0,
+                (int) ((1.0 - mLevel) * (h + mEdgeBitmapOffset)) - mEdgeBitmapOffset,
+                (int) w,
+                (int) h);
+
+        mBufferCanvas.save();
+        mBufferCanvas.clipRect(clip);
+
+        // Draw the front image
+        mFrontDrawable.setBounds(new Rect(0, 0, (int) w, (int) h));
+        mFrontDrawable.draw(mBufferCanvas);
+
+        mBufferCanvas.restore();
+
+        // Draw the edge image on top of the buffer image with a multiply mode
+        mBufferCanvas.drawBitmap(mEdgeBitmap, 0, clip.top, mMultPaint);
+
+        // Draw the buffer image (on top of the background image)
+        canvas.drawBitmap(mDrawingBuffer, 0, 0, null);
+    }
+
+    /**
+     * Sets the sound level
+     *
+     * @param rmsdB The level of the sound, in dB.
+     */
+    public void setRmsdB(float rmsdB) {
+        float level = ((rmsdB - AUDIO_METER_MIN_DB) / AUDIO_METER_DB_RANGE);
+
+        level = Math.min(Math.max(0.0f, level), 1.0f);
+
+        // We smooth towards the new level
+        if (level > mLevel) {
+            mLevel = (level - mLevel) * UP_SMOOTHING_FACTOR + mLevel;
+        } else {
+            mLevel = (level - mLevel) * DOWN_SMOOTHING_FACTOR + mLevel;
+        }
+        invalidate();
+    }
+
+    public void start() {
+        mHandler.post(mDrawFrame);
+    }
+
+    public void stop() {
+        mHandler.removeCallbacks(mDrawFrame);
+    }
+}
diff --git a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java b/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
index 9a6c3a8..a02dbcb 100644
--- a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
+++ b/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
@@ -30,6 +30,7 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.content.res.Configuration;
 import android.net.Uri;
 import android.os.IBinder;
 import android.preference.PreferenceManager;
@@ -78,6 +79,9 @@
     // dialog is already showing a voice search button.
     private static final String IME_OPTION_NO_MICROPHONE = "nm";
 
+    @SuppressWarnings("unused")
+    private static final String TAG = "VoiceIMEConnector";
+
     private boolean mAfterVoiceInput;
     private boolean mHasUsedVoiceInput;
     private boolean mHasUsedVoiceInputUnsupportedLocale;
@@ -164,8 +168,7 @@
         }
     }
 
-    private void showVoiceWarningDialog(final boolean swipe, IBinder token,
-            final boolean configurationChanging) {
+    private void showVoiceWarningDialog(final boolean swipe, IBinder token) {
         if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) {
             return;
         }
@@ -176,7 +179,7 @@
             @Override
             public void onClick(DialogInterface dialog, int whichButton) {
                 mVoiceInput.logKeyboardWarningDialogOk();
-                reallyStartListening(swipe, configurationChanging);
+                reallyStartListening(swipe);
             }
         });
         builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@@ -519,22 +522,38 @@
         onCancelVoice();
     }
 
-    public void switchToRecognitionStatusView(final boolean configurationChanging) {
-        final boolean configChanged = configurationChanging;
+    public void switchToRecognitionStatusView(final Configuration configuration) {
         mHandler.post(new Runnable() {
             @Override
             public void run() {
                 mService.setCandidatesViewShown(false);
                 mRecognizing = true;
+                mVoiceInput.newView();
                 View v = mVoiceInput.getView();
+
                 ViewParent p = v.getParent();
                 if (p != null && p instanceof ViewGroup) {
-                    ((ViewGroup)p).removeView(v);
+                    ((ViewGroup) p).removeView(v);
+                }
+
+                View keyboardView = KeyboardSwitcher.getInstance().getInputView();
+
+                // The full height of the keyboard is difficult to calculate
+                // as the dimension is expressed in "mm" and not in "pixel"
+                // As we add mm, we don't know how the rounding is going to work
+                // thus we may end up with few pixels extra (or less).
+                if (keyboardView != null) {
+                    int h = keyboardView.getHeight();
+                    if (h > 0) {
+                        View popupLayout = v.findViewById(R.id.popup_layout);
+                        popupLayout.getLayoutParams().height = h;
+                    }
                 }
                 mService.setInputView(v);
                 mService.updateInputViewShown();
-                if (configChanged) {
-                    mVoiceInput.onConfigurationChanged();
+
+                if (configuration != null) {
+                    mVoiceInput.onConfigurationChanged(configuration);
                 }
         }});
     }
@@ -544,7 +563,7 @@
         mImm.switchToLastInputMethod(token);
     }
 
-    private void reallyStartListening(boolean swipe, final boolean configurationChanging) {
+    private void reallyStartListening(boolean swipe) {
         if (!VOICE_INSTALLED) {
             return;
         }
@@ -573,22 +592,21 @@
 
         FieldContext context = makeFieldContext();
         mVoiceInput.startListening(context, swipe);
-        switchToRecognitionStatusView(configurationChanging);
+        switchToRecognitionStatusView(null);
     }
 
-    public void startListening(final boolean swipe, IBinder token,
-            final boolean configurationChanging) {
+    public void startListening(final boolean swipe, IBinder token) {
+        // TODO: remove swipe which is no longer used.
         if (VOICE_INSTALLED) {
             if (needsToShowWarningDialog()) {
                 // Calls reallyStartListening if user clicks OK, does nothing if user clicks Cancel.
-                showVoiceWarningDialog(swipe, token, configurationChanging);
+                showVoiceWarningDialog(swipe, token);
             } else {
-                reallyStartListening(swipe, configurationChanging);
+                reallyStartListening(swipe);
             }
         }
     }
 
-
     private boolean fieldCanDoVoice(FieldContext fieldContext) {
         return !mPasswordText
                 && mVoiceInput != null
@@ -632,7 +650,7 @@
             // Close keyboard view if it is been shown.
             if (KeyboardSwitcher.getInstance().isInputViewShown())
                 KeyboardSwitcher.getInstance().getInputView().purgeKeyboardAndClosing();
-            startListening(false, token, false);
+            startListening(false, token);
         }
         // If we have no token, onAttachedToWindow will take care of showing dialog and start
         // listening.
@@ -644,9 +662,9 @@
         mSubtypeSwitcher.setVoiceInput(mVoiceInput);
     }
 
-    public void onConfigurationChanged(boolean configurationChanging) {
+    public void onConfigurationChanged(Configuration configuration) {
         if (mRecognizing) {
-            switchToRecognitionStatusView(configurationChanging);
+            switchToRecognitionStatusView(configuration);
         }
     }
 
diff --git a/java/src/com/android/inputmethod/voice/VoiceInput.java b/java/src/com/android/inputmethod/voice/VoiceInput.java
index f77b4dd..ffa349f 100644
--- a/java/src/com/android/inputmethod/voice/VoiceInput.java
+++ b/java/src/com/android/inputmethod/voice/VoiceInput.java
@@ -22,6 +22,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -129,12 +130,17 @@
     
     private final static int MSG_CLOSE_ERROR_DIALOG = 1;
 
+    private final static int MSG_RESET = 2;
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
-            if (msg.what == MSG_CLOSE_ERROR_DIALOG) {
+            if (msg.what == MSG_RESET || msg.what == MSG_CLOSE_ERROR_DIALOG) {
                 mState = DEFAULT;
                 mRecognitionView.finish();
+            }
+
+            if (msg.what == MSG_CLOSE_ERROR_DIALOG) {
                 mUiListener.onCancelVoice();
             }
         }
@@ -277,8 +283,9 @@
      * The configuration of the IME changed and may have caused the views to be layed out
      * again. Restore the state of the recognition view.
      */
-    public void onConfigurationChanged() {
+    public void onConfigurationChanged(Configuration configuration) {
         mRecognitionView.restoreState();
+        mRecognitionView.getView().dispatchConfigurationChanged(configuration);
     }
 
     /**
@@ -509,7 +516,7 @@
         mState = DEFAULT;
 
         // Remove all pending tasks (e.g., timers to cancel voice input)
-        mHandler.removeMessages(MSG_CLOSE_ERROR_DIALOG);
+        mHandler.removeMessages(MSG_RESET);
 
         mSpeechRecognizer.cancel();
         mUiListener.onCancelVoice();