Merge "[CB10] Add an event for string input"
diff --git a/java/res/values-iw-sw600dp/config-spacing-and-punctuations.xml b/java/res/values-iw-sw600dp/config-spacing-and-punctuations.xml
new file mode 100644
index 0000000..b562b18
--- /dev/null
+++ b/java/res/values-iw-sw600dp/config-spacing-and-punctuations.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- The all letters need to be mirrored are found at
+         http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt -->
+    <!-- Symbols that are suggested between words -->
+    <string name="suggested_punctuations" translatable="false">:,;,\",(|),)|(,\',-,/,@,_</string>
+</resources>
diff --git a/java/res/values-iw/config-spacing-and-punctuations.xml b/java/res/values-iw/config-spacing-and-punctuations.xml
new file mode 100644
index 0000000..9a9e6ee
--- /dev/null
+++ b/java/res/values-iw/config-spacing-and-punctuations.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- The all letters need to be mirrored are found at
+         http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt -->
+    <!-- Symbols that are suggested between words -->
+    <string name="suggested_punctuations" translatable="false">!,?,\\,,:,;,\",(|),)|(,\',-,/,@,_</string>
+</resources>
diff --git a/java/res/values-sw600dp/config-spacing-and-punctuations.xml b/java/res/values-sw600dp/config-spacing-and-punctuations.xml
index 9c12cf4..4d19412 100644
--- a/java/res/values-sw600dp/config-spacing-and-punctuations.xml
+++ b/java/res/values-sw600dp/config-spacing-and-punctuations.xml
@@ -19,5 +19,5 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Symbols that are suggested between words -->
-    <string name="suggested_punctuations" translatable="false">:,;,\",!text/keyspec_left_parenthesis,!text/keyspec_right_parenthesis,\',-,/,@,_</string>
+    <string name="suggested_punctuations" translatable="false">:,;,\",(,),\',-,/,@,_</string>
 </resources>
diff --git a/java/res/values/config-spacing-and-punctuations.xml b/java/res/values/config-spacing-and-punctuations.xml
index 1dd2e1f..ad5663d 100644
--- a/java/res/values/config-spacing-and-punctuations.xml
+++ b/java/res/values/config-spacing-and-punctuations.xml
@@ -21,7 +21,7 @@
     <!-- TODO: these settings depend on the language. They should be put either in the dictionary
          header, or in the subtype maybe? -->
     <!-- Symbols that are suggested between words -->
-    <string name="suggested_punctuations" translatable="false">!,?,\\,,:,;,\",!text/keyspec_left_parenthesis,!text/keyspec_right_parenthesis,\',-,/,@,_</string>
+    <string name="suggested_punctuations" translatable="false">!,?,\\,,:,;,\",(,),\',-,/,@,_</string>
     <!-- Symbols that are normally preceded by a space (used to add an auto-space before these) -->
     <string name="symbols_preceded_by_space" translatable="false">([{&amp;</string>
     <!-- Symbols that are normally followed by a space (used to add an auto-space after these) -->
diff --git a/java/res/xml-sw600dp/keys_pcqwerty2_right3.xml b/java/res/xml-sw600dp/keys_pcqwerty2_right3.xml
index ab99ec5..76ac6bb 100644
--- a/java/res/xml-sw600dp/keys_pcqwerty2_right3.xml
+++ b/java/res/xml-sw600dp/keys_pcqwerty2_right3.xml
@@ -23,7 +23,7 @@
 >
     <switch>
         <case
-            latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
+            latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked"
         >
             <Key
                 latin:keySpec="["
diff --git a/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml b/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml
index 5443396..f18fb50 100644
--- a/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml
+++ b/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml
@@ -23,7 +23,7 @@
 >
     <switch>
         <case
-            latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
+            latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked"
         >
             <Key
                 latin:keySpec=";"
diff --git a/java/res/xml-sw600dp/keys_pcqwerty4_right3.xml b/java/res/xml-sw600dp/keys_pcqwerty4_right3.xml
index c95ca2e..ff1a2c8 100644
--- a/java/res/xml-sw600dp/keys_pcqwerty4_right3.xml
+++ b/java/res/xml-sw600dp/keys_pcqwerty4_right3.xml
@@ -23,7 +23,7 @@
 >
     <switch>
         <case
-            latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
+            latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked"
         >
             <Key
                 latin:keySpec=","
diff --git a/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml b/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml
index 5389e22..5c7506e 100644
--- a/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml
+++ b/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml
@@ -21,87 +21,98 @@
 <merge
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
 >
-    <Key
-        latin:keySpec="`"
-        latin:keyHintLabel="~"
-        latin:additionalMoreKeys="~"
-        latin:keyStyle="hasShiftedLetterHintStyle" />
-    <Key
-        latin:keySpec="1"
-        latin:keyHintLabel="!"
-        latin:additionalMoreKeys="!"
-        latin:keyStyle="hasShiftedLetterHintStyle"
-        latin:moreKeys="!text/more_keys_for_exclamation,!text/more_keys_for_symbols_1" />
-    <Key
-        latin:keySpec="2"
-        latin:keyHintLabel="\@"
-        latin:additionalMoreKeys="\@"
-        latin:keyStyle="hasShiftedLetterHintStyle"
-        latin:moreKeys="!text/more_keys_for_symbols_2" />
-    <Key
-        latin:keySpec="3"
-        latin:keyHintLabel="\#"
-        latin:additionalMoreKeys="\#"
-        latin:keyStyle="hasShiftedLetterHintStyle"
-        latin:moreKeys="!text/more_keys_for_symbols_3" />
-    <Key
-        latin:keySpec="4"
-        latin:keyHintLabel="$"
-        latin:additionalMoreKeys="$"
-        latin:keyStyle="hasShiftedLetterHintStyle"
-        latin:moreKeys="!text/more_keys_for_symbols_4" />
-    <Key
-        latin:keySpec="5"
-        latin:keyHintLabel="%"
-        latin:additionalMoreKeys="\\%"
-        latin:keyStyle="hasShiftedLetterHintStyle"
-        latin:moreKeys="!text/more_keys_for_symbols_5" />
-    <Key
-        latin:keySpec="6"
-        latin:keyHintLabel="^"
-        latin:additionalMoreKeys="^"
-        latin:keyStyle="hasShiftedLetterHintStyle"
-        latin:moreKeys="!text/more_keys_for_symbols_6" />
-    <Key
-        latin:keySpec="7"
-        latin:keyHintLabel="&amp;"
-        latin:additionalMoreKeys="&amp;"
-        latin:keyStyle="hasShiftedLetterHintStyle"
-        latin:moreKeys="!text/more_keys_for_symbols_7" />
-    <Key
-        latin:keySpec="8"
-        latin:keyHintLabel="*"
-        latin:additionalMoreKeys="*"
-        latin:keyStyle="hasShiftedLetterHintStyle"
-        latin:moreKeys="!text/more_keys_for_symbols_8" />
-    <Key
-        latin:keySpec="9"
-        latin:keyHintLabel="("
-        latin:additionalMoreKeys="("
-        latin:keyStyle="hasShiftedLetterHintStyle"
-        latin:moreKeys="!text/more_keys_for_symbols_9" />
-    <Key
-        latin:keySpec="0"
-        latin:keyHintLabel=")"
-        latin:additionalMoreKeys=")"
-        latin:keyStyle="hasShiftedLetterHintStyle"
-        latin:moreKeys="!text/more_keys_for_symbols_0" />
-    <!-- U+2013: "–" EN DASH
-         U+2014: "—" EM DASH
-         U+00B7: "·" MIDDLE DOT -->
-    <Key
-        latin:keySpec="-"
-        latin:keyHintLabel="_"
-        latin:additionalMoreKeys="_"
-        latin:keyStyle="hasShiftedLetterHintStyle"
-        latin:moreKeys="&#x2013;,&#x2014;,&#x00B7;" />
-    <!-- U+221E: "∞" INFINITY
-         U+2260: "≠" NOT EQUAL TO
-         U+2248: "≈" ALMOST EQUAL TO -->
-    <Key
-        latin:keySpec="="
-        latin:keyHintLabel="+"
-        latin:additionalMoreKeys="+"
-        latin:keyStyle="hasShiftedLetterHintStyle"
-        latin:moreKeys="&#x221E;,&#x2260;,&#x2248;" />
+    <switch>
+        <case
+            latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked"
+        >
+            <Key
+                latin:keySpec="`"
+                latin:keyHintLabel="~"
+                latin:additionalMoreKeys="~"
+                latin:keyStyle="hasShiftedLetterHintStyle" />
+            <Key
+                latin:keySpec="1"
+                latin:keyHintLabel="!"
+                latin:additionalMoreKeys="!"
+                latin:keyStyle="hasShiftedLetterHintStyle"
+                latin:moreKeys="!text/more_keys_for_exclamation,!text/more_keys_for_symbols_1" />
+            <Key
+                latin:keySpec="2"
+                latin:keyHintLabel="\@"
+                latin:additionalMoreKeys="\@"
+                latin:keyStyle="hasShiftedLetterHintStyle"
+                latin:moreKeys="!text/more_keys_for_symbols_2" />
+            <Key
+                latin:keySpec="3"
+                latin:keyHintLabel="\#"
+                latin:additionalMoreKeys="\#"
+                latin:keyStyle="hasShiftedLetterHintStyle"
+                latin:moreKeys="!text/more_keys_for_symbols_3" />
+            <Key
+                latin:keySpec="4"
+                latin:keyHintLabel="$"
+                latin:additionalMoreKeys="$"
+                latin:keyStyle="hasShiftedLetterHintStyle"
+                latin:moreKeys="!text/more_keys_for_symbols_4" />
+            <Key
+                latin:keySpec="5"
+                latin:keyHintLabel="%"
+                latin:additionalMoreKeys="\\%"
+                latin:keyStyle="hasShiftedLetterHintStyle"
+                latin:moreKeys="!text/more_keys_for_symbols_5" />
+            <Key
+                latin:keySpec="6"
+                latin:keyHintLabel="^"
+                latin:additionalMoreKeys="^"
+                latin:keyStyle="hasShiftedLetterHintStyle"
+                latin:moreKeys="!text/more_keys_for_symbols_6" />
+            <Key
+                latin:keySpec="7"
+                latin:keyHintLabel="&amp;"
+                latin:additionalMoreKeys="&amp;"
+                latin:keyStyle="hasShiftedLetterHintStyle"
+                latin:moreKeys="!text/more_keys_for_symbols_7" />
+            <Key
+                latin:keySpec="8"
+                latin:keyHintLabel="*"
+                latin:additionalMoreKeys="*"
+                latin:keyStyle="hasShiftedLetterHintStyle"
+                latin:moreKeys="!text/more_keys_for_symbols_8" />
+            <Key
+                latin:keySpec="9"
+                latin:keyHintLabel="("
+                latin:additionalMoreKeys="("
+                latin:keyStyle="hasShiftedLetterHintStyle"
+                latin:moreKeys="!text/more_keys_for_symbols_9" />
+            <Key
+                latin:keySpec="0"
+                latin:keyHintLabel=")"
+                latin:additionalMoreKeys=")"
+                latin:keyStyle="hasShiftedLetterHintStyle"
+                latin:moreKeys="!text/more_keys_for_symbols_0" />
+            <!-- U+2013: "–" EN DASH
+                 U+2014: "—" EM DASH
+                 U+00B7: "·" MIDDLE DOT -->
+            <Key
+                latin:keySpec="-"
+                latin:keyHintLabel="_"
+                latin:additionalMoreKeys="_"
+                latin:keyStyle="hasShiftedLetterHintStyle"
+                latin:moreKeys="&#x2013;,&#x2014;,&#x00B7;" />
+            <!-- U+221E: "∞" INFINITY
+                 U+2260: "≠" NOT EQUAL TO
+                 U+2248: "≈" ALMOST EQUAL TO -->
+            <Key
+                latin:keySpec="="
+                latin:keyHintLabel="+"
+                latin:additionalMoreKeys="+"
+                latin:keyStyle="hasShiftedLetterHintStyle"
+                latin:moreKeys="&#x221E;,&#x2260;,&#x2248;" />
+        </case>
+        <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted" -->
+        <default>
+            <include
+                 latin:keyboardLayout="@xml/rowkeys_pcqwerty1_shift" />
+        </default>
+    </switch>
 </merge>
diff --git a/java/res/xml-sw600dp/rows_pcqwerty.xml b/java/res/xml-sw600dp/rows_pcqwerty.xml
index b503d83..73b7e47 100644
--- a/java/res/xml-sw600dp/rows_pcqwerty.xml
+++ b/java/res/xml-sw600dp/rows_pcqwerty.xml
@@ -26,19 +26,8 @@
     <Row
         latin:keyWidth="7.0%p"
     >
-        <switch>
-            <case
-                latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
-            >
-                <include
-                    latin:keyboardLayout="@xml/rowkeys_pcqwerty1" />
-            </case>
-            <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" -->
-            <default>
-                <include
-                     latin:keyboardLayout="@xml/rowkeys_pcqwerty1_shift" />
-            </default>
-        </switch>
+        <include
+            latin:keyboardLayout="@xml/rowkeys_pcqwerty1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml/keys_pcqwerty2_right3.xml b/java/res/xml/keys_pcqwerty2_right3.xml
index 9e62b09..b188cff 100644
--- a/java/res/xml/keys_pcqwerty2_right3.xml
+++ b/java/res/xml/keys_pcqwerty2_right3.xml
@@ -23,7 +23,7 @@
 >
     <switch>
         <case
-            latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
+            latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked"
         >
             <Key
                 latin:keySpec="["
diff --git a/java/res/xml/keys_pcqwerty3_right2.xml b/java/res/xml/keys_pcqwerty3_right2.xml
index d889216..8a1f60f 100644
--- a/java/res/xml/keys_pcqwerty3_right2.xml
+++ b/java/res/xml/keys_pcqwerty3_right2.xml
@@ -23,7 +23,7 @@
 >
     <switch>
         <case
-            latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
+            latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked"
         >
             <Key
                 latin:keySpec=";"
diff --git a/java/res/xml/keys_pcqwerty4_right3.xml b/java/res/xml/keys_pcqwerty4_right3.xml
index f32d809..6beba20 100644
--- a/java/res/xml/keys_pcqwerty4_right3.xml
+++ b/java/res/xml/keys_pcqwerty4_right3.xml
@@ -23,7 +23,7 @@
 >
     <switch>
         <case
-            latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
+            latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked"
         >
             <Key
                 latin:keySpec=","
diff --git a/java/res/xml/rowkeys_pcqwerty1.xml b/java/res/xml/rowkeys_pcqwerty1.xml
index fdb5072..3695733 100644
--- a/java/res/xml/rowkeys_pcqwerty1.xml
+++ b/java/res/xml/rowkeys_pcqwerty1.xml
@@ -21,61 +21,72 @@
 <merge
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
 >
-    <Key
-        latin:keySpec="`"
-        latin:additionalMoreKeys="~" />
-    <Key
-        latin:keySpec="1"
-        latin:additionalMoreKeys="!,!text/more_keys_for_exclamation"
-        latin:moreKeys="!text/more_keys_for_symbols_1" />
-    <Key
-        latin:keySpec="2"
-        latin:additionalMoreKeys="\@"
-        latin:moreKeys="!text/more_keys_for_symbols_2" />
-    <Key
-        latin:keySpec="3"
-        latin:additionalMoreKeys="\#"
-        latin:moreKeys="!text/more_keys_for_symbols_3" />
-    <Key
-        latin:keySpec="4"
-        latin:additionalMoreKeys="$"
-        latin:moreKeys="!text/more_keys_for_symbols_4" />
-    <Key
-        latin:keySpec="5"
-        latin:additionalMoreKeys="\\%"
-        latin:moreKeys="!text/more_keys_for_symbols_5" />
-    <Key
-        latin:keySpec="6"
-        latin:additionalMoreKeys="^"
-        latin:moreKeys="!text/more_keys_for_symbols_6" />
-    <Key
-        latin:keySpec="7"
-        latin:additionalMoreKeys="&amp;"
-        latin:moreKeys="!text/more_keys_for_symbols_7" />
-    <Key
-        latin:keySpec="8"
-        latin:additionalMoreKeys="*"
-        latin:moreKeys="!text/more_keys_for_symbols_8" />
-    <Key
-        latin:keySpec="9"
-        latin:additionalMoreKeys="("
-        latin:moreKeys="!text/more_keys_for_symbols_9" />
-    <Key
-        latin:keySpec="0"
-        latin:additionalMoreKeys=")"
-        latin:moreKeys="!text/more_keys_for_symbols_0" />
-    <!-- U+2013: "–" EN DASH
-         U+2014: "—" EM DASH
-         U+00B7: "·" MIDDLE DOT -->
-    <Key
-        latin:keySpec="-"
-        latin:additionalMoreKeys="_"
-        latin:moreKeys="&#x2013;,&#x2014;,&#x00B7;" />
-    <!-- U+221E: "∞" INFINITY
-         U+2260: "≠" NOT EQUAL TO
-         U+2248: "≈" ALMOST EQUAL TO -->
-    <Key
-        latin:keySpec="="
-        latin:additionalMoreKeys="+"
-        latin:moreKeys="!fixedColumnOrder!4,&#x221E;,&#x2260;,&#x2248;,%" />
+    <switch>
+        <case
+            latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked"
+        >
+            <Key
+                latin:keySpec="`"
+                latin:additionalMoreKeys="~" />
+            <Key
+                latin:keySpec="1"
+                latin:additionalMoreKeys="!,!text/more_keys_for_exclamation"
+                latin:moreKeys="!text/more_keys_for_symbols_1" />
+            <Key
+                latin:keySpec="2"
+                latin:additionalMoreKeys="\@"
+                latin:moreKeys="!text/more_keys_for_symbols_2" />
+            <Key
+                latin:keySpec="3"
+                latin:additionalMoreKeys="\#"
+                latin:moreKeys="!text/more_keys_for_symbols_3" />
+            <Key
+                latin:keySpec="4"
+                latin:additionalMoreKeys="$"
+                latin:moreKeys="!text/more_keys_for_symbols_4" />
+            <Key
+                latin:keySpec="5"
+                latin:additionalMoreKeys="\\%"
+                latin:moreKeys="!text/more_keys_for_symbols_5" />
+            <Key
+                latin:keySpec="6"
+                latin:additionalMoreKeys="^"
+                latin:moreKeys="!text/more_keys_for_symbols_6" />
+            <Key
+                latin:keySpec="7"
+                latin:additionalMoreKeys="&amp;"
+                latin:moreKeys="!text/more_keys_for_symbols_7" />
+            <Key
+                latin:keySpec="8"
+                latin:additionalMoreKeys="*"
+                latin:moreKeys="!text/more_keys_for_symbols_8" />
+            <Key
+                latin:keySpec="9"
+                latin:additionalMoreKeys="("
+                latin:moreKeys="!text/more_keys_for_symbols_9" />
+            <Key
+                latin:keySpec="0"
+                latin:additionalMoreKeys=")"
+                latin:moreKeys="!text/more_keys_for_symbols_0" />
+            <!-- U+2013: "–" EN DASH
+                 U+2014: "—" EM DASH
+                 U+00B7: "·" MIDDLE DOT -->
+            <Key
+                latin:keySpec="-"
+                latin:additionalMoreKeys="_"
+                latin:moreKeys="&#x2013;,&#x2014;,&#x00B7;" />
+            <!-- U+221E: "∞" INFINITY
+                 U+2260: "≠" NOT EQUAL TO
+                 U+2248: "≈" ALMOST EQUAL TO -->
+            <Key
+                latin:keySpec="="
+                latin:additionalMoreKeys="+"
+                latin:moreKeys="!fixedColumnOrder!4,&#x221E;,&#x2260;,&#x2248;,%" />
+        </case>
+        <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted" -->
+        <default>
+            <include
+                 latin:keyboardLayout="@xml/rowkeys_pcqwerty1_shift" />
+        </default>
+    </switch>
 </merge>
diff --git a/java/res/xml/rows_pcqwerty.xml b/java/res/xml/rows_pcqwerty.xml
index 8846989..a5ed745 100644
--- a/java/res/xml/rows_pcqwerty.xml
+++ b/java/res/xml/rows_pcqwerty.xml
@@ -26,19 +26,8 @@
     <Row
         latin:keyWidth="7.692%p"
     >
-        <switch>
-            <case
-                latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
-            >
-                <include
-                    latin:keyboardLayout="@xml/rowkeys_pcqwerty1" />
-            </case>
-            <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" -->
-            <default>
-                <include
-                     latin:keyboardLayout="@xml/rowkeys_pcqwerty1_shift" />
-            </default>
-        </switch>
+        <include
+            latin:keyboardLayout="@xml/rowkeys_pcqwerty1" />
     </Row>
     <Row
         latin:keyWidth="7.692%p"
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 66cb9e3..2dfde94 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -163,7 +163,7 @@
         mCurrentSettingsValues = settingsValues;
         try {
             mState.onLoadKeyboard();
-            mKeyboardTextsSet.setLocale(mSubtypeSwitcher.getCurrentSubtypeLocale());
+            mKeyboardTextsSet.setLocale(mSubtypeSwitcher.getCurrentSubtypeLocale(), mThemeContext);
         } catch (KeyboardLayoutSetException e) {
             Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause());
             LatinImeLogger.logOnException(e.mKeyboardId.toString(), e.getCause());
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
index 81a8e71..dfe0df0 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
@@ -34,7 +34,6 @@
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.utils.ResourceUtils;
-import com.android.inputmethod.latin.utils.RunInLocale;
 import com.android.inputmethod.latin.utils.StringUtils;
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
 import com.android.inputmethod.latin.utils.XmlParseUtils;
@@ -45,7 +44,6 @@
 
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.Locale;
 
 /**
  * Keyboard Building helper.
@@ -278,18 +276,7 @@
 
             params.mThemeId = keyboardAttr.getInt(R.styleable.Keyboard_themeId, 0);
             params.mIconsSet.loadIcons(keyboardAttr);
-            final Locale locale = params.mId.mLocale;
-            params.mTextsSet.setLocale(locale);
-            final RunInLocale<Void> job = new RunInLocale<Void>() {
-                @Override
-                protected Void job(final Resources res) {
-                    params.mTextsSet.loadStringResources(mContext);
-                    return null;
-                }
-            };
-            // Null means the current system locale.
-            job.runInLocale(mResources,
-                    SubtypeLocaleUtils.isNoLanguage(params.mId.mSubtype) ? null : locale);
+            params.mTextsSet.setLocale(params.mId.mLocale, mContext);
 
             final int resourceId = keyboardAttr.getResourceId(
                     R.styleable.Keyboard_touchPositionCorrectionData, 0);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index 976038c..044cd11 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -23,6 +23,8 @@
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.RunInLocale;
+import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
 
 import java.util.HashMap;
 import java.util.Locale;
@@ -38,23 +40,29 @@
     // Resource name to text map.
     private HashMap<String, String> mResourceNameToTextsMap = CollectionUtils.newHashMap();
 
-    public void setLocale(final Locale locale) {
+    public void setLocale(final Locale locale, final Context context) {
         final String language = locale.getLanguage();
         mTextsTable = KeyboardTextsTable.getTextsTable(language);
-    }
-
-    public void loadStringResources(final Context context) {
+        final Resources res = context.getResources();
         final int referenceId = context.getApplicationInfo().labelRes;
-        loadStringResourcesInternal(context, RESOURCE_NAMES, referenceId);
+        final String resourcePackageName = res.getResourcePackageName(referenceId);
+        final RunInLocale<Void> job = new RunInLocale<Void>() {
+            @Override
+            protected Void job(final Resources resource) {
+                loadStringResourcesInternal(res, RESOURCE_NAMES, resourcePackageName);
+                return null;
+            }
+        };
+        // Null means the current system locale.
+        job.runInLocale(res,
+                SubtypeLocaleUtils.NO_LANGUAGE.equals(locale.toString()) ? null : locale);
     }
 
     @UsedForTesting
-    void loadStringResourcesInternal(final Context context, final String[] resourceNames,
-            final int referenceId) {
-        final Resources res = context.getResources();
-        final String packageName = res.getResourcePackageName(referenceId);
+    void loadStringResourcesInternal(final Resources res, final String[] resourceNames,
+            final String resourcePackageName) {
         for (final String resName : resourceNames) {
-            final int resId = res.getIdentifier(resName, "string", packageName);
+            final int resId = res.getIdentifier(resName, "string", resourcePackageName);
             mResourceNameToTextsMap.put(resName, res.getString(resId));
         }
     }
@@ -77,6 +85,7 @@
         return size;
     }
 
+    // TODO: Resolve text reference when creating {@link KeyboardTextsTable} class.
     public String resolveTextReference(final String rawText) {
         if (TextUtils.isEmpty(rawText)) {
             return null;
@@ -127,7 +136,7 @@
 
     // These texts' name should be aligned with the @string/<name> in
     // values*/strings-action-keys.xml.
-    private static final String[] RESOURCE_NAMES = {
+    static final String[] RESOURCE_NAMES = {
         // Labels for action.
         "label_go_key",
         "label_send_key",
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 544fd03..0aa34e8 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -161,9 +161,9 @@
     private static native int getNextWordNative(long dict, int token, int[] outCodePoints);
     private static native void getSuggestionsNative(long dict, long proximityInfo,
             long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times,
-            int[] pointerIds, int[] inputCodePoints, int inputSize, int commitPoint,
-            int[] suggestOptions, int[] prevWordCodePointArray, int[] outputSuggestionCount,
-            int[] outputCodePoints, int[] outputScores, int[] outputIndices, int[] outputTypes,
+            int[] pointerIds, int[] inputCodePoints, int inputSize, int[] suggestOptions,
+            int[] prevWordCodePointArray, int[] outputSuggestionCount, int[] outputCodePoints,
+            int[] outputScores, int[] outputIndices, int[] outputTypes,
             int[] outputAutoCommitFirstWordConfidence);
     private static native void addUnigramWordNative(long dict, int[] word, int probability,
             int[] shortcutTarget, int shortcutProbability, boolean isNotAWord,
@@ -262,7 +262,7 @@
         getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(),
                 getTraverseSession(sessionId).getSession(), ips.getXCoordinates(),
                 ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), mInputCodePoints,
-                inputSize, 0 /* commitPoint */, mNativeSuggestOptions.getOptions(),
+                inputSize, mNativeSuggestOptions.getOptions(),
                 prevWordCodePointArray, mOutputSuggestionCount, mOutputCodePoints, mOutputScores,
                 mSpaceIndices, mOutputTypes, mOutputAutoCommitFirstWordConfidence);
         final int count = mOutputSuggestionCount[0];
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 714ef0a..38e3864 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -169,7 +169,6 @@
 
         private int mDelayUpdateSuggestions;
         private int mDelayUpdateShiftState;
-        private long mDoubleSpacePeriodTimerStart;
 
         public UIHandler(final LatinIME ownerInstance) {
             super(ownerInstance);
@@ -283,10 +282,6 @@
             sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mDelayUpdateShiftState);
         }
 
-        public void cancelUpdateShiftState() {
-            removeMessages(MSG_UPDATE_SHIFT_STATE);
-        }
-
         @UsedForTesting
         public void removeAllMessages() {
             for (int i = 0; i <= MSG_LAST; ++i) {
@@ -314,19 +309,6 @@
             obtainMessage(MSG_ON_END_BATCH_INPUT, suggestedWords).sendToTarget();
         }
 
-        public void startDoubleSpacePeriodTimer() {
-            mDoubleSpacePeriodTimerStart = SystemClock.uptimeMillis();
-        }
-
-        public void cancelDoubleSpacePeriodTimer() {
-            mDoubleSpacePeriodTimerStart = 0;
-        }
-
-        public boolean isAcceptingDoubleSpacePeriod() {
-            return SystemClock.uptimeMillis() - mDoubleSpacePeriodTimerStart
-                    < getOwnerInstance().mSettings.getCurrent().mDoubleSpacePeriodTimeout;
-        }
-
         // Working variables for the following methods.
         private boolean mIsOrientationChanging;
         private boolean mPendingSuccessiveImsCallback;
@@ -882,7 +864,6 @@
         setNeutralSuggestionStrip();
 
         mHandler.cancelUpdateSuggestionStrip();
-        mHandler.cancelDoubleSpacePeriodTimer();
 
         mainKeyboardView.setMainDictionaryAvailability(null != suggest
                 ? suggest.mDictionaryFacilitator.hasMainDictionary() : false);
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 62c752e..36b30ea 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -95,6 +95,7 @@
     // TODO: This boolean is persistent state and causes large side effects at unexpected times.
     // Find a way to remove it for readability.
     private boolean mIsAutoCorrectionIndicatorOn;
+    private long mDoubleSpacePeriodCountdownStart;
 
     public InputLogic(final LatinIME latinIME,
             final SuggestionStripViewAccessor suggestionStripViewAccessor) {
@@ -137,6 +138,7 @@
         // In some cases (namely, after rotation of the device) editorInfo.initialSelStart is lying
         // so we try using some heuristics to find out about these and fix them.
         mConnection.tryFixLyingCursorPosition();
+        cancelDoubleSpacePeriodCountdown();
         mInputLogicHandler = new InputLogicHandler(mLatinIME, this);
     }
 
@@ -406,7 +408,7 @@
 
         // TODO: Consolidate the double-space period timer, mLastKeyTime, and the space state.
         if (event.mCodePoint != Constants.CODE_SPACE) {
-            handler.cancelDoubleSpacePeriodTimer();
+            cancelDoubleSpacePeriodCountdown();
         }
 
         boolean didAutoCorrect = false;
@@ -847,7 +849,7 @@
 
         if (Constants.CODE_SPACE == codePoint) {
             if (inputTransaction.mSettingsValues.isSuggestionsRequested()) {
-                if (maybeDoubleSpacePeriod(inputTransaction.mSettingsValues, handler)) {
+                if (maybeDoubleSpacePeriod(inputTransaction)) {
                     inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
                     mSpaceState = SpaceState.DOUBLE;
                 } else if (!mSuggestedWords.isPunctuationSuggestions()) {
@@ -855,7 +857,7 @@
                 }
             }
 
-            handler.startDoubleSpacePeriodTimer();
+            startDoubleSpacePeriodCountdown(inputTransaction);
             handler.postUpdateSuggestionStrip();
         } else {
             if (swapWeakSpace) {
@@ -952,7 +954,7 @@
                 return;
             }
             if (SpaceState.DOUBLE == inputTransaction.mSpaceState) {
-                handler.cancelDoubleSpacePeriodTimer();
+                cancelDoubleSpacePeriodCountdown();
                 if (mConnection.revertDoubleSpacePeriod()) {
                     // No need to reset mSpaceState, it has already be done (that's why we
                     // receive it as a parameter)
@@ -1100,6 +1102,19 @@
         return false;
     }
 
+    public void startDoubleSpacePeriodCountdown(final InputTransaction inputTransaction) {
+        mDoubleSpacePeriodCountdownStart = inputTransaction.mTimestamp;
+    }
+
+    public void cancelDoubleSpacePeriodCountdown() {
+        mDoubleSpacePeriodCountdownStart = 0;
+    }
+
+    public boolean isDoubleSpacePeriodCountdownActive(final InputTransaction inputTransaction) {
+        return inputTransaction.mTimestamp - mDoubleSpacePeriodCountdownStart
+                < inputTransaction.mSettingsValues.mDoubleSpacePeriodTimeout;
+    }
+
     /**
      * Apply the double-space-to-period transformation if applicable.
      *
@@ -1112,14 +1127,12 @@
      * method applies the transformation and returns true. Otherwise, it does nothing and
      * returns false.
      *
-     * @param settingsValues the current values of the settings.
+     * @param inputTransaction The transaction in progress.
      * @return true if we applied the double-space-to-period transformation, false otherwise.
      */
-    private boolean maybeDoubleSpacePeriod(final SettingsValues settingsValues,
-            // TODO: remove this argument
-            final LatinIME.UIHandler handler) {
-        if (!settingsValues.mUseDoubleSpacePeriod) return false;
-        if (!handler.isAcceptingDoubleSpacePeriod()) return false;
+    private boolean maybeDoubleSpacePeriod(final InputTransaction inputTransaction) {
+        if (!inputTransaction.mSettingsValues.mUseDoubleSpacePeriod) return false;
+        if (!isDoubleSpacePeriodCountdownActive(inputTransaction)) return false;
         // We only do this when we see two spaces and an accepted code point before the cursor.
         // The code point may be a surrogate pair but the two spaces may not, so we need 4 chars.
         final CharSequence lastThree = mConnection.getTextBeforeCursor(4, 0);
@@ -1135,10 +1148,10 @@
                 Character.isSurrogatePair(lastThree.charAt(0), lastThree.charAt(1)) ?
                         Character.codePointAt(lastThree, 0) : lastThree.charAt(length - 3);
         if (canBeFollowedByDoubleSpacePeriod(firstCodePoint)) {
-            handler.cancelDoubleSpacePeriodTimer();
+            cancelDoubleSpacePeriodCountdown();
             mConnection.deleteSurroundingText(2, 0);
-            final String textToInsert =
-                    settingsValues.mSpacingAndPunctuations.mSentenceSeparatorAndSpace;
+            final String textToInsert = inputTransaction.mSettingsValues.mSpacingAndPunctuations
+                    .mSentenceSeparatorAndSpace;
             mConnection.commitText(textToInsert, 1);
             if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
                 ResearchLogger.latinIME_maybeDoubleSpacePeriod(textToInsert,
diff --git a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
index 5954758..796921f 100644
--- a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
+++ b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
@@ -18,7 +18,6 @@
 
 import android.content.res.Resources;
 
-import com.android.inputmethod.keyboard.internal.KeyboardTextsSet;
 import com.android.inputmethod.keyboard.internal.MoreKeySpec;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.PunctuationSuggestions;
@@ -61,10 +60,8 @@
         // English variants. German rules (not "German typography") also have small gotchas.
         mUsesAmericanTypography = Locale.ENGLISH.getLanguage().equals(locale.getLanguage());
         mUsesGermanRules = Locale.GERMAN.getLanguage().equals(locale.getLanguage());
-        final KeyboardTextsSet textsSet = new KeyboardTextsSet();
-        textsSet.setLocale(locale);
         final String[] suggestPuncsSpec = MoreKeySpec.splitKeySpecs(
-                textsSet.resolveTextReference(res.getString(R.string.suggested_punctuations)));
+                res.getString(R.string.suggested_punctuations));
         mSuggestPuncList = PunctuationSuggestions.newPunctuationSuggestions(suggestPuncsSpec);
     }
 
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index eec354a..ac0b4ab 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -143,7 +143,7 @@
 static void latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, jlong dict,
         jlong proximityInfo, jlong dicTraverseSession, jintArray xCoordinatesArray,
         jintArray yCoordinatesArray, jintArray timesArray, jintArray pointerIdsArray,
-        jintArray inputCodePointsArray, jint inputSize, jint commitPoint, jintArray suggestOptions,
+        jintArray inputCodePointsArray, jint inputSize, jintArray suggestOptions,
         jintArray prevWordCodePointsForBigrams, jintArray outSuggestionCount,
         jintArray outCodePointsArray, jintArray outScoresArray, jintArray outSpaceIndicesArray,
         jintArray outTypesArray, jintArray outAutoCommitFirstWordConfidenceArray) {
@@ -220,7 +220,7 @@
         // TODO: Use SuggestionResults to return suggestions.
         count = dictionary->getSuggestions(pInfo, traverseSession, xCoordinates, yCoordinates,
                 times, pointerIds, inputCodePoints, inputSize, prevWordCodePoints,
-                prevWordCodePointsLength, commitPoint, &givenSuggestOptions, outputCodePoints,
+                prevWordCodePointsLength, &givenSuggestOptions, outputCodePoints,
                 scores, spaceIndices, outputTypes, outputAutoCommitFirstWordConfidence);
     } else {
         SuggestionResults suggestionResults(MAX_RESULTS);
@@ -506,7 +506,7 @@
     },
     {
         const_cast<char *>("getSuggestionsNative"),
-        const_cast<char *>("(JJJ[I[I[I[I[III[I[I[I[I[I[I[I[I)V"),
+        const_cast<char *>("(JJJ[I[I[I[I[II[I[I[I[I[I[I[I[I)V"),
         reinterpret_cast<void *>(latinime_BinaryDictionary_getSuggestions)
     },
     {
diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h
index 65dad56..ae228fb 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node.h
@@ -270,9 +270,10 @@
 
     bool hasMatchedOrProximityCodePoints() const {
         // This DicNode does not have matched or proximity code points when all code points have
-        // been handled as edit corrections so far.
-        return mDicNodeState.mDicNodeStateScoring.getEditCorrectionCount()
-                < getNodeCodePointCount();
+        // been handled as edit corrections or completion so far.
+        const int editCorrectionCount = mDicNodeState.mDicNodeStateScoring.getEditCorrectionCount();
+        const int completionCount = mDicNodeState.mDicNodeStateScoring.getCompletionCount();
+        return (editCorrectionCount + completionCount) < getNodeCodePointCount();
     }
 
     bool isTotalInputSizeExceedingLimit() const {
@@ -283,33 +284,6 @@
         return prevWordsLen + currentWordDepth > MAX_WORD_LENGTH - 3;
     }
 
-    // TODO: This may be defective. Needs to be revised.
-    bool truncateNode(const DicNode *const topNode, const int inputCommitPoint) {
-        const int prevWordLenOfTop = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength();
-        int newPrevWordStartIndex = inputCommitPoint;
-        int charCount = 0;
-        // Find new word start index
-        for (int i = 0; i < prevWordLenOfTop; ++i) {
-            const int c = mDicNodeState.mDicNodeStatePrevWord.getPrevWordCodePointAt(i);
-            // TODO: Check other separators.
-            if (c != KEYCODE_SPACE && c != KEYCODE_SINGLE_QUOTE) {
-                if (charCount == inputCommitPoint) {
-                    newPrevWordStartIndex = i;
-                    break;
-                }
-                ++charCount;
-            }
-        }
-        if (!mDicNodeState.mDicNodeStatePrevWord.startsWith(
-                &topNode->mDicNodeState.mDicNodeStatePrevWord, newPrevWordStartIndex - 1)) {
-            // Node mismatch.
-            return false;
-        }
-        mDicNodeState.mDicNodeStateInput.truncate(inputCommitPoint);
-        mDicNodeState.mDicNodeStatePrevWord.truncate(newPrevWordStartIndex);
-        return true;
-    }
-
     void outputResult(int *dest) const {
         const uint16_t prevWordLength = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength();
         const uint16_t currentDepth = getNodeCodePointCount();
diff --git a/native/jni/src/suggest/core/dicnode/dic_nodes_cache.cpp b/native/jni/src/suggest/core/dicnode/dic_nodes_cache.cpp
index b6be47e..ef4a6b5 100644
--- a/native/jni/src/suggest/core/dicnode/dic_nodes_cache.cpp
+++ b/native/jni/src/suggest/core/dicnode/dic_nodes_cache.cpp
@@ -28,37 +28,4 @@
 // Capacity for reducing memory footprint.
 const int DicNodesCache::SMALL_PRIORITY_QUEUE_CAPACITY = 100;
 
-/**
- * Truncates all of the dicNodes so that they start at the given commit point.
- * Only called for multi-word typing input.
- */
-DicNode *DicNodesCache::setCommitPoint(int commitPoint) {
-    std::list<DicNode> dicNodesList;
-    while (mCachedDicNodesForContinuousSuggestion->getSize() > 0) {
-        DicNode dicNode;
-        mCachedDicNodesForContinuousSuggestion->copyPop(&dicNode);
-        dicNodesList.push_front(dicNode);
-    }
-
-    // Get the starting words of the top scoring dicNode (last dicNode popped from priority queue)
-    // up to the commit point. These words have already been committed to the text view.
-    DicNode *topDicNode = &dicNodesList.front();
-    DicNode topDicNodeCopy;
-    DicNodeUtils::initByCopy(topDicNode, &topDicNodeCopy);
-
-    // Keep only those dicNodes that match the same starting words.
-    std::list<DicNode>::iterator iter;
-    for (iter = dicNodesList.begin(); iter != dicNodesList.end(); iter++) {
-        DicNode *dicNode = &*iter;
-        if (dicNode->truncateNode(&topDicNodeCopy, commitPoint)) {
-            mCachedDicNodesForContinuousSuggestion->copyPush(dicNode);
-        } else {
-            // Top dicNode should be reprocessed.
-            ASSERT(dicNode != topDicNode);
-            DicNode::managedDelete(dicNode);
-        }
-    }
-    mInputIndex -= commitPoint;
-    return topDicNode;
-}
 }  // namespace latinime
diff --git a/native/jni/src/suggest/core/dicnode/dic_nodes_cache.h b/native/jni/src/suggest/core/dicnode/dic_nodes_cache.h
index c31c056..d4769e7 100644
--- a/native/jni/src/suggest/core/dicnode/dic_nodes_cache.h
+++ b/native/jni/src/suggest/core/dicnode/dic_nodes_cache.h
@@ -76,8 +76,6 @@
                 moveNodesAndReturnReusableEmptyQueue(mNextActiveDicNodes, &mActiveDicNodes);
     }
 
-    DicNode *setCommitPoint(int commitPoint);
-
     int activeSize() const { return mActiveDicNodes->getSize(); }
     int terminalSize() const { return mTerminalDicNodes->getSize(); }
     bool isLookAheadCorrectionInputIndex(const int inputIndex) const {
diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_input.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_input.h
index 3d78811..03042a8 100644
--- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_input.h
+++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_input.h
@@ -27,11 +27,6 @@
     DicNodeStateInput() {}
     ~DicNodeStateInput() {}
 
-    // TODO: Merge into DicNodeStatePrevWord::truncate
-    void truncate(const int commitPoint) {
-        mInputIndex[0] -= commitPoint;
-    }
-
     void init() {
         for (int i = 0; i < MAX_POINTER_COUNT_G; i++) {
             // TODO: The initial value for mInputIndex should be -1?
diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h
index f2b1ce8..409841e 100644
--- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h
+++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h
@@ -70,18 +70,6 @@
         mSecondWordFirstInputIndex = prevWordSecondWordFirstInputIndex;
     }
 
-    void truncate(const int offset) {
-        // TODO: memmove
-        if (mPrevWordLength < offset) {
-            memset(mPrevWord, 0, sizeof(mPrevWord));
-            mPrevWordLength = 0;
-            return;
-        }
-        const int newPrevWordLength = mPrevWordLength - offset;
-        memmove(mPrevWord, &mPrevWord[offset], newPrevWordLength * sizeof(mPrevWord[0]));
-        mPrevWordLength = newPrevWordLength;
-    }
-
     void setSecondWordFirstInputIndex(const int inputIndex) {
         mSecondWordFirstInputIndex = inputIndex;
     }
@@ -111,18 +99,6 @@
         return mPrevWord[id];
     }
 
-    bool startsWith(const DicNodeStatePrevWord *const prefix, const int prefixLen) const {
-        if (prefixLen > mPrevWordLength) {
-            return false;
-        }
-        for (int i = 0; i < prefixLen; ++i) {
-            if (mPrevWord[i] != prefix->mPrevWord[i]) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     const int *getPrevWordBuf() const {
         return mPrevWord;
     }
diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h
index 458eac8..b0db55f 100644
--- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h
+++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h
@@ -31,7 +31,7 @@
     AK_FORCE_INLINE DicNodeStateScoring()
             : mDoubleLetterLevel(NOT_A_DOUBLE_LETTER),
               mDigraphIndex(DigraphUtils::NOT_A_DIGRAPH_INDEX),
-              mEditCorrectionCount(0), mProximityCorrectionCount(0),
+              mEditCorrectionCount(0), mProximityCorrectionCount(0), mCompletionCount(0),
               mNormalizedCompoundDistance(0.0f), mSpatialDistance(0.0f), mLanguageDistance(0.0f),
               mRawLength(0.0f), mContainedErrorTypes(ErrorTypeUtils::NOT_AN_ERROR),
               mNormalizedCompoundDistanceAfterFirstWord(MAX_VALUE_FOR_WEIGHTING) {
@@ -42,6 +42,7 @@
     void init() {
         mEditCorrectionCount = 0;
         mProximityCorrectionCount = 0;
+        mCompletionCount = 0;
         mNormalizedCompoundDistance = 0.0f;
         mSpatialDistance = 0.0f;
         mLanguageDistance = 0.0f;
@@ -55,6 +56,7 @@
     AK_FORCE_INLINE void init(const DicNodeStateScoring *const scoring) {
         mEditCorrectionCount = scoring->mEditCorrectionCount;
         mProximityCorrectionCount = scoring->mProximityCorrectionCount;
+        mCompletionCount = scoring->mCompletionCount;
         mNormalizedCompoundDistance = scoring->mNormalizedCompoundDistance;
         mSpatialDistance = scoring->mSpatialDistance;
         mLanguageDistance = scoring->mLanguageDistance;
@@ -77,6 +79,9 @@
         if (ErrorTypeUtils::isProximityCorrectionError(errorType)) {
             ++mProximityCorrectionCount;
         }
+        if (ErrorTypeUtils::isCompletion(errorType)) {
+            ++mCompletionCount;
+        }
     }
 
     // Saves the current normalized distance for space-aware gestures.
@@ -129,6 +134,10 @@
         return mProximityCorrectionCount;
     }
 
+    int16_t getCompletionCount() const {
+        return mCompletionCount;
+    }
+
     float getRawLength() const {
         return mRawLength;
     }
@@ -182,6 +191,7 @@
 
     int16_t mEditCorrectionCount;
     int16_t mProximityCorrectionCount;
+    int16_t mCompletionCount;
 
     float mNormalizedCompoundDistance;
     float mSpatialDistance;
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index c26e3aa..07b07f7 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -45,7 +45,7 @@
 
 int Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession,
         int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints,
-        int inputSize, int *prevWordCodePoints, int prevWordLength, int commitPoint,
+        int inputSize, int *prevWordCodePoints, int prevWordLength,
         const SuggestOptions *const suggestOptions, int *outWords, int *outputScores,
         int *spaceIndices, int *outputTypes, int *outputAutoCommitFirstWordConfidence) const {
     TimeKeeper::setCurrentTime();
@@ -54,7 +54,7 @@
         DicTraverseSession::initSessionInstance(
                 traverseSession, this, prevWordCodePoints, prevWordLength, suggestOptions);
         result = mGestureSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates,
-                ycoordinates, times, pointerIds, inputCodePoints, inputSize, commitPoint, outWords,
+                ycoordinates, times, pointerIds, inputCodePoints, inputSize, outWords,
                 outputScores, spaceIndices, outputTypes, outputAutoCommitFirstWordConfidence);
         if (DEBUG_DICT) {
             DUMP_RESULT(outWords, outputScores);
@@ -64,7 +64,7 @@
         DicTraverseSession::initSessionInstance(
                 traverseSession, this, prevWordCodePoints, prevWordLength, suggestOptions);
         result = mTypingSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates,
-                ycoordinates, times, pointerIds, inputCodePoints, inputSize, commitPoint,
+                ycoordinates, times, pointerIds, inputCodePoints, inputSize,
                 outWords, outputScores, spaceIndices, outputTypes,
                 outputAutoCommitFirstWordConfidence);
         if (DEBUG_DICT) {
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h
index ce032fc..4d482e7 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary.h
@@ -64,7 +64,7 @@
 
     int getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession,
             int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints,
-            int inputSize, int *prevWordCodePoints, int prevWordLength, int commitPoint,
+            int inputSize, int *prevWordCodePoints, int prevWordLength,
             const SuggestOptions *const suggestOptions, int *outWords, int *outputScores,
             int *spaceIndices, int *outputTypes, int *outputAutoCommitFirstWordConfidence) const;
 
diff --git a/native/jni/src/suggest/core/dictionary/error_type_utils.h b/native/jni/src/suggest/core/dictionary/error_type_utils.h
index 1122291..cc77867 100644
--- a/native/jni/src/suggest/core/dictionary/error_type_utils.h
+++ b/native/jni/src/suggest/core/dictionary/error_type_utils.h
@@ -59,6 +59,10 @@
         return (errorType & PROXIMITY_CORRECTION) != 0;
     }
 
+    static bool isCompletion(const ErrorType errorType) {
+        return (errorType & COMPLETION) != 0;
+    }
+
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(ErrorTypeUtils);
 
diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp
index f60a210..f6de571 100644
--- a/native/jni/src/suggest/core/suggest.cpp
+++ b/native/jni/src/suggest/core/suggest.cpp
@@ -44,7 +44,7 @@
  */
 int Suggest::getSuggestions(ProximityInfo *pInfo, void *traverseSession,
         int *inputXs, int *inputYs, int *times, int *pointerIds, int *inputCodePoints,
-        int inputSize, int commitPoint, int *outWords, int *outputScores, int *outputIndices,
+        int inputSize, int *outWords, int *outputScores, int *outputIndices,
         int *outputTypes, int *outputAutoCommitFirstWordConfidence) const {
     PROF_OPEN;
     PROF_START(0);
@@ -54,7 +54,7 @@
             pointerIds, maxSpatialDistance, TRAVERSAL->getMaxPointerCount());
     // TODO: Add the way to evaluate cache
 
-    initializeSearch(tSession, commitPoint);
+    initializeSearch(tSession);
     PROF_END(0);
     PROF_START(1);
 
@@ -77,27 +77,15 @@
  * Initializes the search at the root of the lexicon trie. Note that when possible the search will
  * continue suggestion from where it left off during the last call.
  */
-void Suggest::initializeSearch(DicTraverseSession *traverseSession, int commitPoint) const {
+void Suggest::initializeSearch(DicTraverseSession *traverseSession) const {
     if (!traverseSession->getProximityInfoState(0)->isUsed()) {
         return;
     }
 
-    // Never auto partial commit for now.
-    commitPoint = 0;
-
     if (traverseSession->getInputSize() > MIN_CONTINUOUS_SUGGESTION_INPUT_SIZE
             && traverseSession->isContinuousSuggestionPossible()) {
-        if (commitPoint == 0) {
-            // Continue suggestion
-            traverseSession->getDicTraverseCache()->continueSearch();
-        } else {
-            // Continue suggestion after partial commit.
-            DicNode *topDicNode =
-                    traverseSession->getDicTraverseCache()->setCommitPoint(commitPoint);
-            traverseSession->setPrevWordPtNodePos(topDicNode->getPrevWordPtNodePos());
-            traverseSession->getDicTraverseCache()->continueSearch();
-            traverseSession->setPartiallyCommited();
-        }
+        // Continue suggestion
+        traverseSession->getDicTraverseCache()->continueSearch();
     } else {
         // Restart recognition at the root.
         traverseSession->resetCache(TRAVERSAL->getMaxCacheSize(traverseSession->getInputSize()),
diff --git a/native/jni/src/suggest/core/suggest.h b/native/jni/src/suggest/core/suggest.h
index c42986a..33ea0b6 100644
--- a/native/jni/src/suggest/core/suggest.h
+++ b/native/jni/src/suggest/core/suggest.h
@@ -47,15 +47,15 @@
               WEIGHTING(suggestPolicy ? suggestPolicy->getWeighting() : nullptr) {}
     AK_FORCE_INLINE virtual ~Suggest() {}
     int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs,
-            int *times, int *pointerIds, int *inputCodePoints, int inputSize, int commitPoint,
-            int *outWords, int *outputScores, int *outputIndices, int *outputTypes,
+            int *times, int *pointerIds, int *inputCodePoints, int inputSize, int *outWords,
+            int *outputScores, int *outputIndices, int *outputTypes,
             int *outputAutoCommitFirstWordConfidence) const;
 
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(Suggest);
     void createNextWordDicNode(DicTraverseSession *traverseSession, DicNode *dicNode,
             const bool spaceSubstitution) const;
-    void initializeSearch(DicTraverseSession *traverseSession, int commitPoint) const;
+    void initializeSearch(DicTraverseSession *traverseSession) const;
     void expandCurrentDicNodes(DicTraverseSession *traverseSession) const;
     void processTerminalDicNode(DicTraverseSession *traverseSession, DicNode *dicNode) const;
     void processExpandedDicNode(DicTraverseSession *traverseSession, DicNode *dicNode) const;
diff --git a/native/jni/src/suggest/core/suggest_interface.h b/native/jni/src/suggest/core/suggest_interface.h
index 9a07580..f10db83 100644
--- a/native/jni/src/suggest/core/suggest_interface.h
+++ b/native/jni/src/suggest/core/suggest_interface.h
@@ -27,8 +27,8 @@
  public:
     virtual int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs,
             int *inputYs, int *times, int *pointerIds, int *inputCodePoints, int inputSize,
-            int commitPoint, int *outWords, int *outputScores, int *outputIndices,
-            int *outputTypes, int *outputAutoCommitFirstWordConfidence) const = 0;
+            int *outWords, int *outputScores, int *outputIndices, int *outputTypes,
+            int *outputAutoCommitFirstWordConfidence) const = 0;
     SuggestInterface() {}
     virtual ~SuggestInterface() {}
  private:
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTestsBase.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTestsBase.java
index c342533..7923afc 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTestsBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTestsBase.java
@@ -22,12 +22,8 @@
 import static com.android.inputmethod.latin.Constants.CODE_OUTPUT_TEXT;
 import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED;
 
-import android.content.Context;
-import android.content.res.Resources;
 import android.test.AndroidTestCase;
 
-import com.android.inputmethod.latin.utils.RunInLocale;
-
 import java.util.Locale;
 
 abstract class KeySpecParserTestsBase extends AndroidTestCase {
@@ -51,16 +47,7 @@
     protected void setUp() throws Exception {
         super.setUp();
 
-        mTextsSet.setLocale(TEST_LOCALE);
-        final Context context = getContext();
-        new RunInLocale<Void>() {
-            @Override
-            protected Void job(final Resources res) {
-                mTextsSet.loadStringResources(context);
-                return null;
-            }
-        }.runInLocale(context.getResources(), TEST_LOCALE);
-
+        mTextsSet.setLocale(TEST_LOCALE, getContext());
         mCodeSettings = KeyboardCodesSet.getCode(CODE_SETTINGS_NAME);
         mCodeActionNext = KeyboardCodesSet.getCode("key_action_next");
         mSettingsIconId = KeyboardIconsSet.getIconId(ICON_SETTINGS_NAME);
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSetTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSetTests.java
index 17d7687..eb906cd 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSetTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSetTests.java
@@ -17,7 +17,6 @@
 package com.android.inputmethod.keyboard.internal;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.inputmethod.InputMethodInfo;
@@ -25,7 +24,6 @@
 
 import com.android.inputmethod.latin.RichInputMethodManager;
 import com.android.inputmethod.latin.utils.CollectionUtils;
-import com.android.inputmethod.latin.utils.RunInLocale;
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
 
 import java.util.ArrayList;
@@ -58,10 +56,11 @@
     // subtypes. The text is needed to implement Emoji Keyboard, see
     // {@link KeyboardSwitcher#setEmojiKeyboard()}.
     public void testSwitchToAlphaKeyLabel() {
+        final Context context = getContext();
         final KeyboardTextsSet textsSet = new KeyboardTextsSet();
         for (final InputMethodSubtype subtype : mAllSubtypesList) {
             final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype);
-            textsSet.setLocale(locale);
+            textsSet.setLocale(locale, context);
             final String switchToAlphaKeyLabel = textsSet.getText(
                     KeyboardTextsSet.SWITCH_TO_ALPHA_KEY_LABEL);
             assertNotNull("Switch to alpha key label of " + locale, switchToAlphaKeyLabel);
@@ -87,15 +86,7 @@
         final KeyboardTextsSet textsSet = new KeyboardTextsSet();
         for (final InputMethodSubtype subtype : mAllSubtypesList) {
             final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype);
-            textsSet.setLocale(locale);
-            final RunInLocale<Void> job = new RunInLocale<Void>() {
-                @Override
-                protected Void job(final Resources res) {
-                    textsSet.loadStringResources(context);
-                    return null;
-                }
-            };
-            job.runInLocale(context.getResources(), locale);
+            textsSet.setLocale(locale, context);
             for (final String name : TEXT_NAMES_FROM_RESOURCE) {
                 final String text = textsSet.getText(name);
                 assertNotNull(name + " of " + locale, text);
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java
index 42a94f4..a193307 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java
@@ -23,7 +23,6 @@
 import android.test.suitebuilder.annotation.MediumTest;
 
 import com.android.inputmethod.latin.utils.CollectionUtils;
-import com.android.inputmethod.latin.utils.RunInLocale;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
@@ -41,20 +40,16 @@
 
         final Instrumentation instrumentation = getInstrumentation();
         final Context targetContext = instrumentation.getTargetContext();
-        mTextsSet.setLocale(TEST_LOCALE);
-        new RunInLocale<Void>() {
-            @Override
-            protected Void job(final Resources res) {
-                mTextsSet.loadStringResources(targetContext);
-                return null;
-            }
-        }.runInLocale(targetContext.getResources(), TEST_LOCALE);
+        mTextsSet.setLocale(TEST_LOCALE, targetContext);
         final String[] testResourceNames = getAllResourceIdNames(
                 com.android.inputmethod.latin.tests.R.string.class);
-        mTextsSet.loadStringResourcesInternal(instrumentation.getContext(), testResourceNames,
+        final Context testContext = instrumentation.getContext();
+        final Resources testRes = testContext.getResources();
+        final String testResPackageName = testRes.getResourcePackageName(
                 // This dummy raw resource is needed to be able to load string resources from a test
                 // APK successfully.
                 com.android.inputmethod.latin.tests.R.raw.dummy_resource_for_testing);
+        mTextsSet.loadStringResourcesInternal(testRes, testResourceNames, testResPackageName);
     }
 
     private static String[] getAllResourceIdNames(final Class<?> resourceIdClass) {
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/PcQwerty.java b/tests/src/com/android/inputmethod/keyboard/layout/PcQwerty.java
new file mode 100644
index 0000000..9da6dcc
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/PcQwerty.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+package com.android.inputmethod.keyboard.layout;
+
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
+
+import java.util.Locale;
+
+/**
+ * The PC QWERTY alphabet keyboard.
+ */
+public final class PcQwerty extends LayoutBase {
+    private static final String LAYOUT_NAME = "pcqwerty";
+
+    public PcQwerty(final LayoutCustomizer customizer) {
+        super(customizer, Symbols.class, SymbolsShifted.class);
+    }
+
+    @Override
+    public String getName() { return LAYOUT_NAME; }
+
+    public static class PcQwertyCustomizer extends LayoutCustomizer {
+        public PcQwertyCustomizer(final Locale locale) { super(locale); }
+
+        @Override
+        public ExpectedKey[] getLeftShiftKeys(final boolean isPhone) {
+            return joinKeys(SHIFT_KEY);
+        }
+
+        @Override
+        public ExpectedKey[] getRightShiftKeys(final boolean isPhone) {
+            return joinKeys(SHIFT_KEY);
+        }
+
+        @Override
+        public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
+            return joinKeys(SETTINGS_KEY);
+        }
+
+        @Override
+        public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
+            return isPhone ? joinKeys(key(ENTER_KEY, EMOJI_KEY)) : joinKeys(EMOJI_KEY);
+        }
+    }
+
+    @Override
+    ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) {
+        final LayoutCustomizer customizer = getCustomizer();
+        final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON);
+        customizer.setAccentedLetters(builder);
+        builder.replaceKeyOfLabel(ROW1_1, key("`", moreKey("~")))
+                .replaceKeyOfLabel(ROW2_11, key("[", moreKey("{")))
+                .replaceKeyOfLabel(ROW2_12, key("]", moreKey("}")))
+                .replaceKeyOfLabel(ROW2_13, key("\\", moreKey("|")))
+                .replaceKeyOfLabel(ROW3_10, key(";", moreKey(":")))
+                .replaceKeyOfLabel(ROW3_11, key("'", joinMoreKeys(additionalMoreKey("\""),
+                        customizer.getDoubleQuoteMoreKeys(),
+                        customizer.getSingleQuoteMoreKeys())))
+                .setAdditionalMoreKeysPositionOf("'", 4)
+                .replaceKeyOfLabel(ROW4_8, key(",", moreKey("<")))
+                .replaceKeyOfLabel(ROW4_9, key(".", moreKey(">")))
+                // U+00BF: "¿" INVERTED QUESTION MARK
+                .replaceKeyOfLabel(ROW4_10, key("/", joinMoreKeys("?", "\u00BF")));
+        if (isPhone) {
+            // U+221E: "∞" INFINITY
+            // U+2260: "≠" NOT EQUAL TO
+            // U+2248: "≈" ALMOST EQUAL TO
+            builder.replaceKeyOfLabel(ROW1_13, key("=",
+                    joinMoreKeys("\u221E", "\u2260", "\u2248", "+")));
+        } else {
+            // U+221E: "∞" INFINITY
+            // U+2260: "≠" NOT EQUAL TO
+            // U+2248: "≈" ALMOST EQUAL TO
+            builder.replaceKeyOfLabel(ROW1_13, key("=",
+                    joinMoreKeys("+", "\u221E", "\u2260", "\u2248")));
+        }
+        return builder.build();
+    }
+
+    @Override
+    ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) {
+        final ExpectedKeyboardBuilder builder;
+        if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED
+                || elementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED) {
+            builder = new ExpectedKeyboardBuilder(getCommonAlphabetLayout(isPhone));
+        } else {
+            builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON);
+            final LayoutCustomizer customizer = getCustomizer();
+            customizer.setAccentedLetters(builder);
+            builder.setKeysOfRow(1,
+                    "~",
+                    // U+00A1: "¡" INVERTED EXCLAMATION MARK
+                    key("!", moreKey("\u00A1")),
+                    "@", "#",
+                    customizer.getCurrencyKey(),
+                    // U+2030: "‰" PER MILLE SIGN
+                    key("%", moreKey("\u2030")),
+                    "^", "&",
+                    // U+2020: "†" DAGGER
+                    // U+2021: "‡" DOUBLE DAGGER
+                    // U+2605: "★" BLACK STAR
+                    key("*", joinMoreKeys("\u2020", "\u2021", "\u2605")),
+                    "(", ")", "_",
+                    // U+00B1: "±" PLUS-MINUS SIGN
+                    // U+00D7: "×" MULTIPLICATION SIGN
+                    // U+00F7: "÷" DIVISION SIGN
+                    // U+221A: "√" SQUARE ROOT
+                    key("+", joinMoreKeys("\u00B1", "\u00D7", "\u00F7", "\u221A")))
+                    .replaceKeyOfLabel(ROW2_11, key("{"))
+                    .replaceKeyOfLabel(ROW2_12, key("}"))
+                    .replaceKeyOfLabel(ROW2_13, key("|"))
+                    .replaceKeyOfLabel(ROW3_10, key(":"))
+                    .replaceKeyOfLabel(ROW3_11, key("\"", joinMoreKeys(
+                            customizer.getDoubleQuoteMoreKeys(),
+                            customizer.getSingleQuoteMoreKeys())))
+                    // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+                    // U+2264: "≤" LESS-THAN OR EQUAL TO
+                    // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+                    .replaceKeyOfLabel(ROW4_8, key("<", joinMoreKeys("\u2039", "\u2264", "\u00AB")))
+                    // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+                    // U+2265: "≥" GREATER-THAN EQUAL TO
+                    // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+                    .replaceKeyOfLabel(ROW4_9, key(">", joinMoreKeys("\u203A", "\u2265", "\u00BB")))
+                    // U+00BF: "¿" INVERTED QUESTION MARK
+                    .replaceKeyOfLabel(ROW4_10, key("?", moreKey("\u00BF")));
+        }
+        builder.toUpperCase(getLocale());
+        return builder.build();
+    }
+
+    // Helper method to create alphabet layout by adding special function keys.
+    @Override
+    ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder,
+            final boolean isPhone) {
+        final LayoutCustomizer customizer = getCustomizer();
+        builder.setKeysOfRow(5, (Object[])customizer.getSpaceKeys(isPhone));
+        builder.addKeysOnTheLeftOfRow(5, (Object[])customizer.getKeysLeftToSpacebar(isPhone));
+        builder.addKeysOnTheRightOfRow(5, (Object[])customizer.getKeysRightToSpacebar(isPhone));
+        if (isPhone) {
+            builder.addKeysOnTheRightOfRow(3, DELETE_KEY);
+        } else {
+            builder.addKeysOnTheRightOfRow(1, DELETE_KEY)
+                    .addKeysOnTheLeftOfRow(2, TAB_KEY)
+                    .addKeysOnTheRightOfRow(3, ENTER_KEY);
+        }
+        builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getLeftShiftKeys(isPhone))
+                .addKeysOnTheRightOfRow(4, (Object[])customizer.getRightShiftKeys(isPhone));
+        return builder;
+    }
+
+    @Override
+    public ExpectedKey[][] getLayout(final boolean isPhone, final int elementId) {
+        if (elementId == KeyboardId.ELEMENT_SYMBOLS
+                || elementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) {
+            return null;
+        }
+        return super.getLayout(isPhone, elementId);
+    }
+
+    private static final String ROW1_1 = "ROW1_1";
+    private static final String ROW1_13 = "ROW1_13";
+    private static final String ROW2_11 = "ROW2_11";
+    private static final String ROW2_12 = "ROW2_12";
+    private static final String ROW2_13 = "ROW2_13";
+    private static final String ROW3_10 = "ROW3_10";
+    private static final String ROW3_11 = "ROW3_11";
+    private static final String ROW4_8 = "ROW4_8";
+    private static final String ROW4_9 = "ROW4_9";
+    private static final String ROW4_10 = "ROW4_10";
+
+    private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder()
+            .setKeysOfRow(1,
+                    ROW1_1,
+                    // U+00A1: "¡" INVERTED EXCLAMATION MARK
+                    // U+00B9: "¹" SUPERSCRIPT ONE
+                    // U+00BD: "½" VULGAR FRACTION ONE HALF
+                    // U+2153: "⅓" VULGAR FRACTION ONE THIRD
+                    // U+00BC: "¼" VULGAR FRACTION ONE QUARTER
+                    // U+215B: "⅛" VULGAR FRACTION ONE EIGHTH
+                    key("1", joinMoreKeys(
+                            "!", "\u00A1", "\u00B9", "\u00BD", "\u2153", "\u00BC", "\u215B")),
+                    // U+00B2: "²" SUPERSCRIPT TWO
+                    // U+2154: "⅔" VULGAR FRACTION TWO THIRDS
+                    key("2", joinMoreKeys("@", "\u00B2", "\u2154")),
+                    // U+00B3: "³" SUPERSCRIPT THREE
+                    // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS
+                    // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS
+                    key("3", joinMoreKeys("#", "\u00B3", "\u00BE", "\u215C")),
+                    // U+2074: "⁴" SUPERSCRIPT FOUR
+                    key("4", joinMoreKeys("$", "\u2074")),
+                    // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS
+                    key("5", joinMoreKeys("%", "\u215D")),
+                    key("6", moreKey("^")),
+                    // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS
+                    key("7", joinMoreKeys("&", "\u215E")),
+                    key("8", moreKey("*")),
+                    key("9", moreKey("(")),
+                    // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N
+                    // U+2205: "∅" EMPTY SET
+                    key("0", joinMoreKeys(")", "\u207F", "\u2205")),
+                    // U+2013: "–" EN DASH
+                    // U+2014: "—" EM DASH
+                    // U+00B7: "·" MIDDLE DOT
+                    key("-", joinMoreKeys("_", "\u2013", "\u2014", "\u00B7")),
+                    ROW1_13)
+            .setKeysOfRow(2, "q", "w", "e", "r", "t", "y", "u", "i", "o", "p",
+                    ROW2_11, ROW2_12, ROW2_13)
+            .setKeysOfRow(3, "a", "s", "d", "f", "g", "h", "j", "k", "l", ROW3_10, ROW3_11)
+            .setKeysOfRow(4, "z", "x", "c", "v", "b", "n", "m", ROW4_8, ROW4_9, ROW4_10)
+            .build();
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
index a13ec75..6176f6a 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
@@ -109,10 +109,14 @@
     // Icon ids.
     private static final int ICON_DELETE = KeyboardIconsSet.getIconId(
             KeyboardIconsSet.NAME_DELETE_KEY);
+    private static final int ICON_TAB = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_TAB_KEY);
     private static final int ICON_SHORTCUT = KeyboardIconsSet.getIconId(
             KeyboardIconsSet.NAME_SHORTCUT_KEY);
     private static final int ICON_SETTINGS = KeyboardIconsSet.getIconId(
             KeyboardIconsSet.NAME_SETTINGS_KEY);
+    private static final int ICON_LANGUAGE_SWITCH = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_LANGUAGE_SWITCH_KEY);
     private static final int ICON_ENTER = KeyboardIconsSet.getIconId(
             KeyboardIconsSet.NAME_ENTER_KEY);
     private static final int ICON_EMOJI = KeyboardIconsSet.getIconId(
@@ -120,8 +124,11 @@
 
     // Functional keys.
     public static final ExpectedKey DELETE_KEY = key(ICON_DELETE, Constants.CODE_DELETE);
+    public static final ExpectedKey TAB_KEY = key(ICON_TAB, Constants.CODE_TAB);
     public static final ExpectedKey SHORTCUT_KEY = key(ICON_SHORTCUT, Constants.CODE_SHORTCUT);
     public static final ExpectedKey SETTINGS_KEY = key(ICON_SETTINGS, Constants.CODE_SETTINGS);
+    public static final ExpectedKey LANGUAGE_SWITCH_KEY = key(
+            ICON_LANGUAGE_SWITCH, Constants.CODE_LANGUAGE_SWITCH);
     public static final ExpectedKey ENTER_KEY = key(ICON_ENTER, Constants.CODE_ENTER);
     public static final ExpectedKey EMOJI_KEY = key(ICON_EMOJI, Constants.CODE_EMOJI);
     public static final ExpectedKey SPACE_KEY = key(
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguagePcQwerty.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguagePcQwerty.java
new file mode 100644
index 0000000..cd8d43c
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguagePcQwerty.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+package com.android.inputmethod.keyboard.layout.tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.PcQwerty;
+import com.android.inputmethod.keyboard.layout.PcQwerty.PcQwertyCustomizer;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
+
+import java.util.Locale;
+
+/**
+ * zz: Alphabet/pcqwerty
+ */
+@SmallTest
+public final class TestsNoLanguagePcQwerty extends LayoutTestsBase {
+    private static final Locale LOCALE = new Locale("zz");
+    private static final LayoutBase LAYOUT = new PcQwerty(new NoLanguagePcQwertyCustomizer(LOCALE));
+
+    @Override
+    LayoutBase getLayout() { return LAYOUT; }
+
+    private static class NoLanguagePcQwertyCustomizer extends PcQwertyCustomizer {
+        private final NoLanguageCustomizer mNoLanguageCustomizer;
+
+        public NoLanguagePcQwertyCustomizer(final Locale locale) {
+            super(locale);
+            mNoLanguageCustomizer = new NoLanguageCustomizer(locale);
+        }
+
+        @Override
+        public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) {
+            return mNoLanguageCustomizer.setAccentedLetters(builder);
+        }
+    }
+}