diff options
95 files changed, 2462 insertions, 664 deletions
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml index f0b47be0e..90f321b01 100644 --- a/java/res/values-af/strings.xml +++ b/java/res/values-af/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android-sleutelbord (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Android-sleutelbord-instellings (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Android-speltoetser (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Android-speltoetserinstellings (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Invoeropsies"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Navorsing-loglêerbevele"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Soek kontakname op"</string> diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml index f6ccec71a..7a6dd1d16 100644 --- a/java/res/values-am/strings.xml +++ b/java/res/values-am/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"የAndroid ቁልፍ ሰሌዳ (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"የAndroid ቁልፍ ሰሌዳ ቅንብሮች (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Android ፊደል አራሚ (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"የAndroid ፊደል አራሚ ቅንብሮች (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"ግቤት አማራጮች"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"የጥናት የምዝግብ ማስታወሻ ትዕዛዞች"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"የእውቅያ ስሞችን ተመልከት"</string> diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml index f9b01d377..e9f92373c 100644 --- a/java/res/values-ar/strings.xml +++ b/java/res/values-ar/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"لوحة مفاتيح Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"إعدادات لوحة مفاتيح Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"المدقق الإملائي في Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"إعدادات المدقق الإملائي في Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"خيارات الإرسال"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"أوامر سجلات البحث"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"بحث في أسماء جهات الاتصال"</string> diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml index 6c95cceba..c32a56d1d 100644 --- a/java/res/values-be/strings.xml +++ b/java/res/values-be/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Клавіятура Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Налады клавіятуры Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Iнструмент праверкi правапiсу для Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Налады інструмента праверкі правапісу для Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Параметры ўводу"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Каманды гiсторыя даследаванняў"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Шукаць імёны кантактаў"</string> diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml index 58a6a7083..5feac034b 100644 --- a/java/res/values-bg/strings.xml +++ b/java/res/values-bg/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Клавиатура на Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Настройки на клавиатурата на Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Програма за правописна проверка за Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Настройки на програмата за правописна проверка за Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Опции за въвеждане"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Команди за рег. файл за проучвания"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Търсене на имена"</string> diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml index 5539fee7e..3ebf6397c 100644 --- a/java/res/values-ca/strings.xml +++ b/java/res/values-ca/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Teclat d\'Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Configuració del teclat d\'Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Corrector ortogràfic d\'Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Configuració del corrector ortogràfic d\'Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opcions d\'entrada"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Recerca d\'ordres de reg."</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cerca noms de contactes"</string> diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml index c7261ba7f..050ae6481 100644 --- a/java/res/values-cs/strings.xml +++ b/java/res/values-cs/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Klávesnice Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Nastavení klávesnice Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Kontrola pravopisu Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Nastavení kontroly pravopisu Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Možnosti zadávání textu a dat"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Příkazy vývoj. protokolu"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Vyhledat kontakty"</string> diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml index 1ed998359..034c98f62 100644 --- a/java/res/values-da/strings.xml +++ b/java/res/values-da/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android-tastatur (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Indstillinger for Android-tastatur (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Android-stavekontrol (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Indstillinger for Android-stavekontrol (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Indstillinger for input"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Forskningslogkommandoer"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Slå kontaktnavne op"</string> diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml index 9816621c6..39444ea2f 100644 --- a/java/res/values-de/strings.xml +++ b/java/res/values-de/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android-Tastatur (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Android-Tastatureinstellungen (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Android-Rechtschreibprüfung (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Einstellungen für die Android-Rechtschreibprüfung (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Eingabeoptionen"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Forschungsprotokollbefehle"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontaktnamen prüfen"</string> diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml index f3b84c60b..93de977a7 100644 --- a/java/res/values-el/strings.xml +++ b/java/res/values-el/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Πληκτρολόγιο Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Ρυθμίσεις πληκτρολογίου Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Ορθογραφικός έλεγχος Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Ρυθμίσεις ορθογραφικού ελέγχου Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Επιλογές εισόδου"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Έρευνα εντολών καταγραφής"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Αναζήτηση ονομάτων επαφών"</string> diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml index c7f20aae3..a544f7798 100644 --- a/java/res/values-es-rUS/strings.xml +++ b/java/res/values-es-rUS/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Teclado de Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Configuración del teclado de Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Corrector ortográfico de Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Configuración del corrector ortográfico de Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opciones de entrada"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Comandos registro invest."</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Buscar nombres contactos"</string> diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml index 81682589a..afc04f5b7 100644 --- a/java/res/values-es/strings.xml +++ b/java/res/values-es/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Teclado Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Ajustes del teclado de Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Corrector de Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Ajustes del corrector de Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opciones entrada texto"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Comandos registro investigación"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Nombres de contactos"</string> diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml index 8968bf4f8..acfa957f9 100644 --- a/java/res/values-et/strings.xml +++ b/java/res/values-et/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Androidi klaviatuur (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Androidi klaviatuuri seaded (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Androidi õigekirjakontroll (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Androidi õigekirjakontrolli seaded (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Sisestusvalikud"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Uuringulogi käsud"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontakti nimede kontroll."</string> diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml index 723ecd631..52d5b835e 100644 --- a/java/res/values-fa/strings.xml +++ b/java/res/values-fa/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"صفحه کلید Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"تنظیمات صفحه کلید Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"غلطگیر Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"تنظیمات غلطگیر Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"گزینههای ورودی"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"فرمانهای گزارشگیری پژوهش"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"جستجوی نام مخاطبین"</string> diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml index 2e6e4d1ce..8f36524df 100644 --- a/java/res/values-fi/strings.xml +++ b/java/res/values-fi/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android-näppäimistö (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Android-näppäimistön asetukset (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Android-oikoluku (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Android-oikoluvun asetukset (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Syöttövalinnat"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Tutkimuslokin komennot"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Hae kontaktien nimiä"</string> diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml index 2b8e3cbae..4daa0f6d9 100644 --- a/java/res/values-fr/strings.xml +++ b/java/res/values-fr/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Clavier Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Paramètres du clavier Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Correcteur orthographique Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Paramètres du correcteur orthographique Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Options de saisie"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Commandes journaux rech."</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Rechercher noms contacts"</string> diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml index 28c48791e..c4238e88f 100644 --- a/java/res/values-hi/strings.xml +++ b/java/res/values-hi/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android कीबोर्ड (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Android कीबोर्ड सेटिंग (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Android वर्तनी परीक्षक (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Android वर्तनी परीक्षक सेटिंग (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"इनपुट विकल्प"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"लॉग आदेशों का शोध करें"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"संपर्क नामों को खोजें"</string> diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml index 473287698..a5515cf06 100644 --- a/java/res/values-hr/strings.xml +++ b/java/res/values-hr/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Androidova tipkovnica (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Postavke Androidove tipkovnice (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Androidova provjera pravopisa (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Postavke Androidove provjere pravopisa (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opcije ulaza"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Istraživanje naredbi dnevnika"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Potražite imena kontakata"</string> diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml index 68ca03e63..d6075f778 100644 --- a/java/res/values-hu/strings.xml +++ b/java/res/values-hu/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android-billentyűzet (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Android-billentyűzet beállításai (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Androidos helyesírás-ellenőrző (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Androidos helyesírás-ellenőrző beállításai (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Beviteli beállítások"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Naplózási parancsok"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Névjegyek keresése"</string> diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml index e361e6951..953e0919d 100644 --- a/java/res/values-in/strings.xml +++ b/java/res/values-in/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Keyboard Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Setelan Keyboard Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Pemeriksa Ejaan Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Setelan Pemeriksa Ejaan Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opsi masukan"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Riset Perintah Log"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cari nama kontak"</string> diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml index 52c2bfa88..7ce349a5e 100644 --- a/java/res/values-it/strings.xml +++ b/java/res/values-it/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Tastiera Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Impostazioni tastiera Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Controllo ortografico Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Impostazioni controllo ortografico Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opzioni inserimento"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Ricerca comandi di log"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cerca in nomi contatti"</string> diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml index a2359378d..e3d3064b2 100644 --- a/java/res/values-iw/strings.xml +++ b/java/res/values-iw/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"מקלדת Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"הגדרות מקלדת Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"בודק האיות של Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"הגדרות בודק האיות של Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"אפשרויות קלט"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"פקודות יומן מחקר"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"חפש שמות של אנשי קשר"</string> diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml index a3da75200..6d6259d13 100644 --- a/java/res/values-ja/strings.xml +++ b/java/res/values-ja/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Androidキーボード(AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Androidキーボードの設定(AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Androidスペルチェッカー(AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Androidスペルチェッカーの設定(AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"入力オプション"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"ログコマンドの検索"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"連絡先名の検索"</string> diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml index 1f4596bbc..c58613dd7 100644 --- a/java/res/values-ko/strings.xml +++ b/java/res/values-ko/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android 키보드(AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Android 키보드 설정(AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Android 맞춤법 검사기(AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Android 맞춤법 검사기 설정(AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"입력 옵션"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"로그 명령 탐색"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"연락처 이름 조회"</string> diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml index 307b5f234..57cf7bdfd 100644 --- a/java/res/values-lt/strings.xml +++ b/java/res/values-lt/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"„Android“ klaviatūra (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"„Android“ klaviatūros nustatymai (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"„Android“ rašybos tikrinimo programa (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"„Android“ rašybos tikrinimo programos nustatymai (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Įvesties parinktys"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Tyrinėti žurnalo komandas"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontaktų vardų paieška"</string> diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml index 0241583f6..499a451d1 100644 --- a/java/res/values-lv/strings.xml +++ b/java/res/values-lv/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android tastatūra (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Android tastatūras iestatījumi (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Android pareizrakstības pārbaudītājs (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Android pareizrakstības pārbaudītāja iestatījumi (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Ievades opcijas"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Izpētes žurnāla komandas"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Meklēt kontaktp. vārdus"</string> diff --git a/java/res/values-ms/strings.xml b/java/res/values-ms/strings.xml index afb036a89..faf91646a 100644 --- a/java/res/values-ms/strings.xml +++ b/java/res/values-ms/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Papan kekunci Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Tetapan Papan Kekunci Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Penyemak Ejaan Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Tetapan Penyemak Ejaan Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Pilihan input"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Arahan Log Penyelidikan"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cari nama kenalan"</string> diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml index 5db141c06..cd2606d75 100644 --- a/java/res/values-nb/strings.xml +++ b/java/res/values-nb/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android-tastatur (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Instillinger for Android-tastatur (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Android-stavekontroll (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Innstillinger for Android-stavekontroll (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Inndataalternativer"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Kommandoer for undersøkelseslogging"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Slå opp kontaktnavn"</string> diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml index 176f828cc..fb2a82e40 100644 --- a/java/res/values-nl/strings.xml +++ b/java/res/values-nl/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android-toetsenbord (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Instellingen voor het Android-toetsenbord (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Spellingcontrole van Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Instellingen voor spellingcontrole van Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Invoeropties"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Opdrachten in onderzoekslogbestand"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Contactnamen opzoeken"</string> diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml index 34a03f6d3..f703a74e2 100644 --- a/java/res/values-pl/strings.xml +++ b/java/res/values-pl/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Klawiatura Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Ustawienia klawiatury Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Sprawdzanie pisowni na Androidzie (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Ustawienia sprawdzania pisowni na Androidzie (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opcje wprowadzania"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Polecenia dziennika badań"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Przeszukaj kontakty"</string> diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml index 81e1485e1..9c52fd76c 100644 --- a/java/res/values-pt-rPT/strings.xml +++ b/java/res/values-pt-rPT/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Teclado Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Definições do Teclado Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Verificador Ortográfico Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Definições do Verificador Ortográfico Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opções de introdução"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Comandos de Reg. Invest."</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Procurar nomes de contac."</string> diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml index 880aca65d..dd1fcfd03 100644 --- a/java/res/values-pt/strings.xml +++ b/java/res/values-pt/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Teclado Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Configurações de teclado Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Corretor ortográfico do Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Configurações de corretor ortográfico do Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opções de entrada"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Pesq. comandos de reg."</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Buscar nomes de contatos"</string> diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml index a62bfd274..b0732c802 100644 --- a/java/res/values-ro/strings.xml +++ b/java/res/values-ro/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Tastatură Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Setări tastatură Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Verificator ortografic Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Setări verificator ortografic Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opţiuni de introducere text"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Comenzi jurnal cercetare"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Verificare nume în agendă"</string> diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml index dab73870e..b3d770679 100644 --- a/java/res/values-ru/strings.xml +++ b/java/res/values-ru/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Клавиатура Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Настройки клавиатуры Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Проверка правописания Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Настройки проверки правописания Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Настройки"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Все команды"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Поиск контактов"</string> diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml index d6d8068b7..77d9409ae 100644 --- a/java/res/values-sk/strings.xml +++ b/java/res/values-sk/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Klávesnica Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Nastavenia klávesnice Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Kontrola pravopisu (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Nastavenia kontroly pravopisu Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Možnosti zadávania textu a údajov"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Príkazy denníka výskumu"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Vyhľadať kontakty"</string> diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml index 37540c3f7..87961ef2f 100644 --- a/java/res/values-sl/strings.xml +++ b/java/res/values-sl/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Tipkovnica za Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Nastavitve tipkovnice za Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Črkovalnik za Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Nastavitve črkovalnika za Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Možnosti vnosa"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Ukazi za dnevnik raziskav"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Iskanje imen stikov"</string> diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml index 8b8720f59..d8b3dbfbe 100644 --- a/java/res/values-sr/strings.xml +++ b/java/res/values-sr/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android тастатура (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Подешавања Android тастатуре (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Android провера правописа (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Подешавања Android провере правописа (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Опције уноса"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Команде евиденције истраживања"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Потражи имена контаката"</string> diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml index 6ceed109b..d17893380 100644 --- a/java/res/values-sv/strings.xml +++ b/java/res/values-sv/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Androids tangentbord (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Inställningar för Androids tangentbord (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Stavningskontroll i Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Inställningar för Androids stavningskontroll (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Inmatningsalternativ"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Loggkommandon"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Sök namn på kontakter"</string> diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml index 5b566016d..290952645 100644 --- a/java/res/values-sw/strings.xml +++ b/java/res/values-sw/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Kibodi ya Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Mipangilio ya Kibodi ya Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Kikagua-tahajia cha Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Mipangilio ya Kikagua-tahajia cha Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Chaguo za uingizaji"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Amri za Kumbukumbu za Utafiti"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Angalia majina ya unaowasiliana nao"</string> diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml index 28580762f..142903ca2 100644 --- a/java/res/values-th/strings.xml +++ b/java/res/values-th/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"แป้นพิมพ์แอนดรอยด์ (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"การตั้งค่าแป้นพิมพ์แอนดรอยด์ (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"เครื่องตรวจตัวสะกดแอนดรอยด์ (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"การตั้งค่าเครื่องตรวจตัวสะกดแอนดรอยด์ (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"ตัวเลือกการป้อนข้อมูล"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"คำสั่งบันทึกการวิจัย"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"ค้นหารายชื่อติดต่อ"</string> diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml index 04127ab61..fea07b446 100644 --- a/java/res/values-tl/strings.xml +++ b/java/res/values-tl/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android Keyboard (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Mga Setting ng Android Keyboard (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Spell Checker ng Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Mga Setting ng Spell Checker ng Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Mga pagpipilian sa input"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Cmmnd sa Log ng Pnnliksik"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Maghanap pangalan contact"</string> diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml index f238f20d2..b976932de 100644 --- a/java/res/values-tr/strings.xml +++ b/java/res/values-tr/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android klavye (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Android Klavye Ayarları (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Android Yazım Denetleyici (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Android Yazım Denetleyici Ayarları (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Giriş seçenekleri"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Araştırma Günlüğü Komutları"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kişi adlarını denetle"</string> diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml index 42a0b9f26..f81ace632 100644 --- a/java/res/values-uk/strings.xml +++ b/java/res/values-uk/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Клавіатура Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Налаштування клавіатури Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Перевірка орфографії Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Налаштування перевірки орфографії Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Парам. введення"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Команди журналу дослідж."</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Шукати імена контактів"</string> diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml index 245e68541..fac412a57 100644 --- a/java/res/values-vi/strings.xml +++ b/java/res/values-vi/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Bàn phím Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Cài đặt bàn phím Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Trình kiểm tra chính tả Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Cài đặt trình kiểm tra chính tả Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Tùy chọn nhập"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Lệnh ghi nhật ký cho nghiên cứu"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Tra cứu tên liên hệ"</string> diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml index cba33224b..693a6746d 100644 --- a/java/res/values-zh-rCN/strings.xml +++ b/java/res/values-zh-rCN/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android 键盘 (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Android 键盘设置 (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Android 拼写检查工具 (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Android 拼写检查工具设置 (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"输入选项"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"研究记录命令"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"查找联系人姓名"</string> diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml index 9a4896974..1fb204f2e 100644 --- a/java/res/values-zh-rTW/strings.xml +++ b/java/res/values-zh-rTW/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Android 鍵盤 (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Android 鍵盤設定 (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Android 拼字檢查 (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Android 拼字檢查設定 (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"輸入選項"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"研究紀錄指令"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"查詢聯絡人姓名"</string> diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml index e360750dc..bcec13d4b 100644 --- a/java/res/values-zu/strings.xml +++ b/java/res/values-zu/strings.xml @@ -20,14 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for aosp_android_keyboard_ime_name (8250992613616792321) --> - <skip /> - <!-- no translation found for aosp_android_keyboard_ime_settings (423615877174850267) --> - <skip /> - <!-- no translation found for aosp_spell_checker_service_name (511950477199948048) --> - <skip /> - <!-- no translation found for aosp_android_spell_checker_service_settings (2970535894327288421) --> - <skip /> + <string name="aosp_android_keyboard_ime_name" msgid="8250992613616792321">"Ikhibhodi ye-Android (AOSP)"</string> + <string name="aosp_android_keyboard_ime_settings" msgid="423615877174850267">"Izilungiselelo zekhibhodi ye-Android (AOSP)"</string> + <string name="aosp_spell_checker_service_name" msgid="511950477199948048">"Isihloli sokupela se-Android (AOSP)"</string> + <string name="aosp_android_spell_checker_service_settings" msgid="2970535894327288421">"Izilungiselelo zesihloli sokupela se-Android (AOSP)"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Okukhethwa kukho kokungenayo"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Imiyalo yefayela lokungena lokucwaninga"</string> <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Bheka amagama woxhumana nabo"</string> diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index ebcd3d956..201fc7030 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -350,10 +350,10 @@ <!-- Inform the user that a particular language has an available dictionary --> <string name="has_dictionary">Dictionary available</string> - <!-- Preferences item for enabling to send user statistics to Google --> + <!-- Preferences item for enabling to send user statistics for development only diagnostics --> <string name="prefs_enable_log">Enable user feedback</string> - <!-- Description for enabling to send user statistics to Google --> - <string name="prefs_description_log">Help improve this input method editor by automatically sending usage statistics and crash reports to Google.</string> + <!-- Description for enabling to send user statistics for development only diagnostics --> + <string name="prefs_description_log">Help improve this input method editor by automatically sending usage statistics and crash reports</string> <!-- Title of the item to change the keyboard theme [CHAR LIMIT=20]--> <string name="keyboard_layout">Keyboard theme</string> @@ -422,12 +422,12 @@ <!-- Title of an option for usability study mode --> <string name="prefs_usability_study_mode">Usability study mode</string> - <!-- Title of the settings for key long press delay --> - <string name="prefs_key_longpress_timeout_settings">Key long press delay settings</string> - <!-- Title of the settings for keypress vibration duration --> - <string name="prefs_keypress_vibration_duration_settings">Keypress vibration duration settings</string> - <!-- Title of the settings for keypress sound volume --> - <string name="prefs_keypress_sound_volume_settings">Keypress sound volume settings</string> + <!-- Title of the settings for key long press delay [CHAR LIMIT=30] --> + <string name="prefs_key_longpress_timeout_settings">Key long press delay</string> + <!-- Title of the settings for keypress vibration duration [CHAR LIMIT=30] --> + <string name="prefs_keypress_vibration_duration_settings">Keypress vibration duration</string> + <!-- Title of the settings for keypress sound volume [CHAR LIMIT=30] --> + <string name="prefs_keypress_sound_volume_settings">Keypress sound volume</string> <!-- Title of the settings for reading an external dictionary file --> <string name="prefs_read_external_dictionary">Read external dictionary file</string> <!-- Message to show when there are no files to install as an external dictionary [CHAR LIMIT=100] --> diff --git a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java index b047fe038..e3e6d39e4 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java @@ -44,6 +44,7 @@ final class GesturePreviewTrail { // The wall time of the zero value in {@link #mEventTimes} private long mCurrentTimeBase; private int mTrailStartIndex; + private int mLastInterpolatedDrawIndex; static final class Params { public final int mTrailColor; @@ -96,6 +97,17 @@ final class GesturePreviewTrail { } final int[] eventTimes = mEventTimes.getPrimitiveArray(); final int strokeId = stroke.getGestureStrokeId(); + // Because interpolation algorithm in {@link GestureStrokeWithPreviewPoints} can't determine + // the interpolated points in the last segment of gesture stroke, it may need recalculation + // of interpolation when new segments are added to the stroke. + // {@link #mLastInterpolatedDrawIndex} holds the start index of the last segment. It may + // be updated by the interpolation + // {@link GestureStrokeWithPreviewPoints#interpolatePreviewStroke} + // or by animation {@link #drawGestureTrail(Canvas,Paint,Rect,Params)} below. + final int lastInterpolatedIndex = (strokeId == mCurrentStrokeId) + ? mLastInterpolatedDrawIndex : trailSize; + mLastInterpolatedDrawIndex = stroke.interpolateStrokeAndReturnStartIndexOfLastSegment( + lastInterpolatedIndex, mEventTimes, mXCoordinates, mYCoordinates); if (strokeId != mCurrentStrokeId) { final int elapsedTime = (int)(downTime - mCurrentTimeBase); for (int i = mTrailStartIndex; i < trailSize; i++) { @@ -216,6 +228,10 @@ final class GesturePreviewTrail { System.arraycopy(eventTimes, startIndex, eventTimes, 0, newSize); System.arraycopy(xCoords, startIndex, xCoords, 0, newSize); System.arraycopy(yCoords, startIndex, yCoords, 0, newSize); + // The start index of the last segment of the stroke + // {@link mLastInterpolatedDrawIndex} should also be updated because all array + // elements have just been shifted for compaction. + mLastInterpolatedDrawIndex = Math.max(mLastInterpolatedDrawIndex - startIndex, 0); } mEventTimes.setLength(newSize); mXCoordinates.setLength(newSize); diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java index fc81410ff..3315954c1 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java @@ -21,19 +21,32 @@ import com.android.inputmethod.latin.ResizableIntArray; public final class GestureStrokeWithPreviewPoints extends GestureStroke { public static final int PREVIEW_CAPACITY = 256; + private static final boolean ENABLE_INTERPOLATION = true; + private final ResizableIntArray mPreviewEventTimes = new ResizableIntArray(PREVIEW_CAPACITY); private final ResizableIntArray mPreviewXCoordinates = new ResizableIntArray(PREVIEW_CAPACITY); private final ResizableIntArray mPreviewYCoordinates = new ResizableIntArray(PREVIEW_CAPACITY); private int mStrokeId; private int mLastPreviewSize; + private final HermiteInterpolator mInterpolator = new HermiteInterpolator(); + private int mLastInterpolatedPreviewIndex; - private int mMinPreviewSampleLengthSquare; + private int mMinPreviewSamplingDistanceSquared; private int mLastX; private int mLastY; + private double mMinPreviewSamplingDistance; + private double mDistanceFromLastSample; - // TODO: Move this to resource. - private static final float MIN_PREVIEW_SAMPLE_LENGTH_RATIO_TO_KEY_WIDTH = 0.1f; + // TODO: Move these constants to resource. + // The minimum linear distance between sample points for preview in keyWidth unit. + private static final float MIN_PREVIEW_SAMPLING_RATIO_TO_KEY_WIDTH = 0.1f; + // The minimum trail distance between sample points for preview in keyWidth unit when using + // interpolation. + private static final float MIN_PREVIEW_SAMPLING_RATIO_TO_KEY_WIDTH_WITH_INTERPOLATION = 0.2f; + // The angular threshold to use interpolation in radian. PI/12 is 15 degree. + private static final double INTERPOLATION_ANGULAR_THRESHOLD = Math.PI / 12.0d; + private static final int MAX_INTERPOLATION_PARTITION = 4; public GestureStrokeWithPreviewPoints(final int pointerId, final GestureStrokeParams params) { super(pointerId, params); @@ -44,6 +57,7 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { super.reset(); mStrokeId++; mLastPreviewSize = 0; + mLastInterpolatedPreviewIndex = 0; mPreviewEventTimes.setLength(0); mPreviewXCoordinates.setLength(0); mPreviewYCoordinates.setLength(0); @@ -53,35 +67,49 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { return mStrokeId; } - public int getGestureStrokePreviewSize() { - return mPreviewEventTimes.getLength(); - } - @Override public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) { super.setKeyboardGeometry(keyWidth, keyboardHeight); - final float sampleLength = keyWidth * MIN_PREVIEW_SAMPLE_LENGTH_RATIO_TO_KEY_WIDTH; - mMinPreviewSampleLengthSquare = (int)(sampleLength * sampleLength); + final float samplingRatioToKeyWidth = ENABLE_INTERPOLATION + ? MIN_PREVIEW_SAMPLING_RATIO_TO_KEY_WIDTH_WITH_INTERPOLATION + : MIN_PREVIEW_SAMPLING_RATIO_TO_KEY_WIDTH; + mMinPreviewSamplingDistance = keyWidth * samplingRatioToKeyWidth; + mMinPreviewSamplingDistanceSquared = (int)( + mMinPreviewSamplingDistance * mMinPreviewSamplingDistance); } - private boolean needsSampling(final int x, final int y) { + private boolean needsSampling(final int x, final int y, final boolean isMajorEvent) { + if (ENABLE_INTERPOLATION) { + mDistanceFromLastSample += Math.hypot(x - mLastX, y - mLastY); + mLastX = x; + mLastY = y; + if (mDistanceFromLastSample >= mMinPreviewSamplingDistance) { + mDistanceFromLastSample = 0.0d; + return true; + } + return false; + } + final int dx = x - mLastX; final int dy = y - mLastY; - return dx * dx + dy * dy >= mMinPreviewSampleLengthSquare; + if (isMajorEvent || dx * dx + dy * dy >= mMinPreviewSamplingDistanceSquared) { + mLastX = x; + mLastY = y; + return true; + } + return false; } @Override public boolean addPointOnKeyboard(final int x, final int y, final int time, final boolean isMajorEvent) { - final boolean onValidArea = super.addPointOnKeyboard(x, y, time, isMajorEvent); - if (isMajorEvent || needsSampling(x, y)) { + if (needsSampling(x, y, isMajorEvent)) { mPreviewEventTimes.add(time); mPreviewXCoordinates.add(x); mPreviewYCoordinates.add(y); - mLastX = x; - mLastY = y; } - return onValidArea; + return super.addPointOnKeyboard(x, y, time, isMajorEvent); + } public void appendPreviewStroke(final ResizableIntArray eventTimes, @@ -95,4 +123,82 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { yCoords.append(mPreviewYCoordinates, mLastPreviewSize, length); mLastPreviewSize = mPreviewEventTimes.getLength(); } + + /** + * Calculate interpolated points between the last interpolated point and the end of the trail. + * And return the start index of the last interpolated segment of input arrays because it + * may need to recalculate the interpolated points in the segment if further segments are + * added to this stroke. + * + * @param lastInterpolatedIndex the start index of the last interpolated segment of + * <code>eventTimes</code>, <code>xCoords</code>, and <code>yCoords</code>. + * @param eventTimes the event time array of gesture preview trail to be drawn. + * @param xCoords the x-coordinates array of gesture preview trail to be drawn. + * @param yCoords the y-coordinates array of gesture preview trail to be drawn. + * @return the start index of the last interpolated segment of input arrays. + */ + public int interpolateStrokeAndReturnStartIndexOfLastSegment(final int lastInterpolatedIndex, + final ResizableIntArray eventTimes, final ResizableIntArray xCoords, + final ResizableIntArray yCoords) { + if (!ENABLE_INTERPOLATION) { + return lastInterpolatedIndex; + } + final int size = mPreviewEventTimes.getLength(); + final int[] pt = mPreviewEventTimes.getPrimitiveArray(); + final int[] px = mPreviewXCoordinates.getPrimitiveArray(); + final int[] py = mPreviewYCoordinates.getPrimitiveArray(); + mInterpolator.reset(px, py, 0, size); + // The last segment of gesture stroke needs to be interpolated again because the slope of + // the tangent at the last point isn't determined. + int lastInterpolatedDrawIndex = lastInterpolatedIndex; + int d1 = lastInterpolatedIndex; + for (int p2 = mLastInterpolatedPreviewIndex + 1; p2 < size; p2++) { + final int p1 = p2 - 1; + final int p0 = p1 - 1; + final int p3 = p2 + 1; + mLastInterpolatedPreviewIndex = p1; + lastInterpolatedDrawIndex = d1; + mInterpolator.setInterval(p0, p1, p2, p3); + final double m1 = Math.atan2(mInterpolator.mSlope1Y, mInterpolator.mSlope1X); + final double m2 = Math.atan2(mInterpolator.mSlope2Y, mInterpolator.mSlope2X); + final double dm = Math.abs(angularDiff(m2, m1)); + final int partition = Math.min((int)Math.ceil(dm / INTERPOLATION_ANGULAR_THRESHOLD), + MAX_INTERPOLATION_PARTITION); + final int t1 = eventTimes.get(d1); + final int dt = pt[p2] - pt[p1]; + d1++; + for (int i = 1; i < partition; i++) { + final float t = i / (float)partition; + mInterpolator.interpolate(t); + eventTimes.add(d1, (int)(dt * t) + t1); + xCoords.add(d1, (int)mInterpolator.mInterpolatedX); + yCoords.add(d1, (int)mInterpolator.mInterpolatedY); + d1++; + } + eventTimes.add(d1, pt[p2]); + xCoords.add(d1, px[p2]); + yCoords.add(d1, py[p2]); + } + return lastInterpolatedDrawIndex; + } + + private static final double TWO_PI = Math.PI * 2.0d; + + /** + * Calculate the angular of rotation from <code>a0</code> to <code>a1</code>. + * + * @param a1 the angular to which the rotation ends. + * @param a0 the angular from which the rotation starts. + * @return the angular rotation value from a0 to a1, normalized to [-PI, +PI]. + */ + private static double angularDiff(final double a1, final double a0) { + double deltaAngle = a1 - a0; + while (deltaAngle > Math.PI) { + deltaAngle -= TWO_PI; + } + while (deltaAngle < -Math.PI) { + deltaAngle += TWO_PI; + } + return deltaAngle; + } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/HermiteInterpolator.java b/java/src/com/android/inputmethod/keyboard/internal/HermiteInterpolator.java new file mode 100644 index 000000000..0ec8153f5 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/HermiteInterpolator.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2013 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.internal; + +import com.android.inputmethod.annotations.UsedForTesting; + +/** + * Interpolates XY-coordinates using Cubic Hermite Curve. + */ +public final class HermiteInterpolator { + private int[] mXCoords; + private int[] mYCoords; + private int mMinPos; + private int mMaxPos; + + // Working variable to calculate interpolated value. + /** The coordinates of the start point of the interval. */ + public int mP1X, mP1Y; + /** The coordinates of the end point of the interval. */ + public int mP2X, mP2Y; + /** The slope of the tangent at the start point. */ + public float mSlope1X, mSlope1Y; + /** The slope of the tangent at the end point. */ + public float mSlope2X, mSlope2Y; + /** The interpolated coordinates. + * The return variables of {@link #interpolate(float)} to avoid instantiations. + */ + public float mInterpolatedX, mInterpolatedY; + + public HermiteInterpolator() { + // Nothing to do with here. + } + + /** + * Reset this interpolator to point XY-coordinates data. + * @param xCoords the array of x-coordinates. Valid data are in left-open interval + * <code>[minPos, maxPos)</code>. + * @param yCoords the array of y-coordinates. Valid data are in left-open interval + * <code>[minPos, maxPos)</code>. + * @param minPos the minimum index of left-open interval of valid data. + * @param maxPos the maximum index of left-open interval of valid data. + */ + @UsedForTesting + public void reset(final int[] xCoords, final int[] yCoords, final int minPos, + final int maxPos) { + mXCoords = xCoords; + mYCoords = yCoords; + mMinPos = minPos; + mMaxPos = maxPos; + } + + /** + * Set interpolation interval. + * <p> + * The start and end coordinates of the interval will be set in {@link #mP1X}, {@link #mP1Y}, + * {@link #mP2X}, and {@link #mP2Y}. The slope of the tangents at start and end points will be + * set in {@link #mSlope1X}, {@link #mSlope1Y}, {@link #mSlope2X}, and {@link #mSlope2Y}. + * + * @param p0 the index just before interpolation interval. If <code>p1</code> points the start + * of valid points, <code>p0</code> must be less than <code>minPos</code> of + * {@link #reset(int[],int[],int,int)}. + * @param p1 the start index of interpolation interval. + * @param p2 the end index of interpolation interval. + * @param p3 the index just after interpolation interval. If <code>p2</code> points the end of + * valid points, <code>p3</code> must be equal or greater than <code>maxPos</code> of + * {@link #reset(int[],int[],int,int)}. + */ + @UsedForTesting + public void setInterval(final int p0, final int p1, final int p2, final int p3) { + mP1X = mXCoords[p1]; + mP1Y = mYCoords[p1]; + mP2X = mXCoords[p2]; + mP2Y = mYCoords[p2]; + // A(ax,ay) is the vector p1->p2. + final int ax = mP2X - mP1X; + final int ay = mP2Y - mP1Y; + + // Calculate the slope of the tangent at p1. + if (p0 >= mMinPos) { + // p1 has previous valid point p0. + // The slope of the tangent is half of the vector p0->p2. + mSlope1X = (mP2X - mXCoords[p0]) / 2.0f; + mSlope1Y = (mP2Y - mYCoords[p0]) / 2.0f; + } else if (p3 < mMaxPos) { + // p1 has no previous valid point, but p2 has next valid point p3. + // B(bx,by) is the slope vector of the tangent at p2. + final float bx = (mXCoords[p3] - mP1X) / 2.0f; + final float by = (mYCoords[p3] - mP1Y) / 2.0f; + final float crossProdAB = ax * by - ay * bx; + final float dotProdAB = ax * bx + ay * by; + final float normASquare = ax * ax + ay * ay; + final float invHalfNormASquare = 1.0f / normASquare / 2.0f; + // The slope of the tangent is the mirror image of vector B to vector A. + mSlope1X = invHalfNormASquare * (dotProdAB * ax + crossProdAB * ay); + mSlope1Y = invHalfNormASquare * (dotProdAB * ay - crossProdAB * ax); + } else { + // p1 and p2 have no previous valid point. (Interval has only point p1 and p2) + mSlope1X = ax; + mSlope1Y = ay; + } + + // Calculate the slope of the tangent at p2. + if (p3 < mMaxPos) { + // p2 has next valid point p3. + // The slope of the tangent is half of the vector p1->p3. + mSlope2X = (mXCoords[p3] - mP1X) / 2.0f; + mSlope2Y = (mYCoords[p3] - mP1Y) / 2.0f; + } else if (p0 >= mMinPos) { + // p2 has no next valid point, but p1 has previous valid point p0. + // B(bx,by) is the slope vector of the tangent at p1. + final float bx = (mP2X - mXCoords[p0]) / 2.0f; + final float by = (mP2Y - mYCoords[p0]) / 2.0f; + final float crossProdAB = ax * by - ay * bx; + final float dotProdAB = ax * bx + ay * by; + final float normASquare = ax * ax + ay * ay; + final float invHalfNormASquare = 1.0f / normASquare / 2.0f; + // The slope of the tangent is the mirror image of vector B to vector A. + mSlope2X = invHalfNormASquare * (dotProdAB * ax + crossProdAB * ay); + mSlope2Y = invHalfNormASquare * (dotProdAB * ay - crossProdAB * ax); + } else { + // p1 and p2 has no previous valid point. (Interval has only point p1 and p2) + mSlope2X = ax; + mSlope2Y = ay; + } + } + + /** + * Calculate interpolation value at <code>t</code> in unit interval <code>[0,1]</code>. + * <p> + * On the unit interval [0,1], given a starting point p1 at t=0 and an ending point p2 at t=1 + * with the slope of the tangent m1 at p1 and m2 at p2, the polynomial of cubic Hermite curve + * can be defined by + * p(t) = (1+2t)(1-t)(1-t)*p1 + t(1-t)(1-t)*m1 + (3-2t)t^2*p2 + (t-1)t^2*m2 + * where t is an element of [0,1]. + * <p> + * The interpolated XY-coordinates will be set in {@link #mInterpolatedX} and + * {@link #mInterpolatedY}. + * + * @param t the interpolation parameter. The value must be in close interval <code>[0,1]</code>. + */ + @UsedForTesting + public void interpolate(final float t) { + final float omt = 1.0f - t; + final float tm2 = 2.0f * t; + final float k1 = 1.0f + tm2; + final float k2 = 3.0f - tm2; + final float omt2 = omt * omt; + final float t2 = t * t; + mInterpolatedX = (k1 * mP1X + t * mSlope1X) * omt2 + (k2 * mP2X - omt * mSlope2X) * t2; + mInterpolatedY = (k1 * mP1Y + t * mSlope1Y) * omt2 + (k2 * mP2Y - omt * mSlope2Y) * t2; + } +} diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 92b68dcd7..3262a9a10 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1143,11 +1143,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction if (!mWordComposer.isComposingWord()) return; final String typedWord = mWordComposer.getTypedWord(); if (typedWord.length() > 0) { - commitChosenWord(typedWord, LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, - separatorString); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.getInstance().onWordFinished(typedWord, mWordComposer.isBatchMode()); } + commitChosenWord(typedWord, LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, + separatorString); } } @@ -1905,7 +1905,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction private boolean handleSeparator(final int primaryCode, final int x, final int y, final int spaceState) { if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.recordTimeForLogUnitSplit(); ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord()); } boolean didAutoCorrect = false; diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index 90c3fcdd2..dcb514a5e 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -22,6 +22,10 @@ import java.util.ArrayList; import java.util.Locale; public final class StringUtils { + public static final int CAPITALIZE_NONE = 0; // No caps, or mixed case + public static final int CAPITALIZE_FIRST = 1; // First only + public static final int CAPITALIZE_ALL = 2; // All caps + private StringUtils() { // This utility class is not publicly instantiable. } @@ -171,4 +175,31 @@ public final class StringUtils { } return list.toArray(new String[list.size()]); } + + // This method assumes the text is not empty or null. + public static int getCapitalizationType(final String text) { + // If the first char is not uppercase, then the word is either all lower case or + // camel case, and in either case we return CAPITALIZE_NONE. + if (!Character.isUpperCase(text.codePointAt(0))) return CAPITALIZE_NONE; + final int len = text.length(); + int capsCount = 1; + int letterCount = 1; + for (int i = 1; i < len; i = text.offsetByCodePoints(i, 1)) { + if (1 != capsCount && letterCount != capsCount) break; + final int codePoint = text.codePointAt(i); + if (Character.isUpperCase(codePoint)) { + ++capsCount; + ++letterCount; + } else if (Character.isLetter(codePoint)) { + // We need to discount non-letters since they may not be upper-case, but may + // still be part of a word (e.g. single quote or dash, as in "IT'S" or "FULL-TIME") + ++letterCount; + } + } + // We know the first char is upper case. So we want to test if either every letter other + // than the first is lower case, or if they are all upper case. If the string is exactly + // one char long, then we will arrive here with letterCount 1, and this is correct, too. + if (1 == capsCount) return CAPITALIZE_FIRST; + return (letterCount == capsCount ? CAPITALIZE_ALL : CAPITALIZE_NONE); + } } diff --git a/java/src/com/android/inputmethod/latin/define/ProductionFlag.java b/java/src/com/android/inputmethod/latin/define/ProductionFlag.java index 699e47b6a..dc937fb25 100644 --- a/java/src/com/android/inputmethod/latin/define/ProductionFlag.java +++ b/java/src/com/android/inputmethod/latin/define/ProductionFlag.java @@ -28,5 +28,5 @@ public final class ProductionFlag { // USES_DEVELOPMENT_ONLY_DIAGNOSTICS must be false for any production build. public static final boolean USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG = false; - public static final boolean IS_HARDWARE_KEYBOARD_SUPPORTED = true; + public static final boolean IS_HARDWARE_KEYBOARD_SUPPORTED = false; } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 38a26486d..8d3b062ff 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -58,10 +58,6 @@ public final class AndroidSpellCheckerService extends SpellCheckerService public static final String PREF_USE_CONTACTS_KEY = "pref_spellcheck_use_contacts"; - public static final int CAPITALIZE_NONE = 0; // No caps, or mixed case - public static final int CAPITALIZE_FIRST = 1; // First only - public static final int CAPITALIZE_ALL = 2; // All caps - private final static String[] EMPTY_STRING_ARRAY = new String[0]; private Map<String, DictionaryPool> mDictionaryPools = CollectionUtils.newSynchronizedTreeMap(); private Map<String, UserBinaryDictionary> mUserDictionaries = @@ -325,13 +321,13 @@ public final class AndroidSpellCheckerService extends SpellCheckerService } Collections.reverse(mSuggestions); StringUtils.removeDupes(mSuggestions); - if (CAPITALIZE_ALL == capitalizeType) { + if (StringUtils.CAPITALIZE_ALL == capitalizeType) { for (int i = 0; i < mSuggestions.size(); ++i) { // get(i) returns a CharSequence which is actually a String so .toString() // should return the same object. mSuggestions.set(i, mSuggestions.get(i).toString().toUpperCase(locale)); } - } else if (CAPITALIZE_FIRST == capitalizeType) { + } else if (StringUtils.CAPITALIZE_FIRST == capitalizeType) { for (int i = 0; i < mSuggestions.size(); ++i) { // Likewise mSuggestions.set(i, StringUtils.toTitleCase( @@ -438,31 +434,4 @@ public final class AndroidSpellCheckerService extends SpellCheckerService } return new DictAndProximity(dictionaryCollection, proximityInfo); } - - // This method assumes the text is not empty or null. - public static int getCapitalizationType(String text) { - // If the first char is not uppercase, then the word is either all lower case, - // and in either case we return CAPITALIZE_NONE. - if (!Character.isUpperCase(text.codePointAt(0))) return CAPITALIZE_NONE; - final int len = text.length(); - int capsCount = 1; - int letterCount = 1; - for (int i = 1; i < len; i = text.offsetByCodePoints(i, 1)) { - if (1 != capsCount && letterCount != capsCount) break; - final int codePoint = text.codePointAt(i); - if (Character.isUpperCase(codePoint)) { - ++capsCount; - ++letterCount; - } else if (Character.isLetter(codePoint)) { - // We need to discount non-letters since they may not be upper-case, but may - // still be part of a word (e.g. single quote or dash, as in "IT'S" or "FULL-TIME") - ++letterCount; - } - } - // We know the first char is upper case. So we want to test if either every letter other - // than the first is lower case, or if they are all upper case. If the string is exactly - // one char long, then we will arrive here with letterCount 1, and this is correct, too. - if (1 == capsCount) return CAPITALIZE_FIRST; - return (letterCount == capsCount ? CAPITALIZE_ALL : CAPITALIZE_NONE); - } } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java index 4f86a3175..b15063235 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java @@ -150,7 +150,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { // Greek letters are either in the 370~3FF range (Greek & Coptic), or in the // 1F00~1FFF range (Greek extended). Our dictionary contains both sort of characters. // Our dictionary also contains a few words with 0xF2; it would be best to check - // if that's correct, but a Google search does return results for these words so + // if that's correct, but a web search does return results for these words so // they are probably okay. return (codePoint >= 0x370 && codePoint <= 0x3FF) || (codePoint >= 0x1F00 && codePoint <= 0x1FFF) @@ -214,14 +214,14 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { // If the word is in there as is, then it's in the dictionary. If not, we'll test lower // case versions, but only if the word is not already all-lower case or mixed case. if (dict.isValidWord(text)) return true; - if (AndroidSpellCheckerService.CAPITALIZE_NONE == capitalizeType) return false; + if (StringUtils.CAPITALIZE_NONE == capitalizeType) return false; // If we come here, we have a capitalized word (either First- or All-). // Downcase the word and look it up again. If the word is only capitalized, we // tested all possibilities, so if it's still negative we can return false. final String lowerCaseText = text.toLowerCase(mLocale); if (dict.isValidWord(lowerCaseText)) return true; - if (AndroidSpellCheckerService.CAPITALIZE_FIRST == capitalizeType) return false; + if (StringUtils.CAPITALIZE_FIRST == capitalizeType) return false; // If the lower case version is not in the dictionary, it's still possible // that we have an all-caps version of a word that needs to be capitalized @@ -296,7 +296,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { } } - final int capitalizeType = AndroidSpellCheckerService.getCapitalizationType(text); + final int capitalizeType = StringUtils.getCapitalizationType(text); boolean isInDict = true; DictAndProximity dictInfo = null; try { diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index 6e486ce70..fa124f3ba 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -1635,8 +1635,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang final String scrubbedAutoCorrection = scrubDigitsFromString(autoCorrection); final ResearchLogger researchLogger = getInstance(); researchLogger.mCurrentLogUnit.initializeSuggestions(suggestedWords); - researchLogger.commitCurrentLogUnitAsWord(scrubbedAutoCorrection, Long.MAX_VALUE, - isBatchMode); + researchLogger.onWordFinished(scrubbedAutoCorrection, isBatchMode); // Add the autocorrection logStatement at the end of the logUnit for the committed word. // We have to do this after calling commitCurrentLogUnitAsWord, because it may split the diff --git a/native/jni/Android.mk b/native/jni/Android.mk index 423c24e88..cbe9515fe 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -24,20 +24,14 @@ FLAG_DO_PROFILE ?= false include $(CLEAR_VARS) LATIN_IME_SRC_DIR := src -LATIN_IME_SRC_FULLPATH_DIR := $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR) -LOCAL_C_INCLUDES += \ - $(LATIN_IME_SRC_FULLPATH_DIR) \ - $(LATIN_IME_SRC_FULLPATH_DIR)/suggest \ - $(LATIN_IME_SRC_FULLPATH_DIR)/suggest/core/dicnode \ - $(LATIN_IME_SRC_FULLPATH_DIR)/suggest/core/policy \ - $(LATIN_IME_SRC_FULLPATH_DIR)/suggest/core/session +LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR) LOCAL_CFLAGS += -Werror -Wall -Wextra -Weffc++ -Wformat=2 -Wcast-qual -Wcast-align \ -Wwrite-strings -Wfloat-equal -Wpointer-arith -Winit-self -Wredundant-decls -Wno-system-headers ifeq ($(TARGET_ARCH), arm) -ifneq ($(TARGET_GCC_VERSION), 4.7) +ifeq ($(TARGET_GCC_VERSION), 4.6) LOCAL_CFLAGS += -Winline endif # TARGET_GCC_VERSION endif # TARGET_ARCH @@ -58,19 +52,27 @@ LATIN_IME_CORE_SRC_FILES := \ correction.cpp \ dictionary.cpp \ dic_traverse_wrapper.cpp \ + digraph_utils.cpp \ proximity_info.cpp \ proximity_info_params.cpp \ proximity_info_state.cpp \ proximity_info_state_utils.cpp \ unigram_dictionary.cpp \ words_priority_queue.cpp \ - suggest/core/dicnode/dic_node.cpp \ - suggest/core/dicnode/dic_nodes_cache.cpp \ - suggest/core/dicnode/dic_node_utils.cpp \ + suggest/core/suggest.cpp \ + $(addprefix suggest/core/dicnode/, \ + dic_node.cpp \ + dic_node_utils.cpp \ + dic_nodes_cache.cpp) \ suggest/core/policy/weighting.cpp \ suggest/core/session/dic_traverse_session.cpp \ - suggest/gesture_suggest.cpp \ - suggest/typing_suggest.cpp + suggest/policyimpl/gesture/gesture_suggest_policy_factory.cpp \ + $(addprefix suggest/policyimpl/typing/, \ + scoring_params.cpp \ + typing_scoring.cpp \ + typing_suggest_policy.cpp \ + typing_traversal.cpp \ + typing_weighting.cpp) LOCAL_SRC_FILES := \ $(LATIN_IME_JNI_SRC_FILES) \ @@ -125,6 +127,4 @@ include $(BUILD_SHARED_LIBRARY) #################### Clean up the tmp vars LATIN_IME_CORE_SRC_FILES := LATIN_IME_JNI_SRC_FILES := -LATIN_IME_GESTURE_IMPL_SRC_FILES := LATIN_IME_SRC_DIR := -LATIN_IME_SRC_FULLPATH_DIR := diff --git a/native/jni/jni_common.cpp b/native/jni/jni_common.cpp index 1ea204102..8e5c50880 100644 --- a/native/jni/jni_common.cpp +++ b/native/jni/jni_common.cpp @@ -16,12 +16,12 @@ #define LOG_TAG "LatinIME: jni" +#include "jni_common.h" + #include "com_android_inputmethod_keyboard_ProximityInfo.h" #include "com_android_inputmethod_latin_BinaryDictionary.h" #include "com_android_inputmethod_latin_DicTraverseSession.h" #include "defines.h" -#include "jni.h" -#include "jni_common.h" /* * Returns the JNI version on success, -1 on failure. diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp index 43e59a262..92890383a 100644 --- a/native/jni/src/bigram_dictionary.cpp +++ b/native/jni/src/bigram_dictionary.cpp @@ -39,7 +39,7 @@ BigramDictionary::~BigramDictionary() { void BigramDictionary::addWordBigram(int *word, int length, int probability, int *bigramProbability, int *bigramCodePoints, int *outputTypes) const { word[length] = 0; - if (DEBUG_DICT) { + if (DEBUG_DICT_FULL) { #ifdef FLAG_DBG char s[length + 1]; for (int i = 0; i <= length; i++) s[i] = static_cast<char>(word[i]); @@ -57,7 +57,7 @@ void BigramDictionary::addWordBigram(int *word, int length, int probability, int } insertAt++; } - if (DEBUG_DICT) { + if (DEBUG_DICT_FULL) { AKLOGI("Bigram: InsertAt -> %d MAX_RESULTS: %d", insertAt, MAX_RESULTS); } if (insertAt >= MAX_RESULTS) { @@ -76,7 +76,7 @@ void BigramDictionary::addWordBigram(int *word, int length, int probability, int *dest++ = *word++; } *dest = 0; // NULL terminate - if (DEBUG_DICT) { + if (DEBUG_DICT_FULL) { AKLOGI("Bigram: Added word at %d", insertAt); } } diff --git a/native/jni/src/correction.cpp b/native/jni/src/correction.cpp index 671507ee0..76234f840 100644 --- a/native/jni/src/correction.cpp +++ b/native/jni/src/correction.cpp @@ -954,7 +954,13 @@ inline static int editDistanceInternal(int *editDistanceTable, const int *before // In dictionary.cpp, getSuggestion() method, -// suggestion scores are computed using the below formula. +// When USE_SUGGEST_INTERFACE_FOR_TYPING is true: +// SUGGEST_INTERFACE_OUTPUT_SCALE was multiplied to the original suggestion scores to convert +// them to integers. +// score = (int)((original score) * SUGGEST_INTERFACE_OUTPUT_SCALE) +// Undo the scaling here to recover the original score. +// normalizedScore = ((float)score) / SUGGEST_INTERFACE_OUTPUT_SCALE +// Otherwise: suggestion scores are computed using the below formula. // original score // := powf(mTypedLetterMultiplier (this is defined 2), // (the number of matched characters between typed word and suggested word)) @@ -991,16 +997,20 @@ inline static int editDistanceInternal(int *editDistanceTable, const int *before return 0.0f; } + // add a weight based on edit distance. + // distance <= max(afterLength, beforeLength) == afterLength, + // so, 0 <= distance / afterLength <= 1 + const float weight = 1.0f - static_cast<float>(distance) / static_cast<float>(afterLength); + + if (USE_SUGGEST_INTERFACE_FOR_TYPING) { + return (static_cast<float>(score) / SUGGEST_INTERFACE_OUTPUT_SCALE) * weight; + } const float maxScore = score >= S_INT_MAX ? static_cast<float>(S_INT_MAX) : static_cast<float>(MAX_INITIAL_SCORE) * powf(static_cast<float>(TYPED_LETTER_MULTIPLIER), static_cast<float>(min(beforeLength, afterLength - spaceCount))) * static_cast<float>(FULL_WORD_MULTIPLIER); - // add a weight based on edit distance. - // distance <= max(afterLength, beforeLength) == afterLength, - // so, 0 <= distance / afterLength <= 1 - const float weight = 1.0f - static_cast<float>(distance) / static_cast<float>(afterLength); return (static_cast<float>(score) / maxScore) * weight; } } // namespace latinime diff --git a/native/jni/src/correction.h b/native/jni/src/correction.h index f0d62102f..a9e9b48a6 100644 --- a/native/jni/src/correction.h +++ b/native/jni/src/correction.h @@ -307,7 +307,7 @@ inline void Correction::startToTraverseAllNodes() { mNeedsToTraverseAllNodes = true; } -inline bool Correction::isSingleQuote(const int c) { +AK_FORCE_INLINE bool Correction::isSingleQuote(const int c) { const int userTypedChar = mProximityInfoState.getPrimaryCodePointAt(mInputIndex); return (c == KEYCODE_SINGLE_QUOTE && userTypedChar != KEYCODE_SINGLE_QUOTE); } diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h index 6e098157d..a45691261 100644 --- a/native/jni/src/defines.h +++ b/native/jni/src/defines.h @@ -287,6 +287,7 @@ static inline void prof_out(void) { #define CALIBRATE_SCORE_BY_TOUCH_COORDINATES true #define SUGGEST_MULTIPLE_WORDS true +#define USE_SUGGEST_INTERFACE_FOR_TYPING true #define SUGGEST_INTERFACE_OUTPUT_SCALE 1000000.0f // The following "rate"s are used as a multiplier before dividing by 100, so they are in percent. diff --git a/native/jni/src/dictionary.cpp b/native/jni/src/dictionary.cpp index 6deab36b6..ed6ddb517 100644 --- a/native/jni/src/dictionary.cpp +++ b/native/jni/src/dictionary.cpp @@ -16,14 +16,18 @@ #define LOG_TAG "LatinIME: dictionary.cpp" +#include "dictionary.h" + +#include <map> // TODO: remove #include <stdint.h> #include "bigram_dictionary.h" #include "binary_format.h" #include "defines.h" -#include "dictionary.h" #include "dic_traverse_wrapper.h" -#include "gesture_suggest.h" +#include "suggest/core/suggest.h" +#include "suggest/policyimpl/gesture/gesture_suggest_policy_factory.h" +#include "suggest/policyimpl/typing/typing_suggest_policy_factory.h" #include "unigram_dictionary.h" namespace latinime { @@ -34,13 +38,15 @@ Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust) mDictSize(dictSize), mMmapFd(mmapFd), mDictBufAdjust(dictBufAdjust), mUnigramDictionary(new UnigramDictionary(mOffsetDict, BinaryFormat::getFlags(mDict))), mBigramDictionary(new BigramDictionary(mOffsetDict)), - mGestureSuggest(new GestureSuggest()) { + mGestureSuggest(new Suggest(GestureSuggestPolicyFactory::getGestureSuggestPolicy())), + mTypingSuggest(new Suggest(TypingSuggestPolicyFactory::getTypingSuggestPolicy())) { } Dictionary::~Dictionary() { delete mUnigramDictionary; delete mBigramDictionary; delete mGestureSuggest; + delete mTypingSuggest; } int Dictionary::getSuggestions(ProximityInfo *proximityInfo, void *traverseSession, @@ -60,14 +66,26 @@ int Dictionary::getSuggestions(ProximityInfo *proximityInfo, void *traverseSessi } return result; } else { - std::map<int, int> bigramMap; - uint8_t bigramFilter[BIGRAM_FILTER_BYTE_SIZE]; - mBigramDictionary->fillBigramAddressToProbabilityMapAndFilter(prevWordCodePoints, - prevWordLength, &bigramMap, bigramFilter); - result = mUnigramDictionary->getSuggestions(proximityInfo, xcoordinates, ycoordinates, - inputCodePoints, inputSize, &bigramMap, bigramFilter, useFullEditDistance, outWords, - frequencies, outputTypes); - return result; + if (USE_SUGGEST_INTERFACE_FOR_TYPING) { + DicTraverseWrapper::initDicTraverseSession( + traverseSession, this, prevWordCodePoints, prevWordLength); + result = mTypingSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates, + ycoordinates, times, pointerIds, inputCodePoints, inputSize, commitPoint, + outWords, frequencies, spaceIndices, outputTypes); + if (DEBUG_DICT) { + DUMP_RESULT(outWords, frequencies); + } + return result; + } else { + std::map<int, int> bigramMap; + uint8_t bigramFilter[BIGRAM_FILTER_BYTE_SIZE]; + mBigramDictionary->fillBigramAddressToProbabilityMapAndFilter(prevWordCodePoints, + prevWordLength, &bigramMap, bigramFilter); + result = mUnigramDictionary->getSuggestions(proximityInfo, xcoordinates, ycoordinates, + inputCodePoints, inputSize, &bigramMap, bigramFilter, useFullEditDistance, + outWords, frequencies, outputTypes); + return result; + } } } diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index 449b95ab6..8c6a7de52 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -79,6 +79,7 @@ class Dictionary { const UnigramDictionary *mUnigramDictionary; const BigramDictionary *mBigramDictionary; SuggestInterface *mGestureSuggest; + SuggestInterface *mTypingSuggest; }; } // namespace latinime #endif // LATINIME_DICTIONARY_H diff --git a/native/jni/src/digraph_utils.cpp b/native/jni/src/digraph_utils.cpp new file mode 100644 index 000000000..8781c5077 --- /dev/null +++ b/native/jni/src/digraph_utils.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "binary_format.h" +#include "defines.h" +#include "digraph_utils.h" + +namespace latinime { + +const DigraphUtils::digraph_t DigraphUtils::GERMAN_UMLAUT_DIGRAPHS[] = + { { 'a', 'e', 0x00E4 }, // U+00E4 : LATIN SMALL LETTER A WITH DIAERESIS + { 'o', 'e', 0x00F6 }, // U+00F6 : LATIN SMALL LETTER O WITH DIAERESIS + { 'u', 'e', 0x00FC } }; // U+00FC : LATIN SMALL LETTER U WITH DIAERESIS +const DigraphUtils::digraph_t DigraphUtils::FRENCH_LIGATURES_DIGRAPHS[] = + { { 'a', 'e', 0x00E6 }, // U+00E6 : LATIN SMALL LETTER AE + { 'o', 'e', 0x0153 } }; // U+0153 : LATIN SMALL LIGATURE OE + +/* static */ bool DigraphUtils::hasDigraphForCodePoint( + const int dictFlags, const int compositeGlyphCodePoint) { + if (DigraphUtils::getDigraphForCodePoint(dictFlags, compositeGlyphCodePoint)) { + return true; + } + return false; +} + +// Retrieves the set of all digraphs associated with the given dictionary. +// Returns the size of the digraph array, or 0 if none exist. +/* static */ int DigraphUtils::getAllDigraphsForDictionaryAndReturnSize( + const int dictFlags, const DigraphUtils::digraph_t **digraphs) { + if (BinaryFormat::REQUIRES_GERMAN_UMLAUT_PROCESSING & dictFlags) { + *digraphs = DigraphUtils::GERMAN_UMLAUT_DIGRAPHS; + return NELEMS(DigraphUtils::GERMAN_UMLAUT_DIGRAPHS); + } + if (BinaryFormat::REQUIRES_FRENCH_LIGATURES_PROCESSING & dictFlags) { + *digraphs = DigraphUtils::FRENCH_LIGATURES_DIGRAPHS; + return NELEMS(DigraphUtils::FRENCH_LIGATURES_DIGRAPHS); + } + return 0; +} + +// Returns the digraph codepoint for the given composite glyph codepoint and digraph codepoint index +// (which specifies the first or second codepoint in the digraph). +/* static */ int DigraphUtils::getDigraphCodePointForIndex(const int dictFlags, + const int compositeGlyphCodePoint, const DigraphCodePointIndex digraphCodePointIndex) { + if (digraphCodePointIndex == NOT_A_DIGRAPH_INDEX) { + return NOT_A_CODE_POINT; + } + const DigraphUtils::digraph_t *digraph = + DigraphUtils::getDigraphForCodePoint(dictFlags, compositeGlyphCodePoint); + if (!digraph) { + return NOT_A_CODE_POINT; + } + if (digraphCodePointIndex == FIRST_DIGRAPH_CODEPOINT) { + return digraph->first; + } else if (digraphCodePointIndex == SECOND_DIGRAPH_CODEPOINT) { + return digraph->second; + } + ASSERT(false); + return NOT_A_CODE_POINT; +} + +/** + * Returns the digraph for the input composite glyph codepoint, or 0 if none exists. + * dictFlags: the dictionary flags needed to determine which digraphs are supported. + * compositeGlyphCodePoint: the method returns the digraph corresponding to this codepoint. + */ +/* static */ const DigraphUtils::digraph_t *DigraphUtils::getDigraphForCodePoint( + const int dictFlags, const int compositeGlyphCodePoint) { + const DigraphUtils::digraph_t *digraphs = 0; + const int digraphsSize = + DigraphUtils::getAllDigraphsForDictionaryAndReturnSize(dictFlags, &digraphs); + for (int i = 0; i < digraphsSize; i++) { + if (digraphs[i].compositeGlyph == compositeGlyphCodePoint) { + return &digraphs[i]; + } + } + return 0; +} + +} // namespace latinime diff --git a/native/jni/src/digraph_utils.h b/native/jni/src/digraph_utils.h new file mode 100644 index 000000000..6e364b67a --- /dev/null +++ b/native/jni/src/digraph_utils.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef DIGRAPH_UTILS_H +#define DIGRAPH_UTILS_H + +namespace latinime { + +class DigraphUtils { + public: + typedef enum { + NOT_A_DIGRAPH_INDEX, + FIRST_DIGRAPH_CODEPOINT, + SECOND_DIGRAPH_CODEPOINT + } DigraphCodePointIndex; + + typedef struct { int first; int second; int compositeGlyph; } digraph_t; + + static bool hasDigraphForCodePoint(const int dictFlags, const int compositeGlyphCodePoint); + static int getAllDigraphsForDictionaryAndReturnSize( + const int dictFlags, const digraph_t **digraphs); + static int getDigraphCodePointForIndex(const int dictFlags, const int compositeGlyphCodePoint, + const DigraphCodePointIndex digraphCodePointIndex); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(DigraphUtils); + static const digraph_t *getDigraphForCodePoint( + const int dictFlags, const int compositeGlyphCodePoint); + + static const digraph_t GERMAN_UMLAUT_DIGRAPHS[]; + static const digraph_t FRENCH_LIGATURES_DIGRAPHS[]; +}; +} // namespace latinime +#endif // DIGRAPH_UTILS_H diff --git a/native/jni/src/suggest/core/dictionary/shortcut_utils.h b/native/jni/src/suggest/core/dictionary/shortcut_utils.h new file mode 100644 index 000000000..c411408ec --- /dev/null +++ b/native/jni/src/suggest/core/dictionary/shortcut_utils.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LATINIME_SHORTCUT_UTILS +#define LATINIME_SHORTCUT_UTILS + +#include "defines.h" +#include "suggest/core/dicnode/dic_node_utils.h" +#include "terminal_attributes.h" + +namespace latinime { + +class ShortcutUtils { + public: + static int outputShortcuts(const TerminalAttributes *const terminalAttributes, + int outputWordIndex, const int finalScore, int *const outputCodePoints, + int *const frequencies, int *const outputTypes, const bool sameAsTyped) { + TerminalAttributes::ShortcutIterator iterator = terminalAttributes->getShortcutIterator(); + while (iterator.hasNextShortcutTarget() && outputWordIndex < MAX_RESULTS) { + int shortcutTarget[MAX_WORD_LENGTH]; + int shortcutProbability; + const int shortcutTargetStringLength = iterator.getNextShortcutTarget( + MAX_WORD_LENGTH, shortcutTarget, &shortcutProbability); + int shortcutScore; + int kind; + if (shortcutProbability == BinaryFormat::WHITELIST_SHORTCUT_PROBABILITY + && sameAsTyped) { + shortcutScore = S_INT_MAX; + kind = Dictionary::KIND_WHITELIST; + } else { + // shortcut entry's score == its base entry's score - 1 + shortcutScore = finalScore; + // Protection against int underflow + shortcutScore = max(S_INT_MIN + 1, shortcutScore) - 1; + kind = Dictionary::KIND_CORRECTION; + } + outputTypes[outputWordIndex] = kind; + frequencies[outputWordIndex] = shortcutScore; + frequencies[outputWordIndex] = max(S_INT_MIN + 1, shortcutScore) - 1; + const int startIndex2 = outputWordIndex * MAX_WORD_LENGTH; + DicNodeUtils::appendTwoWords(0, 0, shortcutTarget, shortcutTargetStringLength, + &outputCodePoints[startIndex2]); + ++outputWordIndex; + } + return outputWordIndex; + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ShortcutUtils); +}; +} // namespace latinime +#endif // LATINIME_SHORTCUT_UTILS diff --git a/native/jni/src/suggest/core/policy/traversal.h b/native/jni/src/suggest/core/policy/traversal.h index 1d5082ff8..02c358aec 100644 --- a/native/jni/src/suggest/core/policy/traversal.h +++ b/native/jni/src/suggest/core/policy/traversal.h @@ -20,6 +20,9 @@ #include "defines.h" namespace latinime { + +class DicTraverseSession; + class Traversal { public: virtual int getMaxPointerCount() const = 0; diff --git a/native/jni/src/suggest/core/policy/weighting.cpp b/native/jni/src/suggest/core/policy/weighting.cpp index 4d08fa0fa..e62b70423 100644 --- a/native/jni/src/suggest/core/policy/weighting.cpp +++ b/native/jni/src/suggest/core/policy/weighting.cpp @@ -14,14 +14,15 @@ * limitations under the License. */ +#include "suggest/core/policy/weighting.h" + #include "char_utils.h" #include "defines.h" -#include "dic_node.h" -#include "dic_node_profiler.h" -#include "dic_node_utils.h" -#include "dic_traverse_session.h" #include "hash_map_compat.h" -#include "weighting.h" +#include "suggest/core/dicnode/dic_node.h" +#include "suggest/core/dicnode/dic_node_profiler.h" +#include "suggest/core/dicnode/dic_node_utils.h" +#include "suggest/core/session/dic_traverse_session.h" namespace latinime { diff --git a/native/jni/src/suggest/core/policy/weighting.h b/native/jni/src/suggest/core/policy/weighting.h index 83a0f4b45..b92dbe278 100644 --- a/native/jni/src/suggest/core/policy/weighting.h +++ b/native/jni/src/suggest/core/policy/weighting.h @@ -18,6 +18,7 @@ #define LATINIME_WEIGHTING_H #include "defines.h" +#include "hash_map_compat.h" namespace latinime { diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.cpp b/native/jni/src/suggest/core/session/dic_traverse_session.cpp index 1f781dd43..ef6616e40 100644 --- a/native/jni/src/suggest/core/session/dic_traverse_session.cpp +++ b/native/jni/src/suggest/core/session/dic_traverse_session.cpp @@ -14,12 +14,13 @@ * limitations under the License. */ +#include "suggest/core/session/dic_traverse_session.h" + #include "defines.h" #include "dictionary.h" -#include "dic_node_utils.h" -#include "dic_traverse_session.h" #include "dic_traverse_wrapper.h" #include "jni.h" +#include "suggest/core/dicnode/dic_node_utils.h" namespace latinime { diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.h b/native/jni/src/suggest/core/session/dic_traverse_session.h index af036f82b..62e1d1ab9 100644 --- a/native/jni/src/suggest/core/session/dic_traverse_session.h +++ b/native/jni/src/suggest/core/session/dic_traverse_session.h @@ -21,10 +21,10 @@ #include <vector> #include "defines.h" -#include "dic_nodes_cache.h" #include "hash_map_compat.h" #include "jni.h" #include "proximity_info_state.h" +#include "suggest/core/dicnode/dic_nodes_cache.h" namespace latinime { diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp new file mode 100644 index 000000000..1e97a9176 --- /dev/null +++ b/native/jni/src/suggest/core/suggest.cpp @@ -0,0 +1,520 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "suggest/core/suggest.h" + +#include "char_utils.h" +#include "dictionary.h" +#include "proximity_info.h" +#include "suggest/core/dicnode/dic_node.h" +#include "suggest/core/dicnode/dic_node_priority_queue.h" +#include "suggest/core/dicnode/dic_node_vector.h" +#include "suggest/core/dictionary/shortcut_utils.h" +#include "suggest/core/policy/scoring.h" +#include "suggest/core/policy/traversal.h" +#include "suggest/core/policy/weighting.h" +#include "suggest/core/session/dic_traverse_session.h" +#include "terminal_attributes.h" + +namespace latinime { + +// Initialization of class constants. +const int Suggest::LOOKAHEAD_DIC_NODES_CACHE_SIZE = 25; +const int Suggest::MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT = 16; +const int Suggest::MIN_CONTINUOUS_SUGGESTION_INPUT_SIZE = 2; +const float Suggest::AUTOCORRECT_CLASSIFICATION_THRESHOLD = 0.33f; +const float Suggest::AUTOCORRECT_LANGUAGE_FEATURE_THRESHOLD = 0.6f; + +const bool Suggest::CORRECT_SPACE_OMISSION = true; +const bool Suggest::CORRECT_TRANSPOSITION = true; +const bool Suggest::CORRECT_INSERTION = true; +const bool Suggest::CORRECT_OMISSION_G = true; + +/** + * Returns a set of suggestions for the given input touch points. The commitPoint argument indicates + * whether to prematurely commit the suggested words up to the given point for sentence-level + * suggestion. + * + * Note: Currently does not support concurrent calls across threads. Continuous suggestion is + * automatically activated for sequential calls that share the same starting input. + * TODO: Stop detecting continuous suggestion. Start using traverseSession instead. + */ +int Suggest::getSuggestions(ProximityInfo *pInfo, void *traverseSession, + int *inputXs, int *inputYs, int *times, int *pointerIds, int *inputCodePoints, + int inputSize, int commitPoint, int *outWords, int *frequencies, int *outputIndices, + int *outputTypes) const { + PROF_OPEN; + PROF_START(0); + const float maxSpatialDistance = TRAVERSAL->getMaxSpatialDistance(); + DicTraverseSession *tSession = static_cast<DicTraverseSession *>(traverseSession); + tSession->setupForGetSuggestions(pInfo, inputCodePoints, inputSize, inputXs, inputYs, times, + pointerIds, maxSpatialDistance, TRAVERSAL->getMaxPointerCount()); + // TODO: Add the way to evaluate cache + + initializeSearch(tSession, commitPoint); + PROF_END(0); + PROF_START(1); + + // keep expanding search dicNodes until all have terminated. + while (tSession->getDicTraverseCache()->activeSize() > 0) { + expandCurrentDicNodes(tSession); + tSession->getDicTraverseCache()->advanceActiveDicNodes(); + tSession->getDicTraverseCache()->advanceInputIndex(inputSize); + } + PROF_END(1); + PROF_START(2); + const int size = outputSuggestions(tSession, frequencies, outWords, outputIndices, outputTypes); + PROF_END(2); + PROF_CLOSE; + return size; +} + +/** + * Initializes the search at the root of the lexicon trie. Note that when possible the search will + * continue suggestion from where it left off during the last call. + */ +void Suggest::initializeSearch(DicTraverseSession *traverseSession, int commitPoint) const { + if (!traverseSession->getProximityInfoState(0)->isUsed()) { + return; + } + if (TRAVERSAL->allowPartialCommit()) { + commitPoint = 0; + } + + if (traverseSession->getInputSize() > MIN_CONTINUOUS_SUGGESTION_INPUT_SIZE + && traverseSession->isContinuousSuggestionPossible()) { + if (commitPoint == 0) { + // Continue suggestion + traverseSession->getDicTraverseCache()->continueSearch(); + } else { + // Continue suggestion after partial commit. + DicNode *topDicNode = + traverseSession->getDicTraverseCache()->setCommitPoint(commitPoint); + traverseSession->setPrevWordPos(topDicNode->getPrevWordNodePos()); + traverseSession->getDicTraverseCache()->continueSearch(); + traverseSession->setPartiallyCommited(); + } + } else { + // Restart recognition at the root. + traverseSession->resetCache(TRAVERSAL->getMaxCacheSize(), MAX_RESULTS); + // Create a new dic node here + DicNode rootNode; + DicNodeUtils::initAsRoot(traverseSession->getDicRootPos(), + traverseSession->getOffsetDict(), traverseSession->getPrevWordPos(), &rootNode); + traverseSession->getDicTraverseCache()->copyPushActive(&rootNode); + } +} + +/** + * Outputs the final list of suggestions (i.e., terminal nodes). + */ +int Suggest::outputSuggestions(DicTraverseSession *traverseSession, int *frequencies, + int *outputCodePoints, int *spaceIndices, int *outputTypes) const { + const int terminalSize = min(MAX_RESULTS, + static_cast<int>(traverseSession->getDicTraverseCache()->terminalSize())); + DicNode terminals[MAX_RESULTS]; // Avoiding non-POD variable length array + + for (int index = terminalSize - 1; index >= 0; --index) { + traverseSession->getDicTraverseCache()->popTerminal(&terminals[index]); + } + + const float languageWeight = SCORING->getAdjustedLanguageWeight( + traverseSession, terminals, terminalSize); + + int outputWordIndex = 0; + // Insert most probable word at index == 0 as long as there is one terminal at least + const bool hasMostProbableString = + SCORING->getMostProbableString(traverseSession, terminalSize, languageWeight, + &outputCodePoints[0], &outputTypes[0], &frequencies[0]); + if (hasMostProbableString) { + ++outputWordIndex; + } + + // Initial value of the loop index for terminal nodes (words) + int doubleLetterTerminalIndex = -1; + DoubleLetterLevel doubleLetterLevel = NOT_A_DOUBLE_LETTER; + SCORING->searchWordWithDoubleLetter(terminals, terminalSize, + &doubleLetterTerminalIndex, &doubleLetterLevel); + + int maxScore = S_INT_MIN; + // Output suggestion results here + for (int terminalIndex = 0; terminalIndex < terminalSize && outputWordIndex < MAX_RESULTS; + ++terminalIndex) { + DicNode *terminalDicNode = &terminals[terminalIndex]; + if (DEBUG_GEO_FULL) { + terminalDicNode->dump("OUT:"); + } + const float doubleLetterCost = SCORING->getDoubleLetterDemotionDistanceCost( + terminalIndex, doubleLetterTerminalIndex, doubleLetterLevel); + const float compoundDistance = terminalDicNode->getCompoundDistance(languageWeight) + + doubleLetterCost; + const TerminalAttributes terminalAttributes(traverseSession->getOffsetDict(), + terminalDicNode->getFlags(), terminalDicNode->getAttributesPos()); + const int originalTerminalProbability = terminalDicNode->getProbability(); + + // Do not suggest words with a 0 probability, or entries that are blacklisted or do not + // represent a word. However, we should still submit their shortcuts if any. + const bool isValidWord = + originalTerminalProbability > 0 && !terminalAttributes.isBlacklistedOrNotAWord(); + // Increase output score of top typing suggestion to ensure autocorrection. + // TODO: Better integration with java side autocorrection logic. + // Force autocorrection for obvious long multi-word suggestions. + const bool isForceCommitMultiWords = TRAVERSAL->allowPartialCommit() + && (traverseSession->isPartiallyCommited() + || (traverseSession->getInputSize() >= MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT + && terminalDicNode->hasMultipleWords())); + + const int finalScore = SCORING->calculateFinalScore( + compoundDistance, traverseSession->getInputSize(), + isForceCommitMultiWords || (isValidWord && SCORING->doesAutoCorrectValidWord())); + + maxScore = max(maxScore, finalScore); + + if (TRAVERSAL->allowPartialCommit()) { + // Index for top typing suggestion should be 0. + if (isValidWord && outputWordIndex == 0) { + terminalDicNode->outputSpacePositionsResult(spaceIndices); + } + } + + // Do not suggest words with a 0 probability, or entries that are blacklisted or do not + // represent a word. However, we should still submit their shortcuts if any. + if (isValidWord) { + outputTypes[outputWordIndex] = Dictionary::KIND_CORRECTION; + frequencies[outputWordIndex] = finalScore; + // Populate the outputChars array with the suggested word. + const int startIndex = outputWordIndex * MAX_WORD_LENGTH; + terminalDicNode->outputResult(&outputCodePoints[startIndex]); + ++outputWordIndex; + } + + const bool sameAsTyped = TRAVERSAL->sameAsTyped(traverseSession, terminalDicNode); + outputWordIndex = ShortcutUtils::outputShortcuts(&terminalAttributes, outputWordIndex, + finalScore, outputCodePoints, frequencies, outputTypes, sameAsTyped); + DicNode::managedDelete(terminalDicNode); + } + + if (hasMostProbableString) { + SCORING->safetyNetForMostProbableString(terminalSize, maxScore, + &outputCodePoints[0], &frequencies[0]); + } + return outputWordIndex; +} + +/** + * Expands the dicNodes in the current search priority queue by advancing to the possible child + * nodes based on the next touch point(s) (or no touch points for lookahead) + */ +void Suggest::expandCurrentDicNodes(DicTraverseSession *traverseSession) const { + const int inputSize = traverseSession->getInputSize(); + DicNodeVector childDicNodes(TRAVERSAL->getDefaultExpandDicNodeSize()); + DicNode omissionDicNode; + + // TODO: Find more efficient caching + const bool shouldDepthLevelCache = TRAVERSAL->shouldDepthLevelCache(traverseSession); + if (shouldDepthLevelCache) { + traverseSession->getDicTraverseCache()->updateLastCachedInputIndex(); + } + if (DEBUG_CACHE) { + AKLOGI("expandCurrentDicNodes depth level cache = %d, inputSize = %d", + shouldDepthLevelCache, inputSize); + } + while (traverseSession->getDicTraverseCache()->activeSize() > 0) { + DicNode dicNode; + traverseSession->getDicTraverseCache()->popActive(&dicNode); + if (dicNode.isTotalInputSizeExceedingLimit()) { + return; + } + childDicNodes.clear(); + const int point0Index = dicNode.getInputIndex(0); + const bool canDoLookAheadCorrection = + TRAVERSAL->canDoLookAheadCorrection(traverseSession, &dicNode); + const bool isLookAheadCorrection = canDoLookAheadCorrection + && traverseSession->getDicTraverseCache()-> + isLookAheadCorrectionInputIndex(static_cast<int>(point0Index)); + const bool isCompletion = dicNode.isCompletion(inputSize); + + const bool shouldNodeLevelCache = + TRAVERSAL->shouldNodeLevelCache(traverseSession, &dicNode); + if (shouldDepthLevelCache || shouldNodeLevelCache) { + if (DEBUG_CACHE) { + dicNode.dump("PUSH_CACHE"); + } + traverseSession->getDicTraverseCache()->copyPushContinue(&dicNode); + dicNode.setCached(); + } + + if (isLookAheadCorrection) { + // The algorithm maintains a small set of "deferred" nodes that have not consumed the + // latest touch point yet. These are needed to apply look-ahead correction operations + // that require special handling of the latest touch point. For example, with insertions + // (e.g., "thiis" -> "this") the latest touch point should not be consumed at all. + if (CORRECT_TRANSPOSITION) { + processDicNodeAsTransposition(traverseSession, &dicNode); + } + if (CORRECT_INSERTION) { + processDicNodeAsInsertion(traverseSession, &dicNode); + } + } else { // !isLookAheadCorrection + // Only consider typing error corrections if the normalized compound distance is + // below a spatial distance threshold. + // NOTE: the threshold may need to be updated if scoring model changes. + // TODO: Remove. Do not prune node here. + const bool allowsErrorCorrections = TRAVERSAL->allowsErrorCorrections(&dicNode); + // Process for handling space substitution (e.g., hevis => he is) + if (allowsErrorCorrections + && TRAVERSAL->isSpaceSubstitutionTerminal(traverseSession, &dicNode)) { + createNextWordDicNode(traverseSession, &dicNode, true /* spaceSubstitution */); + } + + DicNodeUtils::getAllChildDicNodes( + &dicNode, traverseSession->getOffsetDict(), &childDicNodes); + + const int childDicNodesSize = childDicNodes.getSizeAndLock(); + for (int i = 0; i < childDicNodesSize; ++i) { + DicNode *const childDicNode = childDicNodes[i]; + if (isCompletion) { + // Handle forward lookahead when the lexicon letter exceeds the input size. + processDicNodeAsMatch(traverseSession, childDicNode); + continue; + } + if (allowsErrorCorrections + && TRAVERSAL->isOmission(traverseSession, &dicNode, childDicNode)) { + // TODO: (Gesture) Change weight between omission and substitution errors + // TODO: (Gesture) Terminal node should not be handled as omission + omissionDicNode.initByCopy(childDicNode); + processDicNodeAsOmission(traverseSession, &omissionDicNode); + } + const ProximityType proximityType = TRAVERSAL->getProximityType( + traverseSession, &dicNode, childDicNode); + switch (proximityType) { + // TODO: Consider the difference of proximityType here + case MATCH_CHAR: + case PROXIMITY_CHAR: + processDicNodeAsMatch(traverseSession, childDicNode); + break; + case ADDITIONAL_PROXIMITY_CHAR: + if (allowsErrorCorrections) { + processDicNodeAsAdditionalProximityChar(traverseSession, &dicNode, + childDicNode); + } + break; + case SUBSTITUTION_CHAR: + if (allowsErrorCorrections) { + processDicNodeAsSubstitution(traverseSession, &dicNode, childDicNode); + } + break; + case UNRELATED_CHAR: + // Just drop this node and do nothing. + break; + default: + // Just drop this node and do nothing. + break; + } + } + + // Push the node for look-ahead correction + if (allowsErrorCorrections && canDoLookAheadCorrection) { + traverseSession->getDicTraverseCache()->copyPushNextActive(&dicNode); + } + } + } +} + +void Suggest::processTerminalDicNode( + DicTraverseSession *traverseSession, DicNode *dicNode) const { + if (dicNode->getCompoundDistance() >= static_cast<float>(MAX_VALUE_FOR_WEIGHTING)) { + return; + } + if (!dicNode->isTerminalWordNode()) { + return; + } + if (TRAVERSAL->needsToTraverseAllUserInput() + && dicNode->getInputIndex(0) < traverseSession->getInputSize()) { + return; + } + + if (dicNode->shouldBeFilterdBySafetyNetForBigram()) { + return; + } + // Create a non-cached node here. + DicNode terminalDicNode; + DicNodeUtils::initByCopy(dicNode, &terminalDicNode); + Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_TERMINAL, traverseSession, 0, + &terminalDicNode, traverseSession->getBigramCacheMap()); + traverseSession->getDicTraverseCache()->copyPushTerminal(&terminalDicNode); +} + +/** + * Adds the expanded dicNode to the next search priority queue. Also creates an additional next word + * (by the space omission error correction) search path if input dicNode is on a terminal node. + */ +void Suggest::processExpandedDicNode( + DicTraverseSession *traverseSession, DicNode *dicNode) const { + processTerminalDicNode(traverseSession, dicNode); + if (dicNode->getCompoundDistance() < static_cast<float>(MAX_VALUE_FOR_WEIGHTING)) { + if (TRAVERSAL->isSpaceOmissionTerminal(traverseSession, dicNode)) { + createNextWordDicNode(traverseSession, dicNode, false /* spaceSubstitution */); + } + const int allowsLookAhead = !(dicNode->hasMultipleWords() + && dicNode->isCompletion(traverseSession->getInputSize())); + if (dicNode->hasChildren() && allowsLookAhead) { + traverseSession->getDicTraverseCache()->copyPushNextActive(dicNode); + } + } + DicNode::managedDelete(dicNode); +} + +void Suggest::processDicNodeAsMatch(DicTraverseSession *traverseSession, + DicNode *childDicNode) const { + weightChildNode(traverseSession, childDicNode); + processExpandedDicNode(traverseSession, childDicNode); +} + +void Suggest::processDicNodeAsAdditionalProximityChar(DicTraverseSession *traverseSession, + DicNode *dicNode, DicNode *childDicNode) const { + Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_ADDITIONAL_PROXIMITY, + traverseSession, dicNode, childDicNode, 0 /* bigramCacheMap */); + weightChildNode(traverseSession, childDicNode); + processExpandedDicNode(traverseSession, childDicNode); +} + +void Suggest::processDicNodeAsSubstitution(DicTraverseSession *traverseSession, + DicNode *dicNode, DicNode *childDicNode) const { + Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_SUBSTITUTION, traverseSession, + dicNode, childDicNode, 0 /* bigramCacheMap */); + weightChildNode(traverseSession, childDicNode); + processExpandedDicNode(traverseSession, childDicNode); +} + +/** + * Handle the dicNode as an omission error (e.g., ths => this). Skip the current letter and consider + * matches for all possible next letters. Note that just skipping the current letter without any + * other conditions tends to flood the search dic nodes cache with omission nodes. Instead, check + * the possible *next* letters after the omission to better limit search to plausible omissions. + * Note that apostrophes are handled as omissions. + */ +void Suggest::processDicNodeAsOmission( + DicTraverseSession *traverseSession, DicNode *dicNode) const { + // If the omission is surely intentional that it should incur zero cost. + const bool isZeroCostOmission = dicNode->isZeroCostOmission(); + DicNodeVector childDicNodes; + + DicNodeUtils::getAllChildDicNodes(dicNode, traverseSession->getOffsetDict(), &childDicNodes); + + const int size = childDicNodes.getSizeAndLock(); + for (int i = 0; i < size; i++) { + DicNode *const childDicNode = childDicNodes[i]; + if (!isZeroCostOmission) { + // Treat this word as omission + Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_OMISSION, traverseSession, + dicNode, childDicNode, 0 /* bigramCacheMap */); + } + weightChildNode(traverseSession, childDicNode); + + if (!TRAVERSAL->isPossibleOmissionChildNode(traverseSession, dicNode, childDicNode)) { + DicNode::managedDelete(childDicNode); + continue; + } + processExpandedDicNode(traverseSession, childDicNode); + } +} + +/** + * Handle the dicNode as an insertion error (e.g., thiis => this). Skip the current touch point and + * consider matches for the next touch point. + */ +void Suggest::processDicNodeAsInsertion(DicTraverseSession *traverseSession, + DicNode *dicNode) const { + const int16_t pointIndex = dicNode->getInputIndex(0); + DicNodeVector childDicNodes; + DicNodeUtils::getProximityChildDicNodes(dicNode, traverseSession->getOffsetDict(), + traverseSession->getProximityInfoState(0), pointIndex + 1, true, &childDicNodes); + const int size = childDicNodes.getSizeAndLock(); + for (int i = 0; i < size; i++) { + DicNode *const childDicNode = childDicNodes[i]; + Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_INSERTION, traverseSession, + dicNode, childDicNode, 0 /* bigramCacheMap */); + processExpandedDicNode(traverseSession, childDicNode); + } +} + +/** + * Handle the dicNode as a transposition error (e.g., thsi => this). Swap the next two touch points. + */ +void Suggest::processDicNodeAsTransposition(DicTraverseSession *traverseSession, + DicNode *dicNode) const { + const int16_t pointIndex = dicNode->getInputIndex(0); + DicNodeVector childDicNodes1; + DicNodeUtils::getProximityChildDicNodes(dicNode, traverseSession->getOffsetDict(), + traverseSession->getProximityInfoState(0), pointIndex + 1, false, &childDicNodes1); + const int childSize1 = childDicNodes1.getSizeAndLock(); + for (int i = 0; i < childSize1; i++) { + if (childDicNodes1[i]->hasChildren()) { + DicNodeVector childDicNodes2; + DicNodeUtils::getProximityChildDicNodes( + childDicNodes1[i], traverseSession->getOffsetDict(), + traverseSession->getProximityInfoState(0), pointIndex, false, &childDicNodes2); + const int childSize2 = childDicNodes2.getSizeAndLock(); + for (int j = 0; j < childSize2; j++) { + DicNode *const childDicNode2 = childDicNodes2[j]; + Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_TRANSPOSITION, + traverseSession, childDicNodes1[i], childDicNode2, 0 /* bigramCacheMap */); + processExpandedDicNode(traverseSession, childDicNode2); + } + } + DicNode::managedDelete(childDicNodes1[i]); + } +} + +/** + * Weight child node by aligning it to the key + */ +void Suggest::weightChildNode(DicTraverseSession *traverseSession, DicNode *dicNode) const { + const int inputSize = traverseSession->getInputSize(); + if (dicNode->isCompletion(inputSize)) { + Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_COMPLETION, traverseSession, + 0 /* parentDicNode */, dicNode, 0 /* bigramCacheMap */); + } else { // completion + Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_MATCH, traverseSession, + 0 /* parentDicNode */, dicNode, 0 /* bigramCacheMap */); + } +} + +/** + * Creates a new dicNode that represents a space insertion at the end of the input dicNode. Also + * incorporates the unigram / bigram score for the ending word into the new dicNode. + */ +void Suggest::createNextWordDicNode(DicTraverseSession *traverseSession, DicNode *dicNode, + const bool spaceSubstitution) const { + if (!TRAVERSAL->isGoodToTraverseNextWord(dicNode)) { + return; + } + + // Create a non-cached node here. + DicNode newDicNode; + DicNodeUtils::initAsRootWithPreviousWord(traverseSession->getDicRootPos(), + traverseSession->getOffsetDict(), dicNode, &newDicNode); + Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_NEW_WORD, traverseSession, dicNode, + &newDicNode, traverseSession->getBigramCacheMap()); + if (spaceSubstitution) { + // Merge this with CT_NEW_WORD + Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_SPACE_SUBSTITUTION, + traverseSession, 0, &newDicNode, 0 /* bigramCacheMap */); + } + traverseSession->getDicTraverseCache()->copyPushNextActive(&newDicNode); +} +} // namespace latinime diff --git a/native/jni/src/suggest/core/suggest.h b/native/jni/src/suggest/core/suggest.h new file mode 100644 index 000000000..a1e7e7a94 --- /dev/null +++ b/native/jni/src/suggest/core/suggest.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LATINIME_SUGGEST_IMPL_H +#define LATINIME_SUGGEST_IMPL_H + +#include "defines.h" +#include "suggest/core/suggest_interface.h" +#include "suggest/core/policy/suggest_policy.h" + +namespace latinime { + +class DicNode; +class DicTraverseSession; +class ProximityInfo; +class Scoring; +class Traversal; +class Weighting; + +class Suggest : public SuggestInterface { + public: + AK_FORCE_INLINE Suggest(const SuggestPolicy *const suggestPolicy) + : TRAVERSAL(suggestPolicy->getTraversal()), + SCORING(suggestPolicy->getScoring()), WEIGHTING(suggestPolicy->getWeighting()) {} + AK_FORCE_INLINE virtual ~Suggest() {} + int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs, + int *times, int *pointerIds, int *inputCodePoints, int inputSize, int commitPoint, + int *outWords, int *frequencies, int *outputIndices, int *outputTypes) const; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Suggest); + void createNextWordDicNode(DicTraverseSession *traverseSession, DicNode *dicNode, + const bool spaceSubstitution) const; + int outputSuggestions(DicTraverseSession *traverseSession, int *frequencies, + int *outputCodePoints, int *outputIndices, int *outputTypes) const; + void initializeSearch(DicTraverseSession *traverseSession, int commitPoint) const; + void expandCurrentDicNodes(DicTraverseSession *traverseSession) const; + void processTerminalDicNode(DicTraverseSession *traverseSession, DicNode *dicNode) const; + void processExpandedDicNode(DicTraverseSession *traverseSession, DicNode *dicNode) const; + void weightChildNode(DicTraverseSession *traverseSession, DicNode *dicNode) const; + float getAutocorrectScore(DicTraverseSession *traverseSession, DicNode *dicNode) const; + void generateFeatures( + DicTraverseSession *traverseSession, DicNode *dicNode, float *features) const; + void processDicNodeAsOmission(DicTraverseSession *traverseSession, DicNode *dicNode) const; + void processDicNodeAsTransposition(DicTraverseSession *traverseSession, + DicNode *dicNode) const; + void processDicNodeAsInsertion(DicTraverseSession *traverseSession, DicNode *dicNode) const; + void processDicNodeAsAdditionalProximityChar(DicTraverseSession *traverseSession, + DicNode *dicNode, DicNode *childDicNode) const; + void processDicNodeAsSubstitution(DicTraverseSession *traverseSession, DicNode *dicNode, + DicNode *childDicNode) const; + void processDicNodeAsMatch(DicTraverseSession *traverseSession, + DicNode *childDicNode) const; + + // Dic nodes cache size for lookahead (autocompletion) + static const int LOOKAHEAD_DIC_NODES_CACHE_SIZE; + // Max characters to lookahead + static const int MAX_LOOKAHEAD; + // Inputs longer than this will autocorrect if the suggestion is multi-word + static const int MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT; + static const int MIN_CONTINUOUS_SUGGESTION_INPUT_SIZE; + // Base value for converting costs into scores (low so will not autocorrect without classifier) + static const float BASE_OUTPUT_SCORE; + + // Threshold for autocorrection classifier + static const float AUTOCORRECT_CLASSIFICATION_THRESHOLD; + // Threshold for computing the language model feature for autocorrect classification + static const float AUTOCORRECT_LANGUAGE_FEATURE_THRESHOLD; + + // Typing error correction settings + static const bool CORRECT_SPACE_OMISSION; + static const bool CORRECT_TRANSPOSITION; + static const bool CORRECT_INSERTION; + + const Traversal *const TRAVERSAL; + const Scoring *const SCORING; + const Weighting *const WEIGHTING; + + static const bool CORRECT_OMISSION_G; +}; +} // namespace latinime +#endif // LATINIME_SUGGEST_IMPL_H diff --git a/native/jni/src/suggest/suggest_interface.h b/native/jni/src/suggest/core/suggest_interface.h index 0bb85d7e5..0bb85d7e5 100644 --- a/native/jni/src/suggest/suggest_interface.h +++ b/native/jni/src/suggest/core/suggest_interface.h diff --git a/native/jni/src/suggest/gesture_suggest.h b/native/jni/src/suggest/gesture_suggest.h deleted file mode 100644 index 82c3a69ad..000000000 --- a/native/jni/src/suggest/gesture_suggest.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LATINIME_GESTURE_SUGGEST_H -#define LATINIME_GESTURE_SUGGEST_H - -#include "defines.h" -#include "suggest_interface.h" - -namespace latinime { - -class ProximityInfo; - -class GestureSuggest : public SuggestInterface { - public: - GestureSuggest() : mSuggestInterface(getGestureSuggestInstance()) {} - - virtual ~GestureSuggest(); - - int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs, - int *times, int *pointerIds, int *inputCodePoints, int inputSize, int commitPoint, - int *outWords, int *frequencies, int *outputIndices, int *outputTypes) const { - if (!mSuggestInterface) { - return 0; - } - return mSuggestInterface->getSuggestions(pInfo, traverseSession, inputXs, inputYs, times, - pointerIds, inputCodePoints, inputSize, commitPoint, outWords, frequencies, - outputIndices, outputTypes); - } - - static void setGestureSuggestFactoryMethod(SuggestInterface *(*factoryMethod)()) { - sGestureSuggestFactoryMethod = factoryMethod; - } - - private: - DISALLOW_COPY_AND_ASSIGN(GestureSuggest); - static SuggestInterface *getGestureSuggestInstance() { - if (!sGestureSuggestFactoryMethod) { - return 0; - } - return sGestureSuggestFactoryMethod(); - } - - static SuggestInterface *(*sGestureSuggestFactoryMethod)(); - SuggestInterface *mSuggestInterface; -}; -} // namespace latinime -#endif // LATINIME_GESTURE_SUGGEST_H diff --git a/native/jni/src/suggest/typing_suggest.cpp b/native/jni/src/suggest/policyimpl/gesture/gesture_suggest_policy_factory.cpp index 56bd5b69a..6d3173937 100644 --- a/native/jni/src/suggest/typing_suggest.cpp +++ b/native/jni/src/suggest/policyimpl/gesture/gesture_suggest_policy_factory.cpp @@ -14,12 +14,8 @@ * limitations under the License. */ -#include "typing_suggest.h" +#include "gesture_suggest_policy_factory.h" namespace latinime { - SuggestInterface *(*TypingSuggest::sTypingSuggestFactoryMethod)() = 0; - - TypingSuggest::~TypingSuggest() { - delete mSuggestInterface; - } + const SuggestPolicy *(*GestureSuggestPolicyFactory::sGestureSuggestFactoryMethod)() = 0; } // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/gesture/gesture_suggest_policy_factory.h b/native/jni/src/suggest/policyimpl/gesture/gesture_suggest_policy_factory.h new file mode 100644 index 000000000..509b01fc0 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/gesture/gesture_suggest_policy_factory.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LATINIME_GESTURE_SUGGEST_POLICY_FACTORY_H +#define LATINIME_GESTURE_SUGGEST_POLICY_FACTORY_H + +#include "defines.h" + +namespace latinime { + +class SuggestPolicy; + +class GestureSuggestPolicyFactory { + public: + static void setGestureSuggestPolicyFactoryMethod(const SuggestPolicy *(*factoryMethod)()) { + sGestureSuggestFactoryMethod = factoryMethod; + } + + static const SuggestPolicy *getGestureSuggestPolicy() { + if (!sGestureSuggestFactoryMethod) { + return 0; + } + return sGestureSuggestFactoryMethod(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(GestureSuggestPolicyFactory); + static const SuggestPolicy *(*sGestureSuggestFactoryMethod)(); +}; +} // namespace latinime +#endif // LATINIME_GESTURE_SUGGEST_POLICY_FACTORY_H diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp new file mode 100644 index 000000000..0fa684f01 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "suggest/policyimpl/typing/scoring_params.h" + +namespace latinime { +// TODO: RENAME all +const float ScoringParams::MAX_SPATIAL_DISTANCE = 1.0f; +const int ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY = 40; +const int ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY_FOR_CAPPED = 120; +const float ScoringParams::AUTOCORRECT_OUTPUT_THRESHOLD = 1.0f; +const int ScoringParams::MAX_CACHE_DIC_NODE_SIZE = 125; +const int ScoringParams::THRESHOLD_SHORT_WORD_LENGTH = 4; + +const float ScoringParams::DISTANCE_WEIGHT_LENGTH = 0.132f; +const float ScoringParams::PROXIMITY_COST = 0.086f; +const float ScoringParams::FIRST_PROXIMITY_COST = 0.104f; +const float ScoringParams::OMISSION_COST = 0.388f; +const float ScoringParams::OMISSION_COST_SAME_CHAR = 0.431f; +const float ScoringParams::OMISSION_COST_FIRST_CHAR = 0.532f; +const float ScoringParams::INSERTION_COST = 0.670f; +const float ScoringParams::INSERTION_COST_SAME_CHAR = 0.526f; +const float ScoringParams::INSERTION_COST_FIRST_CHAR = 0.563f; +const float ScoringParams::TRANSPOSITION_COST = 0.494f; +const float ScoringParams::SPACE_SUBSTITUTION_COST = 0.239f; +const float ScoringParams::ADDITIONAL_PROXIMITY_COST = 0.380f; +const float ScoringParams::SUBSTITUTION_COST = 0.363f; +const float ScoringParams::COST_NEW_WORD = 0.054f; +const float ScoringParams::COST_NEW_WORD_CAPITALIZED = 0.174f; +const float ScoringParams::DISTANCE_WEIGHT_LANGUAGE = 1.123f; +const float ScoringParams::COST_FIRST_LOOKAHEAD = 0.462f; +const float ScoringParams::COST_LOOKAHEAD = 0.092f; +const float ScoringParams::HAS_PROXIMITY_TERMINAL_COST = 0.126f; +const float ScoringParams::HAS_EDIT_CORRECTION_TERMINAL_COST = 0.056f; +const float ScoringParams::HAS_MULTI_WORD_TERMINAL_COST = 0.136f; +const float ScoringParams::TYPING_BASE_OUTPUT_SCORE = 1.0f; +const float ScoringParams::TYPING_MAX_OUTPUT_SCORE_PER_INPUT = 0.1f; +const float ScoringParams::MAX_NORM_DISTANCE_FOR_EDIT = 0.1f; +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.h b/native/jni/src/suggest/policyimpl/typing/scoring_params.h new file mode 100644 index 000000000..8f104b362 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LATINIME_SCORING_PARAMS_H +#define LATINIME_SCORING_PARAMS_H + +#include "defines.h" + +namespace latinime { + +class ScoringParams { + public: + // Fixed model parameters + static const float MAX_SPATIAL_DISTANCE; + static const int THRESHOLD_NEXT_WORD_PROBABILITY; + static const int THRESHOLD_NEXT_WORD_PROBABILITY_FOR_CAPPED; + static const float AUTOCORRECT_OUTPUT_THRESHOLD; + static const int MAX_CACHE_DIC_NODE_SIZE; + static const int THRESHOLD_SHORT_WORD_LENGTH; + + // Numerically optimized parameters (currently for tap typing only). + // TODO: add ability to modify these constants programmatically. + // TODO: explore optimization of gesture parameters. + static const float DISTANCE_WEIGHT_LENGTH; + static const float PROXIMITY_COST; + static const float FIRST_PROXIMITY_COST; + static const float OMISSION_COST; + static const float OMISSION_COST_SAME_CHAR; + static const float OMISSION_COST_FIRST_CHAR; + static const float INSERTION_COST; + static const float INSERTION_COST_SAME_CHAR; + static const float INSERTION_COST_FIRST_CHAR; + static const float TRANSPOSITION_COST; + static const float SPACE_SUBSTITUTION_COST; + static const float ADDITIONAL_PROXIMITY_COST; + static const float SUBSTITUTION_COST; + static const float COST_NEW_WORD; + static const float COST_NEW_WORD_CAPITALIZED; + static const float DISTANCE_WEIGHT_LANGUAGE; + static const float COST_FIRST_LOOKAHEAD; + static const float COST_LOOKAHEAD; + static const float HAS_PROXIMITY_TERMINAL_COST; + static const float HAS_EDIT_CORRECTION_TERMINAL_COST; + static const float HAS_MULTI_WORD_TERMINAL_COST; + static const float TYPING_BASE_OUTPUT_SCORE; + static const float TYPING_MAX_OUTPUT_SCORE_PER_INPUT; + static const float MAX_NORM_DISTANCE_FOR_EDIT; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ScoringParams); +}; +} // namespace latinime +#endif // LATINIME_SCORING_PARAMS_H diff --git a/native/jni/src/suggest/policyimpl/typing/typing_scoring.cpp b/native/jni/src/suggest/policyimpl/typing/typing_scoring.cpp new file mode 100644 index 000000000..d8c6175e2 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/typing/typing_scoring.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "suggest/policyimpl/typing/typing_scoring.h" + +namespace latinime { +const TypingScoring TypingScoring::sInstance; +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/typing/typing_scoring.h b/native/jni/src/suggest/policyimpl/typing/typing_scoring.h new file mode 100644 index 000000000..90e2133e7 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/typing/typing_scoring.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef LATINIME_TYPING_SCORING_H +#define LATINIME_TYPING_SCORING_H + +#include "defines.h" +#include "suggest/core/policy/scoring.h" +#include "suggest/policyimpl/typing/scoring_params.h" + +namespace latinime { + +class DicNode; +class DicTraverseSession; + +class TypingScoring : public Scoring { + public: + static const TypingScoring *getInstance() { return &sInstance; } + + AK_FORCE_INLINE bool getMostProbableString( + const DicTraverseSession *const traverseSession, const int terminalSize, + const float languageWeight, int *const outputCodePoints, int *const type, + int *const freq) const { + return false; + } + + AK_FORCE_INLINE void safetyNetForMostProbableString(const int terminalSize, + const int maxScore, int *const outputCodePoints, int *const frequencies) const { + } + + AK_FORCE_INLINE void searchWordWithDoubleLetter(DicNode *terminals, + const int terminalSize, int *doubleLetterTerminalIndex, + DoubleLetterLevel *doubleLetterLevel) const { + } + + AK_FORCE_INLINE float getAdjustedLanguageWeight(DicTraverseSession *const traverseSession, + DicNode *const terminals, const int size) const { + return 1.0f; + } + + AK_FORCE_INLINE int calculateFinalScore(const float compoundDistance, + const int inputSize, const bool forceCommit) const { + const float maxDistance = ScoringParams::DISTANCE_WEIGHT_LANGUAGE + + static_cast<float>(inputSize) * ScoringParams::TYPING_MAX_OUTPUT_SCORE_PER_INPUT; + return static_cast<int>((ScoringParams::TYPING_BASE_OUTPUT_SCORE + - (compoundDistance / maxDistance) + + (forceCommit ? ScoringParams::AUTOCORRECT_OUTPUT_THRESHOLD : 0.0f)) + * SUGGEST_INTERFACE_OUTPUT_SCALE); + } + + AK_FORCE_INLINE float getDoubleLetterDemotionDistanceCost(const int terminalIndex, + const int doubleLetterTerminalIndex, + const DoubleLetterLevel doubleLetterLevel) const { + return 0.0f; + } + + AK_FORCE_INLINE bool doesAutoCorrectValidWord() const { + return false; + } + + private: + DISALLOW_COPY_AND_ASSIGN(TypingScoring); + static const TypingScoring sInstance; + + TypingScoring() {} + ~TypingScoring() {} +}; +} // namespace latinime +#endif // LATINIME_TYPING_SCORING_H diff --git a/native/jni/src/suggest/policyimpl/typing/typing_suggest_policy.cpp b/native/jni/src/suggest/policyimpl/typing/typing_suggest_policy.cpp new file mode 100644 index 000000000..0c2763967 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/typing/typing_suggest_policy.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "suggest/policyimpl/typing/typing_suggest_policy.h" + +namespace latinime { +const TypingSuggestPolicy TypingSuggestPolicy::sInstance; +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/typing/typing_suggest_policy.h b/native/jni/src/suggest/policyimpl/typing/typing_suggest_policy.h new file mode 100644 index 000000000..35f48097c --- /dev/null +++ b/native/jni/src/suggest/policyimpl/typing/typing_suggest_policy.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef LATINIME_TYPING_SUGGEST_POLICY_H +#define LATINIME_TYPING_SUGGEST_POLICY_H + +#include "defines.h" +#include "suggest/core/policy/suggest_policy.h" +#include "suggest/policyimpl/typing/typing_scoring.h" +#include "suggest/policyimpl/typing/typing_traversal.h" +#include "suggest/policyimpl/typing/typing_weighting.h" + +namespace latinime { + +class Scoring; +class Traversal; +class Weighting; + +class TypingSuggestPolicy : public SuggestPolicy { + public: + static const TypingSuggestPolicy *getInstance() { return &sInstance; } + + TypingSuggestPolicy() {} + virtual ~TypingSuggestPolicy() {} + AK_FORCE_INLINE const Traversal *getTraversal() const { + return TypingTraversal::getInstance(); + } + + AK_FORCE_INLINE const Scoring *getScoring() const { + return TypingScoring::getInstance(); + } + + AK_FORCE_INLINE const Weighting *getWeighting() const { + return TypingWeighting::getInstance(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(TypingSuggestPolicy); + static const TypingSuggestPolicy sInstance; +}; +} // namespace latinime +#endif // LATINIME_TYPING_SUGGEST_POLICY_H diff --git a/native/jni/src/suggest/policyimpl/typing/typing_suggest_policy_factory.h b/native/jni/src/suggest/policyimpl/typing/typing_suggest_policy_factory.h new file mode 100644 index 000000000..a67b45b1b --- /dev/null +++ b/native/jni/src/suggest/policyimpl/typing/typing_suggest_policy_factory.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef LATINIME_TYPING_SUGGEST_POLICY_FACTORY_H +#define LATINIME_TYPING_SUGGEST_POLICY_FACTORY_H + +#include "defines.h" +#include "typing_suggest_policy.h" + +namespace latinime { + +class SuggestPolicy; + +class TypingSuggestPolicyFactory { + public: + static const SuggestPolicy *getTypingSuggestPolicy() { + return TypingSuggestPolicy::getInstance(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(TypingSuggestPolicyFactory); +}; +} // namespace latinime +#endif // LATINIME_TYPING_SUGGEST_POLICY_FACTORY_H diff --git a/native/jni/src/suggest/policyimpl/typing/typing_traversal.cpp b/native/jni/src/suggest/policyimpl/typing/typing_traversal.cpp new file mode 100644 index 000000000..66f8ba9fa --- /dev/null +++ b/native/jni/src/suggest/policyimpl/typing/typing_traversal.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "suggest/policyimpl/typing/typing_traversal.h" + +namespace latinime { +const bool TypingTraversal::CORRECT_OMISSION = true; +const bool TypingTraversal::CORRECT_SPACE_SUBSTITUTION = true; +const bool TypingTraversal::CORRECT_SPACE_OMISSION = true; +const TypingTraversal TypingTraversal::sInstance; +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/typing/typing_traversal.h b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h new file mode 100644 index 000000000..f22029a2c --- /dev/null +++ b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef LATINIME_TYPING_TRAVERSAL_H +#define LATINIME_TYPING_TRAVERSAL_H + +#include <stdint.h> + +#include "char_utils.h" +#include "defines.h" +#include "proximity_info_state.h" +#include "suggest/core/dicnode/dic_node.h" +#include "suggest/core/dicnode/dic_node_vector.h" +#include "suggest/core/policy/traversal.h" +#include "suggest/core/session/dic_traverse_session.h" +#include "suggest/policyimpl/typing/scoring_params.h" + +namespace latinime { +class TypingTraversal : public Traversal { + public: + static const TypingTraversal *getInstance() { return &sInstance; } + + AK_FORCE_INLINE int getMaxPointerCount() const { + return MAX_POINTER_COUNT; + } + + AK_FORCE_INLINE bool allowsErrorCorrections(const DicNode *const dicNode) const { + return dicNode->getNormalizedSpatialDistance() + < ScoringParams::MAX_NORM_DISTANCE_FOR_EDIT; + } + + AK_FORCE_INLINE bool isOmission(const DicTraverseSession *const traverseSession, + const DicNode *const dicNode, const DicNode *const childDicNode) const { + if (!CORRECT_OMISSION) { + return false; + } + const int inputSize = traverseSession->getInputSize(); + // TODO: Don't refer to isCompletion? + if (dicNode->isCompletion(inputSize)) { + return false; + } + if (dicNode->canBeIntentionalOmission()) { + return true; + } + const int point0Index = dicNode->getInputIndex(0); + const int currentBaseLowerCodePoint = + toBaseLowerCase(childDicNode->getNodeCodePoint()); + const int typedBaseLowerCodePoint = + toBaseLowerCase(traverseSession->getProximityInfoState(0) + ->getPrimaryCodePointAt(point0Index)); + return (currentBaseLowerCodePoint != typedBaseLowerCodePoint); + } + + AK_FORCE_INLINE bool isSpaceSubstitutionTerminal( + const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { + if (!CORRECT_SPACE_SUBSTITUTION) { + return false; + } + if (!canDoLookAheadCorrection(traverseSession, dicNode)) { + return false; + } + const int point0Index = dicNode->getInputIndex(0); + return dicNode->isTerminalWordNode() + && traverseSession->getProximityInfoState(0)-> + hasSpaceProximity(point0Index); + } + + AK_FORCE_INLINE bool isSpaceOmissionTerminal( + const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { + if (!CORRECT_SPACE_OMISSION) { + return false; + } + const int inputSize = traverseSession->getInputSize(); + // TODO: Don't refer to isCompletion? + if (dicNode->isCompletion(inputSize)) { + return false; + } + if (!dicNode->isTerminalWordNode()) { + return false; + } + const int16_t pointIndex = dicNode->getInputIndex(0); + return pointIndex <= inputSize && !dicNode->isTotalInputSizeExceedingLimit() + && !dicNode->shouldBeFilterdBySafetyNetForBigram(); + } + + AK_FORCE_INLINE bool shouldDepthLevelCache( + const DicTraverseSession *const traverseSession) const { + const int inputSize = traverseSession->getInputSize(); + return traverseSession->isCacheBorderForTyping(inputSize); + } + + AK_FORCE_INLINE bool shouldNodeLevelCache( + const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { + return false; + } + + AK_FORCE_INLINE bool canDoLookAheadCorrection( + const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { + const int inputSize = traverseSession->getInputSize(); + return dicNode->canDoLookAheadCorrection(inputSize); + } + + AK_FORCE_INLINE ProximityType getProximityType( + const DicTraverseSession *const traverseSession, const DicNode *const dicNode, + const DicNode *const childDicNode) const { + return traverseSession->getProximityInfoState(0)->getProximityType( + dicNode->getInputIndex(0), childDicNode->getNodeCodePoint(), + true /* checkProximityChars */); + } + + AK_FORCE_INLINE bool needsToTraverseAllUserInput() const { + return true; + } + + AK_FORCE_INLINE float getMaxSpatialDistance() const { + return ScoringParams::MAX_SPATIAL_DISTANCE; + } + + AK_FORCE_INLINE bool allowPartialCommit() const { + return true; + } + + AK_FORCE_INLINE int getDefaultExpandDicNodeSize() const { + return DicNodeVector::DEFAULT_NODES_SIZE_FOR_OPTIMIZATION; + } + + AK_FORCE_INLINE bool sameAsTyped( + const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { + return traverseSession->getProximityInfoState(0)->sameAsTyped( + dicNode->getOutputWordBuf(), dicNode->getDepth()); + } + + AK_FORCE_INLINE int getMaxCacheSize() const { + return ScoringParams::MAX_CACHE_DIC_NODE_SIZE; + } + + AK_FORCE_INLINE bool isPossibleOmissionChildNode( + const DicTraverseSession *const traverseSession, const DicNode *const parentDicNode, + const DicNode *const dicNode) const { + const ProximityType proximityType = + getProximityType(traverseSession, parentDicNode, dicNode); + if (!DicNodeUtils::isProximityChar(proximityType)) { + return false; + } + return true; + } + + AK_FORCE_INLINE bool isGoodToTraverseNextWord(const DicNode *const dicNode) const { + const int probability = dicNode->getProbability(); + if (probability < ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY) { + return false; + } + const int c = dicNode->getOutputWordBuf()[0]; + const bool shortCappedWord = dicNode->getDepth() + < ScoringParams::THRESHOLD_SHORT_WORD_LENGTH && isAsciiUpper(c); + return !shortCappedWord + || probability >= ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY_FOR_CAPPED; + } + + private: + DISALLOW_COPY_AND_ASSIGN(TypingTraversal); + static const bool CORRECT_OMISSION; + static const bool CORRECT_SPACE_SUBSTITUTION; + static const bool CORRECT_SPACE_OMISSION; + static const TypingTraversal sInstance; + + TypingTraversal() {} + ~TypingTraversal() {} +}; +} // namespace latinime +#endif // LATINIME_TYPING_TRAVERSAL_H diff --git a/native/jni/src/suggest/gesture_suggest.cpp b/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp index fce5621d5..1500341bd 100644 --- a/native/jni/src/suggest/gesture_suggest.cpp +++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp @@ -14,12 +14,11 @@ * limitations under the License. */ -#include "gesture_suggest.h" +#include "suggest/policyimpl/typing/typing_weighting.h" -namespace latinime { - SuggestInterface *(*GestureSuggest::sGestureSuggestFactoryMethod)() = 0; +#include "suggest/core/dicnode/dic_node.h" +#include "suggest/policyimpl/typing/scoring_params.h" - GestureSuggest::~GestureSuggest() { - delete mSuggestInterface; - } -} // namespace latinime +namespace latinime { +const TypingWeighting TypingWeighting::sInstance; +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h new file mode 100644 index 000000000..52d54eb0f --- /dev/null +++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LATINIME_TYPING_WEIGHTING_H +#define LATINIME_TYPING_WEIGHTING_H + +#include "defines.h" +#include "suggest/core/dicnode/dic_node_utils.h" +#include "suggest/core/policy/weighting.h" +#include "suggest/core/session/dic_traverse_session.h" +#include "suggest/policyimpl/typing/scoring_params.h" + +namespace latinime { + +class DicNode; +struct DicNode_InputStateG; + +class TypingWeighting : public Weighting { + public: + static const TypingWeighting *getInstance() { return &sInstance; } + + protected: + float getTerminalSpatialCost( + const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { + float cost = 0.0f; + if (dicNode->hasMultipleWords()) { + cost += ScoringParams::HAS_MULTI_WORD_TERMINAL_COST; + } + if (dicNode->getProximityCorrectionCount() > 0) { + cost += ScoringParams::HAS_PROXIMITY_TERMINAL_COST; + } + if (dicNode->getEditCorrectionCount() > 0) { + cost += ScoringParams::HAS_EDIT_CORRECTION_TERMINAL_COST; + } + return cost; + } + + float getOmissionCost(const DicNode *const parentDicNode, const DicNode *const dicNode) const { + bool sameCodePoint = false; + bool isFirstLetterOmission = false; + float cost = 0.0f; + sameCodePoint = dicNode->isSameNodeCodePoint(parentDicNode); + // If the traversal omitted the first letter then the dicNode should now be on the second. + isFirstLetterOmission = dicNode->getDepth() == 2; + if (isFirstLetterOmission) { + cost = ScoringParams::OMISSION_COST_FIRST_CHAR; + } else { + cost = sameCodePoint ? ScoringParams::OMISSION_COST_SAME_CHAR + : ScoringParams::OMISSION_COST; + } + return cost; + } + + float getMatchedCost( + const DicTraverseSession *const traverseSession, const DicNode *const dicNode, + DicNode_InputStateG *inputStateG) const { + const int pointIndex = dicNode->getInputIndex(0); + // Note: min() required since length can be MAX_POINT_TO_KEY_LENGTH for characters not on + // the keyboard (like accented letters) + const float length = min(ScoringParams::MAX_SPATIAL_DISTANCE, + traverseSession->getProximityInfoState(0)->getPointToKeyLength( + pointIndex, dicNode->getNodeCodePoint())); + const float weightedDistance = length * ScoringParams::DISTANCE_WEIGHT_LENGTH; + const bool isFirstChar = pointIndex == 0; + const bool isProximity = isProximityDicNode(traverseSession, dicNode); + const float cost = isProximity ? (isFirstChar ? ScoringParams::FIRST_PROXIMITY_COST + : ScoringParams::PROXIMITY_COST) : 0.0f; + return weightedDistance + cost; + } + + bool isProximityDicNode( + const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { + const int pointIndex = dicNode->getInputIndex(0); + const int primaryCodePoint = toBaseLowerCase( + traverseSession->getProximityInfoState(0)->getPrimaryCodePointAt(pointIndex)); + const int dicNodeChar = toBaseLowerCase(dicNode->getNodeCodePoint()); + return primaryCodePoint != dicNodeChar; + } + + float getTranspositionCost( + const DicTraverseSession *const traverseSession, const DicNode *const parentDicNode, + const DicNode *const dicNode) const { + const int16_t parentPointIndex = parentDicNode->getInputIndex(0); + const int prevCodePoint = parentDicNode->getNodeCodePoint(); + const float distance1 = traverseSession->getProximityInfoState(0)->getPointToKeyLength( + parentPointIndex + 1, prevCodePoint); + const int codePoint = dicNode->getNodeCodePoint(); + const float distance2 = traverseSession->getProximityInfoState(0)->getPointToKeyLength( + parentPointIndex, codePoint); + const float distance = distance1 + distance2; + const float weightedLengthDistance = + distance * ScoringParams::DISTANCE_WEIGHT_LENGTH; + return ScoringParams::TRANSPOSITION_COST + weightedLengthDistance; + } + + float getInsertionCost( + const DicTraverseSession *const traverseSession, + const DicNode *const parentDicNode, const DicNode *const dicNode) const { + const int16_t parentPointIndex = parentDicNode->getInputIndex(0); + const int prevCodePoint = + traverseSession->getProximityInfoState(0)->getPrimaryCodePointAt(parentPointIndex); + + const int currentCodePoint = dicNode->getNodeCodePoint(); + const bool sameCodePoint = prevCodePoint == currentCodePoint; + const float dist = traverseSession->getProximityInfoState(0)->getPointToKeyLength( + parentPointIndex + 1, currentCodePoint); + const float weightedDistance = dist * ScoringParams::DISTANCE_WEIGHT_LENGTH; + const bool singleChar = dicNode->getDepth() == 1; + const float cost = (singleChar ? ScoringParams::INSERTION_COST_FIRST_CHAR : 0.0f) + + (sameCodePoint ? ScoringParams::INSERTION_COST_SAME_CHAR + : ScoringParams::INSERTION_COST); + return cost + weightedDistance; + } + + float getNewWordCost(const DicNode *const dicNode) const { + const bool isCapitalized = dicNode->isCapitalized(); + return isCapitalized ? + ScoringParams::COST_NEW_WORD_CAPITALIZED : ScoringParams::COST_NEW_WORD; + } + + float getNewWordBigramCost( + const DicTraverseSession *const traverseSession, const DicNode *const dicNode, + hash_map_compat<int, int16_t> *const bigramCacheMap) const { + return DicNodeUtils::getBigramNodeImprobability(traverseSession->getOffsetDict(), + dicNode, bigramCacheMap); + } + + float getCompletionCost(const DicTraverseSession *const traverseSession, + const DicNode *const dicNode) const { + // The auto completion starts when the input index is same as the input size + const bool firstCompletion = dicNode->getInputIndex(0) + == traverseSession->getInputSize(); + // TODO: Change the cost for the first completion for the gesture? + const float cost = firstCompletion ? ScoringParams::COST_FIRST_LOOKAHEAD + : ScoringParams::COST_LOOKAHEAD; + return cost; + } + + float getTerminalLanguageCost(const DicTraverseSession *const traverseSession, + const DicNode *const dicNode, const float dicNodeLanguageImprobability) const { + const bool hasEditCount = dicNode->getEditCorrectionCount() > 0; + const bool isSameLength = dicNode->getDepth() == traverseSession->getInputSize(); + const bool hasMultipleWords = dicNode->hasMultipleWords(); + const bool hasProximityErrors = dicNode->getProximityCorrectionCount() > 0; + // Gesture input is always assumed to have proximity errors + // because the input word shouldn't be treated as perfect + const bool isExactMatch = !hasEditCount && !hasMultipleWords + && !hasProximityErrors && isSameLength; + + const float totalPrevWordsLanguageCost = dicNode->getTotalPrevWordsLanguageCost(); + const float languageImprobability = isExactMatch ? 0.0f : dicNodeLanguageImprobability; + const float languageWeight = ScoringParams::DISTANCE_WEIGHT_LANGUAGE; + // TODO: Caveat: The following equation should be: + // totalPrevWordsLanguageCost + (languageImprobability * languageWeight); + return (totalPrevWordsLanguageCost + languageImprobability) * languageWeight; + } + + AK_FORCE_INLINE bool needsToNormalizeCompoundDistance() const { + return false; + } + + AK_FORCE_INLINE float getAdditionalProximityCost() const { + return ScoringParams::ADDITIONAL_PROXIMITY_COST; + } + + AK_FORCE_INLINE float getSubstitutionCost() const { + return ScoringParams::SUBSTITUTION_COST; + } + + AK_FORCE_INLINE float getSpaceSubstitutionCost() const { + return ScoringParams::SPACE_SUBSTITUTION_COST; + } + + private: + DISALLOW_COPY_AND_ASSIGN(TypingWeighting); + static const TypingWeighting sInstance; + + TypingWeighting() {} + ~TypingWeighting() {} +}; +} // namespace latinime +#endif // LATINIME_TYPING_WEIGHTING_H diff --git a/native/jni/src/suggest/typing_suggest.h b/native/jni/src/suggest/typing_suggest.h deleted file mode 100644 index 678037aa2..000000000 --- a/native/jni/src/suggest/typing_suggest.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LATINIME_TYPING_SUGGEST_H -#define LATINIME_TYPING_SUGGEST_H - -#include "defines.h" -#include "suggest_interface.h" - -namespace latinime { - -class ProximityInfo; - -class TypingSuggest : public SuggestInterface { - public: - TypingSuggest() : mSuggestInterface(getTypingSuggestInstance()) {} - - virtual ~TypingSuggest(); - - int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs, - int *times, int *pointerIds, int *inputCodePoints, int inputSize, int commitPoint, - int *outWords, int *frequencies, int *outputIndices, int *outputTypes) const { - if (!mSuggestInterface) { - return 0; - } - return mSuggestInterface->getSuggestions(pInfo, traverseSession, inputXs, inputYs, times, - pointerIds, inputCodePoints, inputSize, commitPoint, outWords, frequencies, - outputIndices, outputTypes); - } - - static void setTypingSuggestFactoryMethod(SuggestInterface *(*factoryMethod)()) { - sTypingSuggestFactoryMethod = factoryMethod; - } - - private: - DISALLOW_COPY_AND_ASSIGN(TypingSuggest); - static SuggestInterface *getTypingSuggestInstance() { - if (!sTypingSuggestFactoryMethod) { - return 0; - } - return sTypingSuggestFactoryMethod(); - } - - static SuggestInterface *(*sTypingSuggestFactoryMethod)(); - SuggestInterface *mSuggestInterface; -}; -} // namespace latinime -#endif // LATINIME_TYPING_SUGGEST_H diff --git a/native/jni/src/unigram_dictionary.cpp b/native/jni/src/unigram_dictionary.cpp index 80ba412a3..33795cade 100644 --- a/native/jni/src/unigram_dictionary.cpp +++ b/native/jni/src/unigram_dictionary.cpp @@ -22,6 +22,7 @@ #include "char_utils.h" #include "defines.h" #include "dictionary.h" +#include "digraph_utils.h" #include "proximity_info.h" #include "terminal_attributes.h" #include "unigram_dictionary.h" @@ -30,15 +31,6 @@ namespace latinime { -const UnigramDictionary::digraph_t UnigramDictionary::GERMAN_UMLAUT_DIGRAPHS[] = - { { 'a', 'e', 0x00E4 }, // U+00E4 : LATIN SMALL LETTER A WITH DIAERESIS - { 'o', 'e', 0x00F6 }, // U+00F6 : LATIN SMALL LETTER O WITH DIAERESIS - { 'u', 'e', 0x00FC } }; // U+00FC : LATIN SMALL LETTER U WITH DIAERESIS - -const UnigramDictionary::digraph_t UnigramDictionary::FRENCH_LIGATURES_DIGRAPHS[] = - { { 'a', 'e', 0x00E6 }, // U+00E6 : LATIN SMALL LETTER AE - { 'o', 'e', 0x0153 } }; // U+0153 : LATIN SMALL LIGATURE OE - // TODO: check the header UnigramDictionary::UnigramDictionary(const uint8_t *const streamStart, const unsigned int flags) : DICT_ROOT(streamStart), ROOT_POS(0), @@ -58,7 +50,7 @@ static void addWord(int *word, int length, int probability, WordsPriorityQueue * // Return the replacement code point for a digraph, or 0 if none. int UnigramDictionary::getDigraphReplacement(const int *codes, const int i, const int inputSize, - const digraph_t *const digraphs, const unsigned int digraphsSize) const { + const DigraphUtils::digraph_t *const digraphs, const unsigned int digraphsSize) const { // There can't be a digraph if we don't have at least 2 characters to examine if (i + 2 > inputSize) return false; @@ -74,7 +66,7 @@ int UnigramDictionary::getDigraphReplacement(const int *codes, const int i, cons // It's an interesting digraph if the second char matches too. if (digraphs[lastDigraphIndex].second == codes[i + 1]) { - return digraphs[lastDigraphIndex].replacement; + return digraphs[lastDigraphIndex].compositeGlyph; } else { return 0; } @@ -93,7 +85,7 @@ void UnigramDictionary::getWordWithDigraphSuggestionsRec(ProximityInfo *proximit const bool useFullEditDistance, const int *codesSrc, const int codesRemain, const int currentDepth, int *codesDest, Correction *correction, WordsPriorityQueuePool *queuePool, - const digraph_t *const digraphs, const unsigned int digraphsSize) const { + const DigraphUtils::digraph_t *const digraphs, const unsigned int digraphsSize) const { ASSERT(sizeof(codesDest[0]) == sizeof(codesSrc[0])); ASSERT(sizeof(xCoordinatesBuffer[0]) == sizeof(xcoordinates[0])); ASSERT(sizeof(yCoordinatesBuffer[0]) == sizeof(ycoordinates[0])); @@ -169,7 +161,10 @@ int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, const int *x queuePool.clearAll(); Correction masterCorrection; masterCorrection.resetCorrection(); - if (BinaryFormat::REQUIRES_GERMAN_UMLAUT_PROCESSING & FLAGS) + const DigraphUtils::digraph_t *digraphs = 0; + const int digraphsSize = + DigraphUtils::getAllDigraphsForDictionaryAndReturnSize(FLAGS, &digraphs); + if (digraphsSize > 0) { // Incrementally tune the word and try all possibilities int codesBuffer[sizeof(*inputCodePoints) * inputSize]; int xCoordinatesBuffer[inputSize]; @@ -177,15 +172,7 @@ int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, const int *x getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer, xCoordinatesBuffer, yCoordinatesBuffer, inputSize, bigramMap, bigramFilter, useFullEditDistance, inputCodePoints, inputSize, 0, codesBuffer, &masterCorrection, - &queuePool, GERMAN_UMLAUT_DIGRAPHS, NELEMS(GERMAN_UMLAUT_DIGRAPHS)); - } else if (BinaryFormat::REQUIRES_FRENCH_LIGATURES_PROCESSING & FLAGS) { - int codesBuffer[sizeof(*inputCodePoints) * inputSize]; - int xCoordinatesBuffer[inputSize]; - int yCoordinatesBuffer[inputSize]; - getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer, - xCoordinatesBuffer, yCoordinatesBuffer, inputSize, bigramMap, bigramFilter, - useFullEditDistance, inputCodePoints, inputSize, 0, codesBuffer, &masterCorrection, - &queuePool, FRENCH_LIGATURES_DIGRAPHS, NELEMS(FRENCH_LIGATURES_DIGRAPHS)); + &queuePool, digraphs, digraphsSize); } else { // Normal processing getWordSuggestions(proximityInfo, xcoordinates, ycoordinates, inputCodePoints, inputSize, bigramMap, bigramFilter, useFullEditDistance, &masterCorrection, &queuePool); diff --git a/native/jni/src/unigram_dictionary.h b/native/jni/src/unigram_dictionary.h index c1955e8bb..1a01758fe 100644 --- a/native/jni/src/unigram_dictionary.h +++ b/native/jni/src/unigram_dictionary.h @@ -20,6 +20,7 @@ #include <map> #include <stdint.h> #include "defines.h" +#include "digraph_utils.h" namespace latinime { @@ -29,8 +30,6 @@ class TerminalAttributes; class WordsPriorityQueuePool; class UnigramDictionary { - typedef struct { int first; int second; int replacement; } digraph_t; - public: // Error tolerances static const int DEFAULT_MAX_ERRORS = 2; @@ -57,13 +56,13 @@ class UnigramDictionary { const bool useFullEditDistance, Correction *correction, WordsPriorityQueuePool *queuePool) const; int getDigraphReplacement(const int *codes, const int i, const int inputSize, - const digraph_t *const digraphs, const unsigned int digraphsSize) const; + const DigraphUtils::digraph_t *const digraphs, const unsigned int digraphsSize) const; void getWordWithDigraphSuggestionsRec(ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, const int *codesBuffer, int *xCoordinatesBuffer, int *yCoordinatesBuffer, const int codesBufferSize, const std::map<int, int> *bigramMap, const uint8_t *bigramFilter, const bool useFullEditDistance, const int *codesSrc, const int codesRemain, const int currentDepth, int *codesDest, Correction *correction, - WordsPriorityQueuePool *queuePool, const digraph_t *const digraphs, + WordsPriorityQueuePool *queuePool, const DigraphUtils::digraph_t *const digraphs, const unsigned int digraphsSize) const; void initSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, const int *codes, const int inputSize, @@ -111,9 +110,6 @@ class UnigramDictionary { const int ROOT_POS; const int MAX_DIGRAPH_SEARCH_DEPTH; const int FLAGS; - - static const digraph_t GERMAN_UMLAUT_DIGRAPHS[]; - static const digraph_t FRENCH_LIGATURES_DIGRAPHS[]; }; } // namespace latinime #endif // LATINIME_UNIGRAM_DICTIONARY_H diff --git a/tests/src/com/android/inputmethod/keyboard/internal/HermiteInterpolatorTests.java b/tests/src/com/android/inputmethod/keyboard/internal/HermiteInterpolatorTests.java new file mode 100644 index 000000000..3ff5aa485 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/internal/HermiteInterpolatorTests.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2013 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.internal; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +@SmallTest +public class HermiteInterpolatorTests extends AndroidTestCase { + private final HermiteInterpolator mInterpolator = new HermiteInterpolator(); + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + private static final float EPSLION = 0.0000005f; + + private static void assertFloatEquals(final String message, float expected, float actual) { + if (Math.abs(expected - actual) >= EPSLION) { + fail(String.format("%s expected:<%s> but was:<%s>", message, expected, actual)); + } + } + + // t=0 p0=(0,1) + // t=1 p1=(1,0) + // t=2 p2=(3,2) + // t=3 p3=(2,3) + // y + // | + // 3 + o p3 + // | + // 2 + o p2 + // | + // 1 o p0 + // | p1 + // 0 +---o---+---+-- x + // 0 1 2 3 + private final int[] mXCoords = { 0, 1, 3, 2 }; + private final int[] mYCoords = { 1, 0, 2, 3 }; + private static final int p0 = 0; + private static final int p1 = 1; + private static final int p2 = 2; + private static final int p3 = 3; + + public void testP0P1() { + // [(p0 p1) p2 p3] + mInterpolator.reset(mXCoords, mYCoords, p0, p3 + 1); + mInterpolator.setInterval(p0 - 1, p0, p1, p1 + 1); + assertEquals("p0x", mXCoords[p0], mInterpolator.mP1X); + assertEquals("p0y", mYCoords[p0], mInterpolator.mP1Y); + assertEquals("p1x", mXCoords[p1], mInterpolator.mP2X); + assertEquals("p1y", mYCoords[p1], mInterpolator.mP2Y); + // XY-slope at p0=3.0 (-0.75/-0.25) + assertFloatEquals("slope x p0", -0.25f, mInterpolator.mSlope1X); + assertFloatEquals("slope y p0", -0.75f, mInterpolator.mSlope1Y); + // XY-slope at p1=1/3.0 (0.50/1.50) + assertFloatEquals("slope x p1", 1.50f, mInterpolator.mSlope2X); + assertFloatEquals("slope y p1", 0.50f, mInterpolator.mSlope2Y); + // t=0.0 (p0) + mInterpolator.interpolate(0.0f); + assertFloatEquals("t=0.0 x", 0.0f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.0 y", 1.0f, mInterpolator.mInterpolatedY); + // t=0.2 + mInterpolator.interpolate(0.2f); + assertFloatEquals("t=0.2 x", 0.02400f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.2 y", 0.78400f, mInterpolator.mInterpolatedY); + // t=0.5 + mInterpolator.interpolate(0.5f); + assertFloatEquals("t=0.5 x", 0.28125f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.5 y", 0.34375f, mInterpolator.mInterpolatedY); + // t=0.8 + mInterpolator.interpolate(0.8f); + assertFloatEquals("t=0.8 x", 0.69600f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.8 y", 0.01600f, mInterpolator.mInterpolatedY); + // t=1.0 (p1) + mInterpolator.interpolate(1.0f); + assertFloatEquals("t=1.0 x", 1.0f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=1.0 y", 0.0f, mInterpolator.mInterpolatedY); + } + + public void testP1P2() { + // [p0 (p1 p2) p3] + mInterpolator.reset(mXCoords, mYCoords, p0, p3 + 1); + mInterpolator.setInterval(p1 - 1, p1, p2, p2 + 1); + assertEquals("p1x", mXCoords[p1], mInterpolator.mP1X); + assertEquals("p1y", mYCoords[p1], mInterpolator.mP1Y); + assertEquals("p2x", mXCoords[p2], mInterpolator.mP2X); + assertEquals("p2y", mYCoords[p2], mInterpolator.mP2Y); + // XY-slope at p1=1/3.0 (0.50/1.50) + assertFloatEquals("slope x p1", 1.50f, mInterpolator.mSlope1X); + assertFloatEquals("slope y p1", 0.50f, mInterpolator.mSlope1Y); + // XY-slope at p2=3.0 (1.50/0.50) + assertFloatEquals("slope x p2", 0.50f, mInterpolator.mSlope2X); + assertFloatEquals("slope y p2", 1.50f, mInterpolator.mSlope2Y); + // t=0.0 (p1) + mInterpolator.interpolate(0.0f); + assertFloatEquals("t=0.0 x", 1.0f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.0 y", 0.0f, mInterpolator.mInterpolatedY); + // t=0.2 + mInterpolator.interpolate(0.2f); + assertFloatEquals("t=0.2 x", 1.384f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.2 y", 0.224f, mInterpolator.mInterpolatedY); + // t=0.5 + mInterpolator.interpolate(0.5f); + assertFloatEquals("t=0.5 x", 2.125f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.5 y", 0.875f, mInterpolator.mInterpolatedY); + // t=0.8 + mInterpolator.interpolate(0.8f); + assertFloatEquals("t=0.8 x", 2.776f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.8 y", 1.616f, mInterpolator.mInterpolatedY); + // t=1.0 (p2) + mInterpolator.interpolate(1.0f); + assertFloatEquals("t=1.0 x", 3.0f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=1.0 y", 2.0f, mInterpolator.mInterpolatedY); + } + + public void testP2P3() { + // [p0 p1 (p2 p3)] + mInterpolator.reset(mXCoords, mYCoords, p0, p3 + 1); + mInterpolator.setInterval(p2 - 1, p2, p3, p3 + 1); + assertEquals("p2x", mXCoords[p2], mInterpolator.mP1X); + assertEquals("p2y", mYCoords[p2], mInterpolator.mP1Y); + assertEquals("p3x", mXCoords[p3], mInterpolator.mP2X); + assertEquals("p3y", mYCoords[p3], mInterpolator.mP2Y); + // XY-slope at p2=3.0 (1.50/0.50) + assertFloatEquals("slope x p2", 0.50f, mInterpolator.mSlope1X); + assertFloatEquals("slope y p2", 1.50f, mInterpolator.mSlope1Y); + // XY-slope at p3=1/3.0 (-0.25/-0.75) + assertFloatEquals("slope x p3", -0.75f, mInterpolator.mSlope2X); + assertFloatEquals("slope y p3", -0.25f, mInterpolator.mSlope2Y); + // t=0.0 (p2) + mInterpolator.interpolate(0.0f); + assertFloatEquals("t=0.0 x", 3.0f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.0 y", 2.0f, mInterpolator.mInterpolatedY); + // t=0.2 + mInterpolator.interpolate(0.2f); + assertFloatEquals("t=0.2 x", 2.98400f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.2 y", 2.30400f, mInterpolator.mInterpolatedY); + // t=0.5 + mInterpolator.interpolate(0.5f); + assertFloatEquals("t=0.5 x", 2.65625f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.5 y", 2.71875f, mInterpolator.mInterpolatedY); + // t=0.8 + mInterpolator.interpolate(0.8f); + assertFloatEquals("t=0.8 x", 2.21600f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.8 y", 2.97600f, mInterpolator.mInterpolatedY); + // t=1.0 (p3) + mInterpolator.interpolate(1.0f); + assertFloatEquals("t=1.0 x", 2.0f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=1.0 y", 3.0f, mInterpolator.mInterpolatedY); + } + + public void testJustP1P2() { + // [(p1 p2)] + mInterpolator.reset(mXCoords, mYCoords, p1, p2 + 1); + mInterpolator.setInterval(p1 - 1, p1, p2, p2 + 1); + assertEquals("p1x", mXCoords[p1], mInterpolator.mP1X); + assertEquals("p1y", mYCoords[p1], mInterpolator.mP1Y); + assertEquals("p2x", mXCoords[p2], mInterpolator.mP2X); + assertEquals("p2y", mYCoords[p2], mInterpolator.mP2Y); + // XY-slope at p1=1.0 (2.0/2.0) + assertFloatEquals("slope x p1", 2.00f, mInterpolator.mSlope1X); + assertFloatEquals("slope y p1", 2.00f, mInterpolator.mSlope1Y); + // XY-slope at p2=1.0 (2.0/2.0) + assertFloatEquals("slope x p2", 2.00f, mInterpolator.mSlope2X); + assertFloatEquals("slope y p2", 2.00f, mInterpolator.mSlope2Y); + // t=0.0 (p1) + mInterpolator.interpolate(0.0f); + assertFloatEquals("t=0.0 x", 1.0f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.0 y", 0.0f, mInterpolator.mInterpolatedY); + // t=0.2 + mInterpolator.interpolate(0.2f); + assertFloatEquals("t=0.2 x", 1.4f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.2 y", 0.4f, mInterpolator.mInterpolatedY); + // t=0.5 + mInterpolator.interpolate(0.5f); + assertFloatEquals("t=0.5 x", 2.0f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.5 y", 1.0f, mInterpolator.mInterpolatedY); + // t=0.8 + mInterpolator.interpolate(0.8f); + assertFloatEquals("t=0.8 x", 2.6f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=0.8 y", 1.6f, mInterpolator.mInterpolatedY); + // t=1.0 (p2) + mInterpolator.interpolate(1.0f); + assertFloatEquals("t=1.0 x", 3.0f, mInterpolator.mInterpolatedX); + assertFloatEquals("t=1.0 y", 2.0f, mInterpolator.mInterpolatedY); + } +} diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java index 4ccbf4857..04e1f932a 100644 --- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java +++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java @@ -130,7 +130,9 @@ public class InputTestsBase extends ServiceTestCase<LatinIME> { protected void setUp() throws Exception { super.setUp(); mTextView = new MyTextView(getContext()); - mTextView.setInputType(InputType.TYPE_CLASS_TEXT); + final int inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT + | InputType.TYPE_TEXT_FLAG_MULTI_LINE; + mTextView.setInputType(inputType); mTextView.setEnabled(true); setupService(); mLatinIME = getService(); @@ -138,9 +140,7 @@ public class InputTestsBase extends ServiceTestCase<LatinIME> { mLatinIME.onCreate(); setDebugMode(previousDebugSetting); final EditorInfo ei = new EditorInfo(); - ei.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT; final InputConnection ic = mTextView.onCreateInputConnection(ei); - ei.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT; final LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); final ViewGroup vg = new FrameLayout(getContext()); @@ -181,17 +181,21 @@ public class InputTestsBase extends ServiceTestCase<LatinIME> { // a message that calls it instead of calling it directly. Looper.loop(); - // Once #quit() has been called, the message queue has an "mQuiting" field that prevents - // any subsequent post in this queue. However the queue itself is still fully functional! - // If we have a way of resetting "queue.mQuiting" then we can continue using it as normal, - // coming back to this method to run the messages. + // Once #quit() has been called, the looper is not functional any more (it used to be, + // but now it SIGSEGV's if it's used again). + // It won't accept creating a new looper for this thread and switching to it... + // ...unless we can trick it into throwing out the old looper and believing it hasn't + // been initialized before. MessageQueue queue = Looper.myQueue(); try { - // However there is no way of doing it externally, and mQuiting is private. + // However there is no way of doing it externally, and the static ThreadLocal + // field into which it's stored is private. // So... get out the big guns. - java.lang.reflect.Field f = MessageQueue.class.getDeclaredField("mQuiting"); - f.setAccessible(true); // What do you mean "private"? - f.setBoolean(queue, false); + java.lang.reflect.Field f = Looper.class.getDeclaredField("sThreadLocal"); + f.setAccessible(true); // private lolwut + final ThreadLocal<Looper> a = (ThreadLocal<Looper>) f.get(looper); + a.set(null); + looper.prepare(); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { |