Merge "Import translations. DO NOT MERGE" into jb-dev
diff --git a/java/res/xml-sw600dp/key_apostrophe.xml b/java/res/xml-sw600dp/key_apostrophe.xml
index 7da4b62..0c838db 100644
--- a/java/res/xml-sw600dp/key_apostrophe.xml
+++ b/java/res/xml-sw600dp/key_apostrophe.xml
@@ -23,20 +23,11 @@
 >
     <switch>
         <case
-            latin:mode="email"
+            latin:mode="email|url"
         >
             <Key
                 latin:keyLabel="-" />
         </case>
-        <case
-            latin:mode="url"
-        >
-            <Key
-                latin:keyLabel="/"
-                latin:keyHintLabel=":"
-                latin:moreKeys=":"
-                latin:keyStyle="hasShiftedLetterHintStyle" />
-        </case>
         <default>
             <Key
                 latin:keyLabel="!text/keylabel_for_apostrophe"
diff --git a/java/res/xml-sw600dp/key_dash.xml b/java/res/xml-sw600dp/key_dash.xml
index f7e0b34..8f91eff 100644
--- a/java/res/xml-sw600dp/key_dash.xml
+++ b/java/res/xml-sw600dp/key_dash.xml
@@ -23,7 +23,7 @@
 >
     <switch>
         <case
-            latin:mode="email"
+            latin:mode="email|url"
         >
             <Key
                 latin:keyLabel="_" />
diff --git a/java/res/xml-sw600dp/key_f1.xml b/java/res/xml-sw600dp/key_f1.xml
new file mode 100644
index 0000000..77afe4e
--- /dev/null
+++ b/java/res/xml-sw600dp/key_f1.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <switch>
+        <case
+            latin:keyboardLayoutSetElement="symbols"
+            latin:mode="url"
+        >
+            <Key
+                latin:keyLabel=":" />
+        </case>
+        <case
+            latin:keyboardLayoutSetElement="symbols"
+        >
+            <Key
+                latin:keyLabel="\@" />
+        </case>
+        <!-- keyboardLayoutSetElement != "symbols" -->
+        <case
+            latin:mode="email"
+        >
+            <Key
+                latin:keyLabel="\@" />
+        </case>
+        <case
+            latin:mode="url"
+        >
+            <Key
+                latin:keyLabel="/"
+                latin:keyHintLabel=":"
+                latin:moreKeys=":"
+                latin:keyStyle="hasShiftedLetterHintStyle" />
+        </case>
+        <default>
+            <Key
+                latin:keyLabel="/"
+                latin:keyHintLabel="\@"
+                latin:moreKeys="\@"
+                latin:keyStyle="hasShiftedLetterHintStyle" />
+        </default>
+    </switch>
+</merge>
diff --git a/java/res/xml-sw600dp/key_f2.xml b/java/res/xml-sw600dp/key_f2.xml
new file mode 100644
index 0000000..ca3b30b
--- /dev/null
+++ b/java/res/xml-sw600dp/key_f2.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <switch>
+        <case
+            latin:mode="email|url"
+        >
+            <Key
+                latin:keyStyle="comKeyStyle" />
+        </case>
+        <case
+            latin:imeAction="actionSearch"
+        >
+            <Key
+                latin:keyLabel=":"
+                latin:keyHintLabel="+"
+                latin:moreKeys="+"
+                latin:keyStyle="hasShiftedLetterHintStyle" />
+        </case>
+        <default>
+            <Key
+                latin:keyStyle="smileyKeyStyle" />
+        </default>
+    </switch>
+</merge>
diff --git a/java/res/xml-sw600dp/key_question_exclamation.xml b/java/res/xml-sw600dp/key_question_exclamation.xml
index f1495de..860a0be 100644
--- a/java/res/xml-sw600dp/key_question_exclamation.xml
+++ b/java/res/xml-sw600dp/key_question_exclamation.xml
@@ -23,20 +23,11 @@
 >
     <switch>
         <case
-            latin:mode="email"
+            latin:mode="email|url"
         >
             <Key
                 latin:keyLabel="-" />
         </case>
-        <case
-            latin:mode="url"
-        >
-            <Key
-                latin:keyLabel="/"
-                latin:keyHintLabel=":"
-                latin:moreKeys=":"
-                latin:keyStyle="hasShiftedLetterHintStyle" />
-        </case>
         <default>
             <Key
                 latin:keyLabel="\?"
diff --git a/java/res/xml-sw600dp/keys_f1f2.xml b/java/res/xml-sw600dp/keys_f1f2.xml
deleted file mode 100644
index 721bfc7..0000000
--- a/java/res/xml-sw600dp/keys_f1f2.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
-    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
-    <switch>
-        <case
-            latin:mode="url"
-        >
-            <Key
-                latin:keyStyle="comKeyStyle"
-                latin:keyWidth="18.0%p" />
-        </case>
-        <default>
-            <switch>
-                <case
-                    latin:mode="email"
-                >
-                    <Key
-                        latin:keyStyle="comKeyStyle" />
-                </case>
-                <case
-                    latin:imeAction="actionSearch"
-                >
-                    <Key
-                        latin:keyLabel=":"
-                        latin:keyHintLabel="+"
-                        latin:moreKeys="+"
-                        latin:keyStyle="hasShiftedLetterHintStyle" />
-                </case>
-                <default>
-                    <Key
-                        latin:keyStyle="smileyKeyStyle" />
-                </default>
-            </switch>
-            <switch>
-                <case
-                    latin:mode="email"
-                >
-                    <Key
-                        latin:keyLabel="\@" />
-                </case>
-                <default>
-                    <Key
-                        latin:keyLabel="/"
-                        latin:keyHintLabel="\@"
-                        latin:moreKeys="\@"
-                        latin:keyStyle="hasShiftedLetterHintStyle" />
-                </default>
-            </switch>
-        </default>
-    </switch>
-</merge>
diff --git a/java/res/xml-sw600dp/row_dvorak4.xml b/java/res/xml-sw600dp/row_dvorak4.xml
index ffc3427..47cee45 100644
--- a/java/res/xml-sw600dp/row_dvorak4.xml
+++ b/java/res/xml-sw600dp/row_dvorak4.xml
@@ -23,22 +23,24 @@
 >
     <Row
         latin:keyWidth="9.0%p"
+        backgroundType="functional"
     >
         <Key
             latin:keyStyle="toSymbolKeyStyle"
             latin:keyWidth="10.0%p" />
         <include
-            latin:keyboardLayout="@xml/keys_f1f2" />
+            latin:keyboardLayout="@xml/key_shortcut" />
+        <include
+            latin:keyboardLayout="@xml/key_f1" />
         <include
             latin:keyXPos="28.0%p"
-            latin:keyboardLayout="@xml/key_space" />
+            latin:keyboardLayout="@xml/key_space"
+            latin:backgroundType="normal" />
         <include
             latin:keyboardLayout="@xml/key_question_exclamation" />
         <include
             latin:keyboardLayout="@xml/key_dash" />
         <include
-            latin:keyXPos="-9.0%p"
-            latin:keyWidth="fillRight"
-            latin:keyboardLayout="@xml/key_shortcut" />
+            latin:keyboardLayout="@xml/key_f2" />
     </Row>
 </merge>
diff --git a/java/res/xml-sw600dp/row_hebrew4.xml b/java/res/xml-sw600dp/row_hebrew4.xml
index 114a5cc..f429f97 100644
--- a/java/res/xml-sw600dp/row_hebrew4.xml
+++ b/java/res/xml-sw600dp/row_hebrew4.xml
@@ -23,20 +23,22 @@
 >
     <Row
         latin:keyWidth="9.0%p"
+        latin:backgroundType="functional"
     >
         <Key
             latin:keyStyle="toSymbolKeyStyle"
             latin:keyWidth="10.0%p" />
         <include
-            latin:keyboardLayout="@xml/keys_f1f2" />
+            latin:keyboardLayout="@xml/key_shortcut" />
+        <include
+            latin:keyboardLayout="@xml/key_f1" />
         <include
             latin:keyXPos="28.0%p"
-            latin:keyboardLayout="@xml/key_space" />
+            latin:keyboardLayout="@xml/key_space"
+            latin:backgroundType="normal" />
         <include
             latin:keyboardLayout="@xml/keys_comma_period" />
         <include
-            latin:keyXPos="-9.0%p"
-            latin:keyWidth="fillRight"
-            latin:keyboardLayout="@xml/key_shortcut" />
+            latin:keyboardLayout="@xml/key_f2" />
     </Row>
 </merge>
diff --git a/java/res/xml-sw600dp/row_qwerty4.xml b/java/res/xml-sw600dp/row_qwerty4.xml
index a4ba8a4..fa43363 100644
--- a/java/res/xml-sw600dp/row_qwerty4.xml
+++ b/java/res/xml-sw600dp/row_qwerty4.xml
@@ -23,22 +23,24 @@
 >
     <Row
         latin:keyWidth="9.0%p"
+        latin:backgroundType="functional"
     >
         <Key
             latin:keyStyle="toSymbolKeyStyle"
             latin:keyWidth="10.0%p" />
         <include
-            latin:keyboardLayout="@xml/keys_f1f2" />
+            latin:keyboardLayout="@xml/key_shortcut" />
+        <include
+            latin:keyboardLayout="@xml/key_f1" />
         <include
             latin:keyXPos="28.0%p"
-            latin:keyboardLayout="@xml/key_space" />
+            latin:keyboardLayout="@xml/key_space"
+            latin:backgroundType="normal" />
         <include
             latin:keyboardLayout="@xml/key_apostrophe" />
         <include
             latin:keyboardLayout="@xml/key_dash" />
         <include
-            latin:keyXPos="-9.0%p"
-            latin:keyWidth="fillRight"
-            latin:keyboardLayout="@xml/key_shortcut" />
+            latin:keyboardLayout="@xml/key_f2" />
     </Row>
 </merge>
diff --git a/java/res/xml-sw600dp/row_symbols4.xml b/java/res/xml-sw600dp/row_symbols4.xml
index 20d1a7d..73a5b17 100644
--- a/java/res/xml-sw600dp/row_symbols4.xml
+++ b/java/res/xml-sw600dp/row_symbols4.xml
@@ -23,25 +23,24 @@
 >
     <Row
         latin:keyWidth="9.0%p"
+        latin:backgroundType="functional"
     >
         <Key
             latin:keyStyle="toAlphaKeyStyle"
             latin:keyWidth="10.0%p" />
         <Key
             latin:keyLabel="/" />
-        <Key
-            latin:keyLabel="\@" />
+        <include
+            latin:keyboardLayout="@xml/key_f1" />
         <include
             latin:keyXPos="28.0%p"
-            latin:keyboardLayout="@xml/key_space" />
+            latin:keyboardLayout="@xml/key_space"
+            latin:backgroundType="normal" />
         <Key
             latin:keyLabel="&quot;"
             latin:moreKeys="!text/more_keys_for_tablet_double_quote" />
         <Key
             latin:keyLabel="_" />
-        <include
-            latin:keyXPos="-9.0%p"
-            latin:keyWidth="fillRight"
-            latin:keyboardLayout="@xml/key_shortcut" />
+        <!-- Here is empty space. -->
     </Row>
 </merge>
diff --git a/java/res/xml-sw600dp/row_symbols_shift4.xml b/java/res/xml-sw600dp/row_symbols_shift4.xml
index fd7b370..6f3aac7 100644
--- a/java/res/xml-sw600dp/row_symbols_shift4.xml
+++ b/java/res/xml-sw600dp/row_symbols_shift4.xml
@@ -23,16 +23,16 @@
 >
     <Row
         latin:keyWidth="9.0%p"
+        latin:backgroundType="functional"
     >
         <Key
             latin:keyStyle="toAlphaKeyStyle"
             latin:keyWidth="10.0%p" />
+        <!-- Here is empty space. -->
         <include
             latin:keyXPos="28.0%p"
-            latin:keyboardLayout="@xml/key_space" />
-        <include
-            latin:keyXPos="-9.0%p"
-            latin:keyWidth="fillRight"
-            latin:keyboardLayout="@xml/key_shortcut" />
+            latin:keyboardLayout="@xml/key_space"
+            latin:backgroundType="normal" />
+        <!-- Here is empty space. -->
     </Row>
 </merge>
diff --git a/java/res/xml-sw600dp/rows_number_normal.xml b/java/res/xml-sw600dp/rows_number_normal.xml
index 3954b00..48b3040 100644
--- a/java/res/xml-sw600dp/rows_number_normal.xml
+++ b/java/res/xml-sw600dp/rows_number_normal.xml
@@ -25,15 +25,18 @@
         <Key
             latin:keyLabel="-"
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel="+"
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel="."
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel="1"
             latin:keyStyle="numKeyStyle"
@@ -52,11 +55,13 @@
     <Row>
         <Key
             latin:keyStyle="numStarKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel="/"
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <switch>
             <case
                 latin:mode="time|datetime"
@@ -66,13 +71,15 @@
                     latin:keyLabelFlags="hasPopupHint"
                     latin:moreKeys="!text/more_keys_for_am_pm"
                     latin:keyStyle="numKeyStyle"
-                    latin:keyWidth="10%p" />
+                    latin:keyWidth="10%p"
+                    latin:backgroundType="functional" />
             </case>
             <default>
                 <Key
                     latin:keyLabel=","
                     latin:keyStyle="numKeyStyle"
-                    latin:keyWidth="10%p" />
+                    latin:keyWidth="10%p"
+                    latin:backgroundType="functional" />
             </default>
         </switch>
         <Key
@@ -94,11 +101,13 @@
         <Key
             latin:keyLabel="("
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel=")"
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <switch>
             <case
                 latin:mode="time|datetime"
@@ -106,13 +115,15 @@
                 <Key
                     latin:keyLabel=":"
                     latin:keyStyle="numKeyStyle"
-                    latin:keyWidth="10%p" />
+                    latin:keyWidth="10%p"
+                    latin:backgroundType="functional" />
             </case>
             <default>
                 <Key
                     latin:keyLabel="="
                     latin:keyStyle="numKeyStyle"
-                    latin:keyWidth="10%p" />
+                    latin:keyWidth="10%p"
+                    latin:backgroundType="functional" />
             </default>
         </switch>
         <Key
@@ -131,7 +142,8 @@
     <Row>
         <Key
             latin:keyStyle="spaceKeyStyle"
-            latin:keyWidth="30%p" />
+            latin:keyWidth="30%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyStyle="numStarKeyStyle"
             latin:keyXPos="31%p" />
@@ -141,9 +153,5 @@
         <Key
             latin:keyLabel="#"
             latin:keyStyle="numKeyStyle" />
-        <include
-            latin:keyXPos="-10%p"
-            latin:keyWidth="fillRight"
-            latin:keyboardLayout="@xml/key_shortcut" />
     </Row>
 </merge>
diff --git a/java/res/xml-sw600dp/rows_phone.xml b/java/res/xml-sw600dp/rows_phone.xml
index 113ce1f..dcc4fde 100644
--- a/java/res/xml-sw600dp/rows_phone.xml
+++ b/java/res/xml-sw600dp/rows_phone.xml
@@ -29,14 +29,17 @@
         <Key
             latin:keyLabel="-"
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel="+"
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyStyle="numPauseKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyStyle="num1KeyStyle"
             latin:keyXPos="31%p" />
@@ -53,14 +56,17 @@
         <Key
             latin:keyLabel=","
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel="."
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyStyle="numWaitKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyStyle="num4KeyStyle"
             latin:keyXPos="31%p" />
@@ -77,15 +83,18 @@
         <Key
             latin:keyLabel="("
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel=")"
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel="N"
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="10%p" />
+            latin:keyWidth="10%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyStyle="num7KeyStyle"
             latin:keyXPos="31%p" />
@@ -99,7 +108,8 @@
     <Row>
         <Key
             latin:keyStyle="spaceKeyStyle"
-            latin:keyWidth="30%p" />
+            latin:keyWidth="30%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyStyle="numStarKeyStyle"
             latin:keyXPos="31%p" />
@@ -108,9 +118,5 @@
         <Key
             latin:keyLabel="#"
             latin:keyStyle="numKeyStyle" />
-        <include
-            latin:keyXPos="-10%p"
-            latin:keyWidth="fillRight"
-            latin:keyboardLayout="@xml/key_shortcut" />
     </Row>
 </merge>
diff --git a/java/res/xml-sw768dp/key_settings.xml b/java/res/xml-sw768dp/key_settings.xml
index 0359a99..0d3bb59 100644
--- a/java/res/xml-sw768dp/key_settings.xml
+++ b/java/res/xml-sw768dp/key_settings.xml
@@ -32,4 +32,4 @@
             <Spacer />
         </default>
     </switch>
- </merge>
+</merge>
diff --git a/java/res/xml-sw768dp/key_shortcut.xml b/java/res/xml-sw768dp/key_shortcut.xml
index 9052705..2d09ebb 100644
--- a/java/res/xml-sw768dp/key_shortcut.xml
+++ b/java/res/xml-sw768dp/key_shortcut.xml
@@ -28,5 +28,9 @@
             <Key
                 latin:keyStyle="shortcutKeyStyle" />
         </case>
+        <default>
+            <!-- The empty space instead of shortcut key. -->
+            <Spacer />
+        </default>
     </switch>
 </merge>
diff --git a/java/res/xml-sw768dp/key_styles_common.xml b/java/res/xml-sw768dp/key_styles_common.xml
index f2fb90b..40082ac 100644
--- a/java/res/xml-sw768dp/key_styles_common.xml
+++ b/java/res/xml-sw768dp/key_styles_common.xml
@@ -74,12 +74,6 @@
     <include
         latin:keyboardLayout="@xml/key_styles_enter" />
     <key-style
-        latin:styleName="defaultActionKeyStyle"
-        latin:code="!code/key_action_enter"
-        latin:keyIcon="!icon/undefined"
-        latin:backgroundType="functional"
-        latin:parentStyle="defaultEnterKeyStyle" />
-    <key-style
         latin:styleName="spaceKeyStyle"
         latin:code="!code/key_space"
         latin:keyActionFlags="noKeyPreview" />
diff --git a/java/res/xml-sw768dp/keys_f1f2.xml b/java/res/xml-sw768dp/keys_f1f2.xml
deleted file mode 100644
index 5697035..0000000
--- a/java/res/xml-sw768dp/keys_f1f2.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
-    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
-    <switch>
-        <case
-            latin:mode="url"
-        >
-            <Key
-                latin:keyStyle="comKeyStyle"
-                latin:keyWidth="16.084%p" />
-        </case>
-        <default>
-            <switch>
-                <case
-                    latin:mode="email"
-                >
-                    <Key
-                        latin:keyStyle="comKeyStyle" />
-                </case>
-                <case
-                    latin:imeAction="actionSearch"
-                >
-                    <Key
-                        latin:keyLabel=":"
-                        latin:keyHintLabel="+"
-                        latin:moreKeys="+"
-                        latin:keyStyle="hasShiftedLetterHintStyle" />
-                </case>
-                <default>
-                    <Key
-                        latin:keyStyle="smileyKeyStyle" />
-                </default>
-            </switch>
-            <switch>
-                <case
-                    latin:mode="email"
-                >
-                    <Key
-                        latin:keyLabel="\@" />
-                </case>
-                <default>
-                    <Key
-                        latin:keyLabel="/"
-                        latin:keyHintLabel="\@"
-                        latin:moreKeys="\@"
-                        latin:keyStyle="hasShiftedLetterHintStyle" />
-                </default>
-            </switch>
-        </default>
-    </switch>
-</merge>
diff --git a/java/res/xml-sw768dp/row_dvorak4.xml b/java/res/xml-sw768dp/row_dvorak4.xml
index ebe517d..0827815 100644
--- a/java/res/xml-sw768dp/row_dvorak4.xml
+++ b/java/res/xml-sw768dp/row_dvorak4.xml
@@ -23,22 +23,24 @@
 >
     <Row
         latin:keyWidth="8.047%p"
+        latin:backgroundType="functional"
     >
         <include
+            latin:keyXPos="5.782%p"
             latin:keyboardLayout="@xml/key_settings" />
         <include
-            latin:keyXPos="13.829%p"
-            latin:keyboardLayout="@xml/keys_f1f2" />
+            latin:keyboardLayout="@xml/key_shortcut" />
+        <include
+            latin:keyboardLayout="@xml/key_f1" />
         <include
             latin:keyXPos="29.923%p"
-            latin:keyboardLayout="@xml/key_space" />
+            latin:keyboardLayout="@xml/key_space"
+            latin:backgroundType="normal" />
         <include
             latin:keyboardLayout="@xml/key_question_exclamation" />
         <include
             latin:keyboardLayout="@xml/key_dash" />
         <include
-            latin:keyXPos="-8.047%p"
-            latin:keyWidth="fillRight"
-            latin:keyboardLayout="@xml/key_shortcut" />
+            latin:keyboardLayout="@xml/key_f2" />
     </Row>
 </merge>
diff --git a/java/res/xml-sw768dp/row_hebrew4.xml b/java/res/xml-sw768dp/row_hebrew4.xml
index 477fd0d..180c564 100644
--- a/java/res/xml-sw768dp/row_hebrew4.xml
+++ b/java/res/xml-sw768dp/row_hebrew4.xml
@@ -23,20 +23,22 @@
 >
     <Row
         latin:keyWidth="8.047%p"
+        latin:backgroundType="functional"
     >
         <include
+            latin:keyXPos="5.782%p"
             latin:keyboardLayout="@xml/key_settings" />
         <include
-            latin:keyXPos="13.829%p"
-            latin:keyboardLayout="@xml/keys_f1f2" />
+            latin:keyboardLayout="@xml/key_shortcut" />
+        <include
+            latin:keyboardLayout="@xml/key_f1" />
         <include
             latin:keyXPos="29.923%p"
-            latin:keyboardLayout="@xml/key_space" />
+            latin:keyboardLayout="@xml/key_space"
+            latin:backgroundType="normal" />
         <include
             latin:keyboardLayout="@xml/keys_comma_period" />
         <include
-            latin:keyXPos="-8.047%p"
-            latin:keyWidth="fillRight"
-            latin:keyboardLayout="@xml/key_shortcut" />
+            latin:keyboardLayout="@xml/key_f2" />
     </Row>
 </merge>
diff --git a/java/res/xml-sw768dp/row_qwerty4.xml b/java/res/xml-sw768dp/row_qwerty4.xml
index 32a6476..92411f5 100644
--- a/java/res/xml-sw768dp/row_qwerty4.xml
+++ b/java/res/xml-sw768dp/row_qwerty4.xml
@@ -23,22 +23,24 @@
 >
     <Row
         latin:keyWidth="8.047%p"
+        latin:backgroundType="functional"
     >
         <include
+            latin:keyXPos="5.782%p"
             latin:keyboardLayout="@xml/key_settings" />
         <include
-            latin:keyXPos="13.829%p"
-            latin:keyboardLayout="@xml/keys_f1f2" />
+            latin:keyboardLayout="@xml/key_shortcut" />
+        <include
+            latin:keyboardLayout="@xml/key_f1" />
         <include
             latin:keyXPos="29.923%p"
-            latin:keyboardLayout="@xml/key_space" />
+            latin:keyboardLayout="@xml/key_space"
+            latin:backgroundType="normal" />
         <include
             latin:keyboardLayout="@xml/key_apostrophe" />
         <include
             latin:keyboardLayout="@xml/key_dash" />
         <include
-            latin:keyXPos="-8.047%p"
-            latin:keyWidth="fillRight"
-            latin:keyboardLayout="@xml/key_shortcut" />
+            latin:keyboardLayout="@xml/key_f2" />
     </Row>
 </merge>
diff --git a/java/res/xml-sw768dp/row_symbols4.xml b/java/res/xml-sw768dp/row_symbols4.xml
index bd85b40..4e1c119 100644
--- a/java/res/xml-sw768dp/row_symbols4.xml
+++ b/java/res/xml-sw768dp/row_symbols4.xml
@@ -23,25 +23,22 @@
 >
     <Row
         latin:keyWidth="8.047%p"
+        latin:backgroundType="functional"
     >
+        <Key
+            latin:keyXPos="13.829%p"
+            latin:keyLabel="/" />
         <include
-            latin:keyboardLayout="@xml/key_settings" />
-        <Key
-            latin:keyLabel="/"
-            latin:keyXPos="13.829%p" />
-        <Key
-            latin:keyLabel="\@" />
+            latin:keyboardLayout="@xml/key_f1" />
         <include
             latin:keyXPos="29.923%p"
-            latin:keyboardLayout="@xml/key_space" />
+            latin:keyboardLayout="@xml/key_space"
+            latin:backgroundType="normal" />
         <Key
             latin:keyLabel="&quot;"
             latin:moreKeys="!text/more_keys_for_tablet_double_quote" />
         <Key
             latin:keyLabel="_" />
-        <include
-            latin:keyXPos="-8.047%p"
-            latin:keyWidth="fillRight"
-            latin:keyboardLayout="@xml/key_shortcut" />
+        <!-- Here is empty space. -->
     </Row>
 </merge>
diff --git a/java/res/xml-sw768dp/row_symbols_shift4.xml b/java/res/xml-sw768dp/row_symbols_shift4.xml
index 82c1d17..561351c 100644
--- a/java/res/xml-sw768dp/row_symbols_shift4.xml
+++ b/java/res/xml-sw768dp/row_symbols_shift4.xml
@@ -23,15 +23,13 @@
 >
     <Row
         latin:keyWidth="8.047%p"
+        latin:backgroundType="functional"
     >
-        <include
-            latin:keyboardLayout="@xml/key_settings" />
+        <!-- Here is empty space. -->
         <include
             latin:keyXPos="29.923%p"
-            latin:keyboardLayout="@xml/key_space" />
-        <include
-            latin:keyXPos="-8.047%p"
-            latin:keyWidth="fillRight"
-            latin:keyboardLayout="@xml/key_shortcut" />
+            latin:keyboardLayout="@xml/key_space"
+            latin:backgroundType="normal" />
+        <!-- Here is empty space. -->
     </Row>
 </merge>
diff --git a/java/res/xml-sw768dp/rows_number_normal.xml b/java/res/xml-sw768dp/rows_number_normal.xml
index 42697ce..84910a8 100644
--- a/java/res/xml-sw768dp/rows_number_normal.xml
+++ b/java/res/xml-sw768dp/rows_number_normal.xml
@@ -30,15 +30,18 @@
             latin:keyLabel="-"
             latin:keyStyle="numKeyStyle"
             latin:keyXPos="13.829%p"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel="+"
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel="."
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel="1"
             latin:keyStyle="numKeyStyle"
@@ -60,11 +63,13 @@
             latin:keyWidth="13.829%p" />
         <Key
             latin:keyStyle="numStarKeyStyle"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel="/"
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <switch>
             <case
                 latin:mode="time|datetime"
@@ -74,13 +79,15 @@
                     latin:keyLabelFlags="hasPopupHint"
                     latin:moreKeys="!text/more_keys_for_am_pm"
                     latin:keyStyle="numKeyStyle"
-                    latin:keyWidth="8.047%p" />
+                    latin:keyWidth="8.047%p"
+                    latin:backgroundType="functional" />
             </case>
             <default>
                 <Key
                     latin:keyLabel=","
                     latin:keyStyle="numKeyStyle"
-                    latin:keyWidth="8.047%p" />
+                    latin:keyWidth="8.047%p"
+                    latin:backgroundType="functional" />
             </default>
         </switch>
         <Key
@@ -105,11 +112,13 @@
         <Key
             latin:keyLabel="("
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel=")"
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <switch>
             <case
                 latin:mode="time|datetime"
@@ -117,13 +126,15 @@
                 <Key
                     latin:keyLabel=":"
                     latin:keyStyle="numKeyStyle"
-                    latin:keyWidth="8.047%p" />
+                    latin:keyWidth="8.047%p"
+                    latin:backgroundType="functional" />
             </case>
             <default>
                 <Key
                     latin:keyLabel="="
                     latin:keyStyle="numKeyStyle"
-                    latin:keyWidth="8.047%p" />
+                    latin:keyWidth="8.047%p"
+                    latin:backgroundType="functional" />
             </default>
         </switch>
         <Key
@@ -146,7 +157,8 @@
         <Key
             latin:keyStyle="spaceKeyStyle"
             latin:keyXPos="13.829%p"
-            latin:keyWidth="24.140%p" />
+            latin:keyWidth="24.140%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyStyle="numStarKeyStyle"
             latin:keyXPos="43.125%p" />
@@ -156,9 +168,5 @@
         <Key
             latin:keyLabel="#"
             latin:keyStyle="numKeyStyle" />
-        <include
-            latin:keyXPos="-8.047%p"
-            latin:keyWidth="fillRight"
-            latin:keyboardLayout="@xml/key_shortcut" />
     </Row>
 </merge>
diff --git a/java/res/xml-sw768dp/rows_phone.xml b/java/res/xml-sw768dp/rows_phone.xml
index b3b3521..2f718db 100644
--- a/java/res/xml-sw768dp/rows_phone.xml
+++ b/java/res/xml-sw768dp/rows_phone.xml
@@ -34,14 +34,17 @@
             latin:keyLabel="-"
             latin:keyStyle="numKeyStyle"
             latin:keyXPos="13.829%p"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel="+"
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyStyle="numPauseKeyStyle"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyStyle="num1KeyStyle"
             latin:keyXPos="43.125%p" />
@@ -62,14 +65,17 @@
             latin:keyLabel=","
             latin:keyStyle="numKeyStyle"
             latin:keyXPos="13.829%p"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel="."
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyStyle="numWaitKeyStyle"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyStyle="num4KeyStyle"
             latin:keyXPos="43.125%p" />
@@ -89,15 +95,18 @@
         <Key
             latin:keyLabel="("
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel=")"
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyLabel="N"
             latin:keyStyle="numKeyStyle"
-            latin:keyWidth="8.047%p" />
+            latin:keyWidth="8.047%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyStyle="num7KeyStyle"
             latin:keyXPos="43.125%p" />
@@ -115,7 +124,8 @@
         <Key
             latin:keyStyle="spaceKeyStyle"
             latin:keyXPos="13.829%p"
-            latin:keyWidth="24.140%p" />
+            latin:keyWidth="24.140%p"
+            latin:backgroundType="functional" />
         <Key
             latin:keyStyle="numStarKeyStyle"
             latin:keyXPos="43.125%p" />
@@ -124,9 +134,5 @@
         <Key
             latin:keyLabel="#"
             latin:keyStyle="numKeyStyle" />
-        <include
-            latin:keyXPos="-8.047%p"
-            latin:keyWidth="fillRight"
-            latin:keyboardLayout="@xml/key_shortcut" />
-    </Row>
+   </Row>
 </merge>
diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml
index 819cdc6..622da21 100644
--- a/java/res/xml/key_styles_common.xml
+++ b/java/res/xml/key_styles_common.xml
@@ -105,8 +105,7 @@
     <key-style
         latin:styleName="spaceKeyStyle"
         latin:code="!code/key_space"
-        latin:keyActionFlags="noKeyPreview|enableLongPress"
-        latin:backgroundType="functional" />
+        latin:keyActionFlags="noKeyPreview|enableLongPress" />
     <!-- U+200C: ZERO WIDTH NON-JOINER
          U+200D: ZERO WIDTH JOINER -->
     <key-style
@@ -115,8 +114,7 @@
         latin:keyIcon="!icon/zwnj_key"
         latin:moreKeys="!icon/zwj_key|&#x200D;"
         latin:keyLabelFlags="hasPopupHint"
-        latin:keyActionFlags="noKeyPreview"
-        latin:backgroundType="functional" />
+        latin:keyActionFlags="noKeyPreview" />
     <key-style
         latin:styleName="shortcutKeyStyle"
         latin:code="!code/key_shortcut"
@@ -137,8 +135,7 @@
         latin:code="!code/key_language_switch"
         latin:keyIcon="!icon/language_switch_key"
         latin:keyActionFlags="noKeyPreview|altCodeWhileTyping|enableLongPress"
-        latin:altCode="!code/key_space"
-        latin:backgroundType="functional" />
+        latin:altCode="!code/key_space" />
     <key-style
         latin:styleName="tabKeyStyle"
         latin:code="!code/key_tab"
diff --git a/java/res/xml/row_qwerty4.xml b/java/res/xml/row_qwerty4.xml
index ecb95e7..43385d2 100644
--- a/java/res/xml/row_qwerty4.xml
+++ b/java/res/xml/row_qwerty4.xml
@@ -38,15 +38,14 @@
             >
                 <!-- U+064B: "ً" ARABIC FATHATAN -->
                 <Key
-                    latin:keyLabel="."
                     latin:keyHintLabel="&#x064B;"
                     latin:keyLabelFlags="hasPopupHint|hasShiftedLetterHint"
                     latin:moreKeys="!text/more_keys_for_arabic_diacritics"
-                    latin:backgroundType="functional" />
+                    latin:keyStyle="punctuationKeyStyle" />
             </case>
             <default>
                 <Key
-                latin:keyStyle="punctuationKeyStyle" />
+                    latin:keyStyle="punctuationKeyStyle" />
             </default>
         </switch>
         <Key
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index ed873a7..e1e1ca9 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -227,7 +227,7 @@
         row.setXPos(keyXPos + keyWidth);
 
         mBackgroundType = style.getInt(keyAttr,
-                R.styleable.Keyboard_Key_backgroundType, BACKGROUND_TYPE_NORMAL);
+                R.styleable.Keyboard_Key_backgroundType, row.getDefaultBackgroundType());
 
         mVisualInsetsLeft = Math.round(Keyboard.Builder.getDimensionOrFraction(keyAttr,
                 R.styleable.Keyboard_Key_visualInsetsLeft, params.mBaseWidth, 0));
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 0be4cf3..21f175d 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -533,6 +533,8 @@
             public final int mRowHeight;
             /** Default keyLabelFlags in this row. */
             private int mDefaultKeyLabelFlags;
+            /** Default backgroundType for this row */
+            private int mDefaultBackgroundType;
 
             private final int mCurrentY;
             // Will be updated by {@link Key}'s constructor.
@@ -551,8 +553,11 @@
                 mDefaultKeyWidth = Builder.getDimensionOrFraction(keyAttr,
                         R.styleable.Keyboard_Key_keyWidth,
                         params.mBaseWidth, params.mDefaultKeyWidth);
+                mDefaultBackgroundType = keyAttr.getInt(R.styleable.Keyboard_Key_backgroundType,
+                        Key.BACKGROUND_TYPE_NORMAL);
                 keyAttr.recycle();
 
+                // TODO: Initialize this with <Row> attribute as backgroundType is done.
                 mDefaultKeyLabelFlags = 0;
                 mCurrentY = y;
                 mCurrentX = 0.0f;
@@ -574,6 +579,14 @@
                 mDefaultKeyLabelFlags = keyLabelFlags;
             }
 
+            public int getDefaultBackgroundType() {
+                return mDefaultBackgroundType;
+            }
+
+            public void setDefaultBackgroundType(int backgroundType) {
+                mDefaultBackgroundType = backgroundType;
+            }
+
             public void setXPos(float keyXPos) {
                 mCurrentX = keyXPos;
             }
@@ -952,6 +965,7 @@
                 int keyboardLayout = 0;
                 float savedDefaultKeyWidth = 0;
                 int savedDefaultKeyLabelFlags = 0;
+                int savedDefaultBackgroundType = Key.BACKGROUND_TYPE_NORMAL;
                 try {
                     XmlParseUtils.checkAttributeExists(keyboardAttr,
                             R.styleable.Keyboard_Include_keyboardLayout, "keyboardLayout",
@@ -959,22 +973,26 @@
                     keyboardLayout = keyboardAttr.getResourceId(
                             R.styleable.Keyboard_Include_keyboardLayout, 0);
                     if (row != null) {
-                        savedDefaultKeyWidth = row.getDefaultKeyWidth();
-                        savedDefaultKeyLabelFlags = row.getDefaultKeyLabelFlags();
                         if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) {
                             // Override current x coordinate.
                             row.setXPos(row.getKeyX(keyAttr));
                         }
+                        // TODO: Remove this if-clause and do the same as backgroundType below.
+                        savedDefaultKeyWidth = row.getDefaultKeyWidth();
                         if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyWidth)) {
                             // Override default key width.
                             row.setDefaultKeyWidth(row.getKeyWidth(keyAttr));
                         }
-                        if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyLabelFlags)) {
-                            // Override default key label flags.
-                            row.setDefaultKeyLabelFlags(
-                                    keyAttr.getInt(R.styleable.Keyboard_Key_keyLabelFlags, 0)
-                                    | savedDefaultKeyLabelFlags);
-                        }
+                        savedDefaultKeyLabelFlags = row.getDefaultKeyLabelFlags();
+                        // Bitwise-or default keyLabelFlag if exists.
+                        row.setDefaultKeyLabelFlags(keyAttr.getInt(
+                                R.styleable.Keyboard_Key_keyLabelFlags, 0)
+                                | savedDefaultKeyLabelFlags);
+                        savedDefaultBackgroundType = row.getDefaultBackgroundType();
+                        // Override default backgroundType if exists.
+                        row.setDefaultBackgroundType(keyAttr.getInt(
+                                R.styleable.Keyboard_Key_backgroundType,
+                                savedDefaultBackgroundType));
                     }
                 } finally {
                     keyboardAttr.recycle();
@@ -991,9 +1009,10 @@
                     parseMerge(parserForInclude, row, skip);
                 } finally {
                     if (row != null) {
-                        // Restore default key width and key label flags.
+                        // Restore default keyWidth, keyLabelFlags, and backgroundType.
                         row.setDefaultKeyWidth(savedDefaultKeyWidth);
                         row.setDefaultKeyLabelFlags(savedDefaultKeyLabelFlags);
+                        row.setDefaultBackgroundType(savedDefaultBackgroundType);
                     }
                     parserForInclude.close();
                 }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index ea2746d..bfdc1e3 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -497,7 +497,7 @@
         // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged()
         // is not guaranteed. It may even be called at the same time on a different thread.
         if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
-        mUserHistoryDictionary = new UserHistoryDictionary(
+        mUserHistoryDictionary = UserHistoryDictionary.getInstance(
                 this, localeStr, Suggest.DIC_USER_HISTORY, mPrefs);
         mSuggest.setUserHistoryDictionary(mUserHistoryDictionary);
     }
diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
index a6ff895..a73e71b 100644
--- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
@@ -29,7 +29,9 @@
 
 import com.android.inputmethod.latin.UserHistoryForgettingCurveUtils.ForgettingCurveParams;
 
+import java.lang.ref.SoftReference;
 import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Locally gathers stats about the words user types and various other signals like auto-correction
@@ -38,6 +40,7 @@
 public class UserHistoryDictionary extends ExpandableDictionary {
     private static final String TAG = "UserHistoryDictionary";
     public static final boolean DBG_SAVE_RESTORE = false;
+    public static final boolean PROFILE_SAVE_RESTORE = LatinImeLogger.sDBG;
 
     /** Any pair being typed or picked */
     private static final int FREQUENCY_FOR_TYPED = 2;
@@ -77,13 +80,14 @@
     /** Locale for which this user history dictionary is storing words */
     private final String mLocale;
 
-    private UserHistoryDictionaryBigramList mBigramList =
+    private final UserHistoryDictionaryBigramList mBigramList =
             new UserHistoryDictionaryBigramList();
-    private final Object mPendingWritesLock = new Object();
     private static volatile boolean sUpdatingDB = false;
     private final SharedPreferences mPrefs;
 
     private final static HashMap<String, String> sDictProjectionMap;
+    private final static ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>>
+            sLangDictCache = new ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>>();
 
     static {
         sDictProjectionMap = new HashMap<String, String>();
@@ -107,7 +111,26 @@
         sDeleteHistoryBigrams = deleteHistoryBigram;
     }
 
-    public UserHistoryDictionary(final Context context, final String locale, final int dicTypeId,
+    public synchronized static UserHistoryDictionary getInstance(
+            final Context context, final String locale,
+            final int dictTypeId, final SharedPreferences sp) {
+        if (sLangDictCache.containsKey(locale)) {
+            final SoftReference<UserHistoryDictionary> ref = sLangDictCache.get(locale);
+            final UserHistoryDictionary dict = ref == null ? null : ref.get();
+            if (dict != null) {
+                if (PROFILE_SAVE_RESTORE) {
+                    Log.w(TAG, "Use cached UserHistoryDictionary for " + locale);
+                }
+                return dict;
+            }
+        }
+        final UserHistoryDictionary dict =
+                new UserHistoryDictionary(context, locale, dictTypeId, sp);
+        sLangDictCache.put(locale, new SoftReference<UserHistoryDictionary>(dict));
+        return dict;
+    }
+
+    private UserHistoryDictionary(final Context context, final String locale, final int dicTypeId,
             SharedPreferences sp) {
         super(context, dicTypeId);
         mLocale = locale;
@@ -123,12 +146,13 @@
     @Override
     public void close() {
         flushPendingWrites();
-        SettingsValues.setLastUserHistoryWriteTime(mPrefs, mLocale);
         // Don't close the database as locale changes will require it to be reopened anyway
         // Also, the database is written to somewhat frequently, so it needs to be kept alive
         // throughout the life of the process.
         // mOpenHelper.close();
-        super.close();
+        // Ignore close because we cache UserHistoryDictionary for each language. See getInstance()
+        // above.
+        // super.close();
     }
 
     /**
@@ -160,7 +184,7 @@
         } else {
             freq = super.setBigramAndGetFrequency(word1, word2, new ForgettingCurveParams(isValid));
         }
-        synchronized (mPendingWritesLock) {
+        synchronized (mBigramList) {
             mBigramList.addBigram(word1, word2);
         }
 
@@ -168,7 +192,7 @@
     }
 
     public boolean cancelAddingUserHistory(String word1, String word2) {
-        synchronized (mPendingWritesLock) {
+        synchronized (mBigramList) {
             if (mBigramList.removeBigram(word1, word2)) {
                 return super.removeBigram(word1, word2);
             }
@@ -180,19 +204,17 @@
      * Schedules a background thread to write any pending words to the database.
      */
     private void flushPendingWrites() {
-        synchronized (mPendingWritesLock) {
+        synchronized (mBigramList) {
             // Nothing pending? Return
             if (mBigramList.isEmpty()) return;
             // Create a background thread to write the pending entries
-            new UpdateDbTask(sOpenHelper, mBigramList, mLocale, this).execute();
-            // Create a new map for writing new entries into while the old one is written to db
-            mBigramList = new UserHistoryDictionaryBigramList();
+            new UpdateDbTask(sOpenHelper, mBigramList, mLocale, this, mPrefs).execute();
         }
     }
 
     /** Used for testing purpose **/
     void waitUntilUpdateDBDone() {
-        synchronized (mPendingWritesLock) {
+        synchronized (mBigramList) {
             while (sUpdatingDB) {
                 try {
                     Thread.sleep(100);
@@ -205,41 +227,46 @@
 
     @Override
     public void loadDictionaryAsync() {
-        final long last = SettingsValues.getLastUserHistoryWriteTime(mPrefs, mLocale);
-        final long now = System.currentTimeMillis();
-        // Load the words that correspond to the current input locale
-        final Cursor cursor = query(MAIN_COLUMN_LOCALE + "=?", new String[] { mLocale });
-        if (null == cursor) return;
-        try {
-            if (cursor.moveToFirst()) {
-                final int word1Index = cursor.getColumnIndex(MAIN_COLUMN_WORD1);
-                final int word2Index = cursor.getColumnIndex(MAIN_COLUMN_WORD2);
-                final int fcIndex = cursor.getColumnIndex(COLUMN_FORGETTING_CURVE_VALUE);
-                while (!cursor.isAfterLast()) {
-                    final String word1 = cursor.getString(word1Index);
-                    final String word2 = cursor.getString(word2Index);
-                    final int fc = cursor.getInt(fcIndex);
-                    if (DBG_SAVE_RESTORE) {
-                        Log.d(TAG, "--- Load user history: " + word1 + ", " + word2 + ","
-                                + mLocale + "," + this);
-                    }
-                    // Safeguard against adding really long words. Stack may overflow due
-                    // to recursive lookup
-                    if (null == word1) {
-                        super.addWord(word2, null /* shortcut */, fc);
-                    } else if (word1.length() < BinaryDictionary.MAX_WORD_LENGTH
-                            && word2.length() < BinaryDictionary.MAX_WORD_LENGTH) {
-                        super.setBigramAndGetFrequency(
-                                word1, word2, new ForgettingCurveParams(fc, now, last));
-                    }
-                    synchronized(mPendingWritesLock) {
+        synchronized(mBigramList) {
+            final long last = SettingsValues.getLastUserHistoryWriteTime(mPrefs, mLocale);
+            final long now = System.currentTimeMillis();
+            // Load the words that correspond to the current input locale
+            final Cursor cursor = query(MAIN_COLUMN_LOCALE + "=?", new String[] { mLocale });
+            if (null == cursor) return;
+            try {
+                if (cursor.moveToFirst()) {
+                    final int word1Index = cursor.getColumnIndex(MAIN_COLUMN_WORD1);
+                    final int word2Index = cursor.getColumnIndex(MAIN_COLUMN_WORD2);
+                    final int fcIndex = cursor.getColumnIndex(COLUMN_FORGETTING_CURVE_VALUE);
+                    while (!cursor.isAfterLast()) {
+                        final String word1 = cursor.getString(word1Index);
+                        final String word2 = cursor.getString(word2Index);
+                        final int fc = cursor.getInt(fcIndex);
+                        if (DBG_SAVE_RESTORE) {
+                            Log.d(TAG, "--- Load user history: " + word1 + ", " + word2 + ","
+                                    + mLocale + "," + this);
+                        }
+                        // Safeguard against adding really long words. Stack may overflow due
+                        // to recursive lookup
+                        if (null == word1) {
+                            super.addWord(word2, null /* shortcut */, fc);
+                        } else if (word1.length() < BinaryDictionary.MAX_WORD_LENGTH
+                                && word2.length() < BinaryDictionary.MAX_WORD_LENGTH) {
+                            super.setBigramAndGetFrequency(
+                                    word1, word2, new ForgettingCurveParams(fc, now, last));
+                        }
                         mBigramList.addBigram(word1, word2, (byte)fc);
+                        cursor.moveToNext();
                     }
-                    cursor.moveToNext();
+                }
+            } finally {
+                cursor.close();
+                if (PROFILE_SAVE_RESTORE) {
+                    final long diff = System.currentTimeMillis() - now;
+                    Log.w(TAG, "PROF: Load User HistoryDictionary: "
+                            + mLocale + ", " + diff + "ms.");
                 }
             }
-        } finally {
-            cursor.close();
         }
     }
 
@@ -317,14 +344,16 @@
         private final DatabaseHelper mDbHelper;
         private final String mLocale;
         private final UserHistoryDictionary mUserHistoryDictionary;
+        private final SharedPreferences mPrefs;
 
         public UpdateDbTask(
                 DatabaseHelper openHelper, UserHistoryDictionaryBigramList pendingWrites,
-                String locale, UserHistoryDictionary dict) {
+                String locale, UserHistoryDictionary dict, SharedPreferences prefs) {
             mBigramList = pendingWrites;
             mLocale = locale;
             mDbHelper = openHelper;
             mUserHistoryDictionary = dict;
+            mPrefs = prefs;
         }
 
         /** Prune any old data if the database is getting too big. */
@@ -363,37 +392,39 @@
 
         @Override
         protected Void doInBackground(Void... v) {
-            SQLiteDatabase db = null;
-            try {
-                db = mDbHelper.getWritableDatabase();
-            } catch (android.database.sqlite.SQLiteCantOpenDatabaseException e) {
-                // If we can't open the db, don't do anything. Exit through the next test
-                // for non-nullity of the db variable.
-            }
-            if (null == db) {
-                // Not much we can do. Just exit.
-                sUpdatingDB = false;
-                return null;
-            }
-            db.execSQL("PRAGMA foreign_keys = ON;");
-            final boolean addLevel0Bigram = mBigramList.size() <= sMaxHistoryBigrams;
+            synchronized(mBigramList) {
+                final long now = PROFILE_SAVE_RESTORE ? System.currentTimeMillis() : 0;
+                int profTotal = 0;
+                int profInsert = 0;
+                int profDelete = 0;
+                SQLiteDatabase db = null;
+                try {
+                    db = mDbHelper.getWritableDatabase();
+                } catch (android.database.sqlite.SQLiteCantOpenDatabaseException e) {
+                    // If we can't open the db, don't do anything. Exit through the next test
+                    // for non-nullity of the db variable.
+                }
+                if (null == db) {
+                    // Not much we can do. Just exit.
+                    sUpdatingDB = false;
+                    return null;
+                }
+                db.execSQL("PRAGMA foreign_keys = ON;");
+                final boolean addLevel0Bigram = mBigramList.size() <= sMaxHistoryBigrams;
 
-            // Write all the entries to the db
-            for (String word1 : mBigramList.keySet()) {
-                final HashMap<String, Byte> word1Bigrams = mBigramList.getBigrams(word1);
-                for (String word2 : word1Bigrams.keySet()) {
-                    // Get new frequency. Do not insert shortcuts/bigrams which freq is "-1".
-                    final int freq; // -1, or 0~255
-                    if (word1 == null) {
-                        freq = FREQUENCY_FOR_TYPED;
-                    } else {
-                        final NextWord nw = mUserHistoryDictionary.getBigramWord(word1, word2);
-                        if (nw != null) {
-                            final ForgettingCurveParams fcp = nw.getFcParams();
+                // Write all the entries to the db
+                for (String word1 : mBigramList.keySet()) {
+                    final HashMap<String, Byte> word1Bigrams = mBigramList.getBigrams(word1);
+                    for (String word2 : word1Bigrams.keySet()) {
+                        if (PROFILE_SAVE_RESTORE) {
+                            ++profTotal;
+                        }
+                        // Get new frequency. Do not insert unigrams/bigrams which freq is "-1".
+                        final int freq; // -1, or 0~255
+                        if (word1 == null) { // unigram
+                            freq = FREQUENCY_FOR_TYPED;
                             final byte prevFc = word1Bigrams.get(word2);
-                            final byte fc = (byte)fcp.getFc();
-                            final boolean isValid = fcp.isValid();
-                            if (prevFc > 0 && prevFc == fc) {
+                            if (prevFc == FREQUENCY_FOR_TYPED) {
                                 // No need to update since we found no changes for this entry.
                                 // Just skip to the next entry.
                                 if (DBG_SAVE_RESTORE) {
@@ -401,67 +432,100 @@
                                             + "," + prevFc);
                                 }
                                 continue;
-                            } else if (UserHistoryForgettingCurveUtils.
-                                    needsToSave(fc, isValid, addLevel0Bigram)) {
-                                freq = fc;
+                            }
+                        } else { // bigram
+                            final NextWord nw = mUserHistoryDictionary.getBigramWord(word1, word2);
+                            if (nw != null) {
+                                final ForgettingCurveParams fcp = nw.getFcParams();
+                                final byte prevFc = word1Bigrams.get(word2);
+                                final byte fc = (byte)fcp.getFc();
+                                final boolean isValid = fcp.isValid();
+                                if (prevFc > 0 && prevFc == fc) {
+                                    // No need to update since we found no changes for this entry.
+                                    // Just skip to the next entry.
+                                    if (DBG_SAVE_RESTORE) {
+                                        Log.d(TAG, "Skip update user history: " + word1 + ","
+                                                + word2 + "," + prevFc);
+                                    }
+                                    continue;
+                                } else if (UserHistoryForgettingCurveUtils.
+                                        needsToSave(fc, isValid, addLevel0Bigram)) {
+                                    freq = fc;
+                                } else {
+                                    freq = -1;
+                                }
                             } else {
                                 freq = -1;
                             }
-                        } else {
-                            freq = -1;
                         }
-                    }
-                    // TODO: this process of making a text search for each pair each time
-                    // is terribly inefficient. Optimize this.
-                    // Find pair id
-                    Cursor c = null;
-                    try {
-                        if (null != word1) {
-                            c = db.query(MAIN_TABLE_NAME, new String[] { MAIN_COLUMN_ID },
-                                    MAIN_COLUMN_WORD1 + "=? AND " + MAIN_COLUMN_WORD2 + "=? AND "
-                                            + MAIN_COLUMN_LOCALE + "=?",
-                                            new String[] { word1, word2, mLocale }, null, null,
-                                            null);
-                        } else {
-                            c = db.query(MAIN_TABLE_NAME, new String[] { MAIN_COLUMN_ID },
-                                    MAIN_COLUMN_WORD1 + " IS NULL AND " + MAIN_COLUMN_WORD2
-                                            + "=? AND " + MAIN_COLUMN_LOCALE + "=?",
-                                            new String[] { word2, mLocale }, null, null, null);
-                        }
-
-                        final int pairId;
-                        if (c.moveToFirst()) {
-                            // Delete existing pair
-                            pairId = c.getInt(c.getColumnIndex(MAIN_COLUMN_ID));
-                            db.delete(FREQ_TABLE_NAME, FREQ_COLUMN_PAIR_ID + "=?",
-                                    new String[] { Integer.toString(pairId) });
-                        } else {
-                            // Create new pair
-                            Long pairIdLong = db.insert(MAIN_TABLE_NAME, null,
-                                    getContentValues(word1, word2, mLocale));
-                            pairId = pairIdLong.intValue();
-                        }
-                        if (freq > 0) {
-                            if (DBG_SAVE_RESTORE) {
-                                Log.d(TAG, "--- Save user history: " + word1 + ", " + word2
-                                        + mLocale + "," + this);
+                        // TODO: this process of making a text search for each pair each time
+                        // is terribly inefficient. Optimize this.
+                        // Find pair id
+                        Cursor c = null;
+                        try {
+                            if (null != word1) {
+                                c = db.query(MAIN_TABLE_NAME, new String[] { MAIN_COLUMN_ID },
+                                        MAIN_COLUMN_WORD1 + "=? AND " + MAIN_COLUMN_WORD2 + "=? AND "
+                                                + MAIN_COLUMN_LOCALE + "=?",
+                                                new String[] { word1, word2, mLocale }, null, null,
+                                                null);
+                            } else {
+                                c = db.query(MAIN_TABLE_NAME, new String[] { MAIN_COLUMN_ID },
+                                        MAIN_COLUMN_WORD1 + " IS NULL AND " + MAIN_COLUMN_WORD2
+                                                + "=? AND " + MAIN_COLUMN_LOCALE + "=?",
+                                                new String[] { word2, mLocale }, null, null, null);
                             }
-                            // Insert new frequency
-                            db.insert(FREQ_TABLE_NAME, null,
-                                    getFrequencyContentValues(pairId, freq));
-                        }
-                    } finally {
-                        if (c != null) {
-                            c.close();
+
+                            final int pairId;
+                            if (c.moveToFirst()) {
+                                if (PROFILE_SAVE_RESTORE) {
+                                    ++profDelete;
+                                }
+                                // Delete existing pair
+                                pairId = c.getInt(c.getColumnIndex(MAIN_COLUMN_ID));
+                                db.delete(FREQ_TABLE_NAME, FREQ_COLUMN_PAIR_ID + "=?",
+                                        new String[] { Integer.toString(pairId) });
+                            } else {
+                                // Create new pair
+                                Long pairIdLong = db.insert(MAIN_TABLE_NAME, null,
+                                        getContentValues(word1, word2, mLocale));
+                                pairId = pairIdLong.intValue();
+                            }
+                            if (freq > 0) {
+                                if (PROFILE_SAVE_RESTORE) {
+                                    ++profInsert;
+                                }
+                                if (DBG_SAVE_RESTORE) {
+                                    Log.d(TAG, "--- Save user history: " + word1 + ", " + word2
+                                            + mLocale + "," + this);
+                                }
+                                // Insert new frequency
+                                db.insert(FREQ_TABLE_NAME, null,
+                                        getFrequencyContentValues(pairId, freq));
+                                // Update an existing bigram entry in mBigramList too in order to
+                                // synchronize the SQL DB and mBigramList.
+                                mBigramList.updateBigram(word1, word2, (byte)freq);
+                            }
+                        } finally {
+                            if (c != null) {
+                                c.close();
+                            }
                         }
                     }
                 }
-            }
 
-            checkPruneData(db);
-            sUpdatingDB = false;
-
-            return null;
+                checkPruneData(db);
+                // Save the timestamp after we finish writing the SQL DB.
+                SettingsValues.setLastUserHistoryWriteTime(mPrefs, mLocale);
+                sUpdatingDB = false;
+                if (PROFILE_SAVE_RESTORE) {
+                    final long diff = System.currentTimeMillis() - now;
+                    Log.w(TAG, "PROF: Write User HistoryDictionary: " + mLocale + ", "+ diff
+                            + "ms. Total: " + profTotal + ". Insert: " + profInsert + ". Delete: "
+                            + profDelete);
+                }
+                return null;
+            } // synchronized
         }
 
         private static ContentValues getContentValues(String word1, String word2, String locale) {
diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java
index 96400dd..2884774 100644
--- a/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java
+++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java
@@ -39,13 +39,19 @@
         mBigramMap.clear();
     }
 
+    /**
+     * Called when the user typed a word.
+     */
     public void addBigram(String word1, String word2) {
         addBigram(word1, word2, FORGETTING_CURVE_INITIAL_VALUE);
     }
 
+    /**
+     * Called when loaded from the SQL DB.
+     */
     public void addBigram(String word1, String word2, byte fcValue) {
         if (UserHistoryDictionary.DBG_SAVE_RESTORE) {
-            Log.d(TAG, "--- add bigram: " + word1 + ", " + word2);
+            Log.d(TAG, "--- add bigram: " + word1 + ", " + word2 + ", " + fcValue);
         }
         final HashMap<String, Byte> map;
         if (mBigramMap.containsKey(word1)) {
@@ -60,6 +66,25 @@
         }
     }
 
+    /**
+     * Called when inserted to the SQL DB.
+     */
+    public void updateBigram(String word1, String word2, byte fcValue) {
+        if (UserHistoryDictionary.DBG_SAVE_RESTORE) {
+            Log.d(TAG, "--- update bigram: " + word1 + ", " + word2 + ", " + fcValue);
+        }
+        final HashMap<String, Byte> map;
+        if (mBigramMap.containsKey(word1)) {
+            map = mBigramMap.get(word1);
+        } else {
+            return;
+        }
+        if (!map.containsKey(word2)) {
+            return;
+        }
+        map.put(word2, fcValue);
+    }
+
     public int size() {
         return mSize;
     }