diff options
78 files changed, 2011 insertions, 1146 deletions
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml index 1ebe4d33a..92de687a6 100644 --- a/java/res/values-af/strings.xml +++ b/java/res/values-af/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Sleutelopspringer-wagperiode"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Geen wagperiode nie"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Verstek"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms."</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms."</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Stel kontakname voor"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Gebruik name van kontakte vir voorstelle en korreksies"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dubbelspasie-punt"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Bruikbaarheidstudie-modus"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Sleuteldruk se vibrasie-tydsduurinstellings"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Sleuteldruk se klankvolume-instellings"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Lees eksterne woordeboeklêer"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Verstek"</string> </resources> diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml index 21dab075c..c5c02daae 100644 --- a/java/res/values-am/strings.xml +++ b/java/res/values-am/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"የቁልፍ ብቅ ባይ መዘግየትን ያስወገዳል"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"የዘገየ የለም"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ነባሪ"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g>ሚሊሰከንድ"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ሚሊሰከንድ"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"የዕውቂያ ስም ጠቁም"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"ከዕውቂያዎች ለጥቆማዎች እና ማስተካከያዎች ስሞች ተጠቀም"</string> <string name="use_double_space_period" msgid="8781529969425082860">"የድርብ-ክፍተት ነጥብ"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"የተገልጋይነት ጥናት ሁነታ"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"ቁልፍ ተጫን በቅንጅቶች ወቅት ንዝረት"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"ቁልፍ ተጫን የድምጽ መጠን ቅንብሮች"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"ውጫዊ የመዝገበቃላት ፋይል አንብብ"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"ነባሪ"</string> </resources> diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml index 64c8b654f..328272782 100644 --- a/java/res/values-ar/strings.xml +++ b/java/res/values-ar/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"تأخير إزالة النافذة المنبثقة الأساسية"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"بلا تأخير"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"افتراضي"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> مللي ثانية"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> مللي ثانية"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"اقتراح أسماء جهات الاتصال"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"استخدام الأسماء من جهات الاتصال للاقتراحات والتصحيحات"</string> <string name="use_double_space_period" msgid="8781529969425082860">"نقطة المسافة المزدوجة"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"وضع سهولة الاستخدام"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"إعدادات مدة اهتزاز الضغط على المفاتيح"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"إعدادات مستوى صوت الضغط على المفاتيح"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"قراءة ملف قاموس خارجي"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"الافتراضية"</string> </resources> diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml index f5d81ea40..ad9fb77f0 100644 --- a/java/res/values-be/strings.xml +++ b/java/res/values-be/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Затрым. скр. падк. клав."</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Няма затрымкі"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Па змаўчанні"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> мс"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> мс"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Прапан. імёны кантактаў"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Выкарыстоўваць імёны са спісу кантактаў для прапаноў і выпраўл."</string> <string name="use_double_space_period" msgid="8781529969425082860">"Падвойны iнтэрвал"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Рэжым даследвання выкарыстальнасці"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Налады працягласцi вiбрацыi пры нацiску"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Налады гучнасцi пры нацiску"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Чытанне знешняга файла слоўніка"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Па змаўчанні"</string> </resources> diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml index abffe8f03..588e0760e 100644 --- a/java/res/values-bg/strings.xml +++ b/java/res/values-bg/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Отхвърляне на подсказката"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без задържане"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"По подразбиране"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> милисек"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> милисек"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Предложения за контакти"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Използване на имена от „Контакти“ за предложения и поправки"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Точка чрез двоен интервал"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Режим за изучаване на използваемостта"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Настройки за продължителност на вибрирането при натискане на клавиш"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Настройки за силата на звука при натискане на клавиш"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Четене на файл за външен речник"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Стандартни"</string> </resources> diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml index e369bda43..796374c69 100644 --- a/java/res/values-ca/strings.xml +++ b/java/res/values-ca/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Retard en ampliar tecla"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sense retard"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predeterminat"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Suggereix noms de contactes"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilitza els noms de contactes per fer suggeriments i correccions"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punt amb doble espai"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Mode d\'estudi d\'usabilitat"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Configuració de durada de vibracions en prémer tecles"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Configuració del volum de so en prémer tecles"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Lectura d\'un fitxer de diccionari extern"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Predeterminat"</string> </resources> diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml index 065ddf1d8..331681971 100644 --- a/java/res/values-cs/strings.xml +++ b/java/res/values-cs/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Prodleva vysk. okna klávesnice"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez prodlevy"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Výchozí"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Navrhovat jména kontaktů"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Použít jména ze seznamu kontaktů k návrhům a opravám"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Tečka dvojitým mezerníkem"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Režim studie použitelnosti"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Délka vibrace při stisku klávesy"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Hlasitost při stisknutí klávesy"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Číst soubor externího slovníku"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Výchozí"</string> </resources> diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml index 5adaf40dc..8a93ba9b1 100644 --- a/java/res/values-da/strings.xml +++ b/java/res/values-da/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Forsink. afvis. af taste-pop op"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Ingen forsink."</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Foreslå navne på kontakter"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Brug navne fra Kontaktpersoner til forslag og rettelser"</string> <string name="use_double_space_period" msgid="8781529969425082860">"To mellemrum for punktum"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Tilstand for brugsstudie"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Indstillinger for varighed af vibration ved tastetryk"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Indstillinger for lydstyrke ved tastetryk"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Læs ekstern ordbogsfil"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Standard"</string> </resources> diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml index 3739dbf02..1a0a01788 100644 --- a/java/res/values-de/strings.xml +++ b/java/res/values-de/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Tasten-Pop-up"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Keine Verzögerung"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Kontakte vorschlagen"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Namen aus \"Kontakte\" als Vorschläge und Korrekturmöglichkeiten anzeigen"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punkt plus Leerzeichen"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Studie zur Benutzerfreundlichkeit"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Vibrationsdauer bei Tastendruck"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Tonlautstärke bei Tastendruck"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Externe Wörterbuchdatei lesen"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Standard"</string> </resources> diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml index 0c0859602..3ac4e4719 100644 --- a/java/res/values-el/strings.xml +++ b/java/res/values-el/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Χρόνος εξαφ. αναδ. παραθ."</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Χωρίς καθυστέρ."</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Προεπιλογή"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Πρόταση ονομάτων επαφών"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Χρησιμοποιήστε ονόματα από τις Επαφές για προτάσεις και διορθ."</string> <string name="use_double_space_period" msgid="8781529969425082860">"Τελεία με διπλό πάτημα πλήκτρ.διαστ."</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Λειτουργία μελέτης χρηστικότητας"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Ρυθμίσεις διάρκειας δόνησης κατά το πάτημα πλήκτρων"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Ρυθμίσεις έντασης ήχου κατά το πάτημα πλήκτρων"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Ανάγνωση εξωτερικού αρχείου λεξικού"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Προεπιλογή"</string> </resources> diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml index 4795df24c..df3b238d9 100644 --- a/java/res/values-en-rGB/strings.xml +++ b/java/res/values-en-rGB/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Key pop-up dismiss delay"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"No delay"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Default"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Suggest Contact names"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Use names from Contacts for suggestions and corrections"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Double-space full stop"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Usability study mode"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Key-press vibration duration settings"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Key-press sound volume settings"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Read external dictionary file"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Default"</string> </resources> diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml index a3ce391dd..7e67f2917 100644 --- a/java/res/values-es-rUS/strings.xml +++ b/java/res/values-es-rUS/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Retraso en rechazo de alerta de tecla"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sin demora"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predeterminada"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nombres de contacto"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Usar nombres de los contactos para sugerencias y correcciones"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punto y doble espacio"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modo de estudio de usabilidad"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Duración de vibración al presionar teclas"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Volumen de sonido al presionar teclas"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Leer archivo de diccionario externo"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Predeterminado"</string> </resources> diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml index 452ed75e9..6c39ceb53 100644 --- a/java/res/values-es/strings.xml +++ b/java/res/values-es/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Retraso al ampliar tecla"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sin retraso"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predeterminado"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir contactos"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizar nombres de contactos para sugerencias y correcciones"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punto y espacio"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modo estudio de usabilidad"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Duración de la vibración al pulsar tecla"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Volumen sonido al pulsar tecla"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Leer archivo de diccionario externo"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Predeterminado"</string> </resources> diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml index 48ce7f61a..1d2b02992 100644 --- a/java/res/values-et/strings.xml +++ b/java/res/values-et/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Hüpiku loobumisviivitus"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Viivituseta"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Vaikeseade"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Soovita kontaktkirjeid"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Kasuta soovitusteks ja parandusteks nimesid kontaktiloendist"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punkt tühikuklahviga"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Kasutatavuse uurimisrežiim"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Klahvivajutuse vibratsiooni kestuse seaded"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Klahvivajutuse helitugevuse seaded"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Välise sõnastikufaili lugemine"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Vaikeväärtus"</string> </resources> diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml index a40fb34ae..f9a3e2eae 100644 --- a/java/res/values-fa/strings.xml +++ b/java/res/values-fa/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"تأخیر در رد کردن کلید نمایشی"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"بدون تأخیر"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"پیشفرض"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g>میلی ثانیه"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> میلیثانیه"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"پیشنهاد نامهای مخاطب"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"برای پیشنهاد و تصحیح از نام مخاطبین استفاده شود"</string> <string name="use_double_space_period" msgid="8781529969425082860">"نقطه با دو فاصله"</string> @@ -150,4 +150,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"حالت بررسی قابلیت استفاده"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"تنظیمات مدت زمان لرزش فشار کلید"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"تنظیمات میزان صدای فشار کلید"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"خواندن فایل فرهنگ لغت خارجی"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"پیشفرض"</string> </resources> diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml index 1b87ae8c2..24f06e2a3 100644 --- a/java/res/values-fi/strings.xml +++ b/java/res/values-fi/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Näppäimen hylkäysviive"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Ei viivettä"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Oletus"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Ehdota yhteystietojen nimiä"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Käytä yhteystietojen nimiä ehdotuksissa ja korjauksissa"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Kaksoisvälilyönti = piste"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Käytettävyystutkimustila"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Näppäimenpainalluksen värinän kestoasetukset"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Näppäimenpainalluksen äänenvoimakkuusasetukset"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Lue ulkoista sanakirjatiedostoa"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Oletusarvot"</string> </resources> diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml index 6471db044..8e868886d 100644 --- a/java/res/values-fr/strings.xml +++ b/java/res/values-fr/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Masquer touche agrandie"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sans délai"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Par défaut"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Proposer noms de contacts"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utiliser des noms de contacts pour les suggestions et corrections"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Point et espace"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Mode d\'étude de l\'utilisabilité"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Durée de vibration à chaque pression"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Volume sonore à chaque pression"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Lire un fichier de dictionnaire externe"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Par défaut"</string> </resources> diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml index 1333f0f04..44ea37fe4 100644 --- a/java/res/values-hi/strings.xml +++ b/java/res/values-hi/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"कुंजी पॉपअप खारिज़ विलंब"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"कोई विलंब नहीं"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"डिफ़ॉल्ट"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> मिलीसेकंड"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> मिलीसेकंड"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"संपर्क नाम सुझाएं"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"सुझाव और सुधार के लिए संपर्क से नामों का उपयोग करें"</string> <string name="use_double_space_period" msgid="8781529969425082860">"दोहरे स्पेस वाला पीरियड"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"उपयोगिता अध्ययन मोड"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"कुंजी-स्पर्श कंपन अवधि सेटिंग"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"कुंजी-स्पर्श ध्वनि वॉल्यूम सेटिंग"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"बाहरी डिक्शनरी फ़ाइल पढ़ें"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"डिफ़ॉल्ट"</string> </resources> diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml index fd627c343..f8db8c926 100644 --- a/java/res/values-hr/strings.xml +++ b/java/res/values-hr/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Odgoda prikaza tipki"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez odgode"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Zadano"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Predlaži imena kontakata"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Upotreba imena iz Kontakata za prijedloge i ispravke"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Točka s dva razmaka"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Način studije upotrebljivosti"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Postavke trajanja vibracije kod pritiska tipke"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Postavke glasnoće zvuka kod pritiska tipke"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Čitanje datoteke vanjskog rječnika"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Zadano"</string> </resources> diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml index c58bb6049..2d938472d 100644 --- a/java/res/values-hu/strings.xml +++ b/java/res/values-hu/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Gombeltüntetés késése"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Nincs késés"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Alapbeállítás"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Javasolt névjegyek"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"A névjegyek használata a javaslatokhoz és javításokhoz"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dupla szóköz: pont"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Használhatósági teszt"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Gombnyomás rezgési időtartamának beállításai"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Gombnyomás hangerejének beállításai"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Külső szótárfájl olvasása"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Alapértelmezett"</string> </resources> diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml index c24c910ff..b2d46654e 100644 --- a/java/res/values-in/strings.xml +++ b/java/res/values-in/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Tundaan singkir munculan kunci"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Tanpa penundaan"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Default"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> md"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> md"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Sarankan nama Kontak"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Menggunakan nama dari Kontak untuk saran dan koreksi"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Titik spasi ganda"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Mode studi daya guna"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Setelan durasi getaran saat tombol ditekan"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Setelan volume suara saat tombol ditekan"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Membaca file kamus eksternal"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Default"</string> </resources> diff --git a/java/res/values-is/strings.xml b/java/res/values-is/strings.xml index 016a1d1e5..c5d45b9b3 100644 --- a/java/res/values-is/strings.xml +++ b/java/res/values-is/strings.xml @@ -64,7 +64,7 @@ <skip /> <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) --> <skip /> - <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <!-- no translation found for abbreviation_unit_milliseconds (8700286094028323363) --> <skip /> <!-- no translation found for use_contacts_dict (4435317977804180815) --> <skip /> @@ -267,4 +267,16 @@ <skip /> <!-- no translation found for prefs_keypress_sound_volume_settings (5875933757082305040) --> <skip /> + <!-- no translation found for prefs_read_external_dictionary (2588931418575013067) --> + <skip /> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <!-- no translation found for button_default (3988017840431881491) --> + <skip /> </resources> diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml index 98dc467d8..704cc1481 100644 --- a/java/res/values-it/strings.xml +++ b/java/res/values-it/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Ritardo eliminaz. popup tasto"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Nessun ritardo"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predefinito"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Suggerisci nomi di contatti"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizza nomi di Contatti per suggerimenti e correzioni"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Doppio spazio per punto"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modalità Studio sull\'usabilità"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Durata vibrazione alla pressione tasto"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Volume audio alla pressione di un tasto"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Leggi file dizionario esterno"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Predefinito"</string> </resources> diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml index 6f642c764..6775986bf 100644 --- a/java/res/values-iw/strings.xml +++ b/java/res/values-iw/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"עיכוב סגירת חלון קופץ של מקש"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"ללא עיכוב"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ברירת מחדל"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> אלפ\' שניה"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> אלפ\' שניה"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"הצע שמות של אנשי קשר"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"השתמש בשמות מרשימת אנשי הקשר עבור הצעות ותיקונים"</string> <string name="use_double_space_period" msgid="8781529969425082860">"רווח כפול לנקודה"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"מצב מחקר שימושיות"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"הגדרות משך רטט בלחיצה על מקש"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"הגדרות עוצמת קול בלחיצה על מקש"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"קריאה של קובץ מילון חיצוני"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"ברירת מחדל"</string> </resources> diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml index df9c05426..17e32e41a 100644 --- a/java/res/values-ja/strings.xml +++ b/java/res/values-ja/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"キーのポップアップ時間"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"すぐに消去"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"デフォルト"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g>ミリ秒"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ミリ秒"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"候補の連絡先名を表示"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"連絡先の名前を使用して候補表示や自動修正を行います"</string> <string name="use_double_space_period" msgid="8781529969425082860">"ダブルスペースピリオド"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"使いやすさの研究モード"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"キー操作バイブの振動時間の設定"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"キー操作音の音量設定"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"外部辞書ファイルの読み取り"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"デフォルト"</string> </resources> diff --git a/java/res/values-ka/strings.xml b/java/res/values-ka/strings.xml index b9ffbf6de..10d587a0e 100644 --- a/java/res/values-ka/strings.xml +++ b/java/res/values-ka/strings.xml @@ -64,7 +64,7 @@ <skip /> <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) --> <skip /> - <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <!-- no translation found for abbreviation_unit_milliseconds (8700286094028323363) --> <skip /> <!-- no translation found for use_contacts_dict (4435317977804180815) --> <skip /> @@ -267,4 +267,16 @@ <skip /> <!-- no translation found for prefs_keypress_sound_volume_settings (5875933757082305040) --> <skip /> + <!-- no translation found for prefs_read_external_dictionary (2588931418575013067) --> + <skip /> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <!-- no translation found for button_default (3988017840431881491) --> + <skip /> </resources> diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml index 1f2a833e3..c58d73c8f 100644 --- a/java/res/values-ko/strings.xml +++ b/java/res/values-ko/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"키 팝업 해제 지연"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"지연 없음"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"기본값"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"주소록 이름 활용"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"추천 및 수정에 주소록의 이름 사용"</string> <string name="use_double_space_period" msgid="8781529969425082860">"더블스페이스 마침표"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"가용성 연구 모드"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"키를 누를 때 진동 시간 설정"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"키를 누를 때 효과음 설정"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"외부 사전 파일 읽기"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"기본값"</string> </resources> diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml index bb295c982..3e58791ec 100644 --- a/java/res/values-lt/strings.xml +++ b/java/res/values-lt/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Pagr. išš. l. atsis. d."</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Be delsos"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Numatytasis"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Siūlyti kontaktų vardus"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Siūlant ir taisant naudoti vardus iš „Kontaktų“"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Tšk. ir tarp. pal. dukart"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Tinkamumo tyrimo režimas"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Vibracijos paspaudus mygtuką trukmės nustatymai"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Garso paspaudus mygtuką garsumo nustatymai"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Skaityti išorinį žodyno failą"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Numatytieji"</string> </resources> diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml index 4b55226d7..95bed36b1 100644 --- a/java/res/values-lv/strings.xml +++ b/java/res/values-lv/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Taust. uzn. loga noraid. aizk."</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez aizkaves"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Noklusējums"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Ieteikt kontaktp. vārdus"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Izmantot kontaktpersonu vārdus kā ieteikumus un labojumus"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dubultpiesk. = punkts"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Lietojamības izpētes režīms"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Taustiņu nospiešanas vibrācijas ilguma iestatījumi"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Taustiņu nospiešanas skaņas skaļuma iestatījumi"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Ārējās vārdnīcas faila nolasīšana"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Noklusējums"</string> </resources> diff --git a/java/res/values-mk/strings.xml b/java/res/values-mk/strings.xml index 7758dbbe3..3b21023f9 100644 --- a/java/res/values-mk/strings.xml +++ b/java/res/values-mk/strings.xml @@ -64,7 +64,7 @@ <skip /> <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) --> <skip /> - <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <!-- no translation found for abbreviation_unit_milliseconds (8700286094028323363) --> <skip /> <!-- no translation found for use_contacts_dict (4435317977804180815) --> <skip /> @@ -267,4 +267,16 @@ <skip /> <!-- no translation found for prefs_keypress_sound_volume_settings (5875933757082305040) --> <skip /> + <!-- no translation found for prefs_read_external_dictionary (2588931418575013067) --> + <skip /> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <!-- no translation found for button_default (3988017840431881491) --> + <skip /> </resources> diff --git a/java/res/values-mn/strings.xml b/java/res/values-mn/strings.xml index 4d38079aa..3b8f21bc3 100644 --- a/java/res/values-mn/strings.xml +++ b/java/res/values-mn/strings.xml @@ -64,7 +64,7 @@ <skip /> <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) --> <skip /> - <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <!-- no translation found for abbreviation_unit_milliseconds (8700286094028323363) --> <skip /> <!-- no translation found for use_contacts_dict (4435317977804180815) --> <skip /> @@ -267,4 +267,16 @@ <skip /> <!-- no translation found for prefs_keypress_sound_volume_settings (5875933757082305040) --> <skip /> + <!-- no translation found for prefs_read_external_dictionary (2588931418575013067) --> + <skip /> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <!-- no translation found for button_default (3988017840431881491) --> + <skip /> </resources> diff --git a/java/res/values-ms/strings.xml b/java/res/values-ms/strings.xml index 0e03b9abe..fa2297e11 100644 --- a/java/res/values-ms/strings.xml +++ b/java/res/values-ms/strings.xml @@ -42,7 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Pop tmbl knci ketpkn lengah"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Tiada lengah"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Lalai"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string> + <!-- no translation found for abbreviation_unit_milliseconds (8700286094028323363) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Cadangkan nama Kenalan"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Menggunakan nama daripada Kenalan untuk cadangan dan pembetulan"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Titik ruang berganda"</string> @@ -146,4 +147,15 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Mod kajian kebolehgunaan"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Tetapan tempoh getaran tekan kekunci"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Tetapan kelantangan bunyi tekanan kekunci"</string> + <!-- no translation found for prefs_read_external_dictionary (2588931418575013067) --> + <skip /> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Lalai"</string> </resources> diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml index 4232e4a4b..646f1af5e 100644 --- a/java/res/values-nb/strings.xml +++ b/java/res/values-nb/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Tregt tastevindu"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"U/ forsinkelse"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Foreslå kontaktnavn"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Bruk navn fra Kontakter til forslag og korrigeringer"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punktum ved doble mellomrom"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Bruksstudiemodus"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Innstillinger for vibrasjonsvarighet ved tastetrykk"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Innstillinger for lydstyrke ved tastetrykk"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Les en ekstern ordlistefil"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Standard"</string> </resources> diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml index b2d60a7bd..5b236dc30 100644 --- a/java/res/values-nl/strings.xml +++ b/java/res/values-nl/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Afwijz.vertr. toetspop-up"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Geen vertraging"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standaard"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Contactnamen suggereren"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Namen uit Contacten gebruiken voor suggesties en correcties"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dubbeltik is punt, spatie"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modus voor gebruiksvriendelijkheidsonderzoek"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Instellingen voor trillingsduur bij druk op een toets"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Instellingen voor geluidsvolume bij druk op een toets"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Extern woordenboekbestand lezen"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Standaard"</string> </resources> diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml index 370eeed30..893de3812 100644 --- a/java/res/values-pl/strings.xml +++ b/java/res/values-pl/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Opóźnienie znikania klawiszy"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez opóźnienia"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Wartość domyślna"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Proponuj osoby z kontaktów"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"W propozycjach i poprawkach użyj nazwisk z kontaktów"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Szybka kropka ze spacją"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Tryb badania przydatności"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Czas trwania wibracji przy naciśnięciu"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Głośność dźwięku przy naciśnięciu"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Odczyt zewnętrznego pliku słownika"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Domyślne"</string> </resources> diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml index f15559784..84c0ce590 100644 --- a/java/res/values-pt-rPT/strings.xml +++ b/java/res/values-pt-rPT/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Atraso p/ ignorar pop-up"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sem atraso"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predefinido"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nomes de Contactos"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizar nomes dos Contactos para sugestões e correções"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Ponto de espaço duplo"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modo de estudo da capacidade de utilização"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Definições de duração da vibração ao premir as teclas"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Definições de volume de som ao premir as teclas"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Ler ficheiro de dicionário externo"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Predefinido"</string> </resources> diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml index 12e964885..80d917148 100644 --- a/java/res/values-pt/strings.xml +++ b/java/res/values-pt/strings.xml @@ -42,7 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Dispens. atraso chave princ."</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sem atraso"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Padrão"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <!-- no translation found for abbreviation_unit_milliseconds (8700286094028323363) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nomes de contato"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Usar nomes dos Contatos para sugestões e correções"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Duplo espaço p/ ponto"</string> @@ -146,4 +147,15 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modo de estudo de utilização"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Configurações de duração da vibração ao tocar a tecla"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Config. volume ao tocar a tecla"</string> + <!-- no translation found for prefs_read_external_dictionary (2588931418575013067) --> + <skip /> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Padrão"</string> </resources> diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml index 90d7357c3..879174b38 100644 --- a/java/res/values-rm/strings.xml +++ b/java/res/values-rm/strings.xml @@ -61,7 +61,7 @@ <skip /> <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) --> <skip /> - <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <!-- no translation found for abbreviation_unit_milliseconds (8700286094028323363) --> <skip /> <!-- no translation found for use_contacts_dict (4435317977804180815) --> <skip /> @@ -259,4 +259,16 @@ <skip /> <!-- no translation found for prefs_keypress_sound_volume_settings (5875933757082305040) --> <skip /> + <!-- no translation found for prefs_read_external_dictionary (2588931418575013067) --> + <skip /> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <!-- no translation found for button_default (3988017840431881491) --> + <skip /> </resources> diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml index 50adaddd7..1484d4a52 100644 --- a/java/res/values-ro/strings.xml +++ b/java/res/values-ro/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Înt. înch. pop-up esenţ."</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Fără întârziere"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Prestabilit"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> msec."</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> msec."</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugeraţi nume din Agendă"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizaţi numele din Agendă pentru sugestii şi corecţii"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Inserează punct spațiu"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modul Studiu privind utilizarea"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Setări pentru durata vibrării la apăsarea tastei"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Setări pentru volumul sunetului la apăsarea tastei"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Citiți fișierul de dicționar extern"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Prestabilit"</string> </resources> diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml index e92a2f8f1..c15695bdd 100644 --- a/java/res/values-ru/strings.xml +++ b/java/res/values-ru/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Задержка закрытия"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без задержки"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"По умолчанию"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> мс"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> мс"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Подсказывать имена"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Подсказывать исправления на основе имен из списка контактов"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Точка с пробелом"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Режим проверки удобства использования"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Настройки вибросигнала при нажатии клавиш"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Настройки громкости звука при нажатии клавиш"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Считывать данные из внешнего словаря"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"По умолчанию"</string> </resources> diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml index fd84a7f0d..101f47b16 100644 --- a/java/res/values-sk/strings.xml +++ b/java/res/values-sk/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Onesk. zrušenia kľúč. kon. okna"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez oneskorenia"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predvolená"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Navrhnúť mená kontaktov"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Používať mená z Kontaktov na návrhy a opravy"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Bodka s medzerou"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Režim štúdie použiteľnosti"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Nastavenia trvania vibrovania pri stlačení klávesu"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Nastavenia hlasitosti zvuku pri stlačení klávesu"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Čítať súbor externého slovníka"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Predvolené"</string> </resources> diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml index 9da540104..698443c30 100644 --- a/java/res/values-sl/strings.xml +++ b/java/res/values-sl/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Trajanje povečanja tipke"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Brez zakasnitve"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Privzeto"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Predlagaj imena stikov"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Uporaba imen iz stikov za predloge in popravke"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dva presl. za vnos pike"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Način za preučevanje uporabnosti"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Nastavitve za trajanje vibriranja ob pritisku tipke"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Nastavitve za glasnost zvoka ob pritisku tipke"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Branje zunanje datoteke slovarja"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Privzeto"</string> </resources> diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml index ad0029efb..58708b09d 100644 --- a/java/res/values-sr/strings.xml +++ b/java/res/values-sr/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Одложи одбац. иск. прозора тастера"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без одлагања"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Подразумевано"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Предложи имена контаката"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Користи имена из Контаката за предлоге и исправке"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Тачка и размак"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Режим за студију могућности коришћења"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Подешавања трајања вибрације при притиску на тастере"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Подешавања јачине звука при притиску на тастере"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Читање датотеке спољног речника"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Подразумевано"</string> </resources> diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml index 403efcf3f..ef544a6ca 100644 --- a/java/res/values-sv/strings.xml +++ b/java/res/values-sv/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Ta bort popup-fördröjning"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Fördröj inte"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> millisek."</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> millisek."</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Föreslå kontaktnamn"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Använd namn från Kontakter för förslag och korrigeringar"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dubbelt blanksteg = punkt"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Läge för studie av användbarhet"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Inställningar för vibrationslängd vid knapptryck"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Volyminställningar för knappljud"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Läs extern ordboksfil"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Standard"</string> </resources> diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml index 7202181e7..4bbe9c073 100644 --- a/java/res/values-sw/strings.xml +++ b/java/res/values-sw/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Kuchelewesha kutupa kitufe ibukizi"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Hakuna kuchelewa"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Chaguo-msingi"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"Millisekunde <xliff:g id="MILLISECONDS">%s</xliff:g>"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"Millisekunde <xliff:g id="MILLISECONDS">%s</xliff:g>"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Pendekeza majini ya Anwani"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Tumia majina kutoka kwa Anwani kwa mapendekezo na marekebisho"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Kitone baada ya nafasi mbili"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modi ya uchunguzi wa utumizi"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Bonyeza mipangilio ya kipindi cha mtetemo"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Bonyeza mipangilio ya nguvu za sauti"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Soma faili ya nje ya kamusi"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Chaguo-msingi"</string> </resources> diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml index e42c53bef..a70500e60 100644 --- a/java/res/values-th/strings.xml +++ b/java/res/values-th/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"หน่วงเวลาก่อนปิดป๊อปอัพหลัก"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"ไม่มีการหน่วงเวลา"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ค่าเริ่มต้น"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> มิลลิวิ"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> มิลลิวิ"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"แนะนำชื่อผู้ติดต่อ"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"ใช้ชื่อจากรายชื่อติดต่อสำหรับคำแนะนำและการแก้ไข"</string> <string name="use_double_space_period" msgid="8781529969425082860">"แตะ Space สองครั้งแทรกจุด"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"โหมดศึกษาประโยชน์ในการใช้งาน"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"การตั้งค่าระยะเวลาการสั่นเมื่อกดแป้นพิมพ์"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"การตั้งค่าระดับเสียงเมื่อกดแป้นพิมพ์"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"อ่านไฟล์พจนานุกรมภายนอก"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"ค่าเริ่มต้น"</string> </resources> diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml index 530dc5ddf..3c93dd520 100644 --- a/java/res/values-tl/strings.xml +++ b/java/res/values-tl/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Balewala antala key popup"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Walang antala"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Default"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Mungkahi pangalan Contact"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Gamitin pangalan mula Mga Contact sa mga mungkahi\'t pagwawasto"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Double-space period"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Study mode ng pagiging kapaki-pakinabang"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Mga setting ng tagal ng vibration ng keypress"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Mga setting ng volume ng tunog ng keypress"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Magbasa ng panlabas na file ng diksyunaryo"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Default"</string> </resources> diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml index e98a31e73..f2c5f2449 100644 --- a/java/res/values-tr/strings.xml +++ b/java/res/values-tr/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Tuş popup\'ının kapatılmasını geciktirme"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Gecikme yok"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Varsayılan"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Kişi Adları öner"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Öneri ve düzeltmeler için Kişiler\'deki adları kullan"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Çift boşlukla nokta ekleme"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Kullanılabilirlik çalışması modu"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Tuşa basma titreşim süresi ayarları"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Tuşa basma ses düzeyi ayarları"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Harici sözlük dosyasını oku"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Varsayılan"</string> </resources> diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml index f6688c2e2..f2de1bee6 100644 --- a/java/res/values-uk/strings.xml +++ b/java/res/values-uk/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Затримка клавіши закриття"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без затримки"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"За умовчанням"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> мс"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> мс"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Пропон. імена контактів"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Використ. імена зі списку контактів для пропозицій і виправлень"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Крапка подвійним пробілом"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Режим вивчення зручності у використанні"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Налаштування тривалості вібрації під час натискання клавіші"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Налаштування гучності звуку під час натискання клавіші"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Читати файл зовнішнього словника"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"За умовчанням"</string> </resources> diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml index efb1291c6..7ba032ffb 100644 --- a/java/res/values-vi/strings.xml +++ b/java/res/values-vi/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Loại bỏ hiển thị phím trễ"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Không có tgian trễ"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Mặc định"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> mili giây"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> mili giây"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Đề xuất tên liên hệ"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Sử dụng tên từ Danh bạ cho các đề xuất và chỉnh sửa"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dấu cách đôi"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Chế độ nghiên cứu tính khả dụng"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Cài đặt thời gian rung khi nhấn phím"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Cài đặt âm lượng khi nhấn phím"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Đọc tệp từ điển bên ngoài"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Mặc định"</string> </resources> diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml index 922fcc6e2..b4ead85f2 100644 --- a/java/res/values-zh-rCN/strings.xml +++ b/java/res/values-zh-rCN/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"弹出字符隐藏延迟"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"无延迟"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"默认"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g>毫秒"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>毫秒"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"联系人姓名建议"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"使用联系人中的姓名提供建议和更正"</string> <string name="use_double_space_period" msgid="8781529969425082860">"双击空格插入句号"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"可用性研究模式"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"按键振动持续时间设置"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"按键音量设置"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"读取外部字典文件"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"默认"</string> </resources> diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml index 1d1627711..8d34ba21f 100644 --- a/java/res/values-zh-rTW/strings.xml +++ b/java/res/values-zh-rTW/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"關閉彈出式鍵盤的延遲時間"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"不延遲"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"預設"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> 毫秒"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> 毫秒"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"建議聯絡人名稱"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"根據「聯絡人」名稱提供建議與修正"</string> <string name="use_double_space_period" msgid="8781529969425082860">"輕按兩下空格鍵即插入句號"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"使用習慣學習模式"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"按鍵震動持續時間設定"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"按鍵音量設定"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"讀取外部字典檔案"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"預設"</string> </resources> diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml index 491451327..660dab18d 100644 --- a/java/res/values-zu/strings.xml +++ b/java/res/values-zu/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Ukuvela kokhiye cashisa ukulibazisa"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Cha ukulibazisa"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Okuzenzakalelayo"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Sikisela amagama Othintana nabo"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Amagama abasebenzisi kusuka Kothintana nabo bokusikisela nokulungisa"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Isikhathi se-Double-space"</string> @@ -146,4 +146,14 @@ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Imodi yesitadi yokusebenziseka"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Izilungiselelo ze-keypress vibration duraton"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Izilungiselelo zevolumu yomsindo wekeypress"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Funda ifayela elangaphandle lesichazamazwi"</string> + <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) --> + <skip /> + <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) --> + <skip /> + <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) --> + <skip /> + <!-- no translation found for error (8940763624668513648) --> + <skip /> + <string name="button_default" msgid="3988017840431881491">"Okuzenzakalelayo"</string> </resources> diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 670564c39..4dab50fd8 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -169,11 +169,11 @@ public class KeyboardView extends View { public void setKeyboard(final Keyboard keyboard) { mKeyboard = keyboard; LatinImeLogger.onSetKeyboard(keyboard); - requestLayout(); - invalidateAllKeys(); final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; mKeyDrawParams.updateParams(keyHeight, mKeyVisualAttributes); mKeyDrawParams.updateParams(keyHeight, keyboard.mKeyVisualAttributes); + invalidateAllKeys(); + requestLayout(); } /** @@ -638,7 +638,6 @@ public class KeyboardView extends View { public void closing() { mInvalidateAllKeys = true; mKeyboard = null; - requestLayout(); } @Override diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index c0a8f1f5e..cbd4f53a8 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -175,9 +175,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack // More keys keyboard private final Paint mBackgroundDimAlphaPaint = new Paint(); private boolean mNeedsToDimEntireKeyboard; - private final WeakHashMap<Key, MoreKeysPanel> mMoreKeysPanelCache = - new WeakHashMap<Key, MoreKeysPanel>(); - private final int mMoreKeysLayout; + private final View mMoreKeysKeyboardContainer; + private final WeakHashMap<Key, Keyboard> mMoreKeysKeyboardCache = + CollectionUtils.newWeakHashMap(); private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint; // More keys panel (used by both more keys keyboard and more suggestions view) // TODO: Consider extending to support multiple more keys panels @@ -243,7 +243,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack break; case MSG_LONGPRESS_KEY: if (tracker != null) { - keyboardView.openMoreKeysKeyboardIfRequired(tracker.getKey(), tracker); + keyboardView.onLongPress(tracker); } else { KeyboardSwitcher.getInstance().onLongPressTimeout(msg.arg1); } @@ -544,7 +544,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack if (mKeyPreviewLayoutId == 0) { mShowKeyPreviewPopup = false; } - mMoreKeysLayout = mainKeyboardViewAttr.getResourceId( + final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId( R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0); mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean( R.styleable.MainKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false); @@ -566,6 +566,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack mPreviewPlacerView.addPreview(mSlidingKeyInputPreview); mainKeyboardViewAttr.recycle(); + mMoreKeysKeyboardContainer = LayoutInflater.from(getContext()) + .inflate(moreKeysKeyboardLayoutId, null); mLanguageOnSpacebarFadeoutAnimator = loadObjectAnimator( languageOnSpacebarFadeoutAnimatorResId, this); mAltCodeKeyWhileTypingFadeoutAnimator = loadObjectAnimator( @@ -653,7 +655,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection); PointerTracker.setKeyDetector(mKeyDetector); mTouchScreenRegulator.setKeyboardGeometry(keyboard.mOccupiedWidth); - mMoreKeysPanelCache.clear(); + mMoreKeysKeyboardCache.clear(); mSpaceKey = keyboard.getKey(Constants.CODE_SPACE); mSpaceIcon = (mSpaceKey != null) @@ -942,123 +944,105 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } } - private boolean openMoreKeysKeyboardIfRequired(final Key parentKey, - final PointerTracker tracker) { - // Check if we have a popup layout specified first. - if (mMoreKeysLayout == 0) { - return false; - } - - // Check if we are already displaying popup panel. - if (mMoreKeysPanel != null) { - return false; - } - if (parentKey == null) { - return false; - } - return onLongPress(parentKey, tracker); - } - - private MoreKeysPanel onCreateMoreKeysPanel(final Key parentKey) { - if (parentKey.mMoreKeys == null) { + private MoreKeysPanel onCreateMoreKeysPanel(final Key key, final Context context) { + if (key.mMoreKeys == null) { return null; } - - final View container = LayoutInflater.from(getContext()).inflate(mMoreKeysLayout, null); - if (container == null) { - throw new NullPointerException(); + Keyboard moreKeysKeyboard = mMoreKeysKeyboardCache.get(key); + if (moreKeysKeyboard == null) { + moreKeysKeyboard = new MoreKeysKeyboard.Builder( + context, key, this, mKeyPreviewDrawParams).build(); + mMoreKeysKeyboardCache.put(key, moreKeysKeyboard); } + final View container = mMoreKeysKeyboardContainer; final MoreKeysKeyboardView moreKeysKeyboardView = (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view); - final Keyboard moreKeysKeyboard = new MoreKeysKeyboard.Builder( - container, parentKey, this, mKeyPreviewDrawParams) - .build(); moreKeysKeyboardView.setKeyboard(moreKeysKeyboard); container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - return moreKeysKeyboardView; } /** * Called when a key is long pressed. - * @param parentKey the key that was long pressed * @param tracker the pointer tracker which pressed the parent key * @return true if the long press is handled, false otherwise. Subclasses should call the * method on the base class if the subclass doesn't wish to handle the call. */ - private boolean onLongPress(final Key parentKey, final PointerTracker tracker) { + private boolean onLongPress(final PointerTracker tracker) { + if (isShowingMoreKeysPanel()) { + return false; + } + final Key key = tracker.getKey(); + if (key == null) { + return false; + } if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.mainKeyboardView_onLongPress(); } - final int primaryCode = parentKey.mCode; - if (parentKey.hasEmbeddedMoreKey()) { - final int embeddedCode = parentKey.mMoreKeys[0].mCode; + final int code = key.mCode; + if (key.hasEmbeddedMoreKey()) { + final int embeddedCode = key.mMoreKeys[0].mCode; tracker.onLongPressed(); invokeCodeInput(embeddedCode); - invokeReleaseKey(primaryCode); - KeyboardSwitcher.getInstance().hapticAndAudioFeedback(primaryCode); + invokeReleaseKey(code); + KeyboardSwitcher.getInstance().hapticAndAudioFeedback(code); return true; } - if (primaryCode == Constants.CODE_SPACE || primaryCode == Constants.CODE_LANGUAGE_SWITCH) { + if (code == Constants.CODE_SPACE || code == Constants.CODE_LANGUAGE_SWITCH) { // Long pressing the space key invokes IME switcher dialog. if (invokeCustomRequest(LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) { tracker.onLongPressed(); - invokeReleaseKey(primaryCode); + invokeReleaseKey(code); return true; } } - return openMoreKeysPanel(parentKey, tracker); + return openMoreKeysPanel(key, tracker); } - private boolean invokeCustomRequest(final int code) { - return mKeyboardActionListener.onCustomRequest(code); + private boolean invokeCustomRequest(final int requestCode) { + return mKeyboardActionListener.onCustomRequest(requestCode); } - private void invokeCodeInput(final int primaryCode) { + private void invokeCodeInput(final int code) { mKeyboardActionListener.onCodeInput( - primaryCode, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + code, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); } - private void invokeReleaseKey(final int primaryCode) { - mKeyboardActionListener.onReleaseKey(primaryCode, false); + private void invokeReleaseKey(final int code) { + mKeyboardActionListener.onReleaseKey(code, false); } - private boolean openMoreKeysPanel(final Key parentKey, final PointerTracker tracker) { - MoreKeysPanel moreKeysPanel = mMoreKeysPanelCache.get(parentKey); + private boolean openMoreKeysPanel(final Key key, final PointerTracker tracker) { + final MoreKeysPanel moreKeysPanel = onCreateMoreKeysPanel(key, getContext()); if (moreKeysPanel == null) { - moreKeysPanel = onCreateMoreKeysPanel(parentKey); - if (moreKeysPanel == null) { - return false; - } - mMoreKeysPanelCache.put(parentKey, moreKeysPanel); + return false; } final int[] lastCoords = CoordinateUtils.newInstance(); tracker.getLastCoordinates(lastCoords); - final boolean keyPreviewEnabled = isKeyPreviewPopupEnabled() && !parentKey.noKeyPreview(); + final boolean keyPreviewEnabled = isKeyPreviewPopupEnabled() && !key.noKeyPreview(); // The more keys keyboard is usually horizontally aligned with the center of the parent key. // If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more // keys keyboard is placed at the touch point of the parent key. final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint && !keyPreviewEnabled) ? CoordinateUtils.x(lastCoords) - : parentKey.mX + parentKey.mWidth / 2; + : key.mX + key.mWidth / 2; // The more keys keyboard is usually vertically aligned with the top edge of the parent key // (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically // aligned with the bottom edge of the visible part of the key preview. // {@code mPreviewVisibleOffset} has been set appropriately in // {@link KeyboardView#showKeyPreview(PointerTracker)}. - final int pointY = parentKey.mY + mKeyPreviewDrawParams.mPreviewVisibleOffset; + final int pointY = key.mY + mKeyPreviewDrawParams.mPreviewVisibleOffset; moreKeysPanel.showMoreKeysPanel(this, this, pointX, pointY, mKeyboardActionListener); final int translatedX = moreKeysPanel.translateX(CoordinateUtils.x(lastCoords)); final int translatedY = moreKeysPanel.translateY(CoordinateUtils.y(lastCoords)); tracker.onShowMoreKeysPanel(translatedX, translatedY, moreKeysPanel); - dimEntireKeyboard(true /* dimmed */); return true; } public boolean isInSlidingKeyInput() { - if (mMoreKeysPanel != null) { + if (isShowingMoreKeysPanel()) { return true; } return PointerTracker.isAnyInSlidingKeyInput(); @@ -1069,19 +1053,17 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack if (isShowingMoreKeysPanel()) { onDismissMoreKeysPanel(); } + mPreviewPlacerView.addView(panel.getContainerView()); mMoreKeysPanel = panel; - mPreviewPlacerView.addView(mMoreKeysPanel.getContainerView()); + dimEntireKeyboard(true /* dimmed */); } public boolean isShowingMoreKeysPanel() { - return (mMoreKeysPanel != null); + return mMoreKeysPanel != null && mMoreKeysPanel.isShowingInParent(); } @Override public void onCancelMoreKeysPanel() { - if (isShowingMoreKeysPanel()) { - mMoreKeysPanel.dismissMoreKeysPanel(); - } PointerTracker.dismissAllMoreKeysPanels(); } @@ -1254,9 +1236,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack public void closing() { dismissAllKeyPreviews(); cancelAllMessages(); + onDismissMoreKeysPanel(); + mMoreKeysKeyboardCache.clear(); super.closing(); - onCancelMoreKeysPanel(); - mMoreKeysPanelCache.clear(); } /** @@ -1331,7 +1313,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack invalidateKey(mSpaceKey); } - public void dimEntireKeyboard(final boolean dimmed) { + private void dimEntireKeyboard(final boolean dimmed) { final boolean needsRedrawing = mNeedsToDimEntireKeyboard != dimmed; mNeedsToDimEntireKeyboard = dimmed; if (needsRedrawing) { diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java index 6df883e41..66c30149c 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java @@ -16,9 +16,9 @@ package com.android.inputmethod.keyboard; +import android.content.Context; import android.graphics.Paint; import android.graphics.drawable.Drawable; -import android.view.View; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams; @@ -260,15 +260,15 @@ public final class MoreKeysKeyboard extends Keyboard { /** * The builder of MoreKeysKeyboard. - * @param containerView the container of {@link MoreKeysKeyboardView}. + * @param context the context of {@link MoreKeysKeyboardView}. * @param parentKey the {@link Key} that invokes more keys keyboard. * @param parentKeyboardView the {@link KeyboardView} that contains the parentKey. * @param keyPreviewDrawParams the parameter to place key preview. */ - public Builder(final View containerView, final Key parentKey, + public Builder(final Context context, final Key parentKey, final MainKeyboardView parentKeyboardView, final KeyPreviewDrawParams keyPreviewDrawParams) { - super(containerView.getContext(), new MoreKeysKeyboardParams()); + super(context, new MoreKeysKeyboardParams()); final Keyboard parentKeyboard = parentKeyboardView.getKeyboard(); load(parentKeyboard.mMoreKeysTemplate, parentKeyboard.mId); diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java index 0d42ab2fe..9e75f8b8a 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java @@ -174,6 +174,7 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel @Override public boolean dismissMoreKeysPanel() { + super.closing(); if (mController == null) return false; return mController.onDismissMoreKeysPanel(); } diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index 29c65f19b..32cee734a 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -30,8 +30,7 @@ public final class ProximityInfo { private static final String TAG = ProximityInfo.class.getSimpleName(); private static final boolean DEBUG = false; - /** MAX_PROXIMITY_CHARS_SIZE must be the same as MAX_PROXIMITY_CHARS_SIZE_INTERNAL - * in defines.h */ + // Must be equal to MAX_PROXIMITY_CHARS_SIZE in native/jni/src/defines.h public static final int MAX_PROXIMITY_CHARS_SIZE = 16; /** Number of key widths from current touch point to search for nearest keys. */ private static final float SEARCH_DISTANCE = 1.2f; @@ -88,9 +87,13 @@ public final class ProximityInfo { final int rowSize, final int gridWidth, final int gridHeight) { final ProximityInfo spellCheckerProximityInfo = createDummyProximityInfo(); spellCheckerProximityInfo.mNativeProximityInfo = - spellCheckerProximityInfo.setProximityInfoNative("", - rowSize, gridWidth, gridHeight, gridWidth, gridHeight, - 1, proximityCharsArray, 0, null, null, null, null, null, null, null, null); + spellCheckerProximityInfo.setProximityInfoNative("" /* locale */, + gridWidth /* displayWidth */, gridHeight /* displayHeight */, + gridWidth, gridHeight, 1 /* mostCommonKeyWidth */, proximityCharsArray, + 0 /* keyCount */, null /*keyXCoordinates */, null /* keyYCoordinates */, + null /* keyWidths */, null /* keyHeights */, null /* keyCharCodes */, + null /* sweetSpotCenterXs */, null /* sweetSpotCenterYs */, + null /* sweetSpotRadii */); return spellCheckerProximityInfo; } @@ -100,11 +103,11 @@ public final class ProximityInfo { } // TODO: Stop passing proximityCharsArray - private static native long setProximityInfoNative(String locale, int maxProximityCharsSize, + private static native long setProximityInfoNative(String locale, int displayWidth, int displayHeight, int gridWidth, int gridHeight, int mostCommonKeyWidth, int[] proximityCharsArray, int keyCount, int[] keyXCoordinates, int[] keyYCoordinates, int[] keyWidths, int[] keyHeights, int[] keyCharCodes, - float[] sweetSpotCenterX, float[] sweetSpotCenterY, float[] sweetSpotRadii); + float[] sweetSpotCenterXs, float[] sweetSpotCenterYs, float[] sweetSpotRadii); private static native void releaseProximityInfoNative(long nativeProximityInfo); @@ -230,9 +233,9 @@ public final class ProximityInfo { } // TODO: Stop passing proximityCharsArray - return setProximityInfoNative(mLocaleStr, MAX_PROXIMITY_CHARS_SIZE, mKeyboardMinWidth, - mKeyboardHeight, mGridWidth, mGridHeight, mMostCommonKeyWidth, proximityCharsArray, - keyCount, keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes, + return setProximityInfoNative(mLocaleStr, mKeyboardMinWidth, mKeyboardHeight, + mGridWidth, mGridHeight, mMostCommonKeyWidth, proximityCharsArray, keyCount, + keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes, sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii); } diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 59d51b0b9..ad3163347 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -35,9 +35,9 @@ public final class BinaryDictionary extends Dictionary { public static final String DICTIONARY_PACK_AUTHORITY = "com.android.inputmethod.latin.dictionarypack"; - // Must be identical to MAX_WORD_LENGTH in native/jni/src/defines.h + // Must be equal to MAX_WORD_LENGTH in native/jni/src/defines.h private static final int MAX_WORD_LENGTH = Constants.Dictionary.MAX_WORD_LENGTH; - // Must be identical to MAX_RESULTS in native/jni/src/defines.h + // Must be equal to MAX_RESULTS in native/jni/src/defines.h private static final int MAX_RESULTS = 18; private long mNativeDict; diff --git a/java/src/com/android/inputmethod/latin/CollectionUtils.java b/java/src/com/android/inputmethod/latin/CollectionUtils.java index c75f2df5c..a8623cc63 100644 --- a/java/src/com/android/inputmethod/latin/CollectionUtils.java +++ b/java/src/com/android/inputmethod/latin/CollectionUtils.java @@ -27,6 +27,7 @@ import java.util.LinkedList; import java.util.Map; import java.util.TreeMap; import java.util.TreeSet; +import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -39,6 +40,10 @@ public final class CollectionUtils { return new HashMap<K,V>(); } + public static <K, V> WeakHashMap<K, V> newWeakHashMap() { + return new WeakHashMap<K, V>(); + } + public static <K,V> TreeMap<K,V> newTreeMap() { return new TreeMap<K,V>(); } diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java index 748900b3a..85cc55232 100644 --- a/java/src/com/android/inputmethod/latin/Constants.java +++ b/java/src/com/android/inputmethod/latin/Constants.java @@ -127,7 +127,7 @@ public final class Constants { } public static final class Dictionary { - // Must be identical to MAX_WORD_LENGTH in native/jni/src/defines.h + // Must be equal to MAX_WORD_LENGTH in native/jni/src/defines.h public static final int MAX_WORD_LENGTH = 48; private Dictionary() { diff --git a/java/src/com/android/inputmethod/latin/InputPointers.java b/java/src/com/android/inputmethod/latin/InputPointers.java index 4d6c4f356..81c833000 100644 --- a/java/src/com/android/inputmethod/latin/InputPointers.java +++ b/java/src/com/android/inputmethod/latin/InputPointers.java @@ -18,8 +18,11 @@ package com.android.inputmethod.latin; import com.android.inputmethod.annotations.UsedForTesting; +import android.util.Log; + // TODO: This class is not thread-safe. public final class InputPointers { + private static final String TAG = InputPointers.class.getSimpleName(); private final int mDefaultCapacity; private final ResizableIntArray mXCoordinates; private final ResizableIntArray mYCoordinates; @@ -126,6 +129,11 @@ public final class InputPointers { } public int[] getTimes() { + if (LatinImeLogger.sDBG) { + if (!isValidTimeStamps()) { + throw new RuntimeException("Time stamps are invalid."); + } + } return mTimes.getPrimitiveArray(); } @@ -134,4 +142,18 @@ public final class InputPointers { return "size=" + getPointerSize() + " id=" + mPointerIds + " time=" + mTimes + " x=" + mXCoordinates + " y=" + mYCoordinates; } + + private boolean isValidTimeStamps() { + final int[] times = mTimes.getPrimitiveArray(); + for (int i = 1; i < getPointerSize(); ++i) { + if (times[i] < times[i - 1]) { + // dump + for (int j = 0; j < times.length; ++j) { + Log.d(TAG, "--- (" + j + ") " + times[j]); + } + return false; + } + } + return true; + } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index a48778ab3..fc9953ac0 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -2490,7 +2490,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction private void launchSubActivity(final Class<? extends Activity> activityClass) { Intent intent = new Intent(); intent.setClass(LatinIME.this, activityClass); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED + | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); } diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java index 26a304ef8..438820d17 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java @@ -19,7 +19,6 @@ package com.android.inputmethod.latin.suggestions; import android.content.Context; import android.util.AttributeSet; -import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.MoreKeysKeyboardView; import com.android.inputmethod.latin.R; @@ -28,7 +27,6 @@ import com.android.inputmethod.latin.R; * key presses and touch movements. */ public final class MoreSuggestionsView extends MoreKeysKeyboardView { - public MoreSuggestionsView(final Context context, final AttributeSet attrs) { this(context, attrs, R.attr.moreSuggestionsViewStyle); } @@ -44,32 +42,15 @@ public final class MoreSuggestionsView extends MoreKeysKeyboardView { return pane.mOccupiedWidth / 2; } - @Override - protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { - final Keyboard keyboard = getKeyboard(); - if (keyboard != null) { - final int width = keyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight(); - final int height = keyboard.mOccupiedHeight + getPaddingTop() + getPaddingBottom(); - setMeasuredDimension(width, height); - } else { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - } - public void updateKeyboardGeometry(final int keyHeight) { mKeyDrawParams.updateParams(keyHeight, mKeyVisualAttributes); } @Override - public void onCodeInput(final int primaryCode, final int x, final int y) { - final int index = primaryCode - MoreSuggestions.SUGGESTION_CODE_BASE; + public void onCodeInput(final int code, final int x, final int y) { + final int index = code - MoreSuggestions.SUGGESTION_CODE_BASE; if (index >= 0 && index < SuggestionStripView.MAX_SUGGESTIONS) { mListener.onCustomRequest(index); } } - - @Override - public boolean isShowingInParent() { - return (getContainerView().getParent() != null); - } } diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index 92b96e754..bc51d5d62 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -676,12 +676,11 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick new MoreKeysPanel.Controller() { @Override public boolean onDismissMoreKeysPanel() { - mMainKeyboardView.dimEntireKeyboard(false /* dimmed */); return mMainKeyboardView.onDismissMoreKeysPanel(); } @Override - public void onShowMoreKeysPanel(MoreKeysPanel panel) { + public void onShowMoreKeysPanel(final MoreKeysPanel panel) { mMainKeyboardView.onShowMoreKeysPanel(panel); } @@ -728,7 +727,6 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick mMoreSuggestionsMode = MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING; mOriginX = mLastX; mOriginY = mLastY; - mMainKeyboardView.dimEntireKeyboard(true /* dimmed */); for (int i = 0; i < params.mSuggestionsCountInStrip; i++) { mWords.get(i).setPressed(false); } diff --git a/native/jni/Android.mk b/native/jni/Android.mk index f2aebd55d..3735ec07b 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -54,7 +54,9 @@ LATIN_IME_CORE_SRC_FILES := \ dictionary.cpp \ dic_traverse_wrapper.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/gesture_suggest.cpp \ diff --git a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp index d718290ad..30ca3f1b8 100644 --- a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp +++ b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp @@ -25,14 +25,14 @@ namespace latinime { static jlong latinime_Keyboard_setProximityInfo(JNIEnv *env, jclass clazz, jstring localeJStr, - jint maxProximityCharsSize, jint displayWidth, jint displayHeight, jint gridWidth, - jint gridHeight, jint mostCommonkeyWidth, jintArray proximityChars, jint keyCount, + jint displayWidth, jint displayHeight, jint gridWidth, jint gridHeight, + jint mostCommonkeyWidth, jintArray proximityChars, jint keyCount, jintArray keyXCoordinates, jintArray keyYCoordinates, jintArray keyWidths, jintArray keyHeights, jintArray keyCharCodes, jfloatArray sweetSpotCenterXs, jfloatArray sweetSpotCenterYs, jfloatArray sweetSpotRadii) { - ProximityInfo *proximityInfo = new ProximityInfo(env, localeJStr, maxProximityCharsSize, - displayWidth, displayHeight, gridWidth, gridHeight, mostCommonkeyWidth, proximityChars, - keyCount, keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes, + ProximityInfo *proximityInfo = new ProximityInfo(env, localeJStr, displayWidth, displayHeight, + gridWidth, gridHeight, mostCommonkeyWidth, proximityChars, keyCount, + keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes, sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii); return reinterpret_cast<jlong>(proximityInfo); } @@ -43,7 +43,7 @@ static void latinime_Keyboard_release(JNIEnv *env, jclass clazz, jlong proximity } static JNINativeMethod sMethods[] = { - {"setProximityInfoNative", "(Ljava/lang/String;IIIIII[II[I[I[I[I[I[F[F[F)J", + {"setProximityInfoNative", "(Ljava/lang/String;IIIII[II[I[I[I[I[I[F[F[F)J", reinterpret_cast<void *>(latinime_Keyboard_setProximityInfo)}, {"releaseProximityInfoNative", "(J)V", reinterpret_cast<void *>(latinime_Keyboard_release)} }; diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h index f5f527831..922a746b8 100644 --- a/native/jni/src/defines.h +++ b/native/jni/src/defines.h @@ -28,10 +28,13 @@ #define AK_FORCE_INLINE inline #endif // defined(FLAG_DO_PROFILE) || defined(FLAG_DBG) -// Must be identical to Constants.Dictionary.MAX_WORD_LENGTH in Java +// Must be equal to Constants.Dictionary.MAX_WORD_LENGTH in Java #define MAX_WORD_LENGTH 48 -// Must be identical to BinaryDictionary.MAX_RESULTS in Java +// Must be equal to BinaryDictionary.MAX_RESULTS in Java #define MAX_RESULTS 18 +// Must be equal to ProximityInfo.MAX_PROXIMITY_CHARS_SIZE in Java +#define MAX_PROXIMITY_CHARS_SIZE 16 +#define ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE 2 #if defined(FLAG_DO_PROFILE) || defined(FLAG_DBG) #include <android/log.h> @@ -248,6 +251,10 @@ static inline void prof_out(void) { // GCC warns about this. #define S_INT_MIN (-2147483647 - 1) // -(1 << 31) #endif + +#define M_PI_F 3.14159265f +#define MAX_PERCENTILE 100 + // Number of base-10 digits in the largest integer + 1 to leave room for a zero terminator. // As such, this is the maximum number of characters will be needed to represent an int as a // string, including the terminator; this is used as the size of a string buffer large enough to @@ -322,12 +329,6 @@ static inline void prof_out(void) { #define MAX_FREQ 255 #define MAX_BIGRAM_FREQ 15 -// This must be the same as ProximityInfo#MAX_PROXIMITY_CHARS_SIZE, currently it's 16. -#define MAX_PROXIMITY_CHARS_SIZE_INTERNAL 16 - -// This must be equal to ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE in KeyDetector.java -#define ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE 2 - // Assuming locale strings such as en_US, sr-Latn etc. #define MAX_LOCALE_STRING_LENGTH 10 @@ -392,8 +393,6 @@ static inline void prof_out(void) { template<typename T> inline T min(T a, T b) { return a < b ? a : b; } template<typename T> inline T max(T a, T b) { return a > b ? a : b; } -#define M_PI_F 3.14159265f - #define NELEMS(x) (sizeof(x) / sizeof((x)[0])) // The ratio of neutral area radius to sweet spot radius. diff --git a/native/jni/src/proximity_info.cpp b/native/jni/src/proximity_info.cpp index c563b0796..8157fe2d0 100644 --- a/native/jni/src/proximity_info.cpp +++ b/native/jni/src/proximity_info.cpp @@ -47,15 +47,14 @@ static AK_FORCE_INLINE void safeGetOrFillZeroFloatArrayRegion(JNIEnv *env, jfloa } } -ProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr, const int maxProximityCharsSize, +ProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr, const int keyboardWidth, const int keyboardHeight, const int gridWidth, const int gridHeight, const int mostCommonKeyWidth, const jintArray proximityChars, const int keyCount, const jintArray keyXCoordinates, const jintArray keyYCoordinates, const jintArray keyWidths, const jintArray keyHeights, const jintArray keyCharCodes, const jfloatArray sweetSpotCenterXs, const jfloatArray sweetSpotCenterYs, const jfloatArray sweetSpotRadii) - : MAX_PROXIMITY_CHARS_SIZE(maxProximityCharsSize), GRID_WIDTH(gridWidth), - GRID_HEIGHT(gridHeight), MOST_COMMON_KEY_WIDTH(mostCommonKeyWidth), + : GRID_WIDTH(gridWidth), GRID_HEIGHT(gridHeight), MOST_COMMON_KEY_WIDTH(mostCommonKeyWidth), MOST_COMMON_KEY_WIDTH_SQUARE(mostCommonKeyWidth * mostCommonKeyWidth), CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth), CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight), @@ -65,11 +64,17 @@ ProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr, const int ma && keyWidths && keyHeights && keyCharCodes && sweetSpotCenterXs && sweetSpotCenterYs && sweetSpotRadii), mProximityCharsArray(new int[GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE - /* proximityGridLength */]), + /* proximityCharsLength */]), mCodeToKeyMap() { - const int proximityGridLength = GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE; + /* Let's check the input array length here to make sure */ + const jsize proximityCharsLength = env->GetArrayLength(proximityChars); + if (proximityCharsLength != GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE) { + AKLOGE("Invalid proximityCharsLength: %d", proximityCharsLength); + ASSERT(false); + return; + } if (DEBUG_PROXIMITY_INFO) { - AKLOGI("Create proximity info array %d", proximityGridLength); + AKLOGI("Create proximity info array %d", proximityCharsLength); } const jsize localeCStrUtf8Length = env->GetStringUTFLength(localeJStr); if (localeCStrUtf8Length >= MAX_LOCALE_STRING_LENGTH) { @@ -78,7 +83,8 @@ ProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr, const int ma } memset(mLocaleStr, 0, sizeof(mLocaleStr)); env->GetStringUTFRegion(localeJStr, 0, env->GetStringLength(localeJStr), mLocaleStr); - safeGetOrFillZeroIntArrayRegion(env, proximityChars, proximityGridLength, mProximityCharsArray); + safeGetOrFillZeroIntArrayRegion(env, proximityChars, proximityCharsLength, + mProximityCharsArray); safeGetOrFillZeroIntArrayRegion(env, keyXCoordinates, KEY_COUNT, mKeyXCoordinates); safeGetOrFillZeroIntArrayRegion(env, keyYCoordinates, KEY_COUNT, mKeyYCoordinates); safeGetOrFillZeroIntArrayRegion(env, keyWidths, KEY_COUNT, mKeyWidths); diff --git a/native/jni/src/proximity_info.h b/native/jni/src/proximity_info.h index cd0bc32cc..6d571d7bb 100644 --- a/native/jni/src/proximity_info.h +++ b/native/jni/src/proximity_info.h @@ -28,7 +28,7 @@ class Correction; class ProximityInfo { public: - ProximityInfo(JNIEnv *env, const jstring localeJStr, const int maxProximityCharsSize, + ProximityInfo(JNIEnv *env, const jstring localeJStr, const int keyboardWidth, const int keyboardHeight, const int gridWidth, const int gridHeight, const int mostCommonKeyWidth, const jintArray proximityChars, const int keyCount, const jintArray keyXCoordinates, const jintArray keyYCoordinates, @@ -126,7 +126,6 @@ class ProximityInfo { float calculateNormalizedSquaredDistance(const int keyIndex, const int inputIndex) const; bool hasInputCoordinates() const; - const int MAX_PROXIMITY_CHARS_SIZE; const int GRID_WIDTH; const int GRID_HEIGHT; const int MOST_COMMON_KEY_WIDTH; diff --git a/native/jni/src/proximity_info_params.cpp b/native/jni/src/proximity_info_params.cpp new file mode 100644 index 000000000..5a51f62d9 --- /dev/null +++ b/native/jni/src/proximity_info_params.cpp @@ -0,0 +1,30 @@ +/* + * 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 "proximity_info_params.h" + +namespace latinime { +const int ProximityInfoParams::LOOKUP_RADIUS_PERCENTILE = 50; +const int ProximityInfoParams::FIRST_POINT_TIME_OFFSET_MILLIS = 150; +const int ProximityInfoParams::STRONG_DOUBLE_LETTER_TIME_MILLIS = 600; +const int ProximityInfoParams::MIN_DOUBLE_LETTER_BEELINE_SPEED_PERCENTILE = 5; +const int ProximityInfoParams::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2 = 10; +const int ProximityInfoParams::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR = + 1 << NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2; +const float ProximityInfoParams::NOT_A_DISTANCE_FLOAT = -1.0f; +// TODO: Investigate if this is required +const float ProximityInfoParams::SEARCH_KEY_RADIUS_RATIO = 0.95f; +} // namespace latinime diff --git a/native/jni/src/proximity_info_params.h b/native/jni/src/proximity_info_params.h new file mode 100644 index 000000000..b941fec0b --- /dev/null +++ b/native/jni/src/proximity_info_params.h @@ -0,0 +1,38 @@ +/* + * 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_PROXIMITY_INFO_PARAMS_H +#define LATINIME_PROXIMITY_INFO_PARAMS_H + +#include "defines.h" + +namespace latinime { + +class ProximityInfoParams { + public: + static const int LOOKUP_RADIUS_PERCENTILE; + static const int FIRST_POINT_TIME_OFFSET_MILLIS; + static const int STRONG_DOUBLE_LETTER_TIME_MILLIS; + static const int MIN_DOUBLE_LETTER_BEELINE_SPEED_PERCENTILE; + static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR; + static const float NOT_A_DISTANCE_FLOAT; + static const float SEARCH_KEY_RADIUS_RATIO; + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfoParams); + static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2; +}; +} // namespace latinime +#endif // LATINIME_PROXIMITY_INFO_PARAMS_H diff --git a/native/jni/src/proximity_info_state.cpp b/native/jni/src/proximity_info_state.cpp index 31b6e4baf..e720275d0 100644 --- a/native/jni/src/proximity_info_state.cpp +++ b/native/jni/src/proximity_info_state.cpp @@ -27,15 +27,7 @@ namespace latinime { -const int ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2 = 10; -const int ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR = - 1 << NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2; -const float ProximityInfoState::NOT_A_DISTANCE_FLOAT = -1.0f; const int ProximityInfoState::NOT_A_CODE = -1; -const int ProximityInfoState::LOOKUP_RADIUS_PERCENTILE = 50; -const int ProximityInfoState::FIRST_POINT_TIME_OFFSET_MILLIS = 150; -const int ProximityInfoState::STRONG_DOUBLE_LETTER_TIME_MILLIS = 600; -const int ProximityInfoState::MIN_DOUBLE_LETTER_BEELINE_SPEED_PERCENTILE = 5; void ProximityInfoState::initInputParams(const int pointerId, const float maxPointToKeyLength, const ProximityInfo *proximityInfo, const int *const inputCodes, const int inputSize, @@ -65,10 +57,10 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi int pushTouchPointStartIndex = 0; int lastSavedInputSize = 0; mMaxPointToKeyLength = maxPointToKeyLength; - if (mIsContinuationPossible && mInputIndice.size() > 1) { + if (mIsContinuationPossible && mSampledInputIndice.size() > 1) { // Just update difference. // Two points prior is never skipped. Thus, we pop 2 input point data here. - pushTouchPointStartIndex = mInputIndice[mInputIndice.size() - 2]; + pushTouchPointStartIndex = mSampledInputIndice[mSampledInputIndice.size() - 2]; popInputData(); popInputData(); lastSavedInputSize = mSampledInputXs.size(); @@ -76,9 +68,9 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi // Clear all data. mSampledInputXs.clear(); mSampledInputYs.clear(); - mTimes.clear(); - mInputIndice.clear(); - mLengthCache.clear(); + mSampledTimes.clear(); + mSampledInputIndice.clear(); + mSampledLengthCache.clear(); mDistanceCache_G.clear(); mNearKeysVector.clear(); mSearchKeysVector.clear(); @@ -97,92 +89,42 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi mSampledInputSize = ProximityInfoStateUtils::updateTouchPoints( mProximityInfo->getMostCommonKeyWidth(), mProximityInfo, mMaxPointToKeyLength, mInputProximities, xCoordinates, yCoordinates, times, pointerIds, inputSize, - isGeometric, pointerId, pushTouchPointStartIndex, - &mSampledInputXs, &mSampledInputYs, &mTimes, &mLengthCache, &mInputIndice); + isGeometric, pointerId, pushTouchPointStartIndex, &mSampledInputXs, + &mSampledInputYs, &mSampledTimes, &mSampledLengthCache, &mSampledInputIndice); } if (mSampledInputSize > 0 && isGeometric) { - refreshSpeedRates(inputSize, xCoordinates, yCoordinates, times, lastSavedInputSize); - refreshBeelineSpeedRates(inputSize, xCoordinates, yCoordinates, times); - } - - if (DEBUG_GEO_FULL) { - for (int i = 0; i < mSampledInputSize; ++i) { - AKLOGI("Sampled(%d): x = %d, y = %d, time = %d", i, mSampledInputXs[i], - mSampledInputYs[i], mTimes[i]); - } + mAverageSpeed = ProximityInfoStateUtils::refreshSpeedRates( + inputSize, xCoordinates, yCoordinates, times, lastSavedInputSize, + mSampledInputSize, &mSampledInputXs, &mSampledInputYs, &mSampledTimes, + &mSampledLengthCache, &mSampledInputIndice, &mSpeedRates, &mDirections); + ProximityInfoStateUtils::refreshBeelineSpeedRates( + mProximityInfo->getMostCommonKeyWidth(), mAverageSpeed, inputSize, + xCoordinates, yCoordinates, times, mSampledInputSize, &mSampledInputXs, + &mSampledInputYs, &mSampledInputIndice, &mBeelineSpeedPercentiles); } if (mSampledInputSize > 0) { - const int keyCount = mProximityInfo->getKeyCount(); - mNearKeysVector.resize(mSampledInputSize); - mSearchKeysVector.resize(mSampledInputSize); - mDistanceCache_G.resize(mSampledInputSize * keyCount); - for (int i = lastSavedInputSize; i < mSampledInputSize; ++i) { - mNearKeysVector[i].reset(); - mSearchKeysVector[i].reset(); - static const float NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD = 4.0f; - for (int k = 0; k < keyCount; ++k) { - const int index = i * keyCount + k; - const int x = mSampledInputXs[i]; - const int y = mSampledInputYs[i]; - const float normalizedSquaredDistance = - mProximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y); - mDistanceCache_G[index] = normalizedSquaredDistance; - if (normalizedSquaredDistance < NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) { - mNearKeysVector[i][k] = true; - } - } - } + ProximityInfoStateUtils::initGeometricDistanceInfos( + mProximityInfo, mProximityInfo->getKeyCount(), + mSampledInputSize, lastSavedInputSize, &mSampledInputXs, &mSampledInputYs, + &mNearKeysVector, &mSearchKeysVector, &mDistanceCache_G); if (isGeometric) { // updates probabilities of skipping or mapping each key for all points. - updateAlignPointProbabilities(lastSavedInputSize); - - static const float READ_FORWORD_LENGTH_SCALE = 0.95f; - const int readForwordLength = static_cast<int>( - hypotf(mProximityInfo->getKeyboardWidth(), mProximityInfo->getKeyboardHeight()) - * READ_FORWORD_LENGTH_SCALE); - for (int i = 0; i < mSampledInputSize; ++i) { - if (i >= lastSavedInputSize) { - mSearchKeysVector[i].reset(); - } - for (int j = max(i, lastSavedInputSize); j < mSampledInputSize; ++j) { - if (mLengthCache[j] - mLengthCache[i] >= readForwordLength) { - break; - } - mSearchKeysVector[i] |= mNearKeysVector[j]; - } - } + ProximityInfoStateUtils::updateAlignPointProbabilities( + mMaxPointToKeyLength, mProximityInfo->getMostCommonKeyWidth(), + mProximityInfo->getKeyCount(), lastSavedInputSize, mSampledInputSize, + &mSampledInputXs, &mSampledInputYs, &mSpeedRates, &mSampledLengthCache, + &mDistanceCache_G, &mNearKeysVector, &mCharProbabilities); + ProximityInfoStateUtils::updateSearchKeysVector(mProximityInfo, mSampledInputSize, + lastSavedInputSize, &mSampledLengthCache, &mNearKeysVector, &mSearchKeysVector); } } if (DEBUG_SAMPLING_POINTS) { - std::stringstream originalX, originalY, sampledX, sampledY; - for (int i = 0; i < inputSize; ++i) { - originalX << xCoordinates[i]; - originalY << yCoordinates[i]; - if (i != inputSize - 1) { - originalX << ";"; - originalY << ";"; - } - } - AKLOGI("===== sampled points ====="); - for (int i = 0; i < mSampledInputSize; ++i) { - if (isGeometric) { - AKLOGI("%d: x = %d, y = %d, time = %d, relative speed = %.4f, beeline speed = %d", - i, mSampledInputXs[i], mSampledInputYs[i], mTimes[i], mSpeedRates[i], - getBeelineSpeedPercentile(i)); - } - sampledX << mSampledInputXs[i]; - sampledY << mSampledInputYs[i]; - if (i != mSampledInputSize - 1) { - sampledX << ";"; - sampledY << ";"; - } - } - AKLOGI("original points:\n%s, %s,\nsampled points:\n%s, %s,\n", - originalX.str().c_str(), originalY.str().c_str(), sampledX.str().c_str(), - sampledY.str().c_str()); + ProximityInfoStateUtils::dump(isGeometric, inputSize, xCoordinates, yCoordinates, + mSampledInputSize, &mSampledInputXs, &mSampledInputYs, &mSampledTimes, &mSpeedRates, + &mBeelineSpeedPercentiles); } // end /////////////////////// @@ -192,200 +134,28 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi mTouchPositionCorrectionEnabled = mSampledInputSize > 0 && mHasTouchPositionCorrectionData && xCoordinates && yCoordinates; if (!isGeometric && pointerId == 0) { - for (int i = 0; i < inputSize; ++i) { - mPrimaryInputWord[i] = getPrimaryCodePointAt(i); - } - - for (int i = 0; i < mSampledInputSize && mTouchPositionCorrectionEnabled; ++i) { - const int *proximityCodePoints = getProximityCodePointsAt(i); - const int primaryKey = proximityCodePoints[0]; - const int x = xCoordinates[i]; - const int y = yCoordinates[i]; - if (DEBUG_PROXIMITY_CHARS) { - int a = x + y + primaryKey; - a += 0; - AKLOGI("--- Primary = %c, x = %d, y = %d", primaryKey, x, y); - } - for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL && proximityCodePoints[j] > 0; - ++j) { - const int currentCodePoint = proximityCodePoints[j]; - const float squaredDistance = - hasInputCoordinates() ? calculateNormalizedSquaredDistance( - mProximityInfo->getKeyIndexOf(currentCodePoint), i) : - NOT_A_DISTANCE_FLOAT; - if (squaredDistance >= 0.0f) { - mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j] = - (int) (squaredDistance * NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR); - } else { - mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j] = - (j == 0) ? EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO : - PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO; - } - if (DEBUG_PROXIMITY_CHARS) { - AKLOGI("--- Proximity (%d) = %c", j, currentCodePoint); - } - } + ProximityInfoStateUtils::initPrimaryInputWord( + inputSize, mInputProximities, mPrimaryInputWord); + if (mTouchPositionCorrectionEnabled) { + ProximityInfoStateUtils::initNormalizedSquaredDistances( + mProximityInfo, inputSize, xCoordinates, yCoordinates, mInputProximities, + hasInputCoordinates(), &mSampledInputXs, &mSampledInputYs, + mNormalizedSquaredDistances); } } - if (DEBUG_GEO_FULL) { AKLOGI("ProximityState init finished: %d points out of %d", mSampledInputSize, inputSize); } } -void ProximityInfoState::refreshSpeedRates(const int inputSize, const int *const xCoordinates, - const int *const yCoordinates, const int *const times, const int lastSavedInputSize) { - // Relative speed calculation. - const int sumDuration = mTimes.back() - mTimes.front(); - const int sumLength = mLengthCache.back() - mLengthCache.front(); - mAverageSpeed = static_cast<float>(sumLength) / static_cast<float>(sumDuration); - mSpeedRates.resize(mSampledInputSize); - for (int i = lastSavedInputSize; i < mSampledInputSize; ++i) { - const int index = mInputIndice[i]; - int length = 0; - int duration = 0; - - // Calculate velocity by using distances and durations of - // NUM_POINTS_FOR_SPEED_CALCULATION points for both forward and backward. - static const int NUM_POINTS_FOR_SPEED_CALCULATION = 2; - for (int j = index; j < min(inputSize - 1, index + NUM_POINTS_FOR_SPEED_CALCULATION); - ++j) { - if (i < mSampledInputSize - 1 && j >= mInputIndice[i + 1]) { - break; - } - length += getDistanceInt(xCoordinates[j], yCoordinates[j], - xCoordinates[j + 1], yCoordinates[j + 1]); - duration += times[j + 1] - times[j]; - } - for (int j = index - 1; j >= max(0, index - NUM_POINTS_FOR_SPEED_CALCULATION); --j) { - if (i > 0 && j < mInputIndice[i - 1]) { - break; - } - // TODO: use mLengthCache instead? - length += getDistanceInt(xCoordinates[j], yCoordinates[j], - xCoordinates[j + 1], yCoordinates[j + 1]); - duration += times[j + 1] - times[j]; - } - if (duration == 0 || sumDuration == 0) { - // Cannot calculate speed; thus, it gives an average value (1.0); - mSpeedRates[i] = 1.0f; - } else { - const float speed = static_cast<float>(length) / static_cast<float>(duration); - mSpeedRates[i] = speed / mAverageSpeed; - } - } - - // Direction calculation. - mDirections.resize(mSampledInputSize - 1); - for (int i = max(0, lastSavedInputSize - 1); i < mSampledInputSize - 1; ++i) { - mDirections[i] = getDirection(i, i + 1); - } -} - -static const int MAX_PERCENTILE = 100; -void ProximityInfoState::refreshBeelineSpeedRates(const int inputSize, - const int *const xCoordinates, const int *const yCoordinates, const int * times) { - if (DEBUG_SAMPLING_POINTS){ - AKLOGI("--- refresh beeline speed rates"); - } - mBeelineSpeedPercentiles.resize(mSampledInputSize); - for (int i = 0; i < mSampledInputSize; ++i) { - mBeelineSpeedPercentiles[i] = static_cast<int>(calculateBeelineSpeedRate( - i, inputSize, xCoordinates, yCoordinates, times) * MAX_PERCENTILE); - } -} - -float ProximityInfoState::calculateBeelineSpeedRate( - const int id, const int inputSize, const int *const xCoordinates, - const int *const yCoordinates, const int * times) const { - if (mSampledInputSize <= 0 || mAverageSpeed < 0.001f) { - if (DEBUG_SAMPLING_POINTS){ - AKLOGI("--- invalid state: cancel. size = %d, ave = %f", - mSampledInputSize, mAverageSpeed); - } - return 1.0f; - } - const int lookupRadius = - mProximityInfo->getMostCommonKeyWidth() * LOOKUP_RADIUS_PERCENTILE / MAX_PERCENTILE; - const int x0 = mSampledInputXs[id]; - const int y0 = mSampledInputYs[id]; - const int actualInputIndex = mInputIndice[id]; - int tempTime = 0; - int tempBeelineDistance = 0; - int start = actualInputIndex; - // lookup forward - while (start > 0 && tempBeelineDistance < lookupRadius) { - tempTime += times[start] - times[start - 1]; - --start; - tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[start], yCoordinates[start]); - } - // Exclusive unless this is an edge point - if (start > 0 && start < actualInputIndex) { - ++start; - } - tempTime= 0; - tempBeelineDistance = 0; - int end = actualInputIndex; - // lookup backward - while (end < (inputSize - 1) && tempBeelineDistance < lookupRadius) { - tempTime += times[end + 1] - times[end]; - ++end; - tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[end], yCoordinates[end]); - } - // Exclusive unless this is an edge point - if (end > actualInputIndex && end < (inputSize - 1)) { - --end; - } - - if (start >= end) { - if (DEBUG_DOUBLE_LETTER) { - AKLOGI("--- double letter: start == end %d", start); - } - return 1.0f; - } - - const int x2 = xCoordinates[start]; - const int y2 = yCoordinates[start]; - const int x3 = xCoordinates[end]; - const int y3 = yCoordinates[end]; - const int beelineDistance = getDistanceInt(x2, y2, x3, y3); - int adjustedStartTime = times[start]; - if (start == 0 && actualInputIndex == 0 && inputSize > 1) { - adjustedStartTime += FIRST_POINT_TIME_OFFSET_MILLIS; - } - int adjustedEndTime = times[end]; - if (end == (inputSize - 1) && inputSize > 1) { - adjustedEndTime -= FIRST_POINT_TIME_OFFSET_MILLIS; - } - const int time = adjustedEndTime - adjustedStartTime; - if (time <= 0) { - return 1.0f; - } - - if (time >= STRONG_DOUBLE_LETTER_TIME_MILLIS){ - return 0.0f; - } - if (DEBUG_DOUBLE_LETTER) { - AKLOGI("--- (%d, %d) double letter: start = %d, end = %d, dist = %d, time = %d, speed = %f," - " ave = %f, val = %f, start time = %d, end time = %d", - id, mInputIndice[id], start, end, beelineDistance, time, - (static_cast<float>(beelineDistance) / static_cast<float>(time)), mAverageSpeed, - ((static_cast<float>(beelineDistance) / static_cast<float>(time)) / mAverageSpeed), - adjustedStartTime, adjustedEndTime); - } - // Offset 1% - // TODO: Detect double letter more smartly - return 0.01f + static_cast<float>(beelineDistance) / static_cast<float>(time) / mAverageSpeed; -} - bool ProximityInfoState::checkAndReturnIsContinuationPossible(const int inputSize, const int *const xCoordinates, const int *const yCoordinates, const int *const times, const bool isGeometric) const { if (isGeometric) { for (int i = 0; i < mSampledInputSize; ++i) { - const int index = mInputIndice[i]; + const int index = mSampledInputIndice[i]; if (index > inputSize || xCoordinates[index] != mSampledInputXs[i] || - yCoordinates[index] != mSampledInputYs[i] || times[index] != mTimes[i]) { + yCoordinates[index] != mSampledInputYs[i] || times[index] != mSampledTimes[i]) { return false; } } @@ -404,26 +174,9 @@ bool ProximityInfoState::checkAndReturnIsContinuationPossible(const int inputSiz return true; } -float ProximityInfoState::calculateNormalizedSquaredDistance( - const int keyIndex, const int inputIndex) const { - if (keyIndex == NOT_AN_INDEX) { - return NOT_A_DISTANCE_FLOAT; - } - if (!mProximityInfo->hasSweetSpotData(keyIndex)) { - return NOT_A_DISTANCE_FLOAT; - } - if (NOT_A_COORDINATE == mSampledInputXs[inputIndex]) { - return NOT_A_DISTANCE_FLOAT; - } - const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter( - keyIndex, inputIndex); - const float squaredRadius = square(mProximityInfo->getSweetSpotRadiiAt(keyIndex)); - return squaredDistance / squaredRadius; -} - int ProximityInfoState::getDuration(const int index) const { if (index >= 0 && index < mSampledInputSize - 1) { - return mTimes[index + 1] - mTimes[index]; + return mSampledTimes[index + 1] - mSampledTimes[index]; } return 0; } @@ -450,16 +203,10 @@ float ProximityInfoState::getPointToKeyLength_G(const int inputIndex, const int } // TODO: Remove the "scale" parameter -// This function basically converts from a length to an edit distance. Accordingly, it's obviously -// wrong to compare with mMaxPointToKeyLength. float ProximityInfoState::getPointToKeyByIdLength( const int inputIndex, const int keyId, const float scale) const { - if (keyId != NOT_AN_INDEX) { - const int index = inputIndex * mProximityInfo->getKeyCount() + keyId; - return min(mDistanceCache_G[index] * scale, mMaxPointToKeyLength); - } - // If the char is not a key on the keyboard then return the max length. - return static_cast<float>(MAX_POINT_TO_KEY_LENGTH); + return ProximityInfoStateUtils::getPointToKeyByIdLength(mMaxPointToKeyLength, + &mDistanceCache_G, mProximityInfo->getKeyCount(), inputIndex, keyId, scale); } float ProximityInfoState::getPointToKeyByIdLength(const int inputIndex, const int keyId) const { @@ -498,7 +245,7 @@ ProximityType ProximityInfoState::getMatchedProximityId(const int index, const i // Not an exact nor an accent-alike match: search the list of close keys int j = 1; - while (j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL + while (j < MAX_PROXIMITY_CHARS_SIZE && currentCodePoints[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) { const bool matched = (currentCodePoints[j] == baseLowerC || currentCodePoints[j] == c); if (matched) { @@ -509,10 +256,10 @@ ProximityType ProximityInfoState::getMatchedProximityId(const int index, const i } ++j; } - if (j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL + if (j < MAX_PROXIMITY_CHARS_SIZE && currentCodePoints[j] == ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) { ++j; - while (j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL + while (j < MAX_PROXIMITY_CHARS_SIZE && currentCodePoints[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) { const bool matched = (currentCodePoints[j] == baseLowerC || currentCodePoints[j] == c); if (matched) { @@ -533,15 +280,6 @@ int ProximityInfoState::getSpaceY() const { return mProximityInfo->getKeyCenterYOfKeyIdG(keyId); } -float ProximityInfoState::calculateSquaredDistanceFromSweetSpotCenter( - const int keyIndex, const int inputIndex) const { - const float sweetSpotCenterX = mProximityInfo->getSweetSpotCenterXAt(keyIndex); - const float sweetSpotCenterY = mProximityInfo->getSweetSpotCenterYAt(keyIndex); - const float inputX = static_cast<float>(mSampledInputXs[inputIndex]); - const float inputY = static_cast<float>(mSampledInputYs[inputIndex]); - return square(inputX - sweetSpotCenterX) + square(inputY - sweetSpotCenterY); -} - // Puts possible characters into filter and returns new filter size. int ProximityInfoState::getAllPossibleChars( const size_t index, int *const filter, const int filterSize) const { @@ -576,48 +314,13 @@ bool ProximityInfoState::isKeyInSerchKeysAfterIndex(const int index, const int k } void ProximityInfoState::popInputData() { - ProximityInfoStateUtils::popInputData(&mSampledInputXs, &mSampledInputYs, &mTimes, - &mLengthCache, &mInputIndice); + ProximityInfoStateUtils::popInputData(&mSampledInputXs, &mSampledInputYs, &mSampledTimes, + &mSampledLengthCache, &mSampledInputIndice); } float ProximityInfoState::getDirection(const int index0, const int index1) const { - if (index0 < 0 || index0 > mSampledInputSize - 1) { - return 0.0f; - } - if (index1 < 0 || index1 > mSampledInputSize - 1) { - return 0.0f; - } - const int x1 = mSampledInputXs[index0]; - const int y1 = mSampledInputYs[index0]; - const int x2 = mSampledInputXs[index1]; - const int y2 = mSampledInputYs[index1]; - return getAngle(x1, y1, x2, y2); -} - -float ProximityInfoState::getPointAngle(const int index) const { - if (index <= 0 || index >= mSampledInputSize - 1) { - return 0.0f; - } - const float previousDirection = getDirection(index - 1, index); - const float nextDirection = getDirection(index, index + 1); - const float directionDiff = getAngleDiff(previousDirection, nextDirection); - return directionDiff; -} - -float ProximityInfoState::getPointsAngle( - const int index0, const int index1, const int index2) const { - if (index0 < 0 || index0 > mSampledInputSize - 1) { - return 0.0f; - } - if (index1 < 0 || index1 > mSampledInputSize - 1) { - return 0.0f; - } - if (index2 < 0 || index2 > mSampledInputSize - 1) { - return 0.0f; - } - const float previousDirection = getDirection(index0, index1); - const float nextDirection = getDirection(index1, index2); - return getAngleDiff(previousDirection, nextDirection); + return ProximityInfoStateUtils::getDirection( + &mSampledInputXs, &mSampledInputYs, index0, index1); } float ProximityInfoState::getLineToKeyDistance( @@ -640,293 +343,6 @@ float ProximityInfoState::getLineToKeyDistance( keyX, keyY, x0, y0, x1, y1, extend); } -// Updates probabilities of aligning to some keys and skipping. -// Word suggestion should be based on this probabilities. -void ProximityInfoState::updateAlignPointProbabilities(const int start) { - static const float MIN_PROBABILITY = 0.000001f; - static const float MAX_SKIP_PROBABILITY = 0.95f; - static const float SKIP_FIRST_POINT_PROBABILITY = 0.01f; - static const float SKIP_LAST_POINT_PROBABILITY = 0.1f; - static const float MIN_SPEED_RATE_FOR_SKIP_PROBABILITY = 0.15f; - static const float SPEED_WEIGHT_FOR_SKIP_PROBABILITY = 0.9f; - static const float SLOW_STRAIGHT_WEIGHT_FOR_SKIP_PROBABILITY = 0.6f; - static const float NEAREST_DISTANCE_WEIGHT = 0.5f; - static const float NEAREST_DISTANCE_BIAS = 0.5f; - static const float NEAREST_DISTANCE_WEIGHT_FOR_LAST = 0.6f; - static const float NEAREST_DISTANCE_BIAS_FOR_LAST = 0.4f; - - static const float ANGLE_WEIGHT = 0.90f; - static const float DEEP_CORNER_ANGLE_THRESHOLD = M_PI_F * 60.0f / 180.0f; - static const float SKIP_DEEP_CORNER_PROBABILITY = 0.1f; - static const float CORNER_ANGLE_THRESHOLD = M_PI_F * 30.0f / 180.0f; - static const float STRAIGHT_ANGLE_THRESHOLD = M_PI_F * 15.0f / 180.0f; - static const float SKIP_CORNER_PROBABILITY = 0.4f; - static const float SPEED_MARGIN = 0.1f; - static const float CENTER_VALUE_OF_NORMALIZED_DISTRIBUTION = 0.0f; - - const int keyCount = mProximityInfo->getKeyCount(); - mCharProbabilities.resize(mSampledInputSize); - // Calculates probabilities of using a point as a correlated point with the character - // for each point. - for (int i = start; i < mSampledInputSize; ++i) { - mCharProbabilities[i].clear(); - // First, calculates skip probability. Starts form MIN_SKIP_PROBABILITY. - // Note that all values that are multiplied to this probability should be in [0.0, 1.0]; - float skipProbability = MAX_SKIP_PROBABILITY; - - const float currentAngle = getPointAngle(i); - const float speedRate = getSpeedRate(i); - - float nearestKeyDistance = static_cast<float>(MAX_POINT_TO_KEY_LENGTH); - for (int j = 0; j < keyCount; ++j) { - if (mNearKeysVector[i].test(j)) { - const float distance = getPointToKeyByIdLength(i, j); - if (distance < nearestKeyDistance) { - nearestKeyDistance = distance; - } - } - } - - if (i == 0) { - skipProbability *= min(1.0f, nearestKeyDistance * NEAREST_DISTANCE_WEIGHT - + NEAREST_DISTANCE_BIAS); - // Promote the first point - skipProbability *= SKIP_FIRST_POINT_PROBABILITY; - } else if (i == mSampledInputSize - 1) { - skipProbability *= min(1.0f, nearestKeyDistance * NEAREST_DISTANCE_WEIGHT_FOR_LAST - + NEAREST_DISTANCE_BIAS_FOR_LAST); - // Promote the last point - skipProbability *= SKIP_LAST_POINT_PROBABILITY; - } else { - // If the current speed is relatively slower than adjacent keys, we promote this point. - if (getSpeedRate(i - 1) - SPEED_MARGIN > speedRate - && speedRate < getSpeedRate(i + 1) - SPEED_MARGIN) { - if (currentAngle < CORNER_ANGLE_THRESHOLD) { - skipProbability *= min(1.0f, speedRate - * SLOW_STRAIGHT_WEIGHT_FOR_SKIP_PROBABILITY); - } else { - // If the angle is small enough, we promote this point more. (e.g. pit vs put) - skipProbability *= min(1.0f, speedRate * SPEED_WEIGHT_FOR_SKIP_PROBABILITY - + MIN_SPEED_RATE_FOR_SKIP_PROBABILITY); - } - } - - skipProbability *= min(1.0f, speedRate * nearestKeyDistance * - NEAREST_DISTANCE_WEIGHT + NEAREST_DISTANCE_BIAS); - - // Adjusts skip probability by a rate depending on angle. - // ANGLE_RATE of skipProbability is adjusted by current angle. - skipProbability *= (M_PI_F - currentAngle) / M_PI_F * ANGLE_WEIGHT - + (1.0f - ANGLE_WEIGHT); - if (currentAngle > DEEP_CORNER_ANGLE_THRESHOLD) { - skipProbability *= SKIP_DEEP_CORNER_PROBABILITY; - } - // We assume the angle of this point is the angle for point[i], point[i - 2] - // and point[i - 3]. The reason why we don't use the angle for point[i], point[i - 1] - // and point[i - 2] is this angle can be more affected by the noise. - const float prevAngle = getPointsAngle(i, i - 2, i - 3); - if (i >= 3 && prevAngle < STRAIGHT_ANGLE_THRESHOLD - && currentAngle > CORNER_ANGLE_THRESHOLD) { - skipProbability *= SKIP_CORNER_PROBABILITY; - } - } - - // probabilities must be in [0.0, MAX_SKIP_PROBABILITY]; - ASSERT(skipProbability >= 0.0f); - ASSERT(skipProbability <= MAX_SKIP_PROBABILITY); - mCharProbabilities[i][NOT_AN_INDEX] = skipProbability; - - // Second, calculates key probabilities by dividing the rest probability - // (1.0f - skipProbability). - const float inputCharProbability = 1.0f - skipProbability; - - // TODO: The variance is critical for accuracy; thus, adjusting these parameter by machine - // learning or something would be efficient. - static const float SPEEDxANGLE_WEIGHT_FOR_STANDARD_DIVIATION = 0.3f; - static const float MAX_SPEEDxANGLE_RATE_FOR_STANDERD_DIVIATION = 0.25f; - static const float SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DIVIATION = 0.5f; - static const float MAX_SPEEDxNEAREST_RATE_FOR_STANDERD_DIVIATION = 0.15f; - static const float MIN_STANDERD_DIVIATION = 0.37f; - - const float speedxAngleRate = min(speedRate * currentAngle / M_PI_F - * SPEEDxANGLE_WEIGHT_FOR_STANDARD_DIVIATION, - MAX_SPEEDxANGLE_RATE_FOR_STANDERD_DIVIATION); - const float speedxNearestKeyDistanceRate = min(speedRate * nearestKeyDistance - * SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DIVIATION, - MAX_SPEEDxNEAREST_RATE_FOR_STANDERD_DIVIATION); - const float sigma = speedxAngleRate + speedxNearestKeyDistanceRate + MIN_STANDERD_DIVIATION; - - ProximityInfoUtils::NormalDistribution - distribution(CENTER_VALUE_OF_NORMALIZED_DISTRIBUTION, sigma); - static const float PREV_DISTANCE_WEIGHT = 0.5f; - static const float NEXT_DISTANCE_WEIGHT = 0.6f; - // Summing up probability densities of all near keys. - float sumOfProbabilityDensities = 0.0f; - for (int j = 0; j < keyCount; ++j) { - if (mNearKeysVector[i].test(j)) { - float distance = sqrtf(getPointToKeyByIdLength(i, j)); - if (i == 0 && i != mSampledInputSize - 1) { - // For the first point, weighted average of distances from first point and the - // next point to the key is used as a point to key distance. - const float nextDistance = sqrtf(getPointToKeyByIdLength(i + 1, j)); - if (nextDistance < distance) { - // The distance of the first point tends to bigger than continuing - // points because the first touch by the user can be sloppy. - // So we promote the first point if the distance of that point is larger - // than the distance of the next point. - distance = (distance + nextDistance * NEXT_DISTANCE_WEIGHT) - / (1.0f + NEXT_DISTANCE_WEIGHT); - } - } else if (i != 0 && i == mSampledInputSize - 1) { - // For the first point, weighted average of distances from last point and - // the previous point to the key is used as a point to key distance. - const float previousDistance = sqrtf(getPointToKeyByIdLength(i - 1, j)); - if (previousDistance < distance) { - // The distance of the last point tends to bigger than continuing points - // because the last touch by the user can be sloppy. So we promote the - // last point if the distance of that point is larger than the distance of - // the previous point. - distance = (distance + previousDistance * PREV_DISTANCE_WEIGHT) - / (1.0f + PREV_DISTANCE_WEIGHT); - } - } - // TODO: Promote the first point when the extended line from the next input is near - // from a key. Also, promote the last point as well. - sumOfProbabilityDensities += distribution.getProbabilityDensity(distance); - } - } - - // Split the probability of an input point to keys that are close to the input point. - for (int j = 0; j < keyCount; ++j) { - if (mNearKeysVector[i].test(j)) { - float distance = sqrtf(getPointToKeyByIdLength(i, j)); - if (i == 0 && i != mSampledInputSize - 1) { - // For the first point, weighted average of distances from the first point and - // the next point to the key is used as a point to key distance. - const float prevDistance = sqrtf(getPointToKeyByIdLength(i + 1, j)); - if (prevDistance < distance) { - distance = (distance + prevDistance * NEXT_DISTANCE_WEIGHT) - / (1.0f + NEXT_DISTANCE_WEIGHT); - } - } else if (i != 0 && i == mSampledInputSize - 1) { - // For the first point, weighted average of distances from last point and - // the previous point to the key is used as a point to key distance. - const float prevDistance = sqrtf(getPointToKeyByIdLength(i - 1, j)); - if (prevDistance < distance) { - distance = (distance + prevDistance * PREV_DISTANCE_WEIGHT) - / (1.0f + PREV_DISTANCE_WEIGHT); - } - } - const float probabilityDensity = distribution.getProbabilityDensity(distance); - const float probability = inputCharProbability * probabilityDensity - / sumOfProbabilityDensities; - mCharProbabilities[i][j] = probability; - } - } - } - - - if (DEBUG_POINTS_PROBABILITY) { - for (int i = 0; i < mSampledInputSize; ++i) { - std::stringstream sstream; - sstream << i << ", "; - sstream << "(" << mSampledInputXs[i] << ", " << mSampledInputYs[i] << "), "; - sstream << "Speed: "<< getSpeedRate(i) << ", "; - sstream << "Angle: "<< getPointAngle(i) << ", \n"; - - for (hash_map_compat<int, float>::iterator it = mCharProbabilities[i].begin(); - it != mCharProbabilities[i].end(); ++it) { - if (it->first == NOT_AN_INDEX) { - sstream << it->first - << "(skip):" - << it->second - << "\n"; - } else { - sstream << it->first - << "(" - << static_cast<char>(mProximityInfo->getCodePointOf(it->first)) - << "):" - << it->second - << "\n"; - } - } - AKLOGI("%s", sstream.str().c_str()); - } - } - - // Decrease key probabilities of points which don't have the highest probability of that key - // among nearby points. Probabilities of the first point and the last point are not suppressed. - for (int i = max(start, 1); i < mSampledInputSize; ++i) { - for (int j = i + 1; j < mSampledInputSize; ++j) { - if (!suppressCharProbabilities(i, j)) { - break; - } - } - for (int j = i - 1; j >= max(start, 0); --j) { - if (!suppressCharProbabilities(i, j)) { - break; - } - } - } - - // Converting from raw probabilities to log probabilities to calculate spatial distance. - for (int i = start; i < mSampledInputSize; ++i) { - for (int j = 0; j < keyCount; ++j) { - hash_map_compat<int, float>::iterator it = mCharProbabilities[i].find(j); - if (it == mCharProbabilities[i].end()){ - mNearKeysVector[i].reset(j); - } else if(it->second < MIN_PROBABILITY) { - // Erases from near keys vector because it has very low probability. - mNearKeysVector[i].reset(j); - mCharProbabilities[i].erase(j); - } else { - it->second = -logf(it->second); - } - } - mCharProbabilities[i][NOT_AN_INDEX] = -logf(mCharProbabilities[i][NOT_AN_INDEX]); - } -} - -// Decreases char probabilities of index0 by checking probabilities of a near point (index1) and -// increases char probabilities of index1 by checking probabilities of index0. -bool ProximityInfoState::suppressCharProbabilities(const int index0, const int index1) { - ASSERT(0 <= index0 && index0 < mSampledInputSize); - ASSERT(0 <= index1 && index1 < mSampledInputSize); - - static const float SUPPRESSION_LENGTH_WEIGHT = 1.5f; - static const float MIN_SUPPRESSION_RATE = 0.1f; - static const float SUPPRESSION_WEIGHT = 0.5f; - static const float SUPPRESSION_WEIGHT_FOR_PROBABILITY_GAIN = 0.1f; - static const float SKIP_PROBABALITY_WEIGHT_FOR_PROBABILITY_GAIN = 0.3f; - - const float keyWidthFloat = static_cast<float>(mProximityInfo->getMostCommonKeyWidth()); - const float diff = fabsf(static_cast<float>(mLengthCache[index0] - mLengthCache[index1])); - if (diff > keyWidthFloat * SUPPRESSION_LENGTH_WEIGHT) { - return false; - } - const float suppressionRate = MIN_SUPPRESSION_RATE - + diff / keyWidthFloat / SUPPRESSION_LENGTH_WEIGHT * SUPPRESSION_WEIGHT; - for (hash_map_compat<int, float>::iterator it = mCharProbabilities[index0].begin(); - it != mCharProbabilities[index0].end(); ++it) { - hash_map_compat<int, float>::iterator it2 = mCharProbabilities[index1].find(it->first); - if (it2 != mCharProbabilities[index1].end() && it->second < it2->second) { - const float newProbability = it->second * suppressionRate; - const float suppression = it->second - newProbability; - it->second = newProbability; - // mCharProbabilities[index0][NOT_AN_INDEX] is the probability of skipping this point. - mCharProbabilities[index0][NOT_AN_INDEX] += suppression; - - // Add the probability of the same key nearby index1 - const float probabilityGain = min(suppression * SUPPRESSION_WEIGHT_FOR_PROBABILITY_GAIN, - mCharProbabilities[index1][NOT_AN_INDEX] - * SKIP_PROBABALITY_WEIGHT_FOR_PROBABILITY_GAIN); - it2->second += probabilityGain; - mCharProbabilities[index1][NOT_AN_INDEX] -= probabilityGain; - } - } - return true; -} - // Get a word that is detected by tracing the most probable string into codePointBuf and // returns probability of generating the word. float ProximityInfoState::getMostProbableString(int *const codePointBuf) const { diff --git a/native/jni/src/proximity_info_state.h b/native/jni/src/proximity_info_state.h index 0f0eb7d39..8bada277e 100644 --- a/native/jni/src/proximity_info_state.h +++ b/native/jni/src/proximity_info_state.h @@ -17,13 +17,13 @@ #ifndef LATINIME_PROXIMITY_INFO_STATE_H #define LATINIME_PROXIMITY_INFO_STATE_H -#include <bitset> #include <cstring> // for memset() #include <vector> #include "char_utils.h" #include "defines.h" #include "hash_map_compat.h" +#include "proximity_info_params.h" #include "proximity_info_state_utils.h" namespace latinime { @@ -32,15 +32,8 @@ class ProximityInfo; class ProximityInfoState { public: - typedef std::bitset<MAX_KEY_COUNT_IN_A_KEYBOARD> NearKeycodesSet; - static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2; - static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR; - static const float NOT_A_DISTANCE_FLOAT; + static const int NOT_A_CODE; - static const int LOOKUP_RADIUS_PERCENTILE; - static const int FIRST_POINT_TIME_OFFSET_MILLIS; - static const int STRONG_DOUBLE_LETTER_TIME_MILLIS; - static const int MIN_DOUBLE_LETTER_BEELINE_SPEED_PERCENTILE; ///////////////////////////////////////// // Defined in proximity_info_state.cpp // @@ -57,10 +50,11 @@ class ProximityInfoState { : mProximityInfo(0), mMaxPointToKeyLength(0.0f), mAverageSpeed(0.0f), mHasTouchPositionCorrectionData(false), mMostCommonKeyWidthSquare(0), mKeyCount(0), mCellHeight(0), mCellWidth(0), mGridHeight(0), mGridWidth(0), - mIsContinuationPossible(false), mSampledInputXs(), mSampledInputYs(), mTimes(), - mInputIndice(), mLengthCache(), mBeelineSpeedPercentiles(), mDistanceCache_G(), - mSpeedRates(), mDirections(), mCharProbabilities(), mNearKeysVector(), - mSearchKeysVector(), mTouchPositionCorrectionEnabled(false), mSampledInputSize(0) { + mIsContinuationPossible(false), mSampledInputXs(), mSampledInputYs(), mSampledTimes(), + mSampledInputIndice(), mSampledLengthCache(), mBeelineSpeedPercentiles(), + mDistanceCache_G(), mSpeedRates(), mDirections(), mCharProbabilities(), + mNearKeysVector(), mSearchKeysVector(), mTouchPositionCorrectionEnabled(false), + mSampledInputSize(0) { memset(mInputProximities, 0, sizeof(mInputProximities)); memset(mNormalizedSquaredDistances, 0, sizeof(mNormalizedSquaredDistances)); memset(mPrimaryInputWord, 0, sizeof(mPrimaryInputWord)); @@ -76,7 +70,7 @@ class ProximityInfoState { AK_FORCE_INLINE bool existsCodePointInProximityAt(const int index, const int c) const { const int *codePoints = getProximityCodePointsAt(index); int i = 0; - while (codePoints[i] > 0 && i < MAX_PROXIMITY_CHARS_SIZE_INTERNAL) { + while (codePoints[i] > 0 && i < MAX_PROXIMITY_CHARS_SIZE) { if (codePoints[i++] == c) { return true; } @@ -102,7 +96,7 @@ class ProximityInfoState { inline int getNormalizedSquaredDistance( const int inputIndex, const int proximityIndex) const { return mNormalizedSquaredDistances[ - inputIndex * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + proximityIndex]; + inputIndex * MAX_PROXIMITY_CHARS_SIZE + proximityIndex]; } inline const int *getPrimaryInputWord() const { @@ -122,7 +116,7 @@ class ProximityInfoState { if (*inputProximities != *word) { return false; } - inputProximities += MAX_PROXIMITY_CHARS_SIZE_INTERNAL; + inputProximities += MAX_PROXIMITY_CHARS_SIZE; word++; } return true; @@ -149,7 +143,7 @@ class ProximityInfoState { bool hasSpaceProximity(const int index) const; int getLengthCache(const int index) const { - return mLengthCache[index]; + return mSampledLengthCache[index]; } bool isContinuationPossible() const { @@ -180,7 +174,8 @@ class ProximityInfoState { const int beelineSpeedRate = getBeelineSpeedPercentile(id); if (beelineSpeedRate == 0) { return A_STRONG_DOUBLE_LETTER; - } else if (beelineSpeedRate < MIN_DOUBLE_LETTER_BEELINE_SPEED_PERCENTILE) { + } else if (beelineSpeedRate + < ProximityInfoParams::MIN_DOUBLE_LETTER_BEELINE_SPEED_PERCENTILE) { return A_DOUBLE_LETTER; } else { return NOT_A_DOUBLE_LETTER; @@ -193,10 +188,6 @@ class ProximityInfoState { // get xy direction float getDirection(const int x, const int y) const; - float getPointAngle(const int index) const; - // Returns angle of three points. x, y, and z are indices. - float getPointsAngle(const int index0, const int index1, const int index2) const; - float getMostProbableString(int *const codePointBuf) const; float getProbability(const int index, const int charCode) const; @@ -207,7 +198,6 @@ class ProximityInfoState { bool isKeyInSerchKeysAfterIndex(const int index, const int keyId) const; private: DISALLOW_COPY_AND_ASSIGN(ProximityInfoState); - typedef hash_map_compat<int, float> NearKeysDistanceMap; ///////////////////////////////////////// // Defined in proximity_info_state.cpp // ///////////////////////////////////////// @@ -216,15 +206,9 @@ class ProximityInfoState { float calculateSquaredDistanceFromSweetSpotCenter( const int keyIndex, const int inputIndex) const; - bool pushTouchPoint(const int inputIndex, const int nodeCodePoint, int x, int y, const int time, - const bool sample, const bool isLastPoint, const float sumAngle, - NearKeysDistanceMap *const currentNearKeysDistances, - const NearKeysDistanceMap *const prevNearKeysDistances, - const NearKeysDistanceMap *const prevPrevNearKeysDistances); ///////////////////////////////////////// // Defined here // ///////////////////////////////////////// - inline float square(const float x) const { return x * x; } bool hasInputCoordinates() const { return mSampledInputXs.size() > 0 && mSampledInputYs.size() > 0; @@ -233,28 +217,9 @@ class ProximityInfoState { inline const int *getProximityCodePointsAt(const int index) const { return ProximityInfoStateUtils::getProximityCodePointsAt(mInputProximities, index); } - - float updateNearKeysDistances(const int x, const int y, - NearKeysDistanceMap *const currentNearKeysDistances); - bool isPrevLocalMin(const NearKeysDistanceMap *const currentNearKeysDistances, - const NearKeysDistanceMap *const prevNearKeysDistances, - const NearKeysDistanceMap *const prevPrevNearKeysDistances) const; - float getPointScore( - const int x, const int y, const int time, const bool last, const float nearest, - const float sumAngle, const NearKeysDistanceMap *const currentNearKeysDistances, - const NearKeysDistanceMap *const prevNearKeysDistances, - const NearKeysDistanceMap *const prevPrevNearKeysDistances) const; bool checkAndReturnIsContinuationPossible(const int inputSize, const int *const xCoordinates, const int *const yCoordinates, const int *const times, const bool isGeometric) const; void popInputData(); - void updateAlignPointProbabilities(const int start); - bool suppressCharProbabilities(const int index1, const int index2); - void refreshSpeedRates(const int inputSize, const int *const xCoordinates, - const int *const yCoordinates, const int *const times, const int lastSavedInputSize); - void refreshBeelineSpeedRates(const int inputSize, - const int *const xCoordinates, const int *const yCoordinates, const int * times); - float calculateBeelineSpeedRate(const int id, const int inputSize, - const int *const xCoordinates, const int *const yCoordinates, const int * times) const; // const const ProximityInfo *mProximityInfo; @@ -271,9 +236,9 @@ class ProximityInfoState { std::vector<int> mSampledInputXs; std::vector<int> mSampledInputYs; - std::vector<int> mTimes; - std::vector<int> mInputIndice; - std::vector<int> mLengthCache; + std::vector<int> mSampledTimes; + std::vector<int> mSampledInputIndice; + std::vector<int> mSampledLengthCache; std::vector<int> mBeelineSpeedPercentiles; std::vector<float> mDistanceCache_G; std::vector<float> mSpeedRates; @@ -283,15 +248,15 @@ class ProximityInfoState { // The vector for the key code set which holds nearby keys for each sampled input point // 1. Used to calculate the probability of the key // 2. Used to calculate mSearchKeysVector - std::vector<NearKeycodesSet> mNearKeysVector; + std::vector<ProximityInfoStateUtils::NearKeycodesSet> mNearKeysVector; // The vector for the key code set which holds nearby keys of some trailing sampled input points // for each sampled input point. These nearby keys contain the next characters which can be in // the dictionary. Specifically, currently we are looking for keys nearby trailing sampled // inputs including the current input point. - std::vector<NearKeycodesSet> mSearchKeysVector; + std::vector<ProximityInfoStateUtils::NearKeycodesSet> mSearchKeysVector; bool mTouchPositionCorrectionEnabled; - int mInputProximities[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH]; - int mNormalizedSquaredDistances[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH]; + int mInputProximities[MAX_PROXIMITY_CHARS_SIZE * MAX_WORD_LENGTH]; + int mNormalizedSquaredDistances[MAX_PROXIMITY_CHARS_SIZE * MAX_WORD_LENGTH]; int mSampledInputSize; int mPrimaryInputWord[MAX_WORD_LENGTH]; }; diff --git a/native/jni/src/proximity_info_state_utils.cpp b/native/jni/src/proximity_info_state_utils.cpp new file mode 100644 index 000000000..be6cde17b --- /dev/null +++ b/native/jni/src/proximity_info_state_utils.cpp @@ -0,0 +1,1029 @@ +/* + * 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 <cmath> +#include <sstream> // for debug prints +#include <vector> + +#include "defines.h" +#include "geometry_utils.h" +#include "proximity_info.h" +#include "proximity_info_params.h" +#include "proximity_info_state_utils.h" + +namespace latinime { + +/* static */ int ProximityInfoStateUtils::updateTouchPoints(const int mostCommonKeyWidth, + const ProximityInfo *const proximityInfo, const int maxPointToKeyLength, + const int *const inputProximities, const int *const inputXCoordinates, + const int *const inputYCoordinates, const int *const times, const int *const pointerIds, + const int inputSize, const bool isGeometric, const int pointerId, + const int pushTouchPointStartIndex, std::vector<int> *sampledInputXs, + std::vector<int> *sampledInputYs, std::vector<int> *sampledInputTimes, + std::vector<int> *sampledLengthCache, std::vector<int> *sampledInputIndice) { + if (DEBUG_SAMPLING_POINTS) { + if (times) { + for (int i = 0; i < inputSize; ++i) { + AKLOGI("(%d) x %d, y %d, time %d", + i, inputXCoordinates[i], inputYCoordinates[i], times[i]); + } + } + } +#ifdef DO_ASSERT_TEST + if (times) { + for (int i = 0; i < inputSize; ++i) { + if (i > 0) { + if (times[i] < times[i - 1]) { + AKLOGI("Invalid time sequence. %d, %d", times[i], times[i - 1]); + ASSERT(false); + } + } + } + } +#endif + const bool proximityOnly = !isGeometric + && (inputXCoordinates[0] < 0 || inputYCoordinates[0] < 0); + int lastInputIndex = pushTouchPointStartIndex; + for (int i = lastInputIndex; i < inputSize; ++i) { + const int pid = pointerIds ? pointerIds[i] : 0; + if (pointerId == pid) { + lastInputIndex = i; + } + } + if (DEBUG_GEO_FULL) { + AKLOGI("Init ProximityInfoState: last input index = %d", lastInputIndex); + } + // Working space to save near keys distances for current, prev and prevprev input point. + NearKeysDistanceMap nearKeysDistances[3]; + // These pointers are swapped for each inputs points. + NearKeysDistanceMap *currentNearKeysDistances = &nearKeysDistances[0]; + NearKeysDistanceMap *prevNearKeysDistances = &nearKeysDistances[1]; + NearKeysDistanceMap *prevPrevNearKeysDistances = &nearKeysDistances[2]; + // "sumAngle" is accumulated by each angle of input points. And when "sumAngle" exceeds + // the threshold we save that point, reset sumAngle. This aims to keep the figure of + // the curve. + float sumAngle = 0.0f; + + for (int i = pushTouchPointStartIndex; i <= lastInputIndex; ++i) { + // Assuming pointerId == 0 if pointerIds is null. + const int pid = pointerIds ? pointerIds[i] : 0; + if (DEBUG_GEO_FULL) { + AKLOGI("Init ProximityInfoState: (%d)PID = %d", i, pid); + } + if (pointerId == pid) { + const int c = isGeometric ? + NOT_A_COORDINATE : getPrimaryCodePointAt(inputProximities, i); + const int x = proximityOnly ? NOT_A_COORDINATE : inputXCoordinates[i]; + const int y = proximityOnly ? NOT_A_COORDINATE : inputYCoordinates[i]; + const int time = times ? times[i] : -1; + + if (i > 1) { + const float prevAngle = getAngle( + inputXCoordinates[i - 2], inputYCoordinates[i - 2], + inputXCoordinates[i - 1], inputYCoordinates[i - 1]); + const float currentAngle = + getAngle(inputXCoordinates[i - 1], inputYCoordinates[i - 1], x, y); + sumAngle += getAngleDiff(prevAngle, currentAngle); + } + + if (pushTouchPoint(mostCommonKeyWidth, proximityInfo, maxPointToKeyLength, + i, c, x, y, time, isGeometric /* doSampling */, + i == lastInputIndex, sumAngle, currentNearKeysDistances, + prevNearKeysDistances, prevPrevNearKeysDistances, + sampledInputXs, sampledInputYs, sampledInputTimes, sampledLengthCache, + sampledInputIndice)) { + // Previous point information was popped. + NearKeysDistanceMap *tmp = prevNearKeysDistances; + prevNearKeysDistances = currentNearKeysDistances; + currentNearKeysDistances = tmp; + } else { + NearKeysDistanceMap *tmp = prevPrevNearKeysDistances; + prevPrevNearKeysDistances = prevNearKeysDistances; + prevNearKeysDistances = currentNearKeysDistances; + currentNearKeysDistances = tmp; + sumAngle = 0.0f; + } + } + } + return sampledInputXs->size(); +} + +/* static */ const int *ProximityInfoStateUtils::getProximityCodePointsAt( + const int *const inputProximities, const int index) { + return inputProximities + (index * MAX_PROXIMITY_CHARS_SIZE); +} + +/* static */ int ProximityInfoStateUtils::getPrimaryCodePointAt( + const int *const inputProximities, const int index) { + return getProximityCodePointsAt(inputProximities, index)[0]; +} + +/* static */ void ProximityInfoStateUtils::initPrimaryInputWord( + const int inputSize, const int *const inputProximities, int *primaryInputWord) { + for (int i = 0; i < inputSize; ++i) { + primaryInputWord[i] = getPrimaryCodePointAt(inputProximities, i); + } +} + +/* static */ float ProximityInfoStateUtils::calculateSquaredDistanceFromSweetSpotCenter( + const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, const int keyIndex, + const int inputIndex) { + const float sweetSpotCenterX = proximityInfo->getSweetSpotCenterXAt(keyIndex); + const float sweetSpotCenterY = proximityInfo->getSweetSpotCenterYAt(keyIndex); + const float inputX = static_cast<float>((*sampledInputXs)[inputIndex]); + const float inputY = static_cast<float>((*sampledInputYs)[inputIndex]); + return SQUARE_FLOAT(inputX - sweetSpotCenterX) + SQUARE_FLOAT(inputY - sweetSpotCenterY); +} + +/* static */ float ProximityInfoStateUtils::calculateNormalizedSquaredDistance( + const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + const int keyIndex, const int inputIndex) { + if (keyIndex == NOT_AN_INDEX) { + return ProximityInfoParams::NOT_A_DISTANCE_FLOAT; + } + if (!proximityInfo->hasSweetSpotData(keyIndex)) { + return ProximityInfoParams::NOT_A_DISTANCE_FLOAT; + } + if (NOT_A_COORDINATE == (*sampledInputXs)[inputIndex]) { + return ProximityInfoParams::NOT_A_DISTANCE_FLOAT; + } + const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter(proximityInfo, + sampledInputXs, sampledInputYs, keyIndex, inputIndex); + const float squaredRadius = SQUARE_FLOAT(proximityInfo->getSweetSpotRadiiAt(keyIndex)); + return squaredDistance / squaredRadius; +} + +/* static */ void ProximityInfoStateUtils::initNormalizedSquaredDistances( + const ProximityInfo *const proximityInfo, const int inputSize, + const int *inputXCoordinates, const int *inputYCoordinates, + const int *const inputProximities, const bool hasInputCoordinates, + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + int *normalizedSquaredDistances) { + for (int i = 0; i < inputSize; ++i) { + const int *proximityCodePoints = getProximityCodePointsAt(inputProximities, i); + const int primaryKey = proximityCodePoints[0]; + const int x = inputXCoordinates[i]; + const int y = inputYCoordinates[i]; + if (DEBUG_PROXIMITY_CHARS) { + int a = x + y + primaryKey; + a += 0; + AKLOGI("--- Primary = %c, x = %d, y = %d", primaryKey, x, y); + } + for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE && proximityCodePoints[j] > 0; + ++j) { + const int currentCodePoint = proximityCodePoints[j]; + const float squaredDistance = + hasInputCoordinates ? calculateNormalizedSquaredDistance( + proximityInfo, sampledInputXs, sampledInputYs, + proximityInfo->getKeyIndexOf(currentCodePoint), i) : + ProximityInfoParams::NOT_A_DISTANCE_FLOAT; + if (squaredDistance >= 0.0f) { + normalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE + j] = + (int) (squaredDistance + * ProximityInfoParams::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR); + } else { + normalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE + j] = + (j == 0) ? EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO : + PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO; + } + if (DEBUG_PROXIMITY_CHARS) { + AKLOGI("--- Proximity (%d) = %c", j, currentCodePoint); + } + } + } + +} + +/* static */ void ProximityInfoStateUtils::initGeometricDistanceInfos( + const ProximityInfo *const proximityInfo, const int keyCount, + const int sampledInputSize, const int lastSavedInputSize, + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + std::vector<NearKeycodesSet> *nearKeysVector, + std::vector<NearKeycodesSet> *searchKeysVector, + std::vector<float> *distanceCache_G) { + nearKeysVector->resize(sampledInputSize); + searchKeysVector->resize(sampledInputSize); + distanceCache_G->resize(sampledInputSize * keyCount); + for (int i = lastSavedInputSize; i < sampledInputSize; ++i) { + (*nearKeysVector)[i].reset(); + (*searchKeysVector)[i].reset(); + static const float NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD = 4.0f; + for (int k = 0; k < keyCount; ++k) { + const int index = i * keyCount + k; + const int x = (*sampledInputXs)[i]; + const int y = (*sampledInputYs)[i]; + const float normalizedSquaredDistance = + proximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y); + (*distanceCache_G)[index] = normalizedSquaredDistance; + if (normalizedSquaredDistance < NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) { + (*nearKeysVector)[i][k] = true; + } + } + } +} + +/* static */ void ProximityInfoStateUtils::popInputData(std::vector<int> *sampledInputXs, + std::vector<int> *sampledInputYs, std::vector<int> *sampledInputTimes, + std::vector<int> *sampledLengthCache, std::vector<int> *sampledInputIndice) { + sampledInputXs->pop_back(); + sampledInputYs->pop_back(); + sampledInputTimes->pop_back(); + sampledLengthCache->pop_back(); + sampledInputIndice->pop_back(); +} + +/* static */ float ProximityInfoStateUtils::refreshSpeedRates(const int inputSize, + const int *const xCoordinates, const int *const yCoordinates, const int *const times, + const int lastSavedInputSize, const int sampledInputSize, + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + const std::vector<int> *const sampledInputTimes, + const std::vector<int> *const sampledLengthCache, + const std::vector<int> *const sampledInputIndice, std::vector<float> *sampledSpeedRates, + std::vector<float> *sampledDirections) { + // Relative speed calculation. + const int sumDuration = sampledInputTimes->back() - sampledInputTimes->front(); + const int sumLength = sampledLengthCache->back() - sampledLengthCache->front(); + const float averageSpeed = static_cast<float>(sumLength) / static_cast<float>(sumDuration); + sampledSpeedRates->resize(sampledInputSize); + for (int i = lastSavedInputSize; i < sampledInputSize; ++i) { + const int index = (*sampledInputIndice)[i]; + int length = 0; + int duration = 0; + + // Calculate velocity by using distances and durations of + // NUM_POINTS_FOR_SPEED_CALCULATION points for both forward and backward. + static const int NUM_POINTS_FOR_SPEED_CALCULATION = 2; + for (int j = index; j < min(inputSize - 1, index + NUM_POINTS_FOR_SPEED_CALCULATION); + ++j) { + if (i < sampledInputSize - 1 && j >= (*sampledInputIndice)[i + 1]) { + break; + } + length += getDistanceInt(xCoordinates[j], yCoordinates[j], + xCoordinates[j + 1], yCoordinates[j + 1]); + duration += times[j + 1] - times[j]; + } + for (int j = index - 1; j >= max(0, index - NUM_POINTS_FOR_SPEED_CALCULATION); --j) { + if (i > 0 && j < (*sampledInputIndice)[i - 1]) { + break; + } + // TODO: use mSampledLengthCache instead? + length += getDistanceInt(xCoordinates[j], yCoordinates[j], + xCoordinates[j + 1], yCoordinates[j + 1]); + duration += times[j + 1] - times[j]; + } + if (duration == 0 || sumDuration == 0) { + // Cannot calculate speed; thus, it gives an average value (1.0); + (*sampledSpeedRates)[i] = 1.0f; + } else { + const float speed = static_cast<float>(length) / static_cast<float>(duration); + (*sampledSpeedRates)[i] = speed / averageSpeed; + } + } + + // Direction calculation. + sampledDirections->resize(sampledInputSize - 1); + for (int i = max(0, lastSavedInputSize - 1); i < sampledInputSize - 1; ++i) { + (*sampledDirections)[i] = getDirection(sampledInputXs, sampledInputYs, i, i + 1); + } + return averageSpeed; +} + +/* static */ void ProximityInfoStateUtils::refreshBeelineSpeedRates(const int mostCommonKeyWidth, + const float averageSpeed, const int inputSize, const int *const xCoordinates, + const int *const yCoordinates, const int *times, const int sampledInputSize, + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, const std::vector<int> *const inputIndice, + std::vector<int> *beelineSpeedPercentiles) { + if (DEBUG_SAMPLING_POINTS) { + AKLOGI("--- refresh beeline speed rates"); + } + beelineSpeedPercentiles->resize(sampledInputSize); + for (int i = 0; i < sampledInputSize; ++i) { + (*beelineSpeedPercentiles)[i] = static_cast<int>(calculateBeelineSpeedRate( + mostCommonKeyWidth, averageSpeed, i, inputSize, xCoordinates, yCoordinates, times, + sampledInputSize, sampledInputXs, sampledInputYs, inputIndice) * MAX_PERCENTILE); + } +} + +/* static */float ProximityInfoStateUtils::getDirection( + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, const int index0, const int index1) { + ASSERT(sampledInputXs && sampledInputYs); + const int sampledInputSize =sampledInputXs->size(); + if (index0 < 0 || index0 > sampledInputSize - 1) { + return 0.0f; + } + if (index1 < 0 || index1 > sampledInputSize - 1) { + return 0.0f; + } + const int x1 = (*sampledInputXs)[index0]; + const int y1 = (*sampledInputYs)[index0]; + const int x2 = (*sampledInputXs)[index1]; + const int y2 = (*sampledInputYs)[index1]; + return getAngle(x1, y1, x2, y2); +} + +// Calculating point to key distance for all near keys and returning the distance between +// the given point and the nearest key position. +/* static */ float ProximityInfoStateUtils::updateNearKeysDistances( + const ProximityInfo *const proximityInfo, const float maxPointToKeyLength, const int x, + const int y, NearKeysDistanceMap *const currentNearKeysDistances) { + static const float NEAR_KEY_THRESHOLD = 2.0f; + + currentNearKeysDistances->clear(); + const int keyCount = proximityInfo->getKeyCount(); + float nearestKeyDistance = maxPointToKeyLength; + for (int k = 0; k < keyCount; ++k) { + const float dist = proximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y); + if (dist < NEAR_KEY_THRESHOLD) { + currentNearKeysDistances->insert(std::pair<int, float>(k, dist)); + } + if (nearestKeyDistance > dist) { + nearestKeyDistance = dist; + } + } + return nearestKeyDistance; +} + +// Check if previous point is at local minimum position to near keys. +/* static */ bool ProximityInfoStateUtils::isPrevLocalMin( + const NearKeysDistanceMap *const currentNearKeysDistances, + const NearKeysDistanceMap *const prevNearKeysDistances, + const NearKeysDistanceMap *const prevPrevNearKeysDistances) { + static const float MARGIN = 0.01f; + + for (NearKeysDistanceMap::const_iterator it = prevNearKeysDistances->begin(); + it != prevNearKeysDistances->end(); ++it) { + NearKeysDistanceMap::const_iterator itPP = prevPrevNearKeysDistances->find(it->first); + NearKeysDistanceMap::const_iterator itC = currentNearKeysDistances->find(it->first); + if ((itPP == prevPrevNearKeysDistances->end() || itPP->second > it->second + MARGIN) + && (itC == currentNearKeysDistances->end() || itC->second > it->second + MARGIN)) { + return true; + } + } + return false; +} + +// Calculating a point score that indicates usefulness of the point. +/* static */ float ProximityInfoStateUtils::getPointScore(const int mostCommonKeyWidth, + const int x, const int y, const int time, const bool lastPoint, const float nearest, + const float sumAngle, const NearKeysDistanceMap *const currentNearKeysDistances, + const NearKeysDistanceMap *const prevNearKeysDistances, + const NearKeysDistanceMap *const prevPrevNearKeysDistances, + std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs) { + static const int DISTANCE_BASE_SCALE = 100; + static const float NEAR_KEY_THRESHOLD = 0.6f; + static const int CORNER_CHECK_DISTANCE_THRESHOLD_SCALE = 25; + static const float NOT_LOCALMIN_DISTANCE_SCORE = -1.0f; + static const float LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE = 1.0f; + static const float CORNER_ANGLE_THRESHOLD = M_PI_F * 2.0f / 3.0f; + static const float CORNER_SUM_ANGLE_THRESHOLD = M_PI_F / 4.0f; + static const float CORNER_SCORE = 1.0f; + + const size_t size = sampledInputXs->size(); + // If there is only one point, add this point. Besides, if the previous point's distance map + // is empty, we re-compute nearby keys distances from the current point. + // Note that the current point is the first point in the incremental input that needs to + // be re-computed. + if (size <= 1 || prevNearKeysDistances->empty()) { + return 0.0f; + } + + const int baseSampleRate = mostCommonKeyWidth; + const int distPrev = getDistanceInt(sampledInputXs->back(), sampledInputYs->back(), + (*sampledInputXs)[size - 2], (*sampledInputYs)[size - 2]) * DISTANCE_BASE_SCALE; + float score = 0.0f; + + // Location + if (!isPrevLocalMin(currentNearKeysDistances, prevNearKeysDistances, + prevPrevNearKeysDistances)) { + score += NOT_LOCALMIN_DISTANCE_SCORE; + } else if (nearest < NEAR_KEY_THRESHOLD) { + // Promote points nearby keys + score += LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE; + } + // Angle + const float angle1 = getAngle(x, y, sampledInputXs->back(), sampledInputYs->back()); + const float angle2 = getAngle(sampledInputXs->back(), sampledInputYs->back(), + (*sampledInputXs)[size - 2], (*sampledInputYs)[size - 2]); + const float angleDiff = getAngleDiff(angle1, angle2); + + // Save corner + if (distPrev > baseSampleRate * CORNER_CHECK_DISTANCE_THRESHOLD_SCALE + && (sumAngle > CORNER_SUM_ANGLE_THRESHOLD || angleDiff > CORNER_ANGLE_THRESHOLD)) { + score += CORNER_SCORE; + } + return score; +} + +// Sampling touch point and pushing information to vectors. +// Returning if previous point is popped or not. +/* static */ bool ProximityInfoStateUtils::pushTouchPoint(const int mostCommonKeyWidth, + const ProximityInfo *const proximityInfo, const int maxPointToKeyLength, + const int inputIndex, const int nodeCodePoint, int x, int y, + const int time, const bool doSampling, const bool isLastPoint, const float sumAngle, + NearKeysDistanceMap *const currentNearKeysDistances, + const NearKeysDistanceMap *const prevNearKeysDistances, + const NearKeysDistanceMap *const prevPrevNearKeysDistances, + std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs, + std::vector<int> *sampledInputTimes, std::vector<int> *sampledLengthCache, + std::vector<int> *sampledInputIndice) { + static const int LAST_POINT_SKIP_DISTANCE_SCALE = 4; + + size_t size = sampledInputXs->size(); + bool popped = false; + if (nodeCodePoint < 0 && doSampling) { + const float nearest = updateNearKeysDistances( + proximityInfo, maxPointToKeyLength, x, y, currentNearKeysDistances); + const float score = getPointScore(mostCommonKeyWidth, x, y, time, isLastPoint, nearest, + sumAngle, currentNearKeysDistances, prevNearKeysDistances, + prevPrevNearKeysDistances, sampledInputXs, sampledInputYs); + if (score < 0) { + // Pop previous point because it would be useless. + popInputData(sampledInputXs, sampledInputYs, sampledInputTimes, sampledLengthCache, + sampledInputIndice); + size = sampledInputXs->size(); + popped = true; + } else { + popped = false; + } + // Check if the last point should be skipped. + if (isLastPoint && size > 0) { + if (getDistanceInt(x, y, sampledInputXs->back(), + sampledInputYs->back()) * LAST_POINT_SKIP_DISTANCE_SCALE + < mostCommonKeyWidth) { + // This point is not used because it's too close to the previous point. + if (DEBUG_GEO_FULL) { + AKLOGI("p0: size = %zd, x = %d, y = %d, lx = %d, ly = %d, dist = %d, " + "width = %d", size, x, y, sampledInputXs->back(), + sampledInputYs->back(), getDistanceInt( + x, y, sampledInputXs->back(), sampledInputYs->back()), + mostCommonKeyWidth / LAST_POINT_SKIP_DISTANCE_SCALE); + } + return popped; + } + } + } + + if (nodeCodePoint >= 0 && (x < 0 || y < 0)) { + const int keyId = proximityInfo->getKeyIndexOf(nodeCodePoint); + if (keyId >= 0) { + x = proximityInfo->getKeyCenterXOfKeyIdG(keyId); + y = proximityInfo->getKeyCenterYOfKeyIdG(keyId); + } + } + + // Pushing point information. + if (size > 0) { + sampledLengthCache->push_back( + sampledLengthCache->back() + getDistanceInt( + x, y, sampledInputXs->back(), sampledInputYs->back())); + } else { + sampledLengthCache->push_back(0); + } + sampledInputXs->push_back(x); + sampledInputYs->push_back(y); + sampledInputTimes->push_back(time); + sampledInputIndice->push_back(inputIndex); + if (DEBUG_GEO_FULL) { + AKLOGI("pushTouchPoint: x = %03d, y = %03d, time = %d, index = %d, popped ? %01d", + x, y, time, inputIndex, popped); + } + return popped; +} + +/* static */ float ProximityInfoStateUtils::calculateBeelineSpeedRate(const int mostCommonKeyWidth, + const float averageSpeed, const int id, const int inputSize, const int *const xCoordinates, + const int *const yCoordinates, const int *times, const int sampledInputSize, + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + const std::vector<int> *const sampledInputIndices) { + if (sampledInputSize <= 0 || averageSpeed < 0.001f) { + if (DEBUG_SAMPLING_POINTS) { + AKLOGI("--- invalid state: cancel. size = %d, ave = %f", + sampledInputSize, averageSpeed); + } + return 1.0f; + } + const int lookupRadius = mostCommonKeyWidth + * ProximityInfoParams::LOOKUP_RADIUS_PERCENTILE / MAX_PERCENTILE; + const int x0 = (*sampledInputXs)[id]; + const int y0 = (*sampledInputYs)[id]; + const int actualInputIndex = (*sampledInputIndices)[id]; + int tempTime = 0; + int tempBeelineDistance = 0; + int start = actualInputIndex; + // lookup forward + while (start > 0 && tempBeelineDistance < lookupRadius) { + tempTime += times[start] - times[start - 1]; + --start; + tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[start], yCoordinates[start]); + } + // Exclusive unless this is an edge point + if (start > 0 && start < actualInputIndex) { + ++start; + } + tempTime= 0; + tempBeelineDistance = 0; + int end = actualInputIndex; + // lookup backward + while (end < (inputSize - 1) && tempBeelineDistance < lookupRadius) { + tempTime += times[end + 1] - times[end]; + ++end; + tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[end], yCoordinates[end]); + } + // Exclusive unless this is an edge point + if (end > actualInputIndex && end < (inputSize - 1)) { + --end; + } + + if (start >= end) { + if (DEBUG_DOUBLE_LETTER) { + AKLOGI("--- double letter: start == end %d", start); + } + return 1.0f; + } + + const int x2 = xCoordinates[start]; + const int y2 = yCoordinates[start]; + const int x3 = xCoordinates[end]; + const int y3 = yCoordinates[end]; + const int beelineDistance = getDistanceInt(x2, y2, x3, y3); + int adjustedStartTime = times[start]; + if (start == 0 && actualInputIndex == 0 && inputSize > 1) { + adjustedStartTime += ProximityInfoParams::FIRST_POINT_TIME_OFFSET_MILLIS; + } + int adjustedEndTime = times[end]; + if (end == (inputSize - 1) && inputSize > 1) { + adjustedEndTime -= ProximityInfoParams::FIRST_POINT_TIME_OFFSET_MILLIS; + } + const int time = adjustedEndTime - adjustedStartTime; + if (time <= 0) { + return 1.0f; + } + + if (time >= ProximityInfoParams::STRONG_DOUBLE_LETTER_TIME_MILLIS){ + return 0.0f; + } + if (DEBUG_DOUBLE_LETTER) { + AKLOGI("--- (%d, %d) double letter: start = %d, end = %d, dist = %d, time = %d," + " speed = %f, ave = %f, val = %f, start time = %d, end time = %d", + id, (*sampledInputIndices)[id], start, end, beelineDistance, time, + (static_cast<float>(beelineDistance) / static_cast<float>(time)), averageSpeed, + ((static_cast<float>(beelineDistance) / static_cast<float>(time)) + / averageSpeed), adjustedStartTime, adjustedEndTime); + } + // Offset 1% + // TODO: Detect double letter more smartly + return 0.01f + static_cast<float>(beelineDistance) / static_cast<float>(time) / averageSpeed; +} + +/* static */ float ProximityInfoStateUtils::getPointAngle( + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, const int index) { + if (!sampledInputXs || !sampledInputYs) { + return 0.0f; + } + const int sampledInputSize = sampledInputXs->size(); + if (index <= 0 || index >= sampledInputSize - 1) { + return 0.0f; + } + const float previousDirection = getDirection(sampledInputXs, sampledInputYs, index - 1, index); + const float nextDirection = getDirection(sampledInputXs, sampledInputYs, index, index + 1); + const float directionDiff = getAngleDiff(previousDirection, nextDirection); + return directionDiff; +} + +/* static */ float ProximityInfoStateUtils::getPointsAngle( + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + const int index0, const int index1, const int index2) { + if (!sampledInputXs || !sampledInputYs) { + return 0.0f; + } + const int sampledInputSize = sampledInputXs->size(); + if (index0 < 0 || index0 > sampledInputSize - 1) { + return 0.0f; + } + if (index1 < 0 || index1 > sampledInputSize - 1) { + return 0.0f; + } + if (index2 < 0 || index2 > sampledInputSize - 1) { + return 0.0f; + } + const float previousDirection = getDirection(sampledInputXs, sampledInputYs, index0, index1); + const float nextDirection = getDirection(sampledInputXs, sampledInputYs, index1, index2); + return getAngleDiff(previousDirection, nextDirection); +} + +// TODO: Remove the "scale" parameter +// This function basically converts from a length to an edit distance. Accordingly, it's obviously +// wrong to compare with mMaxPointToKeyLength. +/* static */ float ProximityInfoStateUtils::getPointToKeyByIdLength(const float maxPointToKeyLength, + const std::vector<float> *const distanceCache_G, const int keyCount, + const int inputIndex, const int keyId, const float scale) { + if (keyId != NOT_AN_INDEX) { + const int index = inputIndex * keyCount + keyId; + return min((*distanceCache_G)[index] * scale, maxPointToKeyLength); + } + // If the char is not a key on the keyboard then return the max length. + return static_cast<float>(MAX_POINT_TO_KEY_LENGTH); +} + +/* static */ float ProximityInfoStateUtils::getPointToKeyByIdLength(const float maxPointToKeyLength, + const std::vector<float> *const distanceCache_G, const int keyCount, + const int inputIndex, const int keyId) { + return getPointToKeyByIdLength(maxPointToKeyLength, distanceCache_G, keyCount, inputIndex, + keyId, 1.0f); +} + +// Updates probabilities of aligning to some keys and skipping. +// Word suggestion should be based on this probabilities. +/* static */ void ProximityInfoStateUtils::updateAlignPointProbabilities( + const float maxPointToKeyLength, const int mostCommonKeyWidth, const int keyCount, + const int start, const int sampledInputSize, const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + const std::vector<float> *const sampledSpeedRates, + const std::vector<int> *const sampledLengthCache, + const std::vector<float> *const distanceCache_G, + std::vector<NearKeycodesSet> *nearKeysVector, + std::vector<hash_map_compat<int, float> > *charProbabilities) { + static const float MIN_PROBABILITY = 0.000001f; + static const float MAX_SKIP_PROBABILITY = 0.95f; + static const float SKIP_FIRST_POINT_PROBABILITY = 0.01f; + static const float SKIP_LAST_POINT_PROBABILITY = 0.1f; + static const float MIN_SPEED_RATE_FOR_SKIP_PROBABILITY = 0.15f; + static const float SPEED_WEIGHT_FOR_SKIP_PROBABILITY = 0.9f; + static const float SLOW_STRAIGHT_WEIGHT_FOR_SKIP_PROBABILITY = 0.6f; + static const float NEAREST_DISTANCE_WEIGHT = 0.5f; + static const float NEAREST_DISTANCE_BIAS = 0.5f; + static const float NEAREST_DISTANCE_WEIGHT_FOR_LAST = 0.6f; + static const float NEAREST_DISTANCE_BIAS_FOR_LAST = 0.4f; + + static const float ANGLE_WEIGHT = 0.90f; + static const float DEEP_CORNER_ANGLE_THRESHOLD = M_PI_F * 60.0f / 180.0f; + static const float SKIP_DEEP_CORNER_PROBABILITY = 0.1f; + static const float CORNER_ANGLE_THRESHOLD = M_PI_F * 30.0f / 180.0f; + static const float STRAIGHT_ANGLE_THRESHOLD = M_PI_F * 15.0f / 180.0f; + static const float SKIP_CORNER_PROBABILITY = 0.4f; + static const float SPEED_MARGIN = 0.1f; + static const float CENTER_VALUE_OF_NORMALIZED_DISTRIBUTION = 0.0f; + + charProbabilities->resize(sampledInputSize); + // Calculates probabilities of using a point as a correlated point with the character + // for each point. + for (int i = start; i < sampledInputSize; ++i) { + (*charProbabilities)[i].clear(); + // First, calculates skip probability. Starts form MIN_SKIP_PROBABILITY. + // Note that all values that are multiplied to this probability should be in [0.0, 1.0]; + float skipProbability = MAX_SKIP_PROBABILITY; + + const float currentAngle = getPointAngle(sampledInputXs, sampledInputYs, i); + const float speedRate = (*sampledSpeedRates)[i]; + + float nearestKeyDistance = static_cast<float>(MAX_POINT_TO_KEY_LENGTH); + for (int j = 0; j < keyCount; ++j) { + if ((*nearKeysVector)[i].test(j)) { + const float distance = getPointToKeyByIdLength( + maxPointToKeyLength, distanceCache_G, keyCount, i, j); + if (distance < nearestKeyDistance) { + nearestKeyDistance = distance; + } + } + } + + if (i == 0) { + skipProbability *= min(1.0f, nearestKeyDistance * NEAREST_DISTANCE_WEIGHT + + NEAREST_DISTANCE_BIAS); + // Promote the first point + skipProbability *= SKIP_FIRST_POINT_PROBABILITY; + } else if (i == sampledInputSize - 1) { + skipProbability *= min(1.0f, nearestKeyDistance * NEAREST_DISTANCE_WEIGHT_FOR_LAST + + NEAREST_DISTANCE_BIAS_FOR_LAST); + // Promote the last point + skipProbability *= SKIP_LAST_POINT_PROBABILITY; + } else { + // If the current speed is relatively slower than adjacent keys, we promote this point. + if ((*sampledSpeedRates)[i - 1] - SPEED_MARGIN > speedRate + && speedRate < (*sampledSpeedRates)[i + 1] - SPEED_MARGIN) { + if (currentAngle < CORNER_ANGLE_THRESHOLD) { + skipProbability *= min(1.0f, speedRate + * SLOW_STRAIGHT_WEIGHT_FOR_SKIP_PROBABILITY); + } else { + // If the angle is small enough, we promote this point more. (e.g. pit vs put) + skipProbability *= min(1.0f, speedRate * SPEED_WEIGHT_FOR_SKIP_PROBABILITY + + MIN_SPEED_RATE_FOR_SKIP_PROBABILITY); + } + } + + skipProbability *= min(1.0f, speedRate * nearestKeyDistance * + NEAREST_DISTANCE_WEIGHT + NEAREST_DISTANCE_BIAS); + + // Adjusts skip probability by a rate depending on angle. + // ANGLE_RATE of skipProbability is adjusted by current angle. + skipProbability *= (M_PI_F - currentAngle) / M_PI_F * ANGLE_WEIGHT + + (1.0f - ANGLE_WEIGHT); + if (currentAngle > DEEP_CORNER_ANGLE_THRESHOLD) { + skipProbability *= SKIP_DEEP_CORNER_PROBABILITY; + } + // We assume the angle of this point is the angle for point[i], point[i - 2] + // and point[i - 3]. The reason why we don't use the angle for point[i], point[i - 1] + // and point[i - 2] is this angle can be more affected by the noise. + const float prevAngle = getPointsAngle(sampledInputXs, sampledInputYs, i, i - 2, i - 3); + if (i >= 3 && prevAngle < STRAIGHT_ANGLE_THRESHOLD + && currentAngle > CORNER_ANGLE_THRESHOLD) { + skipProbability *= SKIP_CORNER_PROBABILITY; + } + } + + // probabilities must be in [0.0, MAX_SKIP_PROBABILITY]; + ASSERT(skipProbability >= 0.0f); + ASSERT(skipProbability <= MAX_SKIP_PROBABILITY); + (*charProbabilities)[i][NOT_AN_INDEX] = skipProbability; + + // Second, calculates key probabilities by dividing the rest probability + // (1.0f - skipProbability). + const float inputCharProbability = 1.0f - skipProbability; + + // TODO: The variance is critical for accuracy; thus, adjusting these parameter by machine + // learning or something would be efficient. + static const float SPEEDxANGLE_WEIGHT_FOR_STANDARD_DIVIATION = 0.3f; + static const float MAX_SPEEDxANGLE_RATE_FOR_STANDERD_DIVIATION = 0.25f; + static const float SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DIVIATION = 0.5f; + static const float MAX_SPEEDxNEAREST_RATE_FOR_STANDERD_DIVIATION = 0.15f; + static const float MIN_STANDERD_DIVIATION = 0.37f; + + const float speedxAngleRate = min(speedRate * currentAngle / M_PI_F + * SPEEDxANGLE_WEIGHT_FOR_STANDARD_DIVIATION, + MAX_SPEEDxANGLE_RATE_FOR_STANDERD_DIVIATION); + const float speedxNearestKeyDistanceRate = min(speedRate * nearestKeyDistance + * SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DIVIATION, + MAX_SPEEDxNEAREST_RATE_FOR_STANDERD_DIVIATION); + const float sigma = speedxAngleRate + speedxNearestKeyDistanceRate + MIN_STANDERD_DIVIATION; + + ProximityInfoUtils::NormalDistribution + distribution(CENTER_VALUE_OF_NORMALIZED_DISTRIBUTION, sigma); + static const float PREV_DISTANCE_WEIGHT = 0.5f; + static const float NEXT_DISTANCE_WEIGHT = 0.6f; + // Summing up probability densities of all near keys. + float sumOfProbabilityDensities = 0.0f; + for (int j = 0; j < keyCount; ++j) { + if ((*nearKeysVector)[i].test(j)) { + float distance = sqrtf(getPointToKeyByIdLength( + maxPointToKeyLength, distanceCache_G, keyCount, i, j)); + if (i == 0 && i != sampledInputSize - 1) { + // For the first point, weighted average of distances from first point and the + // next point to the key is used as a point to key distance. + const float nextDistance = sqrtf(getPointToKeyByIdLength( + maxPointToKeyLength, distanceCache_G, keyCount, i + 1, j)); + if (nextDistance < distance) { + // The distance of the first point tends to bigger than continuing + // points because the first touch by the user can be sloppy. + // So we promote the first point if the distance of that point is larger + // than the distance of the next point. + distance = (distance + nextDistance * NEXT_DISTANCE_WEIGHT) + / (1.0f + NEXT_DISTANCE_WEIGHT); + } + } else if (i != 0 && i == sampledInputSize - 1) { + // For the first point, weighted average of distances from last point and + // the previous point to the key is used as a point to key distance. + const float previousDistance = sqrtf(getPointToKeyByIdLength( + maxPointToKeyLength, distanceCache_G, keyCount, i - 1, j)); + if (previousDistance < distance) { + // The distance of the last point tends to bigger than continuing points + // because the last touch by the user can be sloppy. So we promote the + // last point if the distance of that point is larger than the distance of + // the previous point. + distance = (distance + previousDistance * PREV_DISTANCE_WEIGHT) + / (1.0f + PREV_DISTANCE_WEIGHT); + } + } + // TODO: Promote the first point when the extended line from the next input is near + // from a key. Also, promote the last point as well. + sumOfProbabilityDensities += distribution.getProbabilityDensity(distance); + } + } + + // Split the probability of an input point to keys that are close to the input point. + for (int j = 0; j < keyCount; ++j) { + if ((*nearKeysVector)[i].test(j)) { + float distance = sqrtf(getPointToKeyByIdLength( + maxPointToKeyLength, distanceCache_G, keyCount, i, j)); + if (i == 0 && i != sampledInputSize - 1) { + // For the first point, weighted average of distances from the first point and + // the next point to the key is used as a point to key distance. + const float prevDistance = sqrtf(getPointToKeyByIdLength( + maxPointToKeyLength, distanceCache_G, keyCount, i + 1, j)); + if (prevDistance < distance) { + distance = (distance + prevDistance * NEXT_DISTANCE_WEIGHT) + / (1.0f + NEXT_DISTANCE_WEIGHT); + } + } else if (i != 0 && i == sampledInputSize - 1) { + // For the first point, weighted average of distances from last point and + // the previous point to the key is used as a point to key distance. + const float prevDistance = sqrtf(getPointToKeyByIdLength( + maxPointToKeyLength, distanceCache_G, keyCount, i - 1, j)); + if (prevDistance < distance) { + distance = (distance + prevDistance * PREV_DISTANCE_WEIGHT) + / (1.0f + PREV_DISTANCE_WEIGHT); + } + } + const float probabilityDensity = distribution.getProbabilityDensity(distance); + const float probability = inputCharProbability * probabilityDensity + / sumOfProbabilityDensities; + (*charProbabilities)[i][j] = probability; + } + } + } + + if (DEBUG_POINTS_PROBABILITY) { + for (int i = 0; i < sampledInputSize; ++i) { + std::stringstream sstream; + sstream << i << ", "; + sstream << "(" << (*sampledInputXs)[i] << ", " << (*sampledInputYs)[i] << "), "; + sstream << "Speed: "<< (*sampledSpeedRates)[i] << ", "; + sstream << "Angle: "<< getPointAngle(sampledInputXs, sampledInputYs, i) << ", \n"; + + for (hash_map_compat<int, float>::iterator it = (*charProbabilities)[i].begin(); + it != (*charProbabilities)[i].end(); ++it) { + if (it->first == NOT_AN_INDEX) { + sstream << it->first + << "(skip):" + << it->second + << "\n"; + } else { + sstream << it->first + << "(" + //<< static_cast<char>(mProximityInfo->getCodePointOf(it->first)) + << "):" + << it->second + << "\n"; + } + } + AKLOGI("%s", sstream.str().c_str()); + } + } + + // Decrease key probabilities of points which don't have the highest probability of that key + // among nearby points. Probabilities of the first point and the last point are not suppressed. + for (int i = max(start, 1); i < sampledInputSize; ++i) { + for (int j = i + 1; j < sampledInputSize; ++j) { + if (!suppressCharProbabilities( + mostCommonKeyWidth, sampledInputSize, sampledLengthCache, i, j, + charProbabilities)) { + break; + } + } + for (int j = i - 1; j >= max(start, 0); --j) { + if (!suppressCharProbabilities( + mostCommonKeyWidth, sampledInputSize, sampledLengthCache, i, j, + charProbabilities)) { + break; + } + } + } + + // Converting from raw probabilities to log probabilities to calculate spatial distance. + for (int i = start; i < sampledInputSize; ++i) { + for (int j = 0; j < keyCount; ++j) { + hash_map_compat<int, float>::iterator it = (*charProbabilities)[i].find(j); + if (it == (*charProbabilities)[i].end()){ + (*nearKeysVector)[i].reset(j); + } else if(it->second < MIN_PROBABILITY) { + // Erases from near keys vector because it has very low probability. + (*nearKeysVector)[i].reset(j); + (*charProbabilities)[i].erase(j); + } else { + it->second = -logf(it->second); + } + } + (*charProbabilities)[i][NOT_AN_INDEX] = -logf((*charProbabilities)[i][NOT_AN_INDEX]); + } +} + +/* static */ void ProximityInfoStateUtils::updateSearchKeysVector( + const ProximityInfo *const proximityInfo, const int sampledInputSize, + const int lastSavedInputSize, + const std::vector<int> *const sampledLengthCache, + const std::vector<NearKeycodesSet> *const nearKeysVector, + std::vector<NearKeycodesSet> *searchKeysVector) { + const int readForwordLength = static_cast<int>( + hypotf(proximityInfo->getKeyboardWidth(), proximityInfo->getKeyboardHeight()) + * ProximityInfoParams::SEARCH_KEY_RADIUS_RATIO); + for (int i = 0; i < sampledInputSize; ++i) { + if (i >= lastSavedInputSize) { + (*searchKeysVector)[i].reset(); + } + for (int j = max(i, lastSavedInputSize); j < sampledInputSize; ++j) { + // TODO: Investigate if this is required. This may not fail. + if ((*sampledLengthCache)[j] - (*sampledLengthCache)[i] >= readForwordLength) { + break; + } + (*searchKeysVector)[i] |= (*nearKeysVector)[j]; + } + } +} + +// Decreases char probabilities of index0 by checking probabilities of a near point (index1) and +// increases char probabilities of index1 by checking probabilities of index0. +/* static */ bool ProximityInfoStateUtils::suppressCharProbabilities(const int mostCommonKeyWidth, + const int sampledInputSize, const std::vector<int> *const lengthCache, + const int index0, const int index1, + std::vector<hash_map_compat<int, float> > *charProbabilities) { + ASSERT(0 <= index0 && index0 < sampledInputSize); + ASSERT(0 <= index1 && index1 < sampledInputSize); + + static const float SUPPRESSION_LENGTH_WEIGHT = 1.5f; + static const float MIN_SUPPRESSION_RATE = 0.1f; + static const float SUPPRESSION_WEIGHT = 0.5f; + static const float SUPPRESSION_WEIGHT_FOR_PROBABILITY_GAIN = 0.1f; + static const float SKIP_PROBABALITY_WEIGHT_FOR_PROBABILITY_GAIN = 0.3f; + + const float keyWidthFloat = static_cast<float>(mostCommonKeyWidth); + const float diff = fabsf(static_cast<float>((*lengthCache)[index0] - (*lengthCache)[index1])); + if (diff > keyWidthFloat * SUPPRESSION_LENGTH_WEIGHT) { + return false; + } + const float suppressionRate = MIN_SUPPRESSION_RATE + + diff / keyWidthFloat / SUPPRESSION_LENGTH_WEIGHT * SUPPRESSION_WEIGHT; + for (hash_map_compat<int, float>::iterator it = (*charProbabilities)[index0].begin(); + it != (*charProbabilities)[index0].end(); ++it) { + hash_map_compat<int, float>::iterator it2 = (*charProbabilities)[index1].find(it->first); + if (it2 != (*charProbabilities)[index1].end() && it->second < it2->second) { + const float newProbability = it->second * suppressionRate; + const float suppression = it->second - newProbability; + it->second = newProbability; + // mCharProbabilities[index0][NOT_AN_INDEX] is the probability of skipping this point. + (*charProbabilities)[index0][NOT_AN_INDEX] += suppression; + + // Add the probability of the same key nearby index1 + const float probabilityGain = min(suppression * SUPPRESSION_WEIGHT_FOR_PROBABILITY_GAIN, + (*charProbabilities)[index1][NOT_AN_INDEX] + * SKIP_PROBABALITY_WEIGHT_FOR_PROBABILITY_GAIN); + it2->second += probabilityGain; + (*charProbabilities)[index1][NOT_AN_INDEX] -= probabilityGain; + } + } + return true; +} + +/* static */ void ProximityInfoStateUtils::dump(const bool isGeometric, const int inputSize, + const int *const inputXCoordinates, const int *const inputYCoordinates, + const int sampledInputSize, const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + const std::vector<int> *const sampledTimes, + const std::vector<float> *const sampledSpeedRates, + const std::vector<int> *const sampledBeelineSpeedPercentiles) { + if (DEBUG_GEO_FULL) { + for (int i = 0; i < sampledInputSize; ++i) { + AKLOGI("Sampled(%d): x = %d, y = %d, time = %d", i, (*sampledInputXs)[i], + (*sampledInputYs)[i], sampledTimes ? (*sampledTimes)[i] : -1); + } + } + + std::stringstream originalX, originalY, sampledX, sampledY; + for (int i = 0; i < inputSize; ++i) { + originalX << inputXCoordinates[i]; + originalY << inputYCoordinates[i]; + if (i != inputSize - 1) { + originalX << ";"; + originalY << ";"; + } + } + AKLOGI("===== sampled points ====="); + for (int i = 0; i < sampledInputSize; ++i) { + if (isGeometric) { + AKLOGI("%d: x = %d, y = %d, time = %d, relative speed = %.4f, beeline speed = %d", + i, (*sampledInputXs)[i], (*sampledInputYs)[i], (*sampledTimes)[i], + (*sampledSpeedRates)[i], (*sampledBeelineSpeedPercentiles)[i]); + } + sampledX << (*sampledInputXs)[i]; + sampledY << (*sampledInputYs)[i]; + if (i != sampledInputSize - 1) { + sampledX << ";"; + sampledY << ";"; + } + } + AKLOGI("original points:\n%s, %s,\nsampled points:\n%s, %s,\n", + originalX.str().c_str(), originalY.str().c_str(), sampledX.str().c_str(), + sampledY.str().c_str()); +} +} // namespace latinime diff --git a/native/jni/src/proximity_info_state_utils.h b/native/jni/src/proximity_info_state_utils.h index 53b992a2a..b70121ad2 100644 --- a/native/jni/src/proximity_info_state_utils.h +++ b/native/jni/src/proximity_info_state_utils.h @@ -17,16 +17,21 @@ #ifndef LATINIME_PROXIMITY_INFO_STATE_UTILS_H #define LATINIME_PROXIMITY_INFO_STATE_UTILS_H +#include <bitset> #include <vector> #include "defines.h" -#include "geometry_utils.h" #include "hash_map_compat.h" -#include "proximity_info.h" namespace latinime { +class ProximityInfo; +class ProximityInfoParams; + class ProximityInfoStateUtils { public: + typedef hash_map_compat<int, float> NearKeysDistanceMap; + typedef std::bitset<MAX_KEY_COUNT_IN_A_KEYBOARD> NearKeycodesSet; + static int updateTouchPoints(const int mostCommonKeyWidth, const ProximityInfo *const proximityInfo, const int maxPointToKeyLength, const int *const inputProximities, @@ -35,285 +40,123 @@ class ProximityInfoStateUtils { const bool isGeometric, const int pointerId, const int pushTouchPointStartIndex, std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs, std::vector<int> *sampledInputTimes, std::vector<int> *sampledLengthCache, - std::vector<int> *sampledInputIndice) { - if (DEBUG_SAMPLING_POINTS) { - if (times) { - for (int i = 0; i < inputSize; ++i) { - AKLOGI("(%d) x %d, y %d, time %d", - i, xCoordinates[i], yCoordinates[i], times[i]); - } - } - } -#ifdef DO_ASSERT_TEST - if (times) { - for (int i = 0; i < inputSize; ++i) { - if (i > 0) { - ASSERT(times[i] >= times[i - 1]); - } - } - } -#endif - const bool proximityOnly = !isGeometric - && (inputXCoordinates[0] < 0 || inputYCoordinates[0] < 0); - int lastInputIndex = pushTouchPointStartIndex; - for (int i = lastInputIndex; i < inputSize; ++i) { - const int pid = pointerIds ? pointerIds[i] : 0; - if (pointerId == pid) { - lastInputIndex = i; - } - } - if (DEBUG_GEO_FULL) { - AKLOGI("Init ProximityInfoState: last input index = %d", lastInputIndex); - } - // Working space to save near keys distances for current, prev and prevprev input point. - NearKeysDistanceMap nearKeysDistances[3]; - // These pointers are swapped for each inputs points. - NearKeysDistanceMap *currentNearKeysDistances = &nearKeysDistances[0]; - NearKeysDistanceMap *prevNearKeysDistances = &nearKeysDistances[1]; - NearKeysDistanceMap *prevPrevNearKeysDistances = &nearKeysDistances[2]; - // "sumAngle" is accumulated by each angle of input points. And when "sumAngle" exceeds - // the threshold we save that point, reset sumAngle. This aims to keep the figure of - // the curve. - float sumAngle = 0.0f; - - for (int i = pushTouchPointStartIndex; i <= lastInputIndex; ++i) { - // Assuming pointerId == 0 if pointerIds is null. - const int pid = pointerIds ? pointerIds[i] : 0; - if (DEBUG_GEO_FULL) { - AKLOGI("Init ProximityInfoState: (%d)PID = %d", i, pid); - } - if (pointerId == pid) { - const int c = isGeometric ? - NOT_A_COORDINATE : getPrimaryCodePointAt(inputProximities, i); - const int x = proximityOnly ? NOT_A_COORDINATE : inputXCoordinates[i]; - const int y = proximityOnly ? NOT_A_COORDINATE : inputYCoordinates[i]; - const int time = times ? times[i] : -1; - - if (i > 1) { - const float prevAngle = getAngle( - inputXCoordinates[i - 2], inputYCoordinates[i - 2], - inputXCoordinates[i - 1], inputYCoordinates[i - 1]); - const float currentAngle = - getAngle(inputXCoordinates[i - 1], inputYCoordinates[i - 1], x, y); - sumAngle += getAngleDiff(prevAngle, currentAngle); - } - - if (pushTouchPoint(mostCommonKeyWidth, proximityInfo, maxPointToKeyLength, - i, c, x, y, time, isGeometric /* do sampling */, - i == lastInputIndex, sumAngle, currentNearKeysDistances, - prevNearKeysDistances, prevPrevNearKeysDistances, - sampledInputXs, sampledInputYs, sampledInputTimes, sampledLengthCache, - sampledInputIndice)) { - // Previous point information was popped. - NearKeysDistanceMap *tmp = prevNearKeysDistances; - prevNearKeysDistances = currentNearKeysDistances; - currentNearKeysDistances = tmp; - } else { - NearKeysDistanceMap *tmp = prevPrevNearKeysDistances; - prevPrevNearKeysDistances = prevNearKeysDistances; - prevNearKeysDistances = currentNearKeysDistances; - currentNearKeysDistances = tmp; - sumAngle = 0.0f; - } - } - } - return sampledInputXs->size(); - } - - static const int *getProximityCodePointsAt( - const int *const inputProximities, const int index) { - return inputProximities + (index * MAX_PROXIMITY_CHARS_SIZE_INTERNAL); - } - - static int getPrimaryCodePointAt(const int *const inputProximities, const int index) { - return getProximityCodePointsAt(inputProximities, index)[0]; - } - + std::vector<int> *sampledInputIndice); + static const int *getProximityCodePointsAt(const int *const inputProximities, const int index); + static int getPrimaryCodePointAt(const int *const inputProximities, const int index); static void popInputData(std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs, std::vector<int> *sampledInputTimes, std::vector<int> *sampledLengthCache, - std::vector<int> *sampledInputIndice) { - sampledInputXs->pop_back(); - sampledInputYs->pop_back(); - sampledInputTimes->pop_back(); - sampledLengthCache->pop_back(); - sampledInputIndice->pop_back(); - } - + std::vector<int> *sampledInputIndice); + static float refreshSpeedRates(const int inputSize, const int *const xCoordinates, + const int *const yCoordinates, const int *const times, const int lastSavedInputSize, + const int sampledInputSize, const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + const std::vector<int> *const sampledInputTimes, + const std::vector<int> *const sampledLengthCache, + const std::vector<int> *const sampledInputIndice, + std::vector<float> *sampledSpeedRates, std::vector<float> *sampledDirections); + static void refreshBeelineSpeedRates(const int mostCommonKeyWidth, const float averageSpeed, + const int inputSize, const int *const xCoordinates, const int *const yCoordinates, + const int *times, const int sampledInputSize, + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, const std::vector<int> *const inputIndice, + std::vector<int> *beelineSpeedPercentiles); + static float getDirection(const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, const int index0, const int index1); + static void updateAlignPointProbabilities( + const float maxPointToKeyLength, const int mostCommonKeyWidth, const int keyCount, + const int start, const int sampledInputSize, + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + const std::vector<float> *const sampledSpeedRates, + const std::vector<int> *const sampledLengthCache, + const std::vector<float> *const distanceCache_G, + std::vector<NearKeycodesSet> *nearKeysVector, + std::vector<hash_map_compat<int, float> > *charProbabilities); + static void updateSearchKeysVector( + const ProximityInfo *const proximityInfo, const int sampledInputSize, + const int lastSavedInputSize, + const std::vector<int> *const sampledLengthCache, + const std::vector<NearKeycodesSet> *const nearKeysVector, + std::vector<NearKeycodesSet> *searchKeysVector); + static float getPointToKeyByIdLength(const float maxPointToKeyLength, + const std::vector<float> *const distanceCache_G, const int keyCount, + const int inputIndex, const int keyId, const float scale); + static float getPointToKeyByIdLength(const float maxPointToKeyLength, + const std::vector<float> *const distanceCache_G, const int keyCount, + const int inputIndex, const int keyId); + static void initGeometricDistanceInfos( + const ProximityInfo *const proximityInfo, const int keyCount, + const int sampledInputSize, const int lastSavedInputSize, + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + std::vector<NearKeycodesSet> *nearKeysVector, + std::vector<NearKeycodesSet> *searchKeysVector, + std::vector<float> *distanceCache_G); + static void initPrimaryInputWord( + const int inputSize, const int *const inputProximities, int *primaryInputWord); + static void initNormalizedSquaredDistances( + const ProximityInfo *const proximityInfo, const int inputSize, + const int *inputXCoordinates, const int *inputYCoordinates, + const int *const inputProximities, const bool hasInputCoordinates, + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + int *normalizedSquaredDistances); + static void dump(const bool isGeometric, const int inputSize, + const int *const inputXCoordinates, const int *const inputYCoordinates, + const int sampledInputSize, const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + const std::vector<int> *const sampledTimes, + const std::vector<float> *const sampledSpeedRates, + const std::vector<int> *const sampledBeelineSpeedPercentiles); private: DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfoStateUtils); - typedef hash_map_compat<int, float> NearKeysDistanceMap; - - // Calculating point to key distance for all near keys and returning the distance between - // the given point and the nearest key position. static float updateNearKeysDistances(const ProximityInfo *const proximityInfo, const float maxPointToKeyLength, const int x, const int y, - NearKeysDistanceMap *const currentNearKeysDistances) { - static const float NEAR_KEY_THRESHOLD = 2.0f; - - currentNearKeysDistances->clear(); - const int keyCount = proximityInfo->getKeyCount(); - float nearestKeyDistance = maxPointToKeyLength; - for (int k = 0; k < keyCount; ++k) { - const float dist = proximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y); - if (dist < NEAR_KEY_THRESHOLD) { - currentNearKeysDistances->insert(std::pair<int, float>(k, dist)); - } - if (nearestKeyDistance > dist) { - nearestKeyDistance = dist; - } - } - return nearestKeyDistance; - } - - // Check if previous point is at local minimum position to near keys. + NearKeysDistanceMap *const currentNearKeysDistances); static bool isPrevLocalMin(const NearKeysDistanceMap *const currentNearKeysDistances, const NearKeysDistanceMap *const prevNearKeysDistances, - const NearKeysDistanceMap *const prevPrevNearKeysDistances) { - static const float MARGIN = 0.01f; - - for (NearKeysDistanceMap::const_iterator it = prevNearKeysDistances->begin(); - it != prevNearKeysDistances->end(); ++it) { - NearKeysDistanceMap::const_iterator itPP = prevPrevNearKeysDistances->find(it->first); - NearKeysDistanceMap::const_iterator itC = currentNearKeysDistances->find(it->first); - if ((itPP == prevPrevNearKeysDistances->end() || itPP->second > it->second + MARGIN) - && (itC == currentNearKeysDistances->end() - || itC->second > it->second + MARGIN)) { - return true; - } - } - return false; - } - - // Calculating a point score that indicates usefulness of the point. - static float getPointScore(const int mostCommonKeyWidth, - const int x, const int y, const int time, const bool lastPoint, const float nearest, - const float sumAngle, const NearKeysDistanceMap *const currentNearKeysDistances, + const NearKeysDistanceMap *const prevPrevNearKeysDistances); + static float getPointScore(const int mostCommonKeyWidth, const int x, const int y, + const int time, const bool lastPoint, const float nearest, const float sumAngle, + const NearKeysDistanceMap *const currentNearKeysDistances, const NearKeysDistanceMap *const prevNearKeysDistances, const NearKeysDistanceMap *const prevPrevNearKeysDistances, - std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs) { - static const int DISTANCE_BASE_SCALE = 100; - static const float NEAR_KEY_THRESHOLD = 0.6f; - static const int CORNER_CHECK_DISTANCE_THRESHOLD_SCALE = 25; - static const float NOT_LOCALMIN_DISTANCE_SCORE = -1.0f; - static const float LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE = 1.0f; - static const float CORNER_ANGLE_THRESHOLD = M_PI_F * 2.0f / 3.0f; - static const float CORNER_SUM_ANGLE_THRESHOLD = M_PI_F / 4.0f; - static const float CORNER_SCORE = 1.0f; - - const size_t size = sampledInputXs->size(); - // If there is only one point, add this point. Besides, if the previous point's distance map - // is empty, we re-compute nearby keys distances from the current point. - // Note that the current point is the first point in the incremental input that needs to - // be re-computed. - if (size <= 1 || prevNearKeysDistances->empty()) { - return 0.0f; - } - - const int baseSampleRate = mostCommonKeyWidth; - const int distPrev = getDistanceInt( - sampledInputXs->back(), sampledInputYs->back(), - (*sampledInputXs)[size - 2], (*sampledInputYs)[size - 2]) * DISTANCE_BASE_SCALE; - float score = 0.0f; - - // Location - if (!isPrevLocalMin(currentNearKeysDistances, prevNearKeysDistances, - prevPrevNearKeysDistances)) { - score += NOT_LOCALMIN_DISTANCE_SCORE; - } else if (nearest < NEAR_KEY_THRESHOLD) { - // Promote points nearby keys - score += LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE; - } - // Angle - const float angle1 = getAngle(x, y, sampledInputXs->back(), sampledInputYs->back()); - const float angle2 = getAngle(sampledInputXs->back(), sampledInputYs->back(), - (*sampledInputXs)[size - 2], (*sampledInputYs)[size - 2]); - const float angleDiff = getAngleDiff(angle1, angle2); - - // Save corner - if (distPrev > baseSampleRate * CORNER_CHECK_DISTANCE_THRESHOLD_SCALE - && (sumAngle > CORNER_SUM_ANGLE_THRESHOLD || angleDiff > CORNER_ANGLE_THRESHOLD)) { - score += CORNER_SCORE; - } - return score; - } - - // Sampling touch point and pushing information to vectors. - // Returning if previous point is popped or not. + std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs); static bool pushTouchPoint(const int mostCommonKeyWidth, const ProximityInfo *const proximityInfo, const int maxPointToKeyLength, - const int inputIndex, const int nodeCodePoint, int x, int y, - const int time, const bool sample, const bool isLastPoint, const float sumAngle, + const int inputIndex, const int nodeCodePoint, int x, int y, const int time, + const bool doSampling, const bool isLastPoint, const float sumAngle, NearKeysDistanceMap *const currentNearKeysDistances, const NearKeysDistanceMap *const prevNearKeysDistances, const NearKeysDistanceMap *const prevPrevNearKeysDistances, std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs, std::vector<int> *sampledInputTimes, std::vector<int> *sampledLengthCache, - std::vector<int> *sampledInputIndice) { - static const int LAST_POINT_SKIP_DISTANCE_SCALE = 4; - - size_t size = sampledInputXs->size(); - bool popped = false; - if (nodeCodePoint < 0 && sample) { - const float nearest = updateNearKeysDistances( - proximityInfo, maxPointToKeyLength, x, y, currentNearKeysDistances); - const float score = getPointScore(mostCommonKeyWidth, x, y, time, isLastPoint, nearest, - sumAngle, currentNearKeysDistances, prevNearKeysDistances, - prevPrevNearKeysDistances, sampledInputXs, sampledInputYs); - if (score < 0) { - // Pop previous point because it would be useless. - popInputData(sampledInputXs, sampledInputYs, sampledInputTimes, sampledLengthCache, - sampledInputIndice); - size = sampledInputXs->size(); - popped = true; - } else { - popped = false; - } - // Check if the last point should be skipped. - if (isLastPoint && size > 0) { - if (getDistanceInt(x, y, sampledInputXs->back(), - sampledInputYs->back()) * LAST_POINT_SKIP_DISTANCE_SCALE - < mostCommonKeyWidth) { - // This point is not used because it's too close to the previous point. - if (DEBUG_GEO_FULL) { - AKLOGI("p0: size = %zd, x = %d, y = %d, lx = %d, ly = %d, dist = %d, " - "width = %d", size, x, y, mSampledInputXs.back(), - mSampledInputYs.back(), ProximityInfoUtils::getDistanceInt( - x, y, mSampledInputXs.back(), mSampledInputYs.back()), - mProximityInfo->getMostCommonKeyWidth() - / LAST_POINT_SKIP_DISTANCE_SCALE); - } - return popped; - } - } - } - - if (nodeCodePoint >= 0 && (x < 0 || y < 0)) { - const int keyId = proximityInfo->getKeyIndexOf(nodeCodePoint); - if (keyId >= 0) { - x = proximityInfo->getKeyCenterXOfKeyIdG(keyId); - y = proximityInfo->getKeyCenterYOfKeyIdG(keyId); - } - } - - // Pushing point information. - if (size > 0) { - sampledLengthCache->push_back( - sampledLengthCache->back() + getDistanceInt( - x, y, sampledInputXs->back(), sampledInputYs->back())); - } else { - sampledLengthCache->push_back(0); - } - sampledInputXs->push_back(x); - sampledInputYs->push_back(y); - sampledInputTimes->push_back(time); - sampledInputIndice->push_back(inputIndex); - if (DEBUG_GEO_FULL) { - AKLOGI("pushTouchPoint: x = %03d, y = %03d, time = %d, index = %d, popped ? %01d", - x, y, time, inputIndex, popped); - } - return popped; - } + std::vector<int> *sampledInputIndice); + static float calculateBeelineSpeedRate(const int mostCommonKeyWidth, const float averageSpeed, + const int id, const int inputSize, const int *const xCoordinates, + const int *const yCoordinates, const int *times, const int sampledInputSize, + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + const std::vector<int> *const inputIndice); + static float getPointAngle( + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, const int index); + static float getPointsAngle( + const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, + const int index0, const int index1, const int index2); + static bool suppressCharProbabilities(const int mostCommonKeyWidth, + const int sampledInputSize, const std::vector<int> *const lengthCache, + const int index0, const int index1, + std::vector<hash_map_compat<int, float> > *charProbabilities); + static float calculateSquaredDistanceFromSweetSpotCenter( + const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, const int keyIndex, + const int inputIndex); + static float calculateNormalizedSquaredDistance( + const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs, + const std::vector<int> *const sampledInputYs, const int keyIndex, const int inputIndex); }; } // namespace latinime #endif // LATINIME_PROXIMITY_INFO_STATE_UTILS_H diff --git a/native/jni/src/proximity_info_utils.h b/native/jni/src/proximity_info_utils.h index 09302075a..24917d879 100644 --- a/native/jni/src/proximity_info_utils.h +++ b/native/jni/src/proximity_info_utils.h @@ -61,7 +61,7 @@ class ProximityInfoUtils { const int primaryKey = inputCodes[i]; const int x = inputXCoordinates[i]; const int y = inputYCoordinates[i]; - int *proximities = &inputProximities[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL]; + int *proximities = &inputProximities[i * MAX_PROXIMITY_CHARS_SIZE]; calculateProximities(keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, proximityCharsArray, maxProximityCharsSize, cellHeight, cellWidth, gridWidth, mostCommonKeyWidth, keyCount, x, y, primaryKey, localeStr, codeToKeyMap, @@ -71,9 +71,9 @@ class ProximityInfoUtils { if (DEBUG_PROXIMITY_CHARS) { for (int i = 0; i < inputSize; ++i) { AKLOGI("---"); - for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL; ++j) { + for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE; ++j) { int proximityChar = - inputProximities[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j]; + inputProximities[i * MAX_PROXIMITY_CHARS_SIZE + j]; proximityChar += 0; AKLOGI("--- (%d)%c", i, proximityChar); } diff --git a/native/jni/src/suggest_utils.h b/native/jni/src/suggest_utils.h index 42cc5dea0..7d49cde7e 100644 --- a/native/jni/src/suggest_utils.h +++ b/native/jni/src/suggest_utils.h @@ -18,6 +18,7 @@ #define LATINIME_SUGGEST_UTILS_H #include "defines.h" +#include "proximity_info_params.h" #include "proximity_info_state.h" namespace latinime { @@ -35,7 +36,7 @@ class SuggestUtils { static const float R1 = NEUTRAL_SCORE_SQUARED_RADIUS; static const float R2 = HALF_SCORE_SQUARED_RADIUS; const float x = normalizedSquaredDistance / static_cast<float>( - ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR); + ProximityInfoParams::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR); const float factor = max((x < R1) ? (A * (R1 - x) + B * x) / R1 : (B * (R2 - x) + C * (x - R1)) / (R2 - R1), MIN); |