Merge "Move language-specific keyboard setting to resources."
diff --git a/java/res/layout-xlarge/recognition_status.xml b/java/res/layout-xlarge/recognition_status.xml
new file mode 100644
index 0000000..40bc098
--- /dev/null
+++ b/java/res/layout-xlarge/recognition_status.xml
@@ -0,0 +1,101 @@
+<?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.
+*/
+-->
+<RelativeLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        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="371dip"
+            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.deprecated.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>
+        <!--
+        The text is set by the code. We specify a random text (voice_error), so the
+        text view does not have a zero height. This is necessary to keep the slash
+        mic and the recording mic is the same position
+        -->
+        <TextView
+                android:id="@+id/language"
+                android:text="@string/voice_error"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:singleLine="true"
+                android:textSize="14sp"
+                android:layout_marginBottom="3dip"
+                android:layout_gravity="center"
+                android:textColor="#ffffff"
+                android:visibility="invisible"/>
+        <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>
+</RelativeLayout>
diff --git a/java/res/layout/recognition_status.xml b/java/res/layout/recognition_status.xml
index 45f6897..a2ddb7c 100644
--- a/java/res/layout/recognition_status.xml
+++ b/java/res/layout/recognition_status.xml
@@ -1,19 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* 
+/*
 **
 ** Copyright 2009, 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 
+** 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 
+**     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 
+** 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.
 */
 -->
@@ -37,7 +37,7 @@
                 android:layout_width="wrap_content"
                 android:singleLine="true"
                 android:layout_marginTop="10dip"
-                android:textSize="28sp"
+                android:textSize="20sp"
                 android:textColor="#ffffff"
                 android:layout_gravity="center"
                 android:visibility="invisible"/>
@@ -81,7 +81,8 @@
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
                 android:singleLine="true"
-                android:textSize="14sp"
+                android:textSize="15sp"
+                android:layout_marginTop="3dip"
                 android:layout_marginBottom="3dip"
                 android:layout_gravity="center"
                 android:textColor="#ffffff"
@@ -89,13 +90,13 @@
         <Button
                 android:id="@+id/button"
                 android:layout_width="match_parent"
-                android:layout_height="54dip"
+                android:layout_height="30dip"
                 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" />
+                android:textSize="15sp" />
     </LinearLayout>
 </RelativeLayout>
diff --git a/java/res/values/donottranslate-altchars.xml b/java/res/values/donottranslate-altchars.xml
index 621a2ea..883ccb7 100644
--- a/java/res/values/donottranslate-altchars.xml
+++ b/java/res/values/donottranslate-altchars.xml
@@ -48,7 +48,8 @@
     <string name="alternates_for_currency_euro">¢,£,$,¥,₱</string>
     <string name="alternates_for_currency_pound">¢,$,€,¥,₱</string>
     <string name="alternates_for_smiley">":-)|:-) ,:-(|:-( ,;-)|;-) ,:-P|:-P ,=-O|=-O ,:-*|:-* ,:O|:O ,B-)|B-) ,:-$|:-$ ,:-!|:-! ,:-[|:-[ ,O:-)|O:-) ,:-\\\\\\\\|:-\\\\\\\\ ,:\'(|:\'( ,:-D|:-D "</string>
-    <string name="alternates_for_punctuation">":,/,&amp;,(,),-,+,;,\@,\',\",\?,!,\\,"</string>
+    <string name="alternates_for_punctuation">"\?,!,\\,,:,-,\',\",(,),/,;,+,&amp;,\@"</string>
+    <string name="alternates_for_web_tab_punctuation">".,\?,!,\\,,:,-,\',\",(,),/,;,+,&amp;,\@"</string>
     <string name="keylabel_for_popular_domain">".com"</string>
     <!-- popular web domains for the locale - most popular, displayed on the keyboard -->
     <string name="alternates_for_popular_domain">".net,.org,.gov,.edu"</string>
diff --git a/java/res/xml/kbd_qwerty_f1.xml b/java/res/xml/kbd_qwerty_f1.xml
index 3ebdd10..d0e2884 100644
--- a/java/res/xml/kbd_qwerty_f1.xml
+++ b/java/res/xml/kbd_qwerty_f1.xml
@@ -45,6 +45,13 @@
                         latin:keyStyle="micKeyStyle" />
                 </case>
                 <!-- latin:hasVoiceKey="false" -->
+                <case
+                    latin:mode="web"
+                >
+                    <Key
+                        latin:keyLabel="."
+                        latin:keyStyle="settingsPopupStyle" />
+                </case>
                 <default>
                     <Key
                         latin:keyLabel=","
diff --git a/java/res/xml/kbd_qwerty_row4.xml b/java/res/xml/kbd_qwerty_row4.xml
index 18ff608..82f5a4a 100644
--- a/java/res/xml/kbd_qwerty_row4.xml
+++ b/java/res/xml/kbd_qwerty_row4.xml
@@ -43,8 +43,10 @@
                         latin:mode="web"
                     >
                          <Key
-                            latin:keyStyle="tabKeyStyle"
-                            latin:keyWidth="10%p" />
+                            latin:keyHintIcon="@drawable/hint_popup"
+                            latin:popupCharacters="@string/alternates_for_web_tab_punctuation"
+                            latin:maxPopupKeyboardColumn="8"
+                            latin:keyStyle="tabKeyStyle" />
                     </case>
                     <default>
                         <Key
@@ -83,28 +85,28 @@
                     latin:keyStyle="settingsKeyStyle" />
                 <include
                     latin:keyboardLayout="@xml/kbd_qwerty_f1" />
+                <Key
+                    latin:keyStyle="spaceKeyStyle"
+                    latin:keyWidth="30%p" />
                 <switch>
                     <case
                         latin:mode="web"
                     >
-                        <Key
-                            latin:keyStyle="spaceKeyStyle"
-                            latin:keyWidth="30%p" />
-                        <Key
+                         <Key
+                            latin:keyHintIcon="@drawable/hint_popup"
+                            latin:popupCharacters="@string/alternates_for_web_tab_punctuation"
+                            latin:maxPopupKeyboardColumn="8"
                             latin:keyStyle="tabKeyStyle" />
                     </case>
                     <default>
                         <Key
-                            latin:keyStyle="spaceKeyStyle"
-                            latin:keyWidth="30%p" />
+                            latin:keyLabel="."
+                            latin:keyHintIcon="@drawable/hint_popup"
+                            latin:popupCharacters="@string/alternates_for_punctuation"
+                            latin:maxPopupKeyboardColumn="7"
+                            latin:keyStyle="functionalKeyStyle" />
                     </default>
                 </switch>
-                <Key
-                    latin:keyLabel="."
-                    latin:keyHintIcon="@drawable/hint_popup"
-                    latin:popupCharacters="@string/alternates_for_punctuation"
-                    latin:maxPopupKeyboardColumn="7"
-                    latin:keyStyle="functionalKeyStyle" />
                 <switch>
                     <case
                         latin:mode="im"
@@ -114,14 +116,6 @@
                             latin:keyWidth="25%p"
                             latin:keyEdgeFlags="right" />
                     </case>
-                    <case
-                        latin:mode="web"
-                    >
-                        <Key
-                            latin:keyStyle="returnKeyStyle"
-                            latin:keyWidth="15%p"
-                            latin:keyEdgeFlags="right" />
-                    </case>
                     <default>
                         <Key
                             latin:keyStyle="returnKeyStyle"
diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
index 0c2a58e..d99f407 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
@@ -67,7 +67,8 @@
 
     // For the compatibility, IMM will create dummy subtypes if subtypes are not found.
     // This is required to be false if the current behavior is broken. For now, it's ok to be true.
-    private static final boolean HAS_VOICE_FUNCTION = true;
+    public static final boolean FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES =
+            !InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED;
     private static final String VOICE_MODE = "voice";
     private static final String KEYBOARD_MODE = "keyboard";
 
@@ -118,8 +119,7 @@
         Object retval = CompatUtils.invoke(mImm, null, METHOD_getEnabledInputMethodSubtypeList,
                 (imi != null ? imi.getInputMethodInfo() : null), allowsImplicitlySelectedSubtypes);
         if (retval == null || !(retval instanceof List) || ((List<?>)retval).isEmpty()) {
-            if (InputMethodServiceCompatWrapper.
-                    CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) {
+            if (!FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES) {
                 // Returns an empty list
                 return Collections.emptyList();
             }
@@ -148,7 +148,7 @@
 
     @SuppressWarnings("unused")
     private InputMethodSubtypeCompatWrapper getLastResortSubtype(String mode) {
-        if (VOICE_MODE.equals(mode) && !HAS_VOICE_FUNCTION)
+        if (VOICE_MODE.equals(mode) && !FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES)
             return null;
         Locale inputLocale = SubtypeSwitcher.getInstance().getInputLocale();
         if (inputLocale == null)
@@ -160,8 +160,7 @@
             getShortcutInputMethodsAndSubtypes() {
         Object retval = CompatUtils.invoke(mImm, null, METHOD_getShortcutInputMethodsAndSubtypes);
         if (retval == null || !(retval instanceof Map) || ((Map<?, ?>)retval).isEmpty()) {
-            if (InputMethodServiceCompatWrapper.
-                    CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) {
+            if (!FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES) {
                 // Returns an empty map
                 return Collections.emptyMap();
             }
diff --git a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java
index d6afd06..828aea4 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java
@@ -47,11 +47,17 @@
     @SuppressWarnings("unused")
     public void notifyOnCurrentInputMethodSubtypeChanged(InputMethodSubtypeCompatWrapper subtype) {
         // Do nothing when the API level is 11 or later
-        if (CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) return;
+        // and FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES is not true
+        if (CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED && !InputMethodManagerCompatWrapper.
+                FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES) {
+            return;
+        }
         if (subtype == null) {
             subtype = mImm.getCurrentInputMethodSubtype();
         }
         if (subtype != null) {
+            if (!InputMethodManagerCompatWrapper.FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES
+                    && !subtype.isDummy()) return;
             if (!InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) {
                 LanguageSwitcherProxy.getInstance().setLocale(subtype.getLocale());
             }
diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
index 86c8af3..806c355 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
@@ -116,6 +116,10 @@
         return (String)CompatUtils.invoke(mObj, null, METHOD_getExtraValueOf, key);
     }
 
+    public boolean isDummy() {
+        return !hasOriginalObject();
+    }
+
     @Override
     public boolean equals(Object o) {
         if (o instanceof InputMethodSubtypeCompatWrapper) {
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index 7b334ac..f01a81d 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -258,6 +258,8 @@
         }
     }
 
+
+    /* Damerau-Levenshtein distance */
     public static int editDistance(CharSequence s, CharSequence t) {
         if (s == null || t == null) {
             throw new IllegalArgumentException("editDistance: Arguments should not be null.");
@@ -273,14 +275,29 @@
         }
         for (int i = 0; i < sl; ++i) {
             for (int j = 0; j < tl; ++j) {
-                if (Character.toLowerCase(s.charAt(i)) == Character.toLowerCase(t.charAt(j))) {
-                    dp[i + 1][j + 1] = dp[i][j];
-                } else {
-                    dp[i + 1][j + 1] = 1 + Math.min(dp[i][j],
-                            Math.min(dp[i + 1][j], dp[i][j + 1]));
+                final char sc = Character.toLowerCase(s.charAt(i));
+                final char tc = Character.toLowerCase(t.charAt(j));
+                final int cost = sc == tc ? 0 : 1;
+                dp[i + 1][j + 1] = Math.min(
+                        dp[i][j + 1] + 1, Math.min(dp[i + 1][j] + 1, dp[i][j] + cost));
+                // Overwrite for transposition cases
+                if (i > 0 && j > 0
+                        && sc == Character.toLowerCase(t.charAt(j - 1))
+                        && tc == Character.toLowerCase(s.charAt(i - 1))) {
+                    dp[i + 1][j + 1] = Math.min(dp[i + 1][j + 1], dp[i - 1][j - 1] + cost);
                 }
             }
         }
+        if (LatinImeLogger.sDBG) {
+            Log.d(TAG, "editDistance:" + s + "," + t);
+            for (int i = 0; i < dp.length; ++i) {
+                StringBuffer sb = new StringBuffer();
+                for (int j = 0; j < dp[i].length; ++j) {
+                    sb.append(dp[i][j]).append(',');
+                }
+                Log.d(TAG, i + ":" + sb.toString());
+            }
+        }
         return dp[sl][tl];
     }
 
diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp
index 3832d47..b9f4b96 100644
--- a/native/src/unigram_dictionary.cpp
+++ b/native/src/unigram_dictionary.cpp
@@ -574,7 +574,7 @@
                     * (10 * mInputLength - WORDS_WITH_MISSING_CHARACTER_DEMOTION_START_POS_10X)
                     / (10 * mInputLength
                             - WORDS_WITH_MISSING_CHARACTER_DEMOTION_START_POS_10X + 10);
-            if (DEBUG_DICT) {
+            if (DEBUG_DICT_FULL) {
                 LOGI("Demotion rate for missing character is %d.", demotionRate);
             }
             multiplyRate(demotionRate, &finalFreq);
@@ -603,7 +603,7 @@
         if (sameLength && transposedPos < 0 && skipPos < 0 && excessivePos < 0) {
             finalFreq = capped255MultForFullMatchAccentsOrCapitalizationDifference(finalFreq);
         }
-    } else if (sameLength && transposedPos < 0 && skipPos < 0 && excessivePos < 0 && depth > 1) {
+    } else if (sameLength && transposedPos < 0 && skipPos < 0 && excessivePos < 0 && depth > 0) {
         // A word with proximity corrections
         if (DEBUG_DICT) {
             LOGI("Found one proximity correction.");
@@ -611,6 +611,9 @@
         finalFreq *= 2;
         multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq);
     }
+    if (DEBUG_DICT) {
+        LOGI("calc: %d, %d", depth, sameLength);
+    }
     if (sameLength) finalFreq *= FULL_WORD_MULTIPLIER;
     return finalFreq;
 }