Merge "Import translations. DO NOT MERGE"
diff --git a/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java b/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java
index c22c577..9d7258d 100644
--- a/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java
+++ b/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java
@@ -45,4 +45,9 @@
      * When {@code false}, the split keyboard is not yet ready to be enabled.
      */
     public static final boolean IS_SPLIT_KEYBOARD_SUPPORTED = true;
+
+    /**
+     * When {@code false}, account sign-in in keyboard is not yet ready to be enabled.
+     */
+    public static final boolean ENABLE_ACCOUNT_SIGN_IN = false;
 }
diff --git a/java-overridable/src/com/android/inputmethod/latin/utils/LoginAccountUtils.java b/java-overridable/src/com/android/inputmethod/latin/utils/LoginAccountUtils.java
new file mode 100644
index 0000000..faada29
--- /dev/null
+++ b/java-overridable/src/com/android/inputmethod/latin/utils/LoginAccountUtils.java
@@ -0,0 +1,40 @@
+/*
+ * 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.latin.utils;
+
+import android.content.Context;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Utility class for retrieving accounts that may be used for login.
+ */
+public class LoginAccountUtils {
+    private LoginAccountUtils() {
+        // This utility class is not publicly instantiable.
+    }
+
+    /**
+     * Get the accounts available for login.
+     *
+     * @return an array of accounts. Empty (never null) if no accounts are available for login.
+     */
+    @Nonnull
+    public static String[] getAccountsForLogin(final Context context) {
+        return new String[0];
+    }
+}
diff --git a/java-overridable/src/com/android/inputmethod/latin/utils/StatsUtils.java b/java-overridable/src/com/android/inputmethod/latin/utils/StatsUtils.java
index 38735ec..ad34dc2 100644
--- a/java-overridable/src/com/android/inputmethod/latin/utils/StatsUtils.java
+++ b/java-overridable/src/com/android/inputmethod/latin/utils/StatsUtils.java
@@ -20,6 +20,8 @@
 import com.android.inputmethod.latin.SuggestedWords;
 import com.android.inputmethod.latin.settings.SettingsValues;
 
+import javax.annotation.Nullable;
+
 public final class StatsUtils {
 
     private StatsUtils() {
@@ -63,4 +65,18 @@
 
     public static void onStartInputView(int inputType, int displayOrientation, boolean restarting) {
     }
+
+    public static void onAutoCorrection(final String typedWord, final String autoCorrectionWord,
+            final boolean isBatchInput, @Nullable final String dictionaryType) {
+    }
+
+    public static void onWordCommitUserTyped(final String commitWord, final boolean isBatchMode) {
+    }
+
+    public static void onWordCommitAutoCorrect(final String commitWord, final boolean isBatchMode) {
+    }
+
+    public static void onWordCommitSuggestionPickedManually(
+            final String commitWord, final boolean isBatchMode) {
+    }
 }
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index 054c415..b29a6e2 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -158,5 +158,9 @@
                 <action android:name="android.intent.action.MAIN"/>
             </intent-filter>
         </activity>
+
+        <!-- Unexported activity used for tests. -->
+        <activity android:name=".settings.TestFragmentActivity"
+                android:exported="false" />
     </application>
 </manifest>
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml
index 1647a4e..e9053c4 100644
--- a/java/res/values-af/strings.xml
+++ b/java/res/values-af/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibreer met sleuteldruk"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Klank met sleuteldruk"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Opspring met sleuteldruk"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Invoervoorkeure"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Voorkoms"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Veeltalige opsies"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Gebaarinvoervoorkeure"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Voorkeure"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Voorkoms en uitlegte"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Veeltalige opsies"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Gebaarinvoer"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Tekskorrigering"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Gevorderd"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Skakel oor na die ander invoermetodes"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Taal-wisselsleutel dek ook ander invoermetodes"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Taal-wisselsleutel"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Steminvoerinstellings"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Geen steminvoermetodes geaktiveer nie. Gaan taal- en invoerinstellings na."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Stel invoermetodes op"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Invoertale"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Tale"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Hulp en terugvoering"</string>
-    <string name="select_language" msgid="3693815588777926848">"Invoertale"</string>
+    <string name="select_language" msgid="5709487854987078367">"Tale"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Raak weer om te stoor"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Raak hier om te stoor"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Woordeboek beskikbaar"</string>
diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml
index 753e672..14beb73 100644
--- a/java/res/values-am/strings.xml
+++ b/java/res/values-am/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"በቁልፍመጫንጊዜ አንዝር"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"በቁልፍ መጫን ላይ የሚወጣ ድምፅ"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"ቁልፍ ጫን ላይ ብቅ ባይ"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"የግቤት ምርጫዎች"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"ገጽታ"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"ባለብዙ ቋንቋ አማራጮች"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"የመተየብ እንቅስቃሴ ምልክት ምርጫዎች"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"ምርጫዎች"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"መልክ እና አቀማመጦች"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"ባለብዙ ቋንቋ አማራጮች"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"በጣት ምልክት መተየብ"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"ፅሁፍ ማስተካከያ"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"የላቀ"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"ገፅታ"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"ወደ ሌሎች የግቤት ስልቶች ቀይር"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"የቋንቋ መቀየሪያ ቁልፍ ሌሎች የግቤት ስልቶችንም ይሸፍናል"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"የቋንቋ መቀየሪያ ቁልፍ"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"የድምፅ ግቤት ቁልፍ"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"ምንም የግቤት ስልቶች አልነቁም። የቋንቋ እና የግቤት ቅንብሮችን ይፈትሹ።"</string>
     <string name="configure_input_method" msgid="373356270290742459">"ግቤት ሜተዶችን አዋቀር"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"ቋንቋዎች አግቤት"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"ቋንቋዎች"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"እገዛ እና ግብረመልስ"</string>
-    <string name="select_language" msgid="3693815588777926848">"ቋንቋዎች አግቤት"</string>
+    <string name="select_language" msgid="5709487854987078367">"ቋንቋዎች"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"ለማስቀመጥ እንደገና ንካ"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"ለማስቀመጥ እዚህ ይንኩ"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"መዝገበ ቃላት አለ"</string>
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
index c45924b..c549a07 100644
--- a/java/res/values-ar/strings.xml
+++ b/java/res/values-ar/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"اهتزاز عند ضغط مفتاح"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"صوت عند الضغط على مفتاح"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"انبثاق عند ضغط مفتاح"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"تفضيلات الإدخال"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"المظهر"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"خيارات تعدد اللغات"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"تفضيلات كتابة الإيماءات"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"التفضيلات"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"المظهر والتنسيقات"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"خيارات اللغات المتعددة"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"الكتابة بالإشارة"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"تصحيح النص"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"الإعدادات المتقدمة"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"المظهر"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"التبديل إلى أسلوب إدخال آخر"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"يغطي مفتاح تبديل اللغات أساليب الإدخال الأخرى أيضًا"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"مفتاح تبديل اللغة"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"مفتاح الإدخال الصوتي"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"لم يتم تمكين أي أساليب إدخال صوتي. تحقق من إعدادات اللغة والإدخال."</string>
     <string name="configure_input_method" msgid="373356270290742459">"تهيئة طرق الإدخال"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"لغات الإدخال"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"اللغات"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"المساعدة والتعليقات"</string>
-    <string name="select_language" msgid="3693815588777926848">"لغات الإدخال"</string>
+    <string name="select_language" msgid="5709487854987078367">"اللغات"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"المس مرة أخرى للحفظ"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"المس هنا للحفظ"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"القاموس متاح"</string>
diff --git a/java/res/values-az-rAZ/strings.xml b/java/res/values-az-rAZ/strings.xml
index fb01d72..84543af 100644
--- a/java/res/values-az-rAZ/strings.xml
+++ b/java/res/values-az-rAZ/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrasiyalı klikləmə"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Klikləmə səsi"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Klikləmədə popup"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Daxiletmə tərcihləri"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Görünüş"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Çoxdilli seçimlər"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Jest ilə yazı tərcihləri"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Seçimlər"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Görünüş və düzənlər"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Çoxdilli seçimlər"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Jest ilə yazma"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Mətn korreksiyası"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Qabaqcıl"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Digər daxiletmə metodlarına keçin"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Dil keçid düyməsi başqa daxiletmə metodlarını da əhatə edir"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Dil keçidi düyməsi"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Səs daxiletmə klavişi"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Heç bir səs daxiletmə metodu aktiv deyil. Dil və daxiletmə ayarlarını yoxlayın."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Daxiletmə üsullarını sazla"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Daxiletmə dilləri"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Dillər"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Yardım və geri əlaqə"</string>
-    <string name="select_language" msgid="3693815588777926848">"Daxiletmə dilləri"</string>
+    <string name="select_language" msgid="5709487854987078367">"Dillər"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Yadda saxlamaq üçün yenidən toxunun"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Yadda saxlamaq üçün buraya toxunun"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Lüğət mövcuddur"</string>
diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml
index 0c449ba..9e8d633 100644
--- a/java/res/values-bg/strings.xml
+++ b/java/res/values-bg/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Да вибрира при натискане на клавиш"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Звук при натискане на клавиш"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Изскачащ прозорец при натискане на клавиш"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Въвеждане: Предпочитания"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Облик"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Опции за няколко езика"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Въвежд. чрез жест: Предпоч."</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Предпочитания"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Облик и оформления"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Опции за няколко езика"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Въвеждане чрез жест"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Коригиране на текст"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Разширени"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Тема"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Други методи за въвеждане"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Клавишът за превкл. на езика обхваща и други методи за въвеждане"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Клавиш за превкл. на езика"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Клавиш за гласово въвеждане"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Няма активирани методи на гласово въвеждане. Проверете настройките за език и въвеждане."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Конфигуриране на въвеждането"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Входни езици"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Езици"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Помощ и отзиви"</string>
-    <string name="select_language" msgid="3693815588777926848">"Езици за въвеждане"</string>
+    <string name="select_language" msgid="5709487854987078367">"Езици"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Докоснете отново, за да запазите"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Докоснете тук, за да запазите"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Има достъп до речник"</string>
diff --git a/java/res/values-bn-rBD/strings.xml b/java/res/values-bn-rBD/strings.xml
index f3030d8..5c72120 100644
--- a/java/res/values-bn-rBD/strings.xml
+++ b/java/res/values-bn-rBD/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"কীপ্রেস এর সময় কম্পন"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"কীপ্রেস এর সময়ের শব্দ"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"কীপ্রেস এর ফলে পপআপ"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"ইনপুট পছন্দগুলি"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"উপস্থিতি"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"একাধিক ভাষা বিকল্পগুলি"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"অঙ্গভঙ্গি টাইপিং অভিরুচি"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"পছন্দসমূহ"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"চেহারা ও লেআউটগুলি"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"বহুভাষিক বিকল্পগুলি"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"অঙ্গভঙ্গি টাইপিং"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"পাঠ্য সংশোধন"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"উন্নত"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"থিম"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"অন্য ইনপুট পদ্ধতিতে স্যুইচ করুন"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"ভাষা স্যুইচ কীতে অন্যান্য ইনপুট পদ্ধতি পাওয়া যায়"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"ভাষা স্যুইচ কী"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"ভয়েস ইনপুট কী"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"কোনো ভয়েস ইনপুট পদ্ধতি সক্ষম নয়। ভাষা &amp; ইনপুট সেটিংস পরীক্ষা করুন।"</string>
     <string name="configure_input_method" msgid="373356270290742459">"ইনপুট পদ্ধতি কনফিগার করুন"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"ইনপুট ভাষাগুলি"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"ভাষাগুলি"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"সহায়তা এবং প্রতিক্রিয়া"</string>
-    <string name="select_language" msgid="3693815588777926848">"ইনপুট ভাষাগুলি"</string>
+    <string name="select_language" msgid="5709487854987078367">"ভাষাগুলি"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"সংরক্ষণ করতে আবার ছোঁন"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"সংরক্ষণ করতে এখানে স্পর্শ করুন"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"অভিধান উপলব্ধ"</string>
@@ -121,8 +122,8 @@
     <string name="setup_next_action" msgid="371821437915144603">"পরবর্তী পদক্ষেপ"</string>
     <string name="setup_steps_title" msgid="6400373034871816182">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> সেট আপ হচ্ছে"</string>
     <string name="setup_step1_title" msgid="3147967630253462315">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> সক্ষম করুন"</string>
-    <string name="setup_step1_instruction" msgid="2578631936624637241">"দয়া করে আপনার ভাষা ও ইনপুট সেটিংস <xliff:g id="APPLICATION_NAME">%s</xliff:g> পরীক্ষা করুন। এর ফলে এটি আপনার ডিভাইসে চলার জন্য অনুমোদন পাবে।"</string>
-    <string name="setup_step1_finished_instruction" msgid="10761482004957994">"আপনার ভাষা ও ইনপুট সেটিংসে ইতোমধ্যে <xliff:g id="APPLICATION_NAME">%s</xliff:g> সক্ষম করা হয়েছে, তাই এই পদক্ষেপটি সমাপ্ত। পরবর্তীটিতে এগোন!"</string>
+    <string name="setup_step1_instruction" msgid="2578631936624637241">"দয়া করে আপনার ভাষা ও কিবোর্ড সেটিংস <xliff:g id="APPLICATION_NAME">%s</xliff:g> পরীক্ষা করুন। এর ফলে এটি আপনার ডিভাইসে চলার জন্য অনুমোদন পাবে।"</string>
+    <string name="setup_step1_finished_instruction" msgid="10761482004957994">"আপনার ভাষা ও কিবোর্ড সেটিংসে ইতোমধ্যে <xliff:g id="APPLICATION_NAME">%s</xliff:g> সক্ষম করা হয়েছে, তাই এই পদক্ষেপটি সমাপ্ত। পরবর্তীটিতে এগোন!"</string>
     <string name="setup_step1_action" msgid="4366513534999901728">"সেটিংসে সক্ষম করুন"</string>
     <string name="setup_step2_title" msgid="6860725447906690594">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> এ স্যুইচ করুন"</string>
     <string name="setup_step2_instruction" msgid="9141481964870023336">"এখন, সক্রিয় পাঠ্য-ইনপুট পদ্ধতি হিসেবে \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" নির্বাচন করুন।"</string>
diff --git a/java/res/values-ca/strings-emoji-descriptions.xml b/java/res/values-ca/strings-emoji-descriptions.xml
index 7e4beae..0a356f8 100644
--- a/java/res/values-ca/strings-emoji-descriptions.xml
+++ b/java/res/values-ca/strings-emoji-descriptions.xml
@@ -84,7 +84,7 @@
     <string name="spoken_emoji_267B" msgid="21716857176812762">"Símbol universal de reciclatge negre"</string>
     <string name="spoken_emoji_267F" msgid="8833496533226475443">"Símbol de cadira de rodes"</string>
     <string name="spoken_emoji_2693" msgid="7443148847598433088">"Àncora"</string>
-    <string name="spoken_emoji_26A0" msgid="6272635532992727510">"Senyal de perill"</string>
+    <string name="spoken_emoji_26A0" msgid="6272635532992727510">"Senyal d\'advertiment"</string>
     <string name="spoken_emoji_26A1" msgid="5604749644693339145">"Senyal d\'alt voltatge"</string>
     <string name="spoken_emoji_26AA" msgid="8005748091690377153">"Cercle blanc mitjà"</string>
     <string name="spoken_emoji_26AB" msgid="1655910278422753244">"Cercle negre mitjà"</string>
@@ -578,7 +578,7 @@
     <string name="spoken_emoji_1F4D8" msgid="7189799718984979521">"Llibre blau"</string>
     <string name="spoken_emoji_1F4D9" msgid="3874664073186440225">"Llibre taronja"</string>
     <string name="spoken_emoji_1F4DA" msgid="872212072924287762">"Llibres"</string>
-    <string name="spoken_emoji_1F4DB" msgid="2015183603583392969">"Insígnia de nom"</string>
+    <string name="spoken_emoji_1F4DB" msgid="2015183603583392969">"Etiqueta identificativa"</string>
     <string name="spoken_emoji_1F4DC" msgid="5075845110932456783">"Desplaça"</string>
     <string name="spoken_emoji_1F4DD" msgid="2494006707147586786">"Nota"</string>
     <string name="spoken_emoji_1F4DE" msgid="7883008605002117671">"Auricular del telèfon"</string>
@@ -591,7 +591,7 @@
     <string name="spoken_emoji_1F4E5" msgid="3232462702926143576">"Safata d\'entrada"</string>
     <string name="spoken_emoji_1F4E6" msgid="3399454337197561635">"Paquet"</string>
     <string name="spoken_emoji_1F4E7" msgid="5557136988503873238">"Símbol de correu electrònic"</string>
-    <string name="spoken_emoji_1F4E8" msgid="30698793974124123">"Sobre entrant"</string>
+    <string name="spoken_emoji_1F4E8" msgid="30698793974124123">"Correu entrant"</string>
     <string name="spoken_emoji_1F4E9" msgid="5947550337678643166">"Sobre amb una fletxa cap avall al damunt"</string>
     <string name="spoken_emoji_1F4EA" msgid="772614045207213751">"Bústia tancada amb la bandera baixada"</string>
     <string name="spoken_emoji_1F4EB" msgid="6491414165464146137">"Bústia tancada amb la bandera aixecada"</string>
@@ -616,8 +616,8 @@
     <string name="spoken_emoji_1F502" msgid="2361976580513178391">"Fletxes cap a la dreta i l\'esquerra que formen un cercle obert en sentit horari i un número u encerclat"</string>
     <string name="spoken_emoji_1F503" msgid="8936283551917858793">"Fletxes cap avall i cap amunt que formen un cercle obert en sentit horari"</string>
     <string name="spoken_emoji_1F504" msgid="708290317843535943">"Fletxes cap avall i cap amunt que formen un cercle obert en sentit antihorari"</string>
-    <string name="spoken_emoji_1F505" msgid="6348909939004951860">"Signe de brillantor baixa"</string>
-    <string name="spoken_emoji_1F506" msgid="4449609297521280173">"Signe de brillantor alta"</string>
+    <string name="spoken_emoji_1F505" msgid="6348909939004951860">"Símbol de brillantor baixa"</string>
+    <string name="spoken_emoji_1F506" msgid="4449609297521280173">"Símbol de brillantor alta"</string>
     <string name="spoken_emoji_1F507" msgid="7136386694923708448">"Altaveu amb barra de cancel·lació"</string>
     <string name="spoken_emoji_1F508" msgid="5063567689831527865">"Altaveu"</string>
     <string name="spoken_emoji_1F509" msgid="3948050077992370791">"Altaveu amb una ona de so"</string>
diff --git a/java/res/values-ca/strings-talkback-descriptions.xml b/java/res/values-ca/strings-talkback-descriptions.xml
index 9b01c75..a77db8b 100644
--- a/java/res/values-ca/strings-talkback-descriptions.xml
+++ b/java/res/values-ca/strings-talkback-descriptions.xml
@@ -57,7 +57,7 @@
     <string name="announce_keyboard_mode" msgid="6698257917367823205">"Es mostra el teclat per a <xliff:g id="KEYBOARD_MODE">%s</xliff:g>."</string>
     <string name="keyboard_mode_date" msgid="6597407244976713364">"data"</string>
     <string name="keyboard_mode_date_time" msgid="3642804408726668808">"data i hora"</string>
-    <string name="keyboard_mode_email" msgid="1239682082047693644">"correu electrònic"</string>
+    <string name="keyboard_mode_email" msgid="1239682082047693644">"adreça electrònica"</string>
     <string name="keyboard_mode_im" msgid="3812086215529493501">"missatgeria"</string>
     <string name="keyboard_mode_number" msgid="5395042245837996809">"número"</string>
     <string name="keyboard_mode_phone" msgid="2486230278064523665">"telèfon"</string>
diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml
index cc8c71d..eb44919 100644
--- a/java/res/values-ca/strings.xml
+++ b/java/res/values-ca/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibra en prémer tecles"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"So en prémer tecles"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Amplia en prémer tecles"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Preferències d\'entrada"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Aparença"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Opcions diversos idiomes"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Ajust escriptura gestual"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Preferències"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Aparença i dissenys"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Opcions de diversos idiomes"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Escriptura gestual"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Correcció de textos"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Avançat"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Altres mètodes d\'introducció"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"La tecla de canvi d\'idioma serveix també per a altres mètodes d\'entrada"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Tecla de canvi d\'idioma"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Tecla d\'entrada de veu"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"No hi ha cap mètode d\'introducció activat. Comprova la configuració d\'Idioma i introducció de text."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configura mètodes d\'entrada"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Idiomes"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Idiomes"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Ajuda i opinió"</string>
-    <string name="select_language" msgid="3693815588777926848">"Idiomes d\'introducció"</string>
+    <string name="select_language" msgid="5709487854987078367">"Idiomes"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Torna a tocar per desar"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Toca aquí per desar."</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Diccionari disponible"</string>
@@ -102,7 +103,7 @@
     <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
     <string name="keyboard_theme" msgid="4909551808526178852">"Tema del teclat"</string>
     <string name="custom_input_styles_title" msgid="8429952441821251512">"Estils d\'entrada personalitzats"</string>
-    <string name="add_style" msgid="6163126614514489951">"Afeg. estil"</string>
+    <string name="add_style" msgid="6163126614514489951">"Afegeix estil"</string>
     <string name="add" msgid="8299699805688017798">"Afegeix"</string>
     <string name="remove" msgid="4486081658752944606">"Elimina"</string>
     <string name="save" msgid="7646738597196767214">"Desa"</string>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
index 978c211..9a3d529 100644
--- a/java/res/values-cs/strings.xml
+++ b/java/res/values-cs/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Při stisku klávesy vibrovat"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Zvuk při stisku klávesy"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Detail znaku při stisku klávesy"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Předvolby pro zadávání"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Vzhled"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Možnosti pro více jazyků"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Předvolby pro psaní gesty"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Předvolby"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Vzhled a rozvržení"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Možnosti pro více jazyků"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Psaní gesty"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Oprava textu"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Rozšířená nastavení"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Motiv"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Přepínat metody zadávání"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Klávesa pro přepínání jazyka ovládá i další metody zadávání"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Klávesa přepínání jazyka"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Klávesa hlasového vstupu"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nejsou povoleny žádné metody hlasového vstupu. Zkontrolujte nastavení Jazyk a vstup."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurace metod zadávání"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Vstupní jazyky"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Jazyky"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Nápověda a zpětná vazba"</string>
-    <string name="select_language" msgid="3693815588777926848">"Vstupní jazyky"</string>
+    <string name="select_language" msgid="5709487854987078367">"Jazyky"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Opětovným dotykem provedete uložení"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Klepnutím sem položku uložíte"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Slovník k dispozici"</string>
diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml
index fc396e4..7a3d0fa 100644
--- a/java/res/values-da/strings.xml
+++ b/java/res/values-da/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibration ved tastetryk"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Lyd ved tastetryk"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Pop op ved tastetryk"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Indstillinger for input"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Udseende"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Indst. for flere sprog"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Indstillinger for Glidende indtastning"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Præferencer"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Udseende og layouts"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Indstillinger for flere sprog"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Glidende indtastning"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Tekstkorrigering"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Avanceret"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Skift inputmetode"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Tasten til sprogskift gælder også for andre inputmetoder"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Knap til sprogskift"</string>
@@ -65,18 +66,18 @@
     <string name="bigram_prediction" msgid="1084449187723948550">"Forslag til næste ord"</string>
     <string name="bigram_prediction_summary" msgid="3896362682751109677">"Brug det forrige ord til at give forslag"</string>
     <string name="gesture_input" msgid="826951152254563827">"Aktivér glidende indtastning"</string>
-    <string name="gesture_input_summary" msgid="9180350639305731231">"Skriv et ord ved at glide mellem bogstaverne"</string>
+    <string name="gesture_input_summary" msgid="9180350639305731231">"Skriv et ord ved at trække fingeren rundt mellem bogstaverne"</string>
     <string name="gesture_preview_trail" msgid="3802333369335722221">"Vis glidende trykspor"</string>
     <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dynamiske ordeksempler"</string>
     <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Se ordforslag ved glidende indtastning"</string>
-    <string name="gesture_space_aware" msgid="2078291600664682496">"Bevægelse for udtryk"</string>
+    <string name="gesture_space_aware" msgid="2078291600664682496">"Glidende mellemrum"</string>
     <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Tilføj mellemrum ved at glide til mellemrumstasten"</string>
     <string name="voice_input" msgid="3583258583521397548">"Knap til taleinput"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Der er ingen aktiverede stemmeinputmetoder. Kontrollér Indstillinger for sprog og input."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurer inputmetoder"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Inputsprog"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Sprog"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Hjælp og feedback"</string>
-    <string name="select_language" msgid="3693815588777926848">"Inputsprog"</string>
+    <string name="select_language" msgid="5709487854987078367">"Sprog"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Tryk igen for at gemme"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Klik her for at gemme"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Ordbog er tilgængelig"</string>
diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml
index f2873e6..8c575cb 100644
--- a/java/res/values-de/strings.xml
+++ b/java/res/values-de/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Bei Tastendruck vibrieren"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Ton bei Tastendruck"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up bei Tastendruck"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Eingabeeinstellungen"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Darstellung"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Mehrsprachige Optionen"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Bewegungseingabe-Einst."</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Einstellungen"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Darstellung &amp; Layouts"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Mehrsprachige Optionen"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Bewegungseingabe"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Textkorrektur"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Erweitert"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Design"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Eingabemethoden wechseln"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Sprachwechseltaste umfasst auch andere Eingabemethoden."</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Sprachwechsel"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Taste für Spracheingabe"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Keine Spracheingabemethoden aktiviert. Rufen Sie die Einstellungen für \"Sprache &amp; Eingabe\" auf."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Eingabemethoden konfigurieren"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Eingabesprachen"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Sprachen"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Hilfe &amp; Feedback"</string>
-    <string name="select_language" msgid="3693815588777926848">"Eingabesprachen"</string>
+    <string name="select_language" msgid="5709487854987078367">"Sprachen"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Zum Speichern erneut berühren"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Tippen Sie hier zum Speichern."</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Wörterbuch verfügbar"</string>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
index 2daeb81..8c417e1 100644
--- a/java/res/values-el/strings.xml
+++ b/java/res/values-el/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Δόνηση κατά το πάτημα πλήκτρων"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Ήχος κατά το πάτημα πλήκτρων"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Εμφάνιση με το πάτημα πλήκτρου"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Προτιμήσεις εισαγωγής"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Εμφάνιση"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Πολυγλωσσικές επιλογές"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Προτιμήσεις πληκτρολόγησης χειρονομιών"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Προτιμήσεις"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Εμφάνιση και διάταξη"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Επιλογές για πολλές γλώσσες"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Πληκτρολόγηση με κίνηση"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Διόρθωση κειμένου"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Σύνθετες"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Θέμα"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Άλλη μέθοδος εισόδου"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Το κλειδί αλλαγής γλώσσας καλύπτει και άλλες μεθόδους εισόδου"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Πλήκτρο εναλλαγής γλώσσας"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Κλειδί φωνητικής εξόδου"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Δεν έχουν ενεργοποιηθεί μέθοδοι φωνητικής εισαγωγής. Ελέγξτε τις Ρυθμίσεις Γλώσσας και εισαγωγής."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Διαμόρφωση μεθόδων εισαγωγής"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Γλώσσες εισόδου"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Γλώσσες"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Βοήθεια και σχόλια"</string>
-    <string name="select_language" msgid="3693815588777926848">"Γλώσσες εισόδου"</string>
+    <string name="select_language" msgid="5709487854987078367">"Γλώσσες"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Αγγίξτε ξανά για αποθήκευση"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Αγγίξτε εδώ για αποθήκευση"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Λεξικό διαθέσιμο"</string>
diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml
index 271b837..43926ca 100644
--- a/java/res/values-en-rGB/strings.xml
+++ b/java/res/values-en-rGB/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrate on keypress"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Sound on keypress"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up on key press"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Input preferences"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Appearance"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Multilingual options"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Gesture typing preferences"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Preferences"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Appearance &amp; layouts"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Multilingual options"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Gesture Typing"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Text correction"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Advanced"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Theme"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Switch to other input methods"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Language switch key also covers other input methods"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Language switch key"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Voice input key"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"No voice input methods enabled. Check Language &amp; input settings."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configure input methods"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Input languages"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Languages"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Help &amp; feedback"</string>
-    <string name="select_language" msgid="3693815588777926848">"Input languages"</string>
+    <string name="select_language" msgid="5709487854987078367">"Languages"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Touch again to save"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Touch here to save"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dictionary available"</string>
diff --git a/java/res/values-en-rIN/strings.xml b/java/res/values-en-rIN/strings.xml
index 271b837..43926ca 100644
--- a/java/res/values-en-rIN/strings.xml
+++ b/java/res/values-en-rIN/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrate on keypress"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Sound on keypress"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up on key press"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Input preferences"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Appearance"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Multilingual options"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Gesture typing preferences"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Preferences"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Appearance &amp; layouts"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Multilingual options"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Gesture Typing"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Text correction"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Advanced"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Theme"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Switch to other input methods"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Language switch key also covers other input methods"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Language switch key"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Voice input key"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"No voice input methods enabled. Check Language &amp; input settings."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configure input methods"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Input languages"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Languages"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Help &amp; feedback"</string>
-    <string name="select_language" msgid="3693815588777926848">"Input languages"</string>
+    <string name="select_language" msgid="5709487854987078367">"Languages"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Touch again to save"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Touch here to save"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dictionary available"</string>
diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml
index 31219a7..b6720b5 100644
--- a/java/res/values-es-rUS/strings.xml
+++ b/java/res/values-es-rUS/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar al pulsar teclas"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Sonar al pulsar las teclas"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Aviso emergente al pulsar tecla"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Preferencias de entrada"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Apariencia"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Opciones multilingües"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Pref. escritura gestual"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Preferencias"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Apariencia y diseños"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Opciones multilingües"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Escritura gestual"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Corrección ortográfica"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Avanzada"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Otros métodos de entrada"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"La tecla de cambio de idioma abarca otros métodos de entrada."</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Tecla de selección de idioma"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Tecla de entrada por voz"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"No hay métodos de entrada de voz habilitados. Comprueba la configuración de Teclado e idioma."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de entrada"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Idiomas"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Ayuda y comentarios"</string>
-    <string name="select_language" msgid="3693815588777926848">"Idiomas de entrada"</string>
+    <string name="select_language" msgid="5709487854987078367">"Idiomas"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Vuelve a tocar para guardar."</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Tocar aquí para guardar."</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Diccionario disponible"</string>
diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml
index 8c52164..b4baf59 100644
--- a/java/res/values-es/strings.xml
+++ b/java/res/values-es/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar al pulsar tecla"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Sonar al pulsar tecla"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Ampliar al pulsar tecla"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Preferencias de entrada"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Aspecto"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Opciones multilingües"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Opciones escritura gestual"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Preferencias"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Aspecto y diseño"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Opciones multilingües"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Escritura gestual"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Corrección ortográfica"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Opciones avanzadas"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Otros métodos de introducción"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"La tecla de cambio de idioma sirve también para otros métodos"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Tecla para cambiar de idioma"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Tecla de entrada de voz"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Sin métodos de introducción de voz habilitados. Comprueba ajustes de Idioma e introducción de texto."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de entrada"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Idiomas"</string>
-    <string name="help_and_feedback" msgid="5328219371839879161">"Ayuda y opiniones"</string>
-    <string name="select_language" msgid="3693815588777926848">"Idiomas de introducción"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Idiomas"</string>
+    <string name="help_and_feedback" msgid="5328219371839879161">"Ayuda y sugerencias"</string>
+    <string name="select_language" msgid="5709487854987078367">"Idiomas"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Toca otra vez para guardar"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Toca aquí para guardar"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Hay un diccionario disponible"</string>
@@ -112,7 +113,7 @@
     <string name="enable" msgid="5031294444630523247">"Habilitar"</string>
     <string name="not_now" msgid="6172462888202790482">"Ahora no"</string>
     <string name="custom_input_style_already_exists" msgid="8008728952215449707">"Ya existe el estilo de entrada <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>."</string>
-    <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Duración vibración al pulsar"</string>
+    <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Duración de vibración al pulsar"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Volumen sonido al pulsar tecla"</string>
     <string name="button_default" msgid="3988017840431881491">"Predeterminado"</string>
     <string name="setup_welcome_title" msgid="6112821709832031715">"Te damos la bienvenida a <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
@@ -175,7 +176,7 @@
     <string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"Acceso directo:"</string>
     <string name="user_dict_settings_add_locale_option_name" msgid="4738643440987277705">"Idioma:"</string>
     <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"Escribe una palabra"</string>
-    <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"Acceso directo opcional"</string>
+    <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"Introducir"</string>
     <string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"Editar palabra"</string>
     <string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"Editar"</string>
     <string name="user_dict_settings_context_menu_delete_title" msgid="8142932447689461181">"Eliminar"</string>
diff --git a/java/res/values-et-rEE/strings.xml b/java/res/values-et-rEE/strings.xml
index 869fdd9..584cf50 100644
--- a/java/res/values-et-rEE/strings.xml
+++ b/java/res/values-et-rEE/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibreeri klahvivajutusel"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Heli klahvivajutusel"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Klahvivajutusel kuva hüpik"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Sisestuseelistused"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Ilme"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Mitme keele valikud"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Viipesisestuseelistused"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Eelistused"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Välimus ja paigutused"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Mitmekeelsed valikud"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Joonistusega sisestamine"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Tekstiparandus"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Täpsem"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Teema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Vaheta sisestusmeetodit"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Keelevahetuse võti hõlmab ka muid sisestusmeetodeid"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Keelevahetuse nupp"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Häälesisendi klahv"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ühtegi häälsisendmeetodit pole lubatud. Kontrollige keele- ja sisendiseadeid."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Sisestusmeetodite seadistamine"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Sisestuskeeled"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Keeled"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Abi ja tagasiside"</string>
-    <string name="select_language" msgid="3693815588777926848">"Sisestuskeeled"</string>
+    <string name="select_language" msgid="5709487854987078367">"Keeled"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Salvestamiseks puudutage uuesti"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Salvestamiseks puudutage siin"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Sõnastik saadaval"</string>
diff --git a/java/res/values-eu-rES/strings.xml b/java/res/values-eu-rES/strings.xml
index 0be6ddf..59381da 100644
--- a/java/res/values-eu-rES/strings.xml
+++ b/java/res/values-eu-rES/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Egin dar-dar sakatzean"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Egin soinua tekla sakatzean"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Handitu teklak, sakatzean"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Idazketa-hobespenak"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Itxura"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Aukera eleanitzak"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Keinu-idazketaren hobespenak"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Hobespenak"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Itxura eta diseinuak"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Aukera eleanitzak"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Keinu bidezko idazketa"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Testu-zuzenketa"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Ezarpen aurreratuak"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Gaia"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Aldatu idazketa-metodoa"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Hizkuntza aldatzeko teklak beste idazketa-metodoetarako ere balio du"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Hizkuntza aldatzeko tekla"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Ahots bidezko idazketaren tekla"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ez da ahots bidezko idazketa-metodorik gaitu. Egiaztatu Hizkuntza eta idazketa ataleko ezarpenak."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfiguratu idazketa-metodoak"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Idazketa-hizkuntzak"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Hizkuntzak"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Laguntza eta iritziak"</string>
-    <string name="select_language" msgid="3693815588777926848">"Idazketa-hizkuntzak"</string>
+    <string name="select_language" msgid="5709487854987078367">"Hizkuntzak"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Gordetzeko, ukitu berriro"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Gordetzeko, ukitu hau"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Hiztegia erabilgarri"</string>
diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml
index ac2c8f6..7b78afb 100644
--- a/java/res/values-fa/strings.xml
+++ b/java/res/values-fa/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"لرزش با فشار کلید"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"صدا با فشار کلید"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"بازشدن با فشار کلید"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"اولویت‌های ورودی"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"ظاهر"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"انتخاب‌های چندزبانه"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"موارد ترجیحی تایپ با اشاره"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"تنظیمات ترجیحی"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"ظاهر و طرح‌بندی‌ها"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"گزینه‌های چندزبانی"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"ورودی اشاره‌ای"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"اصلاح نوشتار"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"پیشرفته"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"طرح‌زمینه"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"تغییر به دیگر روش‌های ورودی"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"کلید تغییر زبان، سایر ورودی‌های زبان را نیز پوشش می‌دهد"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"کلید تغییر زبان"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"کلید ورودی صدا"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"هیچ روش ورودی صوتی فعال نشده است. تنظیمات زبان و ورودی را بررسی کنید."</string>
     <string name="configure_input_method" msgid="373356270290742459">"پیکربندی روش‌های ورودی"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"زبان‌های ورودی"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"زبان‌ها"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"راهنما و بازخورد"</string>
-    <string name="select_language" msgid="3693815588777926848">"زبان‌های ورودی"</string>
+    <string name="select_language" msgid="5709487854987078367">"زبان‌ها"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"برای ذخیره دوباره لمس کنید"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"برای ذخیره اینجا را لمس کنید"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"دیکشنری موجود است"</string>
diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml
index a94f573..6d0e3e8 100644
--- a/java/res/values-fi/strings.xml
+++ b/java/res/values-fi/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Käytä värinää näppäimiä painettaessa"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Toista ääni näppäimiä painettaessa"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Ponnahdusikkuna painalluksella"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Syöttöasetukset"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Ulkonäkö"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Kieliasetukset"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Piirtokirjoitusasetukset"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Asetukset"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Ulkoasu ja asettelut"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Monikielisyysasetukset"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Piirtokirjoitus"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Tekstin korjaus"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Lisäasetukset"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Teema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Käytä toista syöttötapaa"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Kielenvaihtonäppäin kattaa myös muut syöttötavat"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Kielenvaihtonäppäin"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Äänisyöteavain"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Äänen syöttötapoja ei ole otettu käyttöön. Tarkista Kieli ja syöttötapa -asetukset."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Määritä syöttötavat"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Syöttökielet"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Kielet"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Ohje ja palaute"</string>
-    <string name="select_language" msgid="3693815588777926848">"Syöttökielet"</string>
+    <string name="select_language" msgid="5709487854987078367">"Kielet"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Tallenna koskettamalla uudelleen"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Tallenna koskettamalla tätä"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Sanakirja saatavilla"</string>
diff --git a/java/res/values-fr-rCA/strings.xml b/java/res/values-fr-rCA/strings.xml
index 8b6afcb..a854598 100644
--- a/java/res/values-fr-rCA/strings.xml
+++ b/java/res/values-fr-rCA/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrer à chaque touche"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Son à chaque touche"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Agrandir les caractères"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Préférences d\'entrée"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Apparence"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Options multilingues"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Préfér. entrée gestuelle"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Préférences"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Apparence et dispositions"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Options multilingues"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Entrée gestuelle"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Correction du texte"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Avancés"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Thème"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Autres modes de saisie"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"La touche de sélection de langue couvre d\'autres modes de saisie"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Touche de sélection de langue"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Touche de saisie vocale"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Aucun mode d\'entrée vocale n\'a été activé. Vérifiez les paramètres de langues et d\'entrée de texte."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configurer les modes de saisie"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Langues de saisie"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Langues"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Aide et commentaires"</string>
-    <string name="select_language" msgid="3693815588777926848">"Langues de saisie"</string>
+    <string name="select_language" msgid="5709487854987078367">"Langues"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Appuyer de nouveau pour enregistrer"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Touchez ici pour enregistrer le mot dans le dictionnaire"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dictionnaire disponible"</string>
diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml
index 79dc431..dd5e998 100644
--- a/java/res/values-fr/strings.xml
+++ b/java/res/values-fr/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrer à chaque touche"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Son à chaque touche"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Agrandir les caractères"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Préférences de saisie"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Apparence"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Options multilingues"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Préf. saisie gestuelle"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Préférences"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Apparence et dispositions"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Options multilingues"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Saisie gestuelle"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Correction du texte"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Paramètres avancés"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Thème"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Autres modes de saisie"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"La touche de sélection de langue couvre d\'autres modes de saisie."</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Touche de sélection de langue"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Touche de saisie vocale"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Aucun mode de saisie vocale activé. Vérifiez les paramètres de langue et de saisie."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configurer les modes de saisie"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Langues de saisie"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Langues"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Aide et commentaires"</string>
-    <string name="select_language" msgid="3693815588777926848">"Langues de saisie"</string>
+    <string name="select_language" msgid="5709487854987078367">"Langues"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Appuyer de nouveau pour enregistrer"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Appuyez ici pour enregistrer."</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dictionnaire disponible"</string>
diff --git a/java/res/values-gl-rES/strings-emoji-descriptions.xml b/java/res/values-gl-rES/strings-emoji-descriptions.xml
index ec17978..cdb67fa 100644
--- a/java/res/values-gl-rES/strings-emoji-descriptions.xml
+++ b/java/res/values-gl-rES/strings-emoji-descriptions.xml
@@ -804,7 +804,7 @@
     <string name="spoken_emoji_1F697" msgid="7978399334396733790">"Automóbil"</string>
     <string name="spoken_emoji_1F698" msgid="7006050861129732018">"Automóbil próximo"</string>
     <string name="spoken_emoji_1F699" msgid="630317052666590607">"Caravana"</string>
-    <string name="spoken_emoji_1F69A" msgid="4739797891735823577">"Camión de reparto"</string>
+    <string name="spoken_emoji_1F69A" msgid="4739797891735823577">"Camión de entrega"</string>
     <string name="spoken_emoji_1F69B" msgid="4715997280786620649">"Camión articulado"</string>
     <string name="spoken_emoji_1F69C" msgid="5557395610750818161">"Tractor"</string>
     <string name="spoken_emoji_1F69D" msgid="5467164189942951047">"Monorraíl"</string>
diff --git a/java/res/values-gl-rES/strings.xml b/java/res/values-gl-rES/strings.xml
index 7f087e9..5b1e66c 100644
--- a/java/res/values-gl-rES/strings.xml
+++ b/java/res/values-gl-rES/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar ao tocar as teclas"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Son ao premer as teclas"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Ventás emerxentes ao premer as teclas"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Preferencias de entrada"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Aparencia"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Opcións multilingües"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Preferencias de escritura de xestos"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Preferencias"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Aparencia e deseños"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Opcións multilingües"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Escritura mediante xestos"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Corrección de texto"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Avanzada"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Outros métodos de entrada"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"A tecla de cambio de idioma inclúe outros métodos de entrada"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Tecla de cambio de idioma"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Tecla de entrada de voz"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Non hai ningún método de entrada de voz activado. Comproba a configuración de Idioma e entrada de texto."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de entrada"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string>
-    <string name="help_and_feedback" msgid="5328219371839879161">"Axuda e opinións"</string>
-    <string name="select_language" msgid="3693815588777926848">"Idiomas de entrada"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Idiomas"</string>
+    <string name="help_and_feedback" msgid="5328219371839879161">"Axuda e suxerencias"</string>
+    <string name="select_language" msgid="5709487854987078367">"Idiomas"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Toca de novo para gardar"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Toca aquí para gardar"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dicionario dispoñible"</string>
diff --git a/java/res/values-hi/strings-action-keys.xml b/java/res/values-hi/strings-action-keys.xml
index 7237c24..8768ee7 100644
--- a/java/res/values-hi/strings-action-keys.xml
+++ b/java/res/values-hi/strings-action-keys.xml
@@ -21,7 +21,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="label_go_key" msgid="4033615332628671065">"जाएं"</string>
-    <string name="label_next_key" msgid="5586407279258592635">"अगला"</string>
+    <string name="label_next_key" msgid="5586407279258592635">"आगे"</string>
     <string name="label_previous_key" msgid="1421141755779895275">"पिछला"</string>
     <string name="label_done_key" msgid="7564866296502630852">"पूर्ण"</string>
     <string name="label_send_key" msgid="482252074224462163">"भेजें"</string>
diff --git a/java/res/values-hi/strings-talkback-descriptions.xml b/java/res/values-hi/strings-talkback-descriptions.xml
index aba2592..6a55f29 100644
--- a/java/res/values-hi/strings-talkback-descriptions.xml
+++ b/java/res/values-hi/strings-talkback-descriptions.xml
@@ -21,8 +21,8 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="spoken_use_headphones" msgid="4313642710742229868">"जोर से बोली जाने वाली पासवर्ड कुंजियां सुनने के लिए हैडसेट प्‍लग करें."</string>
-    <string name="spoken_current_text_is" msgid="4240549866156675799">"वर्तमान पाठ %s है"</string>
-    <string name="spoken_no_text_entered" msgid="1711276837961785646">"कोई पाठ नहीं डाला गया"</string>
+    <string name="spoken_current_text_is" msgid="4240549866156675799">"वर्तमान लेख %s है"</string>
+    <string name="spoken_no_text_entered" msgid="1711276837961785646">"कोई लेख नहीं डाला गया"</string>
     <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> को सुधार कर <xliff:g id="CORRECTED_WORD">%3$s</xliff:g> करता है"</string>
     <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> स्वत: सुधार करता है"</string>
     <string name="spoken_description_unknown" msgid="5139930082759824442">"अज्ञात वर्ण"</string>
@@ -44,7 +44,7 @@
     <string name="spoken_description_search" msgid="5099937658231911288">"खोजें"</string>
     <string name="spoken_description_dot" msgid="5644176501632325560">"डॉट"</string>
     <string name="spoken_description_language_switch" msgid="6818666779313544553">"भाषा स्विच करें"</string>
-    <string name="spoken_description_action_next" msgid="431761808119616962">"अगला"</string>
+    <string name="spoken_description_action_next" msgid="431761808119616962">"आगे"</string>
     <string name="spoken_description_action_previous" msgid="2919072174697865110">"पिछला"</string>
     <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"शिफ़्ट सक्षम किया गया"</string>
     <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"कैप्स लॉक सक्षम किया गया"</string>
@@ -61,7 +61,7 @@
     <string name="keyboard_mode_im" msgid="3812086215529493501">"संदेश सेवा"</string>
     <string name="keyboard_mode_number" msgid="5395042245837996809">"संख्या"</string>
     <string name="keyboard_mode_phone" msgid="2486230278064523665">"फ़ोन"</string>
-    <string name="keyboard_mode_text" msgid="9138789594969187494">"पाठ"</string>
+    <string name="keyboard_mode_text" msgid="9138789594969187494">"लेख"</string>
     <string name="keyboard_mode_time" msgid="8558297845514402675">"समय"</string>
     <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string>
     <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"हाल ही के"</string>
diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml
index 35b09d6..c05d2a8 100644
--- a/java/res/values-hi/strings.xml
+++ b/java/res/values-hi/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"कुंजी दबाने पर कंपन करता है"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"कुंजी दबाने पर आवाज"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"कुंजी दबाने पर पॉपअप दिखाएं"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"इनपुट प्राथमिकताएं"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"प्रकटन"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"बहुभाषी विकल्प"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"हावभाव लेखन वरीयताएं"</string>
-    <string name="settings_screen_correction" msgid="1616818407747682955">"पाठ सुधार"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"प्राथमिकताएं"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"प्रकटन और लेआउट"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"बहुभाषीय  विकल्प"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"हावभाव लेखन"</string>
+    <string name="settings_screen_correction" msgid="1616818407747682955">"लेख सुधार"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"अतिरिक्त सेटिंग"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"थीम"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"अन्‍य इनपुट पद्धतियों पर जाएं"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"भाषा स्‍विच कुंजी में अन्‍य इनपुट पद्धतियां भी शामिल हैं"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"भाषा स्विच कुंजी"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"ध्‍वनि‍ इनपुट कुंजी"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"कोई ध्वनि इनपुट पद्धति सक्षम नहीं है. भाषा और इनपुट सेटिंग जांचें."</string>
     <string name="configure_input_method" msgid="373356270290742459">"इनपुट पद्धति कॉन्‍फ़िगर करें"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"इनपुट भाषा"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"भाषाएं"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"सहायता और फ़ीडबैक"</string>
-    <string name="select_language" msgid="3693815588777926848">"इनपुट भाषाएं"</string>
+    <string name="select_language" msgid="5709487854987078367">"भाषाएं"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"सहेजने के लिए पुन: स्‍पर्श करें"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"सहेजने के लिए यहां स्पर्श करें"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"शब्‍दकोश उपलब्‍ध है"</string>
@@ -121,11 +122,11 @@
     <string name="setup_next_action" msgid="371821437915144603">"अगला चरण"</string>
     <string name="setup_steps_title" msgid="6400373034871816182">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> सेट करना"</string>
     <string name="setup_step1_title" msgid="3147967630253462315">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> को सक्षम करें"</string>
-    <string name="setup_step1_instruction" msgid="2578631936624637241">"कृपया अपनी भाषा और अक्षर सेटिंग में \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" को चेक करें. इससे वह आपके उपकरण पर चलने के लिए अधिकृत हो जाएगा."</string>
+    <string name="setup_step1_instruction" msgid="2578631936624637241">"कृपया अपनी भाषा और अक्षर सेटिंग में \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" को चेक करें. इससे वह आपके डिवाइस पर चलने के लिए अधिकृत हो जाएगा."</string>
     <string name="setup_step1_finished_instruction" msgid="10761482004957994">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> आपकी भाषा और अक्षर सेटिंग में पहले से सक्षम है, इसलिए यह चरण पूर्ण हो गया है. अगले चरण पर जाएं!"</string>
     <string name="setup_step1_action" msgid="4366513534999901728">"सेटिंग में सक्षम करें"</string>
     <string name="setup_step2_title" msgid="6860725447906690594">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> पर स्विच करें"</string>
-    <string name="setup_step2_instruction" msgid="9141481964870023336">"इसके बाद, \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" को अपनी सक्रिय पाठ-इनपुट पद्धति के रूप में चुनें."</string>
+    <string name="setup_step2_instruction" msgid="9141481964870023336">"इसके बाद, \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" को अपनी सक्रिय लेख-इनपुट पद्धति के रूप में चुनें."</string>
     <string name="setup_step2_action" msgid="1660330307159824337">"इनपुट पद्धतियां स्विच करें"</string>
     <string name="setup_step3_title" msgid="3154757183631490281">"बधाई हो, आप बिल्कुल तैयार हैं!"</string>
     <string name="setup_step3_instruction" msgid="8025981829605426000">"अब आप <xliff:g id="APPLICATION_NAME">%s</xliff:g> के साथ अपने सभी पसंदीदा ऐप्स  में लिख सकते हैं."</string>
@@ -153,18 +154,18 @@
     <string name="message_updating" msgid="4457761393932375219">"नई जानकारी देखा जा रहा हैं"</string>
     <string name="message_loading" msgid="5638680861387748936">"लोड हो रहा है…"</string>
     <string name="main_dict_description" msgid="3072821352793492143">"मुख्‍य डिक्‍शनरी"</string>
-    <string name="cancel" msgid="6830980399865683324">"रद्द करें"</string>
+    <string name="cancel" msgid="6830980399865683324">"रहने दें"</string>
     <string name="go_to_settings" msgid="3876892339342569259">"सेटिंग"</string>
     <string name="install_dict" msgid="180852772562189365">"इंस्टॉल करें"</string>
-    <string name="cancel_download_dict" msgid="7843340278507019303">"रद्द करें"</string>
+    <string name="cancel_download_dict" msgid="7843340278507019303">"रहने दें"</string>
     <string name="delete_dict" msgid="756853268088330054">"हटाएं"</string>
-    <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"आपके मोबाइल पर चयनित भाषा के लिए शब्‍दकोश उपलब्‍ध है.&lt;br/&gt; हम आपके लेखन अनुभव को बेहतर बनाने के लिए <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> शब्‍दकोश &lt;b&gt;डाउनलोड करने&lt;/b&gt; की सुझाव देते हैं.&lt;br/&gt; &lt;br/&gt; 3G में डाउनलोड करने पर एक या दो मिनट लगेंगे. यदि आपके पास &lt;b&gt;असीमित डेटा योजना&lt;/b&gt; नहीं है, तो शुल्क लागू हो सकते हैं.&lt;br/&gt; यदि आप अपनी डेटा योजना के बारे में सुनिश्चित नहीं हैं, तो हम अपने आप डाउनलोड प्रारंभ करने के लिए वाई-फ़ाई  कनेक्‍शन ढूंढने की सुझाव देते हैं.&lt;br/&gt; &lt;br/&gt; युक्ति: आप अपने मोबाइल उपकरण के &lt;b&gt;सेटिंग&lt;/b&gt; मेनू में &lt;b&gt;भाषा और इनपुट&lt;/b&gt; पर जाकर शब्‍दकोशों को डाउनलोड कर सकते हैं और निकाल सकते हैं."</string>
+    <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"आपके मोबाइल पर चयनित भाषा के लिए शब्‍दकोश उपलब्‍ध है.&lt;br/&gt; हम आपके लेखन अनुभव को बेहतर बनाने के लिए <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> शब्‍दकोश &lt;b&gt;डाउनलोड करने&lt;/b&gt; की सुझाव देते हैं.&lt;br/&gt; &lt;br/&gt; 3G में डाउनलोड करने पर एक या दो मिनट लगेंगे. यदि आपके पास &lt;b&gt;असीमित डेटा योजना&lt;/b&gt; नहीं है, तो शुल्क लागू हो सकते हैं.&lt;br/&gt; यदि आप अपनी डेटा योजना के बारे में सुनिश्चित नहीं हैं, तो हम अपने आप डाउनलोड प्रारंभ करने के लिए वाई-फ़ाई  कनेक्‍शन ढूंढने की सुझाव देते हैं.&lt;br/&gt; &lt;br/&gt; युक्ति: आप अपने मोबाइल डिवाइस के &lt;b&gt;सेटिंग&lt;/b&gt; मेनू में &lt;b&gt;भाषा और इनपुट&lt;/b&gt; पर जाकर शब्‍दकोशों को डाउनलोड कर सकते हैं और निकाल सकते हैं."</string>
     <string name="download_over_metered" msgid="1643065851159409546">"अभी डाउनलोड करें (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string>
     <string name="do_not_download_over_metered" msgid="2176209579313941583">"वाई-फ़ाई  से डाउनलोड करें"</string>
     <string name="dict_available_notification_title" msgid="4583842811218581658">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> के लिए एक शब्‍दकोश उपलब्‍ध है"</string>
     <string name="dict_available_notification_description" msgid="1075194169443163487">"समीक्षा करने और डाउनलोड करने के लिए दबाएं"</string>
     <string name="toast_downloading_suggestions" msgid="6128155879830851739">"डाउनलोड प्रारंभ हो रहा है: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> के लिए सुझाव जल्दी ही उपलब्ध होंगे."</string>
-    <string name="version_text" msgid="2715354215568469385">"संस्करण <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string>
+    <string name="version_text" msgid="2715354215568469385">"वर्शन <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string>
     <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"जोड़ें"</string>
     <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"शब्दकोश में जोड़ें"</string>
     <string name="user_dict_settings_add_screen_title" msgid="5818914331629278758">"वाक्यांश"</string>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
index 6ffc799..c145b20 100644
--- a/java/res/values-hr/strings.xml
+++ b/java/res/values-hr/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibracija pri pritisku na tipku"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Zvuk pri pritisku tipke"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Povećanja na pritisak tipke"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Postavke unosa"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Izgled"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Višejezične opcije"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Postavke pisanja kretnjama"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Postavke"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Prikaz i izgled"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Višejezične opcije"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Pisanje kretnjama"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Ispravljanje teksta"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Napredno"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Prebaci na druge unose"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Tipka za prebacivanje jezika pokriva i druge načine unosa"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Tipka za izmjenjivanje jezika"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Tipka za glasovni unos"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nije omogućen nijedan način glasovnog unosa. Provjerite postavke jezika i unosa."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfiguriraj načine ulaza"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Jezici unosa"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Jezici"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Pomoć i povratne informacije"</string>
-    <string name="select_language" msgid="3693815588777926848">"Jezici unosa"</string>
+    <string name="select_language" msgid="5709487854987078367">"Jezici"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Dodirnite ponovo za spremanje"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Dodirnite ovdje za spremanje"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Rječnik je dostupan"</string>
diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml
index f77fa12..a373e75 100644
--- a/java/res/values-hu/strings.xml
+++ b/java/res/values-hu/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Rezgés gombnyomásra"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Hangjelzés gombnyomásra"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Nagyobb billentyű gombnyomásra"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Beviteli preferenciák"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Megjelenés"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Többnyelvű beállítások"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Kézmozdulatokkal gépelés"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Beállítások"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Megjelenés és elrendezés"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Többnyelvű beállítások"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Kézmozdulatokkal történő gépelés"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Szövegjavítás"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Speciális"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Téma"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Váltás más beviteli módra"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"A nyelvkapcsoló gomb egyéb beviteli módokat is tartalmaz"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"A nyelvkapcsoló"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Hangbeviteli gomb"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nincs engedélyezett hangbeviteli módszer. Nézze meg a Nyelvi és beviteli beállításokat."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Beviteli módok beállítása"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Beviteli nyelvek"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Nyelvek"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Súgó és visszajelzés"</string>
-    <string name="select_language" msgid="3693815588777926848">"Beviteli nyelvek"</string>
+    <string name="select_language" msgid="5709487854987078367">"Nyelvek"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Érintse meg újból a mentéshez"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"A mentéshez érintse meg itt"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Van elérhető szótár"</string>
diff --git a/java/res/values-hy-rAM/strings.xml b/java/res/values-hy-rAM/strings.xml
index 68f39f5..52bc86b 100644
--- a/java/res/values-hy-rAM/strings.xml
+++ b/java/res/values-hy-rAM/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Թրթռալ սեղմման ժամանակ"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Ձայնը սեղմման ժամանակ"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Ելնող պատուհան՝ ստեղնի հպման դեպքում"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Ներածման նախընտրանքներ"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Արտաքին տեսք"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Լեզվի ընտրանքներ"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Ժեստերով ներածում"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Նախընտրանքներ"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Արտաքին տեսք և դասավորություն"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Բազմալեզու ընտրանքներ"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Ժեստերով մուտքագրում"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Տեքստի ուղղում"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Հավելյալ"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Թեմա"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Անցնել մուտքագրման այլ եղանակների"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Լեզվի փոխարկման բանալին ընդգրկում է այլ մուտքագրման եղանակներ ևս"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Լեզվի փոխարկման ստեղն"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Ձայնային մուտքագրման ստեղն"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ձայնային ներածման որևէ եղանակ միացված չէ։ Ստուգեք Լեզվի և ներածման կարգավորումները։"</string>
     <string name="configure_input_method" msgid="373356270290742459">"Կարգավորել մուտքագրման մեթոդները"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Մուտքագրման լեզուներ"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Լեզուներ"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Օգնություն և հետադարձ կապ"</string>
-    <string name="select_language" msgid="3693815588777926848">"Մուտքագրման լեզուներ"</string>
+    <string name="select_language" msgid="5709487854987078367">"Լեզուներ"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Պահպանելու համար կրկին հպեք"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Պահելու համար հպեք այստեղ"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Բառարանն առկա է"</string>
diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml
index b19b971..89b6645 100644
--- a/java/res/values-in/strings.xml
+++ b/java/res/values-in/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Getar jika tombol ditekan"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Berbunyi jika tombol ditekan"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Muncul saat tombol ditekan"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Preferensi masukan"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Tampilan"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Opsi multi bahasa"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Preferensi ketikan isyarat"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Preferensi"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Tampilan &amp; tata letak"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Opsi multibahasa"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Ketikan Isyarat"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Koreksi teks"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Lanjutan"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Beralih ke metode masukan lain"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Tombol beralih bahasa juga mencakup metode masukan lain"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Tombol pengalih bahasa"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Tombol masukan suara"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Tidak ada metode masukan suara yang diaktifkan. Periksa setelan Bahasan &amp; masukan."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurasikan metode masukan"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Bahasa masukan"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Bahasa"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Bantuan &amp; masukan"</string>
-    <string name="select_language" msgid="3693815588777926848">"Bahasa masukan"</string>
+    <string name="select_language" msgid="5709487854987078367">"Bahasa"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Sentuh lagi untuk menyimpan"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Sentuh di sini untuk menyimpan"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Kamus yang tersedia"</string>
diff --git a/java/res/values-is-rIS/strings.xml b/java/res/values-is-rIS/strings.xml
index 6cb9f8a..5f38e9f 100644
--- a/java/res/values-is-rIS/strings.xml
+++ b/java/res/values-is-rIS/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Titringur þegar ýtt er á lykla"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Hljóð þegar ýtt er á lykil"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Stækkaðir stafir við innslátt"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Inntaksvalkostir"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Útlit"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Tungumálavalkostir"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Still. bendingainnsláttar"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Kjörstillingar"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Útlit og skipulag"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Fjölmálavalkostir"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Bendingainnsláttur"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Textaleiðrétting"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Ítarlegt"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Þema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Skipta um innsláttaraðferð"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Lykill til að skipta um mál inniheldur aðrar innsláttaraðferðir"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Lykill til að breyta tungumáli"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Raddinntakslykill"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Engar innsláttaraðferðir fyrir rödd virkar. Kannaðu stillingar tungumáls og innsláttar."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Stilla innsláttaraðferðir"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Innsláttartungumál"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Tungumál"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Hjálp og ábendingar"</string>
-    <string name="select_language" msgid="3693815588777926848">"Innsláttartungumál"</string>
+    <string name="select_language" msgid="5709487854987078367">"Tungumál"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Snertu aftur til að vista"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Snertu hér til að vista"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Orðabók í boði"</string>
diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml
index d01724f..d6e742e 100644
--- a/java/res/values-it/strings.xml
+++ b/java/res/values-it/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrazione tasti"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Suono tasti"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Popup sui tasti"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Preferenze di immissione"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Aspetto"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Opzioni multilingue"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Pref digitazione testuale"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Preferenze"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Aspetto e layout"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Opzioni multilingue"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Digitazione gestuale"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Correzione testo"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Avanzate"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Altri metodi immissione"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Il tasto per cambiare lingua offre altri metodi di immissione"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Tasto cambio lingua"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Tasto input vocale"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nessun metodo di immissione vocale abilitato. Controlla le impostazioni Lingua e input."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configura metodi di immissione"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Lingue comandi"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Lingue"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Guida e feedback"</string>
-    <string name="select_language" msgid="3693815588777926848">"Lingue comandi"</string>
+    <string name="select_language" msgid="5709487854987078367">"Lingue"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Tocca di nuovo per salvare"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Tocca qui per salvare"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dizionario disponibile"</string>
diff --git a/java/res/values-iw/strings-emoji-descriptions.xml b/java/res/values-iw/strings-emoji-descriptions.xml
index 975ca10..d8ef20f 100644
--- a/java/res/values-iw/strings-emoji-descriptions.xml
+++ b/java/res/values-iw/strings-emoji-descriptions.xml
@@ -556,8 +556,8 @@
     <string name="spoken_emoji_1F4C2" msgid="8095638715523765338">"תיקיית קבצים פתוחה"</string>
     <string name="spoken_emoji_1F4C3" msgid="3727274466173970142">"דף עם גלילה מלמטה"</string>
     <string name="spoken_emoji_1F4C4" msgid="4382570710795501612">"דף פונה כלפי מעלה"</string>
-    <string name="spoken_emoji_1F4C5" msgid="8693944622627762487">"לוח שנה"</string>
-    <string name="spoken_emoji_1F4C6" msgid="8469908708708424640">"לוח שנה נתלש"</string>
+    <string name="spoken_emoji_1F4C5" msgid="8693944622627762487">"יומן"</string>
+    <string name="spoken_emoji_1F4C6" msgid="8469908708708424640">"יומן נתלש"</string>
     <string name="spoken_emoji_1F4C7" msgid="2665313547987324495">"כרטסת"</string>
     <string name="spoken_emoji_1F4C8" msgid="8007686702282833600">"תרשים עם מגמת עלייה"</string>
     <string name="spoken_emoji_1F4C9" msgid="2271951411192893684">"תרשים עם מגמת ירידה"</string>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
index d6c398e..3da9464 100644
--- a/java/res/values-iw/strings.xml
+++ b/java/res/values-iw/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"רטט בלחיצה על מקשים"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"צלילים בעת לחיצה על מקשים"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"חלון קופץ בלחיצה על מקש"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"העדפות קלט"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"מראה"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"אפשרויות ריבוי שפות"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"העדפות של הקלדת החלקה"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"העדפות"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"מראה ופריסות"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"אפשרויות לריבוי שפות"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"הקלדת החלקה"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"תיקון טקסט"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"מתקדם"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"עיצוב"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"עבור לשיטות קלט אחרות"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"מתג החלפת השפה מכסה גם שיטות קלט אחרות"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"מתג החלפת שפה"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"מקש קלט קולי"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"לא הופעלו שיטות של קלט קולי. בדוק את הגדרות השפה והקלט."</string>
     <string name="configure_input_method" msgid="373356270290742459">"הגדרת שיטות קלט"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"שפות קלט"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"שפות"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"עזרה ומשוב"</string>
-    <string name="select_language" msgid="3693815588777926848">"שפות קלט"</string>
+    <string name="select_language" msgid="5709487854987078367">"שפות"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"גע שוב כדי לשמור"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"גע כאן כדי לשמור"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"מילון זמין"</string>
diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml
index ccb2bca..f8cb10a 100644
--- a/java/res/values-ja/strings.xml
+++ b/java/res/values-ja/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"キー操作バイブ"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"キー操作音"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"キー押下時ポップアップ"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"入力設定"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"デザイン"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"複数言語オプション"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"ジェスチャー入力の設定"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"設定"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"外観とレイアウト"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"多言語オプション"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"ジェスチャー入力"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"テキストの修正"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"詳細設定"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"テーマ"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"他の入力方法に切り替え"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"言語切り替えキーは他の入力方法にも対応しています"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"言語切り替えキー"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"音声入力キー"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"有効になっている音声入力方法がありません。[言語と入力]設定をご確認ください。"</string>
     <string name="configure_input_method" msgid="373356270290742459">"入力方法を設定"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"入力言語"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"言語"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"ヘルプとフィードバック"</string>
-    <string name="select_language" msgid="3693815588777926848">"入力言語"</string>
+    <string name="select_language" msgid="5709487854987078367">"言語"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"保存するにはもう一度タップ"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"ここをタップして保存します"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"辞書を利用できます"</string>
diff --git a/java/res/values-ka-rGE/strings.xml b/java/res/values-ka-rGE/strings.xml
index 1ef53ac..f368f72 100644
--- a/java/res/values-ka-rGE/strings.xml
+++ b/java/res/values-ka-rGE/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"ვიბრაცია კლავიშზე დაჭერისას"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"ხმა კლავიშზე დაჭერისას"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"გადიდება ღილაკზე დაჭერისას"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"შეყვანის პარამეტრები"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"იერსახე"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"მრავალენობრივი ვარიანტები"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"ჟესტით შეყვ. პარამეტრები"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"პარამეტრები"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"იარსახე &amp; განლაგებები"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"მრავალენობრივი ვარიანტები"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"ჟესტებით წერა"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"ტექსტის კორექცია"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"გაფართოებული"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"თემა"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"შეყვანის სხვა მეთოდებზე გადართვა"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"ენის გადართვის ღილაკს შეყვანის სხვა მეთოდებსაც შეიცავს"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"ენის გადართვის კლავიში"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"ხმოვანი შეყვანის კლავიში"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"ხმოვანი შეყვანის მეთოდები ჩართული არ არის. შეამოწმეთ ენის &amp; შეყვანის პარამეტრები."</string>
     <string name="configure_input_method" msgid="373356270290742459">"შეყვანის მეთოდების კონფიგურაცია"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"შეყვანის ენები"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"ენები"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"დახმარება და უკუკავშირი"</string>
-    <string name="select_language" msgid="3693815588777926848">"შეყვანის ენები"</string>
+    <string name="select_language" msgid="5709487854987078367">"ენები"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"შეეხეთ ისევ შესანახად"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"აქ შეეხეთ, რომ შეინახოს"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"ხელმისაწვდომია ლექსიკონი"</string>
diff --git a/java/res/values-kk-rKZ/strings.xml b/java/res/values-kk-rKZ/strings.xml
index 7e07ca7..3efa9f9 100644
--- a/java/res/values-kk-rKZ/strings.xml
+++ b/java/res/values-kk-rKZ/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Пернені басқан кездегі діріл"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Пернені басу кезіндегі дыбыс"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Пернені басқан кездегі ашылмалы мәзір"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Енгізу параметрлері"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Сыртқы түр"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Көп тілді опциялар"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Қимыл арқылы теру параметрлері"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Қалауларыңыз"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Сыртқы түр және орналасулар"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Көп тілдік опциялар"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Қимыл арқылы теру"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Мәтінді түзету"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Кеңейтілген"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Тақырып"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Басқа енгізу әдістеріне ауыстырыңыз"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Тілді ауыстыру пернесі басқа енгізу әдістерін де қамтиды"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Тілді ауыстыру пернесі"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Дауыстық енгізу пернесі"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Дауыспен енгізу әдістері қосылмаған. «Тіл және енгізу параметрлері» тармағын тексеріңіз."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Енгізу әдістерін теңшеу"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Енгізу тілдері"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Тілдер"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Анықтама және кері байланыс"</string>
-    <string name="select_language" msgid="3693815588777926848">"Енгізу тілдері"</string>
+    <string name="select_language" msgid="5709487854987078367">"Тілдер"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Сақтау үшін қайта түртіңіз"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Сақтау үшін осы жерді түртіңіз"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Сөздік қолжетімді"</string>
diff --git a/java/res/values-km-rKH/strings.xml b/java/res/values-km-rKH/strings.xml
index 96dd08c..b9350c0 100644
--- a/java/res/values-km-rKH/strings.xml
+++ b/java/res/values-km-rKH/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"ញ័រ​នៅ​ពេល​ចុច​គ្រាប់ចុច"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"សំឡេង​នៅ​ពេល​ចុច​គ្រាប់ចុច"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"លេច​ឡើង​នៅ​​ពេល​ចុច​គ្រាប់​ចុច"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"ចំណូលចិត្ត​បញ្ចូល"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"រូបរាង"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"ជម្រើស​ភាសា​​ច្រើន"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"ចំណូលចិត្តបញ្ចូលកាយវិការ"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"ចំណូលចិត្ត"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"រូបរាង &amp; ប្លង់"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"ជម្រើស​ច្រើន​ភាសា"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"កាយវិការ​បញ្ចូល"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"ការ​កែ​​អត្ថបទ"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"កម្រិត​ខ្ពស់"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"រូបរាង"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"ប្ដូរ​ទៅ​​​វិធីសាស្ត្រ​បញ្ចូល​​​ផ្សេង​ទៀត"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"គ្រាប់ចុច​ប្ដូរ​ភាសា​តាម​វិធីសាស្ត្រ​បញ្ចូល​ផ្សេងទៀត"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"គ្រាប់​ចុច​ប្ដូរ​​ភាសា"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"គ្រាប់​ចុច​បញ្ចូល​​សំឡេង"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"គ្មាន​វិធីសាស្ត្រ​បញ្ចូល​សំឡេង​បាន​បើក។ ពិនិត្យ​មើល​ការ​កំណត់​ភាសា &amp; ការ​បញ្ចូល។"</string>
     <string name="configure_input_method" msgid="373356270290742459">"កំណត់​រចនាសម្ព័ន្ធ​វិធីសាស្ត្រ​បញ្ចូល"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"បញ្ចូល​ភាសា"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"ភាសា"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"ជំនួយ &amp; មតិ​ត្រឡប់"</string>
-    <string name="select_language" msgid="3693815588777926848">"​​បញ្ចូល​ភាសា"</string>
+    <string name="select_language" msgid="5709487854987078367">"ភាសា"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"ប៉ះ​ម្ដង​ទៀត​ ដើម្បី​រក្សា​ទុក"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"ប៉ះ​ទីនេះ​ដើម្បី​រក្សាទុក"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"មាន​វចនានុក្រម"</string>
diff --git a/java/res/values-kn-rIN/strings.xml b/java/res/values-kn-rIN/strings.xml
index 7febef8..cbb8ce1 100644
--- a/java/res/values-kn-rIN/strings.xml
+++ b/java/res/values-kn-rIN/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"ಕೀಲಿಯನ್ನು ಒತ್ತಿದಾಗ ವೈಬ್ರೇಷನ್‌"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"ಕೀಲಿಯನ್ನು ಒತ್ತಿದಾಗ ಶಬ್ದಮಾಡು"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"ಕೀ ಒತ್ತಿದಾಗ ಪಾಪ್ ಅಪ್‌ ಮಾಡು"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"ಇನ್‌ಪುಟ್ ಪ್ರಾಶಸ್ತ್ಯಗಳು"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"ಗೋಚರತೆ"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"ಬಹು ಭಾಷಾ ಆಯ್ಕೆಗಳು"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"ಗೆಶ್ಚರ್ ಟೈಪಿಂಗ್ ಪ್ರಾಶಸ್ತ್ಯಗಳು"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"ಆದ್ಯತೆಗಳು"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"ಗೋಚರತೆ &amp; ಲೇಔಟ್‌ಗಳು"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"ಬಹುಭಾಷೆ ಆಯ್ಕೆಗಳು"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"ಗೆಸ್ಚರ್ ಟೈಪಿಂಗ್"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"ಪಠ್ಯ ತಿದ್ದುಪಡಿ"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"ಸುಧಾರಿತ"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"ಥೀಮ್"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"ಇತರೆ ಇನ್‌ಪುಟ್ ವಿಧಾನಗಳಿಗೆ ಬದಲಾಯಿಸು"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"ಭಾಷಾ ಬದಲಾವಣೆ ಕೀಯು ಇತರೆ ಇನ್‌ಪುಟ್ ವಿಧಾನಗಳನ್ನು ಕೂಡ ಒಳಗೊಂಡಿರುತ್ತದೆ"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"ಭಾಷೆ ಬದಲಾವಣೆ ಕೀ"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"ಧ್ವನಿ ಇನ್‌ಪುಟ್ ಕೀ"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"ಯಾವುದೇ ಧ್ವನಿ ಇನ್‌ಪುಟ್ ವಿಧಾನಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿಲ್ಲ. ಭಾಷೆ &amp; ಇನ್‌ಪುಟ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ."</string>
     <string name="configure_input_method" msgid="373356270290742459">"ಇನ್‌ಪುಟ್ ವಿಧಾನಗಳನ್ನು ಕಾನ್ಫಿಗರ್ ಮಾಡಿ"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"ಇನ್‌ಪುಟ್ ಭಾಷೆಗಳು"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"ಭಾಷೆಗಳು"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"ಸಹಾಯ &amp; ಪ್ರತಿಕ್ರಿಯೆ"</string>
-    <string name="select_language" msgid="3693815588777926848">"ಇನ್‌ಪುಟ್ ಭಾಷೆಗಳು"</string>
+    <string name="select_language" msgid="5709487854987078367">"ಭಾಷೆಗಳು"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"ಉಳಿಸಲು ಮತ್ತೆ ಸ್ಪರ್ಶಿಸಿ"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"ಉಳಿಸಲು ಇಲ್ಲಿ ಸ್ಪರ್ಶಿಸಿ"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"ನಿಘಂಟು ಲಭ್ಯವಿದೆ"</string>
diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml
index 44d4c78..841dcee 100644
--- a/java/res/values-ko/strings.xml
+++ b/java/res/values-ko/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"키를 누를 때 진동 발생"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"키를 누를 때 소리 발생"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"키를 누를 때 팝업"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"입력 환경설정"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"디자인"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"다중 언어 옵션"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"제스처 타이핑 환경설정"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"환경설정"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"모양 및 레이아웃"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"다국어 옵션"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"제스처 타이핑"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"텍스트 수정"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"고급"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"테마"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"다른 입력 방법으로 전환"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"언어 전환 키가 제공하는 기타 입력 방법"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"언어 전환 키"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"음성 입력 키"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"사용 설정된 음성 입력 방법이 없습니다. 언어 및 입력 설정을 확인하세요."</string>
     <string name="configure_input_method" msgid="373356270290742459">"입력 방법 설정"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"입력 언어"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"언어"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"도움말 및 의견"</string>
-    <string name="select_language" msgid="3693815588777926848">"입력 언어"</string>
+    <string name="select_language" msgid="5709487854987078367">"언어"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"저장하려면 다시 터치"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"저장하려면 여기를 터치하세요."</string>
     <string name="has_dictionary" msgid="6071847973466625007">"사전 사용 가능"</string>
diff --git a/java/res/values-ky-rKG/strings.xml b/java/res/values-ky-rKG/strings.xml
index 3f8ac90..9521676 100644
--- a/java/res/values-ky-rKG/strings.xml
+++ b/java/res/values-ky-rKG/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Баскыч басылганда дирилдесин"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Баскыч басылганда чыккан үн"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Баскыч басылганда калкып чыкма"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Киргизүү жеке жөндөөлөрү"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Сырткы көрүнүшү"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Көп тилдүү параметрлер"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Жаңсп терүү жеке жөндлөрү"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Мүмкүнчүлүктөрдү тандоо"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Көрүнүш &amp; жайгашуулар"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Көп тилдүү параметрлер"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Жаңсап терүү"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Текстти оңдоо"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Өркүндөтүлгөн"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Тема"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Башка киргзүү ыкмалрна которуу"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Тил которуштуруу баскычында башка киргизүү ыкмалары дагы камтылган"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Тил которуштуруу баскычы"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Үн менен киргизүү баскычы"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Үн менен киргизүү ыкмаларынын бири да иштетилген эмес. Тил &amp; киргизүү жөндөөлөрүн текшериңиз."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Дайндрд киргзүү ыкмалрн конфигрцлоо"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Киргизүү тилдери"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Тилдер"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Жардам &amp; жооп пикир"</string>
-    <string name="select_language" msgid="3693815588777926848">"Киргизүү тилдери"</string>
+    <string name="select_language" msgid="5709487854987078367">"Тилдер"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Сактоо үчүн кайра тийип коюңуз"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Сактоо үчүн бул жерди басыңыз"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Сөздүк бар"</string>
diff --git a/java/res/values-lo-rLA/strings.xml b/java/res/values-lo-rLA/strings.xml
index 9bf3b63..c2d2f19 100644
--- a/java/res/values-lo-rLA/strings.xml
+++ b/java/res/values-lo-rLA/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"ສັ່ນເຕືອນເມື່ອພິມ"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"ສຽງໃນການກົດປຸ່ມ"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"ໂຕອັກສອນເວລາພິມ"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"​ການ​ຕັ້ງ​ຄ່າ​ການ​ປ້ອນ​ຂໍ້​ມູນ"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"​ຮູບ​ແບບ​ໜ້າ​ຕາ"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"​ໂຕ​ເລືອກ​ລະ​ບົບຫຼາຍ​ພາ​ສາ"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"​ການ​ຕັ້ງ​ຄ່າ​ການ​ພິມ​ດ້ວຍ​ທ່າ​ທາງ"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"ການປັບຄ່າຕ່າງໆຕາມທີ່ໃຈມັກ"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"​ລັກ​ສະ​ນະ &amp; ໂຄງ​ຮ່າງ"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"ຕົວເລືອກຫຼາຍພາສາ"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"ການພິມແບບລາກ"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"​ການ​ແປງ​ຄຳ​ໃຫ້​ຖືກ​ຕ້ອງ"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"​ຂັ້ນ​ສູງ"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"ຮູບແບບສີສັນ"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"ປ່ຽນໄປໃຊ້ການປ້ອນຂໍ້ມູນແບບອື່ນ"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"ໂຕປ່ຽນພາສາເປັນທັງໂຕປ່ຽນຮູບແບບການປ້ອນຂໍ້ມູນເຊັ່ນກັນ"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"ປຸ່ມປ່ຽນພາສາ"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"ປຸ່ມປ້ອນຂໍ້ມູນດ້ວຍສຽງ"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"ບໍ່ມີວິທີການປ້ອນສຽງເປີດນໍາໃຊ້. ໃຫ້ກວດເບິ່ງການຕັ້ງຄ່າໃນເມນູ ພາສາ &amp; ການປ້ອນຂໍ້ມູນ."</string>
     <string name="configure_input_method" msgid="373356270290742459">"ຕັ້ງຄ່າຮູບແບບການປ້ອນຂໍ້ມູນ"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"ພາສາການປ້ອນຂໍ້ມູນ"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"ພາ​ສາ"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"ຊ່ວຍ​ເຫຼືອ &amp; ຄຳ​ຕິ​ຊົມ"</string>
-    <string name="select_language" msgid="3693815588777926848">"ພາສາການປ້ອນຂໍ້ມູນ"</string>
+    <string name="select_language" msgid="5709487854987078367">"ພາ​ສາ"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"ກົດອີກຄັ້ງເພື່ອບັນທຶກ"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"ແຕະ​ບ່ອນ​ນີ້​ເພື່ອ​ບັນ​ທຶກ"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"ມີວັດຈະນານຸກົມ"</string>
diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml
index 42eaace..d34e508 100644
--- a/java/res/values-lt/strings.xml
+++ b/java/res/values-lt/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibruoti, kai paspaudžiami klavišai"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Klavišo paspaudimo garsas"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Iššoka paspaudus klavišą"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Įvesties nuostatos"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Išvaizda"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Kelių kalbų parinktys"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Įvesties gestais nuostat."</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Nuostatos"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Išvaizda ir išdėstymai"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Kelių kalbų parinktys"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Įvestis gestais"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Teksto taisymas"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Išplėstiniai"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Perj. į kt. įvesties būd."</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Kalbos perjungimo klavišu taip pat perjungiami įvesties būdai"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Kalbos keitimo klavišas"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Įvesties balsu klavišas"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nėra jokių įgalintų įvesties balsu metodų. Patikrinkite kalbos ir įvesties nustatymus."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigūruoti įvesties metodus"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Įvesties kalbos"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Kalbos"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Pagalba ir atsiliepimai"</string>
-    <string name="select_language" msgid="3693815588777926848">"Įvesties kalbos"</string>
+    <string name="select_language" msgid="5709487854987078367">"Kalbos"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Jei norite išsaugoti, palieskite dar kartą"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Palieskite čia, kad išsaugotumėte"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Žodynas galimas"</string>
diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml
index 90ed366..b075c03 100644
--- a/java/res/values-lv/strings.xml
+++ b/java/res/values-lv/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrēt, nospiežot taustiņu"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Skaņa, nospiežot taustiņu"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Nospiežot taustiņu, parādīt uznirstošo izvēlni"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Ievades preferences"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Izskats"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Vairāku valodu opcijas"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Ievade ar žestiem"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Preferences"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Izskats un izkārtojumi"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Vairākvalodu opcijas"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Ievade ar žestiem"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Teksta korekcija"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Papildu"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Motīvs"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Pārsl. uz citām iev. met."</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Valodas pārslēgš. taustiņu var lietot arī citām ievades metodēm."</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Valodas pārslēgšanas taustiņš"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Balss ievades atslēga"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nav iespējota neviena balss ievades metode. Pārbaudiet valodas un ievades iestatījumus."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Ievades metožu konfigurēšana"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Ievades valodas"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Valodas"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Palīdzība un atsauksmes"</string>
-    <string name="select_language" msgid="3693815588777926848">"Ievades valodas"</string>
+    <string name="select_language" msgid="5709487854987078367">"Valodas"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Pieskarieties vēlreiz, lai saglabātu."</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Lai saglabātu, pieskarieties šeit"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Ir pieejama vārdnīca."</string>
diff --git a/java/res/values-mk-rMK/strings.xml b/java/res/values-mk-rMK/strings.xml
index 53f0ec6..5af26b9 100644
--- a/java/res/values-mk-rMK/strings.xml
+++ b/java/res/values-mk-rMK/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Вибрирање при притисок на копче"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Звук на притискање копче"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Појавен прозорец на притискање копче"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Приоритети за внесување"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Изглед"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Повеќејазични опции"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Параметри за пишување"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Претпочитани поставки"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Изглед и распоред"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Повеќејазични опции"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Пишување со движење"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Корекција на текст"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Напредни"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Тема"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Префрли на други влезни методи"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Копчето за менување јазици покрива и други методи на внес"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Копче за промена на јазик"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Копче за влез на глас"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Не се овозможени методи за гласовно внесување. Проверете ги поставките за Јазик и внесување."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Конфигурирај методи на влез"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Влезни јазици"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Јазици"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Помош и повратни информации"</string>
-    <string name="select_language" msgid="3693815588777926848">"Влезни јазици"</string>
+    <string name="select_language" msgid="5709487854987078367">"Јазици"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Допрете повторно за да се зачува"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Допри тука да се зачува"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Речникот е достапен"</string>
diff --git a/java/res/values-ml-rIN/strings.xml b/java/res/values-ml-rIN/strings.xml
index 3a3d008..a109f5b 100644
--- a/java/res/values-ml-rIN/strings.xml
+++ b/java/res/values-ml-rIN/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"കീ അമർത്തുമ്പോൾ വൈബ്രേറ്റുചെയ്യുക"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"കീ അമർത്തുമ്പോഴുള്ള ശബ്‌ദമുണ്ടാക്കുക"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"കീ അമർത്തുമ്പോൾ പോപ്പ്അപ്പ് ചെയ്യുക"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"ഇൻപുട്ട് മുൻഗണനകൾ"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"കാഴ്ച്ച"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"ഒന്നിലധികം ഭാഷകൾക്കുള്ള ഓ‌പ്ഷനുകൾ"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"ടൈപ്പുചെയ്യുന്നതിന് മുൻഗണന നൽകുന്ന സവിശേഷത"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"മുൻഗണനകൾ"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"രൂപഭാവവും ലേഔട്ടുകളും"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"മൾട്ടിലിംഗ്വൽ ഓപ്‌ഷനുകൾ"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"ഗെസ്ചർ ടൈപ്പിംഗ്"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"വാചകം തിരുത്തൽ"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"വിപുലമായ"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"തീം"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"മറ്റു ടൈപ്പുചെയ്യൽ രീതികളിലേക്ക് മാറുക"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"ഭാഷ മാറൽ കീയിൽ മറ്റ് ടൈപ്പുചെയ്യൽ രീതികളും ഉൾപ്പെടുന്നു"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"ഭാഷ മാറൽ കീ"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"വോയ്‌സ് ടൈപ്പുചെയ്യൽ കീ"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"വോയ്‌സ് ടൈപ്പുചെയ്യൽ രീതികളൊന്നും പ്രവർത്തനക്ഷമമല്ല. ഭാഷ &amp; ടൈപ്പു ചെയ്യൽ ക്രമീകരണങ്ങൾ പരിശോധിക്കുക."</string>
     <string name="configure_input_method" msgid="373356270290742459">"ടൈപ്പുചെയ്യൽ രീതികൾ കോൺഫിഗർ ചെയ്യുക"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"ടൈപ്പുചെയ്യൽ ഭാഷകൾ"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"ഭാഷകള്‍‌"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"സഹായവും ഫീഡ്‌ബാക്കും"</string>
-    <string name="select_language" msgid="3693815588777926848">"ടൈപ്പുചെയ്യൽ ഭാഷകൾ"</string>
+    <string name="select_language" msgid="5709487854987078367">"ഭാഷകള്‍‌"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"സംരക്ഷിക്കുന്നതിനായി വീണ്ടും സ്‌പർശിക്കുക"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"സംരക്ഷിക്കാൻ ഇവിടെ സ്‌പർശിക്കുക"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"നിഘണ്ടു ലഭ്യമാണ്"</string>
@@ -102,7 +103,7 @@
     <string name="subtype_emoji" msgid="7483586578074549196">"ഇമോജി"</string>
     <string name="keyboard_theme" msgid="4909551808526178852">"കീബോർഡ് തീം"</string>
     <string name="custom_input_styles_title" msgid="8429952441821251512">"ഇഷ്‌ടാനുസൃത ടൈപ്പുചെയ്യൽ ശൈലികൾ"</string>
-    <string name="add_style" msgid="6163126614514489951">"ശൈലി ചേർക്കുക"</string>
+    <string name="add_style" msgid="6163126614514489951">"സ്റ്റൈൽ ചേർക്കുക"</string>
     <string name="add" msgid="8299699805688017798">"ചേര്‍ക്കുക"</string>
     <string name="remove" msgid="4486081658752944606">"നീക്കംചെയ്യുക"</string>
     <string name="save" msgid="7646738597196767214">"സംരക്ഷിക്കുക"</string>
diff --git a/java/res/values-mn-rMN/strings.xml b/java/res/values-mn-rMN/strings.xml
index 4d9de57..e88cf56 100644
--- a/java/res/values-mn-rMN/strings.xml
+++ b/java/res/values-mn-rMN/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Товч дарахад чичрэх"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Товч дарахад дуу гаргах"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Товч дарахад попап гарна"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Оруулгын тохируулга"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Харагдац"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Олон хэлний сонголтууд"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Зангалтын бичих тохируулга"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Тохируулга"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Харагдац &amp; байрлал"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Олон хэлний сонголт"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Зангаагаар бичих"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Текст залруулалт"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Дэлгэрэнгүй"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Загвар"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Оруулах өөр арга руу шилжүүлэх"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Хэл солих түлхүүрт өөр оруулах аргууд мөн багтсан байгаа"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Хэл солих товч"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Дуун оруулгын товч"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ямар ч дуу оруулах хэрэглүүр идэвхжээгүй байна. Хэл болон оруулалтын тохиргоог шалгана уу."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Оруулах аргуудын тохиргоо"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Оруулах хэл"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Хэл"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Тусламж &amp; санал хүсэлт"</string>
-    <string name="select_language" msgid="3693815588777926848">"Оруулах хэл"</string>
+    <string name="select_language" msgid="5709487854987078367">"Хэл"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Хадгалахын тулд дахин хүрнэ үү"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Хадгалахын тулд хүрнэ үү"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Толь бичиг байна"</string>
diff --git a/java/res/values-mr-rIN/strings.xml b/java/res/values-mr-rIN/strings.xml
index 3561996..0d51878 100644
--- a/java/res/values-mr-rIN/strings.xml
+++ b/java/res/values-mr-rIN/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"कीप्रेस करताना होणारे कंपन"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"कीप्रेस करताना होणारा ध्वनी"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"कीप्रेस करताना पॉपअप"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"इनपुट प्राधान्ये"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"दिसणे"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"बहुभाषिक पर्याय"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"हावभाग टायपिंग प्राधान्ये"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"प्राधान्ये"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"स्वरूप आणि लेआउट"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"बहुभाषिक पर्याय"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"जेश्चर टायपिंग"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"मजकूर दुरुस्ती"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"प्रगत"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"थीम"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"अन्य इनपुट पद्धतींवर स्विच करा"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"भाषा स्विच की अन्य इनपुट पद्धती देखील समाविष्ट करते"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"भाषा स्विच की"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"व्हॉइस इनपुट की"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"व्हॉइस इनपुट पद्धती सक्षम केल्या नाहीत. भाषा आणि इनपुट सेटिंग्ज तपासा."</string>
     <string name="configure_input_method" msgid="373356270290742459">"इनपुट पद्धती कॉन्फिगर करा"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"इनपुट भाषा"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"भाषा"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"मदत आणि अभिप्राय"</string>
-    <string name="select_language" msgid="3693815588777926848">"इनपुट भाषा"</string>
+    <string name="select_language" msgid="5709487854987078367">"भाषा"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"जतन करण्यासाठी पुन्हा स्पर्श करा"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"जतन करण्यासाठी येथे स्पर्श करा"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"शब्दकोश उपलब्ध"</string>
diff --git a/java/res/values-ms-rMY/strings.xml b/java/res/values-ms-rMY/strings.xml
index 471fe5e..8032f6b 100644
--- a/java/res/values-ms-rMY/strings.xml
+++ b/java/res/values-ms-rMY/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Getar pada tekanan kekunci"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Bunyi pada tekanan kekunci"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Pop timbul pada tekanan kunci"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Pilihan input"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Tampilan"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Pilihan berbilang bahasa"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Plhn taipan gerak isyarat"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Pilihan"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Rupa &amp; reka letak"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Pilihan berbilang bahasa"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Taipan Gerak Isyarat"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Pembetulan teks"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Lanjutan"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Tukar ke kaedah input lain"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Kunci pertukaran bahasa meliputi kaedah masukan lain juga"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Kekunci tukar bahasa"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Kunci input suara"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Tiada kaedah input suara didayakan. Semak Bahasa &amp; tetapan input."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurasikan kaedah input"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Bahasa input"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Bahasa"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Bantuan &amp; m/balas"</string>
-    <string name="select_language" msgid="3693815588777926848">"Bahasa input"</string>
+    <string name="select_language" msgid="5709487854987078367">"Bahasa"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Sentuh lagi untuk menyimpan"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Sentuh di sini untuk menyimpan"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Kamus tersedia"</string>
diff --git a/java/res/values-my-rMM/strings.xml b/java/res/values-my-rMM/strings.xml
index ed0de4e..744e384 100644
--- a/java/res/values-my-rMM/strings.xml
+++ b/java/res/values-my-rMM/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"ခလုတ်နှိပ်သည်နှင့် တုံခါစေပါ"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"ခလုတ်နှိပ်လျှင် အသံမြည်"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"ကီးနှိပ်လိုက်သည်နှင့် ပေါ်လာရန်"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"စာရိုက်ထည့်မှု ရွေးစရာ"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"အပြင်အဆင်"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"ဘာသာများစွာ ရွေးချယ်မှု"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"အမူယာစာရိုက်ခြင်း စိတ်ကြိုက်များ"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"ရွေးချယ်စရာများ"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"အပြင်ပန်း &amp; အပြင်အဆင်များ"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"ဘာသာစကားစုံ ရွေးချယ်စရာများ"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"လှုပ်ရှားမှုဖြင့်စာရိုက်ခြင်း"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"စာအမှားပြပြင်ခြင်း"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"အဆင့်မြင့်"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"အပြင်အဆင်"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"အခြားထည့်သွင်းမည့် နည်းလမ်းများသို့ ပြောင်းရန်"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"ဘာသာပြောင်းသည့် ကီးသည် အခြားထည့်သွင်းရန် နည်းလမ်းများလည်း ပါဝင်သည်"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"ဘာသာစကား ပြောင်းခလုတ်"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"အသံထည့်သွင်းရန် ခလုတ်"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"မည်သည့် Check Language &amp; input settings."</string>
     <string name="configure_input_method" msgid="373356270290742459">"ထည့်သွင်းရန် နည်းလမ်းကို ပြုပြင်မည်"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"စာရိုက်ထည့် ဘာသာ"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"ဘာသာစကားများ"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"အကူအညီ &amp; တုံ့ပြန်ချက်"</string>
-    <string name="select_language" msgid="3693815588777926848">"စာရိုက်ထည့် ဘာသာ"</string>
+    <string name="select_language" msgid="5709487854987078367">"ဘာသာစကားများ"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"သိမ်းရန် နောက်တစ်ကြိမ်နှိပ်ပါ"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"သိမ်းရန် ဤနေရာကို ထိပါ"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"အဘိဓါန်ရနိုင်"</string>
diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml
index 8a875bc..3f929e2 100644
--- a/java/res/values-nb/strings.xml
+++ b/java/res/values-nb/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrer ved tastetrykk"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Lyd ved tastetrykk"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Hurtigvindu ved tastetrykk"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Inndatainnstillinger"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Utseende"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Flerspråksalternativer"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Innstillinger for ordføring"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Innstillinger"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Utseende og utforming"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Flerspråksalternativer"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Ordføring"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Tekstkorrigering"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Avansert"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Bytt inndatametode"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Tasten for språkbytte dekker også andre inndatametoder"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Nøkkel for språkskifte"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Tast for taleinndata"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ingen taleinndatametoder er aktivert. Sjekk Språk og inndata-innstillingene."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurer inndatametoder"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Inndataspråk"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Språk"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Hjelp og tilbakemelding"</string>
-    <string name="select_language" msgid="3693815588777926848">"Inndataspråk"</string>
+    <string name="select_language" msgid="5709487854987078367">"Språk"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Trykk på nytt for å lagre"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Trykk her for å lagre"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Ordbok tilgjengelig"</string>
diff --git a/java/res/values-ne-rNP/strings.xml b/java/res/values-ne-rNP/strings.xml
index 514510b..dd8fd82 100644
--- a/java/res/values-ne-rNP/strings.xml
+++ b/java/res/values-ne-rNP/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"कुञ्जी थिच्दा भाइब्रेट"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"कुञ्जी थिच्दा आवाज"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"कुञ्जी दबाउँदा पपअप"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"निवेश प्राथमिकता"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"उपस्थिति"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"बहुभाषी विकल्प"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"इशारा टाइप प्राथमिकता"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"प्राथमिकताहरू"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"देखिने; रूपरेखा"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"बहुभाषी विकल्पहरू"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"इशारा टाइपिङ"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"पाठ सुधार"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"उन्नत"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"विषयवस्तु"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"अन्य इनपुट विधिमा स्विच गर्नुहोस्"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"भाषा स्विच किले अन्य इनपुट विधि पनि समेट्छ"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"भाषा स्विच कुञ्जी"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"आवाज इनपुट कुञ्जी"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"कुनै आवाज इनपुट विधिहरू सक्षम गरिएका छैनन्। भाषा र इनपुट सेटिङहरूको जाँच गर्नुहोस्।"</string>
     <string name="configure_input_method" msgid="373356270290742459">"इनपुट विधिहरू कन्फिगर गर्नुहोस्"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"इनपुट भाषाहरू"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"भाषाहरू"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"मद्दत र प्रतिक्रिया"</string>
-    <string name="select_language" msgid="3693815588777926848">"इनपुट भाषाहरू"</string>
+    <string name="select_language" msgid="5709487854987078367">"भाषाहरू"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"बचत गर्न पुनः छुनुहोस्"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"सुरक्षित गर्न यहाँ छुनुहोस्"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"उपलब्ध शब्दकोश"</string>
diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml
index 9b3d1f0..e19294e 100644
--- a/java/res/values-nl/strings.xml
+++ b/java/res/values-nl/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Trillen bij toetsaanslag"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Geluid bij toetsaanslag"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up bij toetsaanslag"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Invoervoorkeuren"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Weergave"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Meertalige opties"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Voorkeuren voor Invoer met bewegingen"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Voorkeuren"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Uiterlijk en indelingen"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Meertalige opties"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Invoer met bewegingen"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Tekstcorrectie"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Geavanceerd"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Thema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Invoermeth. overschakelen"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Schakelknop voor taal ook van toepassing op andere invoermethoden"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Schakelknop voor taal"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Toets voor spraakinvoer"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Geen spraakinvoermethoden ingeschakeld. Ga naar \'Instellingen voor taal en invoer\'."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Invoermethoden configureren"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Invoertalen"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Talen"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Help en feedback"</string>
-    <string name="select_language" msgid="3693815588777926848">"Invoertalen"</string>
+    <string name="select_language" msgid="5709487854987078367">"Talen"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Tik nogmaals om op te slaan"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Tik hier om op te slaan"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Woordenboek beschikbaar"</string>
diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml
index e9c6e2c..3af2b03 100644
--- a/java/res/values-pl/strings.xml
+++ b/java/res/values-pl/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Wibracja przy naciśnięciu"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Dźwięk przy naciśnięciu"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Powiększ po naciśnięciu"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Opcje wprowadzania"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Wygląd"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Opcje obsługi wielu języków"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Ustawienia pisania gestami"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Ustawienia"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Wygląd i układy"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Opcje obsługi wielu języków"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Pisanie gestami"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Korekta tekstu"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Zaawansowane"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Motyw"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Inne metody wprowadzania"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Klawisz zmiany języka obejmuje też inne metody wprowadzania"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Klawisz zmiany języka"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Klawisz rozpoznawania mowy"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nie włączono żadnych metod wprowadzania głosowego. Sprawdź ustawienia języka i wprowadzania."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfiguruj metody wprowadzania"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Języki wprowadzania"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Języki"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Pomoc i opinie"</string>
-    <string name="select_language" msgid="3693815588777926848">"Języki wprowadzania"</string>
+    <string name="select_language" msgid="5709487854987078367">"Języki"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Dotknij ponownie, aby zapisać"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Kliknij tutaj, by zapisać"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Słownik dostępny"</string>
diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml
index 678b38f..6580aa6 100644
--- a/java/res/values-pt-rPT/strings.xml
+++ b/java/res/values-pt-rPT/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar ao primir as teclas"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Som ao premir as teclas"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Mostrar popup ao premir tecla"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Preferências introdução"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Aspeto"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Opções p/ vários idiomas"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Pref. de intr. de gestos"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Preferências"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Aspeto e esquemas"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Opções para vários idiomas"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Escrita com gestos"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Correção de texto"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Avançadas"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Mudar p/ outros mét. ent."</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"A tecla de mudança de idioma abrange outros métodos de entrada"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Tecla alterar idioma"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Chave de entrada de voz"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nenhum método de entrada de texto por voz ativado. Verifique as definições de Idioma e introdução."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de introdução"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Idiomas"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Ajuda e comentários"</string>
-    <string name="select_language" msgid="3693815588777926848">"Idiomas de introdução"</string>
+    <string name="select_language" msgid="5709487854987078367">"Idiomas"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Toque novamente para guardar"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Toque aqui para guardar"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dicionário disponível"</string>
diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml
index 9e0b6e4..cf795c4 100644
--- a/java/res/values-pt/strings.xml
+++ b/java/res/values-pt/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar ao tocar a tecla"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Som ao tocar a tecla"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Exibir pop-up ao digitar"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Preferências de entrada"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Aparência"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Opções multilíngues"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Pref. da entr. por gestos"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Preferências"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Aparência e layouts"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Opções multilíngues"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Escrita com gestos"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Correção de texto"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Avançadas"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Outros métodos de entrada"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"A tecla p/ mudar o idioma também cobre outros métodos de entrada"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Tecla de seleção de idioma"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Tecla p/ inserir texto por voz"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nenhum método de entrada de texto por voz ativado. Verifique as configurações \"Idioma e entrada\"."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de entrada"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Idiomas"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Ajuda e feedback"</string>
-    <string name="select_language" msgid="3693815588777926848">"Idiomas de entrada"</string>
+    <string name="select_language" msgid="5709487854987078367">"Idiomas"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Toque novamente para salvar"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Toque aqui para salvar"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dicionário disponível"</string>
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index bd537a1..c3d1e05 100644
--- a/java/res/values-ro/strings.xml
+++ b/java/res/values-ro/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrare la apăsarea tastei"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Sunet la apăsarea tastei"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up la apăsarea tastei"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Preferințe pentru intrare"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Aspect"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Opțiuni pt. diverse limbi"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Prefer. tastare gestuală"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Preferinţe"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Aspect"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Opțiuni multilingve"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Tastare gestuală"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Corectare text"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Setări avansate"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Temă"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Comut. alte metode de introd."</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Tasta de comutare între limbi include şi alte metode de introd."</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Tastă comutare limbi"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Tastă pentru intrarea vocală"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nicio metodă de intrare vocală activată. Verificați setările pentru limbă și introducere de text."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configuraţi metodele de intrare"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Selectaţi limba"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Limbi"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Ajutor și feedback"</string>
-    <string name="select_language" msgid="3693815588777926848">"Limbi de introducere de text"</string>
+    <string name="select_language" msgid="5709487854987078367">"Limbi"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Atingeţi din nou pentru a salva"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Atingeți aici pentru a salva"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dicţionar disponibil"</string>
diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml
index 491e180..277c5ff 100644
--- a/java/res/values-ru/strings.xml
+++ b/java/res/values-ru/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Виброотклик клавиш"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Звук клавиш"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Увеличение нажатых"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Параметры ввода"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Внешний вид"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Языковые параметры"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Непрерывный ввод"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Настройки"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Вид и разметка"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Дополнительные языки"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Непрерывный ввод"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Исправление текста"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Дополнительные настройки"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Тема"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Смена способов ввода"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Клавиша переключения языков также служит для смены способа ввода"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Клавиша смены языка"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Кнопка голосового ввода"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Голосовой способ ввода не включен. Проверьте раздел настроек \"Язык и ввод\"."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Настройка способов ввода"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Языки ввода"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Выберите язык"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Справка/отзыв"</string>
-    <string name="select_language" msgid="3693815588777926848">"Языки ввода"</string>
+    <string name="select_language" msgid="5709487854987078367">"Язык"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Нажмите, чтобы сохранить"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Нажмите, чтобы сохранить"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Доступен словарь"</string>
diff --git a/java/res/values-si-rLK/strings.xml b/java/res/values-si-rLK/strings.xml
index 72a4437..99b4347 100644
--- a/java/res/values-si-rLK/strings.xml
+++ b/java/res/values-si-rLK/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"යතුර එබීමට කම්පනය කිරීම සක්‍රියයි"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"යතුරු එබිම මත හඬ"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"යතුරු එබීම මත උත්පතනය"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"ආදාන මනාපය"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"පෙනුම"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"බහු මූර්ධජ අක්ෂර විකල්ප"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"ඉංගිතයෙන් ටයිප් කිරීමේ මනාපය"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"අභිරුචි"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"පෙනුම සහ පිරිසැලසුම්"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"බහු භාෂා විකල්ප"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"ඉංගිත ටයිප් කිරීම"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"පෙළ නිවැරදි කිරීම"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"උසස්"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"තේමාව"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"වෙනත් ආදාන ක්‍රම වෙත මාරුවන්න"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"භාෂා මාරු යතුර වෙනත් ආදාන ක්‍රමද ආවරණය කරයි"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"භාෂා මාරු යතුර"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"හඬ ආදාන යතුර"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"හඬ ආදාන සබල කර නැත. භාෂාව සහ ආදාන සැකසීම් පරීක්ෂා කරන්න."</string>
     <string name="configure_input_method" msgid="373356270290742459">"ආදාන ක්‍රම වින්‍යාස කරන්න"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"ආදාන භාෂා"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"භාෂා"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"උදවු සහ ප්‍රතිපෝෂණ"</string>
-    <string name="select_language" msgid="3693815588777926848">"ආදාන භාෂා"</string>
+    <string name="select_language" msgid="5709487854987078367">"භාෂා"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"සුරැකීමට නැවත ස්පර්ශ කරන්න"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"සුරැකීමට මෙතැන ස්පර්ෂ කරන්න"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"ශබ්ද කෝෂය ලබාගත හැක"</string>
diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml
index b9c2b0e..bedc6b3 100644
--- a/java/res/values-sk/strings.xml
+++ b/java/res/values-sk/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Pri stlačení klávesu vibrovať"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Zvuk pri stlačení klávesu"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Zobraziť znaky pri stlačení klávesu"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Predvoľby vstupu"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Vzhľad"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Možnosti viacer. jazykov"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Predvoľby písania gestami"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Predvoľby"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Vzhľad a rozloženia"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Možnosti viacerých jazykov"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Písanie gestami"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Oprava textu"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Rozšírené"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Motív"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Prepnúť na iné metódy vstupu"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Kláves na prepnutie jazyka pokrýva aj ďalšie metódy vstupu"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Kľúč na prepínanie jazyka"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Kľúč hlasového vstupu"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nie sú povolené žiadne metódy hlasového vstupu. Skontrolujte nastavenia položky Jazyk a vstup."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurovať metódy vstupu"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Jazyky vstupu"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Jazyky"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Pomocník a spätná väzba"</string>
-    <string name="select_language" msgid="3693815588777926848">"Jazyky vstupu"</string>
+    <string name="select_language" msgid="5709487854987078367">"Jazyky"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Opätovným dotykom uložíte"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Klepnutím tu uložíte"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"K dispozícii je slovník"</string>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
index 39179d1..a322ed0 100644
--- a/java/res/values-sl/strings.xml
+++ b/java/res/values-sl/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibriranje ob pritisku tipke"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Zvok ob pritisku tipke"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Povečaj črko ob pritisku"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Nastavitve vnosa"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Videz"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Večjezikovne možnosti"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Nastavitve pisanja s kretnjami"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Nastavitve"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Videz in postavitve"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Večjezikovne možnosti"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Pisanje s kretnjami"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Popravki besedila"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Dodatno"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Prekl. na drug nač. vnosa"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Tipka za preklop jezika, ki vključuje tudi druge načine vnosa"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Tipka za preklop med jeziki"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Tipka za glasovni vnos"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ni omogočenih glasovnih načinov vnosa. Preverite nastavitve v razdelku »Jezik in vnos«."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Nastavitev načinov vnosa"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Jeziki vnosa"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Jeziki"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Pomoč in povratne informacije"</string>
-    <string name="select_language" msgid="3693815588777926848">"Jeziki vnosa"</string>
+    <string name="select_language" msgid="5709487854987078367">"Jeziki"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Dotaknite se še enkrat, da shranite"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Če želite shraniti, se dotaknite tukaj"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Slovar je na voljo"</string>
diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml
index 2b69a6c..a5c2a3b 100644
--- a/java/res/values-sr/strings.xml
+++ b/java/res/values-sr/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Вибрирај на притисак тастера"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Звук на притисак тастера"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Искачући прозор приликом притиска тастера"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Подешавања уноса"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Изглед"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Опције за више језика"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Подешавања за унос покретима"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Подешавања"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Изглед и распореди"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Опције за више језика"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Куцање покретима"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Исправљање текста"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Напредно"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Тема"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Пребаци на друге методе уноса"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Тастер за пребацивање језика обухвата и друге методе уноса"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Тастер за пребацивање језика"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Тастер за гласовни унос"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ниједан метод гласовног уноса није омогућен. Проверите Подешавања језика и уноса."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Конфигурисање метода уноса"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Језици за унос"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Језици"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Помоћ и повратне информације"</string>
-    <string name="select_language" msgid="3693815588777926848">"Језици уноса"</string>
+    <string name="select_language" msgid="5709487854987078367">"Језици"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Поново додирните да бисте сачували"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Додирните овде да бисте сачували"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Речник је доступан"</string>
diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml
index e5c6d3b..6bf3a32 100644
--- a/java/res/values-sv/strings.xml
+++ b/java/res/values-sv/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrera vid tangenttryck"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Knappljud"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Popup vid knapptryck"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Inmatningsinställningar"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Utseende"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Flerspråkiga alternativ"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Inställningar för att skriva in gester"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Inställningar"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Utseende och layouter"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Alternativ för flera språk"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Svepskrivning"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Textkorrigering"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Avancerat"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Byt till annan inmatning"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Språkbytesknappen omfattar även andra inmatningsmetoder"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Knapp för att byta språk"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Röstinmatningsknapp"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ingen röstinmatningsmetod har aktiverats. Kontrollera språk- och inmatningsinställningarna."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurera inmatningsmetoder"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Inmatningsspråk"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Språk"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Hjälp och feedback"</string>
-    <string name="select_language" msgid="3693815588777926848">"Inmatningsspråk"</string>
+    <string name="select_language" msgid="5709487854987078367">"Språk"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Spara genom att trycka igen"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Tryck här om du vill spara"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"En ordlista är tillgänglig"</string>
diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml
index b2f4d41..cd4a25b 100644
--- a/java/res/values-sw/strings.xml
+++ b/java/res/values-sw/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Tetema unabofya kitufe"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Toa sauti unapobofya kitufe"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Ibuka kitufe kinapobonyezwa"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Andika mapendeleo"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Mwonekano"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Chaguo za lugha nyingi"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Mapendeleo ya kuchapa kwa ishara"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Mapendeleo"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Muonekano na mipangilio"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Chaguo za lugha nyingi"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Kuandika kwa Ishara"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Masahihisho ya maandishi"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Mahiri"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Mandhari"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Badilisha hadi kwa mbinu zingine za ingizo"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Ufunguo wa kubadilisha lugha unashughulikia mbinu zingine za ingizo pia"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Kitufe cha kubadilisha lugha"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Kibao cha kuweka data kwa kutamka"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Hakuna mbinu ya kuweka data kwa kutamka iliyowashwa. Angalia Lugha na mipangilio ya kuingiza data."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Sanidi mbinu za uingizaji"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Lugha za uingizaji"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Lugha"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Usaidizi na maoni"</string>
-    <string name="select_language" msgid="3693815588777926848">"Lugha zinazoruhusiwa"</string>
+    <string name="select_language" msgid="5709487854987078367">"Lugha"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Gusa tena ili kuhifadhi"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Gusa hapa ili uhifadhi"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Kamusi inapatikana"</string>
diff --git a/java/res/values-ta-rIN/strings.xml b/java/res/values-ta-rIN/strings.xml
index d0a71c1..bdddc0d 100644
--- a/java/res/values-ta-rIN/strings.xml
+++ b/java/res/values-ta-rIN/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"விசையழுத்தின்போது அதிர்வுரு"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"விசையழுத்தத்தின்போது ஒலியெழுப்பு"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"விழை அழுத்தத்தின்போது பாப்அப் செய்"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"உள்ளீட்டு விருப்பங்கள்"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"தோற்றம்"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"பல மொழி விருப்பங்கள்"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"சைகைத்தட்டச்சு விருப்பம்"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"விருப்பங்கள்"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"தோற்றம் &amp; தளவமைப்புகள்"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"பன்மொழி தேர்வுகள்"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"சைகைத் தட்டச்சு"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"உரை திருத்தம்"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"மேம்பட்டவை"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"தீம்"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"பிற உள்ளீட்டு முறைகளுக்கு மாறு"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"மொழி மாற்றல் விசை பிற உள்ளீட்டு முறைகளையும் கட்டுப்படுத்துகிறது"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"மொழி மாற்ற விசை"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"குரல் உள்ளீட்டு விசை"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"குரல் உள்ளீட்டு முறைகள் எதுவும் இயக்கப்படவில்லை. மொழி &amp; உள்ளீட்டு அமைப்புகளைச் சரிபார்க்கவும்."</string>
     <string name="configure_input_method" msgid="373356270290742459">"உள்ளீட்டு முறைகளை உள்ளமைத்தல்"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"உள்ளீட்டு மொழிகள்"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"மொழிகள்"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"உதவி &amp; கருத்து"</string>
-    <string name="select_language" msgid="3693815588777926848">"உள்ளீட்டு மொழிகள்"</string>
+    <string name="select_language" msgid="5709487854987078367">"மொழிகள்"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"சேமிக்க தொடவும்"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"சேமிக்க இங்கு தொடவும்"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"அகராதி உள்ளது"</string>
diff --git a/java/res/values-te-rIN/strings.xml b/java/res/values-te-rIN/strings.xml
index b4bcf2c..d368b05 100644
--- a/java/res/values-te-rIN/strings.xml
+++ b/java/res/values-te-rIN/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"కీని నొక్కినప్పుడు వైబ్రేట్"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"కీని నొక్కినప్పుడు ధ్వని"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"కీని నొక్కినప్పుడు పాప్‌అప్ చూపు"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"ఇన్‌పుట్ ప్రాధాన్యతలు"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"కనిపించే తీరు"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"బహుళ భాషా ఎంపికలు"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"సంజ్ఞ టైపింగ్ ప్రాధాన్యతలు"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"ప్రాధాన్యతలు"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"కనిపించే తీరు &amp; లేఅవుట్‌లు"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"బహుభాషా ఎంపికలు"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"సంజ్ఞ టైపింగ్"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"వచన సవరణ"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"అధునాతనం"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"థీమ్"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"ఇతర ఇన్‌పుట్ పద్ధతులకు మారండి"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"భాష మార్పు కీ ఇతర ఇన్‌పుట్ పద్ధతులను కూడా కవర్ చేస్తుంది"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"భాష మార్పు కీ"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"వాయిస్ ఇన్‌పుట్ కీ"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"వాయిస్ ఇన్‌పుట్ పద్ధతులు ఏవీ ప్రారంభించబడలేదు. భాష &amp; ఇన్‌పుట్ సెట్టింగ్‌లను తనిఖీ చేయండి."</string>
     <string name="configure_input_method" msgid="373356270290742459">"ఇన్‌పుట్ పద్ధతులను కాన్ఫిగర్ చేయండి"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"ఇన్‌పుట్ భాషలు"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"భాషలు"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"సహాయం &amp; అభిప్రాయం"</string>
-    <string name="select_language" msgid="3693815588777926848">"ఇన్‌పుట్ భాషలు"</string>
+    <string name="select_language" msgid="5709487854987078367">"భాషలు"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"సేవ్ చేయడానికి మళ్లీ తాకండి"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"సేవ్ చేయడానికి ఇక్కడ తాకండి"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"నిఘంటువు అందుబాటులో ఉంది"</string>
diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml
index e32a155..5dc761d 100644
--- a/java/res/values-th/strings.xml
+++ b/java/res/values-th/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"สั่นเมื่อกดปุ่ม"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"ส่งเสียงเมื่อกดปุ่ม"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"ป๊อปอัปเมื่อกดแป้น"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"ค่ากำหนดการป้อนข้อมูล"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"ลักษณะที่ปรากฏ"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"ตัวเลือกหลายภาษา"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"การป้อนข้อมูลด้วยท่าทาง"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"ค่ากำหนด"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"ลักษณะที่ปรากฏและรูปแบบ"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"ตัวเลือกหลายภาษา"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"การป้อนข้อมูลด้วยท่าทาง"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"การแก้ไขข้อความ"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"ขั้นสูง"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"ธีม"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"ใช้วิธีการป้อนข้อมูลอื่น"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"แป้นสลับภาษาครอบคลุมวิธีการป้อนข้อมูลอื่นๆ ด้วย"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"แป้นสลับภาษา"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"แป้นการป้อนข้อมูลด้วยเสียง"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"ไม่ได้เปิดใช้วิธีการป้อนข้อมูลด้วยเสียง ตรวจสอบภาษาและการตั้งค่าการป้อนข้อมูล"</string>
     <string name="configure_input_method" msgid="373356270290742459">"กำหนดค่าวิธีการป้อนข้อมูล"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"ภาษาในการป้อนข้อมูล"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"ภาษา"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"ความช่วยเหลือและความคิดเห็น"</string>
-    <string name="select_language" msgid="3693815588777926848">"ภาษาสำหรับการป้อนข้อมูล"</string>
+    <string name="select_language" msgid="5709487854987078367">"ภาษา"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"แตะอีกครั้งเพื่อบัน​​ทึก"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"แตะที่นี่เพื่อบันทึก"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"มีพจนานุกรมให้ใช้งาน"</string>
diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml
index 056d552..7e6e6f7 100644
--- a/java/res/values-tl/strings.xml
+++ b/java/res/values-tl/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Mag-vibrate sa keypress"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Tumunog sa keypress"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Mag-popup sa keypress"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Mga kagustuhan sa input"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Hitsura"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Opsyon sa maraming wika"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Gustong gesture typing"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Mga Kagustuhan"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Hitsura at mga layout"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Opsyon na pangmaraming wika"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Pagta-type Gamit ang Galaw"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Pagwawasto ng text"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Advanced"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Lipat iba paraan ng input"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Saklaw din ng key ng pagpalit ng wika ang ibang paraan ng input"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Key ng panlipat ng wika"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Voice input key"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Walang naka-enable na pamamaraan ng pag-input ng boses. Suriin ang mga setting ng Pag-input ng wika."</string>
     <string name="configure_input_method" msgid="373356270290742459">"I-configure ang mga pamamaraan ng pag-input"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Mag-input ng mga wika"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Mga Wika"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Tulong at feedback"</string>
-    <string name="select_language" msgid="3693815588777926848">"Mga wika ng input"</string>
+    <string name="select_language" msgid="5709487854987078367">"Mga Wika"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Pinduting muli upang i-save"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Pumindot dito upang mag-save"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Available ang diksyunaryo"</string>
diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml
index 66d6c24..edaa1fc 100644
--- a/java/res/values-tr/strings.xml
+++ b/java/res/values-tr/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Tuşa basıldığında titret"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Tuşa basıldığında ses çıkar"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Tuşa basıldığında pop-up aç"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Giriş tercihleri"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Görünüm"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Çok dilli seçenekler"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Hareketle yazma tercihleri"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Tercihler"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Görünüm ve düzen"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Çok dilli seçenekler"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Hareketle Yazma"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Metin düzeltme"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Gelişmiş"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Tema"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Diğer giriş yöntemine geç"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Dil geçiş tuşu diğer giriş yöntemlerini de kapsar"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Dil değiştirme tuşu"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Ses girişi tuşu"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Hiçbir ses girişi yöntemi etkinleştirilmedi. Dil ve giriş ayarlarını kontrol edin."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Giriş yöntemlerini yapılandır"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Giriş dilleri"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Diller"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Yardım ve geri bildirim"</string>
-    <string name="select_language" msgid="3693815588777926848">"Giriş dilleri"</string>
+    <string name="select_language" msgid="5709487854987078367">"Diller"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Kaydetmek için tekrar dokunun"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Kaydetmek için buraya dokunun"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Sözlük kullanılabilir"</string>
diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml
index 7fe0756..a403261 100644
--- a/java/res/values-uk/strings.xml
+++ b/java/res/values-uk/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Вібр. при натисканні клавіш"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Звук при натиску клав."</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Сплив. при нат.клав."</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Параметри введення"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Вигляд"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Параметри кількома мовами"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Параметри вводу жестами"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Параметри"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Вигляд і макети"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Опції кількома мовами"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Введення тексту жестами"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Виправлення тексту"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Додатково"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Тема"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Інші методи введення"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Клавіша зміни мови дозволяє змінювати методи введення"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Клавіша зміни мови"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Ключ голосового вводу"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Способи голосового вводу не ввімкнено. Перейдіть у налаштування \"Мова та введення\"."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Налаштування методів введення"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Мови вводу"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Мови"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Довідка й відгуки"</string>
-    <string name="select_language" msgid="3693815588777926848">"Мови введення"</string>
+    <string name="select_language" msgid="5709487854987078367">"Мови"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Торкніться знову, щоб зберегти"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Торкніться тут, щоб зберегти"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Словник доступний"</string>
diff --git a/java/res/values-ur-rPK/strings.xml b/java/res/values-ur-rPK/strings.xml
index 2e8c9de..8bff975 100644
--- a/java/res/values-ur-rPK/strings.xml
+++ b/java/res/values-ur-rPK/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"کلید دبانے پر وائبریٹ کریں"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"کلید دبانے پر آواز"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"کلید دبانے پر پاپ اپ"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"ان پٹ کی ترجیحات"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"موجودگی"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"کثیر لسانی اختیارات"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"اشارہ ٹائپنگ کی ترجیحات"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"ترجیحات"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"ظہور اور لے آؤٹس"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"کثیر لسانی اختیارات"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"اشارہ جاتی ٹائپنگ"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"متن کی اصلاح"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"جدید ترین"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"تھیم"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"دیگر اندراج طریقوں پر سوئچ کریں"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"زبان سوئچ کرنے کی کلید اندراج کے دیگر طریقوں کا بھی احاطہ کرتی ہے"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"زبان سوئچ کرنے کی کلید"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"صوتی ان پٹ کلید"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"کوئی صوتی اندراج کے طریقے فعال نہیں ہیں۔ زبان اور ان پٹ ترتیبات کو چیک کریں۔"</string>
     <string name="configure_input_method" msgid="373356270290742459">"اندراج کے طریقے کنفیگر کریں"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"ان پٹ زبانیں"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"زبانیں"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"مدد اور تاثرات"</string>
-    <string name="select_language" msgid="3693815588777926848">"ان پٹ زبانیں"</string>
+    <string name="select_language" msgid="5709487854987078367">"زبانیں"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"محفوظ کرنے کیلئے دوبارہ ٹچ کریں"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"محفوظ کرنے کیلئے یہاں ٹچ کریں"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"لغت دستیاب ہے"</string>
diff --git a/java/res/values-uz-rUZ/strings.xml b/java/res/values-uz-rUZ/strings.xml
index 0eb2c16..152bbad 100644
--- a/java/res/values-uz-rUZ/strings.xml
+++ b/java/res/values-uz-rUZ/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Tugma bosilganda tebranish"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Tugma bosilganda ovoz"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Tugma bosilganda qalqib chiqish"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Matn kiritish sozlamalari"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Tashqi ko‘rinishi"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Ko‘p tilli tanlamalar"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Ishora b-n yozish soz-ri"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Shaxsiy sozlamalar"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Tashqi ko‘rinishi va joylashuvi"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Ko‘p tilli tanlamalar"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Imo-ishoralar bilan yozish"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Matnni tuzatish"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Qo‘shimcha"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Mavzu"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Boshqa usullarga o‘tish"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Tilni o‘zgartirish tugmasi matn kiritish usulini ham o‘zgartiradi"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Tilni o‘zgartirish tugmasi"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Ovoz bilan kiritish tugmasi"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ovoz bilan yozish usuli yoqilmagan. Til va matn kiritish sozlamalarini tekshiring."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Matn kiritish usullarini sozlash"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Matn kiritish tillari"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Tillar"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Yordam va fikr-mulohaza"</string>
-    <string name="select_language" msgid="3693815588777926848">"Matn kiritish tillari"</string>
+    <string name="select_language" msgid="5709487854987078367">"Tillar"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Saqlash uchun yana bosing"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Saqlash uchun bu yerga bosing"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Lug‘at mavjud"</string>
diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml
index 6447a2d..d5ec922 100644
--- a/java/res/values-vi/strings.xml
+++ b/java/res/values-vi/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Rung khi nhấn phím"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Âm thanh khi nhấn phím"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Cửa sổ bật lên khi nhấn phím"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Tùy chọn nhập"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Giao diện"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Tùy chọn đa ngôn ngữ"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Tùy chọn nhập bằng cử chỉ"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Tùy chọn"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Giao diện và bố cục"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Tùy chọn đa ngôn ngữ"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Nhập bằng cử chỉ"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Sửa văn bản"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Nâng cao"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Chủ đề"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Phương thức nhập khác"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Khóa chuyển ngôn ngữ bao gồm cả các phương thức nhập liệu khác"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Phím chuyển đổi ngôn ngữ"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Khóa nhập giọng nói"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Không có phương thức nhập bằng giọng nói nào được bật. Kiểm tra cài đặt Ngôn ngữ và phương thức nhập."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Định cấu hình phương thức nhập"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Ngôn ngữ nhập"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Ngôn ngữ"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Trợ giúp và phản hồi"</string>
-    <string name="select_language" msgid="3693815588777926848">"Ngôn ngữ nhập"</string>
+    <string name="select_language" msgid="5709487854987078367">"Ngôn ngữ"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Chạm lại để lưu"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Chạm vào đây để lưu"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Có sẵn từ điển"</string>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index df2acc7..901211c 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"按键振动"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"按键音效"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"按键时弹出显示字符"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"输入偏好设置"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"外观"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"多语言选项"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"滑行输入偏好设置"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"偏好设置"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"外观和布局"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"多语言选项"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"滑行输入"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"文字更正"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"高级"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"主题背景"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"切换到其他输入法"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"语言切换键也可用于切换其他输入法"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"语言切换键"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"语音输入键"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"未启用任何语音输入法。请检查“语言和输入法”设置。"</string>
     <string name="configure_input_method" msgid="373356270290742459">"配置输入法"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"输入语言"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"语言"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"帮助和反馈"</string>
-    <string name="select_language" msgid="3693815588777926848">"输入语言"</string>
+    <string name="select_language" msgid="5709487854987078367">"语言"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"再次触摸即可保存"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"触摸此处即可保存"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"有可用字典"</string>
diff --git a/java/res/values-zh-rHK/strings.xml b/java/res/values-zh-rHK/strings.xml
index 4a8ed69..e484345 100644
--- a/java/res/values-zh-rHK/strings.xml
+++ b/java/res/values-zh-rHK/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"按鍵時震動"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"按鍵時播放音效"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"按鍵時顯示彈出式視窗"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"輸入偏好設定"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"外觀"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"多語言選項"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"觸控輸入偏好設定"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"偏好設定"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"外觀和版面配置"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"多語選項"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"手勢輸入"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"文字更正"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"進階"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"主題背景"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"切換至其他輸入法"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"語言切換鍵包括其他輸入法"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"語言切換鍵"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"語音輸入鍵"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"尚未啟用語音輸入法,請檢查語言和輸入設定。"</string>
     <string name="configure_input_method" msgid="373356270290742459">"設定輸入法"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"輸入語言"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"語言"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"說明與意見反映"</string>
-    <string name="select_language" msgid="3693815588777926848">"輸入語言"</string>
+    <string name="select_language" msgid="5709487854987078367">"語言"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"再次輕觸即可儲存"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"輕觸即可儲存"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"可使用字典"</string>
@@ -140,8 +141,8 @@
     <string name="dictionary_settings_title" msgid="8091417676045693313">"附加字典"</string>
     <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"可使用字典"</string>
     <string name="dictionary_settings_summary" msgid="5305694987799824349">"字典設定"</string>
-    <string name="user_dictionaries" msgid="3582332055892252845">"用戶字典"</string>
-    <string name="default_user_dict_pref_name" msgid="1625055720489280530">"用戶字典"</string>
+    <string name="user_dictionaries" msgid="3582332055892252845">"使用者字典"</string>
+    <string name="default_user_dict_pref_name" msgid="1625055720489280530">"使用者字典"</string>
     <string name="dictionary_available" msgid="4728975345815214218">"可使用字典"</string>
     <string name="dictionary_downloading" msgid="2982650524622620983">"目前下載中"</string>
     <string name="dictionary_installed" msgid="8081558343559342962">"已安裝"</string>
@@ -179,7 +180,7 @@
     <string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"編輯字詞"</string>
     <string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"編輯"</string>
     <string name="user_dict_settings_context_menu_delete_title" msgid="8142932447689461181">"刪除"</string>
-    <string name="user_dict_settings_empty_text" msgid="558499587532668203">"您的用戶字典中沒有任何字詞。輕觸 [新增] (+) 按鈕即可新增字詞。"</string>
+    <string name="user_dict_settings_empty_text" msgid="558499587532668203">"您的使用者字典中沒有任何字詞。輕觸 [新增] (+) 按鈕即可新增字詞。"</string>
     <string name="user_dict_settings_all_languages" msgid="8276126583216298886">"所有語言"</string>
     <string name="user_dict_settings_more_languages" msgid="7131268499685180461">"更多語言..."</string>
     <string name="user_dict_settings_delete" msgid="110413335187193859">"刪除"</string>
diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index 120b8da..abd5c60 100644
--- a/java/res/values-zh-rTW/strings.xml
+++ b/java/res/values-zh-rTW/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"按鍵時震動"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"按鍵聲音"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"按鍵時彈出"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"輸入偏好設定"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"外觀"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"多語言選項"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"手勢輸入偏好設定"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"偏好設定"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"外觀與版面配置"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"多語選項"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"手勢輸入"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"文字修正"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"進階"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"主題"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"切換到其他輸入法"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"使語言切換鍵包含其他輸入法"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"語言切換鍵"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"語音輸入按鍵"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"尚未啟動語音輸入法,請檢查語言與輸入設定。"</string>
     <string name="configure_input_method" msgid="373356270290742459">"設定輸入法"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"輸入語言"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"語言"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"說明與意見回饋"</string>
-    <string name="select_language" msgid="3693815588777926848">"輸入語言"</string>
+    <string name="select_language" msgid="5709487854987078367">"語言"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"再次輕觸即可儲存"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"輕觸這裡即可儲存"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"可用的字典"</string>
diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml
index d65b02e..b9f40f6 100644
--- a/java/res/values-zu/strings.xml
+++ b/java/res/values-zu/strings.xml
@@ -26,12 +26,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Dlidlizelisa ngokucindezela inkinobho"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Umsindo wokucindezela ukhiye"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Ugaxekile ngokucindezela ukhiye"</string>
-    <string name="settings_screen_input" msgid="2808654300248306866">"Okuthandwayo kokokufaka"</string>
-    <string name="settings_screen_appearances" msgid="3611951947835553700">"Ukubonakala"</string>
-    <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"Izinketho zezilimi eziningi"</string>
-    <string name="settings_screen_gesture" msgid="9113437621722871665">"Okuthandwayo kokuthayipha kokuthinta"</string>
+    <string name="settings_screen_preferences" msgid="2696713156722014624">"Izintandokazi"</string>
+    <string name="settings_screen_appearance" msgid="9153102634339912029">"Ukubonakala nezakhiwo"</string>
+    <string name="settings_screen_multilingual" msgid="1391301621464509659">"Izinketho zezilimi eziningi"</string>
+    <string name="settings_screen_gesture" msgid="8826372746901183556">"Ukuthayipha ngokuthinta"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"Ukulungisa umbhalo"</string>
     <string name="settings_screen_advanced" msgid="7472408607625972994">"Okuthuthukisiwe"</string>
+    <string name="settings_screen_theme" msgid="2137262503543943871">"Itimu"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Shintshela kwezinye izindlela zokungena"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Ukhiye wokushintsha ulimi ubandakanya ezinye izindlela zokungenayo"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Ukhiye wokushintsha ullimi"</string>
@@ -74,9 +75,9 @@
     <string name="voice_input" msgid="3583258583521397548">"Inkinobho yokufaka izwi"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Azikho izindlela zokufaka zezwi ezinikwe amandla. Hlola izilungiselelo zolimi kanye nezokufaka."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Misa izindlela zokufakwayo"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"Izilimi zokufakwayo"</string>
+    <string name="language_selection_title" msgid="3666971864764478269">"Izilimi"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"Usizo nempendulo"</string>
-    <string name="select_language" msgid="3693815588777926848">"Izilimi zokufakwayo"</string>
+    <string name="select_language" msgid="5709487854987078367">"Izilimi"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Thinta futhi ukuze ulondoloze"</string>
     <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"Thinta lapha ukuze ulondoloze"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Isichazamazwi siyatholakala"</string>
diff --git a/java/res/values/donottranslate-text-decorator.xml b/java/res/values/donottranslate-text-decorator.xml
index 832610b..2693645 100644
--- a/java/res/values/donottranslate-text-decorator.xml
+++ b/java/res/values/donottranslate-text-decorator.xml
@@ -19,62 +19,11 @@
 -->
 
 <resources>
-    <!-- The delay time in milliseconds from to show the commit indicator -->
-    <integer name="text_decorator_delay_in_milliseconds_to_show_commit_indicator">
-        500
-    </integer>
-
     <!-- The extra margin in dp around the hit area of the commit/add-to-dictionary indicator -->
     <integer name="text_decorator_hit_area_margin_in_dp">
         4
     </integer>
 
-    <!-- If true, the commit/add-to-text indicator will be suppressed when the word isn't going to
-         trigger auto-correction. -->
-    <bool name="text_decorator_only_for_auto_correction">true</bool>
-
-    <!-- If true, the commit/add-to-text indicator will be suppressed when the word is already in
-         the dictionary. -->
-    <bool name="text_decorator_only_for_out_of_vocabulary">false</bool>
-
-    <!-- Background color to be used to highlight the target text when the commit indicator is
-         visible. -->
-    <color name="text_decorator_commit_indicator_text_highlight_color">
-        #B6E2DE
-    </color>
-
-    <!-- Background color of the commit indicator. -->
-    <color name="text_decorator_commit_indicator_background_color">
-        #48B6AC
-    </color>
-
-    <!-- Foreground color of the commit indicator. -->
-    <color name="text_decorator_commit_indicator_foreground_color">
-        #FFFFFF
-    </color>
-
-    <!-- Viewport size of "text_decorator_commit_indicator_path". -->
-    <integer name="text_decorator_commit_indicator_path_size">
-        480
-    </integer>
-
-    <!-- Coordinates of the closed path to be used to render the commit indicator.
-         The format is:  X[0], Y[0], X[1], Y[1], ..., X[N-1], Y[N-1] -->
-    <integer-array name="text_decorator_commit_indicator_path">
-        <item>180</item>
-        <item>323</item>
-        <item>97</item>
-        <item>240</item>
-        <item>68</item>
-        <item>268</item>
-        <item>180</item>
-        <item>380</item>
-        <item>420</item>
-        <item>140</item>
-        <item>392</item>
-        <item>112</item>
-    </integer-array>
-
     <!-- Background color to be used to highlight the target text when the add-to-dictionary
          indicator is visible. -->
     <color name="text_decorator_add_to_dictionary_indicator_text_highlight_color">
diff --git a/java/res/values/keyboard-themes.xml b/java/res/values/keyboard-themes.xml
index 9d772c4..b0bae96 100644
--- a/java/res/values/keyboard-themes.xml
+++ b/java/res/values/keyboard-themes.xml
@@ -26,10 +26,10 @@
         <item>@string/keyboard_theme_holo_blue</item>
     </string-array>
     <!-- An element must be a keyboard theme id of {@link KeyboardTheme#THEME_ID_*}. -->
-    <string-array name="keyboard_theme_ids" translatable="false">
+    <integer-array name="keyboard_theme_ids" translatable="false">
         <item>3</item>
         <item>4</item>
         <item>2</item>
         <item>0</item>
-    </string-array>
+    </integer-array>
 </resources>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index e5341f6..d64444e 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -38,6 +38,8 @@
 
     <!-- Settings screen title for preferences [CHAR LIMIT=33]-->
     <string name="settings_screen_preferences">Preferences</string>
+    <!-- Settings screen title for accounts and privacy preferences [CHAR LIMIT=33]-->
+    <string name="settings_screen_accounts">Accounts &amp; privacy</string>
     <!-- Settings screen title for appearance & layouts preferences [CHAR LIMIT=33] -->
     <string name="settings_screen_appearance">Appearance &amp; layouts</string>
     <!-- Settings screen title for multilingual options [CHAR_LIMIT=33] -->
@@ -51,6 +53,9 @@
     <!-- Settings screen title for keyboard theme settings [CHAR LIMIT=33] -->
     <string name="settings_screen_theme">Theme</string>
 
+    <!--  Option for enabling or disabling the split keyboard layout. [CHAR LIMIT=65]-->
+    <string name="enable_split_keyboard">Enable split keyboard</string>
+
     <!-- Option name for including other IMEs in the language switch list [CHAR LIMIT=30] -->
     <string name="include_other_imes_in_language_switch_list">Switch to other input methods</string>
     <!-- Option summary for including other IMEs in the language switch list [CHAR LIMIT=65] -->
@@ -174,6 +179,23 @@
     <!-- Title of the item to change the keyboard theme [CHAR LIMIT=20]-->
     <string name="keyboard_layout">Keyboard theme</string>
 
+    <!-- Title of the preference item for switching accounts [CHAR LIMIT=30] -->
+    <string name="switch_accounts">Switch accounts</string>
+    <!-- Summary of the preference item for switching accounts when no accounts
+         are selected [CHAR LIMIT=65] -->
+    <string name="no_accounts_selected">No accounts selected</string>
+    <!-- Summary of the preference item for switching accounts when an account
+         is selected [CHAR LIMIT=65] -->
+    <string name="account_selected">Currently using <xliff:g id="EMAIL_ADDRESS" example="someone@example.com">%1$s</xliff:g></string>
+    <!-- Positive text for selecting an account -->
+    <string name="account_select_ok">OK</string>
+    <!-- Negative text for selecting an account -->
+    <string name="account_select_cancel">Cancel</string>
+    <!-- Text for signing out of an account -->
+    <string name="account_select_sign_out">Sign out</string>
+    <!-- Title of the account picker dialog for selecting an account [CHAR LIMIT=40] -->
+    <string name="account_select_title">Select an account to use</string>
+
     <!-- Description for English (UK) keyboard subtype [CHAR LIMIT=25]
          (UK) should be an abbreviation of United Kingdom to fit in the CHAR LIMIT. -->
     <string name="subtype_en_GB">English (UK)</string>
diff --git a/java/res/xml/keyboard_layout_set_qwerty.xml b/java/res/xml/keyboard_layout_set_qwerty.xml
index 1aa6f01..7c9a140 100644
--- a/java/res/xml/keyboard_layout_set_qwerty.xml
+++ b/java/res/xml/keyboard_layout_set_qwerty.xml
@@ -24,7 +24,7 @@
         latin:elementName="alphabet"
         latin:elementKeyboard="@xml/kbd_qwerty"
         latin:enableProximityCharsCorrection="true"
-        latin:supportsSplitLayout="false" />
+        latin:supportsSplitLayout="true" />
     <Element
         latin:elementName="symbols"
         latin:elementKeyboard="@xml/kbd_symbols" />
diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml
index c14cd64..2a5134d 100644
--- a/java/res/xml/prefs.xml
+++ b/java/res/xml/prefs.xml
@@ -23,6 +23,10 @@
         android:title="@string/settings_screen_preferences"
         android:key="screen_preferences" />
     <PreferenceScreen
+        android:fragment="com.android.inputmethod.latin.settings.AccountsSettingsFragment"
+        android:title="@string/settings_screen_accounts"
+        android:key="screen_accounts" />
+    <PreferenceScreen
         android:fragment="com.android.inputmethod.latin.settings.AppearanceSettingsFragment"
         android:title="@string/settings_screen_appearance"
         android:key="screen_appearance" />
diff --git a/java/res/xml/prefs_screen_accounts.xml b/java/res/xml/prefs_screen_accounts.xml
new file mode 100644
index 0000000..b5d526a
--- /dev/null
+++ b/java/res/xml/prefs_screen_accounts.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    android:title="@string/settings_screen_accounts">
+
+    <!-- This preference is a dummy view of the underlying preference.
+         This isn't persisted and the summary/title is refreshed by the fragment
+         after inspecting the underlying account preference. -->
+    <Preference
+        android:key="account_switcher"
+        android:persistent="false"
+        android:title="@string/switch_accounts"
+        android:summary="@string/no_accounts_selected" />
+
+    <!-- title will be set programmatically to embed application name -->
+    <CheckBoxPreference
+        android:key="pref_enable_metrics_logging"
+        android:summary="@string/enable_metrics_logging_summary"
+        android:defaultValue="true"
+        android:persistent="true" />
+</PreferenceScreen>
diff --git a/java/res/xml/prefs_screen_appearance.xml b/java/res/xml/prefs_screen_appearance.xml
index 7719c05..036b665 100644
--- a/java/res/xml/prefs_screen_appearance.xml
+++ b/java/res/xml/prefs_screen_appearance.xml
@@ -26,4 +26,9 @@
         android:fragment="com.android.inputmethod.latin.settings.CustomInputStyleSettingsFragment"
         android:key="custom_input_styles"
         android:title="@string/custom_input_styles_title" />
+    <CheckBoxPreference
+        android:key="pref_split_keyboard"
+        android:title="@string/enable_split_keyboard"
+        android:persistent="true"
+        android:defaultValue="false" />
 </PreferenceScreen>
diff --git a/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java b/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java
index 8a28185..c937eee 100644
--- a/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java
@@ -41,6 +41,8 @@
 
     // Note that CursorAnchorInfo has been introduced in API level XX (Build.VERSION_CODE.LXX).
     private static final CompatUtils.ClassWrapper sCursorAnchorInfoClass;
+    private static final CompatUtils.ToIntMethodWrapper sGetSelectionStartMethod;
+    private static final CompatUtils.ToIntMethodWrapper sGetSelectionEndMethod;
     private static final CompatUtils.ToObjectMethodWrapper<RectF> sGetCharacterBoundsMethod;
     private static final CompatUtils.ToIntMethodWrapper sGetCharacterBoundsFlagsMethod;
     private static final CompatUtils.ToObjectMethodWrapper<CharSequence> sGetComposingTextMethod;
@@ -52,10 +54,14 @@
     private static final CompatUtils.ToObjectMethodWrapper<Matrix> sGetMatrixMethod;
     private static final CompatUtils.ToIntMethodWrapper sGetInsertionMarkerFlagsMethod;
 
-    private static int COMPOSING_TEXT_START_DEFAULT = -1;
+    private static int INVALID_TEXT_INDEX = -1;
     static {
         sCursorAnchorInfoClass = CompatUtils.getClassWrapper(
                 "android.view.inputmethod.CursorAnchorInfo");
+        sGetSelectionStartMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
+                "getSelectionStart", INVALID_TEXT_INDEX);
+        sGetSelectionEndMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
+                "getSelectionEnd", INVALID_TEXT_INDEX);
         sGetCharacterBoundsMethod = sCursorAnchorInfoClass.getMethod(
                 "getCharacterBounds", (RectF)null, int.class);
         sGetCharacterBoundsFlagsMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
@@ -63,7 +69,7 @@
         sGetComposingTextMethod = sCursorAnchorInfoClass.getMethod(
                 "getComposingText", (CharSequence)null);
         sGetComposingTextStartMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
-                "getComposingTextStart", COMPOSING_TEXT_START_DEFAULT);
+                "getComposingTextStart", INVALID_TEXT_INDEX);
         sGetInsertionMarkerBaselineMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
                 "getInsertionMarkerBaseline", 0.0f);
         sGetInsertionMarkerBottomMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
@@ -105,6 +111,14 @@
         return FakeHolder.sInstance;
     }
 
+    public int getSelectionStart() {
+        return sGetSelectionStartMethod.invoke(mInstance);
+    }
+
+    public int getSelectionEnd() {
+        return sGetSelectionEndMethod.invoke(mInstance);
+    }
+
     public CharSequence getComposingText() {
         return sGetComposingTextMethod.invoke(mInstance);
     }
diff --git a/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java b/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java
index 75cc7d4..3dbbc9b 100644
--- a/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java
+++ b/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java
@@ -54,15 +54,13 @@
             if (null != mDownloadManager) {
                 mDownloadManager.remove(ids);
             }
+        } catch (IllegalArgumentException e) {
+            // This is expected to happen on boot when the device is encrypted.
         } catch (SQLiteException e) {
             // We couldn't remove the file from DownloadManager. Apparently, the database can't
             // be opened. It may be a problem with file system corruption. In any case, there is
             // not much we can do apart from avoiding crashing.
             Log.e(TAG, "Can't remove files with ID " + ids + " from download manager", e);
-        } catch (IllegalArgumentException e) {
-            // Not sure how this can happen, but it could be another case where the provider
-            // is disabled. Or it could be a bug in older versions of the framework.
-            Log.e(TAG, "Can't find the content URL for DownloadManager?", e);
         }
     }
 
@@ -71,10 +69,10 @@
             if (null != mDownloadManager) {
                 return mDownloadManager.openDownloadedFile(fileId);
             }
+        } catch (IllegalArgumentException e) {
+            // This is expected to happen on boot when the device is encrypted.
         } catch (SQLiteException e) {
             Log.e(TAG, "Can't open downloaded file with ID " + fileId, e);
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "Can't find the content URL for DownloadManager?", e);
         }
         // We come here if mDownloadManager is null or if an exception was thrown.
         throw new FileNotFoundException();
@@ -85,10 +83,10 @@
             if (null != mDownloadManager) {
                 return mDownloadManager.query(query);
             }
+        } catch (IllegalArgumentException e) {
+            // This is expected to happen on boot when the device is encrypted.
         } catch (SQLiteException e) {
             Log.e(TAG, "Can't query the download manager", e);
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "Can't find the content URL for DownloadManager?", e);
         }
         // We come here if mDownloadManager is null or if an exception was thrown.
         return null;
@@ -99,10 +97,10 @@
             if (null != mDownloadManager) {
                 return mDownloadManager.enqueue(request);
             }
+        } catch (IllegalArgumentException e) {
+            // This is expected to happen on boot when the device is encrypted.
         } catch (SQLiteException e) {
             Log.e(TAG, "Can't enqueue a request with the download manager", e);
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "Can't find the content URL for DownloadManager?", e);
         }
         return 0;
     }
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index bd1c147..863a8b7 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -98,6 +98,16 @@
     private final int mWidth;
     /** Height of the key, excluding the gap */
     private final int mHeight;
+    /**
+     * The combined width in pixels of the horizontal gaps belonging to this key, both to the left
+     * and to the right. I.e., mWidth + mHorizontalGap = total width belonging to the key.
+     */
+    private final int mHorizontalGap;
+    /**
+     * The combined height in pixels of the vertical gaps belonging to this key, both above and
+     * below. I.e., mHeight + mVerticalGap = total height belonging to the key.
+     */
+    private final int mVerticalGap;
     /** X coordinate of the top-left corner of the key in the keyboard layout, excluding the gap. */
     private final int mX;
     /** Y coordinate of the top-left corner of the key in the keyboard layout, excluding the gap. */
@@ -198,8 +208,10 @@
             final String hintLabel, final int labelFlags, final int backgroundType, final int x,
             final int y, final int width, final int height, final int horizontalGap,
             final int verticalGap) {
-        mHeight = height - verticalGap;
         mWidth = width - horizontalGap;
+        mHeight = height - verticalGap;
+        mHorizontalGap = horizontalGap;
+        mVerticalGap = verticalGap;
         mHintLabel = hintLabel;
         mLabelFlags = labelFlags;
         mBackgroundType = backgroundType;
@@ -214,7 +226,7 @@
         mEnabled = (code != CODE_UNSPECIFIED);
         mIconId = iconId;
         // Horizontal gap is divided equally to both sides of the key.
-        mX = x + horizontalGap / 2;
+        mX = x + mHorizontalGap / 2;
         mY = y;
         mHitBox.set(x, y, x + width + 1, y + height);
         mKeyVisualAttributes = null;
@@ -235,18 +247,21 @@
      */
     public Key(final String keySpec, final TypedArray keyAttr, final KeyStyle style,
             final KeyboardParams params, final KeyboardRow row) {
-        final float horizontalGap = isSpacer() ? 0 : params.mHorizontalGap;
+        mHorizontalGap = isSpacer() ? 0 : params.mHorizontalGap;
+        mVerticalGap = params.mVerticalGap;
+
+        final float horizontalGapFloat = mHorizontalGap;
         final int rowHeight = row.getRowHeight();
-        mHeight = rowHeight - params.mVerticalGap;
+        mHeight = rowHeight - mVerticalGap;
 
         final float keyXPos = row.getKeyX(keyAttr);
         final float keyWidth = row.getKeyWidth(keyAttr, keyXPos);
         final int keyYPos = row.getKeyY();
 
         // Horizontal gap is divided equally to both sides of the key.
-        mX = Math.round(keyXPos + horizontalGap / 2);
+        mX = Math.round(keyXPos + horizontalGapFloat / 2);
         mY = keyYPos;
-        mWidth = Math.round(keyWidth - horizontalGap);
+        mWidth = Math.round(keyWidth - horizontalGapFloat);
         mHitBox.set(Math.round(keyXPos), keyYPos, Math.round(keyXPos + keyWidth) + 1,
                 keyYPos + rowHeight);
         // Update row to have current x coordinate.
@@ -388,6 +403,8 @@
         mIconId = key.mIconId;
         mWidth = key.mWidth;
         mHeight = key.mHeight;
+        mHorizontalGap = key.mHorizontalGap;
+        mVerticalGap = key.mVerticalGap;
         mX = key.mX;
         mY = key.mY;
         mHitBox.set(key.mHitBox);
@@ -702,6 +719,10 @@
         return ((mLabelFlags | defaultFlags) & LABEL_FLAGS_KEEP_BACKGROUND_ASPECT_RATIO) != 0;
     }
 
+    public final boolean hasCustomActionLabel() {
+        return (mLabelFlags & LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL) != 0;
+    }
+
     private final boolean isShiftedLetterActivated() {
         return (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) != 0
                 && !TextUtils.isEmpty(mHintLabel);
@@ -784,6 +805,24 @@
     }
 
     /**
+     * The combined width in pixels of the horizontal gaps belonging to this key, both above and
+     * below. I.e., getWidth() + getHorizontalGap() = total width belonging to the key.
+     * @return Horizontal gap belonging to this key.
+     */
+    public int getHorizontalGap() {
+        return mHorizontalGap;
+    }
+
+    /**
+     * The combined height in pixels of the vertical gaps belonging to this key, both above and
+     * below. I.e., getHeight() + getVerticalGap() = total height belonging to the key.
+     * @return Vertical gap belonging to this key.
+     */
+    public int getVerticalGap() {
+        return mVerticalGap;
+    }
+
+    /**
      * Gets the x-coordinate of the top-left corner of the key in pixels, excluding the gap.
      * @return The x-coordinate of the top-left corner of the key in pixels, excluding the gap.
      */
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index 43c6144..f9cf353 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -77,8 +77,7 @@
 
     private final int mHashCode;
 
-    public KeyboardId(final int elementId, final KeyboardLayoutSet.Params params,
-        boolean isSplitLayout) {
+    public KeyboardId(final int elementId, final KeyboardLayoutSet.Params params) {
         mSubtype = params.mSubtype;
         mLocale = SubtypeLocaleUtils.getSubtypeLocale(mSubtype);
         mWidth = params.mKeyboardWidth;
@@ -91,7 +90,7 @@
         mCustomActionLabel = (mEditorInfo.actionLabel != null)
                 ? mEditorInfo.actionLabel.toString() : null;
         mHasShortcutKey = params.mVoiceInputKeyEnabled;
-        mIsSplitLayout = isSplitLayout;
+        mIsSplitLayout = params.mIsSplitLayoutEnabled;
 
         mHashCode = computeHashCode(this);
     }
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index 1dbecdc..47fb7b3 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -115,6 +115,12 @@
         int mKeyboardWidth;
         int mKeyboardHeight;
         int mScriptId = ScriptUtils.SCRIPT_LATIN;
+        // Indicates if the user has enabled the split-layout preference
+        // and the required ProductionFlags are enabled.
+        boolean mIsSplitLayoutEnabledByUser;
+        // Indicates if split layout is actually enabled, taking into account
+        // whether the user has enabled it, and the keyboard layout supports it.
+        boolean mIsSplitLayoutEnabled;
         // Sparse array of KeyboardLayoutSet element parameters indexed by element's id.
         final SparseArray<ElementParams> mKeyboardLayoutSetElementIdToParamsMap =
                 new SparseArray<>();
@@ -170,9 +176,9 @@
         // specified as an elementKeyboard attribute in the file.
         // The KeyboardId is an internal key for a Keyboard object.
 
-        // TODO: AND mSupportsSplitLayout with the user preference that forces a split.
-        final KeyboardId id = new KeyboardId(keyboardLayoutSetElementId, mParams,
-                elementParams.mSupportsSplitLayout);
+        mParams.mIsSplitLayoutEnabled = mParams.mIsSplitLayoutEnabledByUser
+                && elementParams.mSupportsSplitLayout;
+        final KeyboardId id = new KeyboardId(keyboardLayoutSetElementId, mParams);
         try {
             return getKeyboard(elementParams, id);
         } catch (final RuntimeException e) {
@@ -290,12 +296,19 @@
             return this;
         }
 
-        public void disableTouchPositionCorrectionData() {
+        public Builder disableTouchPositionCorrectionData() {
             mParams.mDisableTouchPositionCorrectionDataForTest = true;
+            return this;
         }
 
-        public void setScriptId(final int scriptId) {
+        public Builder setScriptId(final int scriptId) {
             mParams.mScriptId = scriptId;
+            return this;
+        }
+
+        public Builder setSplitLayoutEnabledByUser(final boolean enabled) {
+            mParams.mIsSplitLayoutEnabledByUser = enabled;
+            return this;
         }
 
         public KeyboardLayoutSet build() {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index d36c199..246d11b 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -17,9 +17,7 @@
 package com.android.inputmethod.keyboard;
 
 import android.content.Context;
-import android.content.SharedPreferences;
 import android.content.res.Resources;
-import android.preference.PreferenceManager;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
@@ -38,6 +36,7 @@
 import com.android.inputmethod.latin.RichInputMethodManager;
 import com.android.inputmethod.latin.SubtypeSwitcher;
 import com.android.inputmethod.latin.WordComposer;
+import com.android.inputmethod.latin.define.ProductionFlags;
 import com.android.inputmethod.latin.settings.Settings;
 import com.android.inputmethod.latin.settings.SettingsValues;
 import com.android.inputmethod.latin.utils.ResourceUtils;
@@ -47,7 +46,6 @@
     private static final String TAG = KeyboardSwitcher.class.getSimpleName();
 
     private SubtypeSwitcher mSubtypeSwitcher;
-    private SharedPreferences mPrefs;
 
     private InputView mCurrentInputView;
     private View mMainKeyboardFrame;
@@ -76,13 +74,11 @@
     }
 
     public static void init(final LatinIME latinIme) {
-        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(latinIme);
-        sInstance.initInternal(latinIme, prefs);
+        sInstance.initInternal(latinIme);
     }
 
-    private void initInternal(final LatinIME latinIme, final SharedPreferences prefs) {
+    private void initInternal(final LatinIME latinIme) {
         mLatinIME = latinIme;
-        mPrefs = prefs;
         mSubtypeSwitcher = SubtypeSwitcher.getInstance();
         mState = new KeyboardState(this);
         mIsHardwareAcceleratedDrawingEnabled =
@@ -91,7 +87,7 @@
 
     public void updateKeyboardTheme() {
         final boolean themeUpdated = updateKeyboardThemeAndContextThemeWrapper(
-                mLatinIME, KeyboardTheme.getKeyboardTheme(mPrefs));
+                mLatinIME, KeyboardTheme.getKeyboardTheme(mLatinIME /* context */));
         if (themeUpdated && mKeyboardView != null) {
             mLatinIME.setInputView(onCreateInputView(mIsHardwareAcceleratedDrawingEnabled));
         }
@@ -119,6 +115,8 @@
         builder.setSubtype(mSubtypeSwitcher.getCurrentSubtype());
         builder.setVoiceInputKeyEnabled(settingsValues.mShowsVoiceInputKey);
         builder.setLanguageSwitchKeyEnabled(mLatinIME.shouldShowLanguageSwitchKey());
+        builder.setSplitLayoutEnabledByUser(ProductionFlags.IS_SPLIT_KEYBOARD_SUPPORTED
+                && settingsValues.mIsSplitKeyboardEnabled);
         mKeyboardLayoutSet = builder.build();
         try {
             mState.onLoadKeyboard(currentAutoCapsState, currentRecapitalizeState);
@@ -348,7 +346,7 @@
         }
 
         updateKeyboardThemeAndContextThemeWrapper(
-                mLatinIME, KeyboardTheme.getKeyboardTheme(mPrefs));
+                mLatinIME, KeyboardTheme.getKeyboardTheme(mLatinIME /* context */));
         mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(
                 R.layout.input_view, null);
         mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
index 7161d3f..6d8c8b7 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
@@ -16,14 +16,17 @@
 
 package com.android.inputmethod.keyboard;
 
+import android.content.Context;
 import android.content.SharedPreferences;
 import android.os.Build.VERSION_CODES;
+import android.preference.PreferenceManager;
 import android.util.Log;
 
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.compat.BuildCompatUtils;
 import com.android.inputmethod.latin.R;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 
 public final class KeyboardTheme implements Comparable<KeyboardTheme> {
@@ -40,7 +43,10 @@
     public static final int THEME_ID_LXX_DARK = 4;
     public static final int DEFAULT_THEME_ID = THEME_ID_KLP;
 
-    private static final KeyboardTheme[] KEYBOARD_THEMES = {
+    private static KeyboardTheme[] AVAILABLE_KEYBOARD_THEMES;
+
+    @UsedForTesting
+    static final KeyboardTheme[] KEYBOARD_THEMES = {
         new KeyboardTheme(THEME_ID_ICS, "ICS", R.style.KeyboardTheme_ICS,
                 // This has never been selected because we support ICS or later.
                 VERSION_CODES.BASE),
@@ -93,9 +99,10 @@
     }
 
     @UsedForTesting
-    static KeyboardTheme searchKeyboardThemeById(final int themeId) {
+    static KeyboardTheme searchKeyboardThemeById(final int themeId,
+            final KeyboardTheme[] availableThemeIds) {
         // TODO: This search algorithm isn't optimal if there are many themes.
-        for (final KeyboardTheme theme : KEYBOARD_THEMES) {
+        for (final KeyboardTheme theme : availableThemeIds) {
             if (theme.mThemeId == themeId) {
                 return theme;
             }
@@ -105,13 +112,14 @@
 
     @UsedForTesting
     static KeyboardTheme getDefaultKeyboardTheme(final SharedPreferences prefs,
-            final int sdkVersion) {
+            final int sdkVersion, final KeyboardTheme[] availableThemeArray) {
         final String klpThemeIdString = prefs.getString(KLP_KEYBOARD_THEME_KEY, null);
         if (klpThemeIdString != null) {
             if (sdkVersion <= VERSION_CODES.KITKAT) {
                 try {
                     final int themeId = Integer.parseInt(klpThemeIdString);
-                    final KeyboardTheme theme = searchKeyboardThemeById(themeId);
+                    final KeyboardTheme theme = searchKeyboardThemeById(themeId,
+                            availableThemeArray);
                     if (theme != null) {
                         return theme;
                     }
@@ -125,22 +133,21 @@
             prefs.edit().remove(KLP_KEYBOARD_THEME_KEY).apply();
         }
         // TODO: This search algorithm isn't optimal if there are many themes.
-        for (final KeyboardTheme theme : KEYBOARD_THEMES) {
+        for (final KeyboardTheme theme : availableThemeArray) {
             if (sdkVersion >= theme.mMinApiVersion) {
                 return theme;
             }
         }
-        return searchKeyboardThemeById(DEFAULT_THEME_ID);
+        return searchKeyboardThemeById(DEFAULT_THEME_ID, availableThemeArray);
     }
 
     public static String getKeyboardThemeName(final int themeId) {
-        final KeyboardTheme theme = searchKeyboardThemeById(themeId);
+        final KeyboardTheme theme = searchKeyboardThemeById(themeId, KEYBOARD_THEMES);
         return theme.mThemeName;
     }
 
-    public static void saveKeyboardThemeId(final String themeIdString,
-            final SharedPreferences prefs) {
-        saveKeyboardThemeId(themeIdString, prefs, BuildCompatUtils.EFFECTIVE_SDK_INT);
+    public static void saveKeyboardThemeId(final int themeId, final SharedPreferences prefs) {
+        saveKeyboardThemeId(themeId, prefs, BuildCompatUtils.EFFECTIVE_SDK_INT);
     }
 
     @UsedForTesting
@@ -152,25 +159,45 @@
     }
 
     @UsedForTesting
-    static void saveKeyboardThemeId(final String themeIdString,
-            final SharedPreferences prefs, final int sdkVersion) {
+    static void saveKeyboardThemeId(final int themeId, final SharedPreferences prefs,
+            final int sdkVersion) {
         final String prefKey = getPreferenceKey(sdkVersion);
-        prefs.edit().putString(prefKey, themeIdString).apply();
+        prefs.edit().putString(prefKey, Integer.toString(themeId)).apply();
     }
 
-    public static KeyboardTheme getKeyboardTheme(final SharedPreferences prefs) {
-        return getKeyboardTheme(prefs, BuildCompatUtils.EFFECTIVE_SDK_INT);
+    public static KeyboardTheme getKeyboardTheme(final Context context) {
+        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        final KeyboardTheme[] availableThemeArray = getAvailableThemeArray(context);
+        return getKeyboardTheme(prefs, BuildCompatUtils.EFFECTIVE_SDK_INT, availableThemeArray);
+    }
+
+    static KeyboardTheme[] getAvailableThemeArray(final Context context) {
+        if (AVAILABLE_KEYBOARD_THEMES == null) {
+            final int[] availableThemeIdStringArray = context.getResources().getIntArray(
+                    R.array.keyboard_theme_ids);
+            final ArrayList<KeyboardTheme> availableThemeList = new ArrayList<>();
+            for (final int id : availableThemeIdStringArray) {
+                final KeyboardTheme theme = searchKeyboardThemeById(id, KEYBOARD_THEMES);
+                if (theme != null) {
+                    availableThemeList.add(theme);
+                }
+            }
+            AVAILABLE_KEYBOARD_THEMES = availableThemeList.toArray(
+                    new KeyboardTheme[availableThemeList.size()]);
+        }
+        return AVAILABLE_KEYBOARD_THEMES;
     }
 
     @UsedForTesting
-    static KeyboardTheme getKeyboardTheme(final SharedPreferences prefs, final int sdkVersion) {
+    static KeyboardTheme getKeyboardTheme(final SharedPreferences prefs, final int sdkVersion,
+            final KeyboardTheme[] availableThemeArray) {
         final String lxxThemeIdString = prefs.getString(LXX_KEYBOARD_THEME_KEY, null);
         if (lxxThemeIdString == null) {
-            return getDefaultKeyboardTheme(prefs, sdkVersion);
+            return getDefaultKeyboardTheme(prefs, sdkVersion, availableThemeArray);
         }
         try {
             final int themeId = Integer.parseInt(lxxThemeIdString);
-            final KeyboardTheme theme = searchKeyboardThemeById(themeId);
+            final KeyboardTheme theme = searchKeyboardThemeById(themeId, availableThemeArray);
             if (theme != null) {
                 return theme;
             }
@@ -180,6 +207,6 @@
         }
         // Remove preference that contains unknown or illegal theme id.
         prefs.edit().remove(LXX_KEYBOARD_THEME_KEY).apply();
-        return getDefaultKeyboardTheme(prefs, sdkVersion);
+        return getDefaultKeyboardTheme(prefs, sdkVersion, availableThemeArray);
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index bb3cbb0..98cd1da 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -343,7 +343,9 @@
         final int keyWidth = key.getDrawWidth();
         final int keyHeight = key.getHeight();
         final int bgWidth, bgHeight, bgX, bgY;
-        if (key.needsToKeepBackgroundAspectRatio(mDefaultKeyLabelFlags)) {
+        if (key.needsToKeepBackgroundAspectRatio(mDefaultKeyLabelFlags)
+                // HACK: To disable expanding normal/functional key background.
+                && !key.hasCustomActionLabel()) {
             final int intrinsicWidth = background.getIntrinsicWidth();
             final int intrinsicHeight = background.getIntrinsicHeight();
             final float minScale = Math.min(
diff --git a/java/src/com/android/inputmethod/keyboard/TextDecorator.java b/java/src/com/android/inputmethod/keyboard/TextDecorator.java
index f614b22..315d363 100644
--- a/java/src/com/android/inputmethod/keyboard/TextDecorator.java
+++ b/java/src/com/android/inputmethod/keyboard/TextDecorator.java
@@ -17,23 +17,22 @@
 package com.android.inputmethod.keyboard;
 
 import android.graphics.Matrix;
-import android.graphics.PointF;
 import android.graphics.RectF;
 import android.inputmethodservice.InputMethodService;
 import android.os.Message;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
+import android.view.inputmethod.CursorAnchorInfo;
 
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper;
-import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper;
 
 import javax.annotation.Nonnull;
 
 /**
- * A controller class of commit/add-to-dictionary indicator (a.k.a. TextDecorator). This class
+ * A controller class of the add-to-dictionary indicator (a.k.a. TextDecorator). This class
  * is designed to be independent of UI subsystems such as {@link View}. All the UI related
  * operations are delegated to {@link TextDecoratorUi} via {@link TextDecoratorUiOperator}.
  */
@@ -41,18 +40,22 @@
     private static final String TAG = TextDecorator.class.getSimpleName();
     private static final boolean DEBUG = false;
 
-    private static final int MODE_NONE = 0;
-    private static final int MODE_COMMIT = 1;
-    private static final int MODE_ADD_TO_DICTIONARY = 2;
+    private static final int INVALID_CURSOR_INDEX = -1;
 
-    private int mMode = MODE_NONE;
+    private static final int MODE_MONITOR = 0;
+    private static final int MODE_WAITING_CURSOR_INDEX = 1;
+    private static final int MODE_SHOWING_INDICATOR = 2;
 
-    private final PointF mLocalOrigin = new PointF();
-    private final RectF mRelativeIndicatorBounds = new RectF();
-    private final RectF mRelativeComposingTextBounds = new RectF();
+    private int mMode = MODE_MONITOR;
+
+    private String mLastComposingText = null;
+    private RectF mIndicatorBoundsForLastComposingText = new RectF();
+    private RectF mComposingTextBoundsForLastComposingText = new RectF();
 
     private boolean mIsFullScreenMode = false;
-    private SuggestedWordInfo mWaitingWord = null;
+    private String mWaitingWord = null;
+    private int mWaitingCursorStart = INVALID_CURSOR_INDEX;
+    private int mWaitingCursorEnd = INVALID_CURSOR_INDEX;
     private CursorAnchorInfoCompatWrapper mCursorAnchorInfoWrapper = null;
 
     @Nonnull
@@ -63,16 +66,10 @@
 
     public interface Listener {
         /**
-         * Called when the user clicks the composing text to commit.
-         * @param wordInfo the suggested word which the user clicked on.
+         * Called when the user clicks the indicator to add the word into the dictionary.
+         * @param word the word which the user clicked on.
          */
-        void onClickComposingTextToCommit(final SuggestedWordInfo wordInfo);
-
-        /**
-         * Called when the user clicks the composing text to add the word into the dictionary.
-         * @param wordInfo the suggested word which the user clicked on.
-         */
-        void onClickComposingTextToAddToDictionary(final SuggestedWordInfo wordInfo);
+        void onClickComposingTextToAddToDictionary(final String word);
     }
 
     public TextDecorator(final Listener listener) {
@@ -103,46 +100,19 @@
     }
 
     /**
-     * Shows the "Commit" indicator and associates it with the given suggested word.
+     * Shows the "Add to dictionary" indicator and associates it with associating the given word.
      *
-     * <p>The effect of {@link #showCommitIndicator(SuggestedWordInfo)} and
-     * {@link #showAddToDictionaryIndicator(SuggestedWordInfo)} are exclusive to each other. Call
-     * {@link #reset()} to hide the indicator.</p>
-     *
-     * @param wordInfo the suggested word which should be associated with the indicator. This object
-     * will be passed back in {@link Listener#onClickComposingTextToCommit(SuggestedWordInfo)}
+     * @param word the word which should be associated with the indicator. This object will be
+     * passed back in {@link Listener#onClickComposingTextToAddToDictionary(String)}.
+     * @param selectionStart the cursor index (inclusive) when the indicator should be displayed.
+     * @param selectionEnd the cursor index (exclusive) when the indicator should be displayed.
      */
-    public void showCommitIndicator(final SuggestedWordInfo wordInfo) {
-        if (mMode == MODE_COMMIT && wordInfo != null &&
-                TextUtils.equals(mWaitingWord.mWord, wordInfo.mWord)) {
-            // Skip layout for better performance.
-            return;
-        }
-        mWaitingWord = wordInfo;
-        mMode = MODE_COMMIT;
-        layoutLater();
-    }
-
-    /**
-     * Shows the "Add to dictionary" indicator and associates it with associating the given
-     * suggested word.
-     *
-     * <p>The effect of {@link #showCommitIndicator(SuggestedWordInfo)} and
-     * {@link #showAddToDictionaryIndicator(SuggestedWordInfo)} are exclusive to each other. Call
-     * {@link #reset()} to hide the indicator.</p>
-     *
-     * @param wordInfo the suggested word which should be associated with the indicator. This object
-     * will be passed back in
-     * {@link Listener#onClickComposingTextToAddToDictionary(SuggestedWordInfo)}.
-     */
-    public void showAddToDictionaryIndicator(final SuggestedWordInfo wordInfo) {
-        if (mMode == MODE_ADD_TO_DICTIONARY && wordInfo != null &&
-                TextUtils.equals(mWaitingWord.mWord, wordInfo.mWord)) {
-            // Skip layout for better performance.
-            return;
-        }
-        mWaitingWord = wordInfo;
-        mMode = MODE_ADD_TO_DICTIONARY;
+    public void showAddToDictionaryIndicator(final String word, final int selectionStart,
+            final int selectionEnd) {
+        mWaitingWord = word;
+        mWaitingCursorStart = selectionStart;
+        mWaitingCursorEnd = selectionEnd;
+        mMode = MODE_WAITING_CURSOR_INDEX;
         layoutLater();
         return;
     }
@@ -165,18 +135,19 @@
      */
     public void reset() {
         mWaitingWord = null;
-        mMode = MODE_NONE;
-        mLocalOrigin.set(0.0f, 0.0f);
-        mRelativeIndicatorBounds.set(0.0f, 0.0f, 0.0f, 0.0f);
-        mRelativeComposingTextBounds.set(0.0f, 0.0f, 0.0f, 0.0f);
+        mMode = MODE_MONITOR;
+        mWaitingCursorStart = INVALID_CURSOR_INDEX;
+        mWaitingCursorEnd = INVALID_CURSOR_INDEX;
         cancelLayoutInternalExpectedly("Resetting internal state.");
     }
 
     /**
-     * Must be called when the {@link InputMethodService#onUpdateCursorAnchorInfo()} is called.
+     * Must be called when the {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)}
+     * is called.
      *
      * <p>CAVEAT: Currently the input method author is responsible for ignoring
-     * {@link InputMethodService#onUpdateCursorAnchorInfo()} called in full screen mode.</p>
+     * {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} called in full screen
+     * mode.</p>
      * @param info the compatibility wrapper object for the received {@link CursorAnchorInfo}.
      */
     public void onUpdateCursorAnchorInfo(final CursorAnchorInfoCompatWrapper info) {
@@ -185,29 +156,6 @@
         layoutImmediately();
     }
 
-    /**
-     * Hides indicator if the new composing text doesn't match the expected one.
-     *
-     * <p>Calling this method is optional but recommended whenever the new composition is passed to
-     * the application. The motivation of this method is to reduce the UI latency. With this method,
-     * we can hide the indicator without waiting the arrival of the
-     * {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} callback, assuming that
-     * the application accepts the new composing text without any modification. Even if this
-     * assumption is false, the indicator will be shown again when
-     * {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} is actually received.
-     * </p>
-     *
-     * @param newComposingText the new composing text that is being passed to the application.
-     */
-    public void hideIndicatorIfNecessary(final CharSequence newComposingText) {
-        if (mMode != MODE_COMMIT && mMode != MODE_ADD_TO_DICTIONARY) {
-            return;
-        }
-        if (!TextUtils.equals(newComposingText, mWaitingWord.mWord)) {
-            mUiOperator.hideUi();
-        }
-    }
-
     private void cancelLayoutInternalUnexpectedly(final String message) {
         mUiOperator.hideUi();
         Log.d(TAG, message);
@@ -232,15 +180,6 @@
     }
 
     private void layoutMain() {
-        if (mMode != MODE_COMMIT && mMode != MODE_ADD_TO_DICTIONARY) {
-            if (mMode == MODE_NONE) {
-                cancelLayoutInternalExpectedly("Not ready for layouting.");
-            } else {
-                cancelLayoutInternalUnexpectedly("Unknown mMode=" + mMode);
-            }
-            return;
-        }
-
         final CursorAnchorInfoCompatWrapper info = mCursorAnchorInfoWrapper;
 
         if (info == null) {
@@ -254,104 +193,117 @@
         }
 
         final CharSequence composingText = info.getComposingText();
-        if (mMode == MODE_COMMIT) {
-            if (composingText == null) {
-                cancelLayoutInternalExpectedly("composingText is null.");
-                return;
-            }
+        if (!TextUtils.isEmpty(composingText)) {
             final int composingTextStart = info.getComposingTextStart();
             final int lastCharRectIndex = composingTextStart + composingText.length() - 1;
             final RectF lastCharRect = info.getCharacterBounds(lastCharRectIndex);
-            final int lastCharRectFlag = info.getCharacterBoundsFlags(lastCharRectIndex);
+            final int lastCharRectFlags = info.getCharacterBoundsFlags(lastCharRectIndex);
             final boolean hasInvisibleRegionInLastCharRect =
-                    (lastCharRectFlag & CursorAnchorInfoCompatWrapper.FLAG_HAS_INVISIBLE_REGION)
+                    (lastCharRectFlags & CursorAnchorInfoCompatWrapper.FLAG_HAS_INVISIBLE_REGION)
                             != 0;
             if (lastCharRect == null || matrix == null || hasInvisibleRegionInLastCharRect) {
                 mUiOperator.hideUi();
                 return;
             }
-            final RectF segmentStartCharRect = new RectF(lastCharRect);
-            for (int i = composingText.length() - 2; i >= 0; --i) {
-                final RectF charRect = info.getCharacterBounds(composingTextStart + i);
-                if (charRect == null) {
+
+            // Note that the following layout information is fragile, and must be invalidated
+            // even when surrounding text next to the composing text is changed because it can
+            // affect how the composing text is rendered.
+            // TODO: Investigate if we can change the input logic to make the target text
+            // composing state so that we can retrieve the character bounds reliably.
+            final String composingTextString = composingText.toString();
+            final float top = lastCharRect.top;
+            final float bottom = lastCharRect.bottom;
+            float left = lastCharRect.left;
+            float right = lastCharRect.right;
+            boolean useRtlLayout = false;
+            for (int i = composingText.length() - 1; i >= 0; --i) {
+                final int characterIndex = composingTextStart + i;
+                final RectF characterBounds = info.getCharacterBounds(characterIndex);
+                final int characterBoundsFlags = info.getCharacterBoundsFlags(characterIndex);
+                if (characterBounds == null) {
                     break;
                 }
-                if (charRect.top != segmentStartCharRect.top) {
+                if (characterBounds.top != top) {
                     break;
                 }
-                if (charRect.bottom != segmentStartCharRect.bottom) {
+                if (characterBounds.bottom != bottom) {
                     break;
                 }
-                segmentStartCharRect.set(charRect);
+                if ((characterBoundsFlags & CursorAnchorInfoCompatWrapper.FLAG_IS_RTL) != 0) {
+                    // This is for both RTL text and bi-directional text. RTL languages usually mix
+                    // RTL characters with LTR characters and in this case we should display the
+                    // indicator on the left, while in LTR languages that normally never happens.
+                    // TODO: Try to come up with a better algorithm.
+                    useRtlLayout = true;
+                }
+                left = Math.min(characterBounds.left, left);
+                right = Math.max(characterBounds.right, right);
             }
-
-            mLocalOrigin.set(lastCharRect.right, lastCharRect.top);
-            mRelativeIndicatorBounds.set(lastCharRect.right, lastCharRect.top,
-                    lastCharRect.right + lastCharRect.height(), lastCharRect.bottom);
-            mRelativeIndicatorBounds.offset(-mLocalOrigin.x, -mLocalOrigin.y);
-
-            mRelativeIndicatorBounds.set(lastCharRect.right, lastCharRect.top,
-                    lastCharRect.right + lastCharRect.height(), lastCharRect.bottom);
-            mRelativeIndicatorBounds.offset(-mLocalOrigin.x, -mLocalOrigin.y);
-
-            mRelativeComposingTextBounds.set(segmentStartCharRect.left, segmentStartCharRect.top,
-                    segmentStartCharRect.right, segmentStartCharRect.bottom);
-            mRelativeComposingTextBounds.offset(-mLocalOrigin.x, -mLocalOrigin.y);
-
-            if (mWaitingWord == null) {
-                cancelLayoutInternalExpectedly("mWaitingText is null.");
-                return;
+            mLastComposingText = composingTextString;
+            mComposingTextBoundsForLastComposingText.set(left, top, right, bottom);
+            // The height and width of the indicator is the same as the height of the composing
+            // text.
+            final float indicatorSize = bottom - top;
+            mIndicatorBoundsForLastComposingText.set(0.0f, 0.0f, indicatorSize, indicatorSize);
+            // The horizontal position of the indicator depends on the text direction.
+            final float indicatorTop = top;
+            final float indicatorLeft;
+            if (useRtlLayout) {
+                indicatorLeft = left - indicatorSize;
+            } else {
+                indicatorLeft = right;
             }
-            if (TextUtils.isEmpty(mWaitingWord.mWord)) {
-                cancelLayoutInternalExpectedly("mWaitingText.mWord is empty.");
-                return;
-            }
-            if (!TextUtils.equals(composingText, mWaitingWord.mWord)) {
-                // This is indeed an expected situation because of the asynchronous nature of
-                // input method framework in Android. Note that composingText is notified from the
-                // application, while mWaitingWord.mWord is obtained directly from the InputLogic.
-                cancelLayoutInternalExpectedly(
-                        "Composing text doesn't match the one we are waiting for.");
-                return;
-            }
-        } else {
-            if (!mIsFullScreenMode && !TextUtils.isEmpty(composingText)) {
-                // This is an unexpected case.
-                // TODO: Document this.
-                mUiOperator.hideUi();
-                return;
-            }
-            // In MODE_ADD_TO_DICTIONARY, we cannot retrieve the character position at all because
-            // of the lack of composing text. We will use the insertion marker position instead.
-            if ((info.getInsertionMarkerFlags() &
-                    CursorAnchorInfoCompatWrapper.FLAG_HAS_INVISIBLE_REGION) != 0) {
-                mUiOperator.hideUi();
-                return;
-            }
-            final float insertionMarkerHolizontal = info.getInsertionMarkerHorizontal();
-            final float insertionMarkerTop = info.getInsertionMarkerTop();
-            mLocalOrigin.set(insertionMarkerHolizontal, insertionMarkerTop);
+            mIndicatorBoundsForLastComposingText.offset(indicatorLeft, indicatorTop);
         }
 
-        final RectF indicatorBounds = new RectF(mRelativeIndicatorBounds);
-        final RectF composingTextBounds = new RectF(mRelativeComposingTextBounds);
-        indicatorBounds.offset(mLocalOrigin.x, mLocalOrigin.y);
-        composingTextBounds.offset(mLocalOrigin.x, mLocalOrigin.y);
-        mUiOperator.layoutUi(mMode == MODE_COMMIT, matrix, indicatorBounds, composingTextBounds);
+        final int selectionStart = info.getSelectionStart();
+        final int selectionEnd = info.getSelectionEnd();
+        switch (mMode) {
+            case MODE_MONITOR:
+                mUiOperator.hideUi();
+                return;
+            case MODE_WAITING_CURSOR_INDEX:
+                if (selectionStart != mWaitingCursorStart || selectionEnd != mWaitingCursorEnd) {
+                    mUiOperator.hideUi();
+                    return;
+                }
+                mMode = MODE_SHOWING_INDICATOR;
+                break;
+            case MODE_SHOWING_INDICATOR:
+                if (selectionStart != mWaitingCursorStart || selectionEnd != mWaitingCursorEnd) {
+                    mUiOperator.hideUi();
+                    mMode = MODE_MONITOR;
+                    mWaitingCursorStart = INVALID_CURSOR_INDEX;
+                    mWaitingCursorEnd = INVALID_CURSOR_INDEX;
+                    return;
+                }
+                break;
+            default:
+                cancelLayoutInternalUnexpectedly("Unexpected internal mode=" + mMode);
+                return;
+        }
+
+        if (!TextUtils.equals(mLastComposingText, mWaitingWord)) {
+            cancelLayoutInternalUnexpectedly("mLastComposingText doesn't match mWaitingWord");
+            return;
+        }
+
+        if ((info.getInsertionMarkerFlags() &
+                CursorAnchorInfoCompatWrapper.FLAG_HAS_INVISIBLE_REGION) != 0) {
+            mUiOperator.hideUi();
+            return;
+        }
+
+        mUiOperator.layoutUi(matrix, mIndicatorBoundsForLastComposingText,
+                mComposingTextBoundsForLastComposingText);
     }
 
     private void onClickIndicator() {
-        if (mWaitingWord == null || TextUtils.isEmpty(mWaitingWord.mWord)) {
+        if (mMode != MODE_SHOWING_INDICATOR) {
             return;
         }
-        switch (mMode) {
-            case MODE_COMMIT:
-                mListener.onClickComposingTextToCommit(mWaitingWord);
-                break;
-            case MODE_ADD_TO_DICTIONARY:
-                mListener.onClickComposingTextToAddToDictionary(mWaitingWord);
-                break;
-        }
+        mListener.onClickComposingTextToAddToDictionary(mWaitingWord);
     }
 
     private final LayoutInvalidator mLayoutInvalidator = new LayoutInvalidator(this);
@@ -407,10 +359,7 @@
 
     private final static Listener EMPTY_LISTENER = new Listener() {
         @Override
-        public void onClickComposingTextToCommit(SuggestedWordInfo wordInfo) {
-        }
-        @Override
-        public void onClickComposingTextToAddToDictionary(SuggestedWordInfo wordInfo) {
+        public void onClickComposingTextToAddToDictionary(final String word) {
         }
     };
 
@@ -425,8 +374,7 @@
         public void setOnClickListener(Runnable listener) {
         }
         @Override
-        public void layoutUi(boolean isCommitMode, Matrix matrix, RectF indicatorBounds,
-                RectF composingTextBounds) {
+        public void layoutUi(Matrix matrix, RectF indicatorBounds, RectF composingTextBounds) {
         }
     };
 }
diff --git a/java/src/com/android/inputmethod/keyboard/TextDecoratorUi.java b/java/src/com/android/inputmethod/keyboard/TextDecoratorUi.java
index 6e215a9..b67d177 100644
--- a/java/src/com/android/inputmethod/keyboard/TextDecoratorUi.java
+++ b/java/src/com/android/inputmethod/keyboard/TextDecoratorUi.java
@@ -46,7 +46,6 @@
     private static final int VISUAL_DEBUG_HIT_AREA_COLOR = 0x80ff8000;
 
     private final RelativeLayout mLocalRootView;
-    private final CommitIndicatorView mCommitIndicatorView;
     private final AddToDictionaryIndicatorView mAddToDictionaryIndicatorView;
     private final PopupWindow mTouchEventWindow;
     private final View mTouchEventWindowClickListenerView;
@@ -73,9 +72,7 @@
         mLocalRootView.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
 
         final ViewGroup contentView = getContentView(inputView);
-        mCommitIndicatorView = new CommitIndicatorView(context);
         mAddToDictionaryIndicatorView = new AddToDictionaryIndicatorView(context);
-        mLocalRootView.addView(mCommitIndicatorView);
         mLocalRootView.addView(mAddToDictionaryIndicatorView);
         if (contentView != null) {
             contentView.addView(mLocalRootView);
@@ -110,17 +107,15 @@
 
     @Override
     public void hideUi() {
-        mCommitIndicatorView.setVisibility(View.GONE);
         mAddToDictionaryIndicatorView.setVisibility(View.GONE);
         mTouchEventWindow.dismiss();
     }
 
     @Override
-    public void layoutUi(final boolean isCommitMode, final Matrix matrix,
-            final RectF indicatorBounds, final RectF composingTextBounds) {
+    public void layoutUi(final Matrix matrix, final RectF indicatorBounds,
+            final RectF composingTextBounds) {
         final RectF indicatorBoundsInScreenCoordinates = new RectF();
         matrix.mapRect(indicatorBoundsInScreenCoordinates, indicatorBounds);
-        mCommitIndicatorView.setBounds(indicatorBoundsInScreenCoordinates);
         mAddToDictionaryIndicatorView.setBounds(indicatorBoundsInScreenCoordinates);
 
         final RectF hitAreaBounds = new RectF(composingTextBounds);
@@ -133,20 +128,9 @@
         mLocalRootView.getLocationOnScreen(originScreen);
         final int viewOriginX = originScreen[0];
         final int viewOriginY = originScreen[1];
-
-        final View toBeShown;
-        final View toBeHidden;
-        if (isCommitMode) {
-            toBeShown = mCommitIndicatorView;
-            toBeHidden = mAddToDictionaryIndicatorView;
-        } else {
-            toBeShown = mAddToDictionaryIndicatorView;
-            toBeHidden = mCommitIndicatorView;
-        }
-        toBeShown.setX(indicatorBoundsInScreenCoordinates.left - viewOriginX);
-        toBeShown.setY(indicatorBoundsInScreenCoordinates.top - viewOriginY);
-        toBeShown.setVisibility(View.VISIBLE);
-        toBeHidden.setVisibility(View.GONE);
+        mAddToDictionaryIndicatorView.setX(indicatorBoundsInScreenCoordinates.left - viewOriginX);
+        mAddToDictionaryIndicatorView.setY(indicatorBoundsInScreenCoordinates.top - viewOriginY);
+        mAddToDictionaryIndicatorView.setVisibility(View.VISIBLE);
 
         if (mTouchEventWindow.isShowing()) {
             mTouchEventWindow.update((int)hitAreaBoundsInScreenCoordinates.left - viewOriginX,
@@ -239,15 +223,6 @@
         return windowContentView;
     }
 
-    private static final class CommitIndicatorView extends TextDecoratorUi.IndicatorView {
-        public CommitIndicatorView(final Context context) {
-            super(context, R.array.text_decorator_commit_indicator_path,
-                    R.integer.text_decorator_commit_indicator_path_size,
-                    R.color.text_decorator_commit_indicator_background_color,
-                    R.color.text_decorator_commit_indicator_foreground_color);
-        }
-    }
-
     private static final class AddToDictionaryIndicatorView extends TextDecoratorUi.IndicatorView {
         public AddToDictionaryIndicatorView(final Context context) {
             super(context, R.array.text_decorator_add_to_dictionary_indicator_path,
diff --git a/java/src/com/android/inputmethod/keyboard/TextDecoratorUiOperator.java b/java/src/com/android/inputmethod/keyboard/TextDecoratorUiOperator.java
index f84e12d..9c0b64a 100644
--- a/java/src/com/android/inputmethod/keyboard/TextDecoratorUiOperator.java
+++ b/java/src/com/android/inputmethod/keyboard/TextDecoratorUiOperator.java
@@ -44,12 +44,10 @@
 
     /**
      * Called when the layout should be updated.
-     * @param isCommitMode {@code true} if the commit indicator should be shown. Show the
-     * add-to-dictionary indicator otherwise.
      * @param matrix The matrix that transforms the local coordinates into the screen coordinates.
      * @param indicatorBounds The bounding box of the indicator, in local coordinates.
      * @param composingTextBounds The bounding box of the composing text, in local coordinates.
      */
-    void layoutUi(final boolean isCommitMode, final Matrix matrix, final RectF indicatorBounds,
+    void layoutUi(final Matrix matrix, final RectF indicatorBounds,
             final RectF composingTextBounds);
 }
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
index fa41927..2056a0b 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
@@ -674,15 +674,18 @@
                     R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage());
             final boolean countryCodeMatched = matchString(caseAttr,
                     R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry());
+            final boolean splitLayoutMatched = matchBoolean(caseAttr,
+                    R.styleable.Keyboard_Case_isSplitLayout, id.mIsSplitLayout);
             final boolean selected = keyboardLayoutSetMatched && keyboardLayoutSetElementMatched
                     && keyboardThemeMacthed && modeMatched && navigateNextMatched
                     && navigatePreviousMatched && passwordInputMatched && clobberSettingsKeyMatched
                     && hasShortcutKeyMatched  && languageSwitchKeyEnabledMatched
                     && isMultiLineMatched && imeActionMatched && isIconDefinedMatched
-                    && localeCodeMatched && languageCodeMatched && countryCodeMatched;
+                    && localeCodeMatched && languageCodeMatched && countryCodeMatched
+                    && splitLayoutMatched;
 
             if (DEBUG) {
-                startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE,
+                startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE,
                         textAttr(caseAttr.getString(
                                 R.styleable.Keyboard_Case_keyboardLayoutSet), "keyboardLayoutSet"),
                         textAttr(caseAttr.getString(
@@ -707,6 +710,8 @@
                                 "languageSwitchKeyEnabled"),
                         booleanAttr(caseAttr, R.styleable.Keyboard_Case_isMultiLine,
                                 "isMultiLine"),
+                        booleanAttr(caseAttr, R.styleable.Keyboard_Case_isSplitLayout,
+                                "splitLayout"),
                         textAttr(caseAttr.getString(R.styleable.Keyboard_Case_isIconDefined),
                                 "isIconDefined"),
                         textAttr(caseAttr.getString(R.styleable.Keyboard_Case_localeCode),
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
index 0e3acff..aae134e 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
@@ -3028,16 +3028,16 @@
 
     /* Locale ro: Romanian */
     private static final String[] TEXTS_ro = {
+        // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE
         // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
         // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
-        // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE
         // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
         // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
         // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
         // U+00E6: "æ" LATIN SMALL LETTER AE
         // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
         // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
-        /* morekeys_a */ "\u00E2,\u00E3,\u0103,\u00E0,\u00E1,\u00E4,\u00E6,\u00E5,\u0101",
+        /* morekeys_a */ "\u0103,\u00E2,\u00E3,\u00E0,\u00E1,\u00E4,\u00E6,\u00E5,\u0101",
         /* morekeys_o ~ */
         null, null, null, null,
         /* ~ morekeys_e */
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 2e10875..9bca0bf 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -186,9 +186,10 @@
             long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times,
             int[] pointerIds, int[] inputCodePoints, int inputSize, int[] suggestOptions,
             int[][] prevWordCodePointArrays, boolean[] isBeginningOfSentenceArray,
-            int[] outputSuggestionCount, int[] outputCodePoints, int[] outputScores,
-            int[] outputIndices, int[] outputTypes, int[] outputAutoCommitFirstWordConfidence,
-            float[] inOutLanguageWeight);
+            int prevWordCount, int[] outputSuggestionCount, int[] outputCodePoints,
+            int[] outputScores, int[] outputIndices, int[] outputTypes,
+            int[] outputAutoCommitFirstWordConfidence,
+            float[] inOutWeightOfLangModelVsSpatialModel);
     private static native boolean addUnigramEntryNative(long dict, int[] word, int probability,
             int[] shortcutTarget, int shortcutProbability, boolean isBeginningOfSentence,
             boolean isNotAWord, boolean isBlacklisted, int timestamp);
@@ -256,7 +257,8 @@
     public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
             final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo,
             final SettingsValuesForSuggestion settingsValuesForSuggestion,
-            final int sessionId, final float[] inOutLanguageWeight) {
+            final int sessionId, final float weightForLocale,
+            final float[] inOutWeightOfLangModelVsSpatialModel) {
         if (!isValidDictionary()) {
             return null;
         }
@@ -284,10 +286,12 @@
                 settingsValuesForSuggestion.mSpaceAwareGestureEnabled);
         session.mNativeSuggestOptions.setAdditionalFeaturesOptions(
                 settingsValuesForSuggestion.mAdditionalFeaturesSettingValues);
-        if (inOutLanguageWeight != null) {
-            session.mInputOutputLanguageWeight[0] = inOutLanguageWeight[0];
+        if (inOutWeightOfLangModelVsSpatialModel != null) {
+            session.mInputOutputWeightOfLangModelVsSpatialModel[0] =
+                    inOutWeightOfLangModelVsSpatialModel[0];
         } else {
-            session.mInputOutputLanguageWeight[0] = Dictionary.NOT_A_LANGUAGE_WEIGHT;
+            session.mInputOutputWeightOfLangModelVsSpatialModel[0] =
+                    Dictionary.NOT_A_WEIGHT_OF_LANG_MODEL_VS_SPATIAL_MODEL;
         }
         // TOOD: Pass multiple previous words information for n-gram.
         getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(),
@@ -295,12 +299,14 @@
                 inputPointers.getYCoordinates(), inputPointers.getTimes(),
                 inputPointers.getPointerIds(), session.mInputCodePoints, inputSize,
                 session.mNativeSuggestOptions.getOptions(), session.mPrevWordCodePointArrays,
-                session.mIsBeginningOfSentenceArray, session.mOutputSuggestionCount,
-                session.mOutputCodePoints, session.mOutputScores, session.mSpaceIndices,
-                session.mOutputTypes, session.mOutputAutoCommitFirstWordConfidence,
-                session.mInputOutputLanguageWeight);
-        if (inOutLanguageWeight != null) {
-            inOutLanguageWeight[0] = session.mInputOutputLanguageWeight[0];
+                session.mIsBeginningOfSentenceArray, prevWordsInfo.getPrevWordCount(),
+                session.mOutputSuggestionCount, session.mOutputCodePoints, session.mOutputScores,
+                session.mSpaceIndices, session.mOutputTypes,
+                session.mOutputAutoCommitFirstWordConfidence,
+                session.mInputOutputWeightOfLangModelVsSpatialModel);
+        if (inOutWeightOfLangModelVsSpatialModel != null) {
+            inOutWeightOfLangModelVsSpatialModel[0] =
+                    session.mInputOutputWeightOfLangModelVsSpatialModel[0];
         }
         final int count = session.mOutputSuggestionCount[0];
         final ArrayList<SuggestedWordInfo> suggestions = new ArrayList<>();
@@ -314,7 +320,8 @@
             if (len > 0) {
                 suggestions.add(new SuggestedWordInfo(
                         new String(session.mOutputCodePoints, start, len),
-                        session.mOutputScores[j], session.mOutputTypes[j], this /* sourceDict */,
+                        (int)(session.mOutputScores[j] * weightForLocale), session.mOutputTypes[j],
+                        this /* sourceDict */,
                         session.mSpaceIndices[j] /* indexOfTouchPointOfSecondWord */,
                         session.mOutputAutoCommitFirstWordConfidence[0]));
             }
@@ -358,9 +365,8 @@
         if (!prevWordsInfo.isValid() || TextUtils.isEmpty(word)) {
             return NOT_A_PROBABILITY;
         }
-        final int[][] prevWordCodePointArrays = new int[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM][];
-        final boolean[] isBeginningOfSentenceArray =
-                new boolean[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
+        final int[][] prevWordCodePointArrays = new int[prevWordsInfo.getPrevWordCount()][];
+        final boolean[] isBeginningOfSentenceArray = new boolean[prevWordsInfo.getPrevWordCount()];
         prevWordsInfo.outputToArray(prevWordCodePointArrays, isBeginningOfSentenceArray);
         final int[] wordCodePoints = StringUtils.toCodePointArray(word);
         return getNgramProbabilityNative(mNativeDict, prevWordCodePointArrays,
@@ -455,9 +461,8 @@
         if (!prevWordsInfo.isValid() || TextUtils.isEmpty(word)) {
             return false;
         }
-        final int[][] prevWordCodePointArrays = new int[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM][];
-        final boolean[] isBeginningOfSentenceArray =
-                new boolean[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
+        final int[][] prevWordCodePointArrays = new int[prevWordsInfo.getPrevWordCount()][];
+        final boolean[] isBeginningOfSentenceArray = new boolean[prevWordsInfo.getPrevWordCount()];
         prevWordsInfo.outputToArray(prevWordCodePointArrays, isBeginningOfSentenceArray);
         final int[] wordCodePoints = StringUtils.toCodePointArray(word);
         if (!addNgramEntryNative(mNativeDict, prevWordCodePointArrays,
@@ -473,9 +478,8 @@
         if (!prevWordsInfo.isValid() || TextUtils.isEmpty(word)) {
             return false;
         }
-        final int[][] prevWordCodePointArrays = new int[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM][];
-        final boolean[] isBeginningOfSentenceArray =
-                new boolean[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
+        final int[][] prevWordCodePointArrays = new int[prevWordsInfo.getPrevWordCount()][];
+        final boolean[] isBeginningOfSentenceArray = new boolean[prevWordsInfo.getPrevWordCount()];
         prevWordsInfo.outputToArray(prevWordCodePointArrays, isBeginningOfSentenceArray);
         final int[] wordCodePoints = StringUtils.toCodePointArray(word);
         if (!removeNgramEntryNative(mNativeDict, prevWordCodePointArrays,
@@ -486,6 +490,7 @@
         return true;
     }
 
+    @UsedForTesting
     public void addMultipleDictionaryEntries(final LanguageModelParam[] languageModelParams) {
         if (!isValidDictionary()) return;
         int processedParamCount = 0;
diff --git a/java/src/com/android/inputmethod/latin/DicTraverseSession.java b/java/src/com/android/inputmethod/latin/DicTraverseSession.java
index b341f62..2751c12 100644
--- a/java/src/com/android/inputmethod/latin/DicTraverseSession.java
+++ b/java/src/com/android/inputmethod/latin/DicTraverseSession.java
@@ -40,7 +40,7 @@
     public final int[] mOutputTypes = new int[MAX_RESULTS];
     // Only one result is ever used
     public final int[] mOutputAutoCommitFirstWordConfidence = new int[1];
-    public final float[] mInputOutputLanguageWeight = new float[1];
+    public final float[] mInputOutputWeightOfLangModelVsSpatialModel = new float[1];
 
     public final NativeSuggestOptions mNativeSuggestOptions = new NativeSuggestOptions();
 
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 2f79c76..b58a52b 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -22,6 +22,8 @@
 
 import java.util.ArrayList;
 import java.util.Locale;
+import java.util.Arrays;
+import java.util.HashSet;
 
 /**
  * Abstract base class for a dictionary that can do a fuzzy search for words based on a set of key
@@ -29,7 +31,7 @@
  */
 public abstract class Dictionary {
     public static final int NOT_A_PROBABILITY = -1;
-    public static final float NOT_A_LANGUAGE_WEIGHT = -1.0f;
+    public static final float NOT_A_WEIGHT_OF_LANG_MODEL_VS_SPATIAL_MODEL = -1.0f;
 
     // The following types do not actually come from real dictionary instances, so we create
     // corresponding instances.
@@ -65,6 +67,14 @@
     // The locale for this dictionary. May be null if unknown (phony dictionary for example).
     public final Locale mLocale;
 
+    /**
+     * Set out of the dictionary types listed above that are based on data specific to the user,
+     * e.g., the user's contacts.
+     */
+    private static final HashSet<String> sUserSpecificDictionaryTypes =
+            new HashSet(Arrays.asList(new String[] { TYPE_USER_TYPED, TYPE_USER, TYPE_CONTACTS,
+                    TYPE_USER_HISTORY, TYPE_PERSONALIZATION, TYPE_CONTEXTUAL }));
+
     public Dictionary(final String dictType, final Locale locale) {
         mDictType = dictType;
         mLocale = locale;
@@ -78,15 +88,18 @@
      * @param proximityInfo the object for key proximity. May be ignored by some implementations.
      * @param settingsValuesForSuggestion the settings values used for the suggestion.
      * @param sessionId the session id.
-     * @param inOutLanguageWeight the language weight used for generating suggestions.
-     * inOutLanguageWeight is a float array that has only one element. This can be updated when the
-     * different language weight is used.
+     * @param weightForLocale the weight given to this locale, to multiply the output scores for
+     * multilingual input.
+     * @param inOutWeightOfLangModelVsSpatialModel the weight of the language model as a ratio of
+     * the spatial model, used for generating suggestions. inOutWeightOfLangModelVsSpatialModel is
+     * a float array that has only one element. This can be updated when a different value is used.
      * @return the list of suggestions (possibly null if none)
      */
     abstract public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
             final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo,
             final SettingsValuesForSuggestion settingsValuesForSuggestion,
-            final int sessionId, final float[] inOutLanguageWeight);
+            final int sessionId, final float weightForLocale,
+            final float[] inOutWeightOfLangModelVsSpatialModel);
 
     /**
      * Checks if the given word has to be treated as a valid word. Please note that some
@@ -159,6 +172,14 @@
     }
 
     /**
+     * Whether this dictionary is based on data specific to the user, e.g., the user's contacts.
+     * @return Whether this dictionary is specific to the user.
+     */
+    public boolean isUserSpecific() {
+        return sUserSpecificDictionaryTypes.contains(mDictType);
+    }
+
+    /**
      * Not a true dictionary. A placeholder used to indicate suggestions that don't come from any
      * real dictionary.
      */
@@ -172,7 +193,8 @@
         public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
                 final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo,
                 final SettingsValuesForSuggestion settingsValuesForSuggestion,
-                final int sessionId, final float[] inOutLanguageWeight) {
+                final int sessionId, final float weightForLocale,
+                final float[] inOutWeightOfLangModelVsSpatialModel) {
             return null;
         }
 
diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
index ca5e937..b26b378 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
@@ -62,20 +62,21 @@
     public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
             final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo,
             final SettingsValuesForSuggestion settingsValuesForSuggestion,
-            final int sessionId, final float[] inOutLanguageWeight) {
+            final int sessionId, final float weightForLocale,
+            final float[] inOutWeightOfLangModelVsSpatialModel) {
         final CopyOnWriteArrayList<Dictionary> dictionaries = mDictionaries;
         if (dictionaries.isEmpty()) return null;
         // To avoid creating unnecessary objects, we get the list out of the first
         // dictionary and add the rest to it if not null, hence the get(0)
         ArrayList<SuggestedWordInfo> suggestions = dictionaries.get(0).getSuggestions(composer,
                 prevWordsInfo, proximityInfo, settingsValuesForSuggestion, sessionId,
-                inOutLanguageWeight);
+                weightForLocale, inOutWeightOfLangModelVsSpatialModel);
         if (null == suggestions) suggestions = new ArrayList<>();
         final int length = dictionaries.size();
         for (int i = 1; i < length; ++ i) {
             final ArrayList<SuggestedWordInfo> sugg = dictionaries.get(i).getSuggestions(composer,
                     prevWordsInfo, proximityInfo, settingsValuesForSuggestion, sessionId,
-                    inOutLanguageWeight);
+                    weightForLocale, inOutWeightOfLangModelVsSpatialModel);
             if (null != sugg) suggestions.addAll(sugg);
         }
         return suggestions;
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
index eced45e..aa15bd6 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
@@ -104,6 +104,7 @@
     private static class DictionaryGroup {
         public final Locale mLocale;
         private Dictionary mMainDict;
+        public float mWeightForLocale = 1.0f;
         public final ConcurrentHashMap<String, ExpandableBinaryDictionary> mSubDictMap =
                 new ConcurrentHashMap<>();
 
@@ -595,16 +596,19 @@
             final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo,
             final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId) {
         final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
-        final SuggestionResults suggestionResults =
-                new SuggestionResults(SuggestedWords.MAX_SUGGESTIONS);
-        final float[] languageWeight = new float[] { Dictionary.NOT_A_LANGUAGE_WEIGHT };
+        final SuggestionResults suggestionResults = new SuggestionResults(
+                SuggestedWords.MAX_SUGGESTIONS,
+                prevWordsInfo.mPrevWordsInfo[0].mIsBeginningOfSentence);
+        final float[] weightOfLangModelVsSpatialModel =
+                new float[] { Dictionary.NOT_A_WEIGHT_OF_LANG_MODEL_VS_SPATIAL_MODEL };
         for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
             for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
                 final Dictionary dictionary = dictionaryGroup.getDict(dictType);
                 if (null == dictionary) continue;
                 final ArrayList<SuggestedWordInfo> dictionarySuggestions =
                         dictionary.getSuggestions(composer, prevWordsInfo, proximityInfo,
-                                settingsValuesForSuggestion, sessionId, languageWeight);
+                                settingsValuesForSuggestion, sessionId,
+                                dictionaryGroup.mWeightForLocale, weightOfLangModelVsSpatialModel);
                 if (null == dictionarySuggestions) continue;
                 suggestionResults.addAll(dictionarySuggestions);
                 if (null != suggestionResults.mRawSuggestions) {
@@ -706,6 +710,7 @@
                 getLocale(), personalizationDataChunk, spacingAndPunctuations, callback);
     }
 
+    @UsedForTesting
     public void addPhraseToContextualDictionary(final String[] phrase, final int probability,
             final int bigramProbabilityForWords, final int bigramProbabilityForPhrases) {
         // TODO: we're inserting the phrase into the dictionary for the active language. Rethink
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 671ba67..ad967c1 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -435,7 +435,7 @@
     public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
             final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo,
             final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId,
-            final float[] inOutLanguageWeight) {
+            final float weightForLocale, final float[] inOutWeightOfLangModelVsSpatialModel) {
         reloadDictionaryIfRequired();
         boolean lockAcquired = false;
         try {
@@ -447,7 +447,8 @@
                 }
                 final ArrayList<SuggestedWordInfo> suggestions =
                         mBinaryDictionary.getSuggestions(composer, prevWordsInfo, proximityInfo,
-                                settingsValuesForSuggestion, sessionId, inOutLanguageWeight);
+                                settingsValuesForSuggestion, sessionId, weightForLocale,
+                                inOutWeightOfLangModelVsSpatialModel);
                 if (mBinaryDictionary.isCorrupted()) {
                     Log.i(TAG, "Dictionary (" + mDictName +") is corrupted. "
                             + "Remove and regenerate it.");
diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java
index 50a6e48..ffd363b 100644
--- a/java/src/com/android/inputmethod/latin/InputAttributes.java
+++ b/java/src/com/android/inputmethod/latin/InputAttributes.java
@@ -112,7 +112,7 @@
         mShouldInsertSpacesAutomatically = InputTypeUtils.isAutoSpaceFriendlyType(inputType);
 
         final boolean noMicrophone = mIsPasswordField
-                || InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS == variation
+                || InputTypeUtils.isEmailVariation(variation)
                 || InputType.TYPE_TEXT_VARIATION_URI == variation
                 || hasNoMicrophoneKeyOption();
         mShouldShowVoiceInputKey = !noMicrophone;
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 4757820..69fe6de 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -189,9 +189,8 @@
         private static final int MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED = 6;
         private static final int MSG_RESET_CACHES = 7;
         private static final int MSG_WAIT_FOR_DICTIONARY_LOAD = 8;
-        private static final int MSG_SHOW_COMMIT_INDICATOR = 9;
         // Update this when adding new messages
-        private static final int MSG_LAST = MSG_SHOW_COMMIT_INDICATOR;
+        private static final int MSG_LAST = MSG_WAIT_FOR_DICTIONARY_LOAD;
 
         private static final int ARG1_NOT_GESTURE_INPUT = 0;
         private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1;
@@ -202,7 +201,6 @@
 
         private int mDelayInMillisecondsToUpdateSuggestions;
         private int mDelayInMillisecondsToUpdateShiftState;
-        private int mDelayInMillisecondsToShowCommitIndicator;
 
         public UIHandler(final LatinIME ownerInstance) {
             super(ownerInstance);
@@ -218,8 +216,6 @@
                     R.integer.config_delay_in_milliseconds_to_update_suggestions);
             mDelayInMillisecondsToUpdateShiftState = res.getInteger(
                     R.integer.config_delay_in_milliseconds_to_update_shift_state);
-            mDelayInMillisecondsToShowCommitIndicator = res.getInteger(
-                    R.integer.text_decorator_delay_in_milliseconds_to_show_commit_indicator);
         }
 
         @Override
@@ -277,14 +273,6 @@
                             latinIme.getCurrentRecapitalizeState());
                 }
                 break;
-            case MSG_SHOW_COMMIT_INDICATOR:
-                // Protocol of MSG_SET_COMMIT_INDICATOR_ENABLED:
-                // - what: MSG_SHOW_COMMIT_INDICATOR
-                // - arg1: not used.
-                // - arg2: not used.
-                // - obj:  the Runnable object to be called back.
-                ((Runnable) msg.obj).run();
-                break;
             case MSG_WAIT_FOR_DICTIONARY_LOAD:
                 Log.i(TAG, "Timeout waiting for dictionary load");
                 break;
@@ -385,19 +373,6 @@
             obtainMessage(MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED, suggestedWords).sendToTarget();
         }
 
-        /**
-         * Posts a delayed task to show the commit indicator.
-         *
-         * <p>Only one task can exist in the queue. When this method is called, any prior task that
-         * has not yet fired will be canceled.</p>
-         * @param task the runnable object that will be fired when the delayed task is dispatched.
-         */
-        public void postShowCommitIndicatorTask(final Runnable task) {
-            removeMessages(MSG_SHOW_COMMIT_INDICATOR);
-            sendMessageDelayed(obtainMessage(MSG_SHOW_COMMIT_INDICATOR, task),
-                    mDelayInMillisecondsToShowCommitIndicator);
-        }
-
         // Working variables for the following methods.
         private boolean mIsOrientationChanging;
         private boolean mPendingSuccessiveImsCallback;
@@ -1516,19 +1491,23 @@
         final boolean isEmptyApplicationSpecifiedCompletions =
                 currentSettingsValues.isApplicationSpecifiedCompletionsOn()
                 && suggestedWords.isEmpty();
-        final boolean noSuggestionsToShow = (SuggestedWords.EMPTY == suggestedWords)
+        final boolean noSuggestionsFromDictionaries = (SuggestedWords.EMPTY == suggestedWords)
                 || suggestedWords.isPunctuationSuggestions()
                 || isEmptyApplicationSpecifiedCompletions;
-        if (shouldShowImportantNotice && noSuggestionsToShow) {
+        final boolean isBeginningOfSentencePrediction = (suggestedWords.mInputStyle
+                == SuggestedWords.INPUT_STYLE_BEGINNING_OF_SENTENCE_PREDICTION);
+        final boolean noSuggestionsToOverrideImportantNotice = noSuggestionsFromDictionaries
+                || isBeginningOfSentencePrediction;
+        if (shouldShowImportantNotice && noSuggestionsToOverrideImportantNotice) {
             if (mSuggestionStripView.maybeShowImportantNoticeTitle()) {
                 return;
             }
         }
 
         if (currentSettingsValues.isSuggestionsEnabledPerUserSettings()
-                // We should clear suggestions if there is no suggestion to show.
-                || noSuggestionsToShow
-                || currentSettingsValues.isApplicationSpecifiedCompletionsOn()) {
+                || currentSettingsValues.isApplicationSpecifiedCompletionsOn()
+                // We should clear the contextual strip if there is no suggestion from dictionaries.
+                || noSuggestionsFromDictionaries) {
             mSuggestionStripView.setSuggestions(suggestedWords,
                     SubtypeLocaleUtils.isRtlLanguage(mSubtypeSwitcher.getCurrentSubtype()));
         }
diff --git a/java/src/com/android/inputmethod/latin/PrevWordsInfo.java b/java/src/com/android/inputmethod/latin/PrevWordsInfo.java
index db877ab..76d4f57 100644
--- a/java/src/com/android/inputmethod/latin/PrevWordsInfo.java
+++ b/java/src/com/android/inputmethod/latin/PrevWordsInfo.java
@@ -86,33 +86,30 @@
     // For simplicity of implementation, elements may also be EMPTY_WORD_INFO transiently after the
     // WordComposer was reset and before starting a new composing word, but we should never be
     // calling getSuggetions* in this situation.
-    public WordInfo[] mPrevWordsInfo = new WordInfo[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
+    public final WordInfo[] mPrevWordsInfo;
 
     // Construct from the previous word information.
     public PrevWordsInfo(final WordInfo prevWordInfo) {
-        mPrevWordsInfo[0] = prevWordInfo;
+        mPrevWordsInfo = new WordInfo[] { prevWordInfo };
     }
 
     // Construct from WordInfo array. n-th element represents (n+1)-th previous word's information.
     public PrevWordsInfo(final WordInfo[] prevWordsInfo) {
-        for (int i = 0; i < Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM; i++) {
-            mPrevWordsInfo[i] =
-                    (prevWordsInfo.length > i) ? prevWordsInfo[i] : WordInfo.EMPTY_WORD_INFO;
-        }
+        mPrevWordsInfo = prevWordsInfo;
     }
 
     // Create next prevWordsInfo using current prevWordsInfo.
     public PrevWordsInfo getNextPrevWordsInfo(final WordInfo wordInfo) {
-        final WordInfo[] prevWordsInfo = new WordInfo[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
+        final int nextPrevWordCount = Math.min(Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM,
+                mPrevWordsInfo.length + 1);
+        final WordInfo[] prevWordsInfo = new WordInfo[nextPrevWordCount];
         prevWordsInfo[0] = wordInfo;
-        for (int i = 1; i < prevWordsInfo.length; i++) {
-            prevWordsInfo[i] = mPrevWordsInfo[i - 1];
-        }
+        System.arraycopy(mPrevWordsInfo, 0, prevWordsInfo, 1, prevWordsInfo.length - 1);
         return new PrevWordsInfo(prevWordsInfo);
     }
 
     public boolean isValid() {
-        return mPrevWordsInfo[0].isValid();
+        return mPrevWordsInfo.length > 0 && mPrevWordsInfo[0].isValid();
     }
 
     public void outputToArray(final int[][] codePointArrays,
@@ -129,9 +126,14 @@
         }
     }
 
+    public int getPrevWordCount() {
+        return mPrevWordsInfo.length;
+    }
+
     @Override
     public int hashCode() {
-        return Arrays.hashCode(mPrevWordsInfo);
+        // Just for having equals().
+        return mPrevWordsInfo[0].hashCode();
     }
 
     @Override
@@ -139,7 +141,23 @@
         if (this == o) return true;
         if (!(o instanceof PrevWordsInfo)) return false;
         final PrevWordsInfo prevWordsInfo = (PrevWordsInfo)o;
-        return Arrays.equals(mPrevWordsInfo, prevWordsInfo.mPrevWordsInfo);
+
+        final int minLength = Math.min(mPrevWordsInfo.length, prevWordsInfo.mPrevWordsInfo.length);
+        for (int i = 0; i < minLength; i++) {
+            if (!mPrevWordsInfo[i].equals(prevWordsInfo.mPrevWordsInfo[i])) {
+                return false;
+            }
+        }
+        final WordInfo[] longerWordsInfo =
+                (mPrevWordsInfo.length > prevWordsInfo.mPrevWordsInfo.length) ?
+                        mPrevWordsInfo : prevWordsInfo.mPrevWordsInfo;
+        for (int i = minLength; i < longerWordsInfo.length; i++) {
+            if (longerWordsInfo[i] != null
+                    && !WordInfo.EMPTY_WORD_INFO.equals(longerWordsInfo[i])) {
+                return false;
+            }
+        }
+        return true;
     }
 
     @Override
@@ -150,7 +168,11 @@
             builder.append("PrevWord[");
             builder.append(i);
             builder.append("]: ");
-            if (wordInfo == null || !wordInfo.isValid()) {
+            if (wordInfo == null) {
+                builder.append("null. ");
+                continue;
+            }
+            if (!wordInfo.isValid()) {
                 builder.append("Empty. ");
                 continue;
             }
diff --git a/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java
index ecf25c2..827367b 100644
--- a/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java
@@ -53,11 +53,13 @@
     public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
             final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo,
             final SettingsValuesForSuggestion settingsValuesForSuggestion,
-            final int sessionId, final float[] inOutLanguageWeight) {
+            final int sessionId, final float weightForLocale,
+            final float[] inOutWeightOfLangModelVsSpatialModel) {
         if (mLock.readLock().tryLock()) {
             try {
                 return mBinaryDictionary.getSuggestions(composer, prevWordsInfo, proximityInfo,
-                        settingsValuesForSuggestion, sessionId, inOutLanguageWeight);
+                        settingsValuesForSuggestion, sessionId, weightForLocale,
+                        inOutWeightOfLangModelVsSpatialModel);
             } finally {
                 mLock.readLock().unlock();
             }
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index dc00ecc..d672430 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -252,7 +252,7 @@
      * See {@link InputConnection#commitText(CharSequence, int)}.
      */
     public void commitText(final CharSequence text, final int newCursorPosition) {
-        commitTextWithBackgroundColor(text, newCursorPosition, Color.TRANSPARENT);
+        commitTextWithBackgroundColor(text, newCursorPosition, Color.TRANSPARENT, text.length());
     }
 
     /**
@@ -265,9 +265,11 @@
      * the background color. Note that this method specifies {@link BackgroundColorSpan} with
      * {@link Spanned#SPAN_COMPOSING} flag, meaning that the background color persists until
      * {@link #finishComposingText()} is called.
+     * @param coloredTextLength the length of text, in Java chars, which should be rendered with
+     * the given background color.
      */
     public void commitTextWithBackgroundColor(final CharSequence text, final int newCursorPosition,
-            final int color) {
+            final int color, final int coloredTextLength) {
         if (DEBUG_BATCH_NESTING) checkBatchEdit();
         if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
         mCommittedTextBeforeComposingText.append(text);
@@ -285,7 +287,8 @@
                 mTempObjectForCommitText.clear();
                 mTempObjectForCommitText.append(text);
                 final BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(color);
-                mTempObjectForCommitText.setSpan(backgroundColorSpan, 0, text.length(),
+                final int spanLength = Math.min(coloredTextLength, text.length());
+                mTempObjectForCommitText.setSpan(backgroundColorSpan, 0, spanLength,
                         Spanned.SPAN_COMPOSING | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                 mIC.commitText(mTempObjectForCommitText, newCursorPosition);
                 mLastCommittedTextHasBackgroundColor = true;
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 9bf0175..1ecc995 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -188,8 +188,14 @@
             suggestionsList = suggestionsContainer;
         }
 
-        final int inputStyle = resultsArePredictions ? SuggestedWords.INPUT_STYLE_PREDICTION :
-                inputStyleIfNotPrediction;
+        final int inputStyle;
+        if (resultsArePredictions) {
+            inputStyle = suggestionResults.mIsBeginningOfSentence
+                    ? SuggestedWords.INPUT_STYLE_BEGINNING_OF_SENTENCE_PREDICTION
+                    : SuggestedWords.INPUT_STYLE_PREDICTION;
+        } else {
+            inputStyle = inputStyleIfNotPrediction;
+        }
         callback.onGetSuggestedWords(new SuggestedWords(suggestionsList,
                 suggestionResults.mRawSuggestions,
                 // TODO: this first argument is lying. If this is a whitelisted word which is an
@@ -235,7 +241,7 @@
         SuggestedWordInfo.removeDups(null /* typedWord */, suggestionsContainer);
 
         // For some reason some suggestions with MIN_VALUE are making their way here.
-        // TODO: Find a more robust way to detect distractors.
+        // TODO: Find a more robust way to detect distracters.
         for (int i = suggestionsContainer.size() - 1; i >= 0; --i) {
             if (suggestionsContainer.get(i).mScore < SUPPRESS_SUGGEST_THRESHOLD) {
                 suggestionsContainer.remove(i);
@@ -244,6 +250,8 @@
 
         // In the batch input mode, the most relevant suggested word should act as a "typed word"
         // (typedWordValid=true), not as an "auto correct word" (willAutoCorrect=false).
+        // Note that because this method is never used to get predictions, there is no need to
+        // modify inputType such in getSuggestedWordsForNonBatchInput.
         callback.onGetSuggestedWords(new SuggestedWords(suggestionsContainer,
                 suggestionResults.mRawSuggestions,
                 true /* typedWordValid */,
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index dcfaa3f..3eefafc 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -39,6 +39,7 @@
     public static final int INPUT_STYLE_APPLICATION_SPECIFIED = 4;
     public static final int INPUT_STYLE_RECORRECTION = 5;
     public static final int INPUT_STYLE_PREDICTION = 6;
+    public static final int INPUT_STYLE_BEGINNING_OF_SENTENCE_PREDICTION = 7;
 
     // The maximum number of suggestions available.
     public static final int MAX_SUGGESTIONS = 18;
@@ -80,10 +81,9 @@
             final int inputStyle,
             final int sequenceNumber) {
         this(suggestedWordInfoList, rawSuggestions,
-                (suggestedWordInfoList.isEmpty() || INPUT_STYLE_PREDICTION == inputStyle) ? null
+                (suggestedWordInfoList.isEmpty() || isPrediction(inputStyle)) ? null
                         : suggestedWordInfoList.get(INDEX_OF_TYPED_WORD).mWord,
-                typedWordValid, willAutoCorrect, isObsoleteSuggestions, inputStyle,
-                sequenceNumber);
+                typedWordValid, willAutoCorrect, isObsoleteSuggestions, inputStyle, sequenceNumber);
     }
 
     public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList,
@@ -180,6 +180,7 @@
         return "SuggestedWords:"
                 + " mTypedWordValid=" + mTypedWordValid
                 + " mWillAutoCorrect=" + mWillAutoCorrect
+                + " mInputStyle=" + mInputStyle
                 + " words=" + Arrays.toString(mSuggestedWordInfoList.toArray());
     }
 
@@ -386,8 +387,13 @@
         }
     }
 
+    private static boolean isPrediction(final int inputStyle) {
+        return INPUT_STYLE_PREDICTION == inputStyle
+                || INPUT_STYLE_BEGINNING_OF_SENTENCE_PREDICTION == inputStyle;
+    }
+
     public boolean isPrediction() {
-        return INPUT_STYLE_PREDICTION == mInputStyle;
+        return isPrediction(mInputStyle);
     }
 
     // SuggestedWords is an immutable object, as much as possible. We must not just remove
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 32d1fe3..567aa07 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -49,6 +49,7 @@
     private final ArrayList<Event> mEvents;
     private final InputPointers mInputPointers = new InputPointers(MAX_WORD_LENGTH);
     private String mAutoCorrection;
+    private String mAutoCorrectionDictionaryType;
     private boolean mIsResumed;
     private boolean mIsBatchMode;
     // A memory of the last rejected batch mode suggestion, if any. This goes like this: the user
@@ -418,8 +419,9 @@
     /**
      * Sets the auto-correction for this word.
      */
-    public void setAutoCorrection(final String correction) {
+    public void setAutoCorrection(final String correction, String dictType) {
         mAutoCorrection = correction;
+        mAutoCorrectionDictionaryType = dictType;
     }
 
     /**
@@ -430,6 +432,13 @@
     }
 
     /**
+     * @return the auto-correction dictionary type or null if none.
+     */
+    public String getAutoCorrectionDictionaryTypeOrNull() {
+        return mAutoCorrectionDictionaryType;
+    }
+
+    /**
      * @return whether we started composing this word by resuming suggestion on an existing string
      */
     public boolean isResumed() {
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index c5e60d6..8eccd5c 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -28,6 +28,7 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.EditorInfo;
 
 import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper;
@@ -91,12 +92,8 @@
 
     private final TextDecorator mTextDecorator = new TextDecorator(new TextDecorator.Listener() {
         @Override
-        public void onClickComposingTextToCommit(SuggestedWordInfo wordInfo) {
-            mLatinIME.pickSuggestionManually(wordInfo);
-        }
-        @Override
-        public void onClickComposingTextToAddToDictionary(SuggestedWordInfo wordInfo) {
-            mLatinIME.addWordToUserDictionary(wordInfo.mWord);
+        public void onClickComposingTextToAddToDictionary(final String word) {
+            mLatinIME.addWordToUserDictionary(word);
             mLatinIME.dismissAddToDictionaryHint();
         }
     });
@@ -171,6 +168,7 @@
                 mConnection.requestCursorUpdates(true /* enableMonitor */,
                         true /* requestImmediateCallback */);
             }
+            mTextDecorator.reset();
         }
     }
 
@@ -207,6 +205,8 @@
     public void finishInput() {
         if (mWordComposer.isComposingWord()) {
             mConnection.finishComposingText();
+            StatsUtils.onWordCommitUserTyped(
+                    mWordComposer.getTypedWord(), mWordComposer.isBatchMode());
         }
         resetComposingState(true /* alsoResetLastComposedWord */);
         mInputLogicHandler.reset();
@@ -253,6 +253,7 @@
             promotePhantomSpace(settingsValues);
         }
         mConnection.commitText(text, 1);
+        StatsUtils.onWordCommitUserTyped(mEnteredText, mWordComposer.isBatchMode());
         mConnection.endBatchEdit();
         // Space state must be updated before calling updateShiftState
         mSpaceState = SpaceState.NONE;
@@ -334,17 +335,8 @@
         }
 
         final boolean shouldShowAddToDictionaryHint = shouldShowAddToDictionaryHint(suggestionInfo);
-        final boolean shouldShowAddToDictionaryIndicator =
-                shouldShowAddToDictionaryHint && settingsValues.mShouldShowUiToAcceptTypedWord;
-        final int backgroundColor;
-        if (shouldShowAddToDictionaryIndicator) {
-            backgroundColor = settingsValues.mTextHighlightColorForAddToDictionaryIndicator;
-        } else {
-            backgroundColor = Color.TRANSPARENT;
-        }
-        commitChosenWordWithBackgroundColor(settingsValues, suggestion,
-                LastComposedWord.COMMIT_TYPE_MANUAL_PICK, LastComposedWord.NOT_A_SEPARATOR,
-                backgroundColor);
+        commitChosenWord(settingsValues, suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK,
+                LastComposedWord.NOT_A_SEPARATOR);
         mConnection.endBatchEdit();
         // Don't allow cancellation of manual pick
         mLastComposedWord.deactivate();
@@ -359,11 +351,10 @@
             // That's going to be predictions (or punctuation suggestions), so INPUT_STYLE_NONE.
             handler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_NONE);
         }
-        if (shouldShowAddToDictionaryIndicator) {
-            mTextDecorator.showAddToDictionaryIndicator(suggestionInfo);
-        }
 
         StatsUtils.onPickSuggestionManually(mSuggestedWords, suggestionInfo);
+        StatsUtils.onWordCommitSuggestionPickedManually(
+                suggestionInfo.mWord, mWordComposer.isBatchMode());
         return inputTransaction;
     }
 
@@ -433,6 +424,9 @@
         mRecapitalizeStatus.enable();
         // We moved the cursor and need to invalidate the indicator right now.
         mTextDecorator.reset();
+        // Remaining background color that was used for the add-to-dictionary indicator should be
+        // removed.
+        mConnection.removeBackgroundColorFromHighlightedTextIfNecessary();
         // We moved the cursor. If we are touching a word, we need to resume suggestion.
         mLatinIME.mHandler.postResumeSuggestions(false /* shouldIncludeResumedWordInSuggestions */,
                 true /* shouldDelay */);
@@ -511,7 +505,9 @@
         handler.cancelUpdateSuggestionStrip();
         ++mAutoCommitSequenceNumber;
         mConnection.beginBatchEdit();
-        if (mWordComposer.isComposingWord()) {
+        if (!mWordComposer.isComposingWord()) {
+            mConnection.removeBackgroundColorFromHighlightedTextIfNecessary();
+        } else {
             if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
                 // If we are in the middle of a recorrection, we need to commit the recorrection
                 // first so that we can insert the batch input at the current cursor position.
@@ -582,6 +578,7 @@
                     batchPointers.shift(candidate.mIndexOfTouchPointOfSecondWord);
                     promotePhantomSpace(settingsValues);
                     mConnection.commitText(commitParts[0], 0);
+                    StatsUtils.onWordCommitUserTyped(commitParts[0], mWordComposer.isBatchMode());
                     mSpaceState = SpaceState.PHANTOM;
                     keyboardSwitcher.requestUpdatingShiftState(
                             getCurrentAutoCapsState(settingsValues), getCurrentRecapitalizeState());
@@ -612,53 +609,24 @@
             final SettingsValues settingsValues, final LatinIME.UIHandler handler) {
         if (SuggestedWords.EMPTY != suggestedWords) {
             final String autoCorrection;
+            final String dictType;
             if (suggestedWords.mWillAutoCorrect) {
-                autoCorrection = suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION);
+                SuggestedWordInfo info = suggestedWords.getInfo(
+                        SuggestedWords.INDEX_OF_AUTO_CORRECTION);
+                autoCorrection = info.mWord;
+                dictType = info.mSourceDict.mDictType;
             } else {
                 // We can't use suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD)
                 // because it may differ from mWordComposer.mTypedWord.
                 autoCorrection = suggestedWords.mTypedWord;
+                dictType = Dictionary.TYPE_USER_TYPED;
             }
-            mWordComposer.setAutoCorrection(autoCorrection);
+            // TODO: Use the SuggestedWordInfo to set the auto correction when
+            // user typed word is available via SuggestedWordInfo.
+            mWordComposer.setAutoCorrection(autoCorrection, dictType);
         }
         mSuggestedWords = suggestedWords;
         final boolean newAutoCorrectionIndicator = suggestedWords.mWillAutoCorrect;
-        if (shouldShowCommitIndicator(suggestedWords, settingsValues)) {
-            // typedWordInfo is never null here.
-            final int textBackgroundColor = settingsValues.mTextHighlightColorForCommitIndicator;
-            final SuggestedWordInfo typedWordInfo = suggestedWords.getTypedWordInfoOrNull();
-            handler.postShowCommitIndicatorTask(new Runnable() {
-                @Override
-                public void run() {
-                    // TODO: This needs to be refactored to ensure that mWordComposer is accessed
-                    // only from the UI thread.
-                    if (!mWordComposer.isComposingWord()) {
-                        mTextDecorator.reset();
-                        return;
-                    }
-                    final SuggestedWordInfo currentTypedWordInfo =
-                            mSuggestedWords.getTypedWordInfoOrNull();
-                    if (currentTypedWordInfo == null) {
-                        mTextDecorator.reset();
-                        return;
-                    }
-                    if (!currentTypedWordInfo.equals(typedWordInfo)) {
-                        // Suggested word has been changed. This task is obsolete.
-                        mTextDecorator.reset();
-                        return;
-                    }
-                    // TODO: As with the above TODO comment, this operation must be performed only
-                    // on the UI thread too. Needs to be refactored.
-                    setComposingTextInternalWithBackgroundColor(typedWordInfo.mWord,
-                            1 /* newCursorPosition */, textBackgroundColor);
-                    mTextDecorator.showCommitIndicator(typedWordInfo);
-                }
-            });
-        } else {
-            // Note: It is OK to not cancel previous postShowCommitIndicatorTask() here. Having a
-            // cancellation mechanism could improve performance a bit though.
-            mTextDecorator.reset();
-        }
 
         // Put a blue underline to a word in TextView which will be auto-corrected.
         if (mIsAutoCorrectionIndicatorOn != newAutoCorrectionIndicator
@@ -836,13 +804,14 @@
             final InputTransaction inputTransaction,
             // TODO: remove this argument
             final LatinIME.UIHandler handler) {
-        // In case the "add to dictionary" hint was still displayed.
-        // TODO: Do we really need to check if we have composing text here?
-        if (!mWordComposer.isComposingWord() &&
-                mSuggestionStripViewAccessor.isShowingAddToDictionaryHint()) {
-            mSuggestionStripViewAccessor.dismissAddToDictionaryHint();
+        if (!mWordComposer.isComposingWord()) {
             mConnection.removeBackgroundColorFromHighlightedTextIfNecessary();
-            mTextDecorator.reset();
+            // In case the "add to dictionary" hint was still displayed.
+            // TODO: Do we really need to check if we have composing text here?
+            if (mSuggestionStripViewAccessor.isShowingAddToDictionaryHint()) {
+                mSuggestionStripViewAccessor.dismissAddToDictionaryHint();
+                mTextDecorator.reset();
+            }
         }
 
         final int codePoint = event.mCodePoint;
@@ -1101,8 +1070,10 @@
             inputTransaction.setRequiresUpdateSuggestions();
         } else {
             if (mLastComposedWord.canRevertCommit()) {
-                revertCommit(inputTransaction);
+                final String lastComposedWord = mLastComposedWord.mTypedWord;
+                revertCommit(inputTransaction, inputTransaction.mSettingsValues);
                 StatsUtils.onRevertAutoCorrect();
+                StatsUtils.onWordCommitUserTyped(lastComposedWord, mWordComposer.isBatchMode());
                 return;
             }
             if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) {
@@ -1602,14 +1573,19 @@
      * This is triggered upon pressing backspace just after a commit with auto-correction.
      *
      * @param inputTransaction The transaction in progress.
+     * @param settingsValues the current values of the settings.
      */
-    private void revertCommit(final InputTransaction inputTransaction) {
+    private void revertCommit(final InputTransaction inputTransaction,
+            final SettingsValues settingsValues) {
         final CharSequence originallyTypedWord = mLastComposedWord.mTypedWord;
+        final String originallyTypedWordString =
+                originallyTypedWord != null ? originallyTypedWord.toString() : "";
         final CharSequence committedWord = mLastComposedWord.mCommittedWord;
         final String committedWordString = committedWord.toString();
         final int cancelLength = committedWord.length();
+        final String separatorString = mLastComposedWord.mSeparatorString;
         // We want java chars, not codepoints for the following.
-        final int separatorLength = mLastComposedWord.mSeparatorString.length();
+        final int separatorLength = separatorString.length();
         // TODO: should we check our saved separator against the actual contents of the text view?
         final int deleteLength = cancelLength + separatorLength;
         if (DebugFlags.DEBUG_ENABLED) {
@@ -1628,7 +1604,7 @@
         if (!TextUtils.isEmpty(committedWord)) {
             mDictionaryFacilitator.removeWordFromPersonalizedDicts(committedWordString);
         }
-        final String stringToCommit = originallyTypedWord + mLastComposedWord.mSeparatorString;
+        final String stringToCommit = originallyTypedWord + separatorString;
         final SpannableString textToCommit = new SpannableString(stringToCommit);
         if (committedWord instanceof SpannableString) {
             final SpannableString committedWordWithSuggestionSpans = (SpannableString)committedWord;
@@ -1665,23 +1641,53 @@
                     suggestions.toArray(new String[suggestions.size()]), 0 /* flags */),
                     0 /* start */, lastCharIndex /* end */, 0 /* flags */);
         }
+
+        final boolean shouldShowAddToDictionaryForTypedWord =
+                shouldShowAddToDictionaryForTypedWord(mLastComposedWord, settingsValues);
+
         if (inputTransaction.mSettingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces) {
             // For languages with spaces, we revert to the typed string, but the cursor is still
             // after the separator so we don't resume suggestions. If the user wants to correct
             // the word, they have to press backspace again.
-            mConnection.commitText(textToCommit, 1);
+            if (shouldShowAddToDictionaryForTypedWord) {
+                mConnection.commitTextWithBackgroundColor(textToCommit, 1,
+                        settingsValues.mTextHighlightColorForAddToDictionaryIndicator,
+                        originallyTypedWordString.length());
+            } else {
+                mConnection.commitText(textToCommit, 1);
+            }
         } else {
             // For languages without spaces, we revert the typed string but the cursor is flush
             // with the typed word, so we need to resume suggestions right away.
             final int[] codePoints = StringUtils.toCodePointArray(stringToCommit);
             mWordComposer.setComposingWord(codePoints,
                     mLatinIME.getCoordinatesForCurrentKeyboard(codePoints));
-            setComposingTextInternal(textToCommit, 1);
+            if (shouldShowAddToDictionaryForTypedWord) {
+                setComposingTextInternalWithBackgroundColor(textToCommit, 1,
+                        settingsValues.mTextHighlightColorForAddToDictionaryIndicator,
+                        originallyTypedWordString.length());
+            } else {
+                setComposingTextInternal(textToCommit, 1);
+            }
         }
         // Don't restart suggestion yet. We'll restart if the user deletes the separator.
         mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
-        // We have a separator between the word and the cursor: we should show predictions.
-        inputTransaction.setRequiresUpdateSuggestions();
+
+        if (shouldShowAddToDictionaryForTypedWord) {
+            // Due to the API limitation as of L, we cannot reliably retrieve the reverted text
+            // when the separator causes line breaking. Until this API limitation is addressed in
+            // the framework, show the indicator only when the separator doesn't contain
+            // line-breaking characters.
+            if (!StringUtils.hasLineBreakCharacter(separatorString)) {
+                mTextDecorator.showAddToDictionaryIndicator(originallyTypedWordString,
+                        mConnection.getExpectedSelectionStart(),
+                        mConnection.getExpectedSelectionEnd());
+            }
+            mSuggestionStripViewAccessor.showAddToDictionaryHint(originallyTypedWordString);
+        } else {
+            // We have a separator between the word and the cursor: we should show predictions.
+            inputTransaction.setRequiresUpdateSuggestions();
+        }
     }
 
     /**
@@ -2003,6 +2009,8 @@
             final int indexOfLastSpace = batchInputText.lastIndexOf(Constants.CODE_SPACE) + 1;
             if (0 != indexOfLastSpace) {
                 mConnection.commitText(batchInputText.substring(0, indexOfLastSpace), 1);
+                StatsUtils.onWordCommitUserTyped(
+                        batchInputText.substring(0, indexOfLastSpace), mWordComposer.isBatchMode());
                 final SuggestedWords suggestedWordsForLastWordOfPhraseGesture =
                         suggestedWords.getSuggestedWordsForLastWordOfPhraseGesture();
                 mLatinIME.showSuggestionStrip(suggestedWordsForLastWordOfPhraseGesture);
@@ -2041,8 +2049,10 @@
         if (!mWordComposer.isComposingWord()) return;
         final String typedWord = mWordComposer.getTypedWord();
         if (typedWord.length() > 0) {
+            final boolean isBatchMode = mWordComposer.isBatchMode();
             commitChosenWord(settingsValues, typedWord,
                     LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, separatorString);
+            StatsUtils.onWordCommitUserTyped(typedWord, isBatchMode);
         }
     }
 
@@ -2088,6 +2098,7 @@
                 throw new RuntimeException("We have an auto-correction but the typed word "
                         + "is empty? Impossible! I must commit suicide.");
             }
+            final boolean isBatchMode = mWordComposer.isBatchMode();
             commitChosenWord(settingsValues, autoCorrection,
                     LastComposedWord.COMMIT_TYPE_DECIDED_WORD, separator);
             if (!typedWord.equals(autoCorrection)) {
@@ -2100,39 +2111,25 @@
                 mConnection.commitCorrection(new CorrectionInfo(
                         mConnection.getExpectedSelectionEnd() - autoCorrection.length(),
                         typedWord, autoCorrection));
+                StatsUtils.onAutoCorrection(typedWord, autoCorrection, isBatchMode,
+                        mWordComposer.getAutoCorrectionDictionaryTypeOrNull());
+                StatsUtils.onWordCommitAutoCorrect(autoCorrection, isBatchMode);
+            } else {
+                StatsUtils.onWordCommitUserTyped(autoCorrection, isBatchMode);
             }
         }
     }
 
     /**
-     * Commits the chosen word to the text field and saves it for later retrieval. This is a
-     * synonym of {@code commitChosenWordWithBackgroundColor(settingsValues, chosenWord,
-     * commitType, separatorString, Color.TRANSPARENT}.
-     *
-     * @param settingsValues the current values of the settings.
-     * @param chosenWord the word we want to commit.
-     * @param commitType the type of the commit, as one of LastComposedWord.COMMIT_TYPE_*
-     * @param separatorString the separator that's causing the commit, or NOT_A_SEPARATOR if none.
-     */
-    private void commitChosenWord(final SettingsValues settingsValues, final String chosenWord,
-            final int commitType, final String separatorString) {
-        commitChosenWordWithBackgroundColor(settingsValues, chosenWord, commitType, separatorString,
-                Color.TRANSPARENT);
-    }
-
-    /**
      * Commits the chosen word to the text field and saves it for later retrieval.
      *
      * @param settingsValues the current values of the settings.
      * @param chosenWord the word we want to commit.
      * @param commitType the type of the commit, as one of LastComposedWord.COMMIT_TYPE_*
      * @param separatorString the separator that's causing the commit, or NOT_A_SEPARATOR if none.
-     * @param backgroundColor the background color to be specified with the committed text. Pass
-     * {@link Color#TRANSPARENT} to not specify the background color.
      */
-    private void commitChosenWordWithBackgroundColor(final SettingsValues settingsValues,
-            final String chosenWord, final int commitType, final String separatorString,
-            final int backgroundColor) {
+    private void commitChosenWord(final SettingsValues settingsValues, final String chosenWord,
+            final int commitType, final String separatorString) {
         final SuggestedWords suggestedWords = mSuggestedWords;
         final CharSequence chosenWordWithSuggestions =
                 SuggestionSpanUtils.getTextWithSuggestionSpan(mLatinIME, chosenWord,
@@ -2142,7 +2139,7 @@
         // information from the 1st previous word.
         final PrevWordsInfo prevWordsInfo = mConnection.getPrevWordsInfoFromNthPreviousWord(
                 settingsValues.mSpacingAndPunctuations, mWordComposer.isComposingWord() ? 2 : 1);
-        mConnection.commitTextWithBackgroundColor(chosenWordWithSuggestions, 1, backgroundColor);
+        mConnection.commitText(chosenWordWithSuggestions, 1);
         // Add the word to the user history dictionary
         performAdditionToUserHistoryDictionary(settingsValues, chosenWord, prevWordsInfo);
         // TODO: figure out here if this is an auto-correct or if the best word is actually
@@ -2226,7 +2223,7 @@
     private void setComposingTextInternal(final CharSequence newComposingText,
             final int newCursorPosition) {
         setComposingTextInternalWithBackgroundColor(newComposingText, newCursorPosition,
-                Color.TRANSPARENT);
+                Color.TRANSPARENT, newComposingText.length());
     }
 
     /**
@@ -2242,9 +2239,11 @@
      * @param newCursorPosition the new cursor position
      * @param backgroundColor the background color to be set to the composing text. Set
      * {@link Color#TRANSPARENT} to disable the background color.
+     * @param coloredTextLength the length of text, in Java chars, which should be rendered with
+     * the given background color.
      */
     private void setComposingTextInternalWithBackgroundColor(final CharSequence newComposingText,
-            final int newCursorPosition, final int backgroundColor) {
+            final int newCursorPosition, final int backgroundColor, final int coloredTextLength) {
         final CharSequence composingTextToBeSet;
         if (backgroundColor == Color.TRANSPARENT) {
             composingTextToBeSet = newComposingText;
@@ -2252,7 +2251,8 @@
             final SpannableString spannable = new SpannableString(newComposingText);
             final BackgroundColorSpan backgroundColorSpan =
                     new BackgroundColorSpan(backgroundColor);
-            spannable.setSpan(backgroundColorSpan, 0, spannable.length(),
+            final int spanLength = Math.min(coloredTextLength, spannable.length());
+            spannable.setSpan(backgroundColorSpan, 0, spanLength,
                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
             composingTextToBeSet = spannable;
         }
@@ -2274,7 +2274,8 @@
     }
 
     /**
-     * Must be called from {@link InputMethodService#onUpdateCursorAnchorInfo} is called.
+     * Must be called from {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} is
+     * called.
      * @param info The wrapper object with which we can access cursor/anchor info.
      */
     public void onUpdateCursorAnchorInfo(final CursorAnchorInfoCompatWrapper info) {
@@ -2298,12 +2299,12 @@
     }
 
     /**
-     * Returns whether the commit indicator should be shown or not.
-     * @param suggestedWords the suggested word that is being displayed.
+     * Returns whether the add to dictionary indicator should be shown or not.
+     * @param lastComposedWord the last composed word information.
      * @param settingsValues the current settings value.
      * @return {@code true} if the commit indicator should be shown.
      */
-    private boolean shouldShowCommitIndicator(final SuggestedWords suggestedWords,
+    private boolean shouldShowAddToDictionaryForTypedWord(final LastComposedWord lastComposedWord,
             final SettingsValues settingsValues) {
         if (!mConnection.isCursorAnchorInfoMonitorEnabled()) {
             // We cannot help in this case because we are heavily relying on this new API.
@@ -2312,24 +2313,16 @@
         if (!settingsValues.mShouldShowUiToAcceptTypedWord) {
             return false;
         }
-        final SuggestedWordInfo typedWordInfo = suggestedWords.getTypedWordInfoOrNull();
-        if (typedWordInfo == null) {
+        if (TextUtils.isEmpty(lastComposedWord.mTypedWord)) {
             return false;
         }
-        if (suggestedWords.mInputStyle != SuggestedWords.INPUT_STYLE_TYPING){
+        if (TextUtils.equals(lastComposedWord.mTypedWord, lastComposedWord.mCommittedWord)) {
             return false;
         }
-        if (settingsValues.mShowCommitIndicatorOnlyForAutoCorrection
-                && !suggestedWords.mWillAutoCorrect) {
+        if (!mDictionaryFacilitator.isUserDictionaryEnabled()) {
             return false;
         }
-        // TODO: Calling shouldShowAddToDictionaryHint(typedWordInfo) multiple times should be fine
-        // in terms of performance, but we can do better. One idea is to make SuggestedWords include
-        // a boolean that tells whether the word is a dictionary word or not.
-        if (settingsValues.mShowCommitIndicatorOnlyForOutOfVocabulary
-                && !shouldShowAddToDictionaryHint(typedWordInfo)) {
-            return false;
-        }
-        return true;
+        return !mDictionaryFacilitator.isValidWord(lastComposedWord.mTypedWord,
+                true /* ignoreCase */);
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java
new file mode 100644
index 0000000..06ab1e2
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java
@@ -0,0 +1,193 @@
+/*
+ * 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.latin.settings;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.text.TextUtils;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.SubtypeSwitcher;
+import com.android.inputmethod.latin.define.ProductionFlags;
+import com.android.inputmethod.latin.utils.LoginAccountUtils;
+
+import javax.annotation.Nullable;
+
+/**
+ * "Accounts & Privacy" settings sub screen.
+ *
+ * This settings sub screen handles the following preferences:
+ * <li> Account selection/management for IME
+ * <li> TODO: Sync preferences
+ * <li> TODO: Privacy preferences
+ */
+public final class AccountsSettingsFragment extends SubScreenFragment {
+    static final String PREF_ACCCOUNT_SWITCHER = "account_switcher";
+
+    private final DialogInterface.OnClickListener mAccountSelectedListener =
+            new AccountSelectedListener();
+    private final DialogInterface.OnClickListener mAccountSignedOutListener =
+            new AccountSignedOutListener();
+
+    @Override
+    public void onCreate(final Bundle icicle) {
+        super.onCreate(icicle);
+        addPreferencesFromResource(R.xml.prefs_screen_accounts);
+
+        final Resources res = getResources();
+        final Context context = getActivity();
+
+        // When we are called from the Settings application but we are not already running, some
+        // singleton and utility classes may not have been initialized.  We have to call
+        // initialization method of these classes here. See {@link LatinIME#onCreate()}.
+        SubtypeSwitcher.init(context);
+
+        if (ProductionFlags.IS_METRICS_LOGGING_SUPPORTED) {
+            final Preference enableMetricsLogging =
+                    findPreference(Settings.PREF_ENABLE_METRICS_LOGGING);
+            if (enableMetricsLogging != null) {
+                final String enableMetricsLoggingTitle = res.getString(
+                        R.string.enable_metrics_logging, getApplicationName());
+                enableMetricsLogging.setTitle(enableMetricsLoggingTitle);
+            }
+        } else {
+            removePreference(Settings.PREF_ENABLE_METRICS_LOGGING);
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        refreshAccountSelection();
+    }
+
+    @Override
+    public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
+        // TODO: Look at the preference that changed before refreshing the view.
+        refreshAccountSelection();
+    }
+
+    private void refreshAccountSelection() {
+        final String currentAccount = getCurrentlySelectedAccount();
+        final Preference accountSwitcher = findPreference(PREF_ACCCOUNT_SWITCHER);
+        if (currentAccount == null) {
+            // No account is currently selected.
+            accountSwitcher.setSummary(getString(R.string.no_accounts_selected));
+        } else {
+            // Set the currently selected account.
+            accountSwitcher.setSummary(getString(R.string.account_selected, currentAccount));
+        }
+        final Context context = getActivity();
+        final String[] accountsForLogin = LoginAccountUtils.getAccountsForLogin(context);
+        accountSwitcher.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+            @Override
+            public boolean onPreferenceClick(Preference preference) {
+                if (accountsForLogin.length == 0) {
+                    // TODO: Handle account addition.
+                    Toast.makeText(getActivity(),
+                            getString(R.string.account_select_cancel), Toast.LENGTH_SHORT).show();
+                } else {
+                    createAccountPicker(accountsForLogin, currentAccount).show();
+                }
+                return true;
+            }
+        });
+
+        // TODO: Depending on the account selection, enable/disable preferences that
+        // depend on an account.
+    }
+
+    @Nullable
+    private String getCurrentlySelectedAccount() {
+        return getSharedPreferences().getString(Settings.PREF_ACCOUNT_NAME, null);
+    }
+
+    /**
+     * Creates an account picker dialog showing the given accounts in a list and selecting
+     * the selected account by default.
+     * The list of accounts must not be null/empty.
+     *
+     * Package-private for testing.
+     */
+    AlertDialog createAccountPicker(final String[] accounts,
+            final String selectedAccount) {
+        if (accounts == null || accounts.length == 0) {
+            throw new IllegalArgumentException("List of accounts must not be empty");
+        }
+
+        // See if the currently selected account is in the list.
+        // If it is, the entry is selected, and a sign-out button is provided.
+        // If it isn't, select the 0th account by default which will get picked up
+        // if the user presses OK.
+        int index = 0;
+        boolean isSignedIn = false;
+        for (int i = 0;  i < accounts.length; i++) {
+            if (TextUtils.equals(accounts[i], selectedAccount)) {
+                index = i;
+                isSignedIn = true;
+                break;
+            }
+        }
+        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
+                .setTitle(R.string.account_select_title)
+                .setSingleChoiceItems(accounts, index, null)
+                .setPositiveButton(R.string.account_select_ok, mAccountSelectedListener)
+                .setNegativeButton(R.string.account_select_cancel, null);
+        if (isSignedIn) {
+            builder.setNeutralButton(R.string.account_select_sign_out, mAccountSignedOutListener);
+        }
+        return builder.create();
+    }
+
+    /**
+     * Listener for an account being selected from the picker.
+     * Persists the account to shared preferences.
+     */
+    class AccountSelectedListener implements DialogInterface.OnClickListener {
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            final ListView lv = ((AlertDialog)dialog).getListView();
+            final Object selectedItem = lv.getItemAtPosition(lv.getCheckedItemPosition());
+            getSharedPreferences()
+                    .edit()
+                    .putString(Settings.PREF_ACCOUNT_NAME, (String) selectedItem)
+                    .apply();
+        }
+    }
+
+    /**
+     * Listener for sign-out being initiated from from the picker.
+     * Removed the account from shared preferences.
+     */
+    class AccountSignedOutListener implements DialogInterface.OnClickListener {
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            getSharedPreferences()
+                    .edit()
+                    .remove(Settings.PREF_ACCOUNT_NAME)
+                    .apply();
+        }
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/AdvancedSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/AdvancedSettingsFragment.java
index 00f2c73..a6cb55d 100644
--- a/java/src/com/android/inputmethod/latin/settings/AdvancedSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/AdvancedSettingsFragment.java
@@ -93,14 +93,16 @@
             removePreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON);
         }
 
+        // If metrics logging isn't supported, or account sign in is enabled
+        // don't show the logging preference.
+        // TODO: Eventually when we enable account sign in by default,
+        // we'll remove logging preference from here.
         if (ProductionFlags.IS_METRICS_LOGGING_SUPPORTED) {
             final Preference enableMetricsLogging =
                     findPreference(Settings.PREF_ENABLE_METRICS_LOGGING);
             if (enableMetricsLogging != null) {
-                final int applicationLabelRes = context.getApplicationInfo().labelRes;
-                final String applicationName = res.getString(applicationLabelRes);
                 final String enableMetricsLoggingTitle = res.getString(
-                        R.string.enable_metrics_logging, applicationName);
+                        R.string.enable_metrics_logging, getApplicationName());
                 enableMetricsLogging.setTitle(enableMetricsLoggingTitle);
             }
         } else {
diff --git a/java/src/com/android/inputmethod/latin/settings/AppearanceSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/AppearanceSettingsFragment.java
index f5e4d33..a9884ba 100644
--- a/java/src/com/android/inputmethod/latin/settings/AppearanceSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/AppearanceSettingsFragment.java
@@ -19,6 +19,7 @@
 import android.os.Bundle;
 
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.define.ProductionFlags;
 
 
 /**
@@ -29,6 +30,10 @@
     public void onCreate(final Bundle icicle) {
         super.onCreate(icicle);
         addPreferencesFromResource(R.xml.prefs_screen_appearance);
+        if (!ProductionFlags.IS_SPLIT_KEYBOARD_SUPPORTED
+                || !Settings.getInstance().getCurrent().isTablet()) {
+            removePreference(Settings.PREF_ENABLE_SPLIT_KEYBOARD);
+        }
     }
 
     @Override
@@ -38,4 +43,4 @@
                 findPreference(Settings.PREF_CUSTOM_INPUT_STYLES));
         ThemeSettingsFragment.updateKeyboardThemeSummary(findPreference(Settings.SCREEN_THEME));
     }
-}
+}
\ No newline at end of file
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index 0de2d88..a171fc3 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -43,6 +43,7 @@
     private static final String TAG = Settings.class.getSimpleName();
     // Settings screens
     public static final String SCREEN_PREFERENCES = "screen_preferences";
+    public static final String SCREEN_ACCOUNTS = "screen_accounts";
     public static final String SCREEN_APPEARANCE = "screen_appearance";
     public static final String SCREEN_THEME = "screen_theme";
     public static final String SCREEN_MULTILINGUAL = "screen_multilingual";
@@ -83,6 +84,7 @@
             "pref_include_other_imes_in_language_switch_list";
     public static final String PREF_KEYBOARD_THEME = "pref_keyboard_theme";
     public static final String PREF_CUSTOM_INPUT_STYLES = "custom_input_styles";
+    public static final String PREF_ENABLE_SPLIT_KEYBOARD = "pref_split_keyboard";
     // TODO: consolidate key preview dismiss delay with the key preview animation parameters.
     public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY =
             "pref_key_preview_popup_dismiss_delay";
@@ -103,6 +105,7 @@
     public static final String PREF_KEY_IS_INTERNAL = "pref_key_is_internal";
 
     public static final String PREF_ENABLE_METRICS_LOGGING = "pref_enable_metrics_logging";
+    public static final String PREF_ACCOUNT_NAME = "pref_account_name";
 
     // This preference key is deprecated. Use {@link #PREF_SHOW_LANGUAGE_SWITCH_KEY} instead.
     // This is being used only for the backward compatibility.
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
index 4fc1738..8c48017 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
@@ -25,6 +25,7 @@
 import android.view.MenuItem;
 
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.define.ProductionFlags;
 import com.android.inputmethod.latin.utils.ApplicationUtils;
 import com.android.inputmethod.latin.utils.FeedbackUtils;
 import com.android.inputmethodcommon.InputMethodSettingsFragment;
@@ -51,6 +52,10 @@
             final Preference multilingualOptions = findPreference(Settings.SCREEN_MULTILINGUAL);
             preferenceScreen.removePreference(multilingualOptions);
         }
+        if (!ProductionFlags.ENABLE_ACCOUNT_SIGN_IN) {
+            final Preference accountsPreference = findPreference(Settings.SCREEN_ACCOUNTS);
+            preferenceScreen.removePreference(accountsPreference);
+        }
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index 270b22a..3339ab5 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -25,6 +25,7 @@
 import android.view.inputmethod.EditorInfo;
 
 import com.android.inputmethod.compat.AppWorkaroundsUtils;
+import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.InputAttributes;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.RichInputMethodManager;
@@ -79,6 +80,9 @@
     public final int mKeyLongpressTimeout;
     public final boolean mEnableMetricsLogging;
     public final boolean mShouldShowUiToAcceptTypedWord;
+    // Use split layout for keyboard.
+    public final boolean mIsSplitKeyboardEnabled;
+    public final int mScreenMetrics;
 
     // From the input box
     public final InputAttributes mInputAttributes;
@@ -98,10 +102,7 @@
             new int[AdditionalFeaturesSettingUtils.ADDITIONAL_FEATURES_SETTINGS_SIZE];
 
     // TextDecorator
-    public final int mTextHighlightColorForCommitIndicator;
     public final int mTextHighlightColorForAddToDictionaryIndicator;
-    public final boolean mShowCommitIndicatorOnlyForAutoCorrection;
-    public final boolean mShowCommitIndicatorOnlyForOutOfVocabulary;
 
     // Debug settings
     public final boolean mIsInternal;
@@ -157,6 +158,9 @@
         mDoubleSpacePeriodTimeout = res.getInteger(R.integer.config_double_space_period_timeout);
         mHasHardwareKeyboard = Settings.readHasHardwareKeyboard(res.getConfiguration());
         mEnableMetricsLogging = prefs.getBoolean(Settings.PREF_ENABLE_METRICS_LOGGING, true);
+        mIsSplitKeyboardEnabled = prefs.getBoolean(Settings.PREF_ENABLE_SPLIT_KEYBOARD, false);
+        mScreenMetrics = res.getInteger(R.integer.config_screen_metrics);
+
         mShouldShowUiToAcceptTypedWord = Settings.HAS_UI_TO_ACCEPT_TYPED_WORD
                 && prefs.getBoolean(DebugSettings.PREF_SHOW_UI_TO_ACCEPT_TYPED_WORD, true);
         // Compute other readable settings
@@ -176,12 +180,6 @@
         mSuggestionsEnabledPerUserSettings = readSuggestionsEnabled(prefs);
         AdditionalFeaturesSettingUtils.readAdditionalFeaturesPreferencesIntoArray(
                 prefs, mAdditionalFeaturesSettingValues);
-        mShowCommitIndicatorOnlyForAutoCorrection = res.getBoolean(
-                R.bool.text_decorator_only_for_auto_correction);
-        mShowCommitIndicatorOnlyForOutOfVocabulary = res.getBoolean(
-                R.bool.text_decorator_only_for_out_of_vocabulary);
-        mTextHighlightColorForCommitIndicator = res.getColor(
-                R.color.text_decorator_commit_indicator_text_highlight_color);
         mTextHighlightColorForAddToDictionaryIndicator = res.getColor(
                 R.color.text_decorator_add_to_dictionary_indicator_text_highlight_color);
         mIsInternal = Settings.isInternal(prefs);
@@ -225,6 +223,11 @@
         return mEnableMetricsLogging;
     }
 
+    public boolean isTablet() {
+        return mScreenMetrics == Constants.SCREEN_METRICS_SMALL_TABLET
+                || mScreenMetrics == Constants.SCREEN_METRICS_LARGE_TABLET;
+    }
+
     public boolean isApplicationSpecifiedCompletionsOn() {
         return mInputAttributes.mApplicationSpecifiedCompletionOn;
     }
@@ -431,12 +434,6 @@
         sb.append("" + (null == awu ? "null" : awu.toString()));
         sb.append("\n   mAdditionalFeaturesSettingValues = ");
         sb.append("" + Arrays.toString(mAdditionalFeaturesSettingValues));
-        sb.append("\n   mShowCommitIndicatorOnlyForAutoCorrection = ");
-        sb.append("" + mShowCommitIndicatorOnlyForAutoCorrection);
-        sb.append("\n   mShowCommitIndicatorOnlyForOutOfVocabulary = ");
-        sb.append("" + mShowCommitIndicatorOnlyForOutOfVocabulary);
-        sb.append("\n   mTextHighlightColorForCommitIndicator = ");
-        sb.append("" + mTextHighlightColorForCommitIndicator);
         sb.append("\n   mTextHighlightColorForAddToDictionaryIndicator = ");
         sb.append("" + mTextHighlightColorForAddToDictionaryIndicator);
         sb.append("\n   mIsInternal = ");
diff --git a/java/src/com/android/inputmethod/latin/settings/SubScreenFragment.java b/java/src/com/android/inputmethod/latin/settings/SubScreenFragment.java
index ca5b395..240f8f8 100644
--- a/java/src/com/android/inputmethod/latin/settings/SubScreenFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/SubScreenFragment.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
 import android.os.Bundle;
 import android.preference.ListPreference;
 import android.preference.Preference;
@@ -79,6 +80,16 @@
         return getPreferenceManager().getSharedPreferences();
     }
 
+    /**
+     * Gets the application name to display on the UI.
+     */
+    final String getApplicationName() {
+        final Context context = getActivity();
+        final Resources res = getResources();
+        final int applicationLabelRes = context.getApplicationInfo().labelRes;
+        return res.getString(applicationLabelRes);
+    }
+
     @Override
     public void addPreferencesFromResource(final int preferencesResId) {
         super.addPreferencesFromResource(preferencesResId);
diff --git a/java/src/com/android/inputmethod/latin/settings/TestFragmentActivity.java b/java/src/com/android/inputmethod/latin/settings/TestFragmentActivity.java
new file mode 100644
index 0000000..254bc65
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/settings/TestFragmentActivity.java
@@ -0,0 +1,55 @@
+/*
+ * 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.latin.settings;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * Test activity to use when testing preference fragments. <br/>
+ * Usage: <br/>
+ * Create an ActivityInstrumentationTestCase2 for this activity
+ * and call setIntent() with an intent that specifies the fragment to load in the activity.
+ * The fragment can then be obtained from this activity and used for testing/verification.
+ */
+public final class TestFragmentActivity extends Activity {
+    /**
+     * The fragment name that should be loaded when starting this activity.
+     * This must be specified when starting this activity, as this activity is only
+     * meant to test fragments from instrumentation tests.
+     */
+    public static final String EXTRA_SHOW_FRAGMENT = "show_fragment";
+
+    public Fragment mFragment;
+
+    @Override
+    protected void onCreate(final Bundle savedState) {
+        super.onCreate(savedState);
+        final Intent intent = getIntent();
+        final String fragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);
+        if (fragmentName == null) {
+            throw new IllegalArgumentException("No fragment name specified for testing");
+        }
+
+        mFragment = Fragment.instantiate(this, fragmentName);
+        FragmentManager fragmentManager = getFragmentManager();
+        fragmentManager.beginTransaction().add(mFragment, fragmentName).commit();
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/ThemeSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/ThemeSettingsFragment.java
index 5a3fc36..29289ae 100644
--- a/java/src/com/android/inputmethod/latin/settings/ThemeSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/ThemeSettingsFragment.java
@@ -17,7 +17,6 @@
 package com.android.inputmethod.latin.settings;
 
 import android.content.Context;
-import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.os.Bundle;
 import android.preference.Preference;
@@ -32,12 +31,12 @@
  */
 public final class ThemeSettingsFragment extends SubScreenFragment
         implements OnRadioButtonClickedListener {
-    private String mSelectedThemeId;
+    private int mSelectedThemeId;
 
     static class KeyboardThemePreference extends RadioButtonPreference {
-        final String mThemeId;
+        final int mThemeId;
 
-        KeyboardThemePreference(final Context context, final String name, final String id) {
+        KeyboardThemePreference(final Context context, final String name, final int id) {
             super(context);
             setTitle(name);
             mThemeId = id;
@@ -45,14 +44,13 @@
     }
 
     static void updateKeyboardThemeSummary(final Preference pref) {
-        final Resources res = pref.getContext().getResources();
-        final SharedPreferences prefs = pref.getSharedPreferences();
-        final KeyboardTheme keyboardTheme = KeyboardTheme.getKeyboardTheme(prefs);
-        final String keyboardThemeId = String.valueOf(keyboardTheme.mThemeId);
+        final Context context = pref.getContext();
+        final Resources res = context.getResources();
+        final KeyboardTheme keyboardTheme = KeyboardTheme.getKeyboardTheme(context);
         final String[] keyboardThemeNames = res.getStringArray(R.array.keyboard_theme_names);
-        final String[] keyboardThemeIds = res.getStringArray(R.array.keyboard_theme_ids);
+        final int[] keyboardThemeIds = res.getIntArray(R.array.keyboard_theme_ids);
         for (int index = 0; index < keyboardThemeNames.length; index++) {
-            if (keyboardThemeId.equals(keyboardThemeIds[index])) {
+            if (keyboardTheme.mThemeId == keyboardThemeIds[index]) {
                 pref.setSummary(keyboardThemeNames[index]);
                 return;
             }
@@ -64,18 +62,18 @@
         super.onCreate(icicle);
         addPreferencesFromResource(R.xml.prefs_screen_theme);
         final PreferenceScreen screen = getPreferenceScreen();
+        final Context context = getActivity();
         final Resources res = getResources();
         final String[] keyboardThemeNames = res.getStringArray(R.array.keyboard_theme_names);
-        final String[] keyboardThemeIds = res.getStringArray(R.array.keyboard_theme_ids);
+        final int[] keyboardThemeIds = res.getIntArray(R.array.keyboard_theme_ids);
         for (int index = 0; index < keyboardThemeNames.length; index++) {
             final KeyboardThemePreference pref = new KeyboardThemePreference(
-                    getActivity(), keyboardThemeNames[index], keyboardThemeIds[index]);
+                    context, keyboardThemeNames[index], keyboardThemeIds[index]);
             screen.addPreference(pref);
             pref.setOnRadioButtonClickedListener(this);
         }
-        final SharedPreferences prefs = getSharedPreferences();
-        final KeyboardTheme keyboardTheme = KeyboardTheme.getKeyboardTheme(prefs);
-        mSelectedThemeId = String.valueOf(keyboardTheme.mThemeId);
+        final KeyboardTheme keyboardTheme = KeyboardTheme.getKeyboardTheme(context);
+        mSelectedThemeId = keyboardTheme.mThemeId;
     }
 
     @Override
@@ -106,7 +104,7 @@
             final Preference preference = screen.getPreference(index);
             if (preference instanceof KeyboardThemePreference) {
                 final KeyboardThemePreference pref = (KeyboardThemePreference)preference;
-                final boolean selected = mSelectedThemeId.equals(pref.mThemeId);
+                final boolean selected = (mSelectedThemeId == pref.mThemeId);
                 pref.setSelected(selected);
             }
         }
diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
index 1979080..2494787 100644
--- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
@@ -23,6 +23,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.latin.AssetFileAddress;
 import com.android.inputmethod.latin.BinaryDictionaryGetter;
 import com.android.inputmethod.latin.Constants;
@@ -382,6 +383,7 @@
         return dictList;
     }
 
+    @UsedForTesting
     public static boolean looksValidForDictionaryInsertion(final CharSequence text,
             final SpacingAndPunctuations spacingAndPunctuations) {
         if (TextUtils.isEmpty(text)) return false;
diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilter.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilter.java
index 94c6242..6fd241e 100644
--- a/java/src/com/android/inputmethod/latin/utils/DistracterFilter.java
+++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilter.java
@@ -21,6 +21,7 @@
 
 import android.view.inputmethod.InputMethodSubtype;
 
+import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.latin.PrevWordsInfo;
 
 public interface DistracterFilter {
@@ -36,6 +37,7 @@
     public boolean isDistracterToWordsInDictionaries(final PrevWordsInfo prevWordsInfo,
             final String testedWord, final Locale locale);
 
+    @UsedForTesting
     public int getWordHandlingType(final PrevWordsInfo prevWordsInfo, final String testedWord,
             final Locale locale);
 
diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
index 1db5255..f8a8453 100644
--- a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
@@ -64,9 +64,9 @@
     private final Object mLock = new Object();
 
     // If the score of the top suggestion exceeds this value, the tested word (e.g.,
-    // an OOV, a misspelling, or an in-vocabulary word) would be considered as a distractor to
+    // an OOV, a misspelling, or an in-vocabulary word) would be considered as a distracter to
     // words in dictionary. The greater the threshold is, the less likely the tested word would
-    // become a distractor, which means the tested word will be more likely to be added to
+    // become a distracter, which means the tested word will be more likely to be added to
     // the dictionary.
     private static final float DISTRACTER_WORD_SCORE_THRESHOLD = 0.4f;
 
@@ -196,7 +196,7 @@
         }
         final boolean Word = dictionaryFacilitator.isValidWord(testedWord, false /* ignoreCase */);
         if (Word) {
-            // Valid word is not a distractor.
+            // Valid word is not a distracter.
             if (DEBUG) {
                 Log.d(TAG, "isDistracter: false (valid word)");
             }
@@ -257,12 +257,12 @@
             return false;
         }
         final SuggestedWordInfo firstSuggestion = suggestionResults.first();
-        final boolean isDistractor = suggestionExceedsDistracterThreshold(
+        final boolean isDistracter = suggestionExceedsDistracterThreshold(
                 firstSuggestion, consideredWord, DISTRACTER_WORD_SCORE_THRESHOLD);
         if (DEBUG) {
-            Log.d(TAG, "isDistracter: " + isDistractor);
+            Log.d(TAG, "isDistracter: " + isDistracter);
         }
-        return isDistractor;
+        return isDistracter;
     }
 
     private static boolean suggestionExceedsDistracterThreshold(final SuggestedWordInfo suggestion,
diff --git a/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java b/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java
index c2167a7..ae2de44 100644
--- a/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java
@@ -18,6 +18,7 @@
 
 import com.android.inputmethod.dictionarypack.DictionarySettingsFragment;
 import com.android.inputmethod.latin.about.AboutPreferences;
+import com.android.inputmethod.latin.settings.AccountsSettingsFragment;
 import com.android.inputmethod.latin.settings.AdvancedSettingsFragment;
 import com.android.inputmethod.latin.settings.AppearanceSettingsFragment;
 import com.android.inputmethod.latin.settings.CorrectionSettingsFragment;
@@ -42,6 +43,7 @@
         sLatinImeFragments.add(DictionarySettingsFragment.class.getName());
         sLatinImeFragments.add(AboutPreferences.class.getName());
         sLatinImeFragments.add(PreferencesSettingsFragment.class.getName());
+        sLatinImeFragments.add(AccountsSettingsFragment.class.getName());
         sLatinImeFragments.add(AppearanceSettingsFragment.class.getName());
         sLatinImeFragments.add(ThemeSettingsFragment.class.getName());
         sLatinImeFragments.add(MultiLingualSettingsFragment.class.getName());
diff --git a/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java b/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java
index 05d1247..7955541 100644
--- a/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java
+++ b/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java
@@ -18,6 +18,7 @@
 
 import android.util.Log;
 
+import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.latin.Dictionary;
 import com.android.inputmethod.latin.DictionaryFacilitator;
 import com.android.inputmethod.latin.PrevWordsInfo;
@@ -58,12 +59,14 @@
     public final int mTimestamp;
 
     // Constructor for unigram. TODO: support shortcuts
+    @UsedForTesting
     public LanguageModelParam(final CharSequence word, final int unigramProbability,
             final int timestamp) {
         this(null /* word0 */, word, unigramProbability, Dictionary.NOT_A_PROBABILITY, timestamp);
     }
 
     // Constructor for unigram and bigram.
+    @UsedForTesting
     public LanguageModelParam(final CharSequence word0, final CharSequence word1,
             final int unigramProbability, final int bigramProbability,
             final int timestamp) {
diff --git a/java/src/com/android/inputmethod/latin/utils/PrevWordsInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/PrevWordsInfoUtils.java
index 3cd6361..5720d93 100644
--- a/java/src/com/android/inputmethod/latin/utils/PrevWordsInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/PrevWordsInfoUtils.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.latin.utils;
 
+import java.util.Arrays;
 import java.util.regex.Pattern;
 
 import com.android.inputmethod.latin.Constants;
@@ -56,6 +57,7 @@
         if (prev == null) return PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
         final String[] w = SPACE_REGEX.split(prev);
         final WordInfo[] prevWordsInfo = new WordInfo[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
+        Arrays.fill(prevWordsInfo, WordInfo.EMPTY_WORD_INFO);
         for (int i = 0; i < prevWordsInfo.length; i++) {
             final int focusedWordIndex = w.length - n - i;
             // Referring to the word after the focused word.
@@ -66,7 +68,6 @@
                     if (spacingAndPunctuations.isWordConnector(firstChar)) {
                         // The word following the focused word is starting with a word connector.
                         // TODO: Return meaningful context for this case.
-                        prevWordsInfo[i] = WordInfo.EMPTY_WORD_INFO;
                         break;
                     }
                 }
@@ -93,7 +94,6 @@
             // TODO: Return meaningful context for this case.
             if (spacingAndPunctuations.isWordSeparator(lastChar)
                     || spacingAndPunctuations.isWordConnector(lastChar)) {
-                prevWordsInfo[i] = WordInfo.EMPTY_WORD_INFO;
                 break;
             }
             prevWordsInfo[i] = new WordInfo(focusedWord);
diff --git a/java/src/com/android/inputmethod/latin/utils/StringUtils.java b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
index 55557de..bbcef99 100644
--- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
@@ -37,6 +37,14 @@
 
     private static final String EMPTY_STRING = "";
 
+    private static final char CHAR_LINE_FEED = 0X000A;
+    private static final char CHAR_VERTICAL_TAB = 0X000B;
+    private static final char CHAR_FORM_FEED = 0X000C;
+    private static final char CHAR_CARRIAGE_RETURN = 0X000D;
+    private static final char CHAR_NEXT_LINE = 0X0085;
+    private static final char CHAR_LINE_SEPARATOR = 0X2028;
+    private static final char CHAR_PARAGRAPH_SEPARATOR = 0X2029;
+
     private StringUtils() {
         // This utility class is not publicly instantiable.
     }
@@ -594,4 +602,30 @@
             return sb + "]";
         }
     }
+
+    /**
+     * Returns whether the last composed word contains line-breaking character (e.g. CR or LF).
+     * @param text the text to be examined.
+     * @return {@code true} if the last composed word contains line-breaking separator.
+     */
+    @UsedForTesting
+    public static boolean hasLineBreakCharacter(final String text) {
+        if (TextUtils.isEmpty(text)) {
+            return false;
+        }
+        for (int i = text.length() - 1; i >= 0; --i) {
+            final char c = text.charAt(i);
+            switch (c) {
+                case CHAR_LINE_FEED:
+                case CHAR_VERTICAL_TAB:
+                case CHAR_FORM_FEED:
+                case CHAR_CARRIAGE_RETURN:
+                case CHAR_NEXT_LINE:
+                case CHAR_LINE_SEPARATOR:
+                case CHAR_PARAGRAPH_SEPARATOR:
+                    return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
index eaa5743..d6f6442 100644
--- a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
+++ b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
@@ -22,7 +22,6 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Comparator;
-import java.util.Locale;
 import java.util.TreeSet;
 
 /**
@@ -31,14 +30,17 @@
  */
 public final class SuggestionResults extends TreeSet<SuggestedWordInfo> {
     public final ArrayList<SuggestedWordInfo> mRawSuggestions;
+    // TODO: Instead of a boolean , we may want to include the context of this suggestion results,
+    // such as {@link PrevWordsInfo}.
+    public final boolean mIsBeginningOfSentence;
     private final int mCapacity;
 
-    public SuggestionResults(final int capacity) {
-        this(sSuggestedWordInfoComparator, capacity);
+    public SuggestionResults(final int capacity, final boolean isBeginningOfSentence) {
+        this(sSuggestedWordInfoComparator, capacity, isBeginningOfSentence);
     }
 
-    public SuggestionResults(final Comparator<SuggestedWordInfo> comparator,
-            final int capacity) {
+    private SuggestionResults(final Comparator<SuggestedWordInfo> comparator,
+            final int capacity, final boolean isBeginningOfSentence) {
         super(comparator);
         mCapacity = capacity;
         if (ProductionFlags.INCLUDE_RAW_SUGGESTIONS) {
@@ -46,6 +48,7 @@
         } else {
             mRawSuggestions = null;
         }
+        mIsBeginningOfSentence = isBeginningOfSentence;
     }
 
     @Override
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 81e2ff5..688ce44 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -180,9 +180,10 @@
         jintArray yCoordinatesArray, jintArray timesArray, jintArray pointerIdsArray,
         jintArray inputCodePointsArray, jint inputSize, jintArray suggestOptions,
         jobjectArray prevWordCodePointArrays, jbooleanArray isBeginningOfSentenceArray,
-        jintArray outSuggestionCount, jintArray outCodePointsArray, jintArray outScoresArray,
-        jintArray outSpaceIndicesArray, jintArray outTypesArray,
-        jintArray outAutoCommitFirstWordConfidenceArray, jfloatArray inOutLanguageWeight) {
+        jint prevWordCount, jintArray outSuggestionCount, jintArray outCodePointsArray,
+        jintArray outScoresArray, jintArray outSpaceIndicesArray, jintArray outTypesArray,
+        jintArray outAutoCommitFirstWordConfidenceArray,
+        jfloatArray inOutWeightOfLangModelVsSpatialModel) {
     Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
     // Assign 0 to outSuggestionCount here in case of returning earlier in this method.
     JniDataUtils::putIntToArray(env, outSuggestionCount, 0 /* index */, 0);
@@ -237,42 +238,44 @@
         ASSERT(false);
         return;
     }
-    float languageWeight;
-    env->GetFloatArrayRegion(inOutLanguageWeight, 0, 1 /* len */, &languageWeight);
+    float weightOfLangModelVsSpatialModel;
+    env->GetFloatArrayRegion(inOutWeightOfLangModelVsSpatialModel, 0, 1 /* len */,
+            &weightOfLangModelVsSpatialModel);
     SuggestionResults suggestionResults(MAX_RESULTS);
     const PrevWordsInfo prevWordsInfo = JniDataUtils::constructPrevWordsInfo(env,
-            prevWordCodePointArrays, isBeginningOfSentenceArray);
+            prevWordCodePointArrays, isBeginningOfSentenceArray, prevWordCount);
     if (givenSuggestOptions.isGesture() || inputSize > 0) {
         // TODO: Use SuggestionResults to return suggestions.
         dictionary->getSuggestions(pInfo, traverseSession, xCoordinates, yCoordinates,
                 times, pointerIds, inputCodePoints, inputSize, &prevWordsInfo,
-                &givenSuggestOptions, languageWeight, &suggestionResults);
+                &givenSuggestOptions, weightOfLangModelVsSpatialModel, &suggestionResults);
     } else {
         dictionary->getPredictions(&prevWordsInfo, &suggestionResults);
     }
     suggestionResults.outputSuggestions(env, outSuggestionCount, outCodePointsArray,
             outScoresArray, outSpaceIndicesArray, outTypesArray,
-            outAutoCommitFirstWordConfidenceArray, inOutLanguageWeight);
+            outAutoCommitFirstWordConfidenceArray, inOutWeightOfLangModelVsSpatialModel);
 }
 
 static jint latinime_BinaryDictionary_getProbability(JNIEnv *env, jclass clazz, jlong dict,
         jintArray word) {
     Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
     if (!dictionary) return NOT_A_PROBABILITY;
-    const jsize wordLength = env->GetArrayLength(word);
-    int codePoints[wordLength];
-    env->GetIntArrayRegion(word, 0, wordLength, codePoints);
-    return dictionary->getProbability(codePoints, wordLength);
+    const jsize codePointCount = env->GetArrayLength(word);
+    int codePoints[codePointCount];
+    env->GetIntArrayRegion(word, 0, codePointCount, codePoints);
+    return dictionary->getProbability(CodePointArrayView(codePoints, codePointCount));
 }
 
 static jint latinime_BinaryDictionary_getMaxProbabilityOfExactMatches(
         JNIEnv *env, jclass clazz, jlong dict, jintArray word) {
     Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
     if (!dictionary) return NOT_A_PROBABILITY;
-    const jsize wordLength = env->GetArrayLength(word);
-    int codePoints[wordLength];
-    env->GetIntArrayRegion(word, 0, wordLength, codePoints);
-    return dictionary->getMaxProbabilityOfExactMatches(codePoints, wordLength);
+    const jsize codePointCount = env->GetArrayLength(word);
+    int codePoints[codePointCount];
+    env->GetIntArrayRegion(word, 0, codePointCount, codePoints);
+    return dictionary->getMaxProbabilityOfExactMatches(
+            CodePointArrayView(codePoints, codePointCount));
 }
 
 static jint latinime_BinaryDictionary_getNgramProbability(JNIEnv *env, jclass clazz,
@@ -284,8 +287,10 @@
     int wordCodePoints[wordLength];
     env->GetIntArrayRegion(word, 0, wordLength, wordCodePoints);
     const PrevWordsInfo prevWordsInfo = JniDataUtils::constructPrevWordsInfo(env,
-            prevWordCodePointArrays, isBeginningOfSentenceArray);
-    return dictionary->getNgramProbability(&prevWordsInfo, wordCodePoints, wordLength);
+            prevWordCodePointArrays, isBeginningOfSentenceArray,
+            env->GetArrayLength(prevWordCodePointArrays));
+    return dictionary->getNgramProbability(&prevWordsInfo,
+            CodePointArrayView(wordCodePoints, wordLength));
 }
 
 // Method to iterate all words in the dictionary for makedict.
@@ -340,7 +345,8 @@
             return;
         }
     }
-    const WordProperty wordProperty = dictionary->getWordProperty(wordCodePoints, codePointCount);
+    const WordProperty wordProperty = dictionary->getWordProperty(
+            CodePointArrayView(wordCodePoints, codePointCount));
     wordProperty.outputProperties(env, outCodePoints, outFlags, outProbabilityInfo,
             outBigramTargets, outBigramProbabilityInfo, outShortcutTargets,
             outShortcutProbabilities);
@@ -366,7 +372,8 @@
     // Use 1 for count to indicate the word has inputted.
     const UnigramProperty unigramProperty(isBeginningOfSentence, isNotAWord,
             isBlacklisted, probability, timestamp, 0 /* level */, 1 /* count */, &shortcuts);
-    return dictionary->addUnigramEntry(codePoints, codePointCount, &unigramProperty);
+    return dictionary->addUnigramEntry(CodePointArrayView(codePoints, codePointCount),
+            &unigramProperty);
 }
 
 static bool latinime_BinaryDictionary_removeUnigramEntry(JNIEnv *env, jclass clazz, jlong dict,
@@ -378,7 +385,7 @@
     jsize codePointCount = env->GetArrayLength(word);
     int codePoints[codePointCount];
     env->GetIntArrayRegion(word, 0, codePointCount, codePoints);
-    return dictionary->removeUnigramEntry(codePoints, codePointCount);
+    return dictionary->removeUnigramEntry(CodePointArrayView(codePoints, codePointCount));
 }
 
 static bool latinime_BinaryDictionary_addNgramEntry(JNIEnv *env, jclass clazz, jlong dict,
@@ -389,7 +396,8 @@
         return false;
     }
     const PrevWordsInfo prevWordsInfo = JniDataUtils::constructPrevWordsInfo(env,
-            prevWordCodePointArrays, isBeginningOfSentenceArray);
+            prevWordCodePointArrays, isBeginningOfSentenceArray,
+            env->GetArrayLength(prevWordCodePointArrays));
     jsize wordLength = env->GetArrayLength(word);
     int wordCodePoints[wordLength];
     env->GetIntArrayRegion(word, 0, wordLength, wordCodePoints);
@@ -409,11 +417,13 @@
         return false;
     }
     const PrevWordsInfo prevWordsInfo = JniDataUtils::constructPrevWordsInfo(env,
-            prevWordCodePointArrays, isBeginningOfSentenceArray);
-    jsize wordLength = env->GetArrayLength(word);
-    int wordCodePoints[wordLength];
-    env->GetIntArrayRegion(word, 0, wordLength, wordCodePoints);
-    return dictionary->removeNgramEntry(&prevWordsInfo, wordCodePoints, wordLength);
+            prevWordCodePointArrays, isBeginningOfSentenceArray,
+            env->GetArrayLength(prevWordCodePointArrays));
+    jsize codePointCount = env->GetArrayLength(word);
+    int wordCodePoints[codePointCount];
+    env->GetIntArrayRegion(word, 0, codePointCount, wordCodePoints);
+    return dictionary->removeNgramEntry(&prevWordsInfo,
+            CodePointArrayView(wordCodePoints, codePointCount));
 }
 
 // Returns how many language model params are processed.
@@ -484,7 +494,8 @@
         const UnigramProperty unigramProperty(false /* isBeginningOfSentence */, isNotAWord,
                 isBlacklisted, unigramProbability, timestamp, 0 /* level */, 1 /* count */,
                 &shortcuts);
-        dictionary->addUnigramEntry(word1CodePoints, word1Length, &unigramProperty);
+        dictionary->addUnigramEntry(CodePointArrayView(word1CodePoints, word1Length),
+                &unigramProperty);
         if (word0) {
             jint bigramProbability = env->GetIntField(languageModelParam, bigramProbabilityFieldId);
             const std::vector<int> bigramTargetCodePoints(
@@ -568,8 +579,8 @@
     // Add unigrams.
     do {
         token = dictionary->getNextWordAndNextToken(token, wordCodePoints, &wordCodePointCount);
-        const WordProperty wordProperty = dictionary->getWordProperty(wordCodePoints,
-                wordCodePointCount);
+        const WordProperty wordProperty = dictionary->getWordProperty(
+                CodePointArrayView(wordCodePoints, wordCodePointCount));
         if (wordCodePoints[0] == CODE_POINT_BEGINNING_OF_SENTENCE) {
             // Skip beginning-of-sentence unigram.
             continue;
@@ -593,8 +604,8 @@
     // Add bigrams.
     do {
         token = dictionary->getNextWordAndNextToken(token, wordCodePoints, &wordCodePointCount);
-        const WordProperty wordProperty = dictionary->getWordProperty(wordCodePoints,
-                wordCodePointCount);
+        const WordProperty wordProperty = dictionary->getWordProperty(
+                CodePointArrayView(wordCodePoints, wordCodePointCount));
         if (dictionaryStructureWithBufferPolicy->needsToRunGC(true /* mindsBlockByGC */)) {
             dictionaryStructureWithBufferPolicy = runGCAndGetNewStructurePolicy(
                     std::move(dictionaryStructureWithBufferPolicy), dictFilePathChars);
@@ -661,7 +672,7 @@
     },
     {
         const_cast<char *>("getSuggestionsNative"),
-        const_cast<char *>("(JJJ[I[I[I[I[II[I[[I[Z[I[I[I[I[I[I[F)V"),
+        const_cast<char *>("(JJJ[I[I[I[I[II[I[[I[ZI[I[I[I[I[I[I[F)V"),
         reinterpret_cast<void *>(latinime_BinaryDictionary_getSuggestions)
     },
     {
diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h
index 57e1888..e55c9eb 100644
--- a/native/jni/src/defines.h
+++ b/native/jni/src/defines.h
@@ -301,7 +301,7 @@
 #define NOT_A_DICT_POS (S_INT_MIN)
 #define NOT_A_WORD_ID (S_INT_MIN)
 #define NOT_A_TIMESTAMP (-1)
-#define NOT_A_LANGUAGE_WEIGHT (-1.0f)
+#define NOT_A_WEIGHT_OF_LANG_MODEL_VS_SPATIAL_MODEL (-1.0f)
 
 // A special value to mean the first word confidence makes no sense in this case,
 // e.g. this is not a multi-word suggestion.
@@ -338,7 +338,7 @@
 #define MAX_POINTER_COUNT_G 2
 
 // (MAX_PREV_WORD_COUNT_FOR_N_GRAM + 1)-gram is supported.
-#define MAX_PREV_WORD_COUNT_FOR_N_GRAM 1
+#define MAX_PREV_WORD_COUNT_FOR_N_GRAM 2
 
 #define DISALLOW_DEFAULT_CONSTRUCTOR(TypeName) \
   TypeName() = delete
diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h
index ec61783..5214077 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node.h
@@ -295,8 +295,9 @@
     }
 
     // Used to prune nodes
-    float getCompoundDistance(const float languageWeight) const {
-        return mDicNodeState.mDicNodeStateScoring.getCompoundDistance(languageWeight);
+    float getCompoundDistance(const float weightOfLangModelVsSpatialModel) const {
+        return mDicNodeState.mDicNodeStateScoring.getCompoundDistance(
+                weightOfLangModelVsSpatialModel);
     }
 
     AK_FORCE_INLINE const int *getOutputWordBuf() const {
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 c19d48e..3a54c25 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
@@ -103,8 +103,10 @@
         return getCompoundDistance(1.0f);
     }
 
-    float getCompoundDistance(const float languageWeight) const {
-        return mSpatialDistance + mLanguageDistance * languageWeight;
+    float getCompoundDistance(
+            const float weightOfLangModelVsSpatialModel) const {
+        return mSpatialDistance
+                + mLanguageDistance * weightOfLangModelVsSpatialModel;
     }
 
     float getNormalizedCompoundDistance() const {
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index b843791..e4084b0 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -47,14 +47,14 @@
 void Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession,
         int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints,
         int inputSize, const PrevWordsInfo *const prevWordsInfo,
-        const SuggestOptions *const suggestOptions, const float languageWeight,
+        const SuggestOptions *const suggestOptions, const float weightOfLangModelVsSpatialModel,
         SuggestionResults *const outSuggestionResults) const {
     TimeKeeper::setCurrentTime();
     traverseSession->init(this, prevWordsInfo, suggestOptions);
     const auto &suggest = suggestOptions->isGesture() ? mGestureSuggest : mTypingSuggest;
     suggest->getSuggestions(proximityInfo, traverseSession, xcoordinates,
             ycoordinates, times, pointerIds, inputCodePoints, inputSize,
-            languageWeight, outSuggestionResults);
+            weightOfLangModelVsSpatialModel, outSuggestionResults);
     if (DEBUG_DICT) {
         outSuggestionResults->dumpSuggestions();
     }
@@ -102,21 +102,21 @@
     mDictionaryStructureWithBufferPolicy->iterateNgramEntries(prevWordIds, &listener);
 }
 
-int Dictionary::getProbability(const int *word, int length) const {
-    return getNgramProbability(nullptr /* prevWordsInfo */, word, length);
+int Dictionary::getProbability(const CodePointArrayView codePoints) const {
+    return getNgramProbability(nullptr /* prevWordsInfo */, codePoints);
 }
 
-int Dictionary::getMaxProbabilityOfExactMatches(const int *word, int length) const {
+int Dictionary::getMaxProbabilityOfExactMatches(const CodePointArrayView codePoints) const {
     TimeKeeper::setCurrentTime();
     return DictionaryUtils::getMaxProbabilityOfExactMatches(
-            mDictionaryStructureWithBufferPolicy.get(), word, length);
+            mDictionaryStructureWithBufferPolicy.get(), codePoints);
 }
 
-int Dictionary::getNgramProbability(const PrevWordsInfo *const prevWordsInfo, const int *word,
-        int length) const {
+int Dictionary::getNgramProbability(const PrevWordsInfo *const prevWordsInfo,
+        const CodePointArrayView codePoints) const {
     TimeKeeper::setCurrentTime();
-    int wordId = mDictionaryStructureWithBufferPolicy->getWordId(
-            CodePointArrayView(word, length), false /* forceLowerCaseSearch */);
+    const int wordId = mDictionaryStructureWithBufferPolicy->getWordId(codePoints,
+            false /* forceLowerCaseSearch */);
     if (wordId == NOT_A_WORD_ID) return NOT_A_PROBABILITY;
     if (!prevWordsInfo) {
         return getDictionaryStructurePolicy()->getProbabilityOfWord(WordIdArrayView(), wordId);
@@ -128,7 +128,7 @@
     return getDictionaryStructurePolicy()->getProbabilityOfWord(prevWordIds, wordId);
 }
 
-bool Dictionary::addUnigramEntry(const int *const word, const int length,
+bool Dictionary::addUnigramEntry(const CodePointArrayView codePoints,
         const UnigramProperty *const unigramProperty) {
     if (unigramProperty->representsBeginningOfSentence()
             && !mDictionaryStructureWithBufferPolicy->getHeaderStructurePolicy()
@@ -137,14 +137,12 @@
         return false;
     }
     TimeKeeper::setCurrentTime();
-    return mDictionaryStructureWithBufferPolicy->addUnigramEntry(CodePointArrayView(word, length),
-            unigramProperty);
+    return mDictionaryStructureWithBufferPolicy->addUnigramEntry(codePoints, unigramProperty);
 }
 
-bool Dictionary::removeUnigramEntry(const int *const codePoints, const int codePointCount) {
+bool Dictionary::removeUnigramEntry(const CodePointArrayView codePoints) {
     TimeKeeper::setCurrentTime();
-    return mDictionaryStructureWithBufferPolicy->removeUnigramEntry(
-            CodePointArrayView(codePoints, codePointCount));
+    return mDictionaryStructureWithBufferPolicy->removeUnigramEntry(codePoints);
 }
 
 bool Dictionary::addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
@@ -154,10 +152,9 @@
 }
 
 bool Dictionary::removeNgramEntry(const PrevWordsInfo *const prevWordsInfo,
-        const int *const word, const int length) {
+        const CodePointArrayView codePoints) {
     TimeKeeper::setCurrentTime();
-    return mDictionaryStructureWithBufferPolicy->removeNgramEntry(prevWordsInfo,
-            CodePointArrayView(word, length));
+    return mDictionaryStructureWithBufferPolicy->removeNgramEntry(prevWordsInfo, codePoints);
 }
 
 bool Dictionary::flush(const char *const filePath) {
@@ -182,11 +179,9 @@
             maxResultLength);
 }
 
-const WordProperty Dictionary::getWordProperty(const int *const codePoints,
-        const int codePointCount) {
+const WordProperty Dictionary::getWordProperty(const CodePointArrayView codePoints) {
     TimeKeeper::setCurrentTime();
-    return mDictionaryStructureWithBufferPolicy->getWordProperty(
-            CodePointArrayView(codePoints, codePointCount));
+    return mDictionaryStructureWithBufferPolicy->getWordProperty(codePoints);
 }
 
 int Dictionary::getNextWordAndNextToken(const int token, int *const outCodePoints,
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h
index 0b54f30..324e350 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary.h
@@ -66,29 +66,29 @@
     void getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession,
             int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints,
             int inputSize, const PrevWordsInfo *const prevWordsInfo,
-            const SuggestOptions *const suggestOptions, const float languageWeight,
+            const SuggestOptions *const suggestOptions, const float weightOfLangModelVsSpatialModel,
             SuggestionResults *const outSuggestionResults) const;
 
     void getPredictions(const PrevWordsInfo *const prevWordsInfo,
             SuggestionResults *const outSuggestionResults) const;
 
-    int getProbability(const int *word, int length) const;
+    int getProbability(const CodePointArrayView codePoints) const;
 
-    int getMaxProbabilityOfExactMatches(const int *word, int length) const;
+    int getMaxProbabilityOfExactMatches(const CodePointArrayView codePoints) const;
 
     int getNgramProbability(const PrevWordsInfo *const prevWordsInfo,
-            const int *word, int length) const;
+            const CodePointArrayView codePoints) const;
 
-    bool addUnigramEntry(const int *const codePoints, const int codePointCount,
+    bool addUnigramEntry(const CodePointArrayView codePoints,
             const UnigramProperty *const unigramProperty);
 
-    bool removeUnigramEntry(const int *const codePoints, const int codePointCount);
+    bool removeUnigramEntry(const CodePointArrayView codePoints);
 
     bool addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
             const BigramProperty *const bigramProperty);
 
-    bool removeNgramEntry(const PrevWordsInfo *const prevWordsInfo, const int *const word,
-            const int length);
+    bool removeNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+            const CodePointArrayView codePoints);
 
     bool flush(const char *const filePath);
 
@@ -99,7 +99,7 @@
     void getProperty(const char *const query, const int queryLength, char *const outResult,
             const int maxResultLength);
 
-    const WordProperty getWordProperty(const int *const codePoints, const int codePointCount);
+    const WordProperty getWordProperty(const CodePointArrayView codePoints);
 
     // Method to iterate all words in the dictionary.
     // The returned token has to be used to get the next word. If token is 0, this method newly
diff --git a/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp b/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp
index d09266e..b85f362 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp
@@ -29,7 +29,7 @@
 
 /* static */ int DictionaryUtils::getMaxProbabilityOfExactMatches(
         const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy,
-        const int *const codePoints, const int codePointCount) {
+        const CodePointArrayView codePoints) {
     std::vector<DicNode> current;
     std::vector<DicNode> next;
 
@@ -40,16 +40,16 @@
             dictionaryStructurePolicy, &prevWordIdArray, false /* tryLowerCaseSearch */);
     current.emplace_back();
     DicNodeUtils::initAsRoot(dictionaryStructurePolicy, prevWordIds, &current.front());
-    for (int i = 0; i < codePointCount; ++i) {
+    for (const int codePoint : codePoints) {
         // The base-lower input is used to ignore case errors and accent errors.
-        const int codePoint = CharUtils::toBaseLowerCase(codePoints[i]);
+        const int baseLowerCodePoint = CharUtils::toBaseLowerCase(codePoint);
         for (const DicNode &dicNode : current) {
-            if (dicNode.isInDigraph() && dicNode.getNodeCodePoint() == codePoint) {
+            if (dicNode.isInDigraph() && dicNode.getNodeCodePoint() == baseLowerCodePoint) {
                 next.emplace_back(dicNode);
                 next.back().advanceDigraphIndex();
                 continue;
             }
-            processChildDicNodes(dictionaryStructurePolicy, codePoint, &dicNode, &next);
+            processChildDicNodes(dictionaryStructurePolicy, baseLowerCodePoint, &dicNode, &next);
         }
         current.clear();
         current.swap(next);
diff --git a/native/jni/src/suggest/core/dictionary/dictionary_utils.h b/native/jni/src/suggest/core/dictionary/dictionary_utils.h
index 358ebf6..4dd21c9 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary_utils.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary_utils.h
@@ -20,6 +20,7 @@
 #include <vector>
 
 #include "defines.h"
+#include "utils/int_array_view.h"
 
 namespace latinime {
 
@@ -30,7 +31,7 @@
  public:
     static int getMaxProbabilityOfExactMatches(
             const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy,
-            const int *const codePoints, const int codePointCount);
+            const CodePointArrayView codePoints);
 
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(DictionaryUtils);
diff --git a/native/jni/src/suggest/core/policy/scoring.h b/native/jni/src/suggest/core/policy/scoring.h
index 9e75cac..ce3684a 100644
--- a/native/jni/src/suggest/core/policy/scoring.h
+++ b/native/jni/src/suggest/core/policy/scoring.h
@@ -32,9 +32,11 @@
             const ErrorTypeUtils::ErrorType containedErrorTypes, const bool forceCommit,
             const bool boostExactMatches) const = 0;
     virtual void getMostProbableString(const DicTraverseSession *const traverseSession,
-            const float languageWeight, SuggestionResults *const outSuggestionResults) const = 0;
-    virtual float getAdjustedLanguageWeight(DicTraverseSession *const traverseSession,
-            DicNode *const terminals, const int size) const = 0;
+            const float weightOfLangModelVsSpatialModel,
+            SuggestionResults *const outSuggestionResults) const = 0;
+    virtual float getAdjustedWeightOfLangModelVsSpatialModel(
+            DicTraverseSession *const traverseSession, DicNode *const terminals,
+            const int size) const = 0;
     virtual float getDoubleLetterDemotionDistanceCost(
             const DicNode *const terminalDicNode) const = 0;
     virtual bool autoCorrectsToMultiWordSuggestionIfTop() const = 0;
diff --git a/native/jni/src/suggest/core/result/suggestion_results.cpp b/native/jni/src/suggest/core/result/suggestion_results.cpp
index 4c10bd0..3756d10 100644
--- a/native/jni/src/suggest/core/result/suggestion_results.cpp
+++ b/native/jni/src/suggest/core/result/suggestion_results.cpp
@@ -23,7 +23,7 @@
 void SuggestionResults::outputSuggestions(JNIEnv *env, jintArray outSuggestionCount,
         jintArray outputCodePointsArray, jintArray outScoresArray, jintArray outSpaceIndicesArray,
         jintArray outTypesArray, jintArray outAutoCommitFirstWordConfidenceArray,
-        jfloatArray outLanguageWeight) {
+        jfloatArray outWeightOfLangModelVsSpatialModel) {
     int outputIndex = 0;
     while (!mSuggestedWords.empty()) {
         const SuggestedWord &suggestedWord = mSuggestedWords.top();
@@ -44,7 +44,8 @@
         mSuggestedWords.pop();
     }
     JniDataUtils::putIntToArray(env, outSuggestionCount, 0 /* index */, outputIndex);
-    JniDataUtils::putFloatToArray(env, outLanguageWeight, 0 /* index */, mLanguageWeight);
+    JniDataUtils::putFloatToArray(env, outWeightOfLangModelVsSpatialModel, 0 /* index */,
+            mWeightOfLangModelVsSpatialModel);
 }
 
 void SuggestionResults::addPrediction(const int *const codePoints, const int codePointCount,
@@ -89,7 +90,7 @@
 }
 
 void SuggestionResults::dumpSuggestions() const {
-    AKLOGE("language weight: %f", mLanguageWeight);
+    AKLOGE("weight of language model vs spatial model: %f", mWeightOfLangModelVsSpatialModel);
     std::vector<SuggestedWord> suggestedWords;
     auto copyOfSuggestedWords = mSuggestedWords;
     while (!copyOfSuggestedWords.empty()) {
diff --git a/native/jni/src/suggest/core/result/suggestion_results.h b/native/jni/src/suggest/core/result/suggestion_results.h
index 8e845e2..738c78a 100644
--- a/native/jni/src/suggest/core/result/suggestion_results.h
+++ b/native/jni/src/suggest/core/result/suggestion_results.h
@@ -29,13 +29,15 @@
 class SuggestionResults {
  public:
     explicit SuggestionResults(const int maxSuggestionCount)
-            : mMaxSuggestionCount(maxSuggestionCount), mLanguageWeight(NOT_A_LANGUAGE_WEIGHT),
+            : mMaxSuggestionCount(maxSuggestionCount),
+              mWeightOfLangModelVsSpatialModel(NOT_A_WEIGHT_OF_LANG_MODEL_VS_SPATIAL_MODEL),
               mSuggestedWords() {}
 
     // Returns suggestion count.
     void outputSuggestions(JNIEnv *env, jintArray outSuggestionCount, jintArray outCodePointsArray,
             jintArray outScoresArray, jintArray outSpaceIndicesArray, jintArray outTypesArray,
-            jintArray outAutoCommitFirstWordConfidenceArray, jfloatArray outLanguageWeight);
+            jintArray outAutoCommitFirstWordConfidenceArray,
+            jfloatArray outWeightOfLangModelVsSpatialModel);
     void addPrediction(const int *const codePoints, const int codePointCount, const int score);
     void addSuggestion(const int *const codePoints, const int codePointCount,
             const int score, const int type, const int indexToPartialCommit,
@@ -43,8 +45,8 @@
     void getSortedScores(int *const outScores) const;
     void dumpSuggestions() const;
 
-    void setLanguageWeight(const float languageWeight) {
-        mLanguageWeight = languageWeight;
+    void setWeightOfLangModelVsSpatialModel(const float weightOfLangModelVsSpatialModel) {
+        mWeightOfLangModelVsSpatialModel = weightOfLangModelVsSpatialModel;
     }
 
     int getSuggestionCount() const {
@@ -55,7 +57,7 @@
     DISALLOW_IMPLICIT_CONSTRUCTORS(SuggestionResults);
 
     const int mMaxSuggestionCount;
-    float mLanguageWeight;
+    float mWeightOfLangModelVsSpatialModel;
     std::priority_queue<
             SuggestedWord, std::vector<SuggestedWord>, SuggestedWord::Comparator> mSuggestedWords;
 };
diff --git a/native/jni/src/suggest/core/result/suggestions_output_utils.cpp b/native/jni/src/suggest/core/result/suggestions_output_utils.cpp
index 6e01937..3283f6d 100644
--- a/native/jni/src/suggest/core/result/suggestions_output_utils.cpp
+++ b/native/jni/src/suggest/core/result/suggestions_output_utils.cpp
@@ -34,7 +34,8 @@
 
 /* static */ void SuggestionsOutputUtils::outputSuggestions(
         const Scoring *const scoringPolicy, DicTraverseSession *traverseSession,
-        const float languageWeight, SuggestionResults *const outSuggestionResults) {
+        const float weightOfLangModelVsSpatialModel,
+        SuggestionResults *const outSuggestionResults) {
 #if DEBUG_EVALUATE_MOST_PROBABLE_STRING
     const int terminalSize = 0;
 #else
@@ -44,12 +45,15 @@
     for (int index = terminalSize - 1; index >= 0; --index) {
         traverseSession->getDicTraverseCache()->popTerminal(&terminals[index]);
     }
-    // Compute a language weight when an invalid language weight is passed.
-    // NOT_A_LANGUAGE_WEIGHT (-1) is assumed as an invalid language weight.
-    const float languageWeightToOutputSuggestions = (languageWeight < 0.0f) ?
-            scoringPolicy->getAdjustedLanguageWeight(
-                    traverseSession, terminals.data(), terminalSize) : languageWeight;
-    outSuggestionResults->setLanguageWeight(languageWeightToOutputSuggestions);
+    // Compute a weight of language model when an invalid weight is passed.
+    // NOT_A_WEIGHT_OF_LANG_MODEL_VS_SPATIAL_MODEL (-1) is taken as an invalid value.
+    const float weightOfLangModelVsSpatialModelToOutputSuggestions =
+            (weightOfLangModelVsSpatialModel < 0.0f)
+            ? scoringPolicy->getAdjustedWeightOfLangModelVsSpatialModel(traverseSession,
+                    terminals.data(), terminalSize)
+            : weightOfLangModelVsSpatialModel;
+    outSuggestionResults->setWeightOfLangModelVsSpatialModel(
+            weightOfLangModelVsSpatialModelToOutputSuggestions);
     // Force autocorrection for obvious long multi-word suggestions when the top suggestion is
     // a long multiple words suggestion.
     // TODO: Implement a smarter auto-commit method for handling multi-word suggestions.
@@ -65,16 +69,16 @@
     // Output suggestion results here
     for (auto &terminalDicNode : terminals) {
         outputSuggestionsOfDicNode(scoringPolicy, traverseSession, &terminalDicNode,
-                languageWeightToOutputSuggestions, boostExactMatches, forceCommitMultiWords,
-                outputSecondWordFirstLetterInputIndex, outSuggestionResults);
+                weightOfLangModelVsSpatialModelToOutputSuggestions, boostExactMatches,
+                forceCommitMultiWords, outputSecondWordFirstLetterInputIndex, outSuggestionResults);
     }
-    scoringPolicy->getMostProbableString(traverseSession, languageWeightToOutputSuggestions,
-            outSuggestionResults);
+    scoringPolicy->getMostProbableString(traverseSession,
+            weightOfLangModelVsSpatialModelToOutputSuggestions, outSuggestionResults);
 }
 
 /* static */ void SuggestionsOutputUtils::outputSuggestionsOfDicNode(
         const Scoring *const scoringPolicy, DicTraverseSession *traverseSession,
-        const DicNode *const terminalDicNode, const float languageWeight,
+        const DicNode *const terminalDicNode, const float weightOfLangModelVsSpatialModel,
         const bool boostExactMatches, const bool forceCommitMultiWords,
         const bool outputSecondWordFirstLetterInputIndex,
         SuggestionResults *const outSuggestionResults) {
@@ -83,8 +87,9 @@
     }
     const float doubleLetterCost =
             scoringPolicy->getDoubleLetterDemotionDistanceCost(terminalDicNode);
-    const float compoundDistance = terminalDicNode->getCompoundDistance(languageWeight)
-            + doubleLetterCost;
+    const float compoundDistance =
+            terminalDicNode->getCompoundDistance(weightOfLangModelVsSpatialModel)
+                    + doubleLetterCost;
     const WordAttributes wordAttributes = traverseSession->getDictionaryStructurePolicy()
             ->getWordAttributesInContext(terminalDicNode->getPrevWordIds(),
                     terminalDicNode->getWordId(), nullptr /* multiBigramMap */);
diff --git a/native/jni/src/suggest/core/result/suggestions_output_utils.h b/native/jni/src/suggest/core/result/suggestions_output_utils.h
index b099b47..bf84978 100644
--- a/native/jni/src/suggest/core/result/suggestions_output_utils.h
+++ b/native/jni/src/suggest/core/result/suggestions_output_utils.h
@@ -33,7 +33,7 @@
      * Outputs the final list of suggestions (i.e., terminal nodes).
      */
     static void outputSuggestions(const Scoring *const scoringPolicy,
-            DicTraverseSession *traverseSession, const float languageWeight,
+            DicTraverseSession *traverseSession, const float weightOfLangModelVsSpatialModel,
             SuggestionResults *const outSuggestionResults);
 
  private:
@@ -44,7 +44,7 @@
 
     static void outputSuggestionsOfDicNode(const Scoring *const scoringPolicy,
             DicTraverseSession *traverseSession, const DicNode *const terminalDicNode,
-            const float languageWeight, const bool boostExactMatches,
+            const float weightOfLangModelVsSpatialModel, const bool boostExactMatches,
             const bool forceCommitMultiWords, const bool outputSecondWordFirstLetterInputIndex,
             SuggestionResults *const outSuggestionResults);
     static void outputShortcuts(BinaryDictionaryShortcutIterator *const shortcutIt,
diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp
index 947d41f..457414f 100644
--- a/native/jni/src/suggest/core/suggest.cpp
+++ b/native/jni/src/suggest/core/suggest.cpp
@@ -45,7 +45,7 @@
  */
 void Suggest::getSuggestions(ProximityInfo *pInfo, void *traverseSession,
         int *inputXs, int *inputYs, int *times, int *pointerIds, int *inputCodePoints,
-        int inputSize, const float languageWeight,
+        int inputSize, const float weightOfLangModelVsSpatialModel,
         SuggestionResults *const outSuggestionResults) const {
     PROF_OPEN;
     PROF_START(0);
@@ -68,7 +68,7 @@
     PROF_END(1);
     PROF_START(2);
     SuggestionsOutputUtils::outputSuggestions(
-            SCORING, tSession, languageWeight, outSuggestionResults);
+            SCORING, tSession, weightOfLangModelVsSpatialModel, outSuggestionResults);
     PROF_END(2);
     PROF_CLOSE;
 }
diff --git a/native/jni/src/suggest/core/suggest.h b/native/jni/src/suggest/core/suggest.h
index 788e031..65d5918 100644
--- a/native/jni/src/suggest/core/suggest.h
+++ b/native/jni/src/suggest/core/suggest.h
@@ -49,7 +49,8 @@
     AK_FORCE_INLINE virtual ~Suggest() {}
     void getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs,
             int *times, int *pointerIds, int *inputCodePoints, int inputSize,
-            const float languageWeight, SuggestionResults *const outSuggestionResults) const;
+            const float weightOfLangModelVsSpatialModel,
+            SuggestionResults *const outSuggestionResults) const;
 
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(Suggest);
diff --git a/native/jni/src/suggest/core/suggest_interface.h b/native/jni/src/suggest/core/suggest_interface.h
index a6e5aef..a05aa9c 100644
--- a/native/jni/src/suggest/core/suggest_interface.h
+++ b/native/jni/src/suggest/core/suggest_interface.h
@@ -28,7 +28,8 @@
  public:
     virtual void getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs,
             int *inputYs, int *times, int *pointerIds, int *inputCodePoints, int inputSize,
-            const float languageWeight, SuggestionResults *const suggestionResults) const = 0;
+            const float weightOfLangModelVsSpatialModel,
+            SuggestionResults *const suggestionResults) const = 0;
     SuggestInterface() {}
     virtual ~SuggestInterface() {}
  private:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
index 87cf0cd..daf40d4 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
@@ -65,7 +65,8 @@
               mMaxUnigramCount(HeaderReadWriteUtils::readIntAttributeValue(
                       &mAttributeMap, MAX_UNIGRAM_COUNT_KEY, DEFAULT_MAX_UNIGRAM_COUNT)),
               mMaxBigramCount(HeaderReadWriteUtils::readIntAttributeValue(
-                      &mAttributeMap, MAX_BIGRAM_COUNT_KEY, DEFAULT_MAX_BIGRAM_COUNT)) {}
+                      &mAttributeMap, MAX_BIGRAM_COUNT_KEY, DEFAULT_MAX_BIGRAM_COUNT)),
+              mCodePointTable(HeaderReadWriteUtils::readCodePointTable(&mAttributeMap)) {}
 
     // Constructs header information using an attribute map.
     HeaderPolicy(const FormatUtils::FORMAT_VERSION dictFormatVersion,
@@ -97,7 +98,8 @@
               mMaxUnigramCount(HeaderReadWriteUtils::readIntAttributeValue(
                       &mAttributeMap, MAX_UNIGRAM_COUNT_KEY, DEFAULT_MAX_UNIGRAM_COUNT)),
               mMaxBigramCount(HeaderReadWriteUtils::readIntAttributeValue(
-                      &mAttributeMap, MAX_BIGRAM_COUNT_KEY, DEFAULT_MAX_BIGRAM_COUNT)) {}
+                      &mAttributeMap, MAX_BIGRAM_COUNT_KEY, DEFAULT_MAX_BIGRAM_COUNT)),
+              mCodePointTable(HeaderReadWriteUtils::readCodePointTable(&mAttributeMap)) {}
 
     // Copy header information
     HeaderPolicy(const HeaderPolicy *const headerPolicy)
@@ -118,7 +120,8 @@
               mForgettingCurveDurationToLevelDown(
                       headerPolicy->mForgettingCurveDurationToLevelDown),
               mMaxUnigramCount(headerPolicy->mMaxUnigramCount),
-              mMaxBigramCount(headerPolicy->mMaxBigramCount) {}
+              mMaxBigramCount(headerPolicy->mMaxBigramCount),
+              mCodePointTable(headerPolicy->mCodePointTable) {}
 
     // Temporary dummy header.
     HeaderPolicy()
@@ -128,7 +131,8 @@
               mDate(0), mLastDecayedTime(0), mUnigramCount(0), mBigramCount(0),
               mExtendedRegionSize(0), mHasHistoricalInfoOfWords(false),
               mForgettingCurveOccurrencesToLevelUp(0), mForgettingCurveProbabilityValuesTableId(0),
-              mForgettingCurveDurationToLevelDown(0), mMaxUnigramCount(0), mMaxBigramCount(0) {}
+              mForgettingCurveDurationToLevelDown(0), mMaxUnigramCount(0), mMaxBigramCount(0),
+              mCodePointTable(nullptr) {}
 
     ~HeaderPolicy() {}
 
@@ -139,6 +143,8 @@
         switch (mDictFormatVersion) {
             case FormatUtils::VERSION_2:
                 return FormatUtils::VERSION_2;
+            case FormatUtils::VERSION_201:
+                return FormatUtils::VERSION_201;
             case FormatUtils::VERSION_4_ONLY_FOR_TESTING:
                 return FormatUtils::VERSION_4_ONLY_FOR_TESTING;
             case FormatUtils::VERSION_4:
@@ -250,6 +256,10 @@
         return mDictFormatVersion >= FormatUtils::VERSION_4;
     }
 
+    const int *getCodePointTable() const {
+        return mCodePointTable;
+    }
+
  private:
     DISALLOW_COPY_AND_ASSIGN(HeaderPolicy);
 
@@ -295,6 +305,7 @@
     const int mForgettingCurveDurationToLevelDown;
     const int mMaxUnigramCount;
     const int mMaxBigramCount;
+    const int *const mCodePointTable;
 
     const std::vector<int> readLocale() const;
     float readMultipleWordCostMultiplier() const;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp
index d2c3d2f..41a8b13 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp
@@ -18,6 +18,7 @@
 
 #include <cctype>
 #include <cstdio>
+#include <memory>
 #include <vector>
 
 #include "defines.h"
@@ -34,12 +35,13 @@
 const int HeaderReadWriteUtils::LARGEST_INT_DIGIT_COUNT = 11;
 
 const int HeaderReadWriteUtils::MAX_ATTRIBUTE_KEY_LENGTH = 256;
-const int HeaderReadWriteUtils::MAX_ATTRIBUTE_VALUE_LENGTH = 256;
+const int HeaderReadWriteUtils::MAX_ATTRIBUTE_VALUE_LENGTH = 2048;
 
 const int HeaderReadWriteUtils::HEADER_MAGIC_NUMBER_SIZE = 4;
 const int HeaderReadWriteUtils::HEADER_DICTIONARY_VERSION_SIZE = 2;
 const int HeaderReadWriteUtils::HEADER_FLAG_SIZE = 2;
 const int HeaderReadWriteUtils::HEADER_SIZE_FIELD_SIZE = 4;
+const char *const HeaderReadWriteUtils::CODE_POINT_TABLE_KEY = "codePointTable";
 
 const HeaderReadWriteUtils::DictionaryFlags HeaderReadWriteUtils::NO_FLAGS = 0;
 
@@ -73,20 +75,32 @@
         return;
     }
     int keyBuffer[MAX_ATTRIBUTE_KEY_LENGTH];
-    int valueBuffer[MAX_ATTRIBUTE_VALUE_LENGTH];
+    std::unique_ptr<int[]> valueBuffer(new int[MAX_ATTRIBUTE_VALUE_LENGTH]);
     while (pos < headerSize) {
+        // The values in the header don't use the code point table for their encoding.
         const int keyLength = ByteArrayUtils::readStringAndAdvancePosition(dictBuf,
-                MAX_ATTRIBUTE_KEY_LENGTH, keyBuffer, &pos);
+                MAX_ATTRIBUTE_KEY_LENGTH, nullptr /* codePointTable */, keyBuffer, &pos);
         std::vector<int> key;
         key.insert(key.end(), keyBuffer, keyBuffer + keyLength);
         const int valueLength = ByteArrayUtils::readStringAndAdvancePosition(dictBuf,
-                MAX_ATTRIBUTE_VALUE_LENGTH, valueBuffer, &pos);
+                MAX_ATTRIBUTE_VALUE_LENGTH, nullptr /* codePointTable */, valueBuffer.get(), &pos);
         std::vector<int> value;
-        value.insert(value.end(), valueBuffer, valueBuffer + valueLength);
+        value.insert(value.end(), valueBuffer.get(), valueBuffer.get() + valueLength);
         headerAttributes->insert(AttributeMap::value_type(key, value));
     }
 }
 
+/* static */ const int *HeaderReadWriteUtils::readCodePointTable(
+        AttributeMap *const headerAttributes) {
+    AttributeMap::key_type keyVector;
+    insertCharactersIntoVector(CODE_POINT_TABLE_KEY, &keyVector);
+    AttributeMap::const_iterator it = headerAttributes->find(keyVector);
+    if (it == headerAttributes->end()) {
+        return nullptr;
+    }
+    return it->second.data();
+}
+
 /* static */ bool HeaderReadWriteUtils::writeDictionaryVersion(
         BufferWithExtendableBuffer *const buffer, const FormatUtils::FORMAT_VERSION version,
         int *const writingPos) {
@@ -96,7 +110,8 @@
     }
     switch (version) {
         case FormatUtils::VERSION_2:
-            // Version 2 dictionary writing is not supported.
+        case FormatUtils::VERSION_201:
+            // Version 2 or 201 dictionary writing is not supported.
             return false;
         case FormatUtils::VERSION_4_ONLY_FOR_TESTING:
         case FormatUtils::VERSION_4:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.h b/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.h
index 1ab2eec..5dd91b2 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.h
@@ -46,6 +46,9 @@
     static void fetchAllHeaderAttributes(const uint8_t *const dictBuf,
             DictionaryHeaderStructurePolicy::AttributeMap *const headerAttributes);
 
+    static const int *readCodePointTable(
+            DictionaryHeaderStructurePolicy::AttributeMap *const headerAttributes);
+
     static bool writeDictionaryVersion(BufferWithExtendableBuffer *const buffer,
             const FormatUtils::FORMAT_VERSION version, int *const writingPos);
 
@@ -101,6 +104,8 @@
     static const int HEADER_FLAG_SIZE;
     static const int HEADER_SIZE_FIELD_SIZE;
 
+    static const char *const CODE_POINT_TABLE_KEY;
+
     // Value for the "flags" field. It's unused at the moment.
     static const DictionaryFlags NO_FLAGS;
 
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.cpp
index 82399f1..5c639b1 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.cpp
@@ -23,6 +23,7 @@
 
 #include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.h"
 
+#include "suggest/policyimpl/dictionary/header/header_policy.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h"
 #include "suggest/policyimpl/dictionary/structure/backward/v402/content/probability_dict_content.h"
@@ -59,8 +60,8 @@
     const int parentPos =
             DynamicPtReadingUtils::getParentPtNodePos(parentPosOffset, headPos);
     int codePoints[MAX_WORD_LENGTH];
-    const int codePonitCount = PatriciaTrieReadingUtils::getCharsAndAdvancePosition(
-            dictBuf, flags, MAX_WORD_LENGTH, codePoints, &pos);
+    const int codePointCount = PatriciaTrieReadingUtils::getCharsAndAdvancePosition(
+            dictBuf, flags, MAX_WORD_LENGTH, mHeaderPolicy->getCodePointTable(), codePoints, &pos);
     int terminalIdFieldPos = NOT_A_DICT_POS;
     int terminalId = Ver4DictConstants::NOT_A_TERMINAL_ID;
     int probability = NOT_A_PROBABILITY;
@@ -98,7 +99,7 @@
         // The destination position is stored at the same place as the parent position.
         return fetchPtNodeInfoFromBufferAndProcessMovedPtNode(parentPos, newSiblingNodePos);
     } else {
-        return PtNodeParams(headPos, flags, parentPos, codePonitCount, codePoints,
+        return PtNodeParams(headPos, flags, parentPos, codePointCount, codePoints,
                 terminalIdFieldPos, terminalId, probability, childrenPosFieldPos, childrenPos,
                 newSiblingNodePos);
     }
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
index 41b9a11..ee14037 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
@@ -268,8 +268,8 @@
         return false;
     }
     const CodePointArrayView codePointArrayView(codePointsToAdd, codePointCountToAdd);
-    if (mUpdatingHelper.addUnigramWord(&readingHelper, codePointArrayView.data(),
-            codePointArrayView.size(), unigramProperty, &addedNewUnigram)) {
+    if (mUpdatingHelper.addUnigramWord(&readingHelper, codePointArrayView, unigramProperty,
+            &addedNewUnigram)) {
         if (addedNewUnigram && !unigramProperty->representsBeginningOfSentence()) {
             mUnigramCount++;
         }
@@ -283,8 +283,8 @@
             }
             for (const auto &shortcut : unigramProperty->getShortcuts()) {
                 if (!mUpdatingHelper.addShortcutTarget(wordPos,
-                        shortcut.getTargetCodePoints()->data(),
-                        shortcut.getTargetCodePoints()->size(), shortcut.getProbability())) {
+                        CodePointArrayView(*shortcut.getTargetCodePoints()),
+                        shortcut.getProbability())) {
                     AKLOGE("Cannot add new shortcut target. PtNodePos: %d, length: %zd, "
                             "probability: %d", wordPos, shortcut.getTargetCodePoints()->size(),
                             shortcut.getProbability());
@@ -397,7 +397,7 @@
     WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
     const WordIdArrayView prevWordIds = prevWordsInfo->getPrevWordIds(this, &prevWordIdArray,
             false /* tryLowerCaseSerch */);
-    if (prevWordIds.empty() || prevWordIds[0] == NOT_A_WORD_ID) {
+    if (prevWordIds.firstOrDefault(NOT_A_WORD_ID) == NOT_A_WORD_ID) {
         return false;
     }
     const int wordPos = getTerminalPtNodePosFromWordId(getWordId(wordCodePoints,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
index 9fa93ef..372c9e3 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
@@ -114,7 +114,8 @@
             mmappedBuffer->getReadOnlyByteArrayView());
     switch (formatVersion) {
         case FormatUtils::VERSION_2:
-            AKLOGE("Given path is a directory but the format is version 2. path: %s", path);
+        case FormatUtils::VERSION_201:
+            AKLOGE("Given path is a directory but the format is version 2 or 201. path: %s", path);
             break;
         case FormatUtils::VERSION_4: {
             return newPolicyForV4Dict<backward::v402::Ver4DictConstants,
@@ -175,6 +176,7 @@
     }
     switch (FormatUtils::detectFormatVersion(mmappedBuffer->getReadOnlyByteArrayView())) {
         case FormatUtils::VERSION_2:
+        case FormatUtils::VERSION_201:
             return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(
                     new PatriciaTriePolicy(std::move(mmappedBuffer)));
         case FormatUtils::VERSION_4_ONLY_FOR_TESTING:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp
index f7fd5c0..1b2f857 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp
@@ -39,32 +39,31 @@
         BigramListReadWriteUtils::MASK_ATTRIBUTE_PROBABILITY = 0x0F;
 
 /* static */ bool BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(
-        const uint8_t *const bigramsBuf, const int bufSize, BigramFlags *const outBigramFlags,
+        const ReadOnlyByteArrayView buffer, BigramFlags *const outBigramFlags,
         int *const outTargetPtNodePos, int *const bigramEntryPos) {
-    if (bufSize <= *bigramEntryPos) {
-        AKLOGE("Read invalid pos in getBigramEntryPropertiesAndAdvancePosition(). bufSize: %d, "
-                "bigramEntryPos: %d.", bufSize, *bigramEntryPos);
+    if (static_cast<int>(buffer.size()) <= *bigramEntryPos) {
+        AKLOGE("Read invalid pos in getBigramEntryPropertiesAndAdvancePosition(). bufSize: %zd, "
+                "bigramEntryPos: %d.", buffer.size(), *bigramEntryPos);
         return false;
     }
-    const BigramFlags bigramFlags = ByteArrayUtils::readUint8AndAdvancePosition(bigramsBuf,
+    const BigramFlags bigramFlags = ByteArrayUtils::readUint8AndAdvancePosition(buffer.data(),
             bigramEntryPos);
     if (outBigramFlags) {
         *outBigramFlags = bigramFlags;
     }
-    const int targetPos = getBigramAddressAndAdvancePosition(bigramsBuf, bigramFlags,
-            bigramEntryPos);
+    const int targetPos = getBigramAddressAndAdvancePosition(buffer, bigramFlags, bigramEntryPos);
     if (outTargetPtNodePos) {
         *outTargetPtNodePos = targetPos;
     }
     return true;
 }
 
-/* static */ bool BigramListReadWriteUtils::skipExistingBigrams(const uint8_t *const bigramsBuf,
-        const int bufSize, int *const bigramListPos) {
+/* static */ bool BigramListReadWriteUtils::skipExistingBigrams(const ReadOnlyByteArrayView buffer,
+        int *const bigramListPos) {
     BigramFlags flags;
     do {
-        if (!getBigramEntryPropertiesAndAdvancePosition(bigramsBuf, bufSize, &flags,
-                0 /* outTargetPtNodePos */, bigramListPos)) {
+        if (!getBigramEntryPropertiesAndAdvancePosition(buffer, &flags, 0 /* outTargetPtNodePos */,
+                bigramListPos)) {
             return false;
         }
     } while(hasNext(flags));
@@ -72,18 +71,18 @@
 }
 
 /* static */ int BigramListReadWriteUtils::getBigramAddressAndAdvancePosition(
-        const uint8_t *const bigramsBuf, const BigramFlags flags, int *const pos) {
+        const ReadOnlyByteArrayView buffer, const BigramFlags flags, int *const pos) {
     int offset = 0;
     const int origin = *pos;
     switch (MASK_ATTRIBUTE_ADDRESS_TYPE & flags) {
         case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
-            offset = ByteArrayUtils::readUint8AndAdvancePosition(bigramsBuf, pos);
+            offset = ByteArrayUtils::readUint8AndAdvancePosition(buffer.data(), pos);
             break;
         case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
-            offset = ByteArrayUtils::readUint16AndAdvancePosition(bigramsBuf, pos);
+            offset = ByteArrayUtils::readUint16AndAdvancePosition(buffer.data(), pos);
             break;
         case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
-            offset = ByteArrayUtils::readUint24AndAdvancePosition(bigramsBuf, pos);
+            offset = ByteArrayUtils::readUint24AndAdvancePosition(buffer.data(), pos);
             break;
     }
     if (isOffsetNegative(flags)) {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h
index 10f93fb..a0f7d5e 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h
@@ -21,6 +21,7 @@
 #include <cstdlib>
 
 #include "defines.h"
+#include "utils/byte_array_view.h"
 
 namespace latinime {
 
@@ -30,8 +31,8 @@
 public:
    typedef uint8_t BigramFlags;
 
-   static bool getBigramEntryPropertiesAndAdvancePosition(const uint8_t *const bigramsBuf,
-           const int bufSize, BigramFlags *const outBigramFlags, int *const outTargetPtNodePos,
+   static bool getBigramEntryPropertiesAndAdvancePosition(const ReadOnlyByteArrayView buffer,
+           BigramFlags *const outBigramFlags, int *const outTargetPtNodePos,
            int *const bigramEntryPos);
 
    static AK_FORCE_INLINE int getProbabilityFromFlags(const BigramFlags flags) {
@@ -43,8 +44,7 @@
    }
 
    // Bigrams reading methods
-   static bool skipExistingBigrams(const uint8_t *const bigramsBuf, const int bufSize,
-           int *const bigramListPos);
+   static bool skipExistingBigrams(const ReadOnlyByteArrayView buffer, int *const bigramListPos);
 
 private:
    DISALLOW_IMPLICIT_CONSTRUCTORS(BigramListReadWriteUtils);
@@ -61,7 +61,7 @@
        return (flags & FLAG_ATTRIBUTE_OFFSET_NEGATIVE) != 0;
    }
 
-   static int getBigramAddressAndAdvancePosition(const uint8_t *const bigramsBuf,
+   static int getBigramAddressAndAdvancePosition(const ReadOnlyByteArrayView buffer,
            const BigramFlags flags, int *const pos);
 };
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.cpp
index 086d98b..40782a4 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.cpp
@@ -218,9 +218,9 @@
 }
 
 int DynamicPtReadingHelper::getTerminalPtNodePositionOfWord(const int *const inWord,
-        const int length, const bool forceLowerCaseSearch) {
+        const size_t length, const bool forceLowerCaseSearch) {
     int searchCodePoints[length];
-    for (int i = 0; i < length; ++i) {
+    for (size_t i = 0; i < length; ++i) {
         searchCodePoints[i] = forceLowerCaseSearch ? CharUtils::toLowerCase(inWord[i]) : inWord[i];
     }
     while (!isEnd()) {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h
index b726258..9a7abc9 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h
@@ -138,12 +138,12 @@
     }
 
     // Return code point count exclude the last read node's code points.
-    AK_FORCE_INLINE int getPrevTotalCodePointCount() const {
+    AK_FORCE_INLINE size_t getPrevTotalCodePointCount() const {
         return mReadingState.mTotalCodePointCountSinceInitialization;
     }
 
     // Return code point count include the last read node's code points.
-    AK_FORCE_INLINE int getTotalCodePointCount(const PtNodeParams &ptNodeParams) const {
+    AK_FORCE_INLINE size_t getTotalCodePointCount(const PtNodeParams &ptNodeParams) const {
         return mReadingState.mTotalCodePointCountSinceInitialization
                 + ptNodeParams.getCodePointCount();
     }
@@ -214,7 +214,7 @@
     int getCodePointsAndProbabilityAndReturnCodePointCount(const int maxCodePointCount,
             int *const outCodePoints, int *const outUnigramProbability);
 
-    int getTerminalPtNodePositionOfWord(const int *const inWord, const int length,
+    int getTerminalPtNodePositionOfWord(const int *const inWord, const size_t length,
             const bool forceLowerCaseSearch);
 
  private:
@@ -234,7 +234,7 @@
         int mPos;
         // Remaining node count in the current array.
         int mRemainingPtNodeCountInThisArray;
-        int mTotalCodePointCountSinceInitialization;
+        size_t mTotalCodePointCountSinceInitialization;
         // Counter of PtNodes used to avoid infinite loops caused by broken or malicious links.
         int mTotalPtNodeIndexInThisArrayChain;
         // Counter of PtNode arrays used to avoid infinite loops caused by cyclic links of empty
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp
index 3c62e2e..3b58d7d 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp
@@ -28,17 +28,16 @@
 
 const int DynamicPtUpdatingHelper::CHILDREN_POSITION_FIELD_SIZE = 3;
 
-bool DynamicPtUpdatingHelper::addUnigramWord(
-        DynamicPtReadingHelper *const readingHelper,
-        const int *const wordCodePoints, const int codePointCount,
-        const UnigramProperty *const unigramProperty, bool *const outAddedNewUnigram) {
+bool DynamicPtUpdatingHelper::addUnigramWord(DynamicPtReadingHelper *const readingHelper,
+        const CodePointArrayView wordCodePoints, const UnigramProperty *const unigramProperty,
+        bool *const outAddedNewUnigram) {
     int parentPos = NOT_A_DICT_POS;
     while (!readingHelper->isEnd()) {
         const PtNodeParams ptNodeParams(readingHelper->getPtNodeParams());
         if (!ptNodeParams.isValid()) {
             break;
         }
-        const int matchedCodePointCount = readingHelper->getPrevTotalCodePointCount();
+        const size_t matchedCodePointCount = readingHelper->getPrevTotalCodePointCount();
         if (!readingHelper->isMatchedCodePoint(ptNodeParams, 0 /* index */,
                 wordCodePoints[matchedCodePointCount])) {
             // The first code point is different from target code point. Skip this node and read
@@ -47,26 +46,25 @@
             continue;
         }
         // Check following merged node code points.
-        const int nodeCodePointCount = ptNodeParams.getCodePointCount();
-        for (int j = 1; j < nodeCodePointCount; ++j) {
-            const int nextIndex = matchedCodePointCount + j;
-            if (nextIndex >= codePointCount || !readingHelper->isMatchedCodePoint(ptNodeParams, j,
-                    wordCodePoints[matchedCodePointCount + j])) {
+        const size_t nodeCodePointCount = ptNodeParams.getCodePointArrayView().size();
+        for (size_t j = 1; j < nodeCodePointCount; ++j) {
+            const size_t nextIndex = matchedCodePointCount + j;
+            if (nextIndex >= wordCodePoints.size()
+                    || !readingHelper->isMatchedCodePoint(ptNodeParams, j,
+                            wordCodePoints[matchedCodePointCount + j])) {
                 *outAddedNewUnigram = true;
                 return reallocatePtNodeAndAddNewPtNodes(&ptNodeParams, j, unigramProperty,
-                        wordCodePoints + matchedCodePointCount,
-                        codePointCount - matchedCodePointCount);
+                        wordCodePoints.skip(matchedCodePointCount));
             }
         }
         // All characters are matched.
-        if (codePointCount == readingHelper->getTotalCodePointCount(ptNodeParams)) {
+        if (wordCodePoints.size() == readingHelper->getTotalCodePointCount(ptNodeParams)) {
             return setPtNodeProbability(&ptNodeParams, unigramProperty, outAddedNewUnigram);
         }
         if (!ptNodeParams.hasChildren()) {
             *outAddedNewUnigram = true;
             return createChildrenPtNodeArrayAndAChildPtNode(&ptNodeParams, unigramProperty,
-                    wordCodePoints + readingHelper->getTotalCodePointCount(ptNodeParams),
-                    codePointCount - readingHelper->getTotalCodePointCount(ptNodeParams));
+                    wordCodePoints.skip(readingHelper->getTotalCodePointCount(ptNodeParams)));
         }
         // Advance to the children nodes.
         parentPos = ptNodeParams.getHeadPos();
@@ -79,9 +77,8 @@
     int pos = readingHelper->getPosOfLastForwardLinkField();
     *outAddedNewUnigram = true;
     return createAndInsertNodeIntoPtNodeArray(parentPos,
-            wordCodePoints + readingHelper->getPrevTotalCodePointCount(),
-            codePointCount - readingHelper->getPrevTotalCodePointCount(),
-            unigramProperty, &pos);
+            wordCodePoints.skip(readingHelper->getPrevTotalCodePointCount()), unigramProperty,
+            &pos);
 }
 
 bool DynamicPtUpdatingHelper::addNgramEntry(const PtNodePosArrayView prevWordsPtNodePos,
@@ -120,23 +117,21 @@
 }
 
 bool DynamicPtUpdatingHelper::addShortcutTarget(const int wordPos,
-        const int *const targetCodePoints, const int targetCodePointCount,
-        const int shortcutProbability) {
+        const CodePointArrayView targetCodePoints, const int shortcutProbability) {
     const PtNodeParams ptNodeParams(mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(wordPos));
-    return mPtNodeWriter->addShortcutTarget(&ptNodeParams, targetCodePoints, targetCodePointCount,
-            shortcutProbability);
+    return mPtNodeWriter->addShortcutTarget(&ptNodeParams, targetCodePoints.data(),
+            targetCodePoints.size(), shortcutProbability);
 }
 
 bool DynamicPtUpdatingHelper::createAndInsertNodeIntoPtNodeArray(const int parentPos,
-        const int *const nodeCodePoints, const int nodeCodePointCount,
-        const UnigramProperty *const unigramProperty, int *const forwardLinkFieldPos) {
+        const CodePointArrayView ptNodeCodePoints, const UnigramProperty *const unigramProperty,
+        int *const forwardLinkFieldPos) {
     const int newPtNodeArrayPos = mBuffer->getTailPosition();
     if (!DynamicPtWritingUtils::writeForwardLinkPositionAndAdvancePosition(mBuffer,
             newPtNodeArrayPos, forwardLinkFieldPos)) {
         return false;
     }
-    return createNewPtNodeArrayWithAChildPtNode(parentPos, nodeCodePoints, nodeCodePointCount,
-            unigramProperty);
+    return createNewPtNodeArrayWithAChildPtNode(parentPos, ptNodeCodePoints, unigramProperty);
 }
 
 bool DynamicPtUpdatingHelper::setPtNodeProbability(const PtNodeParams *const originalPtNodeParams,
@@ -153,8 +148,7 @@
         const PtNodeParams ptNodeParamsToWrite(getUpdatedPtNodeParams(originalPtNodeParams,
                 unigramProperty->isNotAWord(), unigramProperty->isBlacklisted(),
                 true /* isTerminal */, originalPtNodeParams->getParentPos(),
-                originalPtNodeParams->getCodePointCount(), originalPtNodeParams->getCodePoints(),
-                unigramProperty->getProbability()));
+                originalPtNodeParams->getCodePointArrayView(), unigramProperty->getProbability()));
         if (!mPtNodeWriter->writeNewTerminalPtNodeAndAdvancePosition(&ptNodeParamsToWrite,
                 unigramProperty, &writingPos)) {
             return false;
@@ -168,17 +162,17 @@
 
 bool DynamicPtUpdatingHelper::createChildrenPtNodeArrayAndAChildPtNode(
         const PtNodeParams *const parentPtNodeParams, const UnigramProperty *const unigramProperty,
-        const int *const codePoints, const int codePointCount) {
+        const CodePointArrayView codePoints) {
     const int newPtNodeArrayPos = mBuffer->getTailPosition();
     if (!mPtNodeWriter->updateChildrenPosition(parentPtNodeParams, newPtNodeArrayPos)) {
         return false;
     }
     return createNewPtNodeArrayWithAChildPtNode(parentPtNodeParams->getHeadPos(), codePoints,
-            codePointCount, unigramProperty);
+            unigramProperty);
 }
 
 bool DynamicPtUpdatingHelper::createNewPtNodeArrayWithAChildPtNode(
-        const int parentPtNodePos, const int *const nodeCodePoints, const int nodeCodePointCount,
+        const int parentPtNodePos, const CodePointArrayView ptNodeCodePoints,
         const UnigramProperty *const unigramProperty) {
     int writingPos = mBuffer->getTailPosition();
     if (!DynamicPtWritingUtils::writePtNodeArraySizeAndAdvancePosition(mBuffer,
@@ -187,8 +181,7 @@
     }
     const PtNodeParams ptNodeParamsToWrite(getPtNodeParamsForNewPtNode(
             unigramProperty->isNotAWord(), unigramProperty->isBlacklisted(), true /* isTerminal */,
-            parentPtNodePos, nodeCodePointCount, nodeCodePoints,
-            unigramProperty->getProbability()));
+            parentPtNodePos, ptNodeCodePoints, unigramProperty->getProbability()));
     if (!mPtNodeWriter->writeNewTerminalPtNodeAndAdvancePosition(&ptNodeParamsToWrite,
             unigramProperty, &writingPos)) {
         return false;
@@ -202,9 +195,9 @@
 
 // Returns whether the dictionary updating was succeeded or not.
 bool DynamicPtUpdatingHelper::reallocatePtNodeAndAddNewPtNodes(
-        const PtNodeParams *const reallocatingPtNodeParams, const int overlappingCodePointCount,
-        const UnigramProperty *const unigramProperty, const int *const newNodeCodePoints,
-        const int newNodeCodePointCount) {
+        const PtNodeParams *const reallocatingPtNodeParams, const size_t overlappingCodePointCount,
+        const UnigramProperty *const unigramProperty,
+        const CodePointArrayView newPtNodeCodePoints) {
     // When addsExtraChild is true, split the reallocating PtNode and add new child.
     // Reallocating PtNode: abcde, newNode: abcxy.
     // abc (1st, not terminal) __ de (2nd)
@@ -212,16 +205,18 @@
     // Otherwise, this method makes 1st part terminal and write information in unigramProperty.
     // Reallocating PtNode: abcde, newNode: abc.
     // abc (1st, terminal) __ de (2nd)
-    const bool addsExtraChild = newNodeCodePointCount > overlappingCodePointCount;
+    const bool addsExtraChild = newPtNodeCodePoints.size() > overlappingCodePointCount;
     const int firstPartOfReallocatedPtNodePos = mBuffer->getTailPosition();
     int writingPos = firstPartOfReallocatedPtNodePos;
     // Write the 1st part of the reallocating node. The children position will be updated later
     // with actual children position.
+    const CodePointArrayView firstPtNodeCodePoints =
+            reallocatingPtNodeParams->getCodePointArrayView().limit(overlappingCodePointCount);
     if (addsExtraChild) {
         const PtNodeParams ptNodeParamsToWrite(getPtNodeParamsForNewPtNode(
                 false /* isNotAWord */, false /* isBlacklisted */, false /* isTerminal */,
-                reallocatingPtNodeParams->getParentPos(), overlappingCodePointCount,
-                reallocatingPtNodeParams->getCodePoints(), NOT_A_PROBABILITY));
+                reallocatingPtNodeParams->getParentPos(), firstPtNodeCodePoints,
+                NOT_A_PROBABILITY));
         if (!mPtNodeWriter->writePtNodeAndAdvancePosition(&ptNodeParamsToWrite, &writingPos)) {
             return false;
         }
@@ -229,8 +224,7 @@
         const PtNodeParams ptNodeParamsToWrite(getPtNodeParamsForNewPtNode(
                 unigramProperty->isNotAWord(), unigramProperty->isBlacklisted(),
                 true /* isTerminal */, reallocatingPtNodeParams->getParentPos(),
-                overlappingCodePointCount, reallocatingPtNodeParams->getCodePoints(),
-                unigramProperty->getProbability()));
+                firstPtNodeCodePoints, unigramProperty->getProbability()));
         if (!mPtNodeWriter->writeNewTerminalPtNodeAndAdvancePosition(&ptNodeParamsToWrite,
                 unigramProperty, &writingPos)) {
             return false;
@@ -248,8 +242,7 @@
     const PtNodeParams childPartPtNodeParams(getUpdatedPtNodeParams(reallocatingPtNodeParams,
             reallocatingPtNodeParams->isNotAWord(), reallocatingPtNodeParams->isBlacklisted(),
             reallocatingPtNodeParams->isTerminal(), firstPartOfReallocatedPtNodePos,
-            reallocatingPtNodeParams->getCodePointCount() - overlappingCodePointCount,
-            reallocatingPtNodeParams->getCodePoints() + overlappingCodePointCount,
+            reallocatingPtNodeParams->getCodePointArrayView().skip(overlappingCodePointCount),
             reallocatingPtNodeParams->getProbability()));
     if (!mPtNodeWriter->writePtNodeAndAdvancePosition(&childPartPtNodeParams, &writingPos)) {
         return false;
@@ -258,8 +251,8 @@
         const PtNodeParams extraChildPtNodeParams(getPtNodeParamsForNewPtNode(
                 unigramProperty->isNotAWord(), unigramProperty->isBlacklisted(),
                 true /* isTerminal */, firstPartOfReallocatedPtNodePos,
-                newNodeCodePointCount - overlappingCodePointCount,
-                newNodeCodePoints + overlappingCodePointCount, unigramProperty->getProbability()));
+                newPtNodeCodePoints.skip(overlappingCodePointCount),
+                unigramProperty->getProbability()));
         if (!mPtNodeWriter->writeNewTerminalPtNodeAndAdvancePosition(&extraChildPtNodeParams,
                 unigramProperty, &writingPos)) {
             return false;
@@ -282,26 +275,24 @@
 }
 
 const PtNodeParams DynamicPtUpdatingHelper::getUpdatedPtNodeParams(
-        const PtNodeParams *const originalPtNodeParams,
-        const bool isNotAWord, const bool isBlacklisted, const bool isTerminal, const int parentPos,
-        const int codePointCount, const int *const codePoints, const int probability) const {
+        const PtNodeParams *const originalPtNodeParams, const bool isNotAWord,
+        const bool isBlacklisted, const bool isTerminal, const int parentPos,
+        const CodePointArrayView codePoints, const int probability) const {
     const PatriciaTrieReadingUtils::NodeFlags flags = PatriciaTrieReadingUtils::createAndGetFlags(
             isBlacklisted, isNotAWord, isTerminal, false /* hasShortcutTargets */,
-            false /* hasBigrams */, codePointCount > 1 /* hasMultipleChars */,
+            false /* hasBigrams */, codePoints.size() > 1u /* hasMultipleChars */,
             CHILDREN_POSITION_FIELD_SIZE);
-    return PtNodeParams(originalPtNodeParams, flags, parentPos, codePointCount, codePoints,
-            probability);
+    return PtNodeParams(originalPtNodeParams, flags, parentPos, codePoints, probability);
 }
 
-const PtNodeParams DynamicPtUpdatingHelper::getPtNodeParamsForNewPtNode(
-        const bool isNotAWord, const bool isBlacklisted, const bool isTerminal,
-        const int parentPos, const int codePointCount, const int *const codePoints,
-        const int probability) const {
+const PtNodeParams DynamicPtUpdatingHelper::getPtNodeParamsForNewPtNode(const bool isNotAWord,
+        const bool isBlacklisted, const bool isTerminal, const int parentPos,
+        const CodePointArrayView codePoints, const int probability) const {
     const PatriciaTrieReadingUtils::NodeFlags flags = PatriciaTrieReadingUtils::createAndGetFlags(
             isBlacklisted, isNotAWord, isTerminal, false /* hasShortcutTargets */,
-            false /* hasBigrams */, codePointCount > 1 /* hasMultipleChars */,
+            false /* hasBigrams */, codePoints.size() > 1u /* hasMultipleChars */,
             CHILDREN_POSITION_FIELD_SIZE);
-    return PtNodeParams(flags, parentPos, codePointCount, codePoints, probability);
+    return PtNodeParams(flags, parentPos, codePoints, probability);
 }
 
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h
index 97c05c1..710047e 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h
@@ -40,19 +40,21 @@
 
     // Add a word to the dictionary. If the word already exists, update the probability.
     bool addUnigramWord(DynamicPtReadingHelper *const readingHelper,
-            const int *const wordCodePoints, const int codePointCount,
-            const UnigramProperty *const unigramProperty, bool *const outAddedNewUnigram);
+            const CodePointArrayView wordCodePoints, const UnigramProperty *const unigramProperty,
+            bool *const outAddedNewUnigram);
 
+    // TODO: Remove after stopping supporting v402.
     // Add an n-gram entry.
     bool addNgramEntry(const PtNodePosArrayView prevWordsPtNodePos, const int wordPos,
             const BigramProperty *const bigramProperty, bool *const outAddedNewEntry);
 
+    // TODO: Remove after stopping supporting v402.
     // Remove an n-gram entry.
     bool removeNgramEntry(const PtNodePosArrayView prevWordsPtNodePos, const int wordPos);
 
     // Add a shortcut target.
-    bool addShortcutTarget(const int wordPos, const int *const targetCodePoints,
-            const int targetCodePointCount, const int shortcutProbability);
+    bool addShortcutTarget(const int wordPos, const CodePointArrayView targetCodePoints,
+            const int shortcutProbability);
 
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPtUpdatingHelper);
@@ -63,33 +65,32 @@
     const PtNodeReader *const mPtNodeReader;
     PtNodeWriter *const mPtNodeWriter;
 
-    bool createAndInsertNodeIntoPtNodeArray(const int parentPos, const int *const nodeCodePoints,
-            const int nodeCodePointCount, const UnigramProperty *const unigramProperty,
+    bool createAndInsertNodeIntoPtNodeArray(const int parentPos,
+            const CodePointArrayView ptNodeCodePoints, const UnigramProperty *const unigramProperty,
             int *const forwardLinkFieldPos);
 
     bool setPtNodeProbability(const PtNodeParams *const originalPtNodeParams,
             const UnigramProperty *const unigramProperty, bool *const outAddedNewUnigram);
 
     bool createChildrenPtNodeArrayAndAChildPtNode(const PtNodeParams *const parentPtNodeParams,
-            const UnigramProperty *const unigramProperty, const int *const codePoints,
-            const int codePointCount);
+            const UnigramProperty *const unigramProperty,
+            const CodePointArrayView remainingCodePoints);
 
-    bool createNewPtNodeArrayWithAChildPtNode(const int parentPos, const int *const nodeCodePoints,
-            const int nodeCodePointCount, const UnigramProperty *const unigramProperty);
+    bool createNewPtNodeArrayWithAChildPtNode(const int parentPos,
+            const CodePointArrayView ptNodeCodePoints,
+            const UnigramProperty *const unigramProperty);
 
-    bool reallocatePtNodeAndAddNewPtNodes(
-            const PtNodeParams *const reallocatingPtNodeParams, const int overlappingCodePointCount,
-            const UnigramProperty *const unigramProperty, const int *const newNodeCodePoints,
-            const int newNodeCodePointCount);
+    bool reallocatePtNodeAndAddNewPtNodes(const PtNodeParams *const reallocatingPtNodeParams,
+            const size_t overlappingCodePointCount, const UnigramProperty *const unigramProperty,
+            const CodePointArrayView newPtNodeCodePoints);
 
     const PtNodeParams getUpdatedPtNodeParams(const PtNodeParams *const originalPtNodeParams,
             const bool isNotAWord, const bool isBlacklisted, const bool isTerminal,
-            const int parentPos, const int codePointCount,
-            const int *const codePoints, const int probability) const;
+            const int parentPos, const CodePointArrayView codePoints, const int probability) const;
 
     const PtNodeParams getPtNodeParamsForNewPtNode(const bool isNotAWord, const bool isBlacklisted,
-            const bool isTerminal, const int parentPos,
-            const int codePointCount, const int *const codePoints, const int probability) const;
+            const bool isTerminal, const int parentPos, const CodePointArrayView codePoints,
+            const int probability) const;
 };
 } // namespace latinime
 #endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_UPDATING_HELPER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.cpp
index e64a13c..6a498b2 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.cpp
@@ -61,19 +61,20 @@
 }
 
 /* static */ int PtReadingUtils::getCodePointAndAdvancePosition(const uint8_t *const buffer,
-        int *const pos) {
-    return ByteArrayUtils::readCodePointAndAdvancePosition(buffer, pos);
+        const int *const codePointTable, int *const pos) {
+    return ByteArrayUtils::readCodePointAndAdvancePosition(buffer, codePointTable, pos);
 }
 
 // Returns the number of read characters.
 /* static */ int PtReadingUtils::getCharsAndAdvancePosition(const uint8_t *const buffer,
-        const NodeFlags flags, const int maxLength, int *const outBuffer, int *const pos) {
+        const NodeFlags flags, const int maxLength, const int *const codePointTable,
+        int *const outBuffer, int *const pos) {
     int length = 0;
     if (hasMultipleChars(flags)) {
-        length = ByteArrayUtils::readStringAndAdvancePosition(buffer, maxLength, outBuffer,
-                pos);
+        length = ByteArrayUtils::readStringAndAdvancePosition(buffer, maxLength, codePointTable,
+                outBuffer, pos);
     } else {
-        const int codePoint = getCodePointAndAdvancePosition(buffer, pos);
+        const int codePoint = getCodePointAndAdvancePosition(buffer, codePointTable, pos);
         if (codePoint == NOT_A_CODE_POINT) {
             // CAVEAT: codePoint == NOT_A_CODE_POINT means the code point is
             // CHARACTER_ARRAY_TERMINATOR. The code point must not be CHARACTER_ARRAY_TERMINATOR
@@ -92,12 +93,12 @@
 
 // Returns the number of skipped characters.
 /* static */ int PtReadingUtils::skipCharacters(const uint8_t *const buffer, const NodeFlags flags,
-        const int maxLength, int *const pos) {
+        const int maxLength, const int *const codePointTable, int *const pos) {
     if (hasMultipleChars(flags)) {
         return ByteArrayUtils::advancePositionToBehindString(buffer, maxLength, pos);
     } else {
         if (maxLength > 0) {
-            getCodePointAndAdvancePosition(buffer, pos);
+            getCodePointAndAdvancePosition(buffer, codePointTable, pos);
             return 1;
         } else {
             return 0;
@@ -134,7 +135,7 @@
 
 /* static */ void PtReadingUtils::readPtNodeInfo(const uint8_t *const dictBuf, const int ptNodePos,
         const DictionaryShortcutsStructurePolicy *const shortcutPolicy,
-        const DictionaryBigramsStructurePolicy *const bigramPolicy,
+        const DictionaryBigramsStructurePolicy *const bigramPolicy, const int *const codePointTable,
         NodeFlags *const outFlags, int *const outCodePointCount, int *const outCodePoint,
         int *const outProbability, int *const outChildrenPos, int *const outShortcutPos,
         int *const outBigramPos, int *const outSiblingPos) {
@@ -142,7 +143,7 @@
     const NodeFlags flags = getFlagsAndAdvancePosition(dictBuf, &readingPos);
     *outFlags = flags;
     *outCodePointCount = getCharsAndAdvancePosition(
-            dictBuf, flags, MAX_WORD_LENGTH, outCodePoint, &readingPos);
+            dictBuf, flags, MAX_WORD_LENGTH, codePointTable, outCodePoint, &readingPos);
     *outProbability = isTerminal(flags) ?
             readProbabilityAndAdvancePosition(dictBuf, &readingPos) : NOT_A_PROBABILITY;
     *outChildrenPos = hasChildrenInFlags(flags) ?
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h
index c3f09c3..a69ec44 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h
@@ -34,15 +34,17 @@
 
     static NodeFlags getFlagsAndAdvancePosition(const uint8_t *const buffer, int *const pos);
 
-    static int getCodePointAndAdvancePosition(const uint8_t *const buffer, int *const pos);
+    static int getCodePointAndAdvancePosition(const uint8_t *const buffer,
+            const int *const codePointTable, int *const pos);
 
     // Returns the number of read characters.
     static int getCharsAndAdvancePosition(const uint8_t *const buffer, const NodeFlags flags,
-            const int maxLength, int *const outBuffer, int *const pos);
+            const int maxLength, const int *const codePointTable, int *const outBuffer,
+            int *const pos);
 
     // Returns the number of skipped characters.
     static int skipCharacters(const uint8_t *const buffer, const NodeFlags flags,
-            const int maxLength, int *const pos);
+            const int maxLength, const int *const codePointTable, int *const pos);
 
     static int readProbabilityAndAdvancePosition(const uint8_t *const buffer, int *const pos);
 
@@ -106,9 +108,10 @@
     static void readPtNodeInfo(const uint8_t *const dictBuf, const int ptNodePos,
             const DictionaryShortcutsStructurePolicy *const shortcutPolicy,
             const DictionaryBigramsStructurePolicy *const bigramPolicy,
-            NodeFlags *const outFlags, int *const outCodePointCount, int *const outCodePoint,
-            int *const outProbability, int *const outChildrenPos, int *const outShortcutPos,
-            int *const outBigramPos, int *const outSiblingPos);
+            const int *const codePointTable, NodeFlags *const outFlags,
+            int *const outCodePointCount, int *const outCodePoint, int *const outProbability,
+            int *const outChildrenPos, int *const outShortcutPos, int *const outBigramPos,
+            int *const outSiblingPos);
 
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(PatriciaTrieReadingUtils);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h
index c12fed3..3ff1829 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h
@@ -89,9 +89,9 @@
     // Construct new params by updating existing PtNode params.
     PtNodeParams(const PtNodeParams *const ptNodeParams,
             const PatriciaTrieReadingUtils::NodeFlags flags, const int parentPos,
-            const int codePointCount, const int *const codePoints, const int probability)
+            const CodePointArrayView codePoints, const int probability)
             : mHeadPos(ptNodeParams->getHeadPos()), mFlags(flags), mHasMovedFlag(true),
-              mParentPos(parentPos), mCodePointCount(codePointCount), mCodePoints(),
+              mParentPos(parentPos), mCodePointCount(codePoints.size()), mCodePoints(),
               mTerminalIdFieldPos(ptNodeParams->getTerminalIdFieldPos()),
               mTerminalId(ptNodeParams->getTerminalId()),
               mProbabilityFieldPos(ptNodeParams->getProbabilityFieldPos()),
@@ -102,20 +102,20 @@
               mShortcutPos(ptNodeParams->getShortcutPos()),
               mBigramPos(ptNodeParams->getBigramsPos()),
               mSiblingPos(ptNodeParams->getSiblingNodePos()) {
-        memcpy(mCodePoints, codePoints, sizeof(int) * mCodePointCount);
+        memcpy(mCodePoints, codePoints.data(), sizeof(int) * mCodePointCount);
     }
 
     PtNodeParams(const PatriciaTrieReadingUtils::NodeFlags flags, const int parentPos,
-            const int codePointCount, const int *const codePoints, const int probability)
+            const CodePointArrayView codePoints, const int probability)
             : mHeadPos(NOT_A_DICT_POS), mFlags(flags), mHasMovedFlag(true), mParentPos(parentPos),
-              mCodePointCount(codePointCount), mCodePoints(),
+              mCodePointCount(codePoints.size()), mCodePoints(),
               mTerminalIdFieldPos(NOT_A_DICT_POS),
               mTerminalId(Ver4DictConstants::NOT_A_TERMINAL_ID),
               mProbabilityFieldPos(NOT_A_DICT_POS), mProbability(probability),
               mChildrenPosFieldPos(NOT_A_DICT_POS), mChildrenPos(NOT_A_DICT_POS),
               mBigramLinkedNodePos(NOT_A_DICT_POS), mShortcutPos(NOT_A_DICT_POS),
               mBigramPos(NOT_A_DICT_POS), mSiblingPos(NOT_A_DICT_POS) {
-        memcpy(mCodePoints, codePoints, sizeof(int) * mCodePointCount);
+        memcpy(mCodePoints, codePoints.data(), sizeof(int) * mCodePointCount);
     }
 
     AK_FORCE_INLINE bool isValid() const {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.cpp
index 91c7694..40b8720 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.cpp
@@ -31,21 +31,23 @@
 const int ShortcutListReadingUtils::WHITELIST_SHORTCUT_PROBABILITY = 15;
 
 /* static */ ShortcutListReadingUtils::ShortcutFlags
-        ShortcutListReadingUtils::getFlagsAndForwardPointer(const uint8_t *const dictRoot,
+        ShortcutListReadingUtils::getFlagsAndForwardPointer(const ReadOnlyByteArrayView buffer,
                 int *const pos) {
-    return ByteArrayUtils::readUint8AndAdvancePosition(dictRoot, pos);
+    return ByteArrayUtils::readUint8AndAdvancePosition(buffer.data(), pos);
 }
 
 /* static */ int ShortcutListReadingUtils::getShortcutListSizeAndForwardPointer(
-        const uint8_t *const dictRoot, int *const pos) {
+        const ReadOnlyByteArrayView buffer, int *const pos) {
     // readUint16andAdvancePosition() returns an offset *including* the uint16 field itself.
-    return ByteArrayUtils::readUint16AndAdvancePosition(dictRoot, pos)
+    return ByteArrayUtils::readUint16AndAdvancePosition(buffer.data(), pos)
             - SHORTCUT_LIST_SIZE_FIELD_SIZE;
 }
 
-/* static */ int ShortcutListReadingUtils::readShortcutTarget(
-        const uint8_t *const dictRoot, const int maxLength, int *const outWord, int *const pos) {
-    return ByteArrayUtils::readStringAndAdvancePosition(dictRoot, maxLength, outWord, pos);
+/* static */ int ShortcutListReadingUtils::readShortcutTarget(const ReadOnlyByteArrayView buffer,
+        const int maxLength, int *const outWord, int *const pos) {
+    // TODO: Use codePointTable for shortcuts.
+    return ByteArrayUtils::readStringAndAdvancePosition(buffer.data(), maxLength,
+            nullptr /* codePointTable */, outWord, pos);
 }
 
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.h
index d065bf7..71cb8cc 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.h
@@ -20,6 +20,7 @@
 #include <cstdint>
 
 #include "defines.h"
+#include "utils/byte_array_view.h"
 
 namespace latinime {
 
@@ -27,7 +28,8 @@
  public:
     typedef uint8_t ShortcutFlags;
 
-    static ShortcutFlags getFlagsAndForwardPointer(const uint8_t *const dictRoot, int *const pos);
+    static ShortcutFlags getFlagsAndForwardPointer(const ReadOnlyByteArrayView buffer,
+            int *const pos);
 
     static AK_FORCE_INLINE int getProbabilityFromFlags(const ShortcutFlags flags) {
         return flags & MASK_ATTRIBUTE_PROBABILITY;
@@ -39,14 +41,15 @@
 
     // This method returns the size of the shortcut list region excluding the shortcut list size
     // field at the beginning.
-    static int getShortcutListSizeAndForwardPointer(const uint8_t *const dictRoot, int *const pos);
+    static int getShortcutListSizeAndForwardPointer(const ReadOnlyByteArrayView buffer,
+            int *const pos);
 
     static AK_FORCE_INLINE int getShortcutListSizeFieldSize() {
         return SHORTCUT_LIST_SIZE_FIELD_SIZE;
     }
 
-    static AK_FORCE_INLINE void skipShortcuts(const uint8_t *const dictRoot, int *const pos) {
-        const int shortcutListSize = getShortcutListSizeAndForwardPointer(dictRoot, pos);
+    static AK_FORCE_INLINE void skipShortcuts(const ReadOnlyByteArrayView buffer, int *const pos) {
+        const int shortcutListSize = getShortcutListSizeAndForwardPointer(buffer, pos);
         *pos += shortcutListSize;
     }
 
@@ -54,7 +57,7 @@
         return getProbabilityFromFlags(flags) == WHITELIST_SHORTCUT_PROBABILITY;
     }
 
-    static int readShortcutTarget(const uint8_t *const dictRoot, const int maxLength,
+    static int readShortcutTarget(const ReadOnlyByteArrayView buffer, const int maxLength,
             int *const outWord, int *const pos);
 
  private:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/bigram/bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/bigram/bigram_list_policy.h
index 73e291e..e260843 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/bigram/bigram_list_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/bigram/bigram_list_policy.h
@@ -22,22 +22,22 @@
 #include "defines.h"
 #include "suggest/core/policy/dictionary_bigrams_structure_policy.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h"
+#include "utils/byte_array_view.h"
 
 namespace latinime {
 
 class BigramListPolicy : public DictionaryBigramsStructurePolicy {
  public:
-    BigramListPolicy(const uint8_t *const bigramsBuf, const int bufSize)
-            : mBigramsBuf(bigramsBuf), mBufSize(bufSize) {}
+    BigramListPolicy(const ReadOnlyByteArrayView buffer) : mBuffer(buffer) {}
 
     ~BigramListPolicy() {}
 
     void getNextBigram(int *const outBigramPos, int *const outProbability, bool *const outHasNext,
             int *const pos) const {
         BigramListReadWriteUtils::BigramFlags flags;
-        if (!BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(mBigramsBuf,
-                mBufSize, &flags, outBigramPos, pos)) {
-            AKLOGE("Cannot read bigram entry. mBufSize: %d, pos: %d. ", mBufSize, *pos);
+        if (!BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(mBuffer, &flags,
+                outBigramPos, pos)) {
+            AKLOGE("Cannot read bigram entry. bufSize: %zd, pos: %d. ", mBuffer.size(), *pos);
             *outProbability = NOT_A_PROBABILITY;
             *outHasNext = false;
             return;
@@ -47,14 +47,13 @@
     }
 
     bool skipAllBigrams(int *const pos) const {
-        return BigramListReadWriteUtils::skipExistingBigrams(mBigramsBuf, mBufSize, pos);
+        return BigramListReadWriteUtils::skipExistingBigrams(mBuffer, pos);
     }
 
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(BigramListPolicy);
 
-    const uint8_t *const mBigramsBuf;
-    const int mBufSize;
+    const ReadOnlyByteArrayView mBuffer;
 };
 } // namespace latinime
 #endif // LATINIME_BIGRAM_LIST_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp
index aae61af..6e7dba9 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp
@@ -37,19 +37,19 @@
         return;
     }
     int nextPos = dicNode->getChildrenPtNodeArrayPos();
-    if (nextPos < 0 || nextPos >= mDictBufferSize) {
-        AKLOGE("Children PtNode array position is invalid. pos: %d, dict size: %d",
-                nextPos, mDictBufferSize);
+    if (!isValidPos(nextPos)) {
+        AKLOGE("Children PtNode array position is invalid. pos: %d, dict size: %zd",
+                nextPos, mBuffer.size());
         mIsCorrupted = true;
         ASSERT(false);
         return;
     }
     const int childCount = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition(
-            mDictRoot, &nextPos);
+            mBuffer.data(), &nextPos);
     for (int i = 0; i < childCount; i++) {
-        if (nextPos < 0 || nextPos >= mDictBufferSize) {
-            AKLOGE("Child PtNode position is invalid. pos: %d, dict size: %d, childCount: %d / %d",
-                    nextPos, mDictBufferSize, i, childCount);
+        if (!isValidPos(nextPos)) {
+            AKLOGE("Child PtNode position is invalid. pos: %d, dict size: %zd, childCount: %d / %d",
+                    nextPos, mBuffer.size(), i, childCount);
             mIsCorrupted = true;
             ASSERT(false);
             return;
@@ -81,6 +81,7 @@
     const int ptNodePos = getTerminalPtNodePosFromWordId(wordId);
     int pos = getRootPosition();
     int wordPos = 0;
+    const int *const codePointTable = mHeaderPolicy.getCodePointTable();
     // One iteration of the outer loop iterates through PtNode arrays. As stated above, we will
     // only traverse PtNodes that are actually a part of the terminal we are searching, so each
     // time we enter this loop we are one depth level further than last time.
@@ -91,56 +92,57 @@
         int lastCandidatePtNodePos = 0;
         // Let's loop through PtNodes in this PtNode array searching for either the terminal
         // or one of its ascendants.
-        if (pos < 0 || pos >= mDictBufferSize) {
-            AKLOGE("PtNode array position is invalid. pos: %d, dict size: %d",
-                    pos, mDictBufferSize);
+        if (!isValidPos(pos)) {
+            AKLOGE("PtNode array position is invalid. pos: %d, dict size: %zd",
+                    pos, mBuffer.size());
             mIsCorrupted = true;
             ASSERT(false);
             *outUnigramProbability = NOT_A_PROBABILITY;
             return 0;
         }
         for (int ptNodeCount = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition(
-                mDictRoot, &pos); ptNodeCount > 0; --ptNodeCount) {
+                mBuffer.data(), &pos); ptNodeCount > 0; --ptNodeCount) {
             const int startPos = pos;
-            if (pos < 0 || pos >= mDictBufferSize) {
-                AKLOGE("PtNode position is invalid. pos: %d, dict size: %d", pos, mDictBufferSize);
+            if (!isValidPos(pos)) {
+                AKLOGE("PtNode position is invalid. pos: %d, dict size: %zd", pos, mBuffer.size());
                 mIsCorrupted = true;
                 ASSERT(false);
                 *outUnigramProbability = NOT_A_PROBABILITY;
                 return 0;
             }
             const PatriciaTrieReadingUtils::NodeFlags flags =
-                    PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
+                    PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mBuffer.data(), &pos);
             const int character = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
-                    mDictRoot, &pos);
+                    mBuffer.data(), codePointTable, &pos);
             if (ptNodePos == startPos) {
                 // We found the position. Copy the rest of the code points in the buffer and return
                 // the length.
                 outCodePoints[wordPos] = character;
                 if (PatriciaTrieReadingUtils::hasMultipleChars(flags)) {
                     int nextChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
-                            mDictRoot, &pos);
+                            mBuffer.data(), codePointTable, &pos);
                     // We count code points in order to avoid infinite loops if the file is broken
                     // or if there is some other bug
                     int charCount = maxCodePointCount;
                     while (NOT_A_CODE_POINT != nextChar && --charCount > 0) {
                         outCodePoints[++wordPos] = nextChar;
                         nextChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
-                                mDictRoot, &pos);
+                                mBuffer.data(), codePointTable, &pos);
                     }
                 }
                 *outUnigramProbability =
-                        PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot,
+                        PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mBuffer.data(),
                                 &pos);
                 return ++wordPos;
             }
             // We need to skip past this PtNode, so skip any remaining code points after the
             // first and possibly the probability.
             if (PatriciaTrieReadingUtils::hasMultipleChars(flags)) {
-                PatriciaTrieReadingUtils::skipCharacters(mDictRoot, flags, MAX_WORD_LENGTH, &pos);
+                PatriciaTrieReadingUtils::skipCharacters(mBuffer.data(), flags, MAX_WORD_LENGTH,
+                        codePointTable, &pos);
             }
             if (PatriciaTrieReadingUtils::isTerminal(flags)) {
-                PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos);
+                PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mBuffer.data(), &pos);
             }
             // The fact that this PtNode has children is very important. Since we already know
             // that this PtNode does not match, if it has no children we know it is irrelevant
@@ -155,7 +157,8 @@
                 int currentPos = pos;
                 // Here comes the tricky part. First, read the children position.
                 const int childrenPos = PatriciaTrieReadingUtils
-                        ::readChildrenPositionAndAdvancePosition(mDictRoot, flags, &currentPos);
+                        ::readChildrenPositionAndAdvancePosition(mBuffer.data(), flags,
+                                &currentPos);
                 if (childrenPos > ptNodePos) {
                     // If the children pos is greater than the position, it means the previous
                     // PtNode, which position is stored in lastCandidatePtNodePos, was the right
@@ -185,30 +188,30 @@
                 if (0 != lastCandidatePtNodePos) {
                     const PatriciaTrieReadingUtils::NodeFlags lastFlags =
                             PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(
-                                    mDictRoot, &lastCandidatePtNodePos);
+                                    mBuffer.data(), &lastCandidatePtNodePos);
                     const int lastChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
-                            mDictRoot, &lastCandidatePtNodePos);
+                            mBuffer.data(), codePointTable, &lastCandidatePtNodePos);
                     // We copy all the characters in this PtNode to the buffer
                     outCodePoints[wordPos] = lastChar;
                     if (PatriciaTrieReadingUtils::hasMultipleChars(lastFlags)) {
                         int nextChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
-                                mDictRoot, &lastCandidatePtNodePos);
+                                mBuffer.data(), codePointTable, &lastCandidatePtNodePos);
                         int charCount = maxCodePointCount;
                         while (-1 != nextChar && --charCount > 0) {
                             outCodePoints[++wordPos] = nextChar;
                             nextChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
-                                    mDictRoot, &lastCandidatePtNodePos);
+                                    mBuffer.data(), codePointTable, &lastCandidatePtNodePos);
                         }
                     }
                     ++wordPos;
                     // Now we only need to branch to the children address. Skip the probability if
                     // it's there, read pos, and break to resume the search at pos.
                     if (PatriciaTrieReadingUtils::isTerminal(lastFlags)) {
-                        PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot,
+                        PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mBuffer.data(),
                                 &lastCandidatePtNodePos);
                     }
                     pos = PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(
-                            mDictRoot, lastFlags, &lastCandidatePtNodePos);
+                            mBuffer.data(), lastFlags, &lastCandidatePtNodePos);
                     break;
                 } else {
                     // Here is a little tricky part: we come here if we found out that all children
@@ -220,14 +223,14 @@
                     // ready to start the next one.
                     if (PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) {
                         PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(
-                                mDictRoot, flags, &pos);
+                                mBuffer.data(), flags, &pos);
                     }
                     if (PatriciaTrieReadingUtils::hasShortcutTargets(flags)) {
                         mShortcutListPolicy.skipAllShortcuts(&pos);
                     }
                     if (PatriciaTrieReadingUtils::hasBigrams(flags)) {
                         if (!mBigramListPolicy.skipAllBigrams(&pos)) {
-                            AKLOGE("Cannot skip bigrams. BufSize: %d, pos: %d.", mDictBufferSize,
+                            AKLOGE("Cannot skip bigrams. BufSize: %zd, pos: %d.", mBuffer.size(),
                                     pos);
                             mIsCorrupted = true;
                             ASSERT(false);
@@ -244,14 +247,14 @@
                 // our pos is after the end of this PtNode, at the start of the next one.
                 if (PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) {
                     PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(
-                            mDictRoot, flags, &pos);
+                            mBuffer.data(), flags, &pos);
                 }
                 if (PatriciaTrieReadingUtils::hasShortcutTargets(flags)) {
                     mShortcutListPolicy.skipAllShortcuts(&pos);
                 }
                 if (PatriciaTrieReadingUtils::hasBigrams(flags)) {
                     if (!mBigramListPolicy.skipAllBigrams(&pos)) {
-                        AKLOGE("Cannot skip bigrams. BufSize: %d, pos: %d.", mDictBufferSize, pos);
+                        AKLOGE("Cannot skip bigrams. BufSize: %zd, pos: %d.", mBuffer.size(), pos);
                         mIsCorrupted = true;
                         ASSERT(false);
                         *outUnigramProbability = NOT_A_PROBABILITY;
@@ -402,9 +405,11 @@
     int shortcutPos = NOT_A_DICT_POS;
     int bigramPos = NOT_A_DICT_POS;
     int siblingPos = NOT_A_DICT_POS;
-    PatriciaTrieReadingUtils::readPtNodeInfo(mDictRoot, ptNodePos, &mShortcutListPolicy,
-            &mBigramListPolicy, &flags, &mergedNodeCodePointCount, mergedNodeCodePoints,
-            &probability, &childrenPos, &shortcutPos, &bigramPos, &siblingPos);
+    const int *const codePointTable = mHeaderPolicy.getCodePointTable();
+    PatriciaTrieReadingUtils::readPtNodeInfo(mBuffer.data(), ptNodePos, &mShortcutListPolicy,
+            &mBigramListPolicy, codePointTable, &flags, &mergedNodeCodePointCount,
+            mergedNodeCodePoints, &probability, &childrenPos, &shortcutPos, &bigramPos,
+            &siblingPos);
     // Skip PtNodes don't start with Unicode code point because they represent non-word information.
     if (CharUtils::isInUnicodeSpace(mergedNodeCodePoints[0])) {
         const int wordId = PatriciaTrieReadingUtils::isTerminal(flags) ? ptNodePos : NOT_A_WORD_ID;
@@ -452,14 +457,14 @@
     int shortcutPos = getShortcutPositionOfPtNode(ptNodePos);
     if (shortcutPos != NOT_A_DICT_POS) {
         int shortcutTargetCodePoints[MAX_WORD_LENGTH];
-        ShortcutListReadingUtils::getShortcutListSizeAndForwardPointer(mDictRoot, &shortcutPos);
+        ShortcutListReadingUtils::getShortcutListSizeAndForwardPointer(mBuffer, &shortcutPos);
         bool hasNext = true;
         while (hasNext) {
             const ShortcutListReadingUtils::ShortcutFlags shortcutFlags =
-                    ShortcutListReadingUtils::getFlagsAndForwardPointer(mDictRoot, &shortcutPos);
+                    ShortcutListReadingUtils::getFlagsAndForwardPointer(mBuffer, &shortcutPos);
             hasNext = ShortcutListReadingUtils::hasNext(shortcutFlags);
             const int shortcutTargetLength = ShortcutListReadingUtils::readShortcutTarget(
-                    mDictRoot, MAX_WORD_LENGTH, shortcutTargetCodePoints, &shortcutPos);
+                    mBuffer, MAX_WORD_LENGTH, shortcutTargetCodePoints, &shortcutPos);
             const std::vector<int> shortcutTarget(shortcutTargetCodePoints,
                     shortcutTargetCodePoints + shortcutTargetLength);
             const int shortcutProbability =
@@ -512,4 +517,9 @@
 int PatriciaTriePolicy::getTerminalPtNodePosFromWordId(const int wordId) const {
     return wordId == NOT_A_WORD_ID ? NOT_A_DICT_POS : wordId;
 }
+
+bool PatriciaTriePolicy::isValidPos(const int pos) const {
+    return pos >= 0 && pos < static_cast<int>(mBuffer.size());
+}
+
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
index fc65de5..3cdf6cd 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
@@ -43,15 +43,13 @@
     PatriciaTriePolicy(MmappedBuffer::MmappedBufferPtr mmappedBuffer)
             : mMmappedBuffer(std::move(mmappedBuffer)),
               mHeaderPolicy(mMmappedBuffer->getReadOnlyByteArrayView().data(),
-                      FormatUtils::VERSION_2),
-              mDictRoot(mMmappedBuffer->getReadOnlyByteArrayView().data()
-                      + mHeaderPolicy.getSize()),
-              mDictBufferSize(mMmappedBuffer->getReadOnlyByteArrayView().size()
-                      - mHeaderPolicy.getSize()),
-              mBigramListPolicy(mDictRoot, mDictBufferSize), mShortcutListPolicy(mDictRoot),
-              mPtNodeReader(mDictRoot, mDictBufferSize, &mBigramListPolicy, &mShortcutListPolicy),
-              mPtNodeArrayReader(mDictRoot, mDictBufferSize),
-              mTerminalPtNodePositionsForIteratingWords(), mIsCorrupted(false) {}
+                      FormatUtils::detectFormatVersion(mMmappedBuffer->getReadOnlyByteArrayView())),
+              mBuffer(mMmappedBuffer->getReadOnlyByteArrayView().skip(mHeaderPolicy.getSize())),
+              mBigramListPolicy(mBuffer), mShortcutListPolicy(mBuffer),
+              mPtNodeReader(mBuffer, &mBigramListPolicy, &mShortcutListPolicy,
+                      mHeaderPolicy.getCodePointTable()),
+              mPtNodeArrayReader(mBuffer), mTerminalPtNodePositionsForIteratingWords(),
+              mIsCorrupted(false) {}
 
     AK_FORCE_INLINE int getRootPosition() const {
         return 0;
@@ -149,8 +147,7 @@
 
     const MmappedBuffer::MmappedBufferPtr mMmappedBuffer;
     const HeaderPolicy mHeaderPolicy;
-    const uint8_t *const mDictRoot;
-    const int mDictBufferSize;
+    const ReadOnlyByteArrayView mBuffer;
     const BigramListPolicy mBigramListPolicy;
     const ShortcutListPolicy mShortcutListPolicy;
     const Ver2ParticiaTrieNodeReader mPtNodeReader;
@@ -166,6 +163,7 @@
     int getTerminalPtNodePosFromWordId(const int wordId) const;
     const WordAttributes getWordAttributes(const int probability,
             const PtNodeParams &ptNodeParams) const;
+    bool isValidPos(const int pos) const;
 };
 } // namespace latinime
 #endif // LATINIME_PATRICIA_TRIE_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/shortcut/shortcut_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/shortcut/shortcut_list_policy.h
index 8e16ccc..5319dd2 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/shortcut/shortcut_list_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/shortcut/shortcut_list_policy.h
@@ -22,13 +22,13 @@
 #include "defines.h"
 #include "suggest/core/policy/dictionary_shortcuts_structure_policy.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.h"
+#include "utils/byte_array_view.h"
 
 namespace latinime {
 
 class ShortcutListPolicy : public DictionaryShortcutsStructurePolicy {
  public:
-    explicit ShortcutListPolicy(const uint8_t *const shortcutBuf)
-            : mShortcutsBuf(shortcutBuf) {}
+    explicit ShortcutListPolicy(const ReadOnlyByteArrayView buffer) : mBuffer(buffer) {}
 
     ~ShortcutListPolicy() {}
 
@@ -37,7 +37,7 @@
             return NOT_A_DICT_POS;
         }
         int listPos = pos;
-        ShortcutListReadingUtils::getShortcutListSizeAndForwardPointer(mShortcutsBuf, &listPos);
+        ShortcutListReadingUtils::getShortcutListSizeAndForwardPointer(mBuffer, &listPos);
         return listPos;
     }
 
@@ -45,7 +45,7 @@
             int *const outCodePointCount, bool *const outIsWhitelist, bool *const outHasNext,
             int *const pos) const {
         const ShortcutListReadingUtils::ShortcutFlags flags =
-                ShortcutListReadingUtils::getFlagsAndForwardPointer(mShortcutsBuf, pos);
+                ShortcutListReadingUtils::getFlagsAndForwardPointer(mBuffer, pos);
         if (outHasNext) {
             *outHasNext = ShortcutListReadingUtils::hasNext(flags);
         }
@@ -54,20 +54,20 @@
         }
         if (outCodePoint) {
             *outCodePointCount = ShortcutListReadingUtils::readShortcutTarget(
-                        mShortcutsBuf, maxCodePointCount, outCodePoint, pos);
+                    mBuffer, maxCodePointCount, outCodePoint, pos);
         }
     }
 
     void skipAllShortcuts(int *const pos) const {
         const int shortcutListSize = ShortcutListReadingUtils
-                ::getShortcutListSizeAndForwardPointer(mShortcutsBuf, pos);
+                ::getShortcutListSizeAndForwardPointer(mBuffer, pos);
         *pos += shortcutListSize;
     }
 
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(ShortcutListPolicy);
 
-    const uint8_t *const mShortcutsBuf;
+    const ReadOnlyByteArrayView mBuffer;
 };
 } // namespace latinime
 #endif // LATINIME_SHORTCUT_LIST_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp
index c1e9387..dc0ed96 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp
@@ -22,10 +22,10 @@
 
 const PtNodeParams Ver2ParticiaTrieNodeReader::fetchPtNodeParamsInBufferFromPtNodePos(
         const int ptNodePos) const {
-    if (ptNodePos < 0 || ptNodePos >= mDictSize) {
+    if (ptNodePos < 0 || ptNodePos >= static_cast<int>(mBuffer.size())) {
         // Reading invalid position because of bug or broken dictionary.
-        AKLOGE("Fetching PtNode info from invalid dictionary position: %d, dictionary size: %d",
-                ptNodePos, mDictSize);
+        AKLOGE("Fetching PtNode info from invalid dictionary position: %d, dictionary size: %zd",
+                ptNodePos, mBuffer.size());
         ASSERT(false);
         return PtNodeParams();
     }
@@ -37,9 +37,9 @@
     int shortcutPos = NOT_A_DICT_POS;
     int bigramPos = NOT_A_DICT_POS;
     int siblingPos = NOT_A_DICT_POS;
-    PatriciaTrieReadingUtils::readPtNodeInfo(mDictBuffer, ptNodePos, mShortuctPolicy,
-            mBigramPolicy, &flags, &mergedNodeCodePointCount, mergedNodeCodePoints, &probability,
-            &childrenPos, &shortcutPos, &bigramPos, &siblingPos);
+    PatriciaTrieReadingUtils::readPtNodeInfo(mBuffer.data(), ptNodePos, mShortuctPolicy,
+            mBigramPolicy, mCodePointTable, &flags, &mergedNodeCodePointCount, mergedNodeCodePoints,
+            &probability, &childrenPos, &shortcutPos, &bigramPos, &siblingPos);
     if (mergedNodeCodePointCount <= 0) {
         AKLOGE("Empty PtNode is not allowed. Code point count: %d", mergedNodeCodePointCount);
         ASSERT(false);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h
index f0725b6..24ec5bc 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h
@@ -22,6 +22,7 @@
 #include "defines.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_reader.h"
+#include "utils/byte_array_view.h"
 
 namespace latinime {
 
@@ -30,21 +31,22 @@
 
 class Ver2ParticiaTrieNodeReader : public PtNodeReader {
  public:
-    Ver2ParticiaTrieNodeReader(const uint8_t *const dictBuffer, const int dictSize,
+    Ver2ParticiaTrieNodeReader(const ReadOnlyByteArrayView buffer,
             const DictionaryBigramsStructurePolicy *const bigramPolicy,
-            const DictionaryShortcutsStructurePolicy *const shortcutPolicy)
-            : mDictBuffer(dictBuffer), mDictSize(dictSize), mBigramPolicy(bigramPolicy),
-              mShortuctPolicy(shortcutPolicy) {}
+            const DictionaryShortcutsStructurePolicy *const shortcutPolicy,
+            const int *const codePointTable)
+            : mBuffer(buffer), mBigramPolicy(bigramPolicy), mShortuctPolicy(shortcutPolicy),
+              mCodePointTable(codePointTable) {}
 
     virtual const PtNodeParams fetchPtNodeParamsInBufferFromPtNodePos(const int ptNodePos) const;
 
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(Ver2ParticiaTrieNodeReader);
 
-    const uint8_t *const mDictBuffer;
-    const int mDictSize;
+    const ReadOnlyByteArrayView mBuffer;
     const DictionaryBigramsStructurePolicy *const mBigramPolicy;
     const DictionaryShortcutsStructurePolicy *const mShortuctPolicy;
+    const int *const mCodePointTable;
 };
 } // namespace latinime
 #endif /* LATINIME_VER2_PATRICIA_TRIE_NODE_READER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.cpp
index b46617d..72ad1eb 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.cpp
@@ -22,16 +22,16 @@
 
 bool Ver2PtNodeArrayReader::readPtNodeArrayInfoAndReturnIfValid(const int ptNodeArrayPos,
         int *const outPtNodeCount, int *const outFirstPtNodePos) const {
-    if (ptNodeArrayPos < 0 || ptNodeArrayPos >= mDictSize) {
+    if (ptNodeArrayPos < 0 || ptNodeArrayPos >= static_cast<int>(mBuffer.size())) {
         // Reading invalid position because of a bug or a broken dictionary.
-        AKLOGE("Reading PtNode array info from invalid dictionary position: %d, dict size: %d",
-                ptNodeArrayPos, mDictSize);
+        AKLOGE("Reading PtNode array info from invalid dictionary position: %d, dict size: %zd",
+                ptNodeArrayPos, mBuffer.size());
         ASSERT(false);
         return false;
     }
     int readingPos = ptNodeArrayPos;
     const int ptNodeCountInArray = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition(
-            mDictBuffer, &readingPos);
+            mBuffer.data(), &readingPos);
     *outPtNodeCount = ptNodeCountInArray;
     *outFirstPtNodePos = readingPos;
     return true;
@@ -39,10 +39,10 @@
 
 bool Ver2PtNodeArrayReader::readForwardLinkAndReturnIfValid(const int forwordLinkPos,
         int *const outNextPtNodeArrayPos) const {
-    if (forwordLinkPos < 0 || forwordLinkPos >= mDictSize) {
+    if (forwordLinkPos < 0 || forwordLinkPos >=  static_cast<int>(mBuffer.size())) {
         // Reading invalid position because of bug or broken dictionary.
-        AKLOGE("Reading forward link from invalid dictionary position: %d, dict size: %d",
-                forwordLinkPos, mDictSize);
+        AKLOGE("Reading forward link from invalid dictionary position: %d, dict size: %zd",
+                forwordLinkPos, mBuffer.size());
         ASSERT(false);
         return false;
     }
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h
index 5482721..548f36b 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h
@@ -21,13 +21,13 @@
 
 #include "defines.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_array_reader.h"
+#include "utils/byte_array_view.h"
 
 namespace latinime {
 
 class Ver2PtNodeArrayReader : public PtNodeArrayReader {
  public:
-    Ver2PtNodeArrayReader(const uint8_t *const dictBuffer, const int dictSize)
-            : mDictBuffer(dictBuffer), mDictSize(dictSize) {};
+    Ver2PtNodeArrayReader(const ReadOnlyByteArrayView buffer) : mBuffer(buffer) {};
 
     virtual bool readPtNodeArrayInfoAndReturnIfValid(const int ptNodeArrayPos,
             int *const outPtNodeCount, int *const outFirstPtNodePos) const;
@@ -37,8 +37,7 @@
  private:
     DISALLOW_COPY_AND_ASSIGN(Ver2PtNodeArrayReader);
 
-    const uint8_t *const mDictBuffer;
-    const int mDictSize;
+    const ReadOnlyByteArrayView mBuffer;
 };
 } // namespace latinime
 #endif /* LATINIME_VER2_PT_NODE_ARRAY_READER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp
index 0675de6..35f0f76 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp
@@ -167,7 +167,15 @@
     if (lastBitmapEntryIndex == TrieMap::INVALID_INDEX) {
         return TrieMap::INVALID_INDEX;
     }
-    return mTrieMap.getNextLevelBitmapEntryIndex(prevWordIds[prevWordIds.size() - 1],
+    const int oldestPrevWordId = prevWordIds.lastOrDefault(NOT_A_WORD_ID);
+    const TrieMap::Result result = mTrieMap.get(oldestPrevWordId, lastBitmapEntryIndex);
+    if (!result.mIsValid) {
+        if (!mTrieMap.put(oldestPrevWordId,
+                ProbabilityEntry().encode(mHasHistoricalInfo), lastBitmapEntryIndex)) {
+            return TrieMap::INVALID_INDEX;
+        }
+    }
+    return mTrieMap.getNextLevelBitmapEntryIndex(prevWordIds.lastOrDefault(NOT_A_WORD_ID),
             lastBitmapEntryIndex);
 }
 
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h
index 3dfaba7..f1bf12c 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h
@@ -36,7 +36,8 @@
 
     // Dummy entry
     ProbabilityEntry()
-            : mFlags(0), mProbability(NOT_A_PROBABILITY), mHistoricalInfo() {}
+            : mFlags(Ver4DictConstants::FLAG_NOT_A_VALID_ENTRY), mProbability(NOT_A_PROBABILITY),
+              mHistoricalInfo() {}
 
     // Entry without historical information
     ProbabilityEntry(const int flags, const int probability)
@@ -61,7 +62,7 @@
                       bigramProperty->getCount()) {}
 
     bool isValid() const {
-        return (mProbability != NOT_A_PROBABILITY) || hasHistoricalInfo();
+        return (mFlags & Ver4DictConstants::FLAG_NOT_A_VALID_ENTRY) == 0;
     }
 
     bool hasHistoricalInfo() const {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp
index 9acf2d4..39822b9 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp
@@ -53,6 +53,7 @@
 const int Ver4DictConstants::WORD_COUNT_FIELD_SIZE = 1;
 
 const uint8_t Ver4DictConstants::FLAG_REPRESENTS_BEGINNING_OF_SENTENCE = 0x1;
+const uint8_t Ver4DictConstants::FLAG_NOT_A_VALID_ENTRY = 0x2;
 
 const int Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE = 64;
 const int Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_DATA_SIZE = 4;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h
index 9703531..dfcdd4d 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h
@@ -51,6 +51,7 @@
     static const int WORD_COUNT_FIELD_SIZE;
     // Flags in probability entry.
     static const uint8_t FLAG_REPRESENTS_BEGINNING_OF_SENTENCE;
+    static const uint8_t FLAG_NOT_A_VALID_ENTRY;
 
     static const int SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE;
     static const int SHORTCUT_ADDRESS_TABLE_DATA_SIZE;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp
index 731092e..d795239 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp
@@ -16,6 +16,7 @@
 
 #include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h"
 
+#include "suggest/policyimpl/dictionary/header/header_policy.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h"
 #include "suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h"
@@ -51,7 +52,7 @@
             DynamicPtReadingUtils::getParentPtNodePos(parentPosOffset, headPos);
     int codePoints[MAX_WORD_LENGTH];
     const int codePonitCount = PatriciaTrieReadingUtils::getCharsAndAdvancePosition(
-            dictBuf, flags, MAX_WORD_LENGTH, codePoints, &pos);
+            dictBuf, flags, MAX_WORD_LENGTH, mHeaderPolicy->getCodePointTable(), codePoints, &pos);
     int terminalIdFieldPos = NOT_A_DICT_POS;
     int terminalId = Ver4DictConstants::NOT_A_TERMINAL_ID;
     int probability = NOT_A_PROBABILITY;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp
index 9ca7124..75ec169 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp
@@ -211,19 +211,17 @@
 
 bool Ver4PatriciaTrieNodeWriter::addNgramEntry(const WordIdArrayView prevWordIds, const int wordId,
         const BigramProperty *const bigramProperty, bool *const outAddedNewBigram) {
-    // TODO: Support n-gram.
     LanguageModelDictContent *const languageModelDictContent =
             mBuffers->getMutableLanguageModelDictContent();
     const ProbabilityEntry probabilityEntry =
-            languageModelDictContent->getNgramProbabilityEntry(
-                    prevWordIds.limit(1 /* maxSize */), wordId);
+            languageModelDictContent->getNgramProbabilityEntry(prevWordIds, wordId);
     const ProbabilityEntry probabilityEntryOfBigramProperty(bigramProperty);
     const ProbabilityEntry updatedProbabilityEntry = createUpdatedEntryFrom(
             &probabilityEntry, &probabilityEntryOfBigramProperty);
     if (!languageModelDictContent->setNgramProbabilityEntry(
-            prevWordIds.limit(1 /* maxSize */), wordId, &updatedProbabilityEntry)) {
-        AKLOGE("Cannot add new ngram entry. prevWordId: %d, wordId: %d",
-                prevWordIds[0], wordId);
+            prevWordIds, wordId, &updatedProbabilityEntry)) {
+        AKLOGE("Cannot add new ngram entry. prevWordId[0]: %d, prevWordId.size(): %zd, wordId: %d",
+                prevWordIds[0], prevWordIds.size(), wordId);
         return false;
     }
     if (!probabilityEntry.isValid() && outAddedNewBigram) {
@@ -234,11 +232,9 @@
 
 bool Ver4PatriciaTrieNodeWriter::removeNgramEntry(const WordIdArrayView prevWordIds,
         const int wordId) {
-    // TODO: Support n-gram.
     LanguageModelDictContent *const languageModelDictContent =
             mBuffers->getMutableLanguageModelDictContent();
-    return languageModelDictContent->removeNgramProbabilityEntry(prevWordIds.limit(1 /* maxSize */),
-            wordId);
+    return languageModelDictContent->removeNgramProbabilityEntry(prevWordIds, wordId);
 }
 
 // TODO: Remove when we stop supporting v402 format.
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
index d537711..8d41356 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
@@ -120,16 +120,15 @@
     const int ptNodePos =
             mBuffers->getTerminalPositionLookupTable()->getTerminalPtNodePosition(wordId);
     const PtNodeParams ptNodeParams = mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos);
-    // TODO: Support n-gram.
     const int probability = mBuffers->getLanguageModelDictContent()->getWordProbability(
-            prevWordIds.limit(1 /* maxSize */), wordId, mHeaderPolicy);
+            prevWordIds, wordId, mHeaderPolicy);
     return WordAttributes(probability, ptNodeParams.isBlacklisted(), ptNodeParams.isNotAWord(),
             probability == 0);
 }
 
 int Ver4PatriciaTriePolicy::getProbabilityOfWord(const WordIdArrayView prevWordIds,
         const int wordId) const {
-    if (wordId == NOT_A_WORD_ID) {
+    if (wordId == NOT_A_WORD_ID || prevWordIds.contains(NOT_A_WORD_ID)) {
         return NOT_A_PROBABILITY;
     }
     const int ptNodePos =
@@ -138,10 +137,8 @@
     if (ptNodeParams.isDeleted() || ptNodeParams.isBlacklisted() || ptNodeParams.isNotAWord()) {
         return NOT_A_PROBABILITY;
     }
-    // TODO: Support n-gram.
     const ProbabilityEntry probabilityEntry =
-            mBuffers->getLanguageModelDictContent()->getNgramProbabilityEntry(
-                    prevWordIds.limit(1 /* maxSize */), wordId);
+            mBuffers->getLanguageModelDictContent()->getNgramProbabilityEntry(prevWordIds, wordId);
     if (!probabilityEntry.isValid()) {
         return NOT_A_PROBABILITY;
     }
@@ -164,16 +161,18 @@
     if (prevWordIds.empty()) {
         return;
     }
-    // TODO: Support n-gram.
     const auto languageModelDictContent = mBuffers->getLanguageModelDictContent();
-    for (const auto entry : languageModelDictContent->getProbabilityEntries(
-            prevWordIds.limit(1 /* maxSize */))) {
-        const ProbabilityEntry &probabilityEntry = entry.getProbabilityEntry();
-        const int probability = probabilityEntry.hasHistoricalInfo() ?
-                ForgettingCurveUtils::decodeProbability(
-                        probabilityEntry.getHistoricalInfo(), mHeaderPolicy) :
-                probabilityEntry.getProbability();
-        listener->onVisitEntry(probability, entry.getWordId());
+    for (size_t i = 1; i <= prevWordIds.size(); ++i) {
+        for (const auto entry : languageModelDictContent->getProbabilityEntries(
+                prevWordIds.limit(i))) {
+            const ProbabilityEntry &probabilityEntry = entry.getProbabilityEntry();
+            const int probability = probabilityEntry.hasHistoricalInfo() ?
+                    ForgettingCurveUtils::decodeProbability(
+                            probabilityEntry.getHistoricalInfo(), mHeaderPolicy)
+                            + ForgettingCurveUtils::getProbabilityBiasForNgram(i + 1 /* n */) :
+                    probabilityEntry.getProbability();
+            listener->onVisitEntry(probability, entry.getWordId());
+        }
     }
 }
 
@@ -228,8 +227,8 @@
         return false;
     }
     const CodePointArrayView codePointArrayView(codePointsToAdd, codePointCountToAdd);
-    if (mUpdatingHelper.addUnigramWord(&readingHelper, codePointArrayView.data(),
-            codePointArrayView.size(), unigramProperty, &addedNewUnigram)) {
+    if (mUpdatingHelper.addUnigramWord(&readingHelper, codePointArrayView, unigramProperty,
+            &addedNewUnigram)) {
         if (addedNewUnigram && !unigramProperty->representsBeginningOfSentence()) {
             mUnigramCount++;
         }
@@ -244,8 +243,8 @@
                     mBuffers->getTerminalPositionLookupTable()->getTerminalPtNodePosition(wordId);
             for (const auto &shortcut : unigramProperty->getShortcuts()) {
                 if (!mUpdatingHelper.addShortcutTarget(wordPos,
-                        shortcut.getTargetCodePoints()->data(),
-                        shortcut.getTargetCodePoints()->size(), shortcut.getProbability())) {
+                        CodePointArrayView(*shortcut.getTargetCodePoints()),
+                        shortcut.getProbability())) {
                     AKLOGE("Cannot add new shortcut target. PtNodePos: %d, length: %zd, "
                             "probability: %d", wordPos, shortcut.getTargetCodePoints()->size(),
                             shortcut.getProbability());
@@ -335,17 +334,8 @@
     if (wordId == NOT_A_WORD_ID) {
         return false;
     }
-    // TODO: Support N-gram.
     bool addedNewEntry = false;
-    WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordsPtNodePos;
-    for (size_t i = 0; i < prevWordsPtNodePos.size(); ++i) {
-        prevWordsPtNodePos[i] = mBuffers->getTerminalPositionLookupTable()
-                ->getTerminalPtNodePosition(prevWordIds[i]);
-    }
-    const int wordPtNodePos = mBuffers->getTerminalPositionLookupTable()
-            ->getTerminalPtNodePosition(wordId);
-    if (mUpdatingHelper.addNgramEntry(WordIdArrayView::fromArray(prevWordsPtNodePos),
-            wordPtNodePos, bigramProperty, &addedNewEntry)) {
+    if (mNodeWriter.addNgramEntry(prevWordIds, wordId, bigramProperty, &addedNewEntry)) {
         if (addedNewEntry) {
             mBigramCount++;
         }
@@ -384,15 +374,7 @@
     if (wordId == NOT_A_WORD_ID) {
         return false;
     }
-    std::array<int, MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordsPtNodePos;
-    for (size_t i = 0; i < prevWordsPtNodePos.size(); ++i) {
-        prevWordsPtNodePos[i] = mBuffers->getTerminalPositionLookupTable()
-                ->getTerminalPtNodePosition(prevWordIds[i]);
-    }
-    const int wordPtNodePos = mBuffers->getTerminalPositionLookupTable()
-            ->getTerminalPtNodePosition(wordId);
-    if (mUpdatingHelper.removeNgramEntry(WordIdArrayView::fromArray(prevWordsPtNodePos),
-            wordPtNodePos)) {
+    if (mNodeWriter.removeNgramEntry(prevWordIds, wordId)) {
         mBigramCount--;
         return true;
     } else {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp
index ecbe792..da2c30c 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp
@@ -42,8 +42,10 @@
     if (readingPosIsInAdditionalBuffer) {
         *pos -= mOriginalBuffer.size();
     }
+    // Code point table is not used for dynamic format.
     *outCodePointCount = ByteArrayUtils::readStringAndAdvancePosition(
-            getBuffer(readingPosIsInAdditionalBuffer), maxCodePointCount, outCodePoints, pos);
+            getBuffer(readingPosIsInAdditionalBuffer), maxCodePointCount,
+            nullptr /* codePointTable */, outCodePoints, pos);
     if (readingPosIsInAdditionalBuffer) {
         *pos += mOriginalBuffer.size();
     }
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h
index 4b3c989..abb9790 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h
@@ -147,11 +147,18 @@
      */
     static AK_FORCE_INLINE int readCodePoint(const uint8_t *const buffer, const int pos) {
         int p = pos;
-        return readCodePointAndAdvancePosition(buffer, &p);
+        return readCodePointAndAdvancePosition(buffer, nullptr /* codePointTable */, &p);
     }
 
     static AK_FORCE_INLINE int readCodePointAndAdvancePosition(
-            const uint8_t *const buffer, int *const pos) {
+            const uint8_t *const buffer, const int *const codePointTable, int *const pos) {
+        /*
+         * codePointTable is an array to convert the most frequent characters in this dictionary to
+         * 1 byte code points. It is only made of the original code points of the most frequent
+         * characters used in this dictionary. 0x20 - 0xFF is used for the 1 byte characters.
+         * The original code points are restored by picking the code points at the indices of the
+         * codePointTable. The indices are calculated by subtracting 0x20 from the firstByte.
+         */
         const uint8_t firstByte = readUint8(buffer, *pos);
         if (firstByte < MINIMUM_ONE_BYTE_CHARACTER_VALUE) {
             if (firstByte == CHARACTER_ARRAY_TERMINATOR) {
@@ -162,6 +169,9 @@
             }
         } else {
             *pos += 1;
+            if (codePointTable) {
+                return codePointTable[firstByte - MINIMUM_ONE_BYTE_CHARACTER_VALUE];
+            }
             return firstByte;
         }
     }
@@ -173,12 +183,13 @@
      */
     // Returns the length of the string.
     static int readStringAndAdvancePosition(const uint8_t *const buffer,
-            const int maxLength, int *const outBuffer, int *const pos) {
+            const int maxLength, const int *const codePointTable, int *const outBuffer,
+            int *const pos) {
         int length = 0;
-        int codePoint = readCodePointAndAdvancePosition(buffer, pos);
+        int codePoint = readCodePointAndAdvancePosition(buffer, codePointTable, pos);
         while (NOT_A_CODE_POINT != codePoint && length < maxLength) {
             outBuffer[length++] = codePoint;
-            codePoint = readCodePointAndAdvancePosition(buffer, pos);
+            codePoint = readCodePointAndAdvancePosition(buffer, codePointTable, pos);
         }
         return length;
     }
@@ -187,9 +198,9 @@
     static int advancePositionToBehindString(
             const uint8_t *const buffer, const int maxLength, int *const pos) {
         int length = 0;
-        int codePoint = readCodePointAndAdvancePosition(buffer, pos);
+        int codePoint = readCodePointAndAdvancePosition(buffer, nullptr /* codePointTable */, pos);
         while (NOT_A_CODE_POINT != codePoint && length < maxLength) {
-            codePoint = readCodePointAndAdvancePosition(buffer, pos);
+            codePoint = readCodePointAndAdvancePosition(buffer, nullptr /* codePointTable */, pos);
             length++;
         }
         return length;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp
index e6e7167..0cffe56 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp
@@ -29,6 +29,8 @@
     switch (formatVersion) {
         case VERSION_2:
             return VERSION_2;
+        case VERSION_201:
+            return VERSION_201;
         case VERSION_4_ONLY_FOR_TESTING:
             return VERSION_4_ONLY_FOR_TESTING;
         case VERSION_4:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h
index 51ad987..9631008 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h
@@ -32,6 +32,7 @@
     enum FORMAT_VERSION {
         // These MUST have the same values as the relevant constants in FormatSpec.java.
         VERSION_2 = 2,
+        VERSION_201 = 201,
         VERSION_4_ONLY_FOR_TESTING = 399,
         VERSION_4 = 402,
         VERSION_4_DEV = 403,
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_scoring.h b/native/jni/src/suggest/policyimpl/typing/typing_scoring.h
index 52c4251..0240bcf 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_scoring.h
+++ b/native/jni/src/suggest/policyimpl/typing/typing_scoring.h
@@ -33,10 +33,12 @@
     static const TypingScoring *getInstance() { return &sInstance; }
 
     AK_FORCE_INLINE void getMostProbableString(const DicTraverseSession *const traverseSession,
-            const float languageWeight, SuggestionResults *const outSuggestionResults) const {}
+            const float weightOfLangModelVsSpatialModel,
+            SuggestionResults *const outSuggestionResults) const {}
 
-    AK_FORCE_INLINE float getAdjustedLanguageWeight(DicTraverseSession *const traverseSession,
-            DicNode *const terminals, const int size) const {
+    AK_FORCE_INLINE float getAdjustedWeightOfLangModelVsSpatialModel(
+            DicTraverseSession *const traverseSession, DicNode *const terminals,
+            const int size) const {
         return 1.0f;
     }
 
diff --git a/native/jni/src/utils/byte_array_view.h b/native/jni/src/utils/byte_array_view.h
index 10d7ae2..2b778af 100644
--- a/native/jni/src/utils/byte_array_view.h
+++ b/native/jni/src/utils/byte_array_view.h
@@ -42,6 +42,13 @@
         return mPtr;
     }
 
+    AK_FORCE_INLINE const ReadOnlyByteArrayView skip(const size_t n) const {
+        if (mSize <= n) {
+            return ReadOnlyByteArrayView();
+        }
+        return ReadOnlyByteArrayView(mPtr + n, mSize - n);
+    }
+
  private:
     DISALLOW_ASSIGNMENT_OPERATOR(ReadOnlyByteArrayView);
 
diff --git a/native/jni/src/utils/int_array_view.h b/native/jni/src/utils/int_array_view.h
index cc5f328..f3a8589 100644
--- a/native/jni/src/utils/int_array_view.h
+++ b/native/jni/src/utils/int_array_view.h
@@ -115,6 +115,20 @@
         memmove(buffer->data() + offset, mPtr, sizeof(int) * mSize);
     }
 
+    AK_FORCE_INLINE int firstOrDefault(const int defaultValue) const {
+        if (empty()) {
+            return defaultValue;
+        }
+        return mPtr[0];
+    }
+
+    AK_FORCE_INLINE int lastOrDefault(const int defaultValue) const {
+        if (empty()) {
+            return defaultValue;
+        }
+        return mPtr[mSize - 1];
+    }
+
  private:
     DISALLOW_ASSIGNMENT_OPERATOR(IntArrayView);
 
diff --git a/native/jni/src/utils/jni_data_utils.h b/native/jni/src/utils/jni_data_utils.h
index cb82d3c..235a03b 100644
--- a/native/jni/src/utils/jni_data_utils.h
+++ b/native/jni/src/utils/jni_data_utils.h
@@ -97,17 +97,13 @@
     }
 
     static PrevWordsInfo constructPrevWordsInfo(JNIEnv *env, jobjectArray prevWordCodePointArrays,
-            jbooleanArray isBeginningOfSentenceArray) {
+            jbooleanArray isBeginningOfSentenceArray, const size_t prevWordCount) {
         int prevWordCodePoints[MAX_PREV_WORD_COUNT_FOR_N_GRAM][MAX_WORD_LENGTH];
         int prevWordCodePointCount[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
         bool isBeginningOfSentence[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
-        jsize prevWordsCount = env->GetArrayLength(prevWordCodePointArrays);
-        for (size_t i = 0; i < NELEMS(prevWordCodePoints); ++i) {
+        for (size_t i = 0; i < prevWordCount; ++i) {
             prevWordCodePointCount[i] = 0;
             isBeginningOfSentence[i] = false;
-            if (prevWordsCount <= static_cast<int>(i)) {
-                continue;
-            }
             jintArray prevWord = (jintArray)env->GetObjectArrayElement(prevWordCodePointArrays, i);
             if (!prevWord) {
                 continue;
@@ -124,7 +120,7 @@
             isBeginningOfSentence[i] = isBeginningOfSentenceBoolean == JNI_TRUE;
         }
         return PrevWordsInfo(prevWordCodePoints, prevWordCodePointCount, isBeginningOfSentence,
-                MAX_PREV_WORD_COUNT_FOR_N_GRAM);
+                prevWordCount);
     }
 
     static void putBooleanToArray(JNIEnv *env, jbooleanArray array, const int index,
diff --git a/native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp b/native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp
index c5849d0..06f82df 100644
--- a/native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp
+++ b/native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp
@@ -29,7 +29,7 @@
 TEST(LanguageModelDictContentTest, TestUnigramProbability) {
     LanguageModelDictContent languageModelDictContent(false /* useHistoricalInfo */);
 
-    const int flag = 0xFF;
+    const int flag = 0xF0;
     const int probability = 10;
     const int wordId = 100;
     const ProbabilityEntry probabilityEntry(flag, probability);
diff --git a/native/jni/tests/suggest/policyimpl/dictionary/utils/byte_array_utils_test.cpp b/native/jni/tests/suggest/policyimpl/dictionary/utils/byte_array_utils_test.cpp
index a1c310d..c201e0d 100644
--- a/native/jni/tests/suggest/policyimpl/dictionary/utils/byte_array_utils_test.cpp
+++ b/native/jni/tests/suggest/policyimpl/dictionary/utils/byte_array_utils_test.cpp
@@ -23,6 +23,19 @@
 namespace latinime {
 namespace {
 
+TEST(ByteArrayUtilsTest, TestReadCodePointTable) {
+    const int codePointTable[] = { 0x6f, 0x6b };
+    const uint8_t buffer[] = { 0x20u, 0x21u, 0x00u, 0x01u, 0x00u };
+    int pos = 0;
+    // Expect the first entry of codePointTable
+    EXPECT_EQ(0x6f, ByteArrayUtils::readCodePointAndAdvancePosition(buffer, codePointTable, &pos));
+    // Expect the second entry of codePointTable
+    EXPECT_EQ(0x6b, ByteArrayUtils::readCodePointAndAdvancePosition(buffer, codePointTable, &pos));
+    // Expect the original code point from buffer[2] to buffer[4], 0x100
+    // It isn't picked from the codePointTable, since it exceeds the range of the codePointTable.
+    EXPECT_EQ(0x100, ByteArrayUtils::readCodePointAndAdvancePosition(buffer, codePointTable, &pos));
+}
+
 TEST(ByteArrayUtilsTest, TestReadInt) {
     const uint8_t buffer[] = { 0x1u, 0x8Au, 0x0u, 0xAAu };
 
@@ -67,7 +80,7 @@
 
     int pos = 0;
     int codePointArray[3];
-    EXPECT_EQ(3, ByteArrayUtils::readStringAndAdvancePosition(buffer, MAX_WORD_LENGTH,
+    EXPECT_EQ(3, ByteArrayUtils::readStringAndAdvancePosition(buffer, MAX_WORD_LENGTH, nullptr,
             codePointArray, &pos));
     EXPECT_EQ(0x10FF00, codePointArray[0]);
     EXPECT_EQ(0x20, codePointArray[1]);
diff --git a/native/jni/tests/utils/int_array_view_test.cpp b/native/jni/tests/utils/int_array_view_test.cpp
index 934e27e..487bd04 100644
--- a/native/jni/tests/utils/int_array_view_test.cpp
+++ b/native/jni/tests/utils/int_array_view_test.cpp
@@ -124,5 +124,25 @@
     EXPECT_EQ(70, buffer[6]);
 }
 
+TEST(IntArrayViewTest, TestFirstOrDefault) {
+    const std::vector<int> intVector = {3, 2, 1, 0, -1, -2};
+    IntArrayView intArrayView(intVector);
+
+    EXPECT_EQ(3, intArrayView.firstOrDefault(10));
+    EXPECT_EQ(10, intArrayView.limit(0).firstOrDefault(10));
+    EXPECT_EQ(-10, intArrayView.limit(0).firstOrDefault(-10));
+    EXPECT_EQ(10, intArrayView.skip(6).firstOrDefault(10));
+}
+
+TEST(IntArrayViewTest, TestLastOrDefault) {
+    const std::vector<int> intVector = {3, 2, 1, 0, -1, -2};
+    IntArrayView intArrayView(intVector);
+
+    EXPECT_EQ(-2, intArrayView.lastOrDefault(10));
+    EXPECT_EQ(10, intArrayView.limit(0).lastOrDefault(10));
+    EXPECT_EQ(-10, intArrayView.limit(0).lastOrDefault(-10));
+    EXPECT_EQ(10, intArrayView.skip(6).lastOrDefault(10));
+}
+
 }  // namespace
 }  // namespace latinime
diff --git a/tests/Android.mk b/tests/Android.mk
index 5baebbd..a084ad1 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -24,6 +24,8 @@
 # Do not compress test data file
 LOCAL_AAPT_FLAGS += -0 .txt
 
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target android-support-test
+
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 8a628cd..26195d3 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -26,7 +26,7 @@
         <!-- meta-data android:name="com.android.contacts.iconset" android:resource="@xml/iconset" /-->
     </application>
 
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.inputmethod.latin"
         android:label="LatinIME tests">
     </instrumentation>
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
index 5708657..5bca2dc 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
@@ -51,7 +51,7 @@
     protected void setUp() throws Exception {
         super.setUp();
         final KeyboardTheme keyboardTheme = KeyboardTheme.searchKeyboardThemeById(
-                getKeyboardThemeForTests());
+                getKeyboardThemeForTests(), KeyboardTheme.KEYBOARD_THEMES);
         setContext(new ContextThemeWrapper(getContext(), keyboardTheme.mStyleId));
         KeyboardLayoutSet.onKeyboardThemeChanged();
 
@@ -117,12 +117,12 @@
     protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
             final EditorInfo editorInfo) {
         return createKeyboardLayoutSet(subtype, editorInfo, false /* voiceInputKeyEnabled */,
-                false /* languageSwitchKeyEnabled */);
+                false /* languageSwitchKeyEnabled */, false /* splitLayoutEnabled */);
     }
 
     protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
             final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
-            final boolean languageSwitchKeyEnabled) {
+            final boolean languageSwitchKeyEnabled, final boolean splitLayoutEnabled) {
         final Context context = getContext();
         final Resources res = context.getResources();
         final int keyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res);
@@ -131,7 +131,8 @@
         builder.setKeyboardGeometry(keyboardWidth, keyboardHeight)
                 .setSubtype(new RichInputMethodSubtype(subtype))
                 .setVoiceInputKeyEnabled(voiceInputKeyEnabled)
-                .setLanguageSwitchKeyEnabled(languageSwitchKeyEnabled);
+                .setLanguageSwitchKeyEnabled(languageSwitchKeyEnabled)
+                .setSplitLayoutEnabledByUser(splitLayoutEnabled);
         return builder.build();
     }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java
index c20954f..34cf407 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java
@@ -28,6 +28,8 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import java.util.Arrays;
+
 @SmallTest
 public class KeyboardThemeTests extends AndroidTestCase {
     private SharedPreferences mPrefs;
@@ -77,7 +79,9 @@
     }
 
     private void assertKeyboardTheme(final int sdkVersion, final int expectedThemeId) {
-        assertEquals(expectedThemeId, KeyboardTheme.getKeyboardTheme(mPrefs, sdkVersion).mThemeId);
+        final KeyboardTheme actualTheme = KeyboardTheme.getKeyboardTheme(
+                mPrefs, sdkVersion, KeyboardTheme.KEYBOARD_THEMES);
+        assertEquals(expectedThemeId, actualTheme.mThemeId);
     }
 
     /*
@@ -139,8 +143,8 @@
         final String oldPrefKey = KeyboardTheme.KLP_KEYBOARD_THEME_KEY;
         setKeyboardThemePreference(oldPrefKey, previousThemeId);
 
-        final KeyboardTheme defaultTheme =
-                KeyboardTheme.getDefaultKeyboardTheme(mPrefs, sdkVersion);
+        final KeyboardTheme defaultTheme = KeyboardTheme.getDefaultKeyboardTheme(
+                mPrefs, sdkVersion, KeyboardTheme.KEYBOARD_THEMES);
 
         assertNotNull(defaultTheme);
         assertEquals(expectedThemeId, defaultTheme.mThemeId);
@@ -194,7 +198,8 @@
         // Clean up new keyboard theme preference to simulate "upgrade to LXX keyboard".
         setKeyboardThemePreference(KeyboardTheme.LXX_KEYBOARD_THEME_KEY, THEME_ID_NULL);
 
-        final KeyboardTheme theme = KeyboardTheme.getKeyboardTheme(mPrefs, sdkVersion);
+        final KeyboardTheme theme = KeyboardTheme.getKeyboardTheme(
+                mPrefs, sdkVersion, KeyboardTheme.KEYBOARD_THEMES);
 
         assertNotNull(theme);
         assertEquals(expectedThemeId, theme.mThemeId);
@@ -341,4 +346,60 @@
         assertUpgradePlatformFromTo(
                 oldSdkVersion, newSdkVersion, THEME_ID_ILLEGAL, THEME_ID_LXX_LIGHT);
     }
+
+    /*
+     * Test for missing selected theme.
+     */
+    private static KeyboardTheme[] LIMITED_THEMES = {
+        KeyboardTheme.searchKeyboardThemeById(THEME_ID_ICS, KeyboardTheme.KEYBOARD_THEMES),
+        KeyboardTheme.searchKeyboardThemeById(THEME_ID_KLP, KeyboardTheme.KEYBOARD_THEMES)
+    };
+    static {
+        Arrays.sort(LIMITED_THEMES);
+    }
+
+    public void testMissingSelectedThemeIcs() {
+        // Clean up preferences.
+        setKeyboardThemePreference(KeyboardTheme.KLP_KEYBOARD_THEME_KEY, THEME_ID_NULL);
+        setKeyboardThemePreference(KeyboardTheme.LXX_KEYBOARD_THEME_KEY, THEME_ID_NULL);
+
+        final int sdkVersion = VERSION_CODES.ICE_CREAM_SANDWICH;
+        final String oldPrefKey = KeyboardTheme.getPreferenceKey(sdkVersion);
+        setKeyboardThemePreference(oldPrefKey, THEME_ID_LXX_LIGHT);
+
+        final KeyboardTheme actualTheme = KeyboardTheme.getKeyboardTheme(
+                mPrefs, sdkVersion, LIMITED_THEMES);
+        // LXX_LIGHT is missing, fall-back to KLP.
+        assertEquals(THEME_ID_KLP, actualTheme.mThemeId);
+    }
+
+    public void testMissingSelectedThemeKlp() {
+        // Clean up preferences.
+        setKeyboardThemePreference(KeyboardTheme.KLP_KEYBOARD_THEME_KEY, THEME_ID_NULL);
+        setKeyboardThemePreference(KeyboardTheme.LXX_KEYBOARD_THEME_KEY, THEME_ID_NULL);
+
+        final int sdkVersion = VERSION_CODES.KITKAT;
+        final String oldPrefKey = KeyboardTheme.getPreferenceKey(sdkVersion);
+        setKeyboardThemePreference(oldPrefKey, THEME_ID_LXX_LIGHT);
+
+        final KeyboardTheme actualTheme = KeyboardTheme.getKeyboardTheme(
+                mPrefs, sdkVersion, LIMITED_THEMES);
+        // LXX_LIGHT is missing, fall-back to KLP.
+        assertEquals(THEME_ID_KLP, actualTheme.mThemeId);
+    }
+
+    public void testMissingSelectedThemeLxx() {
+        // Clean up preferences.
+        setKeyboardThemePreference(KeyboardTheme.KLP_KEYBOARD_THEME_KEY, THEME_ID_NULL);
+        setKeyboardThemePreference(KeyboardTheme.LXX_KEYBOARD_THEME_KEY, THEME_ID_NULL);
+
+        final int sdkVersion = VERSION_CODES_LXX;
+        final String oldPrefKey = KeyboardTheme.getPreferenceKey(sdkVersion);
+        setKeyboardThemePreference(oldPrefKey, THEME_ID_LXX_DARK);
+
+        final KeyboardTheme actualTheme = KeyboardTheme.getKeyboardTheme(
+                mPrefs, sdkVersion, LIMITED_THEMES);
+        // LXX_DARK is missing, fall-back to KLP.
+        assertEquals(THEME_ID_KLP, actualTheme.mThemeId);
+    }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/EnglishSplitCustomizer.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/EnglishSplitCustomizer.java
new file mode 100644
index 0000000..b6d57d3
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/EnglishSplitCustomizer.java
@@ -0,0 +1,35 @@
+/*
+ * 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 com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
+
+import java.util.Locale;
+
+public class EnglishSplitCustomizer extends EnglishCustomizer {
+
+    EnglishSplitCustomizer(Locale locale) {
+        super(locale);
+    }
+
+    @Override
+    public ExpectedKey[] getSpaceKeys(final boolean isPhone) {
+        return LayoutBase.joinKeys(
+                LayoutBase.LANGUAGE_SWITCH_KEY, LayoutBase.SPACE_KEY, LayoutBase.SPACE_KEY);
+    }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java
index a22ed60..a8c4ac8 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java
@@ -54,7 +54,8 @@
                 + (isPhone() ? "phone" : "tablet");
         // TODO: Test with language switch key enabled and disabled.
         mKeyboardLayoutSet = createKeyboardLayoutSet(mSubtype, null /* editorInfo */,
-                true /* voiceInputKeyEnabled */, true /* languageSwitchKeyEnabled */);
+                true /* voiceInputKeyEnabled */, true /* languageSwitchKeyEnabled */,
+                false /* splitLayoutEnabled */);
     }
 
     @Override
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakEmail.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakEmail.java
index 37ca092..b25b846 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakEmail.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakEmail.java
@@ -44,12 +44,13 @@
     @Override
     protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
             final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
-            final boolean languageSwitchKeyEnabled) {
+            final boolean languageSwitchKeyEnabled, final boolean splitLayoutEnabled) {
         final EditorInfo emailField = new EditorInfo();
         emailField.inputType =
                 InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
         return super.createKeyboardLayoutSet(
-                subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled);
+                subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled,
+                splitLayoutEnabled);
     }
 
     private static class DvorakEmailCustomizer extends EnglishDvorakCustomizer {
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakUrl.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakUrl.java
index 3bcae0c..ba22f37 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakUrl.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakUrl.java
@@ -44,12 +44,13 @@
     @Override
     protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
             final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
-            final boolean languageSwitchKeyEnabled) {
+            final boolean languageSwitchKeyEnabled, final boolean splitLayoutEnabled) {
         final EditorInfo emailField = new EditorInfo();
         emailField.inputType =
                 InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI;
         return super.createKeyboardLayoutSet(
-                subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled);
+                subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled,
+                splitLayoutEnabled);
     }
 
     private static class DvorakUrlCustomizer extends EnglishDvorakCustomizer {
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyEmail.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyEmail.java
index 8563d69..f898632 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyEmail.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyEmail.java
@@ -42,12 +42,13 @@
     @Override
     protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
             final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
-            final boolean languageSwitchKeyEnabled) {
+            final boolean languageSwitchKeyEnabled, final boolean splitLayoutEnabled) {
         final EditorInfo emailField = new EditorInfo();
         emailField.inputType =
                 InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
         return super.createKeyboardLayoutSet(
-                subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled);
+                subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled,
+                splitLayoutEnabled);
     }
 
     private static class EnglishEmailCustomizer extends EnglishCustomizer {
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyUrl.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyUrl.java
index 1c1a2bb..0b69c7b 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyUrl.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyUrl.java
@@ -42,12 +42,13 @@
     @Override
     protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
             final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
-            final boolean languageSwitchKeyEnabled) {
+            final boolean languageSwitchKeyEnabled, final boolean splitLayoutEnabled) {
         final EditorInfo emailField = new EditorInfo();
         emailField.inputType =
                 InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI;
         return super.createKeyboardLayoutSet(
-                subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled);
+                subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled,
+                splitLayoutEnabled);
     }
 
     private static class EnglishUrlCustomizer extends EnglishCustomizer {
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsRomanian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsRomanian.java
index 0207f1c..d7b858e 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsRomanian.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsRomanian.java
@@ -59,9 +59,9 @@
                     // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
                     // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
                     .setMoreKeysOf("i", "\u00EE", "\u00EF", "\u00EC", "\u00ED", "\u012F", "\u012B")
+                    // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE
                     // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
                     // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
-                    // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE
                     // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
                     // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
                     // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
@@ -69,7 +69,7 @@
                     // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
                     // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
                     .setMoreKeysOf("a",
-                            "\u00E2", "\u00E3", "\u0103", "\u00E0", "\u00E1", "\u00E4", "\u00E6",
+                            "\u0103", "\u00E2", "\u00E3", "\u00E0", "\u00E1", "\u00E4", "\u00E6",
                             "\u00E5", "\u0101")
                     // U+0219: "ș" LATIN SMALL LETTER S WITH COMMA BELOW
                     // U+00DF: "ß" LATIN SMALL LETTER SHARP S
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSplitLayoutQwertyEnglishUS.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSplitLayoutQwertyEnglishUS.java
new file mode 100644
index 0000000..b9e40e0
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSplitLayoutQwertyEnglishUS.java
@@ -0,0 +1,47 @@
+/*
+ * 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 android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.Qwerty;
+
+import java.util.Locale;
+
+/**
+ * en_US: English (United States)/qwerty - split layout
+ */
+@SmallTest
+public class TestsSplitLayoutQwertyEnglishUS extends LayoutTestsBase {
+    private static final Locale LOCALE = new Locale("en", "US");
+    private static final LayoutBase LAYOUT = new Qwerty(new EnglishSplitCustomizer(LOCALE));
+
+    @Override
+    protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
+            final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
+            final boolean languageSwitchKeyEnabled, final boolean splitLayoutEnabled) {
+        return super.createKeyboardLayoutSet(subtype, editorInfo, voiceInputKeyEnabled,
+            languageSwitchKeyEnabled, true /* splitLayoutEnabled */);
+    }
+
+    @Override
+    LayoutBase getLayout() { return LAYOUT; }
+}
diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
index d7a649a..6860bea 100644
--- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
@@ -183,6 +183,9 @@
                 | InputType.TYPE_TEXT_FLAG_MULTI_LINE;
         mEditText.setInputType(inputType);
         mEditText.setEnabled(true);
+        if (null == Looper.myLooper()) {
+            Looper.prepare();
+        }
         setupService();
         mLatinIME = getService();
         setDebugMode(true);
diff --git a/tests/src/com/android/inputmethod/latin/settings/AccountsSettingsFragmentTests.java b/tests/src/com/android/inputmethod/latin/settings/AccountsSettingsFragmentTests.java
new file mode 100644
index 0000000..2ef8b54
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/settings/AccountsSettingsFragmentTests.java
@@ -0,0 +1,132 @@
+/*
+ * 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.latin.settings;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Intent;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.widget.ListView;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@MediumTest
+public class AccountsSettingsFragmentTests
+        extends ActivityInstrumentationTestCase2<TestFragmentActivity> {
+    private static final String FRAG_NAME = AccountsSettingsFragment.class.getName();
+    private static final long TEST_TIMEOUT_MILLIS = 5000;
+
+    private AlertDialog mDialog;
+
+    public AccountsSettingsFragmentTests() {
+        super(TestFragmentActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        Intent intent = new Intent();
+        intent.putExtra(TestFragmentActivity.EXTRA_SHOW_FRAGMENT, FRAG_NAME);
+        setActivityIntent(intent);
+    }
+
+    public void testEmptyAccounts() {
+        final AccountsSettingsFragment fragment =
+                (AccountsSettingsFragment) getActivity().mFragment;
+        try {
+            fragment.createAccountPicker(new String[0], null);
+            fail("Expected IllegalArgumentException, never thrown");
+        } catch (IllegalArgumentException expected) {
+            // Expected.
+        }
+    }
+
+    public void testMultipleAccounts_noCurrentAccount() {
+        final AccountsSettingsFragment fragment =
+                (AccountsSettingsFragment) getActivity().mFragment;
+        final CountDownLatch latch = new CountDownLatch(1);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mDialog = fragment.createAccountPicker(
+                        new String[] {
+                                "1@example.com",
+                                "2@example.com",
+                                "3@example.com",
+                                "4@example.com"},
+                        null);
+                mDialog.show();
+                latch.countDown();
+            }
+        });
+
+        try {
+            latch.await(TEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException ex) {
+            fail();
+        }
+        getInstrumentation().waitForIdleSync();
+        final ListView lv = mDialog.getListView();
+        // The 1st account should be checked by default.
+        assertEquals("checked-item", 0, lv.getCheckedItemPosition());
+        // There should be 4 accounts in the list.
+        assertEquals("count", 4, lv.getCount());
+        // The sign-out button shouldn't exist
+        assertEquals(View.GONE, mDialog.getButton(Dialog.BUTTON_NEUTRAL).getVisibility());
+        assertEquals(View.VISIBLE, mDialog.getButton(Dialog.BUTTON_NEGATIVE).getVisibility());
+        assertEquals(View.VISIBLE, mDialog.getButton(Dialog.BUTTON_POSITIVE).getVisibility());
+    }
+
+    public void testMultipleAccounts_currentAccount() {
+        final AccountsSettingsFragment fragment =
+                (AccountsSettingsFragment) getActivity().mFragment;
+        final CountDownLatch latch = new CountDownLatch(1);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mDialog = fragment.createAccountPicker(
+                        new String[] {
+                                "1@example.com",
+                                "2@example.com",
+                                "3@example.com",
+                                "4@example.com"},
+                        "3@example.com");
+                mDialog.show();
+                latch.countDown();
+            }
+        });
+
+        try {
+            latch.await(TEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException ex) {
+            fail();
+        }
+        getInstrumentation().waitForIdleSync();
+        final ListView lv = mDialog.getListView();
+        // The 3rd account should be checked by default.
+        assertEquals("checked-item", 2, lv.getCheckedItemPosition());
+        // There should be 4 accounts in the list.
+        assertEquals("count", 4, lv.getCount());
+        // The sign-out button should be shown
+        assertEquals(View.VISIBLE, mDialog.getButton(Dialog.BUTTON_NEUTRAL).getVisibility());
+        assertEquals(View.VISIBLE, mDialog.getButton(Dialog.BUTTON_NEGATIVE).getVisibility());
+        assertEquals(View.VISIBLE, mDialog.getButton(Dialog.BUTTON_POSITIVE).getVisibility());
+    }
+}
diff --git a/tests/src/com/android/inputmethod/latin/utils/DistracterFilterTest.java b/tests/src/com/android/inputmethod/latin/utils/DistracterFilterTest.java
index 5fbd36a..6ed9120 100644
--- a/tests/src/com/android/inputmethod/latin/utils/DistracterFilterTest.java
+++ b/tests/src/com/android/inputmethod/latin/utils/DistracterFilterTest.java
@@ -57,7 +57,7 @@
         mDistracterFilter.close();
     }
 
-    public void testIsDistractorToWordsInDictionaries() {
+    public void testIsDistracterToWordsInDictionaries() {
         final PrevWordsInfo EMPTY_PREV_WORDS_INFO = PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
 
         final Locale localeEnUs = new Locale("en", "US");
diff --git a/tools/make-keyboard-text/res/values-ro/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ro/donottranslate-more-keys.xml
index 6286c7b..834e039 100644
--- a/tools/make-keyboard-text/res/values-ro/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-ro/donottranslate-more-keys.xml
@@ -18,16 +18,16 @@
 */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+    <!-- U+0103: "ă" LATIN SMALL LETTER A WITH BREVE
+         U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
          U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
-         U+0103: "ă" LATIN SMALL LETTER A WITH BREVE
          U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
          U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
          U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
          U+00E6: "æ" LATIN SMALL LETTER AE
          U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
          U+0101: "ā" LATIN SMALL LETTER A WITH MACRON -->
-    <string name="morekeys_a">&#x00E2;,&#x00E3;,&#x0103;,&#x00E0;,&#x00E1;,&#x00E4;,&#x00E6;,&#x00E5;,&#x0101;</string>
+    <string name="morekeys_a">&#x0103;,&#x00E2;,&#x00E3;,&#x00E0;,&#x00E1;,&#x00E4;,&#x00E6;,&#x00E5;,&#x0101;</string>
     <!-- U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
          U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
          U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE