diff options
159 files changed, 3803 insertions, 2078 deletions
diff --git a/java/Android.mk b/java/Android.mk index 52cc18b26..364973bea 100644 --- a/java/Android.mk +++ b/java/Android.mk @@ -28,9 +28,7 @@ LOCAL_JNI_SHARED_LIBRARIES := libjni_latinime # We want to install libjni_latinime.so to the system partition if LatinIME gets installed. LOCAL_REQUIRED_MODULES := libjni_latinime -LOCAL_STATIC_JAVA_LIBRARIES := android-common -LOCAL_STATIC_JAVA_LIBRARIES += inputmethod-common -LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4 +LOCAL_STATIC_JAVA_LIBRARIES := android-common inputmethod-common android-support-v4 # Do not compress dictionary files to mmap dict data runtime LOCAL_AAPT_FLAGS := -0 .dict diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml index 6b823829f..3e80de22a 100644 --- a/java/AndroidManifest.xml +++ b/java/AndroidManifest.xml @@ -18,6 +18,8 @@ coreApp="true" package="com.android.inputmethod.latin"> + <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="16" /> + <uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.READ_USER_DICTIONARY" /> @@ -26,7 +28,8 @@ <application android:label="@string/aosp_android_keyboard_ime_name" android:icon="@drawable/ic_ime_settings" android:backupAgent="BackupAgent" - android:killAfterRestore="false"> + android:killAfterRestore="false" + android:supportsRtl="true"> <service android:name="LatinIME" android:label="@string/aosp_android_keyboard_ime_name" diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml index 0a5d048ef..be692bfdf 100644 --- a/java/res/values-af/strings.xml +++ b/java/res/values-af/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Gebaseer op vorige woord"</string> <string name="gesture_input" msgid="3310827802759290774">"Gebaarinvoer"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Voer \'n woord in deur die letters van \'n woord te trek"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Wys gebaarspoor"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Wys gebaar se woord"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Wys swewende voorskouwoord saam met die gebaar"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Gestoor"</string> <string name="label_go_key" msgid="1635148082137219148">"Gaan"</string> <string name="label_next_key" msgid="362972844525672568">"Volgende"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Soek"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punt"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Verander taal"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Volgende"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Vorige"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift geaktiveer"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Kasslot geaktiveer"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift gedeaktiveer"</string> diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml index ab3b71c1c..f4a9de617 100644 --- a/java/res/values-am/strings.xml +++ b/java/res/values-am/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"በቀዳሚው ቃል ላይ የተመሠረተ"</string> <string name="gesture_input" msgid="3310827802759290774">"የእጅ ምልክት ግብዓት"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"የአንድ ቃል ፊደሎችን በመከታተል አንድ ቃል አስገባ"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"ምልክት የሚሄድበት መንገድ አሳይ"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"የምልክት ቃል አሳይ"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"ተንሳፋፊ የቅድመ እይታ ቃል ከምልክት ጋር አሳይ"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : ተቀምጧል"</string> <string name="label_go_key" msgid="1635148082137219148">"ሂድ"</string> <string name="label_next_key" msgid="362972844525672568">"በመቀጠል"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"ተመለስ"</string> <string name="spoken_description_search" msgid="1247236163755920808">"ፍለጋ"</string> <string name="spoken_description_dot" msgid="40711082435231673">"ነጥብ"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"ቋንቋ ቀይር"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"ቀጣይ"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"ቀዳሚ"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"ቅያር ቁልፍ ነቅቷል"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"አቢያት ማድረጊያ ነቅቷል"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"ቅያር ተሰናክሏል"</string> diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml index 8407f923e..29d046e76 100644 --- a/java/res/values-ar/strings.xml +++ b/java/res/values-ar/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"استنادًا إلى الكلمة السابقة"</string> <string name="gesture_input" msgid="3310827802759290774">"إدخال الإيماءة"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"يمكنك إدخال كلمة من خلال تتبع أحرف كلمة ما"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"عرض مسار الإيماءة"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"عرض كلمة الإيماءة"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"عرض كلمة معاينة متحركة مع الإيماءة"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : تم الحفظ"</string> <string name="label_go_key" msgid="1635148082137219148">"تنفيذ"</string> <string name="label_next_key" msgid="362972844525672568">"التالي"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"رجوع"</string> <string name="spoken_description_search" msgid="1247236163755920808">"بحث"</string> <string name="spoken_description_dot" msgid="40711082435231673">"نقطة"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"تبديل اللغة"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"التالي"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"السابق"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"تم تمكين Shift"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"تم تمكين Caps lock"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"تم تعطيل Shift"</string> diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml index 9301750e3..30217fb32 100644 --- a/java/res/values-be/strings.xml +++ b/java/res/values-be/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"На аснове папярэдняга слова"</string> <string name="gesture_input" msgid="3310827802759290774">"Уваход жэстам"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Увядзiце слова, адсочваючы лiтары"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Паказаць след жэста"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Паказаць слова жэста"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Паказаць плаваючы прагляд слова з жэстам"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Захаваныя"</string> <string name="label_go_key" msgid="1635148082137219148">"Пачаць"</string> <string name="label_next_key" msgid="362972844525672568">"Далей"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Увод"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Пошук"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Кропка"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Пераключыць мову"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Далей"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Назад"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift уключаны"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock уключаны"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift адключаны"</string> diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml index 6061e3c52..dc25205ce 100644 --- a/java/res/values-bg/strings.xml +++ b/java/res/values-bg/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Въз основа на предишната дума"</string> <string name="gesture_input" msgid="3310827802759290774">"Въвеждане чрез жест"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Въвеждане на дума чрез проследяване на буквите й"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Следа на жестовете: Показване"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Показване на дума при жестове"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Показване на дума с плаваща визуализация при жест"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Запазено"</string> <string name="label_go_key" msgid="1635148082137219148">"Старт"</string> <string name="label_next_key" msgid="362972844525672568">"Напред"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Търсене"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Точка"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Смяна на езика"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Следващ"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Предишен"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"„Shift“ е активиран"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"„Caps Lock“ е активиран"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"„Shift“ е деактивиран"</string> diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml index 865a391a0..57b55d310 100644 --- a/java/res/values-ca/strings.xml +++ b/java/res/values-ca/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"En funció de la paraula anterior"</string> <string name="gesture_input" msgid="3310827802759290774">"Entrada de gestos"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Dibuixa les lletres d\'una paraula per escriure-la"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Mostra el recorregut del gest"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Mostra paraules en fer gestos"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Mostra la paraula de visualització prèvia flotant en fer gestos"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: desada"</string> <string name="label_go_key" msgid="1635148082137219148">"Vés"</string> <string name="label_next_key" msgid="362972844525672568">"Següent"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Retorn"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Cerca"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punt"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Canvia l\'idioma"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Següent"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Anterior"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Maj activat"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Bloq Maj activat"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Maj desactivat"</string> diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml index 1d9c8e38c..930cf13db 100644 --- a/java/res/values-cs/strings.xml +++ b/java/res/values-cs/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Na základě předchozího slova"</string> <string name="gesture_input" msgid="3310827802759290774">"Zadávání gesty"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Napište slovo zadáním jeho písmen."</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Zobrazovat stopu gesta"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Zobrazovat slovo gesta"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Zobrazovat plovoucí náhled slova gesta"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Uloženo"</string> <string name="label_go_key" msgid="1635148082137219148">"Přejít"</string> <string name="label_next_key" msgid="362972844525672568">"Další"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> <string name="spoken_description_search" msgid="1247236163755920808">"vyhledávací tlačítko"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Tečka"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Přepnout jazyk"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Další"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Předchozí"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Klávesa Shift je aktivní"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Klávesa Caps Lock je aktivní"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Klávesa Shift je neaktivní"</string> diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml index ca0938740..f04c43d16 100644 --- a/java/res/values-da/strings.xml +++ b/java/res/values-da/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Baseret på tidligere ord"</string> <string name="gesture_input" msgid="3310827802759290774">"Berøringsindtastning"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Indtast et ord ved at skrive bogstaverne for et ord med fingeren"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Vis spor af berøring"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Vis berøringsord"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Vis flydende eksempelord under berøring"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Gemt"</string> <string name="label_go_key" msgid="1635148082137219148">"Gå"</string> <string name="label_next_key" msgid="362972844525672568">"Næste"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Tilbage"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Søg"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punktum"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Skift sprog"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Næste"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Forrige"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Skift er aktiveret"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock er aktiveret"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Skift er deaktiveret"</string> diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml index 437fc80f4..59d8e7357 100644 --- a/java/res/values-de/strings.xml +++ b/java/res/values-de/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Auf Grundlage des vorherigen Wortes"</string> <string name="gesture_input" msgid="3310827802759290774">"Bewegungseingabe"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Wort durch Nachzeichnen der Buchstaben eingeben"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Spur der Bewegung anzeigen"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Wort bei Bewegung anzeigen"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Vorgeschlagenes Wort bei Bewegung anzeigen"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: gespeichert"</string> <string name="label_go_key" msgid="1635148082137219148">"Los"</string> <string name="label_next_key" msgid="362972844525672568">"Weiter"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Eingabe"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Suchen"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Aufzählungspunkt"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Sprache wechseln"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Nächste"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Vorherige"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Umschalttaste aktiviert"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Feststelltaste aktiviert"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Umschalttaste deaktiviert"</string> diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml index 4ecde7b7c..2803ed258 100644 --- a/java/res/values-el/strings.xml +++ b/java/res/values-el/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Βάσει προηγούμενης λέξης"</string> <string name="gesture_input" msgid="3310827802759290774">"Καταχώριση κίνησης"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Καταχώριση μιας λέξης με εντοπισμό των γραμμάτων μιας λέξης"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Εμφάνιση διαδρομής χειρονομίας"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Εμφάνιση λέξης χειρονομίας"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Εμφάνιση κινούμενης προεπισκόπησης λέξης με χειρονομία"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Αποθηκεύτηκε"</string> <string name="label_go_key" msgid="1635148082137219148">"Μετ."</string> <string name="label_next_key" msgid="362972844525672568">"Επόμενο"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Πλήκτρο Return"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Αναζήτηση"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Κουκκίδα"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Αλλαγή γλώσσας"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Επόμενο"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Προηγούμενο"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Το Shift ενεργοποιημένο"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Το Caps lock είναι ενεργοποιημένο"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Το Shift είναι απενεργοποιημένο"</string> diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml index e505f46d2..4d960d7d6 100644 --- a/java/res/values-en-rGB/strings.xml +++ b/java/res/values-en-rGB/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Based on previous word"</string> <string name="gesture_input" msgid="3310827802759290774">"Gesture input"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Input a word by tracing the letters of a word"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Show gesture trail"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Show gesture word"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Show floating preview word with gesture"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Saved"</string> <string name="label_go_key" msgid="1635148082137219148">"Go"</string> <string name="label_next_key" msgid="362972844525672568">"Next"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Search"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Dot"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Switch language"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Next"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Previous"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift enabled"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock enabled"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift disabled"</string> diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml index 4187b87b0..42efb2001 100644 --- a/java/res/values-es-rUS/strings.xml +++ b/java/res/values-es-rUS/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Según la palabra anterior"</string> <string name="gesture_input" msgid="3310827802759290774">"Entrada de gestos"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Ingresa una palabra trazando sus letras."</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Mostrar recorrido de gesto"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Mostrar palabra de gesto"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Mostrar palabra de vista previa flotante al realizar gestos"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string> <string name="label_go_key" msgid="1635148082137219148">"Ir"</string> <string name="label_next_key" msgid="362972844525672568">"Siguiente"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Volver"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Buscar"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punto"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Cambiar idioma"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Siguiente"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Anterior"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Se activó el modo Mayúscula."</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Se activó el bloqueo de mayúsculas."</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Se desactivó el modo Mayúscula"</string> diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml index 9de4fcf57..802864547 100644 --- a/java/res/values-es/strings.xml +++ b/java/res/values-es/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Según la palabra anterior"</string> <string name="gesture_input" msgid="3310827802759290774">"Entrada de gestos"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Trazar las letras de una palabra para introducirla"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Mostrar recorrido del gesto"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Mostrar palabra del gesto"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Mostrar la palabra de vista previa flotante al realizar un gesto"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string> <string name="label_go_key" msgid="1635148082137219148">"Ir"</string> <string name="label_next_key" msgid="362972844525672568">"Sig."</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Tecla Intro"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Buscar"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punto"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Cambiar idioma"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Siguiente"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Anterior"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Mayúsculas habilitadas"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Bloqueo de mayúsculas habilitado"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Mayúsculas inhabilitadas"</string> diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml index cedbde055..152c0300b 100644 --- a/java/res/values-et/strings.xml +++ b/java/res/values-et/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Eelmise sõna põhjal"</string> <string name="gesture_input" msgid="3310827802759290774">"Liigutusega sisest."</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Sisestage sõna, kirjutades sõna tähed sõrmega"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Näita liigutuse jälge"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Näita liigutuse sõna"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Ujuva sõna eelvaate näitamine koos liigutusega"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : salvestatud"</string> <string name="label_go_key" msgid="1635148082137219148">"Mine"</string> <string name="label_next_key" msgid="362972844525672568">"Edasi"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Tagasi"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Otsing"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punkt"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Keele vahetamine"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Järgmine"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Eelmine"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Tõstuklahv on lubatud"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Suurtähelukk on lubatud"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Tõstuklahv on keelatud"</string> diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml index f1bd870e2..4b1422984 100644 --- a/java/res/values-fa/strings.xml +++ b/java/res/values-fa/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"بر اساس کلمه قبلی"</string> <string name="gesture_input" msgid="3310827802759290774">"ورودی اشاره"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"با دنبال کردن حروف یک کلمه، کلمه را وارد کنید"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"نمایش نسخه آزمایشی حرکت"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"نمایش کلمه در طول ورودی حرکتی"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"نمایش کلمه پیشنمایش متحرک با حرکت"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : ذخیره شد"</string> <string name="label_go_key" msgid="1635148082137219148">"برو"</string> <string name="label_next_key" msgid="362972844525672568">"بعدی"</string> @@ -94,6 +97,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> <string name="spoken_description_search" msgid="1247236163755920808">"جستجو"</string> <string name="spoken_description_dot" msgid="40711082435231673">"نقطه"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"تغییر زبان"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"بعدی"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"قبلی"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift فعال است"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock فعال شد"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift غیرفعال است"</string> diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml index 898d522ba..28eeceddd 100644 --- a/java/res/values-fi/strings.xml +++ b/java/res/values-fi/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Perustuu edelliseen sanan"</string> <string name="gesture_input" msgid="3310827802759290774">"Eleiden syöttö"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Syötä sana piirtämällä kirjaimet sormella"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Näytä eleen jälki"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Näytä elesanat"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Näytä eleen yhteydessä kelluva esikatselusana"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Tallennettu"</string> <string name="label_go_key" msgid="1635148082137219148">"Siirry"</string> <string name="label_next_key" msgid="362972844525672568">"Seur."</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Haku"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Piste"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Vaihda kieli"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Seuraava"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Edellinen"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Vaihto päällä"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock päällä"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Vaihto pois käytöstä"</string> diff --git a/java/res/values-fr/donottranslate.xml b/java/res/values-fr/donottranslate.xml index 8cf2516a6..5288bd7d1 100644 --- a/java/res/values-fr/donottranslate.xml +++ b/java/res/values-fr/donottranslate.xml @@ -25,5 +25,7 @@ <!-- Symbols that should promote magic spaces into real space --> <string name="phantom_space_promoting_symbols">;:!?([*&@{<>+=|</string> <!-- Symbols that do NOT separate words --> - <string name="symbols_excluded_from_word_separators">\'</string> + <!-- Note that this is identical to the default value, but since the above ones are different + and those variables only make sense together, this is kept here for readability. --> + <string name="symbols_excluded_from_word_separators">\'-</string> </resources> diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml index 63c36af4c..a8556e870 100644 --- a/java/res/values-fr/strings.xml +++ b/java/res/values-fr/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Suggestions basées sur le mot précédent"</string> <string name="gesture_input" msgid="3310827802759290774">"Saisie gestuelle"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Saisir un mot en traçant ses lettres avec le doigt"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Afficher le tracé du geste"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Afficher un mot lors du geste"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Afficher un aperçu flottant du mot lors de la saisie gestuelle"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : enregistré"</string> <string name="label_go_key" msgid="1635148082137219148">"OK"</string> <string name="label_next_key" msgid="362972844525672568">"Suiv."</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Entrée"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Rechercher"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Point"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Changer de langue"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Touche suivante"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Touche précédente"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Touche Maj activée"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Verrouillage des majuscules activé"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Touche Maj désactivée"</string> diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml index 22c9efb1f..254c2d29b 100644 --- a/java/res/values-hi/strings.xml +++ b/java/res/values-hi/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"पिछले शब्द के आधार पर"</string> <string name="gesture_input" msgid="3310827802759290774">"जेस्चर इनपुट"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"किसी शब्द के अक्षरों को ट्रेस करके कोई शब्द इनपुट करें"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"जेस्चर ट्रेल दिखाएं"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"जेस्चर शब्द दिखाएं"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"जेस्चर के साथ फ़्लोटिंग पूर्वावलोकन शब्द दिखाएं"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: सहेजा गया"</string> <string name="label_go_key" msgid="1635148082137219148">"जाएं"</string> <string name="label_next_key" msgid="362972844525672568">"अगला"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"रिटर्न"</string> <string name="spoken_description_search" msgid="1247236163755920808">"खोजें"</string> <string name="spoken_description_dot" msgid="40711082435231673">"बिंदु"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"भाषा स्विच करें"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"अगला"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"पिछला"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift सक्षम किया गया"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock सक्षम किया गया"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift अक्षम किया गया"</string> diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml index e7c508d90..cb208804e 100644 --- a/java/res/values-hr/strings.xml +++ b/java/res/values-hr/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Na temelju prethodne riječi"</string> <string name="gesture_input" msgid="3310827802759290774">"Unos pokretom"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Unos riječi ispisivanjem slova riječi"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Prikaži trag pokreta"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Prikaži riječ pokreta"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Prikaži lebdeći pregled riječi uz pokret"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Spremljeno"</string> <string name="label_go_key" msgid="1635148082137219148">"Idi"</string> <string name="label_next_key" msgid="362972844525672568">"Dalje"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Pretraživanje"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Točka"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Promijeni jezik"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Sljedeće"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Prethodno"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Omogućena tipka Shift"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Omogućeno pisanje velikih slova"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Onemogućena tipka Shift"</string> diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml index 637b5e482..62d1dd187 100644 --- a/java/res/values-hu/strings.xml +++ b/java/res/values-hu/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Az előző szó alapján"</string> <string name="gesture_input" msgid="3310827802759290774">"Kézi bevitel"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Szó beírása a betűk megrajzolásával"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Mozdulat irányának mutatása"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Mozdulatot leíró szó mutatása"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Mozdulatot leíró szó mutatása lebegő előnézetben"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : mentve"</string> <string name="label_go_key" msgid="1635148082137219148">"Ugrás"</string> <string name="label_next_key" msgid="362972844525672568">"Tovább"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Keresés"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Pont"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Nyelvek felcserélése"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Következő"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Előző"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift bekapcsolva"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock bekapcsolva"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift kikapcsolva"</string> diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml index d5c6d48a4..8273d5483 100644 --- a/java/res/values-in/strings.xml +++ b/java/res/values-in/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Berdasarkan kata sebelumnya"</string> <string name="gesture_input" msgid="3310827802759290774">"Masukan isyarat"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Masukkan kata dengan melacak huruf dari sebuah kata"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Tampilkan jalur isyarat"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Tampilkan kata isyarat"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Tampilkan kata pratinjau melayang dengan isyarat"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Telah disimpan"</string> <string name="label_go_key" msgid="1635148082137219148">"Buka"</string> <string name="label_next_key" msgid="362972844525672568">"Berikutnya"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Kembali"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Telusuri"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Titik"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Ganti bahasa"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Berikutnya"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Sebelumnya"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift diaktifkan"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock diaktifkan"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift dinonaktifkan"</string> diff --git a/java/res/values-it/donottranslate.xml b/java/res/values-it/donottranslate.xml deleted file mode 100644 index 58e94361b..000000000 --- a/java/res/values-it/donottranslate.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2009, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- Symbols that do NOT separate words --> - <string name="symbols_excluded_from_word_separators"></string> -</resources> diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml index efa02b23a..d529b8aad 100644 --- a/java/res/values-it/strings.xml +++ b/java/res/values-it/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"In base alla parola precedente"</string> <string name="gesture_input" msgid="3310827802759290774">"Inserimento con gesti"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Inserisci una parola tracciandone le lettere"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Mostra traccia con gesto"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Mostra parola con gesto"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Mostra parola di anteprima floating con gesto"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : parola salvata"</string> <string name="label_go_key" msgid="1635148082137219148">"Vai"</string> <string name="label_next_key" msgid="362972844525672568">"Avanti"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Invio"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Cerca"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Pallino"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Cambia lingua"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Successivo"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Precedente"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Maiuscolo attivo"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Blocco maiuscole attivo"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Maiuscolo disattivato"</string> diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml index b182ffd32..5c10716ce 100644 --- a/java/res/values-iw/strings.xml +++ b/java/res/values-iw/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"בהתבסס על המילה הקודמת"</string> <string name="gesture_input" msgid="3310827802759290774">"קלט מחווה"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"הזן מילה על ידי החלקת האצבע מאות לאות"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"הצג שובל מחווה"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"הצג מילת מחווה"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"הצג תצוגה מקדימה צפה של המילה בזמן המחווה"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : נשמרה"</string> <string name="label_go_key" msgid="1635148082137219148">"בצע"</string> <string name="label_next_key" msgid="362972844525672568">"הבא"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"חזור"</string> <string name="spoken_description_search" msgid="1247236163755920808">"חיפוש"</string> <string name="spoken_description_dot" msgid="40711082435231673">"נקודה"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"החלף שפה"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"הבא"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"הקודם"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift מופעל"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock מופעל"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift מושבת"</string> diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml index 9d31d5cec..fae12ab4d 100644 --- a/java/res/values-ja/strings.xml +++ b/java/res/values-ja/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"前の語句に基づいた入力候補表示"</string> <string name="gesture_input" msgid="3310827802759290774">"ジェスチャー入力"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"単語の文字をトレースして単語を入力"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"ジェスチャートレイルを表示"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"ジェスチャーワードを表示"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"ジェスチャーでプレビューワードをフローティング表示できます"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:保存しました"</string> <string name="label_go_key" msgid="1635148082137219148">"実行"</string> <string name="label_next_key" msgid="362972844525672568">"次へ"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> <string name="spoken_description_search" msgid="1247236163755920808">"検索"</string> <string name="spoken_description_dot" msgid="40711082435231673">"中点"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"言語を切り替え"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"次へ"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"前へ"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift有効"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock有効"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift解除"</string> diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml index ad9d6e303..9049034c3 100644 --- a/java/res/values-ko/strings.xml +++ b/java/res/values-ko/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"이전 단어에 기반한 추천"</string> <string name="gesture_input" msgid="3310827802759290774">"동작 입력"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"한번에 문자를 그려서 단어 입력"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"동작 흔적 표시"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"동작 단어 표시"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"동작에 따라 단어 미리보기 표시"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: 저장됨"</string> <string name="label_go_key" msgid="1635148082137219148">"이동"</string> <string name="label_next_key" msgid="362972844525672568">"다음"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"리턴 키"</string> <string name="spoken_description_search" msgid="1247236163755920808">"검색"</string> <string name="spoken_description_dot" msgid="40711082435231673">"점"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"언어 전환"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"다음"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"이전"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift 사용"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock 사용"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift 사용중지"</string> diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml index e52452e30..f3b900382 100644 --- a/java/res/values-lt/strings.xml +++ b/java/res/values-lt/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Pagal ankstesnį žodį"</string> <string name="gesture_input" msgid="3310827802759290774">"Įvestis gestais"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Įveskite žodį brėždami jo raides"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Rodyti gestų kelią"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Rodyti gesto žodį"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Rodyti kintantį peržiūros žodį gestu"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: išsaugota"</string> <string name="label_go_key" msgid="1635148082137219148">"Pradėti"</string> <string name="label_next_key" msgid="362972844525672568">"Kitas"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Grįžti"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Ieškoti"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Taškas"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Keisti kalbą"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Kitas"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Ankstesnis"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Įgalintas antrasis lygis"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Įgalintos didžiosios raidės"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Antrasis lygis išjungtas"</string> diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml index 274dd2f27..55be05218 100644 --- a/java/res/values-lv/strings.xml +++ b/java/res/values-lv/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Pamatojoties uz iepriekšējo vārdu"</string> <string name="gesture_input" msgid="3310827802759290774">"Ievade ar žestu"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Ievadiet vārdu, norādot tā burtus."</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Rādīt žesta pēdas"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Rādīt žesta vārdu"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Rādīt peldošo priekšskatījuma vārdu ar žestu"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: saglabāts"</string> <string name="label_go_key" msgid="1635148082137219148">"Sākt"</string> <string name="label_next_key" msgid="362972844525672568">"Tālāk"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Ievadīšanas taustiņš"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Meklēt"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punkts"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Mainīt valodu"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Nākamā"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Iepriekšējā"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Pārslēgšanas režīms iespējots"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Burtslēgs iespējots"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Pārslēgšanas režīms atspējots"</string> diff --git a/java/res/values-ms/strings.xml b/java/res/values-ms/strings.xml index 5100bb901..4f0f19bfc 100644 --- a/java/res/values-ms/strings.xml +++ b/java/res/values-ms/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Berdasarkan perkataan sebelumnya"</string> <string name="gesture_input" msgid="3310827802759290774">"Input gerak isyarat"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Masukkan perkataan dengan menyurih huruf perkataan itu."</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Tunjukkan jejak gerak isyarat"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Tunjukkan perkataan gerak isyarat"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Tunjukkan perkataan pratonton terapung dengan gerak isyarat"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Disimpan"</string> <string name="label_go_key" msgid="1635148082137219148">"Pergi"</string> <string name="label_next_key" msgid="362972844525672568">"Seterusnya"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Carian"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Titik"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Tukar bahasa"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Seterusnya"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Sebelumnya"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Kunci anjak didayakan"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Kunci huruf besar didayakan"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Kunci anjak dilumpuhkan"</string> diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml index be609226a..f603dfaa1 100644 --- a/java/res/values-nb/strings.xml +++ b/java/res/values-nb/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Basert på det forrige ordet"</string> <string name="gesture_input" msgid="3310827802759290774">"Bevegelseskommandoer"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Angi et ord ved å skrive bokstavene på skjermen med fingeren"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Vis bevegelsesspor"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Vis bevegelsesord"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Vis flytende forhåndsvisningsord under bevegelser"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Lagret"</string> <string name="label_go_key" msgid="1635148082137219148">"Utfør"</string> <string name="label_next_key" msgid="362972844525672568">"Neste"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Søk"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Prikk"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Bytt språk"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Neste"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Forrige"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift er aktivert"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock er aktivert"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift er deaktivert"</string> diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml index dd2608668..33816f870 100644 --- a/java/res/values-nl/strings.xml +++ b/java/res/values-nl/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Op basis van het vorige woord"</string> <string name="gesture_input" msgid="3310827802759290774">"Invoer met gebaren"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Voer een woord in door de letters van een woord te volgen"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Gebarenspoor weergeven"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Woord met gebaar weergeven"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Zwevend voorbeeldwoord met gebaar weergeven"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: opgeslagen"</string> <string name="label_go_key" msgid="1635148082137219148">"Start"</string> <string name="label_next_key" msgid="362972844525672568">"Verder"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Zoeken"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Stip"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Taal wijzigen"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Volgende"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Vorige"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift ingeschakeld"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock ingeschakeld"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift uitgeschakeld"</string> diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml index bc2e3ca1a..7e15566ac 100644 --- a/java/res/values-pl/strings.xml +++ b/java/res/values-pl/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Na podstawie poprzedniego słowa"</string> <string name="gesture_input" msgid="3310827802759290774">"Wprowadzanie gestem"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Podaj słowo, pisząc litery palcem"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Pokazuj ślad gestu"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Podpowiadaj przy pisaniu gestem"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Pokazuj pływający podgląd słowa podczas pisania gestem"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Zapisano"</string> <string name="label_go_key" msgid="1635148082137219148">"OK"</string> <string name="label_next_key" msgid="362972844525672568">"Dalej"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Szukaj"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punkt"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Przełącz język"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Dalej"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Wstecz"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift włączony"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock włączony"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift wyłączony"</string> diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml index 48a010a6a..fcab817bb 100644 --- a/java/res/values-pt-rPT/strings.xml +++ b/java/res/values-pt-rPT/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Com base na palavra anterior"</string> <string name="gesture_input" msgid="3310827802759290774">"Introd. por gestos"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Introduza uma palavra, desenhando as letras de uma palavra"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Mostrar percurso do gesto"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Mostrar palavra gesto"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Mostrar palavra de visualização flutuante com gesto"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string> <string name="label_go_key" msgid="1635148082137219148">"OK"</string> <string name="label_next_key" msgid="362972844525672568">"Avançar"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Pesquisar"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Ponto"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Mudar de idioma"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Seguinte"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Anterior"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift ativado"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock ativado"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift desativado"</string> diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml index fc5ccaa00..b4830675b 100644 --- a/java/res/values-pt/strings.xml +++ b/java/res/values-pt/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Com base na palavra anterior"</string> <string name="gesture_input" msgid="3310827802759290774">"Entrada por gesto"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Introduza uma palavra traçando suas letras"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Mostrar percurso do gesto"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Mostrar palavra do gesto"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Mostrar visualização flutuante da palavra com gesto"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Salvo"</string> <string name="label_go_key" msgid="1635148082137219148">"Ir"</string> <string name="label_next_key" msgid="362972844525672568">"Avançar"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Voltar"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Pesquisar"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Ponto"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Alterar idioma"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Próximo"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Anterior"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift ativado"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock ativado"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift desativado"</string> diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml index dceeaf4a2..25d58732d 100644 --- a/java/res/values-rm/strings.xml +++ b/java/res/values-rm/strings.xml @@ -96,6 +96,12 @@ <skip /> <!-- no translation found for gesture_input_summary (7019742443455085809) --> <skip /> + <!-- no translation found for gesture_preview_trail (3802333369335722221) --> + <skip /> + <!-- no translation found for gesture_floating_preview_text (6859416520117939680) --> + <skip /> + <!-- no translation found for gesture_floating_preview_text_summary (3333754126434989709) --> + <skip /> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Memorisà"</string> <string name="label_go_key" msgid="1635148082137219148">"Dai"</string> <string name="label_next_key" msgid="362972844525672568">"Vinavant"</string> @@ -151,6 +157,12 @@ <skip /> <!-- no translation found for spoken_description_dot (40711082435231673) --> <skip /> + <!-- no translation found for spoken_description_language_switch (5507091328222331316) --> + <skip /> + <!-- no translation found for spoken_description_action_next (8636078276664150324) --> + <skip /> + <!-- no translation found for spoken_description_action_previous (800872415009336208) --> + <skip /> <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) --> <skip /> <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) --> diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml index d0473464c..e47ed63f4 100644 --- a/java/res/values-ro/strings.xml +++ b/java/res/values-ro/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Bazate pe cuvântul precedent"</string> <string name="gesture_input" msgid="3310827802759290774">"Utilizaţi gesturi"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Introduceţi un cuvânt desenând literele acestuia"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Se afişează urma gestului"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Sugestie cuvinte la gesturi"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Se afişează previzualizarea cuvântului flotant la gesturi"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: salvat"</string> <string name="label_go_key" msgid="1635148082137219148">"OK"</string> <string name="label_next_key" msgid="362972844525672568">"Înainte"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Căutaţi"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punct"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Schimbaţi limba"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Înainte"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Înapoi"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Tasta Shift a fost activată"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Tasta Caps Lock a fost activată"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Tasta Shift a fost dezactivată"</string> diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml index 7e12ddb22..f780650ab 100644 --- a/java/res/values-ru/strings.xml +++ b/java/res/values-ru/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Подсказки, основанные на предыдущих словах"</string> <string name="gesture_input" msgid="3310827802759290774">"Ввод жестами"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Перемещайте палец от буквы к букве, чтобы составить слово"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Рисовать линию"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Подсказывать слово"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Показывать подсказку во время ввода"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: сохранено"</string> <string name="label_go_key" msgid="1635148082137219148">"Поиск"</string> <string name="label_next_key" msgid="362972844525672568">"Далее"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Клавиша \"Ввод\""</string> <string name="spoken_description_search" msgid="1247236163755920808">"Поиск"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Точка"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Сменить язык"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Далее"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Назад"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Верхний регистр включен"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock включен"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Верхний регистр отключен"</string> diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml index 619f41fc5..4aa0c5ce8 100644 --- a/java/res/values-sk/strings.xml +++ b/java/res/values-sk/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Na základe predchádzajúceho slova"</string> <string name="gesture_input" msgid="3310827802759290774">"Zadávanie gestami"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Napíšte slovo zadaním jeho písmen"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Zobrazovať stopu gesta"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Zobrazovať slovo gesta"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Zobrazovať plávajúcu ukážku slova gesta"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Uložené"</string> <string name="label_go_key" msgid="1635148082137219148">"Hľadať"</string> <string name="label_next_key" msgid="362972844525672568">"Ďalej"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Hľadať"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Bodka"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Prepnúť jazyk"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Ďalšie"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Predchádzajúce"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Kláves Shift je povolený"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Kláves Caps Lock je povolený"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Kláves Shift je zakázaný"</string> diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml index 00c3aad5e..d21e585c3 100644 --- a/java/res/values-sl/strings.xml +++ b/java/res/values-sl/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Na podlagi prejšnje besede"</string> <string name="gesture_input" msgid="3310827802759290774">"Vnos s potezo"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Vnašanje besede z drsenjem po zaslonu od črke do črke"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Prikaži pot poteze"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Pokaži besedo za potezo"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Pokaži plavajoči predogled besede za potezo"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: shranjeno"</string> <string name="label_go_key" msgid="1635148082137219148">"Pojdi"</string> <string name="label_next_key" msgid="362972844525672568">"Naprej"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Vračalka"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Iskanje"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Pika"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Preklop jezika"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Naprej"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Nazaj"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Način »Shift« je omogočen"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Način »Caps Lock« je omogočen"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Način »Shift« je onemogočen"</string> diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml index 7febdf0dc..3b209b305 100644 --- a/java/res/values-sr/strings.xml +++ b/java/res/values-sr/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"На основу претходне речи"</string> <string name="gesture_input" msgid="3310827802759290774">"Унос покретом"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Унесите реч исписивањем слова речи"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Прикажи траг покрета"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Прикажи реч уз покрет"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Приказ плутајућег прегледа речи уз покрет"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Сачувано"</string> <string name="label_go_key" msgid="1635148082137219148">"Иди"</string> <string name="label_next_key" msgid="362972844525672568">"Следеће"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Претражи"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Тачка"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Пребаци језик"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Следеће"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Претходно"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift је омогућен"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock је омогућен"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift је онемогућен"</string> diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml index 301b35813..71ba6204d 100644 --- a/java/res/values-sv/strings.xml +++ b/java/res/values-sv/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Baserat på föregående ord"</string> <string name="gesture_input" msgid="3310827802759290774">"Gestinmatning"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Skriv ett ord för hand genom att rita bokstäverna i ordet"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Visa spår efter rörelse"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Visa svävande ord för rörelse"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Visa förhandsgranskning av svävande ord med rörelse"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: sparat"</string> <string name="label_go_key" msgid="1635148082137219148">"Kör"</string> <string name="label_next_key" msgid="362972844525672568">"Nästa"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Retur"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Sök"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punkt"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Byt språk"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Nästa"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Föregående"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Skift är aktiverat"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock är aktiverat"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Skift är inaktiverat"</string> diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml index eed8e994f..ec960bcd4 100644 --- a/java/res/values-sw/strings.xml +++ b/java/res/values-sw/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Kulingana na neno la awali"</string> <string name="gesture_input" msgid="3310827802759290774">"Ingizo la ishara"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Ingiza neno kwa kufuatilia herufi za neno"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Onyesha njia ya ishara"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Onyesha neno la ishara"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Onyesha neno hakiki linaloelea lililo na ishara"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Imehifadhiwa"</string> <string name="label_go_key" msgid="1635148082137219148">"Nenda"</string> <string name="label_next_key" msgid="362972844525672568">"Ifuatayo"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Rudi"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Tafuta"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Nukta"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Badili lugha"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Inayofuata"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Iliyotangulia"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift imewezeshwa"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock imewezeshwa"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift imelemazwa"</string> diff --git a/java/res/values-sw600dp/config.xml b/java/res/values-sw600dp/config.xml index 619169c52..e296623b2 100644 --- a/java/res/values-sw600dp/config.xml +++ b/java/res/values-sw600dp/config.xml @@ -19,6 +19,8 @@ --> <resources> + <!-- Device form factor. This value must be aligned with {@link KeyboardId.DEVICE_FORM_FACTOR_TABLET7} --> + <integer name="config_device_form_factor">1</integer> <bool name="config_enable_show_voice_key_option">false</bool> <bool name="config_enable_show_popup_on_keypress_option">false</bool> <bool name="config_enable_bigram_suggestions_option">false</bool> diff --git a/java/res/values-sw768dp/config.xml b/java/res/values-sw768dp/config.xml index 27cb9ac21..346fa9979 100644 --- a/java/res/values-sw768dp/config.xml +++ b/java/res/values-sw768dp/config.xml @@ -19,6 +19,8 @@ --> <resources> + <!-- Device form factor. This value must be aligned with {@link KeyboardId.DEVICE_FORM_FACTOR_TABLET10} --> + <integer name="config_device_form_factor">2</integer> <bool name="config_enable_show_voice_key_option">false</bool> <bool name="config_enable_show_popup_on_keypress_option">false</bool> <bool name="config_enable_bigram_suggestions_option">false</bool> diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml index cad003f55..4e8d2e221 100644 --- a/java/res/values-th/strings.xml +++ b/java/res/values-th/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"ตามคำก่อนหน้า"</string> <string name="gesture_input" msgid="3310827802759290774">"ป้อนท่าทางสัมผัส"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"ป้อนคำโดยลากนิ้วเป็นรูปตัวอักษรที่อยู่ในคำ โดยไม่ยกนิ้วขึ้น"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"แสดงรอยทางเดินของท่าทาง"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"แสดงคำแนะนำท่าทาง"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"แสดงตัวอย่างคำแนะนำพร้อมด้วยท่าทาง"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : บันทึกแล้ว"</string> <string name="label_go_key" msgid="1635148082137219148">"ไป"</string> <string name="label_next_key" msgid="362972844525672568">"ถัดไป"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> <string name="spoken_description_search" msgid="1247236163755920808">"ค้นหา"</string> <string name="spoken_description_dot" msgid="40711082435231673">"เครื่องหมายจุด"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"เปลี่ยนภาษา"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"ถัดไป"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"ก่อนหน้า"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"เปิดใช้งาน Shift แล้ว"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"เปิดใช้งาน Caps Lock แล้ว"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"ปิดใช้งาน Shift แล้ว"</string> diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml index 8ebd9c742..a2b46a66b 100644 --- a/java/res/values-tl/strings.xml +++ b/java/res/values-tl/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Batay sa nakaraang salita"</string> <string name="gesture_input" msgid="3310827802759290774">"Pagpasok ng galaw"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Magpasok ng salita sa gamit ang pagsulat sa mga titik ng salita"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Ipakita ang trail ng galaw"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Ipakita ang salita ng galaw"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Ipakita ang lumulutang na preview ng salita na may galaw"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Na-save"</string> <string name="label_go_key" msgid="1635148082137219148">"Punta"</string> <string name="label_next_key" msgid="362972844525672568">"Susunod"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Bumalik"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Paghahanap"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Tuldok"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Magpalit ng wika"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Susunod"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Nakaraan"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Pinagana ang shift"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Pinagana ang caps lock"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Hindi pinagana ang shift"</string> diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml index 32d8d9882..f9eb59831 100644 --- a/java/res/values-tr/strings.xml +++ b/java/res/values-tr/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Önceki kelimeye dayanarak"</string> <string name="gesture_input" msgid="3310827802759290774">"Hareket girişi"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Bir kelimeyi harflerini izleyerek girin"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Hareket izini göster"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Hareketle yazılan kelimeyi göster"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Hareketle kayan önizleme kelimesini göster"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Kaydedildi"</string> <string name="label_go_key" msgid="1635148082137219148">"Git"</string> <string name="label_next_key" msgid="362972844525672568">"İleri"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Ara"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Nokta"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Dili değiştir"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Sonraki"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Önceki"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Üst karakter etkin"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Büyük harf kilidi etkin"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Üst karakter devre dışı"</string> diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml index d0b3b46c5..d62f42082 100644 --- a/java/res/values-uk/strings.xml +++ b/java/res/values-uk/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"На основі попереднього слова"</string> <string name="gesture_input" msgid="3310827802759290774">"Введення жестами"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Введіть слово, малюючи літери, з яких воно складається"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Показувати слід жестів"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Показувати слово для жесту"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Показувати спливаючий перегляд слова під час жесту"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : збережено"</string> <string name="label_go_key" msgid="1635148082137219148">"Іти"</string> <string name="label_next_key" msgid="362972844525672568">"Далі"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Клавіша Return"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Пошук"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Крапка"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Змінити мову"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Далі"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Назад"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift увімкнено"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock увімкнено"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift вимкнено"</string> diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml index e4ffa913c..13f51ad77 100644 --- a/java/res/values-vi/strings.xml +++ b/java/res/values-vi/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Dựa trên từ trước đó"</string> <string name="gesture_input" msgid="3310827802759290774">"Nhập bằng cử chỉ"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Nhập từ bằng cách lần theo các chữ cái của từ"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Hiển thị vệt cử chỉ"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Hiển thị từ theo cử chỉ"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Hiển thị từ xem trước nổi bằng cử chỉ"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Đã lưu"</string> <string name="label_go_key" msgid="1635148082137219148">"Tìm"</string> <string name="label_next_key" msgid="362972844525672568">"Tiếp theo"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Quay lại"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Tìm kiếm"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Dấu chấm"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Chuyển ngôn ngữ"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Tiếp theo"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Trước"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Đã bật Shift"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Đã bật Caps lock"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Đã tắt Shift"</string> diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml index 1361da6f1..c608694ad 100644 --- a/java/res/values-zh-rCN/strings.xml +++ b/java/res/values-zh-rCN/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"根据上一个字词提供建议"</string> <string name="gesture_input" msgid="3310827802759290774">"手势输入"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"连笔书写输入字词"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"显示手指操作轨迹"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"显示手指操作文字"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"进行手指操作时显示浮动预览文字"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已保存"</string> <string name="label_go_key" msgid="1635148082137219148">"开始"</string> <string name="label_next_key" msgid="362972844525672568">"下一步"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"返回"</string> <string name="spoken_description_search" msgid="1247236163755920808">"搜索"</string> <string name="spoken_description_dot" msgid="40711082435231673">"点"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"切换语言"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"下一个"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"上一个"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift 模式已启用"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"大写锁定已启用"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift 模式已停用"</string> diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml index efab7088e..120ae330f 100644 --- a/java/res/values-zh-rTW/strings.xml +++ b/java/res/values-zh-rTW/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"根據上一個字詞產生"</string> <string name="gesture_input" msgid="3310827802759290774">"手勢輸入"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"以手指寫出字詞中字母的方式來輸入字詞"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"顯示手勢軌跡"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"顯示手勢字詞"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"使用手勢輸入時顯示浮動預覽字詞"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已儲存"</string> <string name="label_go_key" msgid="1635148082137219148">"開始"</string> <string name="label_next_key" msgid="362972844525672568">"繼續"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"返回"</string> <string name="spoken_description_search" msgid="1247236163755920808">"搜尋"</string> <string name="spoken_description_dot" msgid="40711082435231673">"點"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"切換語言"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"下一步"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"上一步"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift 鍵已啟用"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"大寫鎖定已啟用"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift 鍵已停用"</string> diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml index 58fc37c56..2b2a5872c 100644 --- a/java/res/values-zu/strings.xml +++ b/java/res/values-zu/strings.xml @@ -60,6 +60,9 @@ <string name="bigram_prediction_summary" msgid="3253961591626441019">"Ngokususela egameni langaphambilini"</string> <string name="gesture_input" msgid="3310827802759290774">"Okokufaka kokuthinta"</string> <string name="gesture_input_summary" msgid="7019742443455085809">"Faka igama ngokulandela ngomkhondo izinhlamvu zegama"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Bonisa i-trail yokuthinta"</string> + <string name="gesture_floating_preview_text" msgid="6859416520117939680">"Bonisa igama lokuthinta"</string> + <string name="gesture_floating_preview_text_summary" msgid="3333754126434989709">"Bonisa igama lokuhlola kuqala elintantayo nokuthinta"</string> <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Kulondoloziwe"</string> <string name="label_go_key" msgid="1635148082137219148">"Iya"</string> <string name="label_next_key" msgid="362972844525672568">"Okulandelayo"</string> @@ -90,6 +93,9 @@ <string name="spoken_description_return" msgid="8178083177238315647">"Buyisela"</string> <string name="spoken_description_search" msgid="1247236163755920808">"Sesha"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Icashazi"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Shintsha ulimi"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Okulandelayo"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Okwangaphambilini"</string> <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"U-Shift uvunyelwe"</string> <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Ofeleba bavunyelwe"</string> <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"U-Shift uvimbelwe"</string> diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index 1d52e46bb..02e8eeb3b 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -118,6 +118,18 @@ <enum name="italic" value="2" /> <enum name="boldItalic" value="3" /> </attr> + + <attr name="gestureFloatingPreviewTextSize" format="dimension" /> + <attr name="gestureFloatingPreviewTextColor" format="color" /> + <attr name="gestureFloatingPreviewTextOffset" format="dimension" /> + <attr name="gestureFloatingPreviewTextShadingColor" format="color" /> + <attr name="gestureFloatingPreviewTextShadingBorder" format="dimension" /> + <attr name="gestureFloatingPreviewTextShadowColor" format="color" /> + <attr name="gestureFloatingPreviewTextShadowBorder" format="dimension" /> + <attr name="gestureFloatingPreviewTextConnectorColor" format="color" /> + <attr name="gestureFloatingPreviewTextConnectorWidth" format="dimension" /> + <attr name="gesturePreviewTrailColor" format="color" /> + <attr name="gesturePreviewTrailWidth" format="dimension" /> </declare-styleable> <declare-styleable name="MainKeyboardView"> diff --git a/java/res/values/config.xml b/java/res/values/config.xml index 50f46c3f5..e5575e7ae 100644 --- a/java/res/values/config.xml +++ b/java/res/values/config.xml @@ -19,6 +19,8 @@ --> <resources> + <!-- Device form factor. This value must be aligned with {@link KeyboardId.DEVICE_FORM_FACTOR_PHONE} --> + <integer name="config_device_form_factor">0</integer> <bool name="config_use_fullscreen_mode">false</bool> <bool name="config_enable_show_voice_key_option">true</bool> <bool name="config_enable_show_popup_on_keypress_option">true</bool> diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml index 925eb55fa..c59bad302 100644 --- a/java/res/values/dimens.xml +++ b/java/res/values/dimens.xml @@ -93,4 +93,12 @@ <dimen name="more_suggestions_hint_text_size">27dp</dimen> <integer name="suggestions_count_in_strip">3</integer> <integer name="center_suggestion_percentile">36</integer> + + <!-- Gesture preview parameters --> + <dimen name="gesture_preview_trail_width">2.5dp</dimen> + <dimen name="gesture_floating_preview_text_size">35dp</dimen> + <dimen name="gesture_floating_preview_text_offset">75dp</dimen> + <dimen name="gesture_floating_preview_text_shadow_border">17.5dp</dimen> + <dimen name="gesture_floating_preview_text_shading_border">7.5dp</dimen> + <dimen name="gesture_floating_preview_text_connector_width">1.0dp</dimen> </resources> diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 12abf8469..07b3f31c7 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -111,10 +111,16 @@ <!-- Description for "next word suggestion" option. This displays suggestions even when there is no input, based on the previous word. --> <string name="bigram_prediction_summary">Based on previous word</string> - <!-- Option to enable gesture input. The user can input a word by tracing the letters of a word without releasing the finger from the screen. [CHAR LIMIT=20]--> + <!-- Option to enable gesture input. The user can input a word by tracing the letters of a word without releasing the finger from the screen. [CHAR LIMIT=30]--> <string name="gesture_input">Gesture input</string> <!-- Description for "gesture_input" option. The user can input a word by tracing the letters of a word without releasing the finger from the screen. [CHAR LIMIT=65]--> <string name="gesture_input_summary">Input a word by tracing the letters of a word</string> + <!-- Option to enable gesture trail preview. The user can see a trail of the gesture during gesture input. [CHAR LIMIT=30]--> + <string name="gesture_preview_trail">Show gesture trail</string> + <!-- Option to enable gesture floating text preview. The user can see a suggested word floating under the moving finger during a gesture input. [CHAR LIMIT=30]--> + <string name="gesture_floating_preview_text">Show gesture word</string> + <!-- Description for "gesture_floating_preview_text" option. The user can see a suggested word floating under the moving finger during a gesture input. [CHAR LIMIT=65]--> + <string name="gesture_floating_preview_text_summary">Show floating preview word with gesture</string> <!-- Indicates that a word has been added to the dictionary --> <string name="added_word"><xliff:g id="word">%s</xliff:g> : Saved</string> @@ -181,6 +187,12 @@ <string name="spoken_description_search">Search</string> <!-- Spoken description for the "U+2022" (BULLET) keyboard key. --> <string name="spoken_description_dot">Dot</string> + <!-- Spoken description for the "Switch language" keyboard key. --> + <string name="spoken_description_language_switch">Switch language</string> + <!-- Spoken description for the "Next" action keyboard key. --> + <string name="spoken_description_action_next">Next</string> + <!-- Spoken description for the "Previous" action keyboard key. --> + <string name="spoken_description_action_previous">Previous</string> <!-- Spoken feedback after turning "Shift" mode on. --> <string name="spoken_description_shiftmode_on">Shift enabled</string> @@ -303,6 +315,15 @@ <!-- Description for English (United States) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25] This should be identical to subtype_en_US aside from the trailing (%s). --> <string name="subtype_with_layout_en_US">English (US) (<xliff:g id="layout">%s</xliff:g>)</string> + <!-- TODO: Uncomment once we can handle IETF language tag with script name specified. + Description for Serbian Cyrillic keyboard subtype [CHAR LIMIT=25] + <string name="subtype_serbian_cyrillic">Serbian (Cyrillic)</string> + Description for Serbian Latin keyboard subtype [CHAR LIMIT=25] + <string name="subtype_serbian_latin">Serbian (Latin)</string> + Description for Serbian Latin keyboard subtype with explicit keyboard layout [CHAR LIMIT=25] + This should be identical to subtype_serbian_latin aside from the trailing (%s). + <string name="subtype_with_layout_sr-Latn">Serbian (Latin) (<xliff:g id="layout">%s</xliff:g>)</string> + --> <!-- Description for language agnostic keyboard subtype [CHAR LIMIT=25] --> <string name="subtype_no_language">No language</string> <!-- Description for language agnostic QWERTY keyboard subtype [CHAR LIMIT=25] --> diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml index 8797fd7aa..955a27631 100644 --- a/java/res/values/styles.xml +++ b/java/res/values/styles.xml @@ -14,7 +14,7 @@ limitations under the License. --> -<resources> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Theme "Basic" --> <style name="Keyboard"> <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] --> @@ -67,6 +67,18 @@ <item name="shadowColor">#BB000000</item> <item name="shadowRadius">2.75</item> <item name="backgroundDimAlpha">128</item> + <!-- android:color/holo_blue_light=#FF33B5E5 --> + <item name="gestureFloatingPreviewTextSize">@dimen/gesture_floating_preview_text_size</item> + <item name="gestureFloatingPreviewTextColor">@android:color/white</item> + <item name="gestureFloatingPreviewTextOffset">@dimen/gesture_floating_preview_text_offset</item> + <item name="gestureFloatingPreviewTextShadingColor">@android:color/holo_blue_light</item> + <item name="gestureFloatingPreviewTextShadingBorder">@dimen/gesture_floating_preview_text_shading_border</item> + <item name="gestureFloatingPreviewTextShadowColor">#FF252525</item> + <item name="gestureFloatingPreviewTextShadowBorder">@dimen/gesture_floating_preview_text_shadow_border</item> + <item name="gestureFloatingPreviewTextConnectorColor">@android:color/white</item> + <item name="gestureFloatingPreviewTextConnectorWidth">@dimen/gesture_floating_preview_text_connector_width</item> + <item name="gesturePreviewTrailColor">@android:color/holo_blue_light</item> + <item name="gesturePreviewTrailWidth">@dimen/gesture_preview_trail_width</item> <!-- Common attributes of MainKeyboardView --> <item name="keyHysteresisDistance">@dimen/config_key_hysteresis_distance</item> <item name="touchNoiseThresholdTime">@integer/config_touch_noise_threshold_time</item> diff --git a/java/res/xml-sw768dp/key_space.xml b/java/res/xml-sw768dp/key_space.xml index 8968f080a..58e71d807 100644 --- a/java/res/xml-sw768dp/key_space.xml +++ b/java/res/xml-sw768dp/key_space.xml @@ -24,15 +24,36 @@ <switch> <case latin:languageCode="fa" + latin:languageSwitchKeyEnabled="true" + > + <Key + latin:keyStyle="languageSwitchKeyStyle" /> + <Key + latin:keyStyle="spaceKeyStyle" + latin:keyWidth="24.141%p" /> + <Key + latin:keyStyle="zwnjKeyStyle" /> + </case> + <case + latin:languageCode="fa" + latin:languageSwitchKeyEnabled="false" > <Key latin:keyStyle="spaceKeyStyle" latin:keyWidth="32.188%p" /> - <!-- U+200C: "" ZERO WIDTH NON-JOINER - U+200D: "" ZERO WIDTH JOINER --> <Key latin:keyStyle="zwnjKeyStyle" /> </case> + <case + latin:languageSwitchKeyEnabled="true" + > + <Key + latin:keyStyle="languageSwitchKeyStyle" /> + <Key + latin:keyStyle="spaceKeyStyle" + latin:keyWidth="32.188%p" /> + </case> + <!-- languageSwitchKeyEnabled="false" --> <default> <Key latin:keyStyle="spaceKeyStyle" diff --git a/java/res/xml-sw768dp/key_styles_common.xml b/java/res/xml-sw768dp/key_styles_common.xml index 7afe5848a..537e76800 100644 --- a/java/res/xml-sw768dp/key_styles_common.xml +++ b/java/res/xml-sw768dp/key_styles_common.xml @@ -76,7 +76,7 @@ <key-style latin:styleName="spaceKeyStyle" latin:code="!code/key_space" - latin:keyActionFlags="noKeyPreview" /> + latin:keyActionFlags="noKeyPreview|enableLongPress" /> <!-- U+200C: ZERO WIDTH NON-JOINER U+200D: ZERO WIDTH JOINER --> <key-style @@ -100,6 +100,12 @@ latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style + latin:styleName="languageSwitchKeyStyle" + latin:code="!code/key_language_switch" + latin:keyIcon="!icon/language_switch_key" + latin:keyActionFlags="noKeyPreview|altCodeWhileTyping|enableLongPress" + latin:altCode="!code/key_space" /> + <key-style latin:styleName="settingsKeyStyle" latin:code="!code/key_settings" latin:keyIcon="!icon/settings_key" diff --git a/java/res/xml-sw768dp/rows_east_slavic.xml b/java/res/xml-sw768dp/rows_east_slavic.xml index 0316c76f6..a4287f162 100644 --- a/java/res/xml-sw768dp/rows_east_slavic.xml +++ b/java/res/xml-sw768dp/rows_east_slavic.xml @@ -33,9 +33,8 @@ <include latin:keyboardLayout="@xml/rowkeys_east_slavic1" latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" /> - <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> <Key - latin:keyLabel="ъ" /> + latin:keyLabel="!text/keylabel_for_east_slavic_row1_12" /> <Key latin:keyStyle="deleteKeyStyle" latin:keyWidth="fillRight" /> diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml index 7f8a23a0e..acdf7645f 100644 --- a/java/res/xml/method.xml +++ b/java/res/xml/method.xml @@ -22,10 +22,12 @@ <!-- Supported subtypes keyboard_locale: script_name/keyboard_layout_set[:keyboard_locale] + af: Afrikaans/qwerty ar: Arabic/arabic be: Belarusian/east_slavic bg: Bulgarian/bulgarian bg: Bulgarian/bulgarian_bds + ca: Catalan/spanish cs: Czech/qwertz da: Danish/nordic de: German/qwertz @@ -41,14 +43,16 @@ hi: Hindi/hindi hr: Croatian/qwertz hu: Hungarian/qwertz + in: Indonesian/qwerty # "id" is official language code of Indonesian. is: Icelandic/qwerty it: Italian/qwerty - iw: Hebrew/hebrew + iw: Hebrew/hebrew # "he" is official language code of Hebrew. ka: Georgian/georgian ky: Kyrgyz/east_slavic lt: Lithuanian/qwerty lv: Latvian/qwerty mk: Macedonian/south_slavic + ms: Malay/qwerty nb: Norwegian Bokmål/nordic nl: Dutch/qwerty pl: Polish/qwerty @@ -59,11 +63,15 @@ sk: Slovak/qwerty sl: Slovenian/qwerty sr: Serbian/south_slavic + (sr-Latn: Serbian/qwerty) # not yet implemented. sv: Swedish/nordic + sw: Swahili/qwerty th: Thai/thai + tl: Tagalog/spanish tr: Turkish/qwerty uk: Ukrainian/east_slavic vi: Vietnamese/qwerty + zu: Zulu/qwerty zz: QWERTY/qwerty --> <!-- TODO: use <lang>_keyboard icon instead of a common keyboard icon. --> @@ -86,6 +94,12 @@ /> <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_generic" + android:imeSubtypeLocale="af" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" android:imeSubtypeLocale="ar" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="SupportTouchPositionCorrection" @@ -110,6 +124,12 @@ /> <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_generic" + android:imeSubtypeLocale="ca" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" android:imeSubtypeLocale="cs" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" @@ -186,6 +206,13 @@ android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" /> + <!-- Java uses the deprecated "in" code instead of the standard "id" code for Indonesian. --> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" + android:imeSubtypeLocale="in" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable" + /> <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_generic" android:imeSubtypeLocale="is" @@ -237,6 +264,12 @@ /> <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_generic" + android:imeSubtypeLocale="ms" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" android:imeSubtypeLocale="nb" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" @@ -295,6 +328,20 @@ android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="SupportTouchPositionCorrection" /> + <!-- TODO: Uncomment once we can handle IETF language tag with script name specified. + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_serbian_cyrillic" + android:imeSubtypeLocale="sr" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="SupportTouchPositionCorrection" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_serbian_latin" + android:imeSubtypeLocale="sr-Latn" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable" + /> + --> <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_generic" android:imeSubtypeLocale="sv" @@ -303,12 +350,24 @@ /> <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_generic" + android:imeSubtypeLocale="sw" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" android:imeSubtypeLocale="th" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=thai" /> <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_generic" + android:imeSubtypeLocale="tl" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" android:imeSubtypeLocale="tr" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" @@ -326,6 +385,12 @@ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable" /> <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" + android:imeSubtypeLocale="zu" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_no_language_qwerty" android:imeSubtypeLocale="zz" android:imeSubtypeMode="keyboard" diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml index 4f11cb7e5..ef6be3eed 100644 --- a/java/res/xml/prefs.xml +++ b/java/res/xml/prefs.xml @@ -102,6 +102,12 @@ android:title="@string/advanced_settings" android:summary="@string/advanced_settings_summary"> <CheckBoxPreference + android:key="pref_key_use_contacts_dict" + android:title="@string/use_contacts_dict" + android:summary="@string/use_contacts_dict_summary" + android:persistent="true" + android:defaultValue="true" /> + <CheckBoxPreference android:key="pref_suppress_language_switch_key" android:title="@string/suppress_language_switch_key" android:persistent="true" @@ -120,18 +126,23 @@ <ListPreference android:key="pref_key_preview_popup_dismiss_delay" android:title="@string/key_preview_popup_dismiss_delay" /> - <CheckBoxPreference - android:key="pref_key_use_contacts_dict" - android:title="@string/use_contacts_dict" - android:summary="@string/use_contacts_dict_summary" - android:persistent="true" - android:defaultValue="true" /> <PreferenceScreen android:key="pref_vibration_duration_settings" android:title="@string/prefs_keypress_vibration_duration_settings"/> <PreferenceScreen android:key="pref_keypress_sound_volume" android:title="@string/prefs_keypress_sound_volume_settings" /> + <CheckBoxPreference + android:key="pref_gesture_preview_trail" + android:title="@string/gesture_preview_trail" + android:persistent="true" + android:defaultValue="true" /> + <CheckBoxPreference + android:key="pref_gesture_floating_preview_text" + android:title="@string/gesture_floating_preview_text" + android:summary="@string/gesture_floating_preview_text_summary" + android:persistent="true" + android:defaultValue="true" /> </PreferenceScreen> </PreferenceCategory> </PreferenceScreen> diff --git a/java/res/xml/rowkeys_east_slavic1.xml b/java/res/xml/rowkeys_east_slavic1.xml index 00cb6a973..c1b43bd36 100644 --- a/java/res/xml/rowkeys_east_slavic1.xml +++ b/java/res/xml/rowkeys_east_slavic1.xml @@ -47,7 +47,7 @@ latin:keyLabel="е" latin:keyHintLabel="5" latin:additionalMoreKeys="5" - latin:moreKeys="!text/more_keys_for_cyrillic_ye" /> + latin:moreKeys="!text/more_keys_for_cyrillic_ie" /> <!-- U+043D: "н" CYRILLIC SMALL LETTER EN --> <Key latin:keyLabel="н" @@ -58,7 +58,8 @@ <Key latin:keyLabel="г" latin:keyHintLabel="7" - latin:additionalMoreKeys="7" /> + latin:additionalMoreKeys="7" + latin:moreKeys="!text/more_keys_for_cyrillic_ghe" /> <!-- U+0448: "ш" CYRILLIC SMALL LETTER SHA --> <Key latin:keyLabel="ш" @@ -75,6 +76,5 @@ latin:additionalMoreKeys="0" /> <!-- U+0445: "х" CYRILLIC SMALL LETTER HA --> <Key - latin:keyLabel="х" - latin:moreKeys="!text/more_keys_for_cyrillic_ha" /> + latin:keyLabel="х" /> </merge> diff --git a/java/res/xml/rowkeys_east_slavic2.xml b/java/res/xml/rowkeys_east_slavic2.xml index c635af2d9..9743727c1 100644 --- a/java/res/xml/rowkeys_east_slavic2.xml +++ b/java/res/xml/rowkeys_east_slavic2.xml @@ -52,7 +52,6 @@ <!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE --> <Key latin:keyLabel="ж" /> - <!-- U+044D: "э" CYRILLIC SMALL LETTER E --> <Key - latin:keyLabel="э" /> + latin:keyLabel="!text/keylabel_for_east_slavic_row2_11" /> </merge> diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java index 5ffd94a43..9b74070af 100644 --- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java +++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java @@ -60,10 +60,8 @@ public class KeyCodeDescriptionMapper { // Manual label substitutions for key labels with no string resource mKeyLabelMap.put(":-)", R.string.spoken_description_smiley); - // Symbols that most TTS engines can't speak - mKeyCodeMap.put(' ', R.string.spoken_description_space); - // Special non-character codes defined in Keyboard + mKeyCodeMap.put(Keyboard.CODE_SPACE, R.string.spoken_description_space); mKeyCodeMap.put(Keyboard.CODE_DELETE, R.string.spoken_description_delete); mKeyCodeMap.put(Keyboard.CODE_ENTER, R.string.spoken_description_return); mKeyCodeMap.put(Keyboard.CODE_SETTINGS, R.string.spoken_description_settings); @@ -71,6 +69,9 @@ public class KeyCodeDescriptionMapper { mKeyCodeMap.put(Keyboard.CODE_SHORTCUT, R.string.spoken_description_mic); mKeyCodeMap.put(Keyboard.CODE_SWITCH_ALPHA_SYMBOL, R.string.spoken_description_to_symbol); mKeyCodeMap.put(Keyboard.CODE_TAB, R.string.spoken_description_tab); + mKeyCodeMap.put(Keyboard.CODE_LANGUAGE_SWITCH, R.string.spoken_description_language_switch); + mKeyCodeMap.put(Keyboard.CODE_ACTION_NEXT, R.string.spoken_description_action_next); + mKeyCodeMap.put(Keyboard.CODE_ACTION_PREVIOUS, R.string.spoken_description_action_previous); } /** @@ -274,8 +275,7 @@ public class KeyCodeDescriptionMapper { return context.getString(OBSCURED_KEY_RES_ID); } - final int resId = mKeyCodeMap.get(code); - if (resId != 0) { + if (mKeyCodeMap.indexOfKey(code) >= 0) { return context.getString(mKeyCodeMap.get(code)); } else if (isDefinedNonCtrl) { return Character.toString((char) code); diff --git a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatUtils.java b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatUtils.java new file mode 100644 index 000000000..0befa7a66 --- /dev/null +++ b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatUtils.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.compat; + +import android.inputmethodservice.InputMethodService; + +import java.lang.reflect.Method; + +public class InputMethodServiceCompatUtils { + private static final Method METHOD_enableHardwareAcceleration = + CompatUtils.getMethod(InputMethodService.class, "enableHardwareAcceleration"); + + private InputMethodServiceCompatUtils() { + // This utility class is not publicly instantiable. + } + + public static boolean enableHardwareAcceleration(InputMethodService ims) { + return (Boolean)CompatUtils.invoke(ims, false, METHOD_enableHardwareAcceleration); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index e1e1ca9cf..178c9ff05 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -414,8 +414,14 @@ public class Key { @Override public String toString() { - return String.format("%s/%s %d,%d %dx%d %s/%s/%s", - Keyboard.printableCode(mCode), mLabel, mX, mY, mWidth, mHeight, mHintLabel, + final String label; + if (StringUtils.codePointCount(mLabel) == 1 && mLabel.codePointAt(0) == mCode) { + label = ""; + } else { + label = "/" + mLabel; + } + return String.format("%s%s %d,%d %dx%d %s/%s/%s", + Keyboard.printableCode(mCode), label, mX, mY, mWidth, mHeight, mHintLabel, KeyboardIconsSet.getIconName(mIconId), backgroundName(mBackgroundType)); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index 9abc79d3c..97d88af4a 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -25,7 +25,6 @@ public class KeyDetector { private Keyboard mKeyboard; private int mCorrectionX; private int mCorrectionY; - private boolean mProximityCorrectOn; /** * This class handles key detection. @@ -38,8 +37,9 @@ public class KeyDetector { } public void setKeyboard(Keyboard keyboard, float correctionX, float correctionY) { - if (keyboard == null) + if (keyboard == null) { throw new NullPointerException(); + } mCorrectionX = (int)correctionX; mCorrectionY = (int)correctionY; mKeyboard = keyboard; @@ -59,19 +59,9 @@ public class KeyDetector { } public Keyboard getKeyboard() { - if (mKeyboard == null) - throw new IllegalStateException("keyboard isn't set"); return mKeyboard; } - public void setProximityCorrectionEnabled(boolean enabled) { - mProximityCorrectOn = enabled; - } - - public boolean isProximityCorrectionEnabled() { - return mProximityCorrectOn; - } - public boolean alwaysAllowsSlidingInput() { return false; } diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index f1a35b212..3abe890cb 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -604,9 +604,6 @@ public class Keyboard { } public float getKeyX(TypedArray keyAttr) { - final int widthType = Builder.getEnumValue(keyAttr, - R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); - final int keyboardRightEdge = mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding; if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) { diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index b54c72687..1e5277345 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -55,10 +55,15 @@ public class KeyboardId { public static final int ELEMENT_PHONE_SYMBOLS = 8; public static final int ELEMENT_NUMBER = 9; + public static final int FORM_FACTOR_PHONE = 0; + public static final int FORM_FACTOR_TABLET7 = 1; + public static final int FORM_FACTOR_TABLET10 = 2; + private static final int IME_ACTION_CUSTOM_LABEL = EditorInfo.IME_MASK_ACTION + 1; public final InputMethodSubtype mSubtype; public final Locale mLocale; + public final int mDeviceFormFactor; public final int mOrientation; public final int mWidth; public final int mMode; @@ -72,11 +77,12 @@ public class KeyboardId { private final int mHashCode; - public KeyboardId(int elementId, InputMethodSubtype subtype, int orientation, int width, - int mode, EditorInfo editorInfo, boolean clobberSettingsKey, boolean shortcutKeyEnabled, - boolean hasShortcutKey, boolean languageSwitchKeyEnabled) { + public KeyboardId(int elementId, InputMethodSubtype subtype, int deviceFormFactor, + int orientation, int width, int mode, EditorInfo editorInfo, boolean clobberSettingsKey, + boolean shortcutKeyEnabled, boolean hasShortcutKey, boolean languageSwitchKeyEnabled) { mSubtype = subtype; mLocale = SubtypeLocale.getSubtypeLocale(subtype); + mDeviceFormFactor = deviceFormFactor; mOrientation = orientation; mWidth = width; mMode = mode; @@ -94,6 +100,7 @@ public class KeyboardId { private static int computeHashCode(KeyboardId id) { return Arrays.hashCode(new Object[] { + id.mDeviceFormFactor, id.mOrientation, id.mElementId, id.mMode, @@ -115,7 +122,8 @@ public class KeyboardId { private boolean equals(KeyboardId other) { if (other == this) return true; - return other.mOrientation == mOrientation + return other.mDeviceFormFactor == mDeviceFormFactor + && other.mOrientation == mOrientation && other.mElementId == mElementId && other.mMode == mMode && other.mWidth == mWidth @@ -184,11 +192,11 @@ public class KeyboardId { @Override public String toString() { - return String.format("[%s %s:%s %s%d %s %s %s%s%s%s%s%s%s%s]", + return String.format("[%s %s:%s %s-%s:%d %s %s %s%s%s%s%s%s%s%s]", elementIdToName(mElementId), mLocale, mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET), - (mOrientation == 1 ? "port" : "land"), mWidth, + deviceFormFactor(mDeviceFormFactor), (mOrientation == 1 ? "port" : "land"), mWidth, modeName(mMode), imeAction(), (navigateNext() ? "navigateNext" : ""), @@ -226,6 +234,15 @@ public class KeyboardId { } } + public static String deviceFormFactor(int devoceFormFactor) { + switch (devoceFormFactor) { + case FORM_FACTOR_PHONE: return "phone"; + case FORM_FACTOR_TABLET7: return "tablet7"; + case FORM_FACTOR_TABLET10: return "tablet10"; + default: return null; + } + } + public static String modeName(int mode) { switch (mode) { case MODE_TEXT: return "text"; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java index aab89a3e5..64b3f0952 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java @@ -115,6 +115,7 @@ public class KeyboardLayoutSet { boolean mNoSettingsKey; boolean mLanguageSwitchKeyEnabled; InputMethodSubtype mSubtype; + int mDeviceFormFactor; int mOrientation; int mWidth; // Sparse array of KeyboardLayoutSet element parameters indexed by element's id. @@ -211,9 +212,10 @@ public class KeyboardLayoutSet { final boolean noLanguage = SubtypeLocale.isNoLanguage(params.mSubtype); final boolean voiceKeyEnabled = params.mVoiceKeyEnabled && !noLanguage; final boolean hasShortcutKey = voiceKeyEnabled && (isSymbols != params.mVoiceKeyOnMain); - return new KeyboardId(keyboardLayoutSetElementId, params.mSubtype, params.mOrientation, - params.mWidth, params.mMode, params.mEditorInfo, params.mNoSettingsKey, - voiceKeyEnabled, hasShortcutKey, params.mLanguageSwitchKeyEnabled); + return new KeyboardId(keyboardLayoutSetElementId, params.mSubtype, params.mDeviceFormFactor, + params.mOrientation, params.mWidth, params.mMode, params.mEditorInfo, + params.mNoSettingsKey, voiceKeyEnabled, hasShortcutKey, + params.mLanguageSwitchKeyEnabled); } public static class Builder { @@ -239,9 +241,11 @@ public class KeyboardLayoutSet { mPackageName, NO_SETTINGS_KEY, mEditorInfo); } - public Builder setScreenGeometry(int orientation, int widthPixels) { - mParams.mOrientation = orientation; - mParams.mWidth = widthPixels; + public Builder setScreenGeometry(int deviceFormFactor, int orientation, int widthPixels) { + final Params params = mParams; + params.mDeviceFormFactor = deviceFormFactor; + params.mOrientation = orientation; + params.mWidth = widthPixels; return this; } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index d637ab5f1..dc84763c1 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -74,7 +74,6 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions { private MainKeyboardView mKeyboardView; private LatinIME mLatinIME; private Resources mResources; - private SettingsValues mCurrentSettingsValues; private KeyboardState mState; @@ -136,11 +135,11 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions { } public void loadKeyboard(EditorInfo editorInfo, SettingsValues settingsValues) { - mCurrentSettingsValues = settingsValues; final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder( mThemeContext, editorInfo); - builder.setScreenGeometry(mThemeContext.getResources().getConfiguration().orientation, - mThemeContext.getResources().getDisplayMetrics().widthPixels); + final Resources res = mThemeContext.getResources(); + builder.setScreenGeometry(res.getInteger(R.integer.config_device_form_factor), + res.getConfiguration().orientation, res.getDisplayMetrics().widthPixels); builder.setSubtype(mSubtypeSwitcher.getCurrentSubtype()); builder.setOptions( settingsValues.isVoiceKeyEnabled(editorInfo), @@ -171,20 +170,20 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions { } private void setKeyboard(final Keyboard keyboard) { - final Keyboard oldKeyboard = mKeyboardView.getKeyboard(); - mKeyboardView.setGestureInputEnabled(mCurrentSettingsValues.mGestureInputEnabled); - mKeyboardView.setKeyboard(keyboard); + final MainKeyboardView keyboardView = mKeyboardView; + final Keyboard oldKeyboard = keyboardView.getKeyboard(); + keyboardView.setKeyboard(keyboard); mCurrentInputView.setKeyboardGeometry(keyboard.mTopPadding); - mKeyboardView.setKeyPreviewPopupEnabled( + keyboardView.setKeyPreviewPopupEnabled( SettingsValues.isKeyPreviewPopupEnabled(mPrefs, mResources), SettingsValues.getKeyPreviewPopupDismissDelay(mPrefs, mResources)); - mKeyboardView.updateAutoCorrectionState(mIsAutoCorrectionActive); - mKeyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); + keyboardView.updateAutoCorrectionState(mIsAutoCorrectionActive); + keyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); final boolean subtypeChanged = (oldKeyboard == null) || !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale); final boolean needsToDisplayLanguage = mSubtypeSwitcher.needsToDisplayLanguage( keyboard.mId.mLocale); - mKeyboardView.startDisplayLanguageOnSpacebar(subtypeChanged, needsToDisplayLanguage, + keyboardView.startDisplayLanguageOnSpacebar(subtypeChanged, needsToDisplayLanguage, ImfUtils.hasMultipleEnabledIMEsOrSubtypes(mLatinIME, true)); } @@ -350,7 +349,7 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions { return mKeyboardView; } - public View onCreateInputView() { + public View onCreateInputView(boolean isHardwareAcceleratedDrawingEnabled) { if (mKeyboardView != null) { mKeyboardView.closing(); } @@ -373,6 +372,10 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions { } mKeyboardView = (MainKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view); + if (isHardwareAcceleratedDrawingEnabled) { + mKeyboardView.setLayerType(View.LAYER_TYPE_HARDWARE, null); + // TODO: Should use LAYER_TYPE_SOFTWARE when hardware acceleration is off? + } mKeyboardView.setKeyboardActionListener(mLatinIME); if (mForceNonDistinctMultitouch) { mKeyboardView.setDistinctMultitouch(false); diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index f751fa53c..69e4d9805 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -25,7 +25,7 @@ import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.PorterDuff; import android.graphics.Rect; -import android.graphics.Region.Op; +import android.graphics.Region; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Message; @@ -35,9 +35,9 @@ import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.RelativeLayout; import android.widget.TextView; +import com.android.inputmethod.keyboard.internal.PreviewPlacerView; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; @@ -97,9 +97,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { // The maximum key label width in the proportion to the key width. private static final float MAX_LABEL_RATIO = 0.90f; - private final static int GESTURE_DRAWING_WIDTH = 5; - private final static int GESTURE_DRAWING_COLOR = 0xff33b5e5; - // Main keyboard private Keyboard mKeyboard; protected final KeyDrawParams mKeyDrawParams; @@ -109,10 +106,10 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { protected final KeyPreviewDrawParams mKeyPreviewDrawParams; private boolean mShowKeyPreviewPopup = true; private int mDelayAfterPreview; - private ViewGroup mPreviewPlacer; + private final PreviewPlacerView mPreviewPlacerView; - /** True if the gesture input is enabled. */ - protected boolean mGestureInputEnabled; + /** True if {@link KeyboardView} should handle gesture events. */ + protected boolean mShouldHandleGesture; // Drawing /** True if the entire keyboard needs to be dimmed. */ @@ -123,16 +120,15 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { private boolean mInvalidateAllKeys; /** The keys that should be drawn */ private final HashSet<Key> mInvalidatedKeys = new HashSet<Key>(); - /** The region of invalidated keys */ - private final Rect mInvalidatedKeysRect = new Rect(); - /** The region of invalidated gestures */ - private final Rect mInvalidatedGesturesRect = new Rect(); + /** The working rectangle variable */ + private final Rect mWorkingRect = new Rect(); /** The keyboard bitmap buffer for faster updates */ - private Bitmap mBuffer; + /** The clip region to draw keys */ + private final Region mClipRegion = new Region(); + private Bitmap mOffscreenBuffer; /** The canvas for the above mutable keyboard bitmap */ - private Canvas mCanvas; + private Canvas mOffscreenCanvas; private final Paint mPaint = new Paint(); - private final Paint mGesturePaint = new Paint(); private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics(); // This sparse array caches key label text height in pixel indexed by key label text size. private static final SparseArray<Float> sTextHeightCache = new SparseArray<Float>(); @@ -261,10 +257,12 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } public void updateKeyHeight(int keyHeight) { - if (mKeyLetterRatio >= 0.0f) + if (mKeyLetterRatio >= 0.0f) { mKeyLetterSize = (int)(keyHeight * mKeyLetterRatio); - if (mKeyLabelRatio >= 0.0f) + } + if (mKeyLabelRatio >= 0.0f) { mKeyLabelSize = (int)(keyHeight * mKeyLabelRatio); + } mKeyLargeLabelSize = (int)(keyHeight * mKeyLargeLabelRatio); mKeyLargeLetterSize = (int)(keyHeight * mKeyLargeLetterRatio); mKeyHintLetterSize = (int)(keyHeight * mKeyHintLetterRatio); @@ -346,13 +344,16 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } public void updateKeyHeight(int keyHeight) { - mPreviewTextSize = (int)(keyHeight * mPreviewTextRatio); - mKeyLetterSize = (int)(keyHeight * mKeyLetterRatio); + if (mPreviewTextRatio >= 0.0f) { + mPreviewTextSize = (int)(keyHeight * mPreviewTextRatio); + } + if (mKeyLetterRatio >= 0.0f) { + mKeyLetterSize = (int)(keyHeight * mKeyLetterRatio); + } } private static void setAlpha(Drawable drawable, int alpha) { - if (drawable == null) - return; + if (drawable == null) return; drawable.setAlpha(alpha); } } @@ -377,18 +378,12 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { R.styleable.KeyboardView_verticalCorrection, 0); mMoreKeysLayout = a.getResourceId(R.styleable.KeyboardView_moreKeysLayout, 0); mBackgroundDimAlpha = a.getInt(R.styleable.KeyboardView_backgroundDimAlpha, 0); + mPreviewPlacerView = new PreviewPlacerView(context, a); a.recycle(); mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout; mPaint.setAntiAlias(true); - - // TODO: These paint parameters should be specified via attribute of the view and styleable. - mGesturePaint.setAntiAlias(true); - mGesturePaint.setStyle(Paint.Style.STROKE); - mGesturePaint.setStrokeJoin(Paint.Join.ROUND); - mGesturePaint.setColor(GESTURE_DRAWING_COLOR); - mGesturePaint.setStrokeWidth(GESTURE_DRAWING_WIDTH); } // Read fraction value in TypedArray as float. @@ -443,8 +438,11 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { return mShowKeyPreviewPopup; } - public void setGestureInputEnabled(boolean gestureInputEnabled) { - mGestureInputEnabled = gestureInputEnabled; + public void setGestureHandlingMode(boolean shouldHandleGesture, + boolean drawsGesturePreviewTrail, boolean drawsGestureFloatingPreviewText) { + mShouldHandleGesture = shouldHandleGesture; + mPreviewPlacerView.setGesturePreviewMode( + drawsGesturePreviewTrail, drawsGestureFloatingPreviewText); } @Override @@ -461,65 +459,107 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); - if (mBufferNeedsUpdate || mBuffer == null) { + if (canvas.isHardwareAccelerated()) { + onDrawKeyboard(canvas); + return; + } + if (mBufferNeedsUpdate || mOffscreenBuffer == null) { mBufferNeedsUpdate = false; - onBufferDraw(); + if (maybeAllocateOffscreenBuffer()) { + mInvalidateAllKeys = true; + // TODO: Stop using the offscreen canvas even when in software rendering + if (mOffscreenCanvas != null) { + mOffscreenCanvas.setBitmap(mOffscreenBuffer); + } else { + mOffscreenCanvas = new Canvas(mOffscreenBuffer); + } + } + onDrawKeyboard(mOffscreenCanvas); } - canvas.drawBitmap(mBuffer, 0, 0, null); + canvas.drawBitmap(mOffscreenBuffer, 0, 0, null); } - private void onBufferDraw() { + private boolean maybeAllocateOffscreenBuffer() { final int width = getWidth(); final int height = getHeight(); - if (width == 0 || height == 0) - return; - if (mBuffer == null || mBuffer.getWidth() != width || mBuffer.getHeight() != height) { - if (mBuffer != null) - mBuffer.recycle(); - mBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - mInvalidateAllKeys = true; - if (mCanvas != null) { - mCanvas.setBitmap(mBuffer); - } else { - mCanvas = new Canvas(mBuffer); - } + if (width == 0 || height == 0) { + return false; } + if (mOffscreenBuffer != null && mOffscreenBuffer.getWidth() == width + && mOffscreenBuffer.getHeight() == height) { + return false; + } + freeOffscreenBuffer(); + mOffscreenBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + return true; + } + private void freeOffscreenBuffer() { + if (mOffscreenBuffer != null) { + mOffscreenBuffer.recycle(); + mOffscreenBuffer = null; + } + } + + private void onDrawKeyboard(final Canvas canvas) { if (mKeyboard == null) return; - final Canvas canvas = mCanvas; + final int width = getWidth(); + final int height = getHeight(); final Paint paint = mPaint; final KeyDrawParams params = mKeyDrawParams; - if (mInvalidateAllKeys || mInvalidatedKeys.isEmpty()) { - mInvalidatedKeysRect.set(0, 0, width, height); - canvas.clipRect(mInvalidatedKeysRect, Op.REPLACE); - canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR); + // Calculate clip region and set. + final boolean drawAllKeys = mInvalidateAllKeys || mInvalidatedKeys.isEmpty(); + final boolean isHardwareAccelerated = canvas.isHardwareAccelerated(); + // TODO: Confirm if it's really required to draw all keys when hardware acceleration is on. + if (drawAllKeys || isHardwareAccelerated) { + mClipRegion.set(0, 0, width, height); + } else { + mClipRegion.setEmpty(); + for (final Key key : mInvalidatedKeys) { + if (mKeyboard.hasKey(key)) { + final int x = key.mX + getPaddingLeft(); + final int y = key.mY + getPaddingTop(); + mWorkingRect.set(x, y, x + key.mWidth, y + key.mHeight); + mClipRegion.union(mWorkingRect); + } + } + } + if (!isHardwareAccelerated) { + canvas.clipRegion(mClipRegion, Region.Op.REPLACE); + } + + // Draw keyboard background. + canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR); + final Drawable background = getBackground(); + if (background != null) { + background.draw(canvas); + } + + // TODO: Confirm if it's really required to draw all keys when hardware acceleration is on. + if (drawAllKeys || isHardwareAccelerated) { // Draw all keys. for (final Key key : mKeyboard.mKeys) { onDrawKey(key, canvas, paint, params); } - if (mNeedsToDimEntireKeyboard) { - drawDimRectangle(canvas, mInvalidatedKeysRect, mBackgroundDimAlpha, paint); - } } else { // Draw invalidated keys. for (final Key key : mInvalidatedKeys) { - if (!mKeyboard.hasKey(key)) { - continue; - } - final int x = key.mX + getPaddingLeft(); - final int y = key.mY + getPaddingTop(); - mInvalidatedKeysRect.set(x, y, x + key.mWidth, y + key.mHeight); - canvas.clipRect(mInvalidatedKeysRect, Op.REPLACE); - canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR); - onDrawKey(key, canvas, paint, params); - if (mNeedsToDimEntireKeyboard) { - drawDimRectangle(canvas, mInvalidatedKeysRect, mBackgroundDimAlpha, paint); + if (mKeyboard.hasKey(key)) { + onDrawKey(key, canvas, paint, params); } } } + // Overlay a dark rectangle to dim. + if (mNeedsToDimEntireKeyboard) { + paint.setColor(Color.BLACK); + paint.setAlpha(mBackgroundDimAlpha); + // Note: clipRegion() above is in effect if it was called. + canvas.drawRect(0, 0, width, height, paint); + } + // ResearchLogging indicator. // TODO: Reimplement using a keyboard background image specific to the ResearchLogger, // and remove this call. @@ -528,7 +568,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } mInvalidatedKeys.clear(); - mInvalidatedKeysRect.setEmpty(); mInvalidateAllKeys = false; } @@ -853,13 +892,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { canvas.translate(-x, -y); } - // Overlay a dark rectangle to dim. - private static void drawDimRectangle(Canvas canvas, Rect rect, int alpha, Paint paint) { - paint.setColor(Color.BLACK); - paint.setAlpha(alpha); - canvas.drawRect(rect, paint); - } - public Paint newDefaultLabelPaint() { final Paint paint = new Paint(); paint.setAntiAlias(true); @@ -888,58 +920,33 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { mDrawingHandler.dismissKeyPreview(mDelayAfterPreview, tracker); } - private static class PreviewView extends RelativeLayout { - KeyPreviewDrawParams mParams; - Paint mGesturePaint; - - public PreviewView(Context context, KeyPreviewDrawParams params, Paint gesturePaint) { - super(context); - setWillNotDraw(false); - mParams = params; - mGesturePaint = gesturePaint; - } - - @Override - public void onDraw(Canvas canvas) { - super.onDraw(canvas); - canvas.translate(mParams.mCoordinates[0], mParams.mCoordinates[1]); - PointerTracker.drawGestureTrailForAllPointerTrackers(canvas, mGesturePaint); - canvas.translate(-mParams.mCoordinates[0], -mParams.mCoordinates[1]); - } - } - private void addKeyPreview(TextView keyPreview) { - if (mPreviewPlacer == null) { - createPreviewPlacer(); - } - mPreviewPlacer.addView( - keyPreview, ViewLayoutUtils.newLayoutParam(mPreviewPlacer, 0, 0)); + locatePreviewPlacerView(); + mPreviewPlacerView.addView( + keyPreview, ViewLayoutUtils.newLayoutParam(mPreviewPlacerView, 0, 0)); } - private void createPreviewPlacer() { - mPreviewPlacer = new PreviewView(getContext(), mKeyPreviewDrawParams, mGesturePaint); + private void locatePreviewPlacerView() { + if (mPreviewPlacerView.getParent() != null) { + return; + } + final int[] viewOrigin = new int[2]; + getLocationInWindow(viewOrigin); + mPreviewPlacerView.setOrigin(viewOrigin[0], viewOrigin[1]); final ViewGroup windowContentView = (ViewGroup)getRootView().findViewById(android.R.id.content); - windowContentView.addView(mPreviewPlacer); + windowContentView.addView(mPreviewPlacerView); + } + + public void showGestureFloatingPreviewText(String gestureFloatingPreviewText) { + locatePreviewPlacerView(); + mPreviewPlacerView.setGestureFloatingPreviewText(gestureFloatingPreviewText); } @Override public void showGestureTrail(PointerTracker tracker) { - if (mPreviewPlacer == null) { - createPreviewPlacer(); - } - final Rect r = tracker.getBoundingBox(); - if (!r.isEmpty()) { - // Invalidate the rectangular region encompassing the gesture. This is needed because - // past points along the gesture will fade and gradually disappear. - final KeyPreviewDrawParams params = mKeyPreviewDrawParams; - mInvalidatedGesturesRect.set(r); - mInvalidatedGesturesRect.offset(params.mCoordinates[0], params.mCoordinates[1]); - mInvalidatedGesturesRect.inset(-GESTURE_DRAWING_WIDTH, -GESTURE_DRAWING_WIDTH); - mPreviewPlacer.invalidate(mInvalidatedGesturesRect); - } else { - mPreviewPlacer.invalidate(); - } + locatePreviewPlacerView(); + mPreviewPlacerView.invalidatePointer(tracker); } @SuppressWarnings("deprecation") // setBackgroundDrawable is replaced by setBackground in API16 @@ -1055,9 +1062,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { mInvalidatedKeys.add(key); final int x = key.mX + getPaddingLeft(); final int y = key.mY + getPaddingTop(); - mInvalidatedKeysRect.union(x, y, x + key.mWidth, y + key.mHeight); + mWorkingRect.set(x, y, x + key.mWidth, y + key.mHeight); mBufferNeedsUpdate = true; - invalidate(mInvalidatedKeysRect); + invalidate(mWorkingRect); } public void closing() { @@ -1082,12 +1089,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { protected void onDetachedFromWindow() { super.onDetachedFromWindow(); closing(); - if (mPreviewPlacer != null) { - mPreviewPlacer.removeAllViews(); - } - if (mBuffer != null) { - mBuffer.recycle(); - mBuffer = null; - } + mPreviewPlacerView.removeAllViews(); + freeOffscreenBuffer(); } } diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 8c234e4e6..79459083f 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -43,6 +43,7 @@ import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; +import com.android.inputmethod.keyboard.internal.SuddenJumpingTouchEventHandler; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; @@ -153,8 +154,7 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key } break; case MSG_TYPING_STATE_EXPIRED: - cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator, - keyboardView.mAltCodeKeyWhileTypingFadeinAnimator); + startWhileTypingFadeinAnimation(keyboardView); break; } } @@ -228,7 +228,7 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key removeMessages(MSG_LONGPRESS_KEY); } - public static void cancelAndStartAnimators(final ObjectAnimator animatorToCancel, + private static void cancelAndStartAnimators(final ObjectAnimator animatorToCancel, final ObjectAnimator animatorToStart) { float startFraction = 0.0f; if (animatorToCancel.isStarted()) { @@ -240,18 +240,39 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key animatorToStart.setCurrentPlayTime(startTime); } + private static void startWhileTypingFadeinAnimation(final MainKeyboardView keyboardView) { + cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator, + keyboardView.mAltCodeKeyWhileTypingFadeinAnimator); + } + + private static void startWhileTypingFadeoutAnimation(final MainKeyboardView keyboardView) { + cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeinAnimator, + keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator); + } + @Override - public void startTypingStateTimer() { + public void startTypingStateTimer(Key typedKey) { + if (typedKey.isModifier() || typedKey.altCodeWhileTyping()) { + return; + } + final boolean isTyping = isTypingState(); removeMessages(MSG_TYPING_STATE_EXPIRED); + final MainKeyboardView keyboardView = getOuterInstance(); + + // When user hits the space or the enter key, just cancel the while-typing timer. + final int typedCode = typedKey.mCode; + if (typedCode == Keyboard.CODE_SPACE || typedCode == Keyboard.CODE_ENTER) { + startWhileTypingFadeinAnimation(keyboardView); + return; + } + sendMessageDelayed( obtainMessage(MSG_TYPING_STATE_EXPIRED), mParams.mIgnoreAltCodeKeyTimeout); if (isTyping) { return; } - final MainKeyboardView keyboardView = getOuterInstance(); - cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeinAnimator, - keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator); + startWhileTypingFadeoutAnimation(keyboardView); } @Override @@ -461,7 +482,7 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key super.setKeyboard(keyboard); mKeyDetector.setKeyboard( keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection); - PointerTracker.setKeyDetector(mKeyDetector, mGestureInputEnabled); + PointerTracker.setKeyDetector(mKeyDetector, mShouldHandleGesture); mTouchScreenRegulator.setKeyboard(keyboard); mMoreKeysPanelCache.clear(); @@ -479,6 +500,14 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key AccessibleKeyboardViewProxy.getInstance().setKeyboard(keyboard); } + @Override + public void setGestureHandlingMode(final boolean shouldHandleGesture, + boolean drawsGesturePreviewTrail, boolean drawsGestureFloatingPreviewText) { + super.setGestureHandlingMode(shouldHandleGesture, drawsGesturePreviewTrail, + drawsGestureFloatingPreviewText); + PointerTracker.setKeyDetector(mKeyDetector, shouldHandleGesture); + } + /** * Returns whether the device has distinct multi-touch panel. * @return true if the device has distinct multi-touch panel. @@ -491,23 +520,6 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key mHasDistinctMultitouch = hasDistinctMultitouch; } - /** - * When enabled, calls to {@link KeyboardActionListener#onCodeInput} will include key - * codes for adjacent keys. When disabled, only the primary key code will be - * reported. - * @param enabled whether or not the proximity correction is enabled - */ - public void setProximityCorrectionEnabled(boolean enabled) { - mKeyDetector.setProximityCorrectionEnabled(enabled); - } - - /** - * Returns true if proximity correction is enabled. - */ - public boolean isProximityCorrectionEnabled() { - return mKeyDetector.isProximityCorrectionEnabled(); - } - @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java index cd4e3001e..a183546dd 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java @@ -39,7 +39,11 @@ public class MoreKeysDetector extends KeyDetector { Key nearestKey = null; int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare; - for (final Key key : getKeyboard().mKeys) { + final Keyboard keyboard = getKeyboard(); + if (keyboard == null) { + throw new NullPointerException("Keyboard isn't set"); + } + for (final Key key : keyboard.mKeys) { final int dist = key.squaredDistanceToEdge(touchX, touchY); if (dist < nearestDist) { nearestKey = key; diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 4a5ecf986..e7e11f481 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -18,7 +18,6 @@ package com.android.inputmethod.keyboard; import android.graphics.Canvas; import android.graphics.Paint; -import android.graphics.Rect; import android.os.SystemClock; import android.util.Log; import android.view.MotionEvent; @@ -42,8 +41,8 @@ public class PointerTracker { private static final boolean DEBUG_LISTENER = false; private static boolean DEBUG_MODE = LatinImeLogger.sDBG; - // TODO: There should be an option to turn on/off the gesture input. - private static boolean sIsGestureEnabled = true; + /** True if {@link PointerTracker}s should handle gesture events. */ + private static boolean sShouldHandleGesture = false; private static final int MIN_GESTURE_RECOGNITION_TIME = 100; // msec @@ -83,7 +82,7 @@ public class PointerTracker { } public interface TimerProxy { - public void startTypingStateTimer(); + public void startTypingStateTimer(Key typedKey); public boolean isTypingState(); public void startKeyRepeatTimer(PointerTracker tracker); public void startLongPressTimer(PointerTracker tracker); @@ -96,7 +95,7 @@ public class PointerTracker { public static class Adapter implements TimerProxy { @Override - public void startTypingStateTimer() {} + public void startTypingStateTimer(Key typedKey) {} @Override public boolean isTypingState() { return false; } @Override @@ -199,7 +198,7 @@ public class PointerTracker { sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack; setParameters(MainKeyboardView.PointerTrackerParams.DEFAULT); - updateGestureInputEnabledState(null, false /* gestureInputEnabled */); + updateGestureHandlingMode(null, false /* shouldHandleGesture */); } public static void setParameters(MainKeyboardView.PointerTrackerParams params) { @@ -208,14 +207,13 @@ public class PointerTracker { params.mTouchNoiseThresholdDistance * params.mTouchNoiseThresholdDistance); } - private static void updateGestureInputEnabledState(Keyboard keyboard, - boolean gestureInputEnabled) { - if (!gestureInputEnabled + private static void updateGestureHandlingMode(Keyboard keyboard, boolean shouldHandleGesture) { + if (!shouldHandleGesture || AccessibilityUtils.getInstance().isTouchExplorationEnabled() || (keyboard != null && keyboard.mId.passwordInput())) { - sIsGestureEnabled = false; + sShouldHandleGesture = false; } else { - sIsGestureEnabled = true; + sShouldHandleGesture = true; } } @@ -243,7 +241,7 @@ public class PointerTracker { } } - public static void setKeyDetector(KeyDetector keyDetector, boolean gestureInputEnabledByUser) { + public static void setKeyDetector(KeyDetector keyDetector, boolean shouldHandleGesture) { final int trackersSize = sTrackers.size(); for (int i = 0; i < trackersSize; ++i) { final PointerTracker tracker = sTrackers.get(i); @@ -252,7 +250,7 @@ public class PointerTracker { tracker.mKeyboardLayoutHasBeenChanged = true; } final Keyboard keyboard = keyDetector.getKeyboard(); - updateGestureInputEnabledState(keyboard, gestureInputEnabledByUser); + updateGestureHandlingMode(keyboard, shouldHandleGesture); } public static void dismissAllKeyPreviews() { @@ -297,17 +295,6 @@ public class PointerTracker { sAggregratedPointers.reset(); } - // TODO: To handle multi-touch gestures we may want to move this method to - // {@link PointerTrackerQueue}. - public static void drawGestureTrailForAllPointerTrackers(Canvas canvas, Paint paint) { - final int trackersSize = sTrackers.size(); - for (int i = 0; i < trackersSize; ++i) { - final PointerTracker tracker = sTrackers.get(i); - tracker.mGestureStroke.drawGestureTrail(canvas, paint, tracker.getLastX(), - tracker.getLastY()); - } - } - private PointerTracker(int id, KeyEventHandler handler) { if (handler == null) throw new NullPointerException(); @@ -342,9 +329,7 @@ public class PointerTracker { mListener.onPressKey(key.mCode); final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; mKeyboardLayoutHasBeenChanged = false; - if (!key.altCodeWhileTyping() && !key.isModifier()) { - mTimerProxy.startTypingStateTimer(); - } + mTimerProxy.startTypingStateTimer(key); return keyboardLayoutHasBeenChanged; } return false; @@ -423,7 +408,7 @@ public class PointerTracker { if (mDrawingProxy != null) { setReleasedKeyGraphics(mCurrentKey); } - mCurrentKey = newKey; + // Keep {@link #mCurrentKey} that comes from previous keyboard. } final int keyQuarterWidth = mKeyboard.mMostCommonKeyWidth / 4; mKeyQuarterWidthSquared = keyQuarterWidth * keyQuarterWidth; @@ -525,6 +510,12 @@ public class PointerTracker { mDrawingProxy.invalidateKey(key); } + public void drawGestureTrail(Canvas canvas, Paint paint) { + if (mInGesture) { + mGestureStroke.drawGestureTrail(canvas, paint, mLastX, mLastY); + } + } + public int getLastX() { return mLastX; } @@ -536,9 +527,6 @@ public class PointerTracker { public long getDownTime() { return mDownTime; } - public Rect getBoundingBox() { - return mGestureStroke.getBoundingBox(); - } private Key onDownKey(int x, int y, long eventTime) { mDownTime = eventTime; @@ -669,8 +657,8 @@ public class PointerTracker { if (queue != null && queue.size() == 1) { mIsPossibleGesture = false; // A gesture should start only from the letter key. - if (sIsGestureEnabled && mIsAlphabetKeyboard && !mIsShowingMoreKeysPanel && key != null - && Keyboard.isLetterCode(key.mCode)) { + if (sShouldHandleGesture && mIsAlphabetKeyboard && !mIsShowingMoreKeysPanel + && key != null && Keyboard.isLetterCode(key.mCode)) { mIsPossibleGesture = true; // TODO: pointer times should be relative to first down even in entire batch input // instead of resetting to 0 for each new down event. @@ -714,7 +702,7 @@ public class PointerTracker { private void onGestureMoveEvent(PointerTracker tracker, int x, int y, long eventTime, boolean isHistorical, Key key) { final int gestureTime = (int)(eventTime - tracker.getDownTime()); - if (sIsGestureEnabled && mIsPossibleGesture) { + if (sShouldHandleGesture && mIsPossibleGesture) { final GestureStroke stroke = mGestureStroke; stroke.addPoint(x, y, gestureTime, isHistorical); if (!mInGesture && stroke.isStartOfAGesture(gestureTime, sWasInGesture)) { @@ -804,13 +792,16 @@ public class PointerTracker { final int dx = x - lastX; final int dy = y - lastY; final int lastMoveSquared = dx * dx + dy * dy; + // TODO: Should find a way to balance gesture detection and this hack. if (sNeedsPhantomSuddenMoveEventHack - && lastMoveSquared >= mKeyQuarterWidthSquared) { + && lastMoveSquared >= mKeyQuarterWidthSquared + && !mIsPossibleGesture) { if (DEBUG_MODE) { Log.w(TAG, String.format("onMoveEvent:" + " phantom sudden move event is translated to " + "up[%d,%d]/down[%d,%d] events", lastX, lastY, x, y)); } + // TODO: This should be moved to outside of this nested if-clause? if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY); } @@ -826,7 +817,9 @@ public class PointerTracker { && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) { onUpEventInternal(x, y, eventTime); } - mKeyAlreadyProcessed = true; + if (!mIsPossibleGesture) { + mKeyAlreadyProcessed = true; + } setReleasedKeyGraphics(oldKey); } } @@ -842,7 +835,9 @@ public class PointerTracker { if (mIsAllowedSlidingKeyInput) { onMoveToNewKey(key, x, y); } else { - mKeyAlreadyProcessed = true; + if (!mIsPossibleGesture) { + mKeyAlreadyProcessed = true; + } } } } @@ -881,6 +876,7 @@ public class PointerTracker { private void onUpEventInternal(int x, int y, long eventTime) { mTimerProxy.cancelKeyTimers(); mIsInSlidingKeyInput = false; + mIsPossibleGesture = false; // Release the last pressed key. setReleasedKeyGraphics(mCurrentKey); if (mIsShowingMoreKeysPanel) { @@ -958,9 +954,7 @@ public class PointerTracker { public void onRegisterKey(Key key) { if (key != null) { detectAndSendKey(key, key.mX, key.mY); - if (!key.altCodeWhileTyping() && !key.isModifier()) { - mTimerProxy.startTypingStateTimer(); - } + mTimerProxy.startTypingStateTimer(key); } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java index c16b70ef0..28d6c1d07 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java @@ -16,7 +16,6 @@ package com.android.inputmethod.keyboard.internal; import android.graphics.Canvas; import android.graphics.Paint; -import android.graphics.Rect; import android.util.FloatMath; import com.android.inputmethod.latin.Constants; @@ -41,7 +40,6 @@ public class GestureStroke { private int mMinGestureLength; private int mMinGestureLengthWhileInGesture; private int mMinGestureSampleLength; - private final Rect mDrawingRect = new Rect(); // TODO: Move some of these to resource. private static final float MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH = 1.0f; @@ -90,7 +88,6 @@ public class GestureStroke { mEventTimes.setLength(0); mXCoordinates.setLength(0); mYCoordinates.setLength(0); - mDrawingRect.setEmpty(); } private void updateLastPoint(final int x, final int y, final int time) { @@ -198,8 +195,4 @@ public class GestureStroke { } } } - - public Rect getBoundingBox() { - return mDrawingRect; - } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java index 53261205d..94a7b826f 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java @@ -84,6 +84,19 @@ public class KeySpecParser { } mIconId = getIconId(moreKeySpec); } + + @Override + public String toString() { + final String label = (mIconId == KeyboardIconsSet.ICON_UNDEFINED ? mLabel + : PREFIX_ICON + KeyboardIconsSet.getIconName(mIconId)); + final String output = (mCode == Keyboard.CODE_OUTPUT_TEXT ? mOutputText + : Keyboard.printableCode(mCode)); + if (StringUtils.codePointCount(label) == 1 && label.codePointAt(0) == mCode) { + return output; + } else { + return label + "|" + output; + } + } } private KeySpecParser() { diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java index d732fc061..bec0f1fef 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java @@ -131,101 +131,102 @@ public final class KeyboardTextsSet { /* 23 */ "more_keys_for_nordic_row2_10", /* 24 */ "more_keys_for_nordic_row2_11", /* 25 */ "keylabel_for_east_slavic_row1_9", - /* 26 */ "keylabel_for_east_slavic_row2_1", - /* 27 */ "keylabel_for_east_slavic_row3_5", - /* 28 */ "more_keys_for_cyrillic_u", - /* 29 */ "more_keys_for_cyrillic_ye", - /* 30 */ "more_keys_for_cyrillic_en", - /* 31 */ "more_keys_for_cyrillic_ha", - /* 32 */ "more_keys_for_east_slavic_row2_1", - /* 33 */ "more_keys_for_cyrillic_o", - /* 34 */ "more_keys_for_cyrillic_soft_sign", - /* 35 */ "keylabel_for_south_slavic_row1_6", - /* 36 */ "keylabel_for_south_slavic_row2_11", - /* 37 */ "keylabel_for_south_slavic_row3_1", - /* 38 */ "keylabel_for_south_slavic_row3_8", - /* 39 */ "more_keys_for_cyrillic_ie", - /* 40 */ "more_keys_for_cyrillic_i", - /* 41 */ "more_keys_for_single_quote", - /* 42 */ "more_keys_for_double_quote", - /* 43 */ "more_keys_for_tablet_double_quote", - /* 44 */ "more_keys_for_currency_dollar", - /* 45 */ "more_keys_for_currency_euro", - /* 46 */ "more_keys_for_currency_pound", - /* 47 */ "more_keys_for_currency_general", - /* 48 */ "more_keys_for_punctuation", - /* 49 */ "more_keys_for_star", - /* 50 */ "more_keys_for_bullet", - /* 51 */ "more_keys_for_plus", - /* 52 */ "more_keys_for_left_parenthesis", - /* 53 */ "more_keys_for_right_parenthesis", - /* 54 */ "more_keys_for_less_than", - /* 55 */ "more_keys_for_greater_than", - /* 56 */ "more_keys_for_arabic_diacritics", - /* 57 */ "keyhintlabel_for_arabic_diacritics", - /* 58 */ "keylabel_for_symbols_1", - /* 59 */ "keylabel_for_symbols_2", - /* 60 */ "keylabel_for_symbols_3", - /* 61 */ "keylabel_for_symbols_4", - /* 62 */ "keylabel_for_symbols_5", - /* 63 */ "keylabel_for_symbols_6", - /* 64 */ "keylabel_for_symbols_7", - /* 65 */ "keylabel_for_symbols_8", - /* 66 */ "keylabel_for_symbols_9", - /* 67 */ "keylabel_for_symbols_0", - /* 68 */ "additional_more_keys_for_symbols_1", - /* 69 */ "additional_more_keys_for_symbols_2", - /* 70 */ "additional_more_keys_for_symbols_3", - /* 71 */ "additional_more_keys_for_symbols_4", - /* 72 */ "additional_more_keys_for_symbols_5", - /* 73 */ "additional_more_keys_for_symbols_6", - /* 74 */ "additional_more_keys_for_symbols_7", - /* 75 */ "additional_more_keys_for_symbols_8", - /* 76 */ "additional_more_keys_for_symbols_9", - /* 77 */ "additional_more_keys_for_symbols_0", - /* 78 */ "more_keys_for_symbols_1", - /* 79 */ "more_keys_for_symbols_2", - /* 80 */ "more_keys_for_symbols_3", - /* 81 */ "more_keys_for_symbols_4", - /* 82 */ "more_keys_for_symbols_5", - /* 83 */ "more_keys_for_symbols_6", - /* 84 */ "more_keys_for_symbols_7", - /* 85 */ "more_keys_for_symbols_8", - /* 86 */ "more_keys_for_symbols_9", - /* 87 */ "more_keys_for_symbols_0", - /* 88 */ "keylabel_for_comma", - /* 89 */ "more_keys_for_comma", - /* 90 */ "keylabel_for_symbols_question", - /* 91 */ "keylabel_for_symbols_semicolon", - /* 92 */ "keylabel_for_symbols_percent", - /* 93 */ "more_keys_for_symbols_exclamation", - /* 94 */ "more_keys_for_symbols_question", - /* 95 */ "more_keys_for_symbols_semicolon", - /* 96 */ "more_keys_for_symbols_percent", - /* 97 */ "keylabel_for_tablet_comma", - /* 98 */ "keyhintlabel_for_tablet_comma", - /* 99 */ "more_keys_for_tablet_comma", - /* 100 */ "keyhintlabel_for_tablet_period", - /* 101 */ "more_keys_for_tablet_period", - /* 102 */ "keylabel_for_apostrophe", - /* 103 */ "keyhintlabel_for_apostrophe", - /* 104 */ "more_keys_for_apostrophe", - /* 105 */ "more_keys_for_am_pm", - /* 106 */ "settings_as_more_key", - /* 107 */ "shortcut_as_more_key", - /* 108 */ "action_next_as_more_key", - /* 109 */ "action_previous_as_more_key", - /* 110 */ "label_to_more_symbol_key", - /* 111 */ "label_to_more_symbol_for_tablet_key", - /* 112 */ "label_tab_key", - /* 113 */ "label_to_phone_numeric_key", - /* 114 */ "label_to_phone_symbols_key", - /* 115 */ "label_time_am", - /* 116 */ "label_time_pm", - /* 117 */ "label_to_symbol_key_pcqwerty", - /* 118 */ "keylabel_for_popular_domain", - /* 119 */ "more_keys_for_popular_domain", - /* 120 */ "more_keys_for_smiley", + /* 26 */ "keylabel_for_east_slavic_row1_12", + /* 27 */ "keylabel_for_east_slavic_row2_1", + /* 28 */ "keylabel_for_east_slavic_row2_11", + /* 29 */ "keylabel_for_east_slavic_row3_5", + /* 30 */ "more_keys_for_cyrillic_u", + /* 31 */ "more_keys_for_cyrillic_en", + /* 32 */ "more_keys_for_cyrillic_ghe", + /* 33 */ "more_keys_for_east_slavic_row2_1", + /* 34 */ "more_keys_for_cyrillic_o", + /* 35 */ "more_keys_for_cyrillic_soft_sign", + /* 36 */ "keylabel_for_south_slavic_row1_6", + /* 37 */ "keylabel_for_south_slavic_row2_11", + /* 38 */ "keylabel_for_south_slavic_row3_1", + /* 39 */ "keylabel_for_south_slavic_row3_8", + /* 40 */ "more_keys_for_cyrillic_ie", + /* 41 */ "more_keys_for_cyrillic_i", + /* 42 */ "more_keys_for_single_quote", + /* 43 */ "more_keys_for_double_quote", + /* 44 */ "more_keys_for_tablet_double_quote", + /* 45 */ "more_keys_for_currency_dollar", + /* 46 */ "more_keys_for_currency_euro", + /* 47 */ "more_keys_for_currency_pound", + /* 48 */ "more_keys_for_currency_general", + /* 49 */ "more_keys_for_punctuation", + /* 50 */ "more_keys_for_star", + /* 51 */ "more_keys_for_bullet", + /* 52 */ "more_keys_for_plus", + /* 53 */ "more_keys_for_left_parenthesis", + /* 54 */ "more_keys_for_right_parenthesis", + /* 55 */ "more_keys_for_less_than", + /* 56 */ "more_keys_for_greater_than", + /* 57 */ "more_keys_for_arabic_diacritics", + /* 58 */ "keyhintlabel_for_arabic_diacritics", + /* 59 */ "keylabel_for_symbols_1", + /* 60 */ "keylabel_for_symbols_2", + /* 61 */ "keylabel_for_symbols_3", + /* 62 */ "keylabel_for_symbols_4", + /* 63 */ "keylabel_for_symbols_5", + /* 64 */ "keylabel_for_symbols_6", + /* 65 */ "keylabel_for_symbols_7", + /* 66 */ "keylabel_for_symbols_8", + /* 67 */ "keylabel_for_symbols_9", + /* 68 */ "keylabel_for_symbols_0", + /* 69 */ "additional_more_keys_for_symbols_1", + /* 70 */ "additional_more_keys_for_symbols_2", + /* 71 */ "additional_more_keys_for_symbols_3", + /* 72 */ "additional_more_keys_for_symbols_4", + /* 73 */ "additional_more_keys_for_symbols_5", + /* 74 */ "additional_more_keys_for_symbols_6", + /* 75 */ "additional_more_keys_for_symbols_7", + /* 76 */ "additional_more_keys_for_symbols_8", + /* 77 */ "additional_more_keys_for_symbols_9", + /* 78 */ "additional_more_keys_for_symbols_0", + /* 79 */ "more_keys_for_symbols_1", + /* 80 */ "more_keys_for_symbols_2", + /* 81 */ "more_keys_for_symbols_3", + /* 82 */ "more_keys_for_symbols_4", + /* 83 */ "more_keys_for_symbols_5", + /* 84 */ "more_keys_for_symbols_6", + /* 85 */ "more_keys_for_symbols_7", + /* 86 */ "more_keys_for_symbols_8", + /* 87 */ "more_keys_for_symbols_9", + /* 88 */ "more_keys_for_symbols_0", + /* 89 */ "keylabel_for_comma", + /* 90 */ "more_keys_for_comma", + /* 91 */ "keylabel_for_symbols_question", + /* 92 */ "keylabel_for_symbols_semicolon", + /* 93 */ "keylabel_for_symbols_percent", + /* 94 */ "more_keys_for_symbols_exclamation", + /* 95 */ "more_keys_for_symbols_question", + /* 96 */ "more_keys_for_symbols_semicolon", + /* 97 */ "more_keys_for_symbols_percent", + /* 98 */ "keylabel_for_tablet_comma", + /* 99 */ "keyhintlabel_for_tablet_comma", + /* 100 */ "more_keys_for_tablet_comma", + /* 101 */ "keyhintlabel_for_tablet_period", + /* 102 */ "more_keys_for_tablet_period", + /* 103 */ "keylabel_for_apostrophe", + /* 104 */ "keyhintlabel_for_apostrophe", + /* 105 */ "more_keys_for_apostrophe", + /* 106 */ "more_keys_for_am_pm", + /* 107 */ "settings_as_more_key", + /* 108 */ "shortcut_as_more_key", + /* 109 */ "action_next_as_more_key", + /* 110 */ "action_previous_as_more_key", + /* 111 */ "label_to_more_symbol_key", + /* 112 */ "label_to_more_symbol_for_tablet_key", + /* 113 */ "label_tab_key", + /* 114 */ "label_to_phone_numeric_key", + /* 115 */ "label_to_phone_symbols_key", + /* 116 */ "label_time_am", + /* 117 */ "label_time_pm", + /* 118 */ "label_to_symbol_key_pcqwerty", + /* 119 */ "keylabel_for_popular_domain", + /* 120 */ "more_keys_for_popular_domain", + /* 121 */ "more_keys_for_smiley", }; private static final String EMPTY = ""; @@ -236,41 +237,41 @@ public final class KeyboardTextsSet { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, - EMPTY, EMPTY, - /* ~40 */ - /* 41 */ "!fixedColumnOrder!4,\u2018,\u2019,\u201A,\u201B", + EMPTY, EMPTY, EMPTY, + /* ~41 */ + /* 42 */ "!fixedColumnOrder!4,\u2018,\u2019,\u201A,\u201B", // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. // <string name="more_keys_for_double_quote">!fixedColumnOrder!6,“,”,„,‟,«,»</string> - /* 42 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB,\u00BB", + /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB,\u00BB", // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«,»,‘,’,‚,‛</string> - /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B", + /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B", // U+00A2: "¢" CENT SIGN // U+00A3: "£" POUND SIGN // U+20AC: "€" EURO SIGN // U+00A5: "¥" YEN SIGN // U+20B1: "₱" PESO SIGN - /* 44 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1", - /* 45 */ "\u00A2,\u00A3,$,\u00A5,\u20B1", - /* 46 */ "\u00A2,$,\u20AC,\u00A5,\u20B1", - /* 47 */ "\u00A2,$,\u20AC,\u00A3,\u00A5,\u20B1", - /* 48 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\\,,?,@,&,\\%,+,;,/,(,)", + /* 45 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1", + /* 46 */ "\u00A2,\u00A3,$,\u00A5,\u20B1", + /* 47 */ "\u00A2,$,\u20AC,\u00A5,\u20B1", + /* 48 */ "\u00A2,$,\u20AC,\u00A3,\u00A5,\u20B1", + /* 49 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\\,,?,@,&,\\%,+,;,/,(,)", // U+2020: "†" DAGGER // U+2021: "‡" DOUBLE DAGGER // U+2605: "★" BLACK STAR - /* 49 */ "\u2020,\u2021,\u2605", + /* 50 */ "\u2020,\u2021,\u2605", // U+266A: "♪" EIGHTH NOTE // U+2665: "♥" BLACK HEART SUIT // U+2660: "♠" BLACK SPADE SUIT // U+2666: "♦" BLACK DIAMOND SUIT // U+2663: "♣" BLACK CLUB SUIT - /* 50 */ "\u266A,\u2665,\u2660,\u2666,\u2663", + /* 51 */ "\u266A,\u2665,\u2660,\u2666,\u2663", // U+00B1: "±" PLUS-MINUS SIGN - /* 51 */ "\u00B1", + /* 52 */ "\u00B1", // The all letters need to be mirrored are found at // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt - /* 52 */ "!fixedColumnOrder!3,<,{,[", - /* 53 */ "!fixedColumnOrder!3,>,},]", + /* 53 */ "!fixedColumnOrder!3,<,{,[", + /* 54 */ "!fixedColumnOrder!3,>,},]", // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK // U+2264: "≤" LESS-THAN OR EQUAL TO @@ -286,95 +287,148 @@ public final class KeyboardTextsSet { // U+201D: "”" RIGHT DOUBLE QUOTATION MARK // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK - /* 54 */ "!fixedColumnOrder!3,\u2039,\u2264,\u00AB", - /* 55 */ "!fixedColumnOrder!3,\u203A,\u2265,\u00BB", - /* 56 */ EMPTY, + /* 55 */ "!fixedColumnOrder!3,\u2039,\u2264,\u00AB", + /* 56 */ "!fixedColumnOrder!3,\u203A,\u2265,\u00BB", /* 57 */ EMPTY, - /* 58 */ "1", - /* 59 */ "2", - /* 60 */ "3", - /* 61 */ "4", - /* 62 */ "5", - /* 63 */ "6", - /* 64 */ "7", - /* 65 */ "8", - /* 66 */ "9", - /* 67 */ "0", - /* 68~ */ + /* 58 */ EMPTY, + /* 59 */ "1", + /* 60 */ "2", + /* 61 */ "3", + /* 62 */ "4", + /* 63 */ "5", + /* 64 */ "6", + /* 65 */ "7", + /* 66 */ "8", + /* 67 */ "9", + /* 68 */ "0", + /* 69~ */ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, - /* ~77 */ + /* ~78 */ // U+00B9: "¹" SUPERSCRIPT ONE // U+00BD: "½" VULGAR FRACTION ONE HALF // U+2153: "⅓" VULGAR FRACTION ONE THIRD // U+00BC: "¼" VULGAR FRACTION ONE QUARTER // U+215B: "⅛" VULGAR FRACTION ONE EIGHTH - /* 78 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B", + /* 79 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B", // U+00B2: "²" SUPERSCRIPT TWO // U+2154: "⅔" VULGAR FRACTION TWO THIRDS - /* 79 */ "\u00B2,\u2154", + /* 80 */ "\u00B2,\u2154", // U+00B3: "³" SUPERSCRIPT THREE // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS - /* 80 */ "\u00B3,\u00BE,\u215C", + /* 81 */ "\u00B3,\u00BE,\u215C", // U+2074: "⁴" SUPERSCRIPT FOUR - /* 81 */ "\u2074", + /* 82 */ "\u2074", // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS - /* 82 */ "\u215D", - /* 83 */ EMPTY, + /* 83 */ "\u215D", + /* 84 */ EMPTY, // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS - /* 84 */ "\u215E", - /* 85 */ EMPTY, + /* 85 */ "\u215E", /* 86 */ EMPTY, + /* 87 */ EMPTY, // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N // U+2205: "∅" EMPTY SET - /* 87 */ "\u207F,\u2205", - /* 88 */ ",", - /* 89 */ EMPTY, - /* 90 */ "?", - /* 91 */ ";", - /* 92 */ "%", + /* 88 */ "\u207F,\u2205", + /* 89 */ ",", + /* 90 */ EMPTY, + /* 91 */ "?", + /* 92 */ ";", + /* 93 */ "%", // U+00A1: "¡" INVERTED EXCLAMATION MARK - /* 93 */ "\u00A1", + /* 94 */ "\u00A1", // U+00BF: "¿" INVERTED QUESTION MARK - /* 94 */ "\u00BF", - /* 95 */ EMPTY, + /* 95 */ "\u00BF", + /* 96 */ EMPTY, // U+2030: "‰" PER MILLE SIGN - /* 96 */ "\u2030", - /* 97 */ ",", - /* 98 */ "!", + /* 97 */ "\u2030", + /* 98 */ ",", /* 99 */ "!", - /* 100 */ "?", + /* 100 */ "!", /* 101 */ "?", - /* 102 */ "\'", - /* 103 */ "\"", + /* 102 */ "?", + /* 103 */ "\'", /* 104 */ "\"", - /* 105 */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm", - /* 106 */ "!icon/settings_key|!code/key_settings", - /* 107 */ "!icon/shortcut_key|!code/key_shortcut", - /* 108 */ "!hasLabels!,!text/label_next_key|!code/key_action_next", - /* 109 */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous", + /* 105 */ "\"", + /* 106 */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm", + /* 107 */ "!icon/settings_key|!code/key_settings", + /* 108 */ "!icon/shortcut_key|!code/key_shortcut", + /* 109 */ "!hasLabels!,!text/label_next_key|!code/key_action_next", + /* 110 */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous", // Label for "switch to more symbol" modifier key. Must be short to fit on key! - /* 110 */ "= \\ <", + /* 111 */ "= \\ <", // Label for "switch to more symbol" modifier key on tablets. Must be short to fit on key! - /* 111 */ "~ \\ {", + /* 112 */ "~ \\ {", // Label for "Tab" key. Must be short to fit on key! - /* 112 */ "Tab", + /* 113 */ "Tab", // Label for "switch to phone numeric" key. Must be short to fit on key! - /* 113 */ "123", + /* 114 */ "123", // Label for "switch to phone symbols" key. Must be short to fit on key! // U+FF0A: "*" FULLWIDTH ASTERISK // U+FF03: "#" FULLWIDTH NUMBER SIGN - /* 114 */ "\uFF0A\uFF03", + /* 115 */ "\uFF0A\uFF03", // Key label for "ante meridiem" - /* 115 */ "AM", + /* 116 */ "AM", // Key label for "post meridiem" - /* 116 */ "PM", + /* 117 */ "PM", // Label for "switch to symbols" key on PC QWERTY layout - /* 117 */ "Sym", - /* 118 */ ".com", + /* 118 */ "Sym", + /* 119 */ ".com", // popular web domains for the locale - most popular, displayed on the keyboard - /* 119 */ "!hasLabels!,.net,.org,.gov,.edu", - /* 120 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ", + /* 120 */ "!hasLabels!,.net,.org,.gov,.edu", + /* 121 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ", + }; + + /* Language af: Afrikaans */ + private static final String[] LANGUAGE_af = { + // This is the same as Dutch except more keys of y and demoting vowels with diaeresis. + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* 0 */ "\u00E1,\u00E2,\u00E4,\u00E0,\u00E6,\u00E3,\u00E5,\u0101", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* 1 */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+0133: "ij" LATIN SMALL LIGATURE IJ + /* 2 */ "\u00ED,\u00EC,\u00EF,\u00EE,\u012F,\u012B,\u0133", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + /* 3 */ "\u00F3,\u00F4,\u00F6,\u00F2,\u00F5,\u0153,\u00F8,\u014D", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* 4 */ "\u00FA,\u00FB,\u00FC,\u00F9,\u016B", + /* 5 */ null, + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* 6 */ "\u00F1,\u0144", + /* 7 */ null, + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+0133: "ij" LATIN SMALL LIGATURE IJ + /* 8 */ "\u00FD,\u0133", }; /* Language ar: Arabic */ @@ -382,33 +436,33 @@ public final class KeyboardTextsSet { /* 0~ */ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, - /* ~41 */ + null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~42 */ // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK // <string name="more_keys_for_double_quote">“,”,„,‟,«|»,»|«</string> - /* 42 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB", + /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB", // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«|»,»|«;,‘,’,‚,‛</string> - /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B", - /* 44~ */ + /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B", + /* 45~ */ null, null, null, null, - /* ~47 */ + /* ~48 */ // U+061F: "؟" ARABIC QUESTION MARK // U+060C: "،" ARABIC COMMA // U+061B: "؛" ARABIC SEMICOLON - /* 48 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(,)", + /* 49 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(,)", // U+2605: "★" BLACK STAR // U+066D: "٭" ARABIC FIVE POINTED STAR - /* 49 */ "\u2605,\u066D", + /* 50 */ "\u2605,\u066D", // U+266A: "♪" EIGHTH NOTE - /* 50 */ "\u266A", - /* 51 */ null, + /* 51 */ "\u266A", + /* 52 */ null, // The all letters need to be mirrored are found at // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt // U+FD3E: "﴾" ORNATE LEFT PARENTHESIS // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS - /* 52 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]", - /* 53 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[", + /* 53 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]", + /* 54 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[", // U+2264: "≤" LESS-THAN OR EQUAL TO // U+2265: "≥" GREATER-THAN EQUAL TO // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK @@ -424,8 +478,8 @@ public final class KeyboardTextsSet { // U+201D: "”" RIGHT DOUBLE QUOTATION MARK // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK - /* 54 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB", - /* 55 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB", + /* 55 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB", + /* 56 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB", // U+0655: "ٕ" ARABIC HAMZA BELOW // U+0654: "ٔ" ARABIC HAMZA ABOVE // U+0652: "ْ" ARABIC SUKUN @@ -441,64 +495,64 @@ public final class KeyboardTextsSet { // U+064E: "َ" ARABIC FATHA // U+0640: "ـ" ARABIC TATWEEL // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. - /* 56 */ "!fixedColumnOrder!7,\u0655,\u0654,\u0652,\u064D,\u064C,\u064B,\u0651,\u0656,\u0670,\u0653,\u0650,\u064F,\u064E,\u0640\u0640\u0640|\u0640", - /* 57 */ "\u0651", + /* 57 */ "!fixedColumnOrder!7,\u0655,\u0654,\u0652,\u064D,\u064C,\u064B,\u0651,\u0656,\u0670,\u0653,\u0650,\u064F,\u064E,\u0640\u0640\u0640|\u0640", + /* 58 */ "\u0651", // U+0661: "١" ARABIC-INDIC DIGIT ONE - /* 58 */ "\u0661", + /* 59 */ "\u0661", // U+0662: "٢" ARABIC-INDIC DIGIT TWO - /* 59 */ "\u0662", + /* 60 */ "\u0662", // U+0663: "٣" ARABIC-INDIC DIGIT THREE - /* 60 */ "\u0663", + /* 61 */ "\u0663", // U+0664: "٤" ARABIC-INDIC DIGIT FOUR - /* 61 */ "\u0664", + /* 62 */ "\u0664", // U+0665: "٥" ARABIC-INDIC DIGIT FIVE - /* 62 */ "\u0665", + /* 63 */ "\u0665", // U+0666: "٦" ARABIC-INDIC DIGIT SIX - /* 63 */ "\u0666", + /* 64 */ "\u0666", // U+0667: "٧" ARABIC-INDIC DIGIT SEVEN - /* 64 */ "\u0667", + /* 65 */ "\u0667", // U+0668: "٨" ARABIC-INDIC DIGIT EIGHT - /* 65 */ "\u0668", + /* 66 */ "\u0668", // U+0669: "٩" ARABIC-INDIC DIGIT NINE - /* 66 */ "\u0669", + /* 67 */ "\u0669", // U+0660: "٠" ARABIC-INDIC DIGIT ZERO - /* 67 */ "\u0660", - /* 68 */ "1", - /* 69 */ "2", - /* 70 */ "3", - /* 71 */ "4", - /* 72 */ "5", - /* 73 */ "6", - /* 74 */ "7", - /* 75 */ "8", - /* 76 */ "9", + /* 68 */ "\u0660", + /* 69 */ "1", + /* 70 */ "2", + /* 71 */ "3", + /* 72 */ "4", + /* 73 */ "5", + /* 74 */ "6", + /* 75 */ "7", + /* 76 */ "8", + /* 77 */ "9", // U+066B: "٫" ARABIC DECIMAL SEPARATOR // U+066C: "٬" ARABIC THOUSANDS SEPARATOR - /* 77 */ "0,\u066B,\u066C", - /* 78~ */ + /* 78 */ "0,\u066B,\u066C", + /* 79~ */ null, null, null, null, null, null, null, null, null, null, - /* ~87 */ + /* ~88 */ // U+060C: "،" ARABIC COMMA - /* 88 */ "\u060C", - /* 89 */ "\\,", - /* 90 */ "\u061F", - /* 91 */ "\u061B", + /* 89 */ "\u060C", + /* 90 */ "\\,", + /* 91 */ "\u061F", + /* 92 */ "\u061B", // U+066A: "٪" ARABIC PERCENT SIGN - /* 92 */ "\u066A", - /* 93 */ null, - /* 94 */ "?", - /* 95 */ ";", + /* 93 */ "\u066A", + /* 94 */ null, + /* 95 */ "?", + /* 96 */ ";", // U+2030: "‰" PER MILLE SIGN - /* 96 */ "\\%,\u2030", - /* 97~ */ + /* 97 */ "\\%,\u2030", + /* 98~ */ null, null, null, null, null, - /* ~101 */ + /* ~102 */ // U+060C: "،" ARABIC COMMA // U+061B: "؛" ARABIC SEMICOLON // U+061F: "؟" ARABIC QUESTION MARK - /* 102 */ "\u060C", - /* 103 */ "\u061F", - /* 104 */ "\u061F,\u061B,!,:,-,/,\',\"", + /* 103 */ "\u060C", + /* 104 */ "\u061F", + /* 105 */ "\u061F,\u061B,!,:,-,/,\',\"", }; /* Language be: Belarusian */ @@ -509,19 +563,24 @@ public final class KeyboardTextsSet { /* ~24 */ // U+045E: "ў" CYRILLIC SMALL LETTER SHORT U /* 25 */ "\u045E", + // U+0451: "ё" CYRILLIC SMALL LETTER IO + /* 26 */ "\u0451", // U+044B: "ы" CYRILLIC SMALL LETTER YERU - /* 26 */ "\u044B", + /* 27 */ "\u044B", + // U+044D: "э" CYRILLIC SMALL LETTER E + /* 28 */ "\u044D", // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I - /* 27 */ "\u0456", - /* 28~ */ - null, null, null, - /* ~30 */ - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 31 */ "\u044A", - /* 32 */ null, - /* 33 */ null, + /* 29 */ "\u0456", + /* 30~ */ + null, null, null, null, null, + /* ~34 */ // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 34 */ "\u044A", + /* 35 */ "\u044A", + /* 36~ */ + null, null, null, null, + /* ~39 */ + // U+0451: "ё" CYRILLIC SMALL LETTER IO + /* 40 */ "\u0451", }; /* Language ca: Catalan */ @@ -854,22 +913,22 @@ public final class KeyboardTextsSet { /* 8~ */ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, - /* ~47 */ + null, null, null, null, null, null, null, null, null, null, null, + /* ~48 */ // U+00A1: "¡" INVERTED EXCLAMATION MARK // U+00BF: "¿" INVERTED QUESTION MARK - /* 48 */ "!fixedColumnOrder!9,\u00A1,\",\',#,-,:,!,\\,,?,\u00BF,@,&,\\%,+,;,/,(,)", - /* 49~ */ + /* 49 */ "!fixedColumnOrder!9,\u00A1,\",\',#,-,:,!,\\,,?,\u00BF,@,&,\\%,+,;,/,(,)", + /* 50~ */ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~98 */ + /* ~99 */ // U+00A1: "¡" INVERTED EXCLAMATION MARK - /* 99 */ "!,\u00A1", - /* 100 */ null, + /* 100 */ "!,\u00A1", + /* 101 */ null, // U+00BF: "¿" INVERTED QUESTION MARK - /* 101 */ "?,\u00BF", + /* 102 */ "?,\u00BF", }; /* Language et: Estonian */ @@ -977,33 +1036,33 @@ public final class KeyboardTextsSet { /* 0~ */ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, - /* ~41 */ + null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~42 */ // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK // <string name="more_keys_for_double_quote">“,”,„,‟,«|»,»|«</string> - /* 42 */ "!fixedColumnOrder!4,\u201C,\u201D,\",\'", + /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\",\'", // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«|»,»|«;,‘,’,‚,‛</string> - /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B", - /* 44~ */ + /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B", + /* 45~ */ null, null, null, null, - /* ~47 */ + /* ~48 */ // U+061F: "؟" ARABIC QUESTION MARK // U+060C: "،" ARABIC COMMA // U+061B: "؛" ARABIC SEMICOLON - /* 48 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(,)", + /* 49 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(,)", // U+2605: "★" BLACK STAR // U+066D: "٭" ARABIC FIVE POINTED STAR - /* 49 */ "\u2605,\u066D", + /* 50 */ "\u2605,\u066D", // U+266A: "♪" EIGHTH NOTE - /* 50 */ "\u266A", - /* 51 */ null, + /* 51 */ "\u266A", + /* 52 */ null, // The all letters need to be mirrored are found at // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt // U+FD3E: "﴾" ORNATE LEFT PARENTHESIS // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS - /* 52 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]", - /* 53 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[", + /* 53 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]", + /* 54 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[", // U+2264: "≤" LESS-THAN OR EQUAL TO // U+2265: "≥" GREATER-THAN EQUAL TO // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK @@ -1019,8 +1078,8 @@ public final class KeyboardTextsSet { // U+201D: "”" RIGHT DOUBLE QUOTATION MARK // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK - /* 54 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,<|>", - /* 55 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,>|<", + /* 55 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,<|>", + /* 56 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,>|<", // U+0655: "ٕ" ARABIC HAMZA BELOW // U+0652: "ْ" ARABIC SUKUN // U+0651: "ّ" ARABIC SHADDA @@ -1036,68 +1095,68 @@ public final class KeyboardTextsSet { // U+064E: "َ" ARABIC FATHA // U+0640: "ـ" ARABIC TATWEEL // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. - /* 56 */ "!fixedColumnOrder!7,\u0655,\u0652,\u0651,\u064C,\u064D,\u064B,\u0654,\u0656,\u0670,\u0653,\u064F,\u0650,\u064E,\u0640\u0640\u0640|\u0640", - /* 57 */ "\u064B", + /* 57 */ "!fixedColumnOrder!7,\u0655,\u0652,\u0651,\u064C,\u064D,\u064B,\u0654,\u0656,\u0670,\u0653,\u064F,\u0650,\u064E,\u0640\u0640\u0640|\u0640", + /* 58 */ "\u064B", // U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE - /* 58 */ "\u06F1", + /* 59 */ "\u06F1", // U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO - /* 59 */ "\u06F2", + /* 60 */ "\u06F2", // U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE - /* 60 */ "\u06F3", + /* 61 */ "\u06F3", // U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR - /* 61 */ "\u06F4", + /* 62 */ "\u06F4", // U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE - /* 62 */ "\u06F5", + /* 63 */ "\u06F5", // U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX - /* 63 */ "\u06F6", + /* 64 */ "\u06F6", // U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN - /* 64 */ "\u06F7", + /* 65 */ "\u06F7", // U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT - /* 65 */ "\u06F8", + /* 66 */ "\u06F8", // U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE - /* 66 */ "\u06F9", + /* 67 */ "\u06F9", // U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO - /* 67 */ "\u06F0", - /* 68 */ "1", - /* 69 */ "2", - /* 70 */ "3", - /* 71 */ "4", - /* 72 */ "5", - /* 73 */ "6", - /* 74 */ "7", - /* 75 */ "8", - /* 76 */ "9", + /* 68 */ "\u06F0", + /* 69 */ "1", + /* 70 */ "2", + /* 71 */ "3", + /* 72 */ "4", + /* 73 */ "5", + /* 74 */ "6", + /* 75 */ "7", + /* 76 */ "8", + /* 77 */ "9", // U+066B: "٫" ARABIC DECIMAL SEPARATOR // U+066C: "٬" ARABIC THOUSANDS SEPARATOR - /* 77 */ "0,\u066B,\u066C", - /* 78~ */ + /* 78 */ "0,\u066B,\u066C", + /* 79~ */ null, null, null, null, null, null, null, null, null, null, - /* ~87 */ + /* ~88 */ // U+060C: "،" ARABIC COMMA - /* 88 */ "\u060C", - /* 89 */ "\\,", - /* 90 */ "\u061F", - /* 91 */ "\u061B", + /* 89 */ "\u060C", + /* 90 */ "\\,", + /* 91 */ "\u061F", + /* 92 */ "\u061B", // U+066A: "٪" ARABIC PERCENT SIGN - /* 92 */ "\u066A", - /* 93 */ null, - /* 94 */ "?", - /* 95 */ ";", + /* 93 */ "\u066A", + /* 94 */ null, + /* 95 */ "?", + /* 96 */ ";", // U+2030: "‰" PER MILLE SIGN - /* 96 */ "\\%,\u2030", + /* 97 */ "\\%,\u2030", // U+060C: "،" ARABIC COMMA // U+061B: "؛" ARABIC SEMICOLON // U+061F: "؟" ARABIC QUESTION MARK // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - /* 97 */ "\u060C", - /* 98 */ "!", - /* 99 */ "!,\\,", - /* 100 */ "\u061F", - /* 101 */ "\u061F,?", - /* 102 */ "\u060C", - /* 103 */ "\u061F", - /* 104 */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\u00AB|\u00BB,\u00BB|\u00AB", + /* 98 */ "\u060C", + /* 99 */ "!", + /* 100 */ "!,\\,", + /* 101 */ "\u061F", + /* 102 */ "\u061F,?", + /* 103 */ "\u060C", + /* 104 */ "\u061F", + /* 105 */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\u00AB|\u00BB,\u00BB|\u00AB", }; /* Language fi: Finnish */ @@ -1206,38 +1265,38 @@ public final class KeyboardTextsSet { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~57 */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~58 */ // U+0967: "१" DEVANAGARI DIGIT ONE - /* 58 */ "\u0967", + /* 59 */ "\u0967", // U+0968: "२" DEVANAGARI DIGIT TWO - /* 59 */ "\u0968", + /* 60 */ "\u0968", // U+0969: "३" DEVANAGARI DIGIT THREE - /* 60 */ "\u0969", + /* 61 */ "\u0969", // U+096A: "४" DEVANAGARI DIGIT FOUR - /* 61 */ "\u096A", + /* 62 */ "\u096A", // U+096B: "५" DEVANAGARI DIGIT FIVE - /* 62 */ "\u096B", + /* 63 */ "\u096B", // U+096C: "६" DEVANAGARI DIGIT SIX - /* 63 */ "\u096C", + /* 64 */ "\u096C", // U+096D: "७" DEVANAGARI DIGIT SEVEN - /* 64 */ "\u096D", + /* 65 */ "\u096D", // U+096E: "८" DEVANAGARI DIGIT EIGHT - /* 65 */ "\u096E", + /* 66 */ "\u096E", // U+096F: "९" DEVANAGARI DIGIT NINE - /* 66 */ "\u096F", + /* 67 */ "\u096F", // U+0966: "०" DEVANAGARI DIGIT ZERO - /* 67 */ "\u0966", - /* 68 */ "1", - /* 69 */ "2", - /* 70 */ "3", - /* 71 */ "4", - /* 72 */ "5", - /* 73 */ "6", - /* 74 */ "7", - /* 75 */ "8", - /* 76 */ "9", - /* 77 */ "0", + /* 68 */ "\u0966", + /* 69 */ "1", + /* 70 */ "2", + /* 71 */ "3", + /* 72 */ "4", + /* 73 */ "5", + /* 74 */ "6", + /* 75 */ "7", + /* 76 */ "8", + /* 77 */ "9", + /* 78 */ "0", }; /* Language hr: Croatian */ @@ -1425,27 +1484,27 @@ public final class KeyboardTextsSet { /* 0~ */ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, - /* ~41 */ + null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~42 */ // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK // <string name="more_keys_for_double_quote">“,”,„,‟,«|»,»|«</string> - /* 42 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB", + /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB", // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«|»,»|«;,‘,’,‚,‛</string> - /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B", - /* 44~ */ + /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B", + /* 45~ */ null, null, null, null, null, - /* ~48 */ + /* ~49 */ // U+2605: "★" BLACK STAR - /* 49 */ "\u2605", - /* 50 */ null, + /* 50 */ "\u2605", + /* 51 */ null, // U+00B1: "±" PLUS-MINUS SIGN // U+FB29: "﬩" HEBREW LETTER ALTERNATIVE PLUS SIGN - /* 51 */ "\u00B1,\uFB29", + /* 52 */ "\u00B1,\uFB29", // The all letters need to be mirrored are found at // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt - /* 52 */ "!fixedColumnOrder!3,<|>,{|},[|]", - /* 53 */ "!fixedColumnOrder!3,>|<,}|{,]|[", + /* 53 */ "!fixedColumnOrder!3,<|>,{|},[|]", + /* 54 */ "!fixedColumnOrder!3,>|<,}|{,]|[", // U+2264: "≤" LESS-THAN OR EQUAL TO // U+2265: "≥" GREATER-THAN EQUAL TO // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK @@ -1461,8 +1520,8 @@ public final class KeyboardTextsSet { // U+201D: "”" RIGHT DOUBLE QUOTATION MARK // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK - /* 54 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB", - /* 55 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB", + /* 55 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB", + /* 56 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB", }; /* Language ky: Kirghiz */ @@ -1473,22 +1532,29 @@ public final class KeyboardTextsSet { /* ~24 */ // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA /* 25 */ "\u0449", + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + /* 26 */ "\u044A", // U+044B: "ы" CYRILLIC SMALL LETTER YERU - /* 26 */ "\u044B", + /* 27 */ "\u044B", + // U+044D: "э" CYRILLIC SMALL LETTER E + /* 28 */ "\u044D", // U+0438: "и" CYRILLIC SMALL LETTER I - /* 27 */ "\u0438", + /* 29 */ "\u0438", // U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U - /* 28 */ "\u04AF", - /* 29 */ null, + /* 30 */ "\u04AF", // U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER - /* 30 */ "\u04A3", - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 31 */ "\u044A", + /* 31 */ "\u04A3", /* 32 */ null, + /* 33 */ null, // U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O - /* 33 */ "\u04E9", + /* 34 */ "\u04E9", // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 34 */ "\u044A", + /* 35 */ "\u044A", + /* 36~ */ + null, null, null, null, + /* ~39 */ + // U+0451: "ё" CYRILLIC SMALL LETTER IO + /* 40 */ "\u0451", }; /* Language lt: Lithuanian */ @@ -1675,21 +1741,21 @@ public final class KeyboardTextsSet { /* 0~ */ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, - /* ~34 */ + null, null, null, null, null, null, + /* ~35 */ // U+0455: "ѕ" CYRILLIC SMALL LETTER DZE - /* 35 */ "\u0455", + /* 36 */ "\u0455", // U+045C: "ќ" CYRILLIC SMALL LETTER KJE - /* 36 */ "\u045C", + /* 37 */ "\u045C", // U+0437: "з" CYRILLIC SMALL LETTER ZE - /* 37 */ "\u0437", + /* 38 */ "\u0437", // U+0453: "ѓ" CYRILLIC SMALL LETTER GJE - /* 38 */ "\u0453", + /* 39 */ "\u0453", // U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE - /* 39 */ "\u0450", + /* 40 */ "\u0450", // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE - /* 40 */ "\u045D", - /* 41 */ null, + /* 41 */ "\u045D", + /* 42 */ null, // U+2018: "‘" LEFT SINGLE QUOTATION MARK // U+2019: "’" RIGHT SINGLE QUOTATION MARK // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK @@ -1700,10 +1766,10 @@ public final class KeyboardTextsSet { // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. // <string name="more_keys_for_double_quote">!fixedColumnOrder!6,„,“,”,‟,«,»</string> - /* 42 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB", + /* 43 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB", // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«,»,‘,’,‚,‛</string> - /* 43 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B", + /* 44 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B", }; /* Language nb: Norwegian Bokmål */ @@ -1965,20 +2031,24 @@ public final class KeyboardTextsSet { /* ~24 */ // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA /* 25 */ "\u0449", + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + /* 26 */ "\u044A", // U+044B: "ы" CYRILLIC SMALL LETTER YERU - /* 26 */ "\u044B", + /* 27 */ "\u044B", + // U+044D: "э" CYRILLIC SMALL LETTER E + /* 28 */ "\u044D", // U+0438: "и" CYRILLIC SMALL LETTER I - /* 27 */ "\u0438", - /* 28 */ null, - // U+0451: "ё" CYRILLIC SMALL LETTER IO - /* 29 */ "\u0451", - /* 30 */ null, - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 31 */ "\u044A", - /* 32 */ null, - /* 33 */ null, + /* 29 */ "\u0438", + /* 30~ */ + null, null, null, null, null, + /* ~34 */ // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 34 */ "\u044A", + /* 35 */ "\u044A", + /* 36~ */ + null, null, null, null, + /* ~39 */ + // U+0451: "ё" CYRILLIC SMALL LETTER IO + /* 40 */ "\u0451", }; /* Language sk: Slovak */ @@ -2096,21 +2166,40 @@ public final class KeyboardTextsSet { /* 0~ */ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, - /* ~34 */ + null, null, null, null, null, null, + /* ~35 */ + // TODO: Move these to sr-Latn once we can handle IETF language tag with script name specified. + // BEGIN: More keys definitions for Serbian (Latin) + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // <string name="more_keys_for_s">š,ß,ś</string> + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // <string name="more_keys_for_c">č,ç,ć</string> + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + // <string name="more_keys_for_d">ď</string> + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // <string name="more_keys_for_z">ž,ź,ż</string> + // END: More keys definitions for Serbian (Latin) + // BEGIN: More keys definitions for Serbian (Cyrillic) // U+0437: "з" CYRILLIC SMALL LETTER ZE - /* 35 */ "\u0437", + /* 36 */ "\u0437", // U+045B: "ћ" CYRILLIC SMALL LETTER TSHE - /* 36 */ "\u045B", + /* 37 */ "\u045B", // U+0455: "ѕ" CYRILLIC SMALL LETTER DZE - /* 37 */ "\u0455", + /* 38 */ "\u0455", // U+0452: "ђ" CYRILLIC SMALL LETTER DJE - /* 38 */ "\u0452", + /* 39 */ "\u0452", // U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE - /* 39 */ "\u0450", + /* 40 */ "\u0450", // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE - /* 40 */ "\u045D", - /* 41 */ null, + /* 41 */ "\u045D", + /* 42 */ null, + // END: More keys definitions for Serbian (Cyrillic) // U+2018: "‘" LEFT SINGLE QUOTATION MARK // U+2019: "’" RIGHT SINGLE QUOTATION MARK // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK @@ -2121,10 +2210,10 @@ public final class KeyboardTextsSet { // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. // <string name="more_keys_for_double_quote">!fixedColumnOrder!6,„,“,”,‟,«,»</string> - /* 42 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB", + /* 43 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB", // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«,»,‘,’,‚,‛</string> - /* 43 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B", + /* 44 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B", }; /* Language sv: Swedish */ @@ -2169,6 +2258,111 @@ public final class KeyboardTextsSet { /* 24 */ "\u00E6", }; + /* Language sw: Swahili */ + private static final String[] LANGUAGE_sw = { + // This is the same as English except more_keys_for_g. + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* 0 */ "\u00E0,\u00E1,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101", + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* 1 */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0113", + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + /* 2 */ "\u00EE,\u00EF,\u00ED,\u012B,\u00EC", + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + /* 3 */ "\u00F4,\u00F6,\u00F2,\u00F3,\u0153,\u00F8,\u014D,\u00F5", + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* 4 */ "\u00FB,\u00FC,\u00F9,\u00FA,\u016B", + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + /* 5 */ "\u00DF", + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + /* 6 */ "\u00F1", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + /* 7 */ "\u00E7", + /* 8~ */ + null, null, null, null, null, null, null, + /* ~14 */ + /* 15 */ "g\'", + }; + + /* Language tl: Tagalog */ + private static final String[] LANGUAGE_tl = { + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + /* 0 */ "\u00E1,\u00E0,\u00E4,\u00E2,\u00E3,\u00E5,\u0105,\u00E6,\u0101,\u00AA", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* 1 */ "\u00E9,\u00E8,\u00EB,\u00EA,\u0119,\u0117,\u0113", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* 2 */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + /* 3 */ "\u00F3,\u00F2,\u00F6,\u00F4,\u00F5,\u00F8,\u0153,\u014D,\u00BA", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* 4 */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B", + /* 5 */ null, + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* 6 */ "\u00F1,\u0144", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + /* 7 */ "\u00E7,\u0107,\u010D", + }; + /* Language tr: Turkish */ private static final String[] LANGUAGE_tr = { // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX @@ -2222,20 +2416,23 @@ public final class KeyboardTextsSet { /* ~24 */ // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA /* 25 */ "\u0449", + // U+0457: "ї" CYRILLIC SMALL LETTER YI + /* 26 */ "\u0457", // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I - /* 26 */ "\u0456", + /* 27 */ "\u0456", + // U+0454: "є" CYRILLIC SMALL LETTER UKRAINIAN IE + /* 28 */ "\u0454", // U+0438: "и" CYRILLIC SMALL LETTER I - /* 27 */ "\u0438", - /* 28~ */ - null, null, null, - /* ~30 */ - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 31 */ "\u044A", + /* 29 */ "\u0438", + /* 30 */ null, + /* 31 */ null, + // U+0491: "ґ" CYRILLIC SMALL LETTER GHE WITH UPTURN + /* 32 */ "\u0491", // U+0457: "ї" CYRILLIC SMALL LETTER YI - /* 32 */ "\u0457", - /* 33 */ null, + /* 33 */ "\u0457", + /* 34 */ null, // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 34 */ "\u044A", + /* 35 */ "\u044A", }; /* Language vi: Vietnamese */ @@ -2319,6 +2516,53 @@ public final class KeyboardTextsSet { /* 9 */ "\u0111", }; + /* Language zu: Zulu */ + private static final String[] LANGUAGE_zu = { + // This is the same as English + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* 0 */ "\u00E0,\u00E1,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101", + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* 1 */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0113", + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + /* 2 */ "\u00EE,\u00EF,\u00ED,\u012B,\u00EC", + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + /* 3 */ "\u00F4,\u00F6,\u00F2,\u00F3,\u0153,\u00F8,\u014D,\u00F5", + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* 4 */ "\u00FB,\u00FC,\u00F9,\u00FA,\u016B", + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + /* 5 */ "\u00DF", + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + /* 6 */ "\u00F1", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + /* 7 */ "\u00E7", + }; + /* Language zz: No language */ private static final String[] LANGUAGE_zz = { // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE @@ -2444,6 +2688,7 @@ public final class KeyboardTextsSet { private static final Object[] LANGUAGES_AND_TEXTS = { "DEFAULT", LANGUAGE_DEFAULT, /* default */ + "af", LANGUAGE_af, /* Afrikaans */ "ar", LANGUAGE_ar, /* Arabic */ "be", LANGUAGE_be, /* Belarusian */ "ca", LANGUAGE_ca, /* Catalan */ @@ -2477,9 +2722,12 @@ public final class KeyboardTextsSet { "sl", LANGUAGE_sl, /* Slovenian */ "sr", LANGUAGE_sr, /* Serbian */ "sv", LANGUAGE_sv, /* Swedish */ + "sw", LANGUAGE_sw, /* Swahili */ + "tl", LANGUAGE_tl, /* Tagalog */ "tr", LANGUAGE_tr, /* Turkish */ "uk", LANGUAGE_uk, /* Ukrainian */ "vi", LANGUAGE_vi, /* Vietnamese */ + "zu", LANGUAGE_zu, /* Zulu */ "zz", LANGUAGE_zz, /* No language */ }; diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java new file mode 100644 index 000000000..c38febf49 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.keyboard.internal; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Paint.Align; +import android.text.TextUtils; +import android.util.SparseArray; +import android.widget.RelativeLayout; + +import com.android.inputmethod.keyboard.PointerTracker; +import com.android.inputmethod.latin.R; + +public class PreviewPlacerView extends RelativeLayout { + private final Paint mGesturePaint; + private final Paint mTextPaint; + private final int mGestureFloatingPreviewTextColor; + private final int mGestureFloatingPreviewTextOffset; + private final int mGestureFloatingPreviewTextShadowColor; + private final int mGestureFloatingPreviewTextShadowBorder; + private final int mGestureFloatingPreviewTextShadingColor; + private final int mGestureFloatingPreviewTextShadingBorder; + private final int mGestureFloatingPreviewTextConnectorColor; + private final int mGestureFloatingPreviewTextConnectorWidth; + + private int mXOrigin; + private int mYOrigin; + + private final SparseArray<PointerTracker> mPointers = new SparseArray<PointerTracker>(); + + private String mGestureFloatingPreviewText; + private boolean mDrawsGesturePreviewTrail; + private boolean mDrawsGestureFloatingPreviewText; + + public PreviewPlacerView(Context context, TypedArray keyboardViewAttr) { + super(context); + setWillNotDraw(false); + + final int gestureFloatingPreviewTextSize = keyboardViewAttr.getDimensionPixelSize( + R.styleable.KeyboardView_gestureFloatingPreviewTextSize, 0); + mGestureFloatingPreviewTextColor = keyboardViewAttr.getColor( + R.styleable.KeyboardView_gestureFloatingPreviewTextColor, 0); + mGestureFloatingPreviewTextOffset = keyboardViewAttr.getDimensionPixelOffset( + R.styleable.KeyboardView_gestureFloatingPreviewTextOffset, 0); + mGestureFloatingPreviewTextShadowColor = keyboardViewAttr.getColor( + R.styleable.KeyboardView_gestureFloatingPreviewTextShadowColor, 0); + mGestureFloatingPreviewTextShadowBorder = keyboardViewAttr.getDimensionPixelSize( + R.styleable.KeyboardView_gestureFloatingPreviewTextShadowBorder, 0); + mGestureFloatingPreviewTextShadingColor = keyboardViewAttr.getColor( + R.styleable.KeyboardView_gestureFloatingPreviewTextShadingColor, 0); + mGestureFloatingPreviewTextShadingBorder = keyboardViewAttr.getDimensionPixelSize( + R.styleable.KeyboardView_gestureFloatingPreviewTextShadingBorder, 0); + mGestureFloatingPreviewTextConnectorColor = keyboardViewAttr.getColor( + R.styleable.KeyboardView_gestureFloatingPreviewTextConnectorColor, 0); + mGestureFloatingPreviewTextConnectorWidth = keyboardViewAttr.getDimensionPixelSize( + R.styleable.KeyboardView_gestureFloatingPreviewTextConnectorWidth, 0); + final int gesturePreviewTrailColor = keyboardViewAttr.getColor( + R.styleable.KeyboardView_gesturePreviewTrailColor, 0); + final int gesturePreviewTrailWidth = keyboardViewAttr.getDimensionPixelSize( + R.styleable.KeyboardView_gesturePreviewTrailWidth, 0); + + mGesturePaint = new Paint(); + mGesturePaint.setAntiAlias(true); + mGesturePaint.setStyle(Paint.Style.STROKE); + mGesturePaint.setStrokeJoin(Paint.Join.ROUND); + mGesturePaint.setColor(gesturePreviewTrailColor); + mGesturePaint.setStrokeWidth(gesturePreviewTrailWidth); + + mTextPaint = new Paint(); + mTextPaint.setAntiAlias(true); + mTextPaint.setStrokeJoin(Paint.Join.ROUND); + mTextPaint.setTextAlign(Align.CENTER); + mTextPaint.setTextSize(gestureFloatingPreviewTextSize); + } + + public void setOrigin(int x, int y) { + mXOrigin = x; + mYOrigin = y; + } + + public void setGesturePreviewMode(boolean drawsGesturePreviewTrail, + boolean drawsGestureFloatingPreviewText) { + mDrawsGesturePreviewTrail = drawsGesturePreviewTrail; + mDrawsGestureFloatingPreviewText = drawsGestureFloatingPreviewText; + } + + public void invalidatePointer(PointerTracker tracker) { + synchronized (mPointers) { + mPointers.put(tracker.mPointerId, tracker); + // TODO: Should narrow the invalidate region. + invalidate(); + } + } + + @Override + public void onDraw(Canvas canvas) { + super.onDraw(canvas); + synchronized (mPointers) { + canvas.translate(mXOrigin, mYOrigin); + final int trackerCount = mPointers.size(); + boolean hasDrawnFloatingPreviewText = false; + for (int index = 0; index < trackerCount; index++) { + final PointerTracker tracker = mPointers.valueAt(index); + if (mDrawsGesturePreviewTrail) { + tracker.drawGestureTrail(canvas, mGesturePaint); + } + // TODO: Figure out more cleaner way to draw gesture preview text. + if (mDrawsGestureFloatingPreviewText && !hasDrawnFloatingPreviewText) { + drawGestureFloatingPreviewText(canvas, tracker, mGestureFloatingPreviewText); + hasDrawnFloatingPreviewText = true; + } + } + canvas.translate(-mXOrigin, -mYOrigin); + } + } + + public void setGestureFloatingPreviewText(String gestureFloatingPreviewText) { + mGestureFloatingPreviewText = gestureFloatingPreviewText; + invalidate(); + } + + private void drawGestureFloatingPreviewText(Canvas canvas, PointerTracker tracker, + String gestureFloatingPreviewText) { + if (TextUtils.isEmpty(gestureFloatingPreviewText)) { + return; + } + + final Paint paint = mTextPaint; + final int lastX = tracker.getLastX(); + final int lastY = tracker.getLastY(); + final int textSize = (int)paint.getTextSize(); + final int canvasWidth = canvas.getWidth(); + + final int halfTextWidth = (int)paint.measureText(gestureFloatingPreviewText) / 2 + textSize; + final int textX = Math.min(Math.max(lastX, halfTextWidth), canvasWidth - halfTextWidth); + + int textY = Math.max(-textSize, lastY - mGestureFloatingPreviewTextOffset); + if (textY < 0) { + // Paint black text shadow if preview extends above keyboard region. + paint.setStyle(Paint.Style.FILL_AND_STROKE); + paint.setColor(mGestureFloatingPreviewTextShadowColor); + paint.setStrokeWidth(mGestureFloatingPreviewTextShadowBorder); + canvas.drawText(gestureFloatingPreviewText, textX, textY, paint); + } + + // Paint the vertical line connecting the touch point to the preview text. + paint.setStyle(Paint.Style.STROKE); + paint.setColor(mGestureFloatingPreviewTextConnectorColor); + paint.setStrokeWidth(mGestureFloatingPreviewTextConnectorWidth); + final int lineTopY = textY - textSize / 4; + canvas.drawLine(lastX, lastY, lastX, lineTopY, paint); + if (lastX != textX) { + // Paint the horizontal line connection the touch point to the preview text. + canvas.drawLine(lastX, lineTopY, textX, lineTopY, paint); + } + + // Paint the shading for the text preview + paint.setStyle(Paint.Style.FILL_AND_STROKE); + paint.setColor(mGestureFloatingPreviewTextShadingColor); + paint.setStrokeWidth(mGestureFloatingPreviewTextShadingBorder); + canvas.drawText(gestureFloatingPreviewText, textX, textY, paint); + + // Paint the text preview + paint.setColor(mGestureFloatingPreviewTextColor); + paint.setStyle(Paint.Style.FILL); + canvas.drawText(gestureFloatingPreviewText, textX, textY, paint); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/SuddenJumpingTouchEventHandler.java b/java/src/com/android/inputmethod/keyboard/internal/SuddenJumpingTouchEventHandler.java index 2398c0850..9e2cbec52 100644 --- a/java/src/com/android/inputmethod/keyboard/SuddenJumpingTouchEventHandler.java +++ b/java/src/com/android/inputmethod/keyboard/internal/SuddenJumpingTouchEventHandler.java @@ -14,12 +14,14 @@ * the License. */ -package com.android.inputmethod.keyboard; +package com.android.inputmethod.keyboard.internal; import android.content.Context; import android.util.Log; import android.view.MotionEvent; +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.MainKeyboardView; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.Utils; diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 5d7995dc2..d101aaf15 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -654,9 +654,12 @@ public class ExpandableDictionary extends Dictionary { --index; mLookedUpString[index] = node.mCode; node = node.mParent; - } while (node != null); + } while (node != null && index > 0); - if (freq >= 0) { + // If node is null, we have a word longer than MAX_WORD_LENGTH in the dictionary. + // It's a little unclear how this can happen, but just in case it does it's safer + // to ignore the word in this case. + if (freq >= 0 && node == null) { suggestions.add(new SuggestedWordInfo(new String(mLookedUpString, index, BinaryDictionary.MAX_WORD_LENGTH - index), freq, SuggestedWordInfo.KIND_CORRECTION, mDictType)); diff --git a/java/src/com/android/inputmethod/latin/JniUtils.java b/java/src/com/android/inputmethod/latin/JniUtils.java index 4808b867a..86a3826d8 100644 --- a/java/src/com/android/inputmethod/latin/JniUtils.java +++ b/java/src/com/android/inputmethod/latin/JniUtils.java @@ -31,11 +31,7 @@ public class JniUtils { try { System.loadLibrary(JniLibName.JNI_LIB_NAME); } catch (UnsatisfiedLinkError ule) { - Log.e(TAG, "Could not load native library " + JniLibName.JNI_LIB_NAME); - if (LatinImeLogger.sDBG) { - throw new RuntimeException( - "Could not load native library " + JniLibName.JNI_LIB_NAME); - } + Log.e(TAG, "Could not load native library " + JniLibName.JNI_LIB_NAME, ule); } } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index d4b59c4cd..a7446695e 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -60,6 +60,7 @@ import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.compat.CompatUtils; import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; +import com.android.inputmethod.compat.InputMethodServiceCompatUtils; import com.android.inputmethod.compat.SuggestionSpanUtils; import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; @@ -82,7 +83,8 @@ import java.util.Locale; * Input method implementation for Qwerty'ish keyboard. */ public class LatinIME extends InputMethodService implements KeyboardActionListener, - SuggestionStripView.Listener, TargetApplicationGetter.OnTargetApplicationKnownListener { + SuggestionStripView.Listener, TargetApplicationGetter.OnTargetApplicationKnownListener, + Suggest.SuggestInitializationListener { private static final String TAG = LatinIME.class.getSimpleName(); private static final boolean TRACE = false; private static boolean DEBUG; @@ -174,6 +176,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private AlertDialog mOptionsDialog; + private final boolean mIsHardwareAcceleratedDrawingEnabled; + public final UIHandler mHandler = new UIHandler(this); public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> { @@ -346,6 +350,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen super(); mSubtypeSwitcher = SubtypeSwitcher.getInstance(); mKeyboardSwitcher = KeyboardSwitcher.getInstance(); + mIsHardwareAcceleratedDrawingEnabled = + InputMethodServiceCompatUtils.enableHardwareAcceleration(this); + Log.i(TAG, "Hardware accelerated drawing: " + mIsHardwareAcceleratedDrawingEnabled); } @Override @@ -426,6 +433,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary()); } + @Override + public void onUpdateMainDictionaryAvailability(boolean isMainDictionaryAvailable) { + mIsMainDictionaryAvailable = isMainDictionaryAvailable; + updateKeyboardViewGestureHandlingModeByMainDictionaryAvailability(); + } + private void initSuggest() { final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); final String localeStr = subtypeLocale.toString(); @@ -437,7 +450,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } else { oldContactsDictionary = null; } - mSuggest = new Suggest(this, subtypeLocale); + mSuggest = new Suggest(this /* Context */, subtypeLocale, + this /* SuggestInitializationListener */); if (mCurrentSettings.mCorrectionEnabled) { mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold); } @@ -531,15 +545,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen commitTyped(LastComposedWord.NOT_A_SEPARATOR); mConnection.finishComposingText(); mConnection.endBatchEdit(); - if (isShowingOptionDialog()) + if (isShowingOptionDialog()) { mOptionsDialog.dismiss(); + } } super.onConfigurationChanged(conf); } @Override public View onCreateInputView() { - return mKeyboardSwitcher.onCreateInputView(); + return mKeyboardSwitcher.onCreateInputView(mIsHardwareAcceleratedDrawingEnabled); } @Override @@ -651,40 +666,61 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen accessUtils.onStartInputViewInternal(editorInfo, restarting); } - mSubtypeSwitcher.updateParametersOnStartInputView(); + if (!restarting) { + mSubtypeSwitcher.updateParametersOnStartInputView(); + } // The EditorInfo might have a flag that affects fullscreen mode. // Note: This call should be done by InputMethodService? updateFullscreenMode(); - mLastSelectionStart = editorInfo.initialSelStart; - mLastSelectionEnd = editorInfo.initialSelEnd; mApplicationSpecifiedCompletions = null; - inputView.closing(); - mEnteredText = null; - resetComposingState(true /* alsoResetLastComposedWord */); - mDeleteCount = 0; - mSpaceState = SPACE_STATE_NONE; - - loadSettings(); + final boolean selectionChanged = mLastSelectionStart != editorInfo.initialSelStart + || mLastSelectionEnd != editorInfo.initialSelEnd; + if (!restarting || selectionChanged) { + // If the selection changed, we reset the input state. Essentially, we come here with + // restarting == true when the app called setText() or similar. We should reset the + // state if the app set the text to something else, but keep it if it set a suggestion + // or something. + mEnteredText = null; + resetComposingState(true /* alsoResetLastComposedWord */); + mDeleteCount = 0; + mSpaceState = SPACE_STATE_NONE; - if (mSuggest != null && mCurrentSettings.mCorrectionEnabled) { - mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold); + if (mSuggestionStripView != null) { + mSuggestionStripView.clear(); + } } - switcher.loadKeyboard(editorInfo, mCurrentSettings); + if (!restarting) { + inputView.closing(); + loadSettings(); + + if (mSuggest != null && mCurrentSettings.mCorrectionEnabled) { + mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold); + } - if (mSuggestionStripView != null) - mSuggestionStripView.clear(); + switcher.loadKeyboard(editorInfo, mCurrentSettings); + updateKeyboardViewGestureHandlingModeByMainDictionaryAvailability(); + } setSuggestionStripShownInternal( isSuggestionsStripVisible(), /* needsInputViewShown */ false); + mLastSelectionStart = editorInfo.initialSelStart; + mLastSelectionEnd = editorInfo.initialSelEnd; + // If we come here something in the text state is very likely to have changed. + // We should update the shift state regardless of whether we are restarting or not, because + // this is not perceived as a layout change that may be disruptive like we may have with + // switcher.loadKeyboard; in apps like Talk, we come here when the text is sent and the + // field gets emptied and we need to re-evaluate the shift state, but not the whole layout + // which would be disruptive. + mKeyboardSwitcher.updateShiftState(); + mHandler.cancelUpdateSuggestionStrip(); mHandler.cancelDoubleSpacesTimer(); inputView.setKeyPreviewPopupEnabled(mCurrentSettings.mKeyPreviewPopupOn, mCurrentSettings.mKeyPreviewPopupDismissDelay); - inputView.setProximityCorrectionEnabled(true); if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); } @@ -856,13 +892,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } } - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions); - } if (!mCurrentSettings.isApplicationSpecifiedCompletionsOn()) return; mApplicationSpecifiedCompletions = applicationSpecifiedCompletions; if (applicationSpecifiedCompletions == null) { clearSuggestionStrip(); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.latinIME_onDisplayCompletions(null); + } return; } @@ -884,6 +920,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // this case? This says to keep whatever the user typed. mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); setSuggestionStripShown(true); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions); + } } private void setSuggestionStripShownInternal(boolean shown, boolean needsInputViewShown) { @@ -1003,15 +1042,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final CharSequence typedWord = mWordComposer.getTypedWord(); if (typedWord.length() > 0) { mConnection.commitText(typedWord, 1); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_commitText(typedWord); - } final CharSequence prevWord = addToUserHistoryDictionary(typedWord); mLastComposedWord = mWordComposer.commitWord( LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, typedWord.toString(), separatorCode, prevWord); } - updateSuggestionStrip(); } // Called from the KeyboardSwitcher which needs to know auto caps state to display @@ -1048,12 +1083,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (lastTwo != null && lastTwo.length() == 2 && lastTwo.charAt(0) == Keyboard.CODE_SPACE) { mConnection.deleteSurroundingText(2, 0); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_deleteSurroundingText(2); - } mConnection.commitText(lastTwo.charAt(1) + " ", 1); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_swapSwapperAndSpaceWhileInBatchEdit(); + ResearchLogger.latinIME_swapSwapperAndSpace(); } mKeyboardSwitcher.updateShiftState(); } @@ -1070,9 +1102,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mHandler.cancelDoubleSpacesTimer(); mConnection.deleteSurroundingText(2, 0); mConnection.commitText(". ", 1); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_doubleSpaceAutoPeriod(); - } mKeyboardSwitcher.updateShiftState(); return true; } @@ -1136,9 +1165,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private void performEditorAction(int actionId) { mConnection.performEditorAction(actionId); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_performEditorAction(actionId); - } } private void handleLanguageSwitchKey() { @@ -1175,6 +1201,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}. if (code >= '0' && code <= '9') { super.sendKeyChar((char)code); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.latinIME_sendKeyCodePoint(code); + } return; } @@ -1191,9 +1220,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final String text = new String(new int[] { code }, 0, 1); mConnection.commitText(text, text.length()); } - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_sendKeyCodePoint(code); - } } // Implementation of {@link KeyboardActionListener}. @@ -1205,11 +1231,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } mLastKeyTime = when; mConnection.beginBatchEdit(); - - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_onCodeInput(primaryCode, x, y); - } - final KeyboardSwitcher switcher = mKeyboardSwitcher; // The space state depends only on the last character pressed and its own previous // state. Here, we revert the space state to neutral if the key is actually modifying @@ -1291,21 +1312,22 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mLastComposedWord.deactivate(); mEnteredText = null; mConnection.endBatchEdit(); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.latinIME_onCodeInput(primaryCode, x, y); + } } // Called from PointerTracker through the KeyboardActionListener interface @Override - public void onTextInput(CharSequence text) { + public void onTextInput(CharSequence rawText) { mConnection.beginBatchEdit(); commitTyped(LastComposedWord.NOT_A_SEPARATOR); - text = specificTldProcessingOnTextInput(text); + mHandler.postUpdateSuggestionStrip(); + final CharSequence text = specificTldProcessingOnTextInput(rawText); if (SPACE_STATE_PHANTOM == mSpaceState) { sendKeyCodePoint(Keyboard.CODE_SPACE); } mConnection.commitText(text, 1); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_commitText(text); - } mConnection.endBatchEdit(); mKeyboardSwitcher.updateShiftState(); mKeyboardSwitcher.onCodeInput(Keyboard.CODE_OUTPUT_TEXT); @@ -1334,6 +1356,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mWordComposer.setBatchInputPointers(batchPointers); final SuggestedWords suggestedWords = getSuggestedWords(); showSuggestionStrip(suggestedWords, null); + final String gestureFloatingPreviewText = (suggestedWords.size() > 0) + ? suggestedWords.getWord(0) : null; + mKeyboardSwitcher.getKeyboardView() + .showGestureFloatingPreviewText(gestureFloatingPreviewText); } @Override @@ -1341,6 +1367,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mWordComposer.setBatchInputPointers(batchPointers); final SuggestedWords suggestedWords = getSuggestedWords(); showSuggestionStrip(suggestedWords, null); + mKeyboardSwitcher.getKeyboardView().showGestureFloatingPreviewText(null); if (suggestedWords == null || suggestedWords.size() == 0) { return; } @@ -1395,9 +1422,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // like the smiley key or the .com key. final int length = mEnteredText.length(); mConnection.deleteSurroundingText(length, 0); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_deleteSurroundingText(length); - } // If we have mEnteredText, then we know that mHasUncommittedTypedChars == false. // In addition we know that spaceState is false, and that we should not be // reverting any autocorrect at this point. So we can safely return. @@ -1417,9 +1441,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mHandler.postUpdateSuggestionStrip(); } else { mConnection.deleteSurroundingText(1, 0); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_deleteSurroundingText(1); - } } } else { if (mLastComposedWord.canRevertCommit()) { @@ -1448,9 +1469,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart; mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd); mConnection.deleteSurroundingText(lengthToDelete, 0); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_deleteSurroundingText(lengthToDelete); - } } else { // There is no selection, just delete one character. if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) { @@ -1469,14 +1487,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } else { mConnection.deleteSurroundingText(1, 0); } - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_deleteSurroundingText(1); - } if (mDeleteCount > DELETE_ACCELERATE_AT) { mConnection.deleteSurroundingText(1, 0); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_deleteSurroundingText(1); - } } } if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) { @@ -1579,11 +1591,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen boolean didAutoCorrect = false; // Handle separator if (mWordComposer.isComposingWord()) { - // In certain languages where single quote is a separator, it's better - // not to auto correct, but accept the typed word. For instance, - // in Italian dov' should not be expanded to dove' because the elision - // requires the last vowel to be removed. - if (mCurrentSettings.mCorrectionEnabled && primaryCode != Keyboard.CODE_SINGLE_QUOTE) { + if (mCurrentSettings.mCorrectionEnabled) { commitCurrentAutoCorrection(primaryCode); didAutoCorrect = true; } else { @@ -1617,13 +1625,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (swapWeakSpace) { swapSwapperAndSpace(); mSpaceState = SPACE_STATE_SWAP_PUNCTUATION; - } else if (SPACE_STATE_PHANTOM == spaceState) { + } else if (SPACE_STATE_PHANTOM == spaceState + && !mCurrentSettings.isWeakSpaceStripper(primaryCode)) { // If we are in phantom space state, and the user presses a separator, we want to // stay in phantom space state so that the next keypress has a chance to add the // space. For example, if I type "Good dat", pick "day" from the suggestion strip // then insert a comma and go on to typing the next word, I want the space to be // inserted automatically before the next word, the same way it is when I don't // input the comma. + // The case is a little different if the separator is a space stripper. Such a + // separator does not normally need a space on the right (that's the difference + // between swappers and strippers), so we should not stay in phantom space state if + // the separator is a stripper. Hence the additional test above. mSpaceState = SPACE_STATE_PHANTOM; } @@ -1647,8 +1660,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen commitTyped(LastComposedWord.NOT_A_SEPARATOR); requestHideSelf(0); MainKeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); - if (inputView != null) + if (inputView != null) { inputView.closing(); + } } // TODO: make this private @@ -1799,10 +1813,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen + "is empty? Impossible! I must commit suicide."); } Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_commitCurrentAutoCorrection(typedWord, - autoCorrection.toString()); - } mExpectingUpdateSelection = true; commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, separatorCodePoint); @@ -1828,13 +1838,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // So, LatinImeLogger logs "" as a user's input. LatinImeLogger.logOnManualSuggestion("", suggestion.toString(), index, suggestedWords); // Rely on onCodeInput to do the complicated swapping/stripping logic consistently. - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_punctuationSuggestion(index, suggestion, x, y); - } final int primaryCode = suggestion.charAt(0); onCodeInput(primaryCode, KeyboardActionListener.SUGGESTION_STRIP_COORDINATE, KeyboardActionListener.SUGGESTION_STRIP_COORDINATE); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.latinIME_punctuationSuggestion(index, suggestion, x, y); + } return; } @@ -1861,10 +1871,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index]; mConnection.commitCompletion(completionInfo); mConnection.endBatchEdit(); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_pickApplicationSpecifiedCompletion(index, - completionInfo.getText(), x, y); - } return; } @@ -1873,12 +1879,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final String replacedWord = mWordComposer.getTypedWord().toString(); LatinImeLogger.logOnManualSuggestion(replacedWord, suggestion.toString(), index, suggestedWords); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion, x, y); - } mExpectingUpdateSelection = true; commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, LastComposedWord.NOT_A_SEPARATOR); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion, x, y); + } mConnection.endBatchEdit(); // Don't allow cancellation of manual pick mLastComposedWord.deactivate(); @@ -1913,9 +1919,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final SuggestedWords suggestedWords = mSuggestionStripView.getSuggestions(); mConnection.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( this, chosenWord, suggestedWords, mIsMainDictionaryAvailable), 1); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_commitText(chosenWord); - } // Add the word to the user history dictionary final CharSequence prevWord = addToUserHistoryDictionary(chosenWord); // TODO: figure out here if this is an auto-correct or if the best word is actually @@ -1982,9 +1985,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mWordComposer.setComposingWord(word, mKeyboardSwitcher.getKeyboard()); final int length = word.length(); mConnection.deleteSurroundingText(length, 0); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_deleteSurroundingText(length); - } mConnection.setComposingText(word, 1); mHandler.postUpdateSuggestionStrip(); } @@ -2012,9 +2012,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } mConnection.deleteSurroundingText(deleteLength, 0); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_deleteSurroundingText(deleteLength); - } if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) { mUserHistoryDictionary.cancelAddingUserHistory( previousWord.toString(), committedWord.toString()); @@ -2044,18 +2041,30 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void onRefreshKeyboard() { // When the device locale is changed in SetupWizard etc., this method may get called via // onConfigurationChanged before SoftInputWindow is shown. + initSuggest(); + loadSettings(); if (mKeyboardSwitcher.getKeyboardView() != null) { // Reload keyboard because the current language has been changed. mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mCurrentSettings); + updateKeyboardViewGestureHandlingModeByMainDictionaryAvailability(); } - initSuggest(); - loadSettings(); // Since we just changed languages, we should re-evaluate suggestions with whatever word // we are currently composing. If we are not composing anything, we may want to display // predictions or punctuation signs (which is done by the updateSuggestionStrip anyway). mHandler.postUpdateSuggestionStrip(); } + private void updateKeyboardViewGestureHandlingModeByMainDictionaryAvailability() { + final MainKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); + if (keyboardView != null) { + final boolean shouldHandleGesture = mCurrentSettings.mGestureInputEnabled + && mIsMainDictionaryAvailable; + keyboardView.setGestureHandlingMode(shouldHandleGesture, + mCurrentSettings.mGesturePreviewTrailEnabled, + mCurrentSettings.mGestureFloatingPreviewTextEnabled); + } + } + // TODO: Remove this method from {@link LatinIME} and move {@link FeedbackManager} to // {@link KeyboardSwitcher}. Called from KeyboardSwitcher public void hapticAndAudioFeedback(final int primaryCode) { diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index 8b4c17322..41e59e92d 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -55,7 +55,9 @@ public class RichInputConnection { public void beginBatchEdit() { if (++mNestLevel == 1) { mIC = mParent.getCurrentInputConnection(); - if (null != mIC) mIC.beginBatchEdit(); + if (null != mIC) { + mIC.beginBatchEdit(); + } } else { if (DBG) { throw new RuntimeException("Nest level too deep"); @@ -66,7 +68,9 @@ public class RichInputConnection { } public void endBatchEdit() { if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead - if (--mNestLevel == 0 && null != mIC) mIC.endBatchEdit(); + if (--mNestLevel == 0 && null != mIC) { + mIC.endBatchEdit(); + } } private void checkBatchEdit() { @@ -79,12 +83,22 @@ public class RichInputConnection { public void finishComposingText() { checkBatchEdit(); - if (null != mIC) mIC.finishComposingText(); + if (null != mIC) { + mIC.finishComposingText(); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.richInputConnection_finishComposingText(); + } + } } public void commitText(final CharSequence text, final int i) { checkBatchEdit(); - if (null != mIC) mIC.commitText(text, i); + if (null != mIC) { + mIC.commitText(text, i); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.richInputConnection_commitText(text, i); + } + } } public int getCursorCapsMode(final int inputType) { @@ -107,37 +121,72 @@ public class RichInputConnection { public void deleteSurroundingText(final int i, final int j) { checkBatchEdit(); - if (null != mIC) mIC.deleteSurroundingText(i, j); + if (null != mIC) { + mIC.deleteSurroundingText(i, j); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.richInputConnection_deleteSurroundingText(i, j); + } + } } public void performEditorAction(final int actionId) { mIC = mParent.getCurrentInputConnection(); - if (null != mIC) mIC.performEditorAction(actionId); + if (null != mIC) { + mIC.performEditorAction(actionId); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.richInputConnection_performEditorAction(actionId); + } + } } public void sendKeyEvent(final KeyEvent keyEvent) { checkBatchEdit(); - if (null != mIC) mIC.sendKeyEvent(keyEvent); + if (null != mIC) { + mIC.sendKeyEvent(keyEvent); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.richInputConnection_sendKeyEvent(keyEvent); + } + } } public void setComposingText(final CharSequence text, final int i) { checkBatchEdit(); - if (null != mIC) mIC.setComposingText(text, i); + if (null != mIC) { + mIC.setComposingText(text, i); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.richInputConnection_setComposingText(text, i); + } + } } public void setSelection(final int from, final int to) { checkBatchEdit(); - if (null != mIC) mIC.setSelection(from, to); + if (null != mIC) { + mIC.setSelection(from, to); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.richInputConnection_setSelection(from, to); + } + } } public void commitCorrection(final CorrectionInfo correctionInfo) { checkBatchEdit(); - if (null != mIC) mIC.commitCorrection(correctionInfo); + if (null != mIC) { + mIC.commitCorrection(correctionInfo); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.richInputConnection_commitCorrection(correctionInfo); + } + } } public void commitCompletion(final CompletionInfo completionInfo) { checkBatchEdit(); - if (null != mIC) mIC.commitCompletion(completionInfo); + if (null != mIC) { + mIC.commitCompletion(completionInfo); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.richInputConnection_commitCompletion(completionInfo); + } + } } public CharSequence getNthPreviousWord(final String sentenceSeperators, final int n) { @@ -315,9 +364,6 @@ public class RichInputConnection { if (lastOne != null && lastOne.length() == 1 && lastOne.charAt(0) == Keyboard.CODE_SPACE) { deleteSurroundingText(1, 0); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_deleteSurroundingText(1); - } } } @@ -382,13 +428,7 @@ public class RichInputConnection { return false; } deleteSurroundingText(2, 0); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_deleteSurroundingText(2); - } commitText(" ", 1); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_revertDoubleSpaceWhileInBatchEdit(); - } return true; } @@ -409,13 +449,7 @@ public class RichInputConnection { return false; } deleteSurroundingText(2, 0); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_deleteSurroundingText(2); - } commitText(" " + textBeforeCursor.subSequence(0, 1), 1); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_revertSwapPunctuation(); - } return true; } } diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 45608f439..6251c9acd 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -62,6 +62,7 @@ public class Settings extends InputMethodSettingsFragment public static final String PREF_LAST_USER_DICTIONARY_WRITE_TIME = "last_user_dictionary_write_time"; public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings"; + public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict"; public static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY = "pref_suppress_language_switch_key"; public static final String PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST = @@ -69,13 +70,15 @@ public class Settings extends InputMethodSettingsFragment public static final String PREF_CUSTOM_INPUT_STYLES = "custom_input_styles"; public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY = "pref_key_preview_popup_dismiss_delay"; - public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict"; public static final String PREF_BIGRAM_PREDICTIONS = "next_word_prediction"; public static final String PREF_GESTURE_INPUT = "gesture_input"; public static final String PREF_VIBRATION_DURATION_SETTINGS = "pref_vibration_duration_settings"; public static final String PREF_KEYPRESS_SOUND_VOLUME = "pref_keypress_sound_volume"; + public static final String PREF_GESTURE_PREVIEW_TRAIL = "pref_gesture_preview_trail"; + public static final String PREF_GESTURE_FLOATING_PREVIEW_TEXT = + "pref_gesture_floating_preview_text"; public static final String PREF_INPUT_LANGUAGE = "input_language"; public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; @@ -94,13 +97,17 @@ public class Settings extends InputMethodSettingsFragment private TextView mKeypressVibrationDurationSettingsTextView; private TextView mKeypressSoundVolumeSettingsTextView; + private static void setPreferenceEnabled(Preference preference, boolean enabled) { + if (preference != null) { + preference.setEnabled(enabled); + } + } + private void ensureConsistencyOfAutoCorrectionSettings() { final String autoCorrectionOff = getResources().getString( R.string.auto_correction_threshold_mode_index_off); final String currentSetting = mAutoCorrectionThresholdPreference.getValue(); - if (null != mBigramPrediction) { - mBigramPrediction.setEnabled(!currentSetting.equals(autoCorrectionOff)); - } + setPreferenceEnabled(mBigramPrediction, !currentSetting.equals(autoCorrectionOff)); } @Override @@ -180,13 +187,11 @@ public class Settings extends InputMethodSettingsFragment if (null == mKeyPreviewPopupDismissDelay.getValue()) { mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue); } - mKeyPreviewPopupDismissDelay.setEnabled( + setPreferenceEnabled(mKeyPreviewPopupDismissDelay, SettingsValues.isKeyPreviewPopupEnabled(prefs, res)); } - final CheckBoxPreference includeOtherImesInLanguageSwitchList = - (CheckBoxPreference)findPreference(PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST); - includeOtherImesInLanguageSwitchList.setEnabled( + setPreferenceEnabled(findPreference(PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST), !SettingsValues.isLanguageSwitchKeySupressed(prefs)); final PreferenceScreen dictionaryLink = @@ -200,10 +205,19 @@ public class Settings extends InputMethodSettingsFragment final boolean gestureInputEnabledByBuildConfig = res.getBoolean( R.bool.config_gesture_input_enabled_by_build_config); + final Preference gesturePreviewTrail = findPreference(PREF_GESTURE_PREVIEW_TRAIL); + final Preference gestureFloatingPreviewText = findPreference( + PREF_GESTURE_FLOATING_PREVIEW_TEXT); if (!gestureInputEnabledByBuildConfig) { - final Preference gestureInputPref = findPreference(PREF_GESTURE_INPUT); - miscSettings.removePreference(gestureInputPref); + miscSettings.removePreference(findPreference(PREF_GESTURE_INPUT)); + miscSettings.removePreference(gesturePreviewTrail); + miscSettings.removePreference(gestureFloatingPreviewText); + } else { + final boolean gestureInputEnabledByUser = prefs.getBoolean(PREF_GESTURE_INPUT, true); + setPreferenceEnabled(gesturePreviewTrail, gestureInputEnabledByUser); + setPreferenceEnabled(gestureFloatingPreviewText, gestureInputEnabledByUser); } + final boolean showUsabilityStudyModeOption = res.getBoolean(R.bool.config_enable_usability_study_mode_option) || ProductionFlag.IS_EXPERIMENTAL || ENABLE_EXPERIMENTAL_SETTINGS; @@ -277,17 +291,22 @@ public class Settings extends InputMethodSettingsFragment public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { (new BackupManager(getActivity())).dataChanged(); if (key.equals(PREF_POPUP_ON)) { - final ListPreference popupDismissDelay = - (ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); - if (null != popupDismissDelay) { - popupDismissDelay.setEnabled(prefs.getBoolean(PREF_POPUP_ON, true)); - } + setPreferenceEnabled(findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY), + prefs.getBoolean(PREF_POPUP_ON, true)); } else if (key.equals(PREF_SUPPRESS_LANGUAGE_SWITCH_KEY)) { - final CheckBoxPreference includeOtherImesInLanguageSwicthList = - (CheckBoxPreference)findPreference( - PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST); - includeOtherImesInLanguageSwicthList.setEnabled( + setPreferenceEnabled(findPreference(PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST), !SettingsValues.isLanguageSwitchKeySupressed(prefs)); + } else if (key.equals(PREF_GESTURE_INPUT)) { + final boolean gestureInputEnabledByConfig = getResources().getBoolean( + R.bool.config_gesture_input_enabled_by_build_config); + if (gestureInputEnabledByConfig) { + final boolean gestureInputEnabledByUser = prefs.getBoolean( + PREF_GESTURE_INPUT, true); + setPreferenceEnabled(findPreference(PREF_GESTURE_PREVIEW_TRAIL), + gestureInputEnabledByUser); + setPreferenceEnabled(findPreference(PREF_GESTURE_FLOATING_PREVIEW_TEXT), + gestureInputEnabledByUser); + } } ensureConsistencyOfAutoCorrectionSettings(); updateVoiceModeSummary(); @@ -335,16 +354,18 @@ public class Settings extends InputMethodSettingsFragment private void refreshEnablingsOfKeypressSoundAndVibrationSettings( SharedPreferences sp, Resources res) { if (mKeypressVibrationDurationSettingsPref != null) { - final boolean hasVibrator = VibratorUtils.getInstance(getActivity()).hasVibrator(); - final boolean vibrateOn = hasVibrator && sp.getBoolean(Settings.PREF_VIBRATE_ON, + final boolean hasVibratorHardware = VibratorUtils.getInstance(getActivity()) + .hasVibrator(); + final boolean vibrateOnByUser = sp.getBoolean(Settings.PREF_VIBRATE_ON, res.getBoolean(R.bool.config_default_vibration_enabled)); - mKeypressVibrationDurationSettingsPref.setEnabled(vibrateOn); + setPreferenceEnabled(mKeypressVibrationDurationSettingsPref, + hasVibratorHardware && vibrateOnByUser); } if (mKeypressSoundVolumeSettingsPref != null) { final boolean soundOn = sp.getBoolean(Settings.PREF_SOUND_ON, res.getBoolean(R.bool.config_default_sound_enabled)); - mKeypressSoundVolumeSettingsPref.setEnabled(soundOn); + setPreferenceEnabled(mKeypressSoundVolumeSettingsPref, soundOn); } } diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 3ed981375..0843bdbbc 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -84,6 +84,8 @@ public class SettingsValues { private final float mKeypressSoundVolumeRawValue; private final InputMethodSubtype[] mAdditionalSubtypes; public final boolean mGestureInputEnabled; + public final boolean mGesturePreviewTrailEnabled; + public final boolean mGestureFloatingPreviewTextEnabled; // From the input box private final InputAttributes mInputAttributes; @@ -174,6 +176,9 @@ public class SettingsValues { R.bool.config_gesture_input_enabled_by_build_config); mGestureInputEnabled = gestureInputEnabledByBuildConfig && prefs.getBoolean(Settings.PREF_GESTURE_INPUT, true); + mGesturePreviewTrailEnabled = prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true); + mGestureFloatingPreviewTextEnabled = prefs.getBoolean( + Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, true); mCorrectionEnabled = mAutoCorrectEnabled && !mInputAttributes.mInputTypeNoAutoCorrect; mSuggestionVisibility = createSuggestionVisibility(res); } diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 598ef1de7..5e2a04124 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -42,6 +42,10 @@ public class Suggest { // TODO: rename this to CORRECTION_ON public static final int CORRECTION_FULL = 1; + public interface SuggestInitializationListener { + public void onUpdateMainDictionaryAvailability(boolean isMainDictionaryAvailable); + } + private static final boolean DBG = LatinImeLogger.sDBG; private Dictionary mMainDictionary; @@ -55,11 +59,14 @@ public class Suggest { private float mAutoCorrectionThreshold; // Locale used for upper- and title-casing words - final private Locale mLocale; + private final Locale mLocale; + private final SuggestInitializationListener mListener; - public Suggest(final Context context, final Locale locale) { + public Suggest(final Context context, final Locale locale, + final SuggestInitializationListener listener) { initAsynchronously(context, locale); mLocale = locale; + mListener = listener; } /* package for test */ Suggest(final Context context, final File dictionary, @@ -67,6 +74,7 @@ public class Suggest { final Dictionary mainDict = DictionaryFactory.createDictionaryForTest(context, dictionary, startOffset, length /* useFullEditDistance */, false, locale); mLocale = locale; + mListener = null; mMainDictionary = mainDict; addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_MAIN, mainDict); initWhitelistAndAutocorrectAndPool(context, locale); @@ -98,6 +106,9 @@ public class Suggest { public void resetMainDict(final Context context, final Locale locale) { mMainDictionary = null; + if (mListener != null) { + mListener.onUpdateMainDictionaryAvailability(hasMainDictionary()); + } new Thread("InitializeBinaryDictionary") { @Override public void run() { @@ -105,6 +116,9 @@ public class Suggest { DictionaryFactory.createMainDictionaryFromManager(context, locale); addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_MAIN, newMainDict); mMainDictionary = newMainDict; + if (mListener != null) { + mListener.onUpdateMainDictionaryAvailability(hasMainDictionary()); + } } }.start(); } @@ -219,7 +233,7 @@ public class Suggest { // the current settings. It may also be useful to know, when the setting is off, whether // the word *would* have been auto-corrected. if (!isCorrectionEnabled || !allowsToBeAutoCorrected || !wordComposer.isComposingWord() - || suggestionsSet.isEmpty() + || suggestionsSet.isEmpty() || wordComposer.hasDigits() || wordComposer.isMostlyCaps() || wordComposer.isResumed() || !hasMainDictionary()) { // If we don't have a main dictionary, we never want to auto-correct. The reason for diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 6d346d179..5606a58e4 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -41,6 +41,7 @@ public class WordComposer { // Cache these values for performance private int mCapsCount; + private int mDigitsCount; private boolean mAutoCapitalized; private int mTrailingSingleQuotesCount; private int mCodePointSize; @@ -65,6 +66,7 @@ public class WordComposer { mTypedWord = new StringBuilder(source.mTypedWord); mInputPointers.copy(source.mInputPointers); mCapsCount = source.mCapsCount; + mDigitsCount = source.mDigitsCount; mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount; @@ -80,6 +82,7 @@ public class WordComposer { mTypedWord.setLength(0); mAutoCorrection = null; mCapsCount = 0; + mDigitsCount = 0; mIsFirstCharCapitalized = false; mTrailingSingleQuotesCount = 0; mIsResumed = false; @@ -141,6 +144,7 @@ public class WordComposer { mIsFirstCharCapitalized = isFirstCharCapitalized( newIndex, primaryCode, mIsFirstCharCapitalized); if (Character.isUpperCase(primaryCode)) mCapsCount++; + if (Character.isDigit(primaryCode)) mDigitsCount++; if (Keyboard.CODE_SINGLE_QUOTE == primaryCode) { ++mTrailingSingleQuotesCount; } else { @@ -213,6 +217,7 @@ public class WordComposer { mTypedWord.deleteCharAt(stringBuilderLength - 1); } if (Character.isUpperCase(lastChar)) mCapsCount--; + if (Character.isDigit(lastChar)) mDigitsCount--; refreshSize(); } // We may have deleted the last one. @@ -268,6 +273,13 @@ public class WordComposer { } /** + * Returns true if we have digits in the composing word. + */ + public boolean hasDigits() { + return mDigitsCount > 0; + } + + /** * Saves the reason why the word is capitalized - whether it was automatic or * due to the user hitting shift in the middle of a sentence. * @param auto whether it was an automatic capitalization due to start of sentence @@ -322,6 +334,7 @@ public class WordComposer { lastComposedWord.deactivate(); } mCapsCount = 0; + mDigitsCount = 0; mIsBatchMode = false; mTypedWord.setLength(0); mTrailingSingleQuotesCount = 0; diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java index 8b53c9427..5864db28e 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java +++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java @@ -61,8 +61,8 @@ public class FusionDictionary implements Iterable<Word> { * This represents an "attribute", that is either a bigram or a shortcut. */ public static class WeightedString { - final String mWord; - int mFrequency; + public final String mWord; + public int mFrequency; public WeightedString(String word, int frequency) { mWord = word; mFrequency = frequency; diff --git a/java/src/com/android/inputmethod/latin/makedict/Word.java b/java/src/com/android/inputmethod/latin/makedict/Word.java index d07826757..65fc72c40 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Word.java +++ b/java/src/com/android/inputmethod/latin/makedict/Word.java @@ -27,10 +27,10 @@ import java.util.Arrays; * This is chiefly used to iterate a dictionary. */ public class Word implements Comparable<Word> { - final String mWord; - final int mFrequency; - final ArrayList<WeightedString> mShortcutTargets; - final ArrayList<WeightedString> mBigrams; + public final String mWord; + public final int mFrequency; + public final ArrayList<WeightedString> mShortcutTargets; + public final ArrayList<WeightedString> mBigrams; private int mHashCode = 0; diff --git a/java/src/com/android/inputmethod/research/FeedbackActivity.java b/java/src/com/android/inputmethod/research/FeedbackActivity.java index c9f3b476a..11eae8813 100644 --- a/java/src/com/android/inputmethod/research/FeedbackActivity.java +++ b/java/src/com/android/inputmethod/research/FeedbackActivity.java @@ -18,10 +18,7 @@ package com.android.inputmethod.research; import android.app.Activity; import android.os.Bundle; -import android.text.Editable; -import android.view.View; import android.widget.CheckBox; -import android.widget.EditText; import com.android.inputmethod.latin.R; @@ -31,6 +28,11 @@ public class FeedbackActivity extends Activity { super.onCreate(savedInstanceState); setContentView(R.layout.research_feedback_activity); final FeedbackLayout layout = (FeedbackLayout) findViewById(R.id.research_feedback_layout); + final CheckBox checkbox = (CheckBox) findViewById(R.id.research_feedback_include_history); + final CharSequence cs = checkbox.getText(); + final String actualString = String.format(cs.toString(), + ResearchLogger.FEEDBACK_WORD_BUFFER_SIZE); + checkbox.setText(actualString); layout.setActivity(this); } diff --git a/java/src/com/android/inputmethod/research/LogBuffer.java b/java/src/com/android/inputmethod/research/LogBuffer.java new file mode 100644 index 000000000..65f5f83ae --- /dev/null +++ b/java/src/com/android/inputmethod/research/LogBuffer.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.research; + +import java.util.LinkedList; + +/** + * A buffer that holds a fixed number of LogUnits. + * + * LogUnits are added in and shifted out in temporal order. Only a subset of the LogUnits are + * actual words; the other LogUnits do not count toward the word limit. Once the buffer reaches + * capacity, adding another LogUnit that is a word evicts the oldest LogUnits out one at a time to + * stay under the capacity limit. + */ +public class LogBuffer { + protected final LinkedList<LogUnit> mLogUnits; + /* package for test */ int mWordCapacity; + // The number of members of mLogUnits that are actual words. + protected int mNumActualWords; + + /** + * Create a new LogBuffer that can hold a fixed number of LogUnits that are words (and + * unlimited number of non-word LogUnits), and that outputs its result to a researchLog. + * + * @param wordCapacity maximum number of words + */ + LogBuffer(final int wordCapacity) { + if (wordCapacity <= 0) { + throw new IllegalArgumentException("wordCapacity must be 1 or greater."); + } + mLogUnits = new LinkedList<LogUnit>(); + mWordCapacity = wordCapacity; + mNumActualWords = 0; + } + + /** + * Adds a new LogUnit to the front of the LIFO queue, evicting existing LogUnit's + * (oldest first) if word capacity is reached. + */ + public void shiftIn(LogUnit newLogUnit) { + if (newLogUnit.getWord() == null) { + // This LogUnit isn't a word, so it doesn't count toward the word-limit. + mLogUnits.add(newLogUnit); + return; + } + if (mNumActualWords == mWordCapacity) { + shiftOutThroughFirstWord(); + } + mLogUnits.add(newLogUnit); + mNumActualWords++; // Must be a word, or we wouldn't be here. + } + + private void shiftOutThroughFirstWord() { + while (!mLogUnits.isEmpty()) { + final LogUnit logUnit = mLogUnits.removeFirst(); + onShiftOut(logUnit); + if (logUnit.hasWord()) { + // Successfully shifted out a word-containing LogUnit and made space for the new + // LogUnit. + mNumActualWords--; + break; + } + } + } + + /** + * Removes all LogUnits from the buffer without calling onShiftOut(). + */ + public void clear() { + mLogUnits.clear(); + mNumActualWords = 0; + } + + /** + * Called when a LogUnit is removed from the LogBuffer as a result of a shiftIn. LogUnits are + * removed in the order entered. This method is not called when shiftOut is called directly. + * + * Base class does nothing; subclasses may override. + */ + protected void onShiftOut(LogUnit logUnit) { + } + + /** + * Called to deliberately remove the oldest LogUnit. Usually called when draining the + * LogBuffer. + */ + public LogUnit shiftOut() { + if (mLogUnits.isEmpty()) { + return null; + } + final LogUnit logUnit = mLogUnits.removeFirst(); + if (logUnit.hasWord()) { + mNumActualWords--; + } + return logUnit; + } +} diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java new file mode 100644 index 000000000..8a80664f5 --- /dev/null +++ b/java/src/com/android/inputmethod/research/LogUnit.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.research; + +import java.util.ArrayList; + +/** + * A group of log statements related to each other. + * + * A LogUnit is collection of LogStatements, each of which is generated by at a particular point + * in the code. (There is no LogStatement class; the data is stored across the instance variables + * here.) A single LogUnit's statements can correspond to all the calls made while in the same + * composing region, or all the calls between committing the last composing region, and the first + * character of the next composing region. + * + * Individual statements in a log may be marked as potentially private. If so, then they are only + * published to a ResearchLog if the ResearchLogger determines that publishing the entire LogUnit + * will not violate the user's privacy. Checks for this may include whether other LogUnits have + * been published recently, or whether the LogUnit contains numbers, etc. + */ +/* package */ class LogUnit { + private final ArrayList<String[]> mKeysList = new ArrayList<String[]>(); + private final ArrayList<Object[]> mValuesList = new ArrayList<Object[]>(); + private final ArrayList<Boolean> mIsPotentiallyPrivate = new ArrayList<Boolean>(); + private String mWord; + private boolean mContainsDigit; + + public void addLogStatement(final String[] keys, final Object[] values, + final Boolean isPotentiallyPrivate) { + mKeysList.add(keys); + mValuesList.add(values); + mIsPotentiallyPrivate.add(isPotentiallyPrivate); + } + + public void publishTo(final ResearchLog researchLog, final boolean isIncludingPrivateData) { + final int size = mKeysList.size(); + for (int i = 0; i < size; i++) { + if (!mIsPotentiallyPrivate.get(i) || isIncludingPrivateData) { + researchLog.outputEvent(mKeysList.get(i), mValuesList.get(i)); + } + } + } + + public void setWord(String word) { + mWord = word; + } + + public String getWord() { + return mWord; + } + + public boolean hasWord() { + return mWord != null; + } + + public void setContainsDigit() { + mContainsDigit = true; + } + + public boolean hasDigit() { + return mContainsDigit; + } + + public boolean isEmpty() { + return mKeysList.isEmpty(); + } +} diff --git a/java/src/com/android/inputmethod/research/MainLogBuffer.java b/java/src/com/android/inputmethod/research/MainLogBuffer.java new file mode 100644 index 000000000..745768d35 --- /dev/null +++ b/java/src/com/android/inputmethod/research/MainLogBuffer.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.research; + +import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.latin.Suggest; + +import java.util.Random; + +public class MainLogBuffer extends LogBuffer { + // The size of the n-grams logged. E.g. N_GRAM_SIZE = 2 means to sample bigrams. + private static final int N_GRAM_SIZE = 2; + // The number of words between n-grams to omit from the log. + private static final int DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES = 18; + + private final ResearchLog mResearchLog; + private Suggest mSuggest; + + // The minimum periodicity with which n-grams can be sampled. E.g. mWinWordPeriod is 10 if + // every 10th bigram is sampled, i.e., words 1-8 are not, but the bigram at words 9 and 10, etc. + // for 11-18, and the bigram at words 19 and 20. If an n-gram is not safe (e.g. it contains a + // number in the middle or an out-of-vocabulary word), then sampling is delayed until a safe + // n-gram does appear. + /* package for test */ int mMinWordPeriod; + + // Counter for words left to suppress before an n-gram can be sampled. Reset to mMinWordPeriod + // after a sample is taken. + /* package for test */ int mWordsUntilSafeToSample; + + public MainLogBuffer(final ResearchLog researchLog) { + super(N_GRAM_SIZE); + mResearchLog = researchLog; + mMinWordPeriod = DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES + N_GRAM_SIZE; + final Random random = new Random(); + mWordsUntilSafeToSample = random.nextInt(mMinWordPeriod); + } + + public void setSuggest(Suggest suggest) { + mSuggest = suggest; + } + + @Override + public void shiftIn(final LogUnit newLogUnit) { + super.shiftIn(newLogUnit); + if (newLogUnit.hasWord()) { + if (mWordsUntilSafeToSample > 0) { + mWordsUntilSafeToSample--; + } + } + } + + public void resetWordCounter() { + mWordsUntilSafeToSample = mMinWordPeriod; + } + + /** + * Determines whether the content of the MainLogBuffer can be safely uploaded in its complete + * form and still protect the user's privacy. + * + * The size of the MainLogBuffer is just enough to hold one n-gram, its corrections, and any + * non-character data that is typed between words. The decision about privacy is made based on + * the buffer's entire content. If it is decided that the privacy risks are too great to upload + * the contents of this buffer, a censored version of the LogItems may still be uploaded. E.g., + * the screen orientation and other characteristics about the device can be uploaded without + * revealing much about the user. + */ + public boolean isSafeToLog() { + // Check that we are not sampling too frequently. Having sampled recently might disclose + // too much of the user's intended meaning. + if (mWordsUntilSafeToSample > 0) { + return false; + } + if (mSuggest == null || !mSuggest.hasMainDictionary()) { + // Main dictionary is unavailable. Since we cannot check it, we cannot tell if a word + // is out-of-vocabulary or not. Therefore, we must judge the entire buffer contents to + // potentially pose a privacy risk. + return false; + } + // Reload the dictionary in case it has changed (e.g., because the user has changed + // languages). + final Dictionary dictionary = mSuggest.getMainDictionary(); + if (dictionary == null) { + return false; + } + // Check each word in the buffer. If any word poses a privacy threat, we cannot upload the + // complete buffer contents in detail. + final int length = mLogUnits.size(); + for (int i = 0; i < length; i++) { + final LogUnit logUnit = mLogUnits.get(i); + final String word = logUnit.getWord(); + if (word == null) { + // Digits outside words are a privacy threat. + if (logUnit.hasDigit()) { + return false; + } + } else { + // Words not in the dictionary are a privacy threat. + if (!(dictionary.isValidWord(word))) { + return false; + } + } + } + // All checks have passed; this buffer's content can be safely uploaded. + return true; + } + + @Override + protected void onShiftOut(LogUnit logUnit) { + if (mResearchLog != null) { + mResearchLog.publish(logUnit, false /* isIncludingPrivateData */); + } + } +} diff --git a/java/src/com/android/inputmethod/research/ResearchLog.java b/java/src/com/android/inputmethod/research/ResearchLog.java index 18bf3c07f..71a6d6a78 100644 --- a/java/src/com/android/inputmethod/research/ResearchLog.java +++ b/java/src/com/android/inputmethod/research/ResearchLog.java @@ -26,7 +26,6 @@ import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.define.ProductionFlag; -import com.android.inputmethod.research.ResearchLogger.LogUnit; import java.io.BufferedWriter; import java.io.File; @@ -37,6 +36,7 @@ import java.io.OutputStreamWriter; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -51,21 +51,22 @@ import java.util.concurrent.TimeUnit; */ public class ResearchLog { private static final String TAG = ResearchLog.class.getSimpleName(); - private static final JsonWriter NULL_JSON_WRITER = new JsonWriter( - new OutputStreamWriter(new NullOutputStream())); + private static final boolean DEBUG = false; + private static final long FLUSH_DELAY_IN_MS = 1000 * 5; + private static final int ABORT_TIMEOUT_IN_MS = 1000 * 4; - final ScheduledExecutorService mExecutor; + /* package */ final ScheduledExecutorService mExecutor; /* package */ final File mFile; private JsonWriter mJsonWriter = NULL_JSON_WRITER; + // true if at least one byte of data has been written out to the log file. This must be + // remembered because JsonWriter requires that calls matching calls to beginObject and + // endObject, as well as beginArray and endArray, and the file is opened lazily, only when + // it is certain that data will be written. Alternatively, the matching call exceptions + // could be caught, but this might suppress other errors. + private boolean mHasWrittenData = false; - private int mLoggingState; - private static final int LOGGING_STATE_UNSTARTED = 0; - private static final int LOGGING_STATE_READY = 1; // don't create file until necessary - private static final int LOGGING_STATE_RUNNING = 2; - private static final int LOGGING_STATE_STOPPING = 3; - private static final int LOGGING_STATE_STOPPED = 4; - private static final long FLUSH_DELAY_IN_MS = 1000 * 5; - + private static final JsonWriter NULL_JSON_WRITER = new JsonWriter( + new OutputStreamWriter(new NullOutputStream())); private static class NullOutputStream extends OutputStream { /** {@inheritDoc} */ @Override @@ -84,128 +85,81 @@ public class ResearchLog { } } - public ResearchLog(File outputFile) { - mExecutor = Executors.newSingleThreadScheduledExecutor(); + public ResearchLog(final File outputFile) { if (outputFile == null) { throw new IllegalArgumentException(); } + mExecutor = Executors.newSingleThreadScheduledExecutor(); mFile = outputFile; - mLoggingState = LOGGING_STATE_UNSTARTED; - } - - public synchronized void start() throws IOException { - switch (mLoggingState) { - case LOGGING_STATE_UNSTARTED: - mLoggingState = LOGGING_STATE_READY; - break; - case LOGGING_STATE_READY: - case LOGGING_STATE_RUNNING: - case LOGGING_STATE_STOPPING: - case LOGGING_STATE_STOPPED: - break; - } } - public synchronized void stop() { - switch (mLoggingState) { - case LOGGING_STATE_UNSTARTED: - mLoggingState = LOGGING_STATE_STOPPED; - break; - case LOGGING_STATE_READY: - case LOGGING_STATE_RUNNING: - mExecutor.submit(new Callable<Object>() { - @Override - public Object call() throws Exception { - try { - mJsonWriter.endArray(); - mJsonWriter.flush(); - mJsonWriter.close(); - } finally { - boolean success = mFile.setWritable(false, false); - mLoggingState = LOGGING_STATE_STOPPED; - } - return null; + public synchronized void close() { + mExecutor.submit(new Callable<Object>() { + @Override + public Object call() throws Exception { + try { + if (mHasWrittenData) { + mJsonWriter.endArray(); + mJsonWriter.flush(); + mJsonWriter.close(); + mHasWrittenData = false; } - }); - removeAnyScheduledFlush(); - mExecutor.shutdown(); - mLoggingState = LOGGING_STATE_STOPPING; - break; - case LOGGING_STATE_STOPPING: - case LOGGING_STATE_STOPPED: - } + } catch (Exception e) { + Log.d(TAG, "error when closing ResearchLog:"); + e.printStackTrace(); + } finally { + if (mFile.exists()) { + mFile.setWritable(false, false); + } + } + return null; + } + }); + removeAnyScheduledFlush(); + mExecutor.shutdown(); } - public boolean isAlive() { - switch (mLoggingState) { - case LOGGING_STATE_UNSTARTED: - case LOGGING_STATE_READY: - case LOGGING_STATE_RUNNING: - return true; - } - return false; - } + private boolean mIsAbortSuccessful; - public void waitUntilStopped(final int timeoutInMs) throws InterruptedException { + public synchronized void abort() { + mExecutor.submit(new Callable<Object>() { + @Override + public Object call() throws Exception { + try { + if (mHasWrittenData) { + mJsonWriter.endArray(); + mJsonWriter.close(); + mHasWrittenData = false; + } + } finally { + mIsAbortSuccessful = mFile.delete(); + } + return null; + } + }); removeAnyScheduledFlush(); mExecutor.shutdown(); - mExecutor.awaitTermination(timeoutInMs, TimeUnit.MILLISECONDS); } - public synchronized void abort() { - switch (mLoggingState) { - case LOGGING_STATE_UNSTARTED: - mLoggingState = LOGGING_STATE_STOPPED; - isAbortSuccessful = true; - break; - case LOGGING_STATE_READY: - case LOGGING_STATE_RUNNING: - mExecutor.submit(new Callable<Object>() { - @Override - public Object call() throws Exception { - try { - mJsonWriter.endArray(); - mJsonWriter.close(); - } finally { - isAbortSuccessful = mFile.delete(); - } - return null; - } - }); - removeAnyScheduledFlush(); - mExecutor.shutdown(); - mLoggingState = LOGGING_STATE_STOPPING; - break; - case LOGGING_STATE_STOPPING: - case LOGGING_STATE_STOPPED: - } + public boolean blockingAbort() throws InterruptedException { + abort(); + mExecutor.awaitTermination(ABORT_TIMEOUT_IN_MS, TimeUnit.MILLISECONDS); + return mIsAbortSuccessful; } - private boolean isAbortSuccessful; - public boolean isAbortSuccessful() { - return isAbortSuccessful; + public void awaitTermination(int delay, TimeUnit timeUnit) throws InterruptedException { + mExecutor.awaitTermination(delay, timeUnit); } /* package */ synchronized void flush() { - switch (mLoggingState) { - case LOGGING_STATE_UNSTARTED: - break; - case LOGGING_STATE_READY: - case LOGGING_STATE_RUNNING: - removeAnyScheduledFlush(); - mExecutor.submit(mFlushCallable); - break; - case LOGGING_STATE_STOPPING: - case LOGGING_STATE_STOPPED: - } + removeAnyScheduledFlush(); + mExecutor.submit(mFlushCallable); } - private Callable<Object> mFlushCallable = new Callable<Object>() { + private final Callable<Object> mFlushCallable = new Callable<Object>() { @Override public Object call() throws Exception { - if (mLoggingState == LOGGING_STATE_RUNNING) { - mJsonWriter.flush(); - } + mJsonWriter.flush(); return null; } }; @@ -224,56 +178,40 @@ public class ResearchLog { mFlushFuture = mExecutor.schedule(mFlushCallable, FLUSH_DELAY_IN_MS, TimeUnit.MILLISECONDS); } - public synchronized void publishPublicEvents(final LogUnit logUnit) { - switch (mLoggingState) { - case LOGGING_STATE_UNSTARTED: - break; - case LOGGING_STATE_READY: - case LOGGING_STATE_RUNNING: - mExecutor.submit(new Callable<Object>() { - @Override - public Object call() throws Exception { - logUnit.publishPublicEventsTo(ResearchLog.this); - scheduleFlush(); - return null; - } - }); - break; - case LOGGING_STATE_STOPPING: - case LOGGING_STATE_STOPPED: - } - } - - public synchronized void publishAllEvents(final LogUnit logUnit) { - switch (mLoggingState) { - case LOGGING_STATE_UNSTARTED: - break; - case LOGGING_STATE_READY: - case LOGGING_STATE_RUNNING: - mExecutor.submit(new Callable<Object>() { - @Override - public Object call() throws Exception { - logUnit.publishAllEventsTo(ResearchLog.this); - scheduleFlush(); - return null; - } - }); - break; - case LOGGING_STATE_STOPPING: - case LOGGING_STATE_STOPPED: + public synchronized void publish(final LogUnit logUnit, final boolean isIncludingPrivateData) { + try { + mExecutor.submit(new Callable<Object>() { + @Override + public Object call() throws Exception { + logUnit.publishTo(ResearchLog.this, isIncludingPrivateData); + scheduleFlush(); + return null; + } + }); + } catch (RejectedExecutionException e) { + // TODO: Add code to record loss of data, and report. } } private static final String CURRENT_TIME_KEY = "_ct"; private static final String UPTIME_KEY = "_ut"; private static final String EVENT_TYPE_KEY = "_ty"; + void outputEvent(final String[] keys, final Object[] values) { - // not thread safe. + // Not thread safe. + if (keys.length == 0) { + return; + } + if (DEBUG) { + if (keys.length != values.length + 1) { + Log.d(TAG, "Key and Value list sizes do not match. " + keys[0]); + } + } try { if (mJsonWriter == NULL_JSON_WRITER) { mJsonWriter = new JsonWriter(new BufferedWriter(new FileWriter(mFile))); - mJsonWriter.setLenient(true); mJsonWriter.beginArray(); + mHasWrittenData = true; } mJsonWriter.beginObject(); mJsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis()); @@ -283,8 +221,8 @@ public class ResearchLog { for (int i = 0; i < length; i++) { mJsonWriter.name(keys[i + 1]); Object value = values[i]; - if (value instanceof String) { - mJsonWriter.value((String) value); + if (value instanceof CharSequence) { + mJsonWriter.value(value.toString()); } else if (value instanceof Number) { mJsonWriter.value((Number) value); } else if (value instanceof Boolean) { @@ -331,14 +269,11 @@ public class ResearchLog { SuggestedWords words = (SuggestedWords) value; mJsonWriter.beginObject(); mJsonWriter.name("typedWordValid").value(words.mTypedWordValid); - mJsonWriter.name("willAutoCorrect") - .value(words.mWillAutoCorrect); + mJsonWriter.name("willAutoCorrect").value(words.mWillAutoCorrect); mJsonWriter.name("isPunctuationSuggestions") - .value(words.mIsPunctuationSuggestions); - mJsonWriter.name("isObsoleteSuggestions") - .value(words.mIsObsoleteSuggestions); - mJsonWriter.name("isPrediction") - .value(words.mIsPrediction); + .value(words.mIsPunctuationSuggestions); + mJsonWriter.name("isObsoleteSuggestions").value(words.mIsObsoleteSuggestions); + mJsonWriter.name("isPrediction").value(words.mIsPrediction); mJsonWriter.name("words"); mJsonWriter.beginArray(); final int size = words.size(); @@ -363,8 +298,8 @@ public class ResearchLog { try { mJsonWriter.close(); } catch (IllegalStateException e1) { - // assume that this is just the json not being terminated properly. - // ignore + // Assume that this is just the json not being terminated properly. + // Ignore } catch (IOException e1) { e1.printStackTrace(); } finally { diff --git a/java/src/com/android/inputmethod/research/ResearchLogUploader.java b/java/src/com/android/inputmethod/research/ResearchLogUploader.java index 3b1213009..9904a1de2 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogUploader.java +++ b/java/src/com/android/inputmethod/research/ResearchLogUploader.java @@ -27,7 +27,6 @@ import android.os.BatteryManager; import android.util.Log; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.R.string; import java.io.BufferedReader; import java.io.File; @@ -48,6 +47,7 @@ public final class ResearchLogUploader { private static final String TAG = ResearchLogUploader.class.getSimpleName(); private static final int UPLOAD_INTERVAL_IN_MS = 1000 * 60 * 15; // every 15 min private static final int BUF_SIZE = 1024 * 8; + protected static final int TIMEOUT_IN_MS = 1000 * 4; private final boolean mCanUpload; private final Context mContext; @@ -55,8 +55,6 @@ public final class ResearchLogUploader { private final URL mUrl; private final ScheduledExecutorService mExecutor; - private Runnable doUploadRunnable = new UploadRunnable(null, false); - public ResearchLogUploader(final Context context, final File filesDir) { mContext = context; mFilesDir = filesDir; @@ -93,11 +91,15 @@ public final class ResearchLogUploader { public void start() { if (mCanUpload) { - Log.d(TAG, "scheduling regular uploading"); - mExecutor.scheduleWithFixedDelay(doUploadRunnable, UPLOAD_INTERVAL_IN_MS, - UPLOAD_INTERVAL_IN_MS, TimeUnit.MILLISECONDS); - } else { - Log.d(TAG, "no permission to upload"); + mExecutor.scheduleWithFixedDelay(new UploadRunnable(null /* logToWaitFor */, + null /* callback */, false /* forceUpload */), + UPLOAD_INTERVAL_IN_MS, UPLOAD_INTERVAL_IN_MS, TimeUnit.MILLISECONDS); + } + } + + public void uploadAfterCompletion(final ResearchLog researchLog, final Callback callback) { + if (mCanUpload) { + mExecutor.submit(new UploadRunnable(researchLog, callback, true /* forceUpload */)); } } @@ -106,7 +108,8 @@ public final class ResearchLogUploader { // another upload happening right now, as it may have missed the latest changes. // TODO: Reschedule regular upload tests starting from now. if (mCanUpload) { - mExecutor.submit(new UploadRunnable(callback, true)); + mExecutor.submit(new UploadRunnable(null /* logToWaitFor */, callback, + true /* forceUpload */)); } } @@ -130,19 +133,33 @@ public final class ResearchLogUploader { } class UploadRunnable implements Runnable { + private final ResearchLog mLogToWaitFor; private final Callback mCallback; private final boolean mForceUpload; - public UploadRunnable(final Callback callback, final boolean forceUpload) { + public UploadRunnable(final ResearchLog logToWaitFor, final Callback callback, + final boolean forceUpload) { + mLogToWaitFor = logToWaitFor; mCallback = callback; mForceUpload = forceUpload; } @Override public void run() { + if (mLogToWaitFor != null) { + waitFor(mLogToWaitFor); + } doUpload(); } + private void waitFor(final ResearchLog researchLog) { + try { + researchLog.awaitTermination(TIMEOUT_IN_MS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + private void doUpload() { if (!mForceUpload && (!isExternallyPowered() || !hasWifiConnection())) { return; diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index 68bd98a23..77c498648 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -34,15 +34,18 @@ import android.graphics.Paint.Style; import android.inputmethodservice.InputMethodService; import android.os.Build; import android.os.IBinder; +import android.os.SystemClock; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; +import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.CorrectionInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.widget.Button; @@ -64,11 +67,8 @@ import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.define.ProductionFlag; import java.io.File; -import java.io.IOException; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Date; -import java.util.List; import java.util.Locale; import java.util.UUID; @@ -94,24 +94,21 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang new SimpleDateFormat("yyyyMMddHHmmssS", Locale.US); private static final boolean IS_SHOWING_INDICATOR = true; private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false; + public static final int FEEDBACK_WORD_BUFFER_SIZE = 5; // constants related to specific log points private static final String WHITESPACE_SEPARATORS = " \t\n\r"; private static final int MAX_INPUTVIEW_LENGTH_TO_CAPTURE = 8192; // must be >=1 private static final String PREF_RESEARCH_LOGGER_UUID_STRING = "pref_research_logger_uuid"; - private static final int ABORT_TIMEOUT_IN_MS = 10 * 1000; // timeout to notify user private static final ResearchLogger sInstance = new ResearchLogger(); // to write to a different filename, e.g., for testing, set mFile before calling start() /* package */ File mFilesDir; /* package */ String mUUIDString; /* package */ ResearchLog mMainResearchLog; - // The mIntentionalResearchLog records all events for the session, private or not (excepting - // passwords). It is written to permanent storage only if the user explicitly commands - // the system to do so. - /* package */ ResearchLog mIntentionalResearchLog; - // LogUnits are queued here and released only when the user requests the intentional log. - private List<LogUnit> mIntentionalResearchLogQueue = new ArrayList<LogUnit>(); + /* package */ ResearchLog mFeedbackLog; + /* package */ MainLogBuffer mMainLogBuffer; + /* package */ LogBuffer mFeedbackLogBuffer; private boolean mIsPasswordView = false; private boolean mIsLoggingSuspended = false; @@ -135,10 +132,13 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private Dictionary mDictionary; private KeyboardSwitcher mKeyboardSwitcher; private InputMethodService mInputMethodService; - + private final Statistics mStatistics; private ResearchLogUploader mResearchLogUploader; + private LogUnit mCurrentLogUnit = new LogUnit(); + private ResearchLogger() { + mStatistics = Statistics.getInstance(); } public static ResearchLogger getInstance() { @@ -259,6 +259,16 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang e.apply(); } + private void setLoggingAllowed(boolean enableLogging) { + if (mPrefs == null) { + return; + } + Editor e = mPrefs.edit(); + e.putBoolean(PREF_USABILITY_STUDY_MODE, enableLogging); + e.apply(); + sIsLogging = enableLogging; + } + private File createLogFile(File filesDir) { final StringBuilder sb = new StringBuilder(); sb.append(FILENAME_PREFIX).append('-'); @@ -268,10 +278,35 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return new File(filesDir, sb.toString()); } + private void checkForEmptyEditor() { + if (mInputMethodService == null) { + return; + } + final InputConnection ic = mInputMethodService.getCurrentInputConnection(); + if (ic == null) { + return; + } + final CharSequence textBefore = ic.getTextBeforeCursor(1, 0); + if (!TextUtils.isEmpty(textBefore)) { + mStatistics.setIsEmptyUponStarting(false); + return; + } + final CharSequence textAfter = ic.getTextAfterCursor(1, 0); + if (!TextUtils.isEmpty(textAfter)) { + mStatistics.setIsEmptyUponStarting(false); + return; + } + if (textBefore != null && textAfter != null) { + mStatistics.setIsEmptyUponStarting(true); + } + } + private void start() { maybeShowSplashScreen(); updateSuspendedState(); requestIndicatorRedraw(); + mStatistics.reset(); + checkForEmptyEditor(); if (!isAllowedToLog()) { // Log.w(TAG, "not in usability mode; not logging"); return; @@ -280,73 +315,58 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang Log.w(TAG, "IME storage directory does not exist. Cannot start logging."); return; } - try { - if (mMainResearchLog == null || !mMainResearchLog.isAlive()) { - mMainResearchLog = new ResearchLog(createLogFile(mFilesDir)); - } - mMainResearchLog.start(); - if (mIntentionalResearchLog == null || !mIntentionalResearchLog.isAlive()) { - mIntentionalResearchLog = new ResearchLog(createLogFile(mFilesDir)); - } - mIntentionalResearchLog.start(); - } catch (IOException e) { - Log.w(TAG, "Could not start ResearchLogger."); + if (mMainLogBuffer == null) { + mMainResearchLog = new ResearchLog(createLogFile(mFilesDir)); + mMainLogBuffer = new MainLogBuffer(mMainResearchLog); + mMainLogBuffer.setSuggest(mSuggest); + } + if (mFeedbackLogBuffer == null) { + mFeedbackLog = new ResearchLog(createLogFile(mFilesDir)); + // LogBuffer is one more than FEEDBACK_WORD_BUFFER_SIZE, because it must also hold + // the feedback LogUnit itself. + mFeedbackLogBuffer = new LogBuffer(FEEDBACK_WORD_BUFFER_SIZE + 1); } } /* package */ void stop() { - if (mMainResearchLog != null) { - mMainResearchLog.stop(); - } - if (mIntentionalResearchLog != null) { - mIntentionalResearchLog.stop(); - } - } + logStatistics(); + commitCurrentLogUnit(); - private void setLoggingAllowed(boolean enableLogging) { - if (mPrefs == null) { - return; + if (mMainLogBuffer != null) { + publishLogBuffer(mMainLogBuffer, mMainResearchLog, false /* isIncludingPrivateData */); + mMainResearchLog.close(); + mMainLogBuffer = null; + } + if (mFeedbackLogBuffer != null) { + mFeedbackLog.close(); + mFeedbackLogBuffer = null; } - Editor e = mPrefs.edit(); - e.putBoolean(PREF_USABILITY_STUDY_MODE, enableLogging); - e.apply(); - sIsLogging = enableLogging; } public boolean abort() { boolean didAbortMainLog = false; - if (mMainResearchLog != null) { - mMainResearchLog.abort(); + if (mMainLogBuffer != null) { + mMainLogBuffer.clear(); try { - mMainResearchLog.waitUntilStopped(ABORT_TIMEOUT_IN_MS); + didAbortMainLog = mMainResearchLog.blockingAbort(); } catch (InterruptedException e) { - // interrupted early. carry on. + // Don't know whether this succeeded or not. We assume not; this is reported + // to the caller. } - if (mMainResearchLog.isAbortSuccessful()) { - didAbortMainLog = true; - } - mMainResearchLog = null; + mMainLogBuffer = null; } - boolean didAbortIntentionalLog = false; - if (mIntentionalResearchLog != null) { - mIntentionalResearchLog.abort(); + boolean didAbortFeedbackLog = false; + if (mFeedbackLogBuffer != null) { + mFeedbackLogBuffer.clear(); try { - mIntentionalResearchLog.waitUntilStopped(ABORT_TIMEOUT_IN_MS); + didAbortFeedbackLog = mFeedbackLog.blockingAbort(); } catch (InterruptedException e) { - // interrupted early. carry on. - } - if (mIntentionalResearchLog.isAbortSuccessful()) { - didAbortIntentionalLog = true; + // Don't know whether this succeeded or not. We assume not; this is reported + // to the caller. } - mIntentionalResearchLog = null; - } - return didAbortMainLog && didAbortIntentionalLog; - } - - /* package */ void flush() { - if (mMainResearchLog != null) { - mMainResearchLog.flush(); + mFeedbackLogBuffer = null; } + return didAbortMainLog && didAbortFeedbackLog; } private void restart() { @@ -450,79 +470,39 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang latinIME.launchKeyboardedDialogActivity(FeedbackActivity.class); } - private ResearchLog mFeedbackLog; - private List<LogUnit> mFeedbackQueue; - private ResearchLog mSavedMainResearchLog; - private ResearchLog mSavedIntentionalResearchLog; - private List<LogUnit> mSavedIntentionalResearchLogQueue; - - private void saveLogsForFeedback() { - mFeedbackLog = mIntentionalResearchLog; - if (mIntentionalResearchLogQueue != null) { - mFeedbackQueue = new ArrayList<LogUnit>(mIntentionalResearchLogQueue); - } else { - mFeedbackQueue = null; - } - mSavedMainResearchLog = mMainResearchLog; - mSavedIntentionalResearchLog = mIntentionalResearchLog; - mSavedIntentionalResearchLogQueue = mIntentionalResearchLogQueue; - - mMainResearchLog = null; - mIntentionalResearchLog = null; - mIntentionalResearchLogQueue = new ArrayList<LogUnit>(); - } - - private static final int LOG_DRAIN_TIMEOUT_IN_MS = 1000 * 5; + private static final String[] EVENTKEYS_FEEDBACK = { + "UserTimestamp", "contents" + }; public void sendFeedback(final String feedbackContents, final boolean includeHistory) { - if (includeHistory && mFeedbackLog != null) { - try { - LogUnit headerLogUnit = new LogUnit(); - headerLogUnit.addLogAtom(EVENTKEYS_INTENTIONAL_LOG, EVENTKEYS_NULLVALUES, false); - mFeedbackLog.publishAllEvents(headerLogUnit); - for (LogUnit logUnit : mFeedbackQueue) { - mFeedbackLog.publishAllEvents(logUnit); - } - userFeedback(mFeedbackLog, feedbackContents); - mFeedbackLog.stop(); - try { - mFeedbackLog.waitUntilStopped(LOG_DRAIN_TIMEOUT_IN_MS); - } catch (InterruptedException e) { - e.printStackTrace(); - } - mIntentionalResearchLog = new ResearchLog(createLogFile(mFilesDir)); - mIntentionalResearchLog.start(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - mIntentionalResearchLogQueue.clear(); - } - mResearchLogUploader.uploadNow(null); - } else { - // create a separate ResearchLog just for feedback - final ResearchLog feedbackLog = new ResearchLog(createLogFile(mFilesDir)); - try { - feedbackLog.start(); - userFeedback(feedbackLog, feedbackContents); - feedbackLog.stop(); - feedbackLog.waitUntilStopped(LOG_DRAIN_TIMEOUT_IN_MS); - mResearchLogUploader.uploadNow(null); - } catch (IOException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } + if (mFeedbackLogBuffer == null) { + return; + } + if (!includeHistory) { + mFeedbackLogBuffer.clear(); } + commitCurrentLogUnit(); + final LogUnit feedbackLogUnit = new LogUnit(); + final Object[] values = { + feedbackContents + }; + feedbackLogUnit.addLogStatement(EVENTKEYS_FEEDBACK, values, + false /* isPotentiallyPrivate */); + mFeedbackLogBuffer.shiftIn(feedbackLogUnit); + publishLogBuffer(mFeedbackLogBuffer, mFeedbackLog, true /* isIncludingPrivateData */); + mFeedbackLog.close(); + mResearchLogUploader.uploadAfterCompletion(mFeedbackLog, null); + mFeedbackLog = new ResearchLog(createLogFile(mFilesDir)); } public void onLeavingSendFeedbackDialog() { mInFeedbackDialog = false; - mMainResearchLog = mSavedMainResearchLog; - mIntentionalResearchLog = mSavedIntentionalResearchLog; - mIntentionalResearchLogQueue = mSavedIntentionalResearchLogQueue; } public void initSuggest(Suggest suggest) { mSuggest = suggest; + if (mMainLogBuffer != null) { + mMainLogBuffer.setSuggest(mSuggest); + } } private void setIsPasswordView(boolean isPasswordView) { @@ -530,7 +510,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } private boolean isAllowedToLog() { - return !mIsPasswordView && !mIsLoggingSuspended && sIsLogging; + return !mIsPasswordView && !mIsLoggingSuspended && sIsLogging && !mInFeedbackDialog; } public void requestIndicatorRedraw() { @@ -577,13 +557,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } - private static final String CURRENT_TIME_KEY = "_ct"; - private static final String UPTIME_KEY = "_ut"; - private static final String EVENT_TYPE_KEY = "_ty"; private static final Object[] EVENTKEYS_NULLVALUES = {}; - private LogUnit mCurrentLogUnit = new LogUnit(); - /** * Buffer a research log event, flagging it as privacy-sensitive. * @@ -599,10 +574,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang final Object[] values) { assert values.length + 1 == keys.length; if (isAllowedToLog()) { - mCurrentLogUnit.addLogAtom(keys, values, true); + mCurrentLogUnit.addLogStatement(keys, values, true /* isPotentiallyPrivate */); } } + private void setCurrentLogUnitContainsDigitFlag() { + mCurrentLogUnit.setContainsDigit(); + } + /** * Buffer a research log event, flaggint it as not privacy-sensitive. * @@ -618,139 +597,54 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private synchronized void enqueueEvent(final String[] keys, final Object[] values) { assert values.length + 1 == keys.length; if (isAllowedToLog()) { - mCurrentLogUnit.addLogAtom(keys, values, false); + mCurrentLogUnit.addLogStatement(keys, values, false /* isPotentiallyPrivate */); } } - // Used to track how often words are logged. Too-frequent logging can leak - // semantics, disclosing private data. - /* package for test */ static class LoggingFrequencyState { - private static final int DEFAULT_WORD_LOG_FREQUENCY = 10; - private int mWordsRemainingToSkip; - private final int mFrequency; - - /** - * Tracks how often words may be uploaded. - * - * @param frequency 1=Every word, 2=Every other word, etc. - */ - public LoggingFrequencyState(int frequency) { - mFrequency = frequency; - mWordsRemainingToSkip = mFrequency; - } - - public void onWordLogged() { - mWordsRemainingToSkip = mFrequency; - } - - public void onWordNotLogged() { - if (mWordsRemainingToSkip > 1) { - mWordsRemainingToSkip--; + /* package for test */ void commitCurrentLogUnit() { + if (!mCurrentLogUnit.isEmpty()) { + if (mMainLogBuffer != null) { + mMainLogBuffer.shiftIn(mCurrentLogUnit); + if (mMainLogBuffer.isSafeToLog() && mMainResearchLog != null) { + publishLogBuffer(mMainLogBuffer, mMainResearchLog, + true /* isIncludingPrivateData */); + mMainLogBuffer.resetWordCounter(); + } } + if (mFeedbackLogBuffer != null) { + mFeedbackLogBuffer.shiftIn(mCurrentLogUnit); + } + mCurrentLogUnit = new LogUnit(); + Log.d(TAG, "commitCurrentLogUnit"); } + } - public boolean isSafeToLog() { - return mWordsRemainingToSkip <= 1; + /* package for test */ void publishLogBuffer(final LogBuffer logBuffer, + final ResearchLog researchLog, final boolean isIncludingPrivateData) { + LogUnit logUnit; + while ((logUnit = logBuffer.shiftOut()) != null) { + researchLog.publish(logUnit, isIncludingPrivateData); } } - /* package for test */ LoggingFrequencyState mLoggingFrequencyState = - new LoggingFrequencyState(LoggingFrequencyState.DEFAULT_WORD_LOG_FREQUENCY); - - /* package for test */ boolean isPrivacyThreat(String word) { - // Current checks: - // - Word not in dictionary - // - Word contains numbers - // - Privacy-safe word not logged recently - if (TextUtils.isEmpty(word)) { - return false; - } - if (!mLoggingFrequencyState.isSafeToLog()) { - return true; - } + private boolean hasOnlyLetters(final String word) { final int length = word.length(); - boolean hasLetter = false; for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) { - final int codePoint = Character.codePointAt(word, i); - if (Character.isDigit(codePoint)) { - return true; + final int codePoint = word.codePointAt(i); + if (!Character.isLetter(codePoint)) { + return false; } - if (Character.isLetter(codePoint)) { - hasLetter = true; - break; // Word may contain digits, but will only be allowed if in the dictionary. - } - } - if (hasLetter) { - if (mDictionary == null && mSuggest != null && mSuggest.hasMainDictionary()) { - mDictionary = mSuggest.getMainDictionary(); - } - if (mDictionary == null) { - // Can't access dictionary. Assume privacy threat. - return true; - } - return !(mDictionary.isValidWord(word)); } - // No letters, no numbers. Punctuation, space, or something else. - return false; + return true; } - private void onWordComplete(String word) { - if (isPrivacyThreat(word)) { - publishLogUnit(mCurrentLogUnit, true); - mLoggingFrequencyState.onWordNotLogged(); - } else { - publishLogUnit(mCurrentLogUnit, false); - mLoggingFrequencyState.onWordLogged(); - } - mCurrentLogUnit = new LogUnit(); - } - - private void publishLogUnit(LogUnit logUnit, boolean isPrivacySensitive) { - if (!isAllowedToLog()) { - return; - } - if (mMainResearchLog == null) { - return; - } - if (isPrivacySensitive) { - mMainResearchLog.publishPublicEvents(logUnit); - } else { - mMainResearchLog.publishAllEvents(logUnit); - } - mIntentionalResearchLogQueue.add(logUnit); - } - - /* package */ void publishCurrentLogUnit(ResearchLog researchLog, boolean isPrivacySensitive) { - publishLogUnit(mCurrentLogUnit, isPrivacySensitive); - } - - static class LogUnit { - private final List<String[]> mKeysList = new ArrayList<String[]>(); - private final List<Object[]> mValuesList = new ArrayList<Object[]>(); - private final List<Boolean> mIsPotentiallyPrivate = new ArrayList<Boolean>(); - - private void addLogAtom(final String[] keys, final Object[] values, - final Boolean isPotentiallyPrivate) { - mKeysList.add(keys); - mValuesList.add(values); - mIsPotentiallyPrivate.add(isPotentiallyPrivate); - } - - public void publishPublicEventsTo(ResearchLog researchLog) { - final int size = mKeysList.size(); - for (int i = 0; i < size; i++) { - if (!mIsPotentiallyPrivate.get(i)) { - researchLog.outputEvent(mKeysList.get(i), mValuesList.get(i)); - } - } - } - - public void publishAllEventsTo(ResearchLog researchLog) { - final int size = mKeysList.size(); - for (int i = 0; i < size; i++) { - researchLog.outputEvent(mKeysList.get(i), mValuesList.get(i)); - } + private void onWordComplete(final String word) { + Log.d(TAG, "onWordComplete: " + word); + if (word != null && word.length() > 0 && hasOnlyLetters(word)) { + mCurrentLogUnit.setWord(word); + mStatistics.recordWordEntered(); } + commitCurrentLogUnit(); } private static int scrubDigitFromCodePoint(int codePoint) { @@ -803,12 +697,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return WORD_REPLACEMENT_STRING; } - // Special methods related to startup, shutdown, logging itself - - private static final String[] EVENTKEYS_INTENTIONAL_LOG = { - "IntentionalLog" - }; - private static final String[] EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL = { "LatinIMEOnStartInputViewInternal", "uuid", "packageName", "inputType", "imeOptions", "fieldId", "display", "model", "prefs", "versionCode", "versionName", "outputFormatVersion" @@ -816,9 +704,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang public static void latinIME_onStartInputViewInternal(final EditorInfo editorInfo, final SharedPreferences prefs) { final ResearchLogger researchLogger = getInstance(); - if (researchLogger.mInFeedbackDialog) { - researchLogger.saveLogsForFeedback(); - } researchLogger.start(); if (editorInfo != null) { final Context context = researchLogger.mInputMethodService; @@ -846,34 +731,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang stop(); } - private static final String[] EVENTKEYS_LATINIME_COMMITTEXT = { - "LatinIMECommitText", "typedWord" - }; - - public static void latinIME_commitText(final CharSequence typedWord) { - final String scrubbedWord = scrubDigitsFromString(typedWord.toString()); - final Object[] values = { - scrubbedWord - }; - final ResearchLogger researchLogger = getInstance(); - researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_COMMITTEXT, values); - researchLogger.onWordComplete(scrubbedWord); - } - private static final String[] EVENTKEYS_USER_FEEDBACK = { "UserFeedback", "FeedbackContents" }; - private void userFeedback(ResearchLog researchLog, String feedbackContents) { - // this method is special; it directs the feedbackContents to a particular researchLog - final LogUnit logUnit = new LogUnit(); - final Object[] values = { - feedbackContents - }; - logUnit.addLogAtom(EVENTKEYS_USER_FEEDBACK, values, false); - researchLog.publishAllEvents(logUnit); - } - // Regular logging methods private static final String[] EVENTKEYS_MAINKEYBOARDVIEW_PROCESSMOTIONEVENT = { @@ -908,51 +769,16 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang "LatinIMEOnCodeInput", "code", "x", "y" }; public static void latinIME_onCodeInput(final int code, final int x, final int y) { - final Object[] values = { - Keyboard.printableCode(scrubDigitFromCodePoint(code)), x, y - }; - getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_ONCODEINPUT, values); - } - - private static final String[] EVENTKEYS_CORRECTION = { - "LogCorrection", "subgroup", "before", "after", "position" - }; - public static void logCorrection(final String subgroup, final String before, final String after, - final int position) { - final Object[] values = { - subgroup, scrubDigitsFromString(before), scrubDigitsFromString(after), position - }; - getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_CORRECTION, values); - } - - private static final String[] EVENTKEYS_LATINIME_COMMITCURRENTAUTOCORRECTION = { - "LatinIMECommitCurrentAutoCorrection", "typedWord", "autoCorrection" - }; - public static void latinIME_commitCurrentAutoCorrection(final String typedWord, - final String autoCorrection) { - final Object[] values = { - scrubDigitsFromString(typedWord), scrubDigitsFromString(autoCorrection) - }; + final long time = SystemClock.uptimeMillis(); final ResearchLogger researchLogger = getInstance(); - researchLogger.enqueuePotentiallyPrivateEvent( - EVENTKEYS_LATINIME_COMMITCURRENTAUTOCORRECTION, values); - } - - private static final String[] EVENTKEYS_LATINIME_DELETESURROUNDINGTEXT = { - "LatinIMEDeleteSurroundingText", "length" - }; - public static void latinIME_deleteSurroundingText(final int length) { final Object[] values = { - length + Keyboard.printableCode(scrubDigitFromCodePoint(code)), x, y }; - getInstance().enqueueEvent(EVENTKEYS_LATINIME_DELETESURROUNDINGTEXT, values); - } - - private static final String[] EVENTKEYS_LATINIME_DOUBLESPACEAUTOPERIOD = { - "LatinIMEDoubleSpaceAutoPeriod" - }; - public static void latinIME_doubleSpaceAutoPeriod() { - getInstance().enqueueEvent(EVENTKEYS_LATINIME_DOUBLESPACEAUTOPERIOD, EVENTKEYS_NULLVALUES); + researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_ONCODEINPUT, values); + if (Character.isDigit(code)) { + researchLogger.setCurrentLogUnitContainsDigitFlag(); + } + researchLogger.mStatistics.recordChar(code, time); } private static final String[] EVENTKEYS_LATINIME_ONDISPLAYCOMPLETIONS = { @@ -979,6 +805,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang public static void latinIME_onWindowHidden(final int savedSelectionStart, final int savedSelectionEnd, final InputConnection ic) { if (ic != null) { + // Capture the TextView contents. This will trigger onUpdateSelection(), so we + // set sLatinIMEExpectingUpdateSelection so that when onUpdateSelection() is called, + // it can tell that it was generated by the logging code, and not by the user, and + // therefore keep user-visible state as is. ic.beginBatchEdit(); ic.performContextMenuAction(android.R.id.selectAll); CharSequence charSequence = ic.getSelectedText(0); @@ -1013,9 +843,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } final ResearchLogger researchLogger = getInstance(); researchLogger.enqueueEvent(EVENTKEYS_LATINIME_ONWINDOWHIDDEN, values); - // Play it safe. Remove privacy-sensitive events. - researchLogger.publishLogUnit(researchLogger.mCurrentLogUnit, true); - researchLogger.mCurrentLogUnit = new LogUnit(); + researchLogger.commitCurrentLogUnit(); getInstance().stop(); } } @@ -1048,29 +876,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_ONUPDATESELECTION, values); } - private static final String[] EVENTKEYS_LATINIME_PERFORMEDITORACTION = { - "LatinIMEPerformEditorAction", "imeActionNext" - }; - public static void latinIME_performEditorAction(final int imeActionNext) { - final Object[] values = { - imeActionNext - }; - getInstance().enqueueEvent(EVENTKEYS_LATINIME_PERFORMEDITORACTION, values); - } - - private static final String[] EVENTKEYS_LATINIME_PICKAPPLICATIONSPECIFIEDCOMPLETION = { - "LatinIMEPickApplicationSpecifiedCompletion", "index", "text", "x", "y" - }; - public static void latinIME_pickApplicationSpecifiedCompletion(final int index, - final CharSequence cs, int x, int y) { - final Object[] values = { - index, cs, x, y - }; - final ResearchLogger researchLogger = getInstance(); - researchLogger.enqueuePotentiallyPrivateEvent( - EVENTKEYS_LATINIME_PICKAPPLICATIONSPECIFIEDCOMPLETION, values); - } - private static final String[] EVENTKEYS_LATINIME_PICKSUGGESTIONMANUALLY = { "LatinIMEPickSuggestionManually", "replacedWord", "index", "suggestion", "x", "y" }; @@ -1096,21 +901,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang getInstance().enqueueEvent(EVENTKEYS_LATINIME_PUNCTUATIONSUGGESTION, values); } - private static final String[] EVENTKEYS_LATINIME_REVERTDOUBLESPACEWHILEINBATCHEDIT = { - "LatinIMERevertDoubleSpaceWhileInBatchEdit" - }; - public static void latinIME_revertDoubleSpaceWhileInBatchEdit() { - getInstance().enqueueEvent(EVENTKEYS_LATINIME_REVERTDOUBLESPACEWHILEINBATCHEDIT, - EVENTKEYS_NULLVALUES); - } - - private static final String[] EVENTKEYS_LATINIME_REVERTSWAPPUNCTUATION = { - "LatinIMERevertSwapPunctuation" - }; - public static void latinIME_revertSwapPunctuation() { - getInstance().enqueueEvent(EVENTKEYS_LATINIME_REVERTSWAPPUNCTUATION, EVENTKEYS_NULLVALUES); - } - private static final String[] EVENTKEYS_LATINIME_SENDKEYCODEPOINT = { "LatinIMESendKeyCodePoint", "code" }; @@ -1118,15 +908,18 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang final Object[] values = { Keyboard.printableCode(scrubDigitFromCodePoint(code)) }; - getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_SENDKEYCODEPOINT, values); + final ResearchLogger researchLogger = getInstance(); + researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_SENDKEYCODEPOINT, values); + if (Character.isDigit(code)) { + researchLogger.setCurrentLogUnitContainsDigitFlag(); + } } - private static final String[] EVENTKEYS_LATINIME_SWAPSWAPPERANDSPACEWHILEINBATCHEDIT = { - "LatinIMESwapSwapperAndSpaceWhileInBatchEdit" + private static final String[] EVENTKEYS_LATINIME_SWAPSWAPPERANDSPACE = { + "LatinIMESwapSwapperAndSpace" }; - public static void latinIME_swapSwapperAndSpaceWhileInBatchEdit() { - getInstance().enqueueEvent(EVENTKEYS_LATINIME_SWAPSWAPPERANDSPACEWHILEINBATCHEDIT, - EVENTKEYS_NULLVALUES); + public static void latinIME_swapSwapperAndSpace() { + getInstance().enqueueEvent(EVENTKEYS_LATINIME_SWAPSWAPPERANDSPACE, EVENTKEYS_NULLVALUES); } private static final String[] EVENTKEYS_MAINKEYBOARDVIEW_ONLONGPRESS = { @@ -1245,6 +1038,128 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_POINTERTRACKER_ONMOVEEVENT, values); } + private static final String[] EVENTKEYS_RICHINPUTCONNECTION_COMMITCOMPLETION = { + "RichInputConnectionCommitCompletion", "completionInfo" + }; + public static void richInputConnection_commitCompletion(final CompletionInfo completionInfo) { + final Object[] values = { + completionInfo + }; + final ResearchLogger researchLogger = getInstance(); + researchLogger.enqueuePotentiallyPrivateEvent( + EVENTKEYS_RICHINPUTCONNECTION_COMMITCOMPLETION, values); + } + + // Disabled for privacy-protection reasons. Because this event comes after + // richInputConnection_commitText, which is the event used to separate LogUnits, the + // data in this event can be associated with the next LogUnit, revealing information + // about the current word even if it was supposed to be suppressed. The occurrance of + // autocorrection can be determined by examining the difference between the text strings in + // the last call to richInputConnection_setComposingText before + // richInputConnection_commitText, so it's not a data loss. + // TODO: Figure out how to log this event without loss of privacy. + /* + private static final String[] EVENTKEYS_RICHINPUTCONNECTION_COMMITCORRECTION = { + "RichInputConnectionCommitCorrection", "typedWord", "autoCorrection" + }; + */ + public static void richInputConnection_commitCorrection(CorrectionInfo correctionInfo) { + /* + final String typedWord = correctionInfo.getOldText().toString(); + final String autoCorrection = correctionInfo.getNewText().toString(); + final Object[] values = { + scrubDigitsFromString(typedWord), scrubDigitsFromString(autoCorrection) + }; + final ResearchLogger researchLogger = getInstance(); + researchLogger.enqueuePotentiallyPrivateEvent( + EVENTKEYS_RICHINPUTCONNECTION_COMMITCORRECTION, values); + */ + } + + private static final String[] EVENTKEYS_RICHINPUTCONNECTION_COMMITTEXT = { + "RichInputConnectionCommitText", "typedWord", "newCursorPosition" + }; + public static void richInputConnection_commitText(final CharSequence typedWord, + final int newCursorPosition) { + final String scrubbedWord = scrubDigitsFromString(typedWord.toString()); + final Object[] values = { + scrubbedWord, newCursorPosition + }; + final ResearchLogger researchLogger = getInstance(); + researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_RICHINPUTCONNECTION_COMMITTEXT, + values); + researchLogger.onWordComplete(scrubbedWord); + } + + private static final String[] EVENTKEYS_RICHINPUTCONNECTION_DELETESURROUNDINGTEXT = { + "RichInputConnectionDeleteSurroundingText", "beforeLength", "afterLength" + }; + public static void richInputConnection_deleteSurroundingText(final int beforeLength, + final int afterLength) { + final Object[] values = { + beforeLength, afterLength + }; + getInstance().enqueuePotentiallyPrivateEvent( + EVENTKEYS_RICHINPUTCONNECTION_DELETESURROUNDINGTEXT, values); + } + + private static final String[] EVENTKEYS_RICHINPUTCONNECTION_FINISHCOMPOSINGTEXT = { + "RichInputConnectionFinishComposingText" + }; + public static void richInputConnection_finishComposingText() { + getInstance().enqueueEvent(EVENTKEYS_RICHINPUTCONNECTION_FINISHCOMPOSINGTEXT, + EVENTKEYS_NULLVALUES); + } + + private static final String[] EVENTKEYS_RICHINPUTCONNECTION_PERFORMEDITORACTION = { + "RichInputConnectionPerformEditorAction", "imeActionNext" + }; + public static void richInputConnection_performEditorAction(final int imeActionNext) { + final Object[] values = { + imeActionNext + }; + getInstance().enqueueEvent(EVENTKEYS_RICHINPUTCONNECTION_PERFORMEDITORACTION, values); + } + + private static final String[] EVENTKEYS_RICHINPUTCONNECTION_SENDKEYEVENT = { + "RichInputConnectionSendKeyEvent", "eventTime", "action", "code" + }; + public static void richInputConnection_sendKeyEvent(final KeyEvent keyEvent) { + final Object[] values = { + keyEvent.getEventTime(), + keyEvent.getAction(), + keyEvent.getKeyCode() + }; + getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_RICHINPUTCONNECTION_SENDKEYEVENT, + values); + } + + private static final String[] EVENTKEYS_RICHINPUTCONNECTION_SETCOMPOSINGTEXT = { + "RichInputConnectionSetComposingText", "text", "newCursorPosition" + }; + public static void richInputConnection_setComposingText(final CharSequence text, + final int newCursorPosition) { + if (text == null) { + throw new RuntimeException("setComposingText is null"); + } + final Object[] values = { + text, newCursorPosition + }; + getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_RICHINPUTCONNECTION_SETCOMPOSINGTEXT, + values); + } + + private static final String[] EVENTKEYS_RICHINPUTCONNECTION_SETSELECTION = { + "RichInputConnectionSetSelection", "from", "to" + }; + public static void richInputConnection_setSelection(final int from, final int to) { + final Object[] values = { + from, to + }; + getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_RICHINPUTCONNECTION_SETSELECTION, + values); + } + private static final String[] EVENTKEYS_SUDDENJUMPINGTOUCHEVENTHANDLER_ONTOUCHEVENT = { "SuddenJumpingTouchEventHandlerOnTouchEvent", "motionEvent" }; @@ -1277,4 +1192,24 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang public void userTimestamp() { getInstance().enqueueEvent(EVENTKEYS_USER_TIMESTAMP, EVENTKEYS_NULLVALUES); } + + private static final String[] EVENTKEYS_STATISTICS = { + "Statistics", "charCount", "letterCount", "numberCount", "spaceCount", "deleteOpsCount", + "wordCount", "isEmptyUponStarting", "isEmptinessStateKnown", "averageTimeBetweenKeys", + "averageTimeBeforeDelete", "averageTimeDuringRepeatedDelete", "averageTimeAfterDelete" + }; + private static void logStatistics() { + final ResearchLogger researchLogger = getInstance(); + final Statistics statistics = researchLogger.mStatistics; + final Object[] values = { + statistics.mCharCount, statistics.mLetterCount, statistics.mNumberCount, + statistics.mSpaceCount, statistics.mDeleteKeyCount, + statistics.mWordCount, statistics.mIsEmptyUponStarting, + statistics.mIsEmptinessStateKnown, statistics.mKeyCounter.getAverageTime(), + statistics.mBeforeDeleteKeyCounter.getAverageTime(), + statistics.mDuringRepeatedDeleteKeysCounter.getAverageTime(), + statistics.mAfterDeleteKeyCounter.getAverageTime() + }; + researchLogger.enqueueEvent(EVENTKEYS_STATISTICS, values); + } } diff --git a/java/src/com/android/inputmethod/research/Statistics.java b/java/src/com/android/inputmethod/research/Statistics.java new file mode 100644 index 000000000..eab465aa2 --- /dev/null +++ b/java/src/com/android/inputmethod/research/Statistics.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.research; + +import com.android.inputmethod.keyboard.Keyboard; + +public class Statistics { + // Number of characters entered during a typing session + int mCharCount; + // Number of letter characters entered during a typing session + int mLetterCount; + // Number of number characters entered + int mNumberCount; + // Number of space characters entered + int mSpaceCount; + // Number of delete operations entered (taps on the backspace key) + int mDeleteKeyCount; + // Number of words entered during a session. + int mWordCount; + // Whether the text field was empty upon editing + boolean mIsEmptyUponStarting; + boolean mIsEmptinessStateKnown; + + // Timers to count average time to enter a key, first press a delete key, + // between delete keys, and then to return typing after a delete key. + final AverageTimeCounter mKeyCounter = new AverageTimeCounter(); + final AverageTimeCounter mBeforeDeleteKeyCounter = new AverageTimeCounter(); + final AverageTimeCounter mDuringRepeatedDeleteKeysCounter = new AverageTimeCounter(); + final AverageTimeCounter mAfterDeleteKeyCounter = new AverageTimeCounter(); + + static class AverageTimeCounter { + int mCount; + int mTotalTime; + + public void reset() { + mCount = 0; + mTotalTime = 0; + } + + public void add(long deltaTime) { + mCount++; + mTotalTime += deltaTime; + } + + public int getAverageTime() { + if (mCount == 0) { + return 0; + } + return mTotalTime / mCount; + } + } + + // To account for the interruptions when the user's attention is directed elsewhere, times + // longer than MIN_TYPING_INTERMISSION are not counted when estimating this statistic. + public static final int MIN_TYPING_INTERMISSION = 2 * 1000; // in milliseconds + public static final int MIN_DELETION_INTERMISSION = 10 * 1000; // in milliseconds + + // The last time that a tap was performed + private long mLastTapTime; + // The type of the last keypress (delete key or not) + boolean mIsLastKeyDeleteKey; + + private static final Statistics sInstance = new Statistics(); + + public static Statistics getInstance() { + return sInstance; + } + + private Statistics() { + reset(); + } + + public void reset() { + mCharCount = 0; + mLetterCount = 0; + mNumberCount = 0; + mSpaceCount = 0; + mDeleteKeyCount = 0; + mWordCount = 0; + mIsEmptyUponStarting = true; + mIsEmptinessStateKnown = false; + mKeyCounter.reset(); + mBeforeDeleteKeyCounter.reset(); + mDuringRepeatedDeleteKeysCounter.reset(); + mAfterDeleteKeyCounter.reset(); + + mLastTapTime = 0; + mIsLastKeyDeleteKey = false; + } + + public void recordChar(int codePoint, long time) { + final long delta = time - mLastTapTime; + if (codePoint == Keyboard.CODE_DELETE) { + mDeleteKeyCount++; + if (delta < MIN_DELETION_INTERMISSION) { + if (mIsLastKeyDeleteKey) { + mDuringRepeatedDeleteKeysCounter.add(delta); + } else { + mBeforeDeleteKeyCounter.add(delta); + } + } + mIsLastKeyDeleteKey = true; + } else { + mCharCount++; + if (Character.isDigit(codePoint)) { + mNumberCount++; + } + if (Character.isLetter(codePoint)) { + mLetterCount++; + } + if (Character.isSpaceChar(codePoint)) { + mSpaceCount++; + } + if (mIsLastKeyDeleteKey && delta < MIN_DELETION_INTERMISSION) { + mAfterDeleteKeyCounter.add(delta); + } else if (!mIsLastKeyDeleteKey && delta < MIN_TYPING_INTERMISSION) { + mKeyCounter.add(delta); + } + mIsLastKeyDeleteKey = false; + } + mLastTapTime = time; + } + + public void recordWordEntered() { + mWordCount++; + } + + public void setIsEmptyUponStarting(final boolean isEmpty) { + mIsEmptyUponStarting = isEmpty; + mIsEmptinessStateKnown = true; + } +} diff --git a/native/jni/Android.mk b/native/jni/Android.mk index 06ed5718e..9f9958377 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -15,8 +15,8 @@ LOCAL_PATH := $(call my-dir) ############ some local flags -# If you change any of those flags, you need to rebuild both libjni_latinime_static -# and the shared library. +# If you change any of those flags, you need to rebuild both libjni_latinime_common_static +# and the shared library that uses libjni_latinime_common_static. FLAG_DBG ?= false FLAG_DO_PROFILE ?= false @@ -69,14 +69,9 @@ endif # FLAG_DO_PROFILE LOCAL_MODULE := libjni_latinime_common_static LOCAL_MODULE_TAGS := optional -# TODO: Remove this conditional block once we have no issues with building against NDK -ifndef TARGET_BUILD_APPS # A full system image build -include external/stlport/libstlport.mk -else # An unbundled build -LOCAL_NDK_VERSION := 7 +LOCAL_NDK_VERSION := 8 LOCAL_SDK_VERSION := 14 LOCAL_NDK_STL_VARIANT := stlport_static -endif include $(BUILD_STATIC_LIBRARY) ###################################### @@ -87,25 +82,20 @@ LOCAL_WHOLE_STATIC_LIBRARIES := libjni_latinime_common_static ifeq ($(FLAG_DO_PROFILE), true) $(warning Making profiling version of native library) - LOCAL_SHARED_LIBRARIES += libcutils libutils + LOCAL_SHARED_LIBRARIES += liblog else # FLAG_DO_PROFILE ifeq ($(FLAG_DBG), true) $(warning Making debug version of native library) - LOCAL_SHARED_LIBRARIES += libcutils libutils + LOCAL_SHARED_LIBRARIES += liblog endif # FLAG_DBG endif # FLAG_DO_PROFILE LOCAL_MODULE := libjni_latinime LOCAL_MODULE_TAGS := optional -# TODO: Remove this conditional block once we have no issues with building against NDK -ifndef TARGET_BUILD_APPS # A full system image build -LOCAL_STATIC_LIBRARIES += libstlport_static -else # An unbundled build -LOCAL_NDK_VERSION := 7 +LOCAL_NDK_VERSION := 8 LOCAL_SDK_VERSION := 14 LOCAL_NDK_STL_VARIANT := stlport_static -endif include $(BUILD_SHARED_LIBRARY) diff --git a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp index 9eb437c06..74390ccdf 100644 --- a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp +++ b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp @@ -1,32 +1,28 @@ /* -** -** Copyright 2011, 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. -*/ + * Copyright (C) 2011, 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. + */ #define LOG_TAG "LatinIME: jni: ProximityInfo" +#include <string> + #include "com_android_inputmethod_keyboard_ProximityInfo.h" #include "jni.h" #include "jni_common.h" #include "proximity_info.h" -#include <assert.h> -#include <errno.h> -#include <stdio.h> -#include <string> - namespace latinime { static jlong latinime_Keyboard_setProximityInfo(JNIEnv *env, jobject object, @@ -48,10 +44,9 @@ static jlong latinime_Keyboard_setProximityInfo(JNIEnv *env, jobject object, jfloat *sweetSpotCenterYs = safeGetFloatArrayElements(env, sweetSpotCenterYArray); jfloat *sweetSpotRadii = safeGetFloatArrayElements(env, sweetSpotRadiusArray); ProximityInfo *proximityInfo = new ProximityInfo( - localeStr, maxProximityCharsSize, displayWidth, - displayHeight, gridWidth, gridHeight, mostCommonkeyWidth, - (const int32_t*)proximityChars, - keyCount, (const int32_t*)keyXCoordinates, (const int32_t*)keyYCoordinates, + localeStr, maxProximityCharsSize, displayWidth, displayHeight, gridWidth, gridHeight, + mostCommonkeyWidth, (const int32_t*)proximityChars, keyCount, + (const int32_t*)keyXCoordinates, (const int32_t*)keyYCoordinates, (const int32_t*)keyWidths, (const int32_t*)keyHeights, (const int32_t*)keyCharCodes, (const float*)sweetSpotCenterXs, (const float*)sweetSpotCenterYs, (const float*)sweetSpotRadii); @@ -85,5 +80,4 @@ int register_ProximityInfo(JNIEnv *env) { return registerNativeMethods(env, kClassPathName, sKeyboardMethods, sizeof(sKeyboardMethods) / sizeof(sKeyboardMethods[0])); } - } // namespace latinime diff --git a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.h b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.h index 4a1e83b09..51fa895d3 100644 --- a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.h +++ b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.h @@ -1,19 +1,18 @@ /* -** -** Copyright 2011, 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. -*/ + * Copyright (C) 2011, 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 _COM_ANDROID_INPUTMETHOD_KEYBOARD_PROXIMITYINFO_H #define _COM_ANDROID_INPUTMETHOD_KEYBOARD_PROXIMITYINFO_H @@ -24,6 +23,5 @@ namespace latinime { int register_ProximityInfo(JNIEnv *env); -} - +} // namespace latinime #endif // _COM_ANDROID_INPUTMETHOD_KEYBOARD_PROXIMITYINFO_H diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 0a282b865..776f5f78f 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -1,48 +1,42 @@ /* -** -** Copyright 2009, 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. -*/ + * Copyright (C) 2009, 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. + */ #define LOG_TAG "LatinIME: jni: BinaryDictionary" #include "binary_format.h" -#include "correction.h" #include "com_android_inputmethod_latin_BinaryDictionary.h" +#include "correction.h" #include "defines.h" #include "dictionary.h" #include "jni.h" #include "jni_common.h" -#include "proximity_info.h" - -#include <assert.h> -#include <errno.h> -#include <stdio.h> #ifdef USE_MMAP_FOR_DICTIONARY -#include <sys/mman.h> -#include <sys/types.h> -#include <sys/stat.h> +#include <cerrno> #include <fcntl.h> -#include <unistd.h> +#include <sys/mman.h> #else // USE_MMAP_FOR_DICTIONARY -#include <stdlib.h> +#include <cstdlib> #endif // USE_MMAP_FOR_DICTIONARY namespace latinime { -void releaseDictBuf(void* dictBuf, const size_t length, int fd); +class ProximityInfo; + +void releaseDictBuf(void *dictBuf, const size_t length, int fd); static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, jstring sourceDir, jlong dictOffset, jlong dictSize, @@ -235,7 +229,7 @@ static void latinime_BinaryDictionary_close(JNIEnv *env, jobject object, jlong d delete dictionary; } -void releaseDictBuf(void* dictBuf, const size_t length, int fd) { +void releaseDictBuf(void *dictBuf, const size_t length, int fd) { #ifdef USE_MMAP_FOR_DICTIONARY int ret = munmap(dictBuf, length); if (ret != 0) { @@ -263,9 +257,8 @@ static JNINativeMethod sMethods[] = { }; int register_BinaryDictionary(JNIEnv *env) { - const char* const kClassPathName = "com/android/inputmethod/latin/BinaryDictionary"; + const char *const kClassPathName = "com/android/inputmethod/latin/BinaryDictionary"; return registerNativeMethods(env, kClassPathName, sMethods, sizeof(sMethods) / sizeof(sMethods[0])); } - } // namespace latinime diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.h b/native/jni/com_android_inputmethod_latin_BinaryDictionary.h index 1b1ba7f0f..b9e944f07 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.h +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.h @@ -1,19 +1,18 @@ /* -** -** Copyright 2011, 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. -*/ + * Copyright (C) 2011, 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 _COM_ANDROID_INPUTMETHOD_LATIN_BINARYDICTIONARY_H #define _COM_ANDROID_INPUTMETHOD_LATIN_BINARYDICTIONARY_H @@ -24,6 +23,5 @@ namespace latinime { int register_BinaryDictionary(JNIEnv *env); -} - +} // namespace latinime #endif // _COM_ANDROID_INPUTMETHOD_LATIN_BINARYDICTIONARY_H diff --git a/native/jni/com_android_inputmethod_latin_NativeUtils.cpp b/native/jni/com_android_inputmethod_latin_NativeUtils.cpp index c1e586a4b..8f1afbeb6 100644 --- a/native/jni/com_android_inputmethod_latin_NativeUtils.cpp +++ b/native/jni/com_android_inputmethod_latin_NativeUtils.cpp @@ -1,25 +1,24 @@ /* -** -** Copyright 2012, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ + * Copyright (C) 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "com_android_inputmethod_latin_NativeUtils.h" #include "jni.h" #include "jni_common.h" -#include <math.h> +#include <cmath> namespace latinime { @@ -32,9 +31,8 @@ static JNINativeMethod sMethods[] = { }; int register_NativeUtils(JNIEnv *env) { - const char* const kClassPathName = "com/android/inputmethod/latin/NativeUtils"; + const char *const kClassPathName = "com/android/inputmethod/latin/NativeUtils"; return registerNativeMethods(env, kClassPathName, sMethods, sizeof(sMethods) / sizeof(sMethods[0])); } - } // namespace latinime diff --git a/native/jni/com_android_inputmethod_latin_NativeUtils.h b/native/jni/com_android_inputmethod_latin_NativeUtils.h index 13a348a5c..d1ffb8f4a 100644 --- a/native/jni/com_android_inputmethod_latin_NativeUtils.h +++ b/native/jni/com_android_inputmethod_latin_NativeUtils.h @@ -1,19 +1,18 @@ /* -** -** Copyright 2012, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ + * Copyright (C) 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef _COM_ANDROID_INPUTMETHOD_LATIN_NATIVEUTILS_H #define _COM_ANDROID_INPUTMETHOD_LATIN_NATIVEUTILS_H @@ -24,6 +23,5 @@ namespace latinime { int register_NativeUtils(JNIEnv *env); -} - +} // namespace latinime #endif // _COM_ANDROID_INPUTMETHOD_LATIN_NATIVEUTILS_H diff --git a/native/jni/jni_common.cpp b/native/jni/jni_common.cpp index 1314bab27..105a4dc4c 100644 --- a/native/jni/jni_common.cpp +++ b/native/jni/jni_common.cpp @@ -1,19 +1,18 @@ /* -** -** Copyright 2011, 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. -*/ + * Copyright (C) 2011, 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. + */ #define LOG_TAG "LatinIME: jni" @@ -22,26 +21,24 @@ #include "com_android_inputmethod_latin_NativeUtils.h" #include "defines.h" #include "jni.h" -#include "proximity_info.h" +#include "jni_common.h" -#include <assert.h> -#include <errno.h> -#include <stdio.h> +#include <cassert> using namespace latinime; /* * Returns the JNI version on success, -1 on failure. */ -jint JNI_OnLoad(JavaVM* vm, void* reserved) { - JNIEnv* env = 0; +jint JNI_OnLoad(JavaVM *vm, void *reserved) { + JNIEnv *env = 0; jint result = -1; - if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { AKLOGE("ERROR: GetEnv failed"); goto bail; } - assert(env != 0); + assert(env); if (!register_BinaryDictionary(env)) { AKLOGE("ERROR: BinaryDictionary native registration failed"); @@ -59,7 +56,7 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { } /* success -- return valid version number */ - result = JNI_VERSION_1_4; + result = JNI_VERSION_1_6; bail: return result; @@ -67,10 +64,10 @@ bail: namespace latinime { -int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* methods, +int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods) { jclass clazz = env->FindClass(className); - if (clazz == 0) { + if (!clazz) { AKLOGE("Native registration unable to find class '%s'", className); return JNI_FALSE; } @@ -82,5 +79,4 @@ int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* m env->DeleteLocalRef(clazz); return JNI_TRUE; } - } // namespace latinime diff --git a/native/jni/jni_common.h b/native/jni/jni_common.h index 6741443ac..658ff18b9 100644 --- a/native/jni/jni_common.h +++ b/native/jni/jni_common.h @@ -1,25 +1,22 @@ /* -** -** Copyright 2011, 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. -*/ + * Copyright (C) 2011, 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_JNI_COMMON_H #define LATINIME_JNI_COMMON_H -#include <stdlib.h> - #include "jni.h" namespace latinime { @@ -54,7 +51,5 @@ inline void safeReleaseFloatArrayElements(JNIEnv *env, jfloatArray jArray, jfloa env->ReleaseFloatArrayElements(jArray, cArray, 0); } } - } // namespace latinime - #endif // LATINIME_JNI_COMMON_H diff --git a/native/jni/src/additional_proximity_chars.cpp b/native/jni/src/additional_proximity_chars.cpp index 224f020f2..de8764678 100644 --- a/native/jni/src/additional_proximity_chars.cpp +++ b/native/jni/src/additional_proximity_chars.cpp @@ -38,4 +38,4 @@ const int32_t AdditionalProximityChars::EN_US_ADDITIONAL_O[EN_US_ADDITIONAL_O_SI const int32_t AdditionalProximityChars::EN_US_ADDITIONAL_U[EN_US_ADDITIONAL_U_SIZE] = { 'a', 'e', 'i', 'o' }; -} +} // namespace latinime diff --git a/native/jni/src/additional_proximity_chars.h b/native/jni/src/additional_proximity_chars.h index 82c31f860..ba76cfced 100644 --- a/native/jni/src/additional_proximity_chars.h +++ b/native/jni/src/additional_proximity_chars.h @@ -45,7 +45,7 @@ class AdditionalProximityChars { } public: - static int getAdditionalCharsSize(const std::string* locale_str, const int32_t c) { + static int getAdditionalCharsSize(const std::string *locale_str, const int32_t c) { if (!isEnLocale(locale_str)) { return 0; } @@ -65,7 +65,7 @@ class AdditionalProximityChars { } } - static const int32_t* getAdditionalChars(const std::string *locale_str, const int32_t c) { + static const int32_t *getAdditionalChars(const std::string *locale_str, const int32_t c) { if (!isEnLocale(locale_str)) { return 0; } @@ -89,7 +89,5 @@ class AdditionalProximityChars { return getAdditionalCharsSize(locale_str, c) > 0; } }; - -} - +} // namespace latinime #endif // LATINIME_ADDITIONAL_PROXIMITY_CHARS_H diff --git a/native/jni/src/basechars.cpp b/native/jni/src/basechars.cpp index 31f1e18a8..c91e5f741 100644 --- a/native/jni/src/basechars.cpp +++ b/native/jni/src/basechars.cpp @@ -18,7 +18,7 @@ namespace latinime { -/** +/* * Table mapping most combined Latin, Greek, and Cyrillic characters * to their base characters. If c is in range, BASE_CHARS[c] == c * if c is not a combined character, or the base character if it @@ -187,8 +187,6 @@ const unsigned short BASE_CHARS[BASE_CHARS_SIZE] = { 0x0423, 0x0443, 0x0423, 0x0443, 0x0427, 0x0447, 0x04f6, 0x04f7, 0x042b, 0x044b, 0x04fa, 0x04fb, 0x04fc, 0x04fd, 0x04fe, 0x04ff, }; - // generated with: // cat UnicodeData.txt | perl -e 'while (<>) { @foo = split(/;/); $foo[5] =~ s/<.*> //; $base[hex($foo[0])] = hex($foo[5]);} for ($i = 0; $i < 0x500; $i += 8) { for ($j = $i; $j < $i + 8; $j++) { printf("0x%04x, ", $base[$j] ? $base[$j] : $j)}; print "\n"; }' - } // namespace latinime diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp index 8057e410a..220171127 100644 --- a/native/jni/src/bigram_dictionary.cpp +++ b/native/jni/src/bigram_dictionary.cpp @@ -1,21 +1,20 @@ /* -** -** Copyright 2010, 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 <string.h> + * Copyright (C) 2010, 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 <cstring> #define LOG_TAG "LatinIME: bigram_dictionary.cpp" @@ -103,7 +102,7 @@ int BigramDictionary::getBigrams(const int32_t *prevWord, int prevWordLength, in // TODO: remove unused arguments, and refrain from storing stuff in members of this class // TODO: have "in" arguments before "out" ones, and make out args explicit in the name - const uint8_t* const root = DICT; + const uint8_t *const root = DICT; int pos = getBigramListPositionForWord(prevWord, prevWordLength, false /* forceLowerCaseSearch */); // getBigramListPositionForWord returns 0 if this word isn't in the dictionary or has no bigrams @@ -127,7 +126,7 @@ int BigramDictionary::getBigrams(const int32_t *prevWord, int prevWordLength, in // codesSize == 0 means we are trying to find bigram predictions. if (codesSize < 1 || checkFirstCharacter(bigramBuffer, inputCodes)) { - const int bigramFreqTemp = UnigramDictionary::MASK_ATTRIBUTE_FREQUENCY & bigramFlags; + const int bigramFreqTemp = BinaryFormat::MASK_ATTRIBUTE_FREQUENCY & bigramFlags; // Due to space constraints, the frequency for bigrams is approximate - the lower the // unigram frequency, the worse the precision. The theoritical maximum error in // resulting frequency is 8 - although in the practice it's never bigger than 3 or 4 @@ -140,7 +139,7 @@ int BigramDictionary::getBigrams(const int32_t *prevWord, int prevWordLength, in ++bigramCount; } } - } while (UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags); + } while (BinaryFormat::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags); return bigramCount; } @@ -149,14 +148,14 @@ int BigramDictionary::getBigrams(const int32_t *prevWord, int prevWordLength, in int BigramDictionary::getBigramListPositionForWord(const int32_t *prevWord, const int prevWordLength, const bool forceLowerCaseSearch) const { if (0 >= prevWordLength) return 0; - const uint8_t* const root = DICT; + const uint8_t *const root = DICT; int pos = BinaryFormat::getTerminalPosition(root, prevWord, prevWordLength, forceLowerCaseSearch); if (NOT_VALID_WORD == pos) return 0; const int flags = BinaryFormat::getFlagsAndForwardPointer(root, &pos); - if (0 == (flags & UnigramDictionary::FLAG_HAS_BIGRAMS)) return 0; - if (0 == (flags & UnigramDictionary::FLAG_HAS_MULTIPLE_CHARS)) { + if (0 == (flags & BinaryFormat::FLAG_HAS_BIGRAMS)) return 0; + if (0 == (flags & BinaryFormat::FLAG_HAS_MULTIPLE_CHARS)) { BinaryFormat::getCharCodeAndForwardPointer(root, &pos); } else { pos = BinaryFormat::skipOtherCharacters(root, pos); @@ -170,7 +169,7 @@ int BigramDictionary::getBigramListPositionForWord(const int32_t *prevWord, void BigramDictionary::fillBigramAddressToFrequencyMapAndFilter(const int32_t *prevWord, const int prevWordLength, std::map<int, int> *map, uint8_t *filter) const { memset(filter, 0, BIGRAM_FILTER_BYTE_SIZE); - const uint8_t* const root = DICT; + const uint8_t *const root = DICT; int pos = getBigramListPositionForWord(prevWord, prevWordLength, false /* forceLowerCaseSearch */); if (0 == pos) { @@ -183,12 +182,12 @@ void BigramDictionary::fillBigramAddressToFrequencyMapAndFilter(const int32_t *p int bigramFlags; do { bigramFlags = BinaryFormat::getFlagsAndForwardPointer(root, &pos); - const int frequency = UnigramDictionary::MASK_ATTRIBUTE_FREQUENCY & bigramFlags; + const int frequency = BinaryFormat::MASK_ATTRIBUTE_FREQUENCY & bigramFlags; const int bigramPos = BinaryFormat::getAttributeAddressAndForwardPointer(root, bigramFlags, &pos); (*map)[bigramPos] = frequency; setInFilter(filter, bigramPos); - } while (0 != (UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags)); + } while (0 != (BinaryFormat::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags)); } bool BigramDictionary::checkFirstCharacter(unsigned short *word, int *inputCodes) const { @@ -209,7 +208,7 @@ bool BigramDictionary::checkFirstCharacter(unsigned short *word, int *inputCodes bool BigramDictionary::isValidBigram(const int32_t *word1, int length1, const int32_t *word2, int length2) const { - const uint8_t* const root = DICT; + const uint8_t *const root = DICT; int pos = getBigramListPositionForWord(word1, length1, false /* forceLowerCaseSearch */); // getBigramListPositionForWord returns 0 if this word isn't in the dictionary or has no bigrams if (0 == pos) return false; @@ -224,7 +223,7 @@ bool BigramDictionary::isValidBigram(const int32_t *word1, int length1, const in if (bigramPos == nextWordPos) { return true; } - } while (UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags); + } while (BinaryFormat::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags); return false; } diff --git a/native/jni/src/bigram_dictionary.h b/native/jni/src/bigram_dictionary.h index 0b3577ad8..d676cca63 100644 --- a/native/jni/src/bigram_dictionary.h +++ b/native/jni/src/bigram_dictionary.h @@ -24,7 +24,6 @@ namespace latinime { -class Dictionary; class BigramDictionary { public: BigramDictionary(const unsigned char *dict, int maxWordLength, int maxPredictions); @@ -53,7 +52,5 @@ class BigramDictionary { // TODO: Re-implement proximity correction for bigram correction static const int MAX_ALTERNATIVES = 1; }; - } // namespace latinime - #endif // LATINIME_BIGRAM_DICTIONARY_H diff --git a/native/jni/src/binary_format.h b/native/jni/src/binary_format.h index 474c854fe..2ee4077c1 100644 --- a/native/jni/src/binary_format.h +++ b/native/jni/src/binary_format.h @@ -18,13 +18,47 @@ #define LATINIME_BINARY_FORMAT_H #include <limits> +#include <map> #include "bloom_filter.h" #include "char_utils.h" -#include "unigram_dictionary.h" namespace latinime { class BinaryFormat { + public: + // Mask and flags for children address type selection. + static const int MASK_GROUP_ADDRESS_TYPE = 0xC0; + static const int FLAG_GROUP_ADDRESS_TYPE_NOADDRESS = 0x00; + static const int FLAG_GROUP_ADDRESS_TYPE_ONEBYTE = 0x40; + static const int FLAG_GROUP_ADDRESS_TYPE_TWOBYTES = 0x80; + static const int FLAG_GROUP_ADDRESS_TYPE_THREEBYTES = 0xC0; + + // Flag for single/multiple char group + static const int FLAG_HAS_MULTIPLE_CHARS = 0x20; + + // Flag for terminal groups + static const int FLAG_IS_TERMINAL = 0x10; + + // Flag for shortcut targets presence + static const int FLAG_HAS_SHORTCUT_TARGETS = 0x08; + // Flag for bigram presence + static const int FLAG_HAS_BIGRAMS = 0x04; + + // Attribute (bigram/shortcut) related flags: + // Flag for presence of more attributes + static const int FLAG_ATTRIBUTE_HAS_NEXT = 0x80; + // Flag for sign of offset. If this flag is set, the offset value must be negated. + static const int FLAG_ATTRIBUTE_OFFSET_NEGATIVE = 0x40; + + // Mask for attribute frequency, stored on 4 bits inside the flags byte. + static const int MASK_ATTRIBUTE_FREQUENCY = 0x0F; + + // Mask and flags for attribute address type selection. + static const int MASK_ATTRIBUTE_ADDRESS_TYPE = 0x30; + static const int FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE = 0x10; + static const int FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES = 0x20; + static const int FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES = 0x30; + private: DISALLOW_IMPLICIT_CONSTRUCTORS(BinaryFormat); const static int32_t MINIMAL_ONE_BYTE_CHARACTER_VALUE = 0x20; @@ -46,29 +80,29 @@ class BinaryFormat { const static int CHARACTER_ARRAY_TERMINATOR_SIZE = 1; const static int SHORTCUT_LIST_SIZE_SIZE = 2; - static int detectFormat(const uint8_t* const dict); - static unsigned int getHeaderSize(const uint8_t* const dict); - static unsigned int getFlags(const uint8_t* const dict); - static int getGroupCountAndForwardPointer(const uint8_t* const dict, int* pos); - static uint8_t getFlagsAndForwardPointer(const uint8_t* const dict, int* pos); - static int32_t getCharCodeAndForwardPointer(const uint8_t* const dict, int* pos); - static int readFrequencyWithoutMovingPointer(const uint8_t* const dict, const int pos); - static int skipOtherCharacters(const uint8_t* const dict, const int pos); + static int detectFormat(const uint8_t *const dict); + static unsigned int getHeaderSize(const uint8_t *const dict); + static unsigned int getFlags(const uint8_t *const dict); + static int getGroupCountAndForwardPointer(const uint8_t *const dict, int *pos); + static uint8_t getFlagsAndForwardPointer(const uint8_t *const dict, int *pos); + static int32_t getCharCodeAndForwardPointer(const uint8_t *const dict, int *pos); + static int readFrequencyWithoutMovingPointer(const uint8_t *const dict, const int pos); + static int skipOtherCharacters(const uint8_t *const dict, const int pos); static int skipChildrenPosition(const uint8_t flags, const int pos); static int skipFrequency(const uint8_t flags, const int pos); - static int skipShortcuts(const uint8_t* const dict, const uint8_t flags, const int pos); - static int skipBigrams(const uint8_t* const dict, const uint8_t flags, const int pos); - static int skipAllAttributes(const uint8_t* const dict, const uint8_t flags, const int pos); - static int skipChildrenPosAndAttributes(const uint8_t* const dict, const uint8_t flags, + static int skipShortcuts(const uint8_t *const dict, const uint8_t flags, const int pos); + static int skipBigrams(const uint8_t *const dict, const uint8_t flags, const int pos); + static int skipAllAttributes(const uint8_t *const dict, const uint8_t flags, const int pos); + static int skipChildrenPosAndAttributes(const uint8_t *const dict, const uint8_t flags, const int pos); - static int readChildrenPosition(const uint8_t* const dict, const uint8_t flags, const int pos); + static int readChildrenPosition(const uint8_t *const dict, const uint8_t flags, const int pos); static bool hasChildrenInFlags(const uint8_t flags); - static int getAttributeAddressAndForwardPointer(const uint8_t* const dict, const uint8_t flags, + static int getAttributeAddressAndForwardPointer(const uint8_t *const dict, const uint8_t flags, int *pos); - static int getTerminalPosition(const uint8_t* const root, const int32_t* const inWord, + static int getTerminalPosition(const uint8_t *const root, const int32_t *const inWord, const int length, const bool forceLowerCaseSearch); - static int getWordAtAddress(const uint8_t* const root, const int address, const int maxDepth, - uint16_t* outWord, int* outUnigramFrequency); + static int getWordAtAddress(const uint8_t *const root, const int address, const int maxDepth, + uint16_t *outWord, int *outUnigramFrequency); static int computeFrequencyForBigram(const int unigramFreq, const int bigramFreq); static int getProbability(const int position, const std::map<int, int> *bigramMap, const uint8_t *bigramFilter, const int unigramFreq); @@ -83,7 +117,7 @@ class BinaryFormat { const static unsigned int NO_FLAGS = 0; }; -inline int BinaryFormat::detectFormat(const uint8_t* const dict) { +inline int BinaryFormat::detectFormat(const uint8_t *const dict) { // The magic number is stored big-endian. const uint32_t magicNumber = (dict[0] << 24) + (dict[1] << 16) + (dict[2] << 8) + dict[3]; switch (magicNumber) { @@ -105,7 +139,7 @@ inline int BinaryFormat::detectFormat(const uint8_t* const dict) { } } -inline unsigned int BinaryFormat::getFlags(const uint8_t* const dict) { +inline unsigned int BinaryFormat::getFlags(const uint8_t *const dict) { switch (detectFormat(dict)) { case 1: return NO_FLAGS; @@ -114,7 +148,7 @@ inline unsigned int BinaryFormat::getFlags(const uint8_t* const dict) { } } -inline unsigned int BinaryFormat::getHeaderSize(const uint8_t* const dict) { +inline unsigned int BinaryFormat::getHeaderSize(const uint8_t *const dict) { switch (detectFormat(dict)) { case 1: return FORMAT_VERSION_1_HEADER_SIZE; @@ -126,17 +160,17 @@ inline unsigned int BinaryFormat::getHeaderSize(const uint8_t* const dict) { } } -inline int BinaryFormat::getGroupCountAndForwardPointer(const uint8_t* const dict, int* pos) { +inline int BinaryFormat::getGroupCountAndForwardPointer(const uint8_t *const dict, int *pos) { const int msb = dict[(*pos)++]; if (msb < 0x80) return msb; return ((msb & 0x7F) << 8) | dict[(*pos)++]; } -inline uint8_t BinaryFormat::getFlagsAndForwardPointer(const uint8_t* const dict, int* pos) { +inline uint8_t BinaryFormat::getFlagsAndForwardPointer(const uint8_t *const dict, int *pos) { return dict[(*pos)++]; } -inline int32_t BinaryFormat::getCharCodeAndForwardPointer(const uint8_t* const dict, int* pos) { +inline int32_t BinaryFormat::getCharCodeAndForwardPointer(const uint8_t *const dict, int *pos) { const int origin = *pos; const int32_t character = dict[origin]; if (character < MINIMAL_ONE_BYTE_CHARACTER_VALUE) { @@ -155,12 +189,12 @@ inline int32_t BinaryFormat::getCharCodeAndForwardPointer(const uint8_t* const d } } -inline int BinaryFormat::readFrequencyWithoutMovingPointer(const uint8_t* const dict, +inline int BinaryFormat::readFrequencyWithoutMovingPointer(const uint8_t *const dict, const int pos) { return dict[pos]; } -inline int BinaryFormat::skipOtherCharacters(const uint8_t* const dict, const int pos) { +inline int BinaryFormat::skipOtherCharacters(const uint8_t *const dict, const int pos) { int currentPos = pos; int32_t character = dict[currentPos++]; while (CHARACTER_ARRAY_TERMINATOR != character) { @@ -174,22 +208,22 @@ inline int BinaryFormat::skipOtherCharacters(const uint8_t* const dict, const in static inline int attributeAddressSize(const uint8_t flags) { static const int ATTRIBUTE_ADDRESS_SHIFT = 4; - return (flags & UnigramDictionary::MASK_ATTRIBUTE_ADDRESS_TYPE) >> ATTRIBUTE_ADDRESS_SHIFT; + return (flags & BinaryFormat::MASK_ATTRIBUTE_ADDRESS_TYPE) >> ATTRIBUTE_ADDRESS_SHIFT; /* Note: this is a value-dependant optimization of what may probably be more readably written this way: - switch (flags * UnigramDictionary::MASK_ATTRIBUTE_ADDRESS_TYPE) { - case UnigramDictionary::FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE: return 1; - case UnigramDictionary::FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES: return 2; - case UnigramDictionary::FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTE: return 3; + switch (flags * BinaryFormat::MASK_ATTRIBUTE_ADDRESS_TYPE) { + case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE: return 1; + case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES: return 2; + case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTE: return 3; default: return 0; } */ } -static inline int skipExistingBigrams(const uint8_t* const dict, const int pos) { +static inline int skipExistingBigrams(const uint8_t *const dict, const int pos) { int currentPos = pos; uint8_t flags = BinaryFormat::getFlagsAndForwardPointer(dict, ¤tPos); - while (flags & UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT) { + while (flags & BinaryFormat::FLAG_ATTRIBUTE_HAS_NEXT) { currentPos += attributeAddressSize(flags); flags = BinaryFormat::getFlagsAndForwardPointer(dict, ¤tPos); } @@ -199,11 +233,11 @@ static inline int skipExistingBigrams(const uint8_t* const dict, const int pos) static inline int childrenAddressSize(const uint8_t flags) { static const int CHILDREN_ADDRESS_SHIFT = 6; - return (UnigramDictionary::MASK_GROUP_ADDRESS_TYPE & flags) >> CHILDREN_ADDRESS_SHIFT; + return (BinaryFormat::MASK_GROUP_ADDRESS_TYPE & flags) >> CHILDREN_ADDRESS_SHIFT; /* See the note in attributeAddressSize. The same applies here */ } -static inline int shortcutByteSize(const uint8_t* const dict, const int pos) { +static inline int shortcutByteSize(const uint8_t *const dict, const int pos) { return ((int)(dict[pos] << 8)) + (dict[pos + 1]); } @@ -212,28 +246,28 @@ inline int BinaryFormat::skipChildrenPosition(const uint8_t flags, const int pos } inline int BinaryFormat::skipFrequency(const uint8_t flags, const int pos) { - return UnigramDictionary::FLAG_IS_TERMINAL & flags ? pos + 1 : pos; + return FLAG_IS_TERMINAL & flags ? pos + 1 : pos; } -inline int BinaryFormat::skipShortcuts(const uint8_t* const dict, const uint8_t flags, +inline int BinaryFormat::skipShortcuts(const uint8_t *const dict, const uint8_t flags, const int pos) { - if (UnigramDictionary::FLAG_HAS_SHORTCUT_TARGETS & flags) { + if (FLAG_HAS_SHORTCUT_TARGETS & flags) { return pos + shortcutByteSize(dict, pos); } else { return pos; } } -inline int BinaryFormat::skipBigrams(const uint8_t* const dict, const uint8_t flags, +inline int BinaryFormat::skipBigrams(const uint8_t *const dict, const uint8_t flags, const int pos) { - if (UnigramDictionary::FLAG_HAS_BIGRAMS & flags) { + if (FLAG_HAS_BIGRAMS & flags) { return skipExistingBigrams(dict, pos); } else { return pos; } } -inline int BinaryFormat::skipAllAttributes(const uint8_t* const dict, const uint8_t flags, +inline int BinaryFormat::skipAllAttributes(const uint8_t *const dict, const uint8_t flags, const int pos) { // This function skips all attributes: shortcuts and bigrams. int newPos = pos; @@ -242,7 +276,7 @@ inline int BinaryFormat::skipAllAttributes(const uint8_t* const dict, const uint return newPos; } -inline int BinaryFormat::skipChildrenPosAndAttributes(const uint8_t* const dict, +inline int BinaryFormat::skipChildrenPosAndAttributes(const uint8_t *const dict, const uint8_t flags, const int pos) { int currentPos = pos; currentPos = skipChildrenPosition(flags, currentPos); @@ -250,18 +284,18 @@ inline int BinaryFormat::skipChildrenPosAndAttributes(const uint8_t* const dict, return currentPos; } -inline int BinaryFormat::readChildrenPosition(const uint8_t* const dict, const uint8_t flags, +inline int BinaryFormat::readChildrenPosition(const uint8_t *const dict, const uint8_t flags, const int pos) { int offset = 0; - switch (UnigramDictionary::MASK_GROUP_ADDRESS_TYPE & flags) { - case UnigramDictionary::FLAG_GROUP_ADDRESS_TYPE_ONEBYTE: + switch (MASK_GROUP_ADDRESS_TYPE & flags) { + case FLAG_GROUP_ADDRESS_TYPE_ONEBYTE: offset = dict[pos]; break; - case UnigramDictionary::FLAG_GROUP_ADDRESS_TYPE_TWOBYTES: + case FLAG_GROUP_ADDRESS_TYPE_TWOBYTES: offset = dict[pos] << 8; offset += dict[pos + 1]; break; - case UnigramDictionary::FLAG_GROUP_ADDRESS_TYPE_THREEBYTES: + case FLAG_GROUP_ADDRESS_TYPE_THREEBYTES: offset = dict[pos] << 16; offset += dict[pos + 1] << 8; offset += dict[pos + 2]; @@ -275,32 +309,31 @@ inline int BinaryFormat::readChildrenPosition(const uint8_t* const dict, const u } inline bool BinaryFormat::hasChildrenInFlags(const uint8_t flags) { - return (UnigramDictionary::FLAG_GROUP_ADDRESS_TYPE_NOADDRESS - != (UnigramDictionary::MASK_GROUP_ADDRESS_TYPE & flags)); + return (FLAG_GROUP_ADDRESS_TYPE_NOADDRESS != (MASK_GROUP_ADDRESS_TYPE & flags)); } -inline int BinaryFormat::getAttributeAddressAndForwardPointer(const uint8_t* const dict, +inline int BinaryFormat::getAttributeAddressAndForwardPointer(const uint8_t *const dict, const uint8_t flags, int *pos) { int offset = 0; const int origin = *pos; - switch (UnigramDictionary::MASK_ATTRIBUTE_ADDRESS_TYPE & flags) { - case UnigramDictionary::FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE: + switch (MASK_ATTRIBUTE_ADDRESS_TYPE & flags) { + case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE: offset = dict[origin]; *pos = origin + 1; break; - case UnigramDictionary::FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES: + case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES: offset = dict[origin] << 8; offset += dict[origin + 1]; *pos = origin + 2; break; - case UnigramDictionary::FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES: + case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES: offset = dict[origin] << 16; offset += dict[origin + 1] << 8; offset += dict[origin + 2]; *pos = origin + 3; break; } - if (UnigramDictionary::FLAG_ATTRIBUTE_OFFSET_NEGATIVE & flags) { + if (FLAG_ATTRIBUTE_OFFSET_NEGATIVE & flags) { return origin - offset; } else { return origin + offset; @@ -309,8 +342,8 @@ inline int BinaryFormat::getAttributeAddressAndForwardPointer(const uint8_t* con // This function gets the byte position of the last chargroup of the exact matching word in the // dictionary. If no match is found, it returns NOT_VALID_WORD. -inline int BinaryFormat::getTerminalPosition(const uint8_t* const root, - const int32_t* const inWord, const int length, const bool forceLowerCaseSearch) { +inline int BinaryFormat::getTerminalPosition(const uint8_t *const root, + const int32_t *const inWord, const int length, const bool forceLowerCaseSearch) { int pos = 0; int wordPos = 0; @@ -332,7 +365,7 @@ inline int BinaryFormat::getTerminalPosition(const uint8_t* const root, // char within a node, so either we found our match in this node, or there is // no match and we can return NOT_VALID_WORD. So we will check all the characters // in this character group indeed does match. - if (UnigramDictionary::FLAG_HAS_MULTIPLE_CHARS & flags) { + if (FLAG_HAS_MULTIPLE_CHARS & flags) { character = BinaryFormat::getCharCodeAndForwardPointer(root, &pos); while (NOT_A_CHARACTER != character) { ++wordPos; @@ -350,14 +383,13 @@ inline int BinaryFormat::getTerminalPosition(const uint8_t* const root, // If we don't match the length AND don't have children, then a word in the // dictionary fully matches a prefix of the searched word but not the full word. ++wordPos; - if (UnigramDictionary::FLAG_IS_TERMINAL & flags) { + if (FLAG_IS_TERMINAL & flags) { if (wordPos == length) { return charGroupPos; } - pos = BinaryFormat::skipFrequency(UnigramDictionary::FLAG_IS_TERMINAL, pos); + pos = BinaryFormat::skipFrequency(FLAG_IS_TERMINAL, pos); } - if (UnigramDictionary::FLAG_GROUP_ADDRESS_TYPE_NOADDRESS - == (UnigramDictionary::MASK_GROUP_ADDRESS_TYPE & flags)) { + if (FLAG_GROUP_ADDRESS_TYPE_NOADDRESS == (MASK_GROUP_ADDRESS_TYPE & flags)) { return NOT_VALID_WORD; } // We have children and we are still shorter than the word we are searching for, so @@ -367,7 +399,7 @@ inline int BinaryFormat::getTerminalPosition(const uint8_t* const root, break; } else { // This chargroup does not match, so skip the remaining part and go to the next. - if (UnigramDictionary::FLAG_HAS_MULTIPLE_CHARS & flags) { + if (FLAG_HAS_MULTIPLE_CHARS & flags) { pos = BinaryFormat::skipOtherCharacters(root, pos); } pos = BinaryFormat::skipFrequency(flags, pos); @@ -396,8 +428,8 @@ inline int BinaryFormat::getTerminalPosition(const uint8_t* const root, * outUnigramFrequency: a pointer to an int to write the frequency into. * Return value : the length of the word, of 0 if the word was not found. */ -inline int BinaryFormat::getWordAtAddress(const uint8_t* const root, const int address, - const int maxDepth, uint16_t* outWord, int* outUnigramFrequency) { +inline int BinaryFormat::getWordAtAddress(const uint8_t *const root, const int address, + const int maxDepth, uint16_t *outWord, int *outUnigramFrequency) { int pos = 0; int wordPos = 0; @@ -420,7 +452,7 @@ inline int BinaryFormat::getWordAtAddress(const uint8_t* const root, const int a // We found the address. Copy the rest of the word in the buffer and return // the length. outWord[wordPos] = character; - if (UnigramDictionary::FLAG_HAS_MULTIPLE_CHARS & flags) { + if (FLAG_HAS_MULTIPLE_CHARS & flags) { int32_t nextChar = getCharCodeAndForwardPointer(root, &pos); // We count chars in order to avoid infinite loops if the file is broken or // if there is some other bug @@ -435,7 +467,7 @@ inline int BinaryFormat::getWordAtAddress(const uint8_t* const root, const int a } // We need to skip past this char group, so skip any remaining chars after the // first and possibly the frequency. - if (UnigramDictionary::FLAG_HAS_MULTIPLE_CHARS & flags) { + if (FLAG_HAS_MULTIPLE_CHARS & flags) { pos = skipOtherCharacters(root, pos); } pos = skipFrequency(flags, pos); @@ -443,8 +475,8 @@ inline int BinaryFormat::getWordAtAddress(const uint8_t* const root, const int a // The fact that this group has children is very important. Since we already know // that this group does not match, if it has no children we know it is irrelevant // to what we are searching for. - const bool hasChildren = (UnigramDictionary::FLAG_GROUP_ADDRESS_TYPE_NOADDRESS != - (UnigramDictionary::MASK_GROUP_ADDRESS_TYPE & flags)); + const bool hasChildren = (FLAG_GROUP_ADDRESS_TYPE_NOADDRESS != + (MASK_GROUP_ADDRESS_TYPE & flags)); // We will write in `found' whether we have passed the children address we are // searching for. For example if we search for "beer", the children of b are less // than the address we are searching for and the children of c are greater. When we @@ -484,7 +516,7 @@ inline int BinaryFormat::getWordAtAddress(const uint8_t* const root, const int a getCharCodeAndForwardPointer(root, &lastCandidateGroupPos); // We copy all the characters in this group to the buffer outWord[wordPos] = lastChar; - if (UnigramDictionary::FLAG_HAS_MULTIPLE_CHARS & lastFlags) { + if (FLAG_HAS_MULTIPLE_CHARS & lastFlags) { int32_t nextChar = getCharCodeAndForwardPointer(root, &lastCandidateGroupPos); int charCount = maxDepth; @@ -540,8 +572,8 @@ inline int BinaryFormat::computeFrequencyForBigram(const int unigramFreq, const // 0 for the bigram frequency represents the middle of the 16th step from the top, // while a value of 15 represents the middle of the top step. // See makedict.BinaryDictInputOutput for details. - const float stepSize = ((float)MAX_FREQ - unigramFreq) / (1.5f + MAX_BIGRAM_FREQ); - return (int)(unigramFreq + (bigramFreq + 1) * stepSize); + const float stepSize = (static_cast<float>(MAX_FREQ) - unigramFreq) / (1.5f + MAX_BIGRAM_FREQ); + return static_cast<int>(unigramFreq + (bigramFreq + 1) * stepSize); } // This returns a probability in log space. @@ -557,7 +589,5 @@ inline int BinaryFormat::getProbability(const int position, const std::map<int, return backoff(unigramFreq); } } - } // namespace latinime - #endif // LATINIME_BINARY_FORMAT_H diff --git a/native/jni/src/bloom_filter.h b/native/jni/src/bloom_filter.h index 7ae6a1fa4..47177dcba 100644 --- a/native/jni/src/bloom_filter.h +++ b/native/jni/src/bloom_filter.h @@ -32,7 +32,5 @@ static inline bool isInFilter(const uint8_t *filter, const int position) { const unsigned int bucket = position % BIGRAM_FILTER_MODULO; return filter[bucket >> 3] & (1 << (bucket & 0x7)); } - } // namespace latinime - #endif // LATINIME_BLOOM_FILTER_H diff --git a/native/jni/src/char_utils.cpp b/native/jni/src/char_utils.cpp index a31a0632c..45d49b087 100644 --- a/native/jni/src/char_utils.cpp +++ b/native/jni/src/char_utils.cpp @@ -14,7 +14,9 @@ * limitations under the License. */ -#include <stdlib.h> +#include <cstdlib> + +#include "char_utils.h" namespace latinime { @@ -895,5 +897,4 @@ unsigned short latin_tolower(unsigned short c) { compare_pair_capital); return p ? p->small : c; } - } // namespace latinime diff --git a/native/jni/src/char_utils.h b/native/jni/src/char_utils.h index 21dca9a0a..edd96bbb0 100644 --- a/native/jni/src/char_utils.h +++ b/native/jni/src/char_utils.h @@ -62,7 +62,5 @@ inline static unsigned short toLowerCase(const unsigned short c) { inline static unsigned short toBaseLowerCase(const unsigned short c) { return toLowerCase(toBaseChar(c)); } - } // namespace latinime - #endif // LATINIME_CHAR_UTILS_H diff --git a/native/jni/src/correction.cpp b/native/jni/src/correction.cpp index 827067b9f..ea4bddae2 100644 --- a/native/jni/src/correction.cpp +++ b/native/jni/src/correction.cpp @@ -14,23 +14,22 @@ * limitations under the License. */ -#include <assert.h> -#include <ctype.h> -#include <math.h> -#include <stdio.h> -#include <string.h> +#include <cassert> +#include <cctype> +#include <cmath> +#include <cstring> #define LOG_TAG "LatinIME: correction.cpp" #include "char_utils.h" #include "correction.h" #include "defines.h" -#include "dictionary.h" -#include "proximity_info.h" #include "proximity_info_state.h" namespace latinime { +class ProximityInfo; + ///////////////////////////// // edit distance funcitons // ///////////////////////////// @@ -95,11 +94,11 @@ inline static int getCurrentEditDistance(int *editDistanceTable, const int editD ////////////////////// // inline functions // ////////////////////// -static const char QUOTE = '\''; +static const char SINGLE_QUOTE = '\''; -inline bool Correction::isQuote(const unsigned short c) { +inline bool Correction::isSingleQuote(const unsigned short c) { const unsigned short userTypedChar = mProximityInfoState.getPrimaryCharAt(mInputIndex); - return (c == QUOTE && userTypedChar != QUOTE); + return (c == SINGLE_QUOTE && userTypedChar != SINGLE_QUOTE); } //////////////// @@ -326,7 +325,7 @@ Correction::CorrectionType Correction::processCharAndCalcState( mDistances[mOutputIndex] = NOT_A_DISTANCE; // Skip checking this node - if (mNeedsToTraverseAllNodes || isQuote(c)) { + if (mNeedsToTraverseAllNodes || isSingleQuote(c)) { bool incremented = false; if (mLastCharExceeded && mInputIndex == mInputLength - 1) { // TODO: Do not check the proximity if EditDistance exceeds the threshold @@ -344,7 +343,7 @@ Correction::CorrectionType Correction::processCharAndCalcState( mDistances[mOutputIndex] = mProximityInfoState.getNormalizedSquaredDistance( mInputIndex, proximityIndex); } - if (!isQuote(c)) { + if (!isSingleQuote(c)) { incrementInputIndex(); incremented = true; } @@ -633,7 +632,7 @@ Correction::CorrectionType Correction::processCharAndCalcState( Correction::~Correction() { } -inline static int getQuoteCount(const unsigned short* word, const int length) { +inline static int getQuoteCount(const unsigned short *word, const int length) { int quoteCount = 0; for (int i = 0; i < length; ++i) { if(word[i] == '\'') { @@ -653,7 +652,7 @@ inline static bool isUpperCase(unsigned short c) { /* static */ int Correction::RankingAlgorithm::calculateFinalProbability(const int inputIndex, - const int outputIndex, const int freq, int* editDistanceTable, const Correction* correction, + const int outputIndex, const int freq, int *editDistanceTable, const Correction *correction, const int inputLength) { const int excessivePos = correction->getExcessivePos(); const int typedLetterMultiplier = correction->TYPED_LETTER_MULTIPLIER; @@ -677,7 +676,7 @@ int Correction::RankingAlgorithm::calculateFinalProbability(const int inputIndex // TODO: use mExcessiveCount const int matchCount = inputLength - correction->mProximityCount - excessiveCount; - const unsigned short* word = correction->mWord; + const unsigned short *word = correction->mWord; const bool skipped = skippedCount > 0; const int quoteDiffCount = max(0, getQuoteCount(word, outputLength) @@ -791,7 +790,7 @@ int Correction::RankingAlgorithm::calculateFinalProbability(const int inputIndex static const float MIN = 0.3f; static const float R1 = NEUTRAL_SCORE_SQUARED_RADIUS; static const float R2 = HALF_SCORE_SQUARED_RADIUS; - const float x = (float)squaredDistance + const float x = static_cast<float>(squaredDistance) / ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR; const float factor = max((x < R1) ? (A * (R1 - x) + B * x) / R1 @@ -916,7 +915,7 @@ int Correction::RankingAlgorithm::calculateFinalProbability(const int inputIndex /* static */ int Correction::RankingAlgorithm::calcFreqForSplitMultipleWords( const int *freqArray, const int *wordLengthArray, const int wordCount, - const Correction* correction, const bool isSpaceProximity, const unsigned short *word) { + const Correction *correction, const bool isSpaceProximity, const unsigned short *word) { const int typedLetterMultiplier = correction->TYPED_LETTER_MULTIPLIER; bool firstCapitalizedWordDemotion = false; @@ -1046,10 +1045,10 @@ int Correction::RankingAlgorithm::calcFreqForSplitMultipleWords( /* Damerau-Levenshtein distance */ inline static int editDistanceInternal( - int* editDistanceTable, const unsigned short* before, - const int beforeLength, const unsigned short* after, const int afterLength) { + int *editDistanceTable, const unsigned short *before, + const int beforeLength, const unsigned short *after, const int afterLength) { // dp[li][lo] dp[a][b] = dp[ a * lo + b] - int* dp = editDistanceTable; + int *dp = editDistanceTable; const int li = beforeLength + 1; const int lo = afterLength + 1; for (int i = 0; i < li; ++i) { @@ -1085,8 +1084,8 @@ inline static int editDistanceInternal( return dp[li * lo - 1]; } -int Correction::RankingAlgorithm::editDistance(const unsigned short* before, - const int beforeLength, const unsigned short* after, const int afterLength) { +int Correction::RankingAlgorithm::editDistance(const unsigned short *before, + const int beforeLength, const unsigned short *after, const int afterLength) { int table[(beforeLength + 1) * (afterLength + 1)]; return editDistanceInternal(table, before, beforeLength, after, afterLength); } @@ -1114,8 +1113,8 @@ int Correction::RankingAlgorithm::editDistance(const unsigned short* before, // So, we can normalize original score by dividing pow(2, min(b.l(),a.l())) * 255 * 2. /* static */ -float Correction::RankingAlgorithm::calcNormalizedScore(const unsigned short* before, - const int beforeLength, const unsigned short* after, const int afterLength, +float Correction::RankingAlgorithm::calcNormalizedScore(const unsigned short *before, + const int beforeLength, const unsigned short *after, const int afterLength, const int score) { if (0 == beforeLength || 0 == afterLength) { return 0; @@ -1133,13 +1132,14 @@ float Correction::RankingAlgorithm::calcNormalizedScore(const unsigned short* be } const float maxScore = score >= S_INT_MAX ? S_INT_MAX : MAX_INITIAL_SCORE - * pow((float)TYPED_LETTER_MULTIPLIER, - (float)min(beforeLength, afterLength - spaceCount)) * FULL_WORD_MULTIPLIER; + * pow(static_cast<float>(TYPED_LETTER_MULTIPLIER), + static_cast<float>(min(beforeLength, afterLength - spaceCount))) + * FULL_WORD_MULTIPLIER; // add a weight based on edit distance. // distance <= max(afterLength, beforeLength) == afterLength, // so, 0 <= distance / afterLength <= 1 - const float weight = 1.0 - (float) distance / afterLength; + const float weight = 1.0f - static_cast<float>(distance) / static_cast<float>(afterLength); return (score / maxScore) * weight; } } // namespace latinime diff --git a/native/jni/src/correction.h b/native/jni/src/correction.h index ae7b3a5f8..81623a46b 100644 --- a/native/jni/src/correction.h +++ b/native/jni/src/correction.h @@ -17,7 +17,7 @@ #ifndef LATINIME_CORRECTION_H #define LATINIME_CORRECTION_H -#include <assert.h> +#include <cassert> #include <stdint.h> #include "correction_state.h" @@ -138,9 +138,9 @@ class Correction { int getFreqForSplitMultipleWords( const int *freqArray, const int *wordLengthArray, const int wordCount, const bool isSpaceProximity, const unsigned short *word); - int getFinalProbability(const int probability, unsigned short **word, int* wordLength); + int getFinalProbability(const int probability, unsigned short **word, int *wordLength); int getFinalProbabilityForSubQueue(const int probability, unsigned short **word, - int* wordLength, const int inputLength); + int *wordLength, const int inputLength); CorrectionType processCharAndCalcState(const int32_t c, const bool isTerminal); @@ -163,15 +163,15 @@ class Correction { class RankingAlgorithm { public: static int calculateFinalProbability(const int inputIndex, const int depth, - const int probability, int *editDistanceTable, const Correction* correction, + const int probability, int *editDistanceTable, const Correction *correction, const int inputLength); static int calcFreqForSplitMultipleWords(const int *freqArray, const int *wordLengthArray, - const int wordCount, const Correction* correction, const bool isSpaceProximity, + const int wordCount, const Correction *correction, const bool isSpaceProximity, const unsigned short *word); - static float calcNormalizedScore(const unsigned short* before, const int beforeLength, - const unsigned short* after, const int afterLength, const int score); - static int editDistance(const unsigned short* before, - const int beforeLength, const unsigned short* after, const int afterLength); + static float calcNormalizedScore(const unsigned short *before, const int beforeLength, + const unsigned short *after, const int afterLength, const int score); + static int editDistance(const unsigned short *before, + const int beforeLength, const unsigned short *after, const int afterLength); private: static const int CODE_SPACE = ' '; static const int MAX_INITIAL_SCORE = 255; @@ -184,7 +184,7 @@ class Correction { proximityInfo, inputCodes, inputLength, xCoordinates, yCoordinates); } - const unsigned short* getPrimaryInputWord() const { + const unsigned short *getPrimaryInputWord() const { return mProximityInfoState.getPrimaryInputWord(); } @@ -197,13 +197,13 @@ class Correction { inline void incrementInputIndex(); inline void incrementOutputIndex(); inline void startToTraverseAllNodes(); - inline bool isQuote(const unsigned short c); + inline bool isSingleQuote(const unsigned short c); inline CorrectionType processSkipChar( const int32_t c, const bool isTerminal, const bool inputIndexIncremented); inline CorrectionType processUnrelatedCorrectionType(); inline void addCharToCurrentWord(const int32_t c); inline int getFinalProbabilityInternal(const int probability, unsigned short **word, - int* wordLength, const int inputLength); + int *wordLength, const int inputLength); static const int TYPED_LETTER_MULTIPLIER = 2; static const int FULL_WORD_MULTIPLIER = 2; diff --git a/native/jni/src/correction_state.h b/native/jni/src/correction_state.h index 5b2cbd3a2..a63d4aa94 100644 --- a/native/jni/src/correction_state.h +++ b/native/jni/src/correction_state.h @@ -79,6 +79,5 @@ inline static void initCorrectionState(CorrectionState *state, const int rootPos state->mSkipping = false; state->mAdditionalProximityMatching = false; } - } // namespace latinime #endif // LATINIME_CORRECTION_STATE_H diff --git a/native/jni/src/debug.h b/native/jni/src/debug.h index 376ba59d9..2168d6672 100644 --- a/native/jni/src/debug.h +++ b/native/jni/src/debug.h @@ -1,26 +1,25 @@ /* -** -** Copyright 2011, 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. -*/ + * Copyright (C) 2011, 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_DEBUG_H #define LATINIME_DEBUG_H #include "defines.h" -static inline unsigned char* convertToUnibyteString(unsigned short* input, unsigned char* output, +static inline unsigned char *convertToUnibyteString(unsigned short *input, unsigned char *output, const unsigned int length) { unsigned int i = 0; for (; i <= length && input[i] != 0; ++i) @@ -29,8 +28,8 @@ static inline unsigned char* convertToUnibyteString(unsigned short* input, unsig return output; } -static inline unsigned char* convertToUnibyteStringAndReplaceLastChar(unsigned short* input, - unsigned char* output, const unsigned int length, unsigned char c) { +static inline unsigned char *convertToUnibyteStringAndReplaceLastChar(unsigned short *input, + unsigned char *output, const unsigned int length, unsigned char c) { unsigned int i = 0; for (; i <= length && input[i] != 0; ++i) output[i] = input[i] & 0xFF; @@ -39,7 +38,7 @@ static inline unsigned char* convertToUnibyteStringAndReplaceLastChar(unsigned s return output; } -static inline void LOGI_S16(unsigned short* string, const unsigned int length) { +static inline void LOGI_S16(unsigned short *string, const unsigned int length) { unsigned char tmp_buffer[length]; convertToUnibyteString(string, tmp_buffer, length); AKLOGI(">> %s", tmp_buffer); @@ -49,7 +48,7 @@ static inline void LOGI_S16(unsigned short* string, const unsigned int length) { // usleep(10); } -static inline void LOGI_S16_PLUS(unsigned short* string, const unsigned int length, +static inline void LOGI_S16_PLUS(unsigned short *string, const unsigned int length, unsigned char c) { unsigned char tmp_buffer[length+1]; convertToUnibyteStringAndReplaceLastChar(string, tmp_buffer, length, c); @@ -58,7 +57,7 @@ static inline void LOGI_S16_PLUS(unsigned short* string, const unsigned int leng // usleep(10); } -static inline void printDebug(const char* tag, int* codes, int codesSize, int MAX_PROXIMITY_CHARS) { +static inline void printDebug(const char *tag, int *codes, int codesSize, int MAX_PROXIMITY_CHARS) { unsigned char *buf = (unsigned char*)malloc((1 + codesSize) * sizeof(*buf)); buf[codesSize] = 0; @@ -68,5 +67,4 @@ static inline void printDebug(const char* tag, int* codes, int codesSize, int MA free(buf); } - #endif // LATINIME_DEBUG_H diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h index c7d3bf313..31dd61e30 100644 --- a/native/jni/src/defines.h +++ b/native/jni/src/defines.h @@ -1,42 +1,79 @@ /* -** -** Copyright 2010, 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. -*/ + * Copyright (C) 2010, 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_DEFINES_H #define LATINIME_DEFINES_H #if defined(FLAG_DO_PROFILE) || defined(FLAG_DBG) -#include <cutils/log.h> -#define AKLOGE ALOGE -#define AKLOGI ALOGI +#include <android/log.h> +#ifndef LOG_TAG +#define LOG_TAG "LatinIME: " +#endif +#define AKLOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##__VA_ARGS__) +#define AKLOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##__VA_ARGS__) +#define DUMP_RESULT(words, frequencies, maxWordCount, maxWordLength) do { \ + dumpResult(words, frequencies, maxWordCount, maxWordLength); } while(0) #define DUMP_WORD(word, length) do { dumpWord(word, length); } while(0) #define DUMP_WORD_INT(word, length) do { dumpWordInt(word, length); } while(0) -static inline void dumpWord(const unsigned short* word, const int length) { +static inline void dumpWordInfo(const unsigned short *word, const int length, + const int rank, const int frequency) { static char charBuf[50]; + int i = 0; + for (; i < length; ++i) { + const unsigned short c = word[i]; + if (c == 0) { + break; + } + charBuf[i] = c; + } + charBuf[i] = 0; + if (i > 1) { + AKLOGI("%2d [ %s ] (%d)", rank, charBuf, frequency); + } +} - for (int i = 0; i < length; ++i) { - charBuf[i] = word[i]; +static inline void dumpResult( + const unsigned short *outWords, const int *frequencies, const int maxWordCounts, + const int maxWordLength) { + AKLOGI("--- DUMP RESULT ---------"); + for (int i = 0; i < maxWordCounts; ++i) { + dumpWordInfo(&outWords[i * maxWordLength], maxWordLength, i, frequencies[i]); } - charBuf[length] = 0; - AKLOGI("[ %s ]", charBuf); + AKLOGI("-------------------------"); } -static inline void dumpWordInt(const int* word, const int length) { +static inline void dumpWord(const unsigned short *word, const int length) { + static char charBuf[50]; + int i = 0; + for (; i < length; ++i) { + const unsigned short c = word[i]; + if (c == 0) { + break; + } + charBuf[i] = c; + } + charBuf[i] = 0; + if (i > 1) { + AKLOGI("[ %s ]", charBuf); + } +} + +static inline void dumpWordInt(const int *word, const int length) { static char charBuf[50]; for (int i = 0; i < length; ++i) { @@ -49,6 +86,7 @@ static inline void dumpWordInt(const int* word, const int length) { #else #define AKLOGE(fmt, ...) #define AKLOGI(fmt, ...) +#define DUMP_RESULT(words, frequencies, maxWordCount, maxWordLength) #define DUMP_WORD(word, length) #define DUMP_WORD_INT(word, length) #endif @@ -86,17 +124,18 @@ static inline void prof_out(void) { AKLOGI("Error: You must call PROF_OPEN before PROF_CLOSE."); } AKLOGI("Total time is %6.3f ms.", - profile_buf[PROF_BUF_SIZE - 1] * 1000 / (float)CLOCKS_PER_SEC); + profile_buf[PROF_BUF_SIZE - 1] * 1000.0f / static_cast<float>(CLOCKS_PER_SEC)); float all = 0; for (int i = 0; i < PROF_BUF_SIZE - 1; ++i) { all += profile_buf[i]; } if (all == 0) all = 1; for (int i = 0; i < PROF_BUF_SIZE - 1; ++i) { - if (profile_buf[i] != 0) { + if (profile_buf[i]) { AKLOGI("(%d): Used %4.2f%%, %8.4f ms. Called %d times.", i, (profile_buf[i] * 100 / all), - profile_buf[i] * 1000 / (float)CLOCKS_PER_SEC, profile_counter[i]); + profile_buf[i] * 1000.0f / static_cast<float>(CLOCKS_PER_SEC), + profile_counter[i]); } } } @@ -116,10 +155,6 @@ static inline void prof_out(void) { #endif // FLAG_DO_PROFILE #ifdef FLAG_DBG -#include <cutils/log.h> -#ifndef LOG_TAG -#define LOG_TAG "LatinIME: " -#endif #define DEBUG_DICT true #define DEBUG_DICT_FULL false #define DEBUG_EDIT_DISTANCE false @@ -146,7 +181,6 @@ static inline void prof_out(void) { #define DEBUG_CORRECTION_FREQ false #define DEBUG_WORDS_PRIORITY_QUEUE false - #endif // FLAG_DBG #ifndef U_SHORT_MAX @@ -313,5 +347,4 @@ typedef enum { // Additional proximity char which can differ by language. ADDITIONAL_PROXIMITY_CHAR } ProximityType; - #endif // LATINIME_DEFINES_H diff --git a/native/jni/src/dictionary.cpp b/native/jni/src/dictionary.cpp index f3166e75a..ee55cfa60 100644 --- a/native/jni/src/dictionary.cpp +++ b/native/jni/src/dictionary.cpp @@ -1,28 +1,29 @@ /* -** -** Copyright 2009, 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 <stdio.h> + * Copyright (C) 2009, 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. + */ #define LOG_TAG "LatinIME: dictionary.cpp" +#include <stdint.h> + +#include "bigram_dictionary.h" #include "binary_format.h" #include "defines.h" #include "dictionary.h" #include "gesture_decoder_wrapper.h" +#include "unigram_dictionary.h" namespace latinime { @@ -55,6 +56,40 @@ Dictionary::~Dictionary() { delete mGestureDecoder; } +int Dictionary::getSuggestions(ProximityInfo *proximityInfo, int *xcoordinates, int *ycoordinates, + int *times, int *pointerIds, int *codes, int codesSize, int *prevWordChars, + int prevWordLength, int commitPoint, bool isGesture, + bool useFullEditDistance, unsigned short *outWords, + int *frequencies, int *spaceIndices, int *outputTypes) { + int result = 0; + if (isGesture) { + mGestureDecoder->setPrevWord(prevWordChars, prevWordLength); + result = mGestureDecoder->getSuggestions(proximityInfo, xcoordinates, ycoordinates, + times, pointerIds, codes, codesSize, commitPoint, + outWords, frequencies, spaceIndices, outputTypes); + if (DEBUG_DICT) { + DUMP_RESULT(outWords, frequencies, 18 /* MAX_WORDS */, MAX_WORD_LENGTH_INTERNAL); + } + return result; + } else { + std::map<int, int> bigramMap; + uint8_t bigramFilter[BIGRAM_FILTER_BYTE_SIZE]; + mBigramDictionary->fillBigramAddressToFrequencyMapAndFilter(prevWordChars, + prevWordLength, &bigramMap, bigramFilter); + result = mUnigramDictionary->getSuggestions(proximityInfo, xcoordinates, + ycoordinates, codes, codesSize, &bigramMap, bigramFilter, + useFullEditDistance, outWords, frequencies, outputTypes); + return result; + } +} + +int Dictionary::getBigrams(const int32_t *word, int length, int *codes, int codesSize, + unsigned short *outWords, int *frequencies, int *outputTypes) const { + if (length <= 0) return 0; + return mBigramDictionary->getBigrams(word, length, codes, codesSize, outWords, frequencies, + outputTypes); +} + int Dictionary::getFrequency(const int32_t *word, int length) const { return mUnigramDictionary->getFrequency(word, length); } @@ -63,5 +98,4 @@ bool Dictionary::isValidBigram(const int32_t *word1, int length1, const int32_t int length2) const { return mBigramDictionary->isValidBigram(word1, length1, word2, length2); } - } // namespace latinime diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index 7911403dc..ab238c824 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -17,18 +17,17 @@ #ifndef LATINIME_DICTIONARY_H #define LATINIME_DICTIONARY_H -#include <map> +#include <stdint.h> -#include "bigram_dictionary.h" -#include "char_utils.h" #include "defines.h" -#include "incremental_decoder_interface.h" -#include "proximity_info.h" -#include "unigram_dictionary.h" -#include "words_priority_queue_pool.h" namespace latinime { +class BigramDictionary; +class IncrementalDecoderInterface; +class ProximityInfo; +class UnigramDictionary; + class Dictionary { public: // Taken from SuggestedWords.java @@ -49,32 +48,10 @@ class Dictionary { int *times, int *pointerIds, int *codes, int codesSize, int *prevWordChars, int prevWordLength, int commitPoint, bool isGesture, bool useFullEditDistance, unsigned short *outWords, - int *frequencies, int *spaceIndices, int *outputTypes) { - int result = 0; - if (isGesture) { - mGestureDecoder->setPrevWord(prevWordChars, prevWordLength); - result = mGestureDecoder->getSuggestions(proximityInfo, xcoordinates, ycoordinates, - times, pointerIds, codes, codesSize, commitPoint, - outWords, frequencies, spaceIndices, outputTypes); - return result; - } else { - std::map<int, int> bigramMap; - uint8_t bigramFilter[BIGRAM_FILTER_BYTE_SIZE]; - mBigramDictionary->fillBigramAddressToFrequencyMapAndFilter(prevWordChars, - prevWordLength, &bigramMap, bigramFilter); - result = mUnigramDictionary->getSuggestions(proximityInfo, xcoordinates, - ycoordinates, codes, codesSize, &bigramMap, bigramFilter, - useFullEditDistance, outWords, frequencies, outputTypes); - return result; - } - } + int *frequencies, int *spaceIndices, int *outputTypes); int getBigrams(const int32_t *word, int length, int *codes, int codesSize, - unsigned short *outWords, int *frequencies, int *outputTypes) const { - if (length <= 0) return 0; - return mBigramDictionary->getBigrams(word, length, codes, codesSize, outWords, frequencies, - outputTypes); - } + unsigned short *outWords, int *frequencies, int *outputTypes) const; int getFrequency(const int32_t *word, int length) const; bool isValidBigram(const int32_t *word1, int length1, const int32_t *word2, int length2) const; @@ -82,7 +59,7 @@ class Dictionary { int getDictSize() const { return mDictSize; } int getMmapFd() const { return mMmapFd; } int getDictBufAdjust() const { return mDictBufAdjust; } - ~Dictionary(); + virtual ~Dictionary(); // public static utility methods // static inline methods should be defined in the header file @@ -113,5 +90,4 @@ inline int Dictionary::wideStrLen(unsigned short *str) { return end - str; } } // namespace latinime - #endif // LATINIME_DICTIONARY_H diff --git a/native/jni/src/proximity_info.cpp b/native/jni/src/proximity_info.cpp index a4a641160..cee408d46 100644 --- a/native/jni/src/proximity_info.cpp +++ b/native/jni/src/proximity_info.cpp @@ -14,18 +14,17 @@ * limitations under the License. */ -#include <assert.h> -#include <math.h> -#include <stdio.h> +#include <cassert> +#include <cmath> +#include <cstring> #include <string> #define LOG_TAG "LatinIME: proximity_info.cpp" #include "additional_proximity_chars.h" +#include "char_utils.h" #include "defines.h" -#include "dictionary.h" #include "proximity_info.h" -#include "proximity_info_state.h" namespace latinime { @@ -110,7 +109,7 @@ bool ProximityInfo::hasSpaceProximity(const int x, const int y) const { if (DEBUG_PROXIMITY_INFO) { AKLOGI("hasSpaceProximity: index %d, %d, %d", startIndex, x, y); } - int32_t* proximityCharsArray = mProximityCharsArray; + int32_t *proximityCharsArray = mProximityCharsArray; for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) { if (DEBUG_PROXIMITY_INFO) { AKLOGI("Index: %d", mProximityCharsArray[startIndex + i]); @@ -171,7 +170,7 @@ void ProximityInfo::calculateNearbyKeyCodes( return; } - const int32_t* additionalProximityChars = + const int32_t *additionalProximityChars = AdditionalProximityChars::getAdditionalChars(&mLocaleStr, primaryKey); for (int j = 0; j < additionalProximitySize; ++j) { const int32_t ac = additionalProximityChars[j]; @@ -216,7 +215,7 @@ int ProximityInfo::getKeyIndex(const int c) const { void ProximityInfo::getCenters(int *centerXs, int *centerYs, int *codeToKeyIndex, int *keyToCodeIndex, int *keyCount, int *keyWidth) const { *keyCount = KEY_COUNT; - *keyWidth = sqrt((float)MOST_COMMON_KEY_WIDTH_SQUARE); + *keyWidth = sqrt(static_cast<float>(MOST_COMMON_KEY_WIDTH_SQUARE)); for (int i = 0; i < KEY_COUNT; ++i) { const int code = mKeyCharCodes[i]; diff --git a/native/jni/src/proximity_info.h b/native/jni/src/proximity_info.h index d58935c6b..abd07dd3e 100644 --- a/native/jni/src/proximity_info.h +++ b/native/jni/src/proximity_info.h @@ -141,7 +141,5 @@ class ProximityInfo { int mCodeToKeyIndex[MAX_CHAR_CODE + 1]; // TODO: move to correction.h }; - } // namespace latinime - #endif // LATINIME_PROXIMITY_INFO_H diff --git a/native/jni/src/proximity_info_state.cpp b/native/jni/src/proximity_info_state.cpp index 149299eb6..86c8a697a 100644 --- a/native/jni/src/proximity_info_state.cpp +++ b/native/jni/src/proximity_info_state.cpp @@ -14,22 +14,19 @@ * limitations under the License. */ -#include <assert.h> +#include <cstring> // for memset() #include <stdint.h> -#include <string> #define LOG_TAG "LatinIME: proximity_info_state.cpp" -#include "additional_proximity_chars.h" #include "defines.h" -#include "dictionary.h" #include "proximity_info.h" #include "proximity_info_state.h" namespace latinime { void ProximityInfoState::initInputParams( - const ProximityInfo* proximityInfo, const int32_t* inputCodes, const int inputLength, - const int* xCoordinates, const int* yCoordinates) { + const ProximityInfo *proximityInfo, const int32_t *inputCodes, const int inputLength, + const int *xCoordinates, const int *yCoordinates) { mProximityInfo = proximityInfo; mHasTouchPositionCorrectionData = proximityInfo->hasTouchPositionCorrectionData(); mMostCommonKeyWidthSquare = proximityInfo->getMostCommonKeyWidthSquare(); @@ -132,8 +129,8 @@ 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 = (float)mInputXCoordinates[inputIndex]; - const float inputY = (float)mInputYCoordinates[inputIndex]; + const float inputX = static_cast<float>(mInputXCoordinates[inputIndex]); + const float inputY = static_cast<float>(mInputYCoordinates[inputIndex]); return square(inputX - sweetSpotCenterX) + square(inputY - sweetSpotCenterY); } } // namespace latinime diff --git a/native/jni/src/proximity_info_state.h b/native/jni/src/proximity_info_state.h index 717871c90..76d45516e 100644 --- a/native/jni/src/proximity_info_state.h +++ b/native/jni/src/proximity_info_state.h @@ -17,11 +17,9 @@ #ifndef LATINIME_PROXIMITY_INFO_STATE_H #define LATINIME_PROXIMITY_INFO_STATE_H -#include <assert.h> #include <stdint.h> #include <string> -#include "additional_proximity_chars.h" #include "char_utils.h" #include "defines.h" @@ -43,14 +41,14 @@ class ProximityInfoState { // Defined in proximity_info_state.cpp // ///////////////////////////////////////// void initInputParams( - const ProximityInfo* proximityInfo, const int32_t* inputCodes, const int inputLength, - const int* xCoordinates, const int* yCoordinates); + const ProximityInfo *proximityInfo, const int32_t *inputCodes, const int inputLength, + const int *xCoordinates, const int *yCoordinates); ///////////////////////////////////////// // Defined here // ///////////////////////////////////////// ProximityInfoState() {}; - inline const int* getProximityCharsAt(const int index) const { + inline const int *getProximityCharsAt(const int index) const { return mInputCodes + (index * MAX_PROXIMITY_CHARS_SIZE_INTERNAL); } @@ -154,7 +152,7 @@ class ProximityInfoState { inputIndex * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + proximityIndex]; } - inline const unsigned short* getPrimaryInputWord() const { + inline const unsigned short *getPrimaryInputWord() const { return mPrimaryInputWord; } @@ -215,7 +213,5 @@ class ProximityInfoState { int mInputLength; unsigned short mPrimaryInputWord[MAX_WORD_LENGTH_INTERNAL]; }; - } // namespace latinime - #endif // LATINIME_PROXIMITY_INFO_STATE_H diff --git a/native/jni/src/terminal_attributes.h b/native/jni/src/terminal_attributes.h index c712f502d..d63364514 100644 --- a/native/jni/src/terminal_attributes.h +++ b/native/jni/src/terminal_attributes.h @@ -17,7 +17,7 @@ #ifndef LATINIME_TERMINAL_ATTRIBUTES_H #define LATINIME_TERMINAL_ATTRIBUTES_H -#include "unigram_dictionary.h" +#include "binary_format.h" namespace latinime { @@ -29,14 +29,14 @@ namespace latinime { class TerminalAttributes { public: class ShortcutIterator { - const uint8_t* const mDict; + const uint8_t *const mDict; bool mHasNextShortcutTarget; int mPos; public: - ShortcutIterator(const uint8_t* dict, const int pos, const uint8_t flags) : mDict(dict), + ShortcutIterator(const uint8_t *dict, const int pos, const uint8_t flags) : mDict(dict), mPos(pos) { - mHasNextShortcutTarget = (0 != (flags & UnigramDictionary::FLAG_HAS_SHORTCUT_TARGETS)); + mHasNextShortcutTarget = (0 != (flags & BinaryFormat::FLAG_HAS_SHORTCUT_TARGETS)); } inline bool hasNextShortcutTarget() const { @@ -46,10 +46,10 @@ class TerminalAttributes { // Gets the shortcut target itself as a uint16_t string. For parameters and return value // see BinaryFormat::getWordAtAddress. // TODO: make the output an uint32_t* to handle the whole unicode range. - inline int getNextShortcutTarget(const int maxDepth, uint16_t* outWord) { + inline int getNextShortcutTarget(const int maxDepth, uint16_t *outWord) { const int shortcutFlags = BinaryFormat::getFlagsAndForwardPointer(mDict, &mPos); mHasNextShortcutTarget = - 0 != (shortcutFlags & UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT); + 0 != (shortcutFlags & BinaryFormat::FLAG_ATTRIBUTE_HAS_NEXT); unsigned int i; for (i = 0; i < MAX_WORD_LENGTH_INTERNAL; ++i) { const int charCode = BinaryFormat::getCharCodeAndForwardPointer(mDict, &mPos); @@ -63,12 +63,12 @@ class TerminalAttributes { private: DISALLOW_IMPLICIT_CONSTRUCTORS(TerminalAttributes); - const uint8_t* const mDict; + const uint8_t *const mDict; const uint8_t mFlags; const int mStartPos; public: - TerminalAttributes(const uint8_t* const dict, const uint8_t flags, const int pos) : + TerminalAttributes(const uint8_t *const dict, const uint8_t flags, const int pos) : mDict(dict), mFlags(flags), mStartPos(pos) { } @@ -79,5 +79,4 @@ class TerminalAttributes { } }; } // namespace latinime - #endif // LATINIME_TERMINAL_ATTRIBUTES_H diff --git a/native/jni/src/unigram_dictionary.cpp b/native/jni/src/unigram_dictionary.cpp index 0ffb3eb63..b6b0210cc 100644 --- a/native/jni/src/unigram_dictionary.cpp +++ b/native/jni/src/unigram_dictionary.cpp @@ -1,32 +1,33 @@ /* -** -** Copyright 2010, 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 <assert.h> -#include <string.h> + * Copyright (C) 2010, 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 <cassert> +#include <cstring> #define LOG_TAG "LatinIME: unigram_dictionary.cpp" +#include "binary_format.h" #include "char_utils.h" #include "defines.h" #include "dictionary.h" -#include "unigram_dictionary.h" - -#include "binary_format.h" +#include "proximity_info.h" #include "terminal_attributes.h" +#include "unigram_dictionary.h" +#include "words_priority_queue.h" +#include "words_priority_queue_pool.h" namespace latinime { @@ -40,7 +41,7 @@ const UnigramDictionary::digraph_t UnigramDictionary::FRENCH_LIGATURES_DIGRAPHS[ { 'o', 'e', 0x0153 } }; // U+0153 : LATIN SMALL LIGATURE OE // TODO: check the header -UnigramDictionary::UnigramDictionary(const uint8_t* const streamStart, int typedLetterMultiplier, +UnigramDictionary::UnigramDictionary(const uint8_t *const streamStart, int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength, int maxWords, const unsigned int flags) : DICT_ROOT(streamStart), MAX_WORD_LENGTH(maxWordLength), MAX_WORDS(maxWords), TYPED_LETTER_MULTIPLIER(typedLetterMultiplier), FULL_WORD_MULTIPLIER(fullWordMultiplier), @@ -68,7 +69,7 @@ static inline void addWord( // Return the replacement code point for a digraph, or 0 if none. int UnigramDictionary::getDigraphReplacement(const int *codes, const int i, const int codesSize, - const digraph_t* const digraphs, const unsigned int digraphsSize) const { + const digraph_t *const digraphs, const unsigned int digraphsSize) const { // There can't be a digraph if we don't have at least 2 characters to examine if (i + 2 > codesSize) return false; @@ -103,7 +104,7 @@ void UnigramDictionary::getWordWithDigraphSuggestionsRec(ProximityInfo *proximit const bool useFullEditDistance, const int *codesSrc, const int codesRemain, const int currentDepth, int *codesDest, Correction *correction, WordsPriorityQueuePool *queuePool, - const digraph_t* const digraphs, const unsigned int digraphsSize) const { + const digraph_t *const digraphs, const unsigned int digraphsSize) const { const int startIndex = codesDest - codesBuffer; if (currentDepth < MAX_DIGRAPH_SEARCH_DEPTH) { @@ -222,7 +223,7 @@ int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, AKLOGI("Returning %d words", suggestedWordsCount); /// Print the returned words for (int j = 0; j < suggestedWordsCount; ++j) { - short unsigned int* w = outWords + j * MAX_WORD_LENGTH; + short unsigned int *w = outWords + j * MAX_WORD_LENGTH; char s[MAX_WORD_LENGTH]; for (int i = 0; i <= MAX_WORD_LENGTH; i++) s[i] = w[i]; (void)s; @@ -259,7 +260,7 @@ void UnigramDictionary::getWordSuggestions(ProximityInfo *proximityInfo, PROF_START(4); bool hasAutoCorrectionCandidate = false; - WordsPriorityQueue* masterQueue = queuePool->getMasterQueue(); + WordsPriorityQueue *masterQueue = queuePool->getMasterQueue(); if (masterQueue->size() > 0) { float nsForMaster = masterQueue->getHighestNormalizedScore( correction->getPrimaryInputWord(), inputLength, 0, 0, 0); @@ -284,11 +285,11 @@ void UnigramDictionary::getWordSuggestions(ProximityInfo *proximityInfo, if (DEBUG_DICT) { queuePool->dumpSubQueue1TopSuggestions(); for (int i = 0; i < SUB_QUEUE_MAX_COUNT; ++i) { - WordsPriorityQueue* queue = queuePool->getSubQueue(FIRST_WORD_INDEX, i); + WordsPriorityQueue *queue = queuePool->getSubQueue(FIRST_WORD_INDEX, i); if (queue->size() > 0) { - WordsPriorityQueue::SuggestedWord* sw = queue->top(); + WordsPriorityQueue::SuggestedWord *sw = queue->top(); const int score = sw->mScore; - const unsigned short* word = sw->mWord; + const unsigned short *word = sw->mWord; const int wordLength = sw->mWordLength; float ns = Correction::RankingAlgorithm::calcNormalizedScore( correction->getPrimaryInputWord(), i, word, wordLength, score); @@ -383,7 +384,7 @@ inline void UnigramDictionary::onTerminal(const int probability, const bool addToSubQueue = inputIndex < SUB_QUEUE_MAX_COUNT; int wordLength; - unsigned short* wordPointer; + unsigned short *wordPointer; if ((currentWordIndex == FIRST_WORD_INDEX) && addToMasterQueue) { WordsPriorityQueue *masterQueue = queuePool->getMasterQueue(); @@ -430,11 +431,11 @@ inline void UnigramDictionary::onTerminal(const int probability, int UnigramDictionary::getSubStringSuggestion( ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, const int *codes, const bool useFullEditDistance, Correction *correction, - WordsPriorityQueuePool* queuePool, const int inputLength, + WordsPriorityQueuePool *queuePool, const int inputLength, const bool hasAutoCorrectionCandidate, const int currentWordIndex, const int inputWordStartPos, const int inputWordLength, const int outputWordStartPos, const bool isSpaceProximity, int *freqArray, - int*wordLengthArray, unsigned short* outputWord, int *outputWordLength) const { + int*wordLengthArray, unsigned short *outputWord, int *outputWordLength) const { if (inputWordLength > MULTIPLE_WORDS_SUGGESTION_MAX_WORD_LENGTH) { return FLAG_MULTIPLE_SUGGEST_ABORT; } @@ -477,7 +478,7 @@ int UnigramDictionary::getSubStringSuggestion( // TODO: Remove the safety net above // ////////////////////////////////////////////// - unsigned short* tempOutputWord = 0; + unsigned short *tempOutputWord = 0; int nextWordLength = 0; // TODO: Optimize init suggestion initSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, @@ -508,7 +509,7 @@ int UnigramDictionary::getSubStringSuggestion( } } } - WordsPriorityQueue* queue = queuePool->getSubQueue(currentWordIndex, inputWordLength); + WordsPriorityQueue *queue = queuePool->getSubQueue(currentWordIndex, inputWordLength); // TODO: Return the correct value depending on doAutoCompletion if (!queue || queue->size() <= 0) { return FLAG_MULTIPLE_SUGGEST_ABORT; @@ -579,10 +580,10 @@ int UnigramDictionary::getSubStringSuggestion( void UnigramDictionary::getMultiWordsSuggestionRec(ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, const int *codes, const bool useFullEditDistance, const int inputLength, - Correction *correction, WordsPriorityQueuePool* queuePool, + Correction *correction, WordsPriorityQueuePool *queuePool, const bool hasAutoCorrectionCandidate, const int startInputPos, const int startWordIndex, - const int outputWordLength, int *freqArray, int* wordLengthArray, - unsigned short* outputWord) const { + const int outputWordLength, int *freqArray, int *wordLengthArray, + unsigned short *outputWord) const { if (startWordIndex >= (MULTIPLE_WORDS_SUGGESTION_MAX_WORDS - 1)) { // Return if the last word index return; @@ -660,7 +661,7 @@ void UnigramDictionary::getMultiWordsSuggestionRec(ProximityInfo *proximityInfo, void UnigramDictionary::getSplitMultipleWordsSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, const int *codes, const bool useFullEditDistance, const int inputLength, - Correction *correction, WordsPriorityQueuePool* queuePool, + Correction *correction, WordsPriorityQueuePool *queuePool, const bool hasAutoCorrectionCandidate) const { if (inputLength >= MAX_WORD_LENGTH) return; if (DEBUG_DICT) { @@ -705,10 +706,10 @@ inline int UnigramDictionary::getMostFrequentWordLike(const int startInputIndex, // In and out parameters may point to the same location. This function takes care // not to use any input parameters after it wrote into its outputs. static inline bool testCharGroupForContinuedLikeness(const uint8_t flags, - const uint8_t* const root, const int startPos, - const uint16_t* const inWord, const int startInputIndex, - int32_t* outNewWord, int* outInputIndex, int* outPos) { - const bool hasMultipleChars = (0 != (UnigramDictionary::FLAG_HAS_MULTIPLE_CHARS & flags)); + const uint8_t *const root, const int startPos, + const uint16_t *const inWord, const int startInputIndex, + int32_t *outNewWord, int *outInputIndex, int *outPos) { + const bool hasMultipleChars = (0 != (BinaryFormat::FLAG_HAS_MULTIPLE_CHARS & flags)); int pos = startPos; int32_t character = BinaryFormat::getCharCodeAndForwardPointer(root, &pos); int32_t baseChar = toBaseLowerCase(character); @@ -743,8 +744,8 @@ static inline bool testCharGroupForContinuedLikeness(const uint8_t flags, // It will compare the frequency to the max frequency, and if greater, will // copy the word into the output buffer. In output value maxFreq, it will // write the new maximum frequency if it changed. -static inline void onTerminalWordLike(const int freq, int32_t* newWord, const int length, - short unsigned int* outWord, int* maxFreq) { +static inline void onTerminalWordLike(const int freq, int32_t *newWord, const int length, + short unsigned int *outWord, int *maxFreq) { if (freq > *maxFreq) { for (int q = 0; q < length; ++q) outWord[q] = newWord[q]; @@ -755,12 +756,12 @@ static inline void onTerminalWordLike(const int freq, int32_t* newWord, const in // Will find the highest frequency of the words like the one passed as an argument, // that is, everything that only differs by case/accents. -int UnigramDictionary::getMostFrequentWordLikeInner(const uint16_t * const inWord, - const int length, short unsigned int* outWord) const { +int UnigramDictionary::getMostFrequentWordLikeInner(const uint16_t *const inWord, + const int length, short unsigned int *outWord) const { int32_t newWord[MAX_WORD_LENGTH_INTERNAL]; int depth = 0; int maxFreq = -1; - const uint8_t* const root = DICT_ROOT; + const uint8_t *const root = DICT_ROOT; int stackChildCount[MAX_WORD_LENGTH_INTERNAL]; int stackInputIndex[MAX_WORD_LENGTH_INTERNAL]; int stackSiblingPos[MAX_WORD_LENGTH_INTERNAL]; @@ -781,7 +782,7 @@ int UnigramDictionary::getMostFrequentWordLikeInner(const uint16_t * const inWor // into inputIndex if there is a match. const bool isAlike = testCharGroupForContinuedLikeness(flags, root, pos, inWord, inputIndex, newWord, &inputIndex, &pos); - if (isAlike && (FLAG_IS_TERMINAL & flags) && (inputIndex == length)) { + if (isAlike && (BinaryFormat::FLAG_IS_TERMINAL & flags) && (inputIndex == length)) { const int frequency = BinaryFormat::readFrequencyWithoutMovingPointer(root, pos); onTerminalWordLike(frequency, newWord, inputIndex, outWord, &maxFreq); } @@ -816,15 +817,15 @@ int UnigramDictionary::getMostFrequentWordLikeInner(const uint16_t * const inWor return maxFreq; } -int UnigramDictionary::getFrequency(const int32_t* const inWord, const int length) const { - const uint8_t* const root = DICT_ROOT; +int UnigramDictionary::getFrequency(const int32_t *const inWord, const int length) const { + const uint8_t *const root = DICT_ROOT; int pos = BinaryFormat::getTerminalPosition(root, inWord, length, false /* forceLowerCaseSearch */); if (NOT_VALID_WORD == pos) { return NOT_A_PROBABILITY; } const uint8_t flags = BinaryFormat::getFlagsAndForwardPointer(root, &pos); - const bool hasMultipleChars = (0 != (FLAG_HAS_MULTIPLE_CHARS & flags)); + const bool hasMultipleChars = (0 != (BinaryFormat::FLAG_HAS_MULTIPLE_CHARS & flags)); if (hasMultipleChars) { pos = BinaryFormat::skipOtherCharacters(root, pos); } else { @@ -872,8 +873,8 @@ inline bool UnigramDictionary::processCurrentNode(const int initialPos, // - FLAG_IS_TERMINAL: whether this node is a terminal or not (it may still have children) // - FLAG_HAS_BIGRAMS: whether this node has bigrams or not const uint8_t flags = BinaryFormat::getFlagsAndForwardPointer(DICT_ROOT, &pos); - const bool hasMultipleChars = (0 != (FLAG_HAS_MULTIPLE_CHARS & flags)); - const bool isTerminalNode = (0 != (FLAG_IS_TERMINAL & flags)); + const bool hasMultipleChars = (0 != (BinaryFormat::FLAG_HAS_MULTIPLE_CHARS & flags)); + const bool isTerminalNode = (0 != (BinaryFormat::FLAG_IS_TERMINAL & flags)); bool needsToInvokeOnTerminal = false; @@ -991,5 +992,4 @@ inline bool UnigramDictionary::processCurrentNode(const int initialPos, *newChildrenPosition = childrenPos; return true; } - } // namespace latinime diff --git a/native/jni/src/unigram_dictionary.h b/native/jni/src/unigram_dictionary.h index ac14fc0bc..6083f0175 100644 --- a/native/jni/src/unigram_dictionary.h +++ b/native/jni/src/unigram_dictionary.h @@ -19,53 +19,19 @@ #include <map> #include <stdint.h> -#include "correction.h" -#include "correction_state.h" #include "defines.h" -#include "proximity_info.h" -#include "words_priority_queue.h" -#include "words_priority_queue_pool.h" namespace latinime { +class Correction; +class ProximityInfo; class TerminalAttributes; +class WordsPriorityQueuePool; + class UnigramDictionary { typedef struct { int first; int second; int replacement; } digraph_t; public: - // Mask and flags for children address type selection. - static const int MASK_GROUP_ADDRESS_TYPE = 0xC0; - static const int FLAG_GROUP_ADDRESS_TYPE_NOADDRESS = 0x00; - static const int FLAG_GROUP_ADDRESS_TYPE_ONEBYTE = 0x40; - static const int FLAG_GROUP_ADDRESS_TYPE_TWOBYTES = 0x80; - static const int FLAG_GROUP_ADDRESS_TYPE_THREEBYTES = 0xC0; - - // Flag for single/multiple char group - static const int FLAG_HAS_MULTIPLE_CHARS = 0x20; - - // Flag for terminal groups - static const int FLAG_IS_TERMINAL = 0x10; - - // Flag for shortcut targets presence - static const int FLAG_HAS_SHORTCUT_TARGETS = 0x08; - // Flag for bigram presence - static const int FLAG_HAS_BIGRAMS = 0x04; - - // Attribute (bigram/shortcut) related flags: - // Flag for presence of more attributes - static const int FLAG_ATTRIBUTE_HAS_NEXT = 0x80; - // Flag for sign of offset. If this flag is set, the offset value must be negated. - static const int FLAG_ATTRIBUTE_OFFSET_NEGATIVE = 0x40; - - // Mask for attribute frequency, stored on 4 bits inside the flags byte. - static const int MASK_ATTRIBUTE_FREQUENCY = 0x0F; - - // Mask and flags for attribute address type selection. - static const int MASK_ATTRIBUTE_ADDRESS_TYPE = 0x30; - static const int FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE = 0x10; - static const int FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES = 0x20; - static const int FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES = 0x30; - // Error tolerances static const int DEFAULT_MAX_ERRORS = 2; static const int MAX_ERRORS_FOR_TWO_WORDS = 1; @@ -73,9 +39,9 @@ class UnigramDictionary { static const int FLAG_MULTIPLE_SUGGEST_ABORT = 0; static const int FLAG_MULTIPLE_SUGGEST_SKIP = 1; static const int FLAG_MULTIPLE_SUGGEST_CONTINUE = 2; - UnigramDictionary(const uint8_t* const streamStart, int typedLetterMultipler, + UnigramDictionary(const uint8_t *const streamStart, int typedLetterMultipler, int fullWordMultiplier, int maxWordLength, int maxWords, const unsigned int flags); - int getFrequency(const int32_t* const inWord, const int length) const; + int getFrequency(const int32_t *const inWord, const int length) const; int getBigramPosition(int pos, unsigned short *word, int offset, int length) const; int getSuggestions( ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, @@ -92,14 +58,14 @@ class UnigramDictionary { const bool useFullEditDistance, Correction *correction, WordsPriorityQueuePool *queuePool) const; int getDigraphReplacement(const int *codes, const int i, const int codesSize, - const digraph_t* const digraphs, const unsigned int digraphsSize) const; + const digraph_t *const digraphs, const unsigned int digraphsSize) const; void getWordWithDigraphSuggestionsRec(ProximityInfo *proximityInfo, - const int *xcoordinates, const int* ycoordinates, const int *codesBuffer, + const int *xcoordinates, const int *ycoordinates, const int *codesBuffer, int *xCoordinatesBuffer, int *yCoordinatesBuffer, const int codesBufferSize, const std::map<int, int> *bigramMap, const uint8_t *bigramFilter, - const bool useFullEditDistance, const int* codesSrc, const int codesRemain, - const int currentDepth, int* codesDest, Correction *correction, - WordsPriorityQueuePool* queuePool, const digraph_t* const digraphs, + const bool useFullEditDistance, const int *codesSrc, const int codesRemain, + const int currentDepth, int *codesDest, Correction *correction, + WordsPriorityQueuePool *queuePool, const digraph_t *const digraphs, const unsigned int digraphsSize) const; void initSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, const int *codes, const int codesSize, @@ -107,16 +73,16 @@ class UnigramDictionary { void getOneWordSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, const int *codes, const std::map<int, int> *bigramMap, const uint8_t *bigramFilter, const bool useFullEditDistance, const int inputLength, - Correction *correction, WordsPriorityQueuePool* queuePool) const; + Correction *correction, WordsPriorityQueuePool *queuePool) const; void getSuggestionCandidates( const bool useFullEditDistance, const int inputLength, const std::map<int, int> *bigramMap, const uint8_t *bigramFilter, - Correction *correction, WordsPriorityQueuePool* queuePool, const bool doAutoCompletion, + Correction *correction, WordsPriorityQueuePool *queuePool, const bool doAutoCompletion, const int maxErrors, const int currentWordIndex) const; void getSplitMultipleWordsSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, const int *codes, const bool useFullEditDistance, const int inputLength, - Correction *correction, WordsPriorityQueuePool* queuePool, + Correction *correction, WordsPriorityQueuePool *queuePool, const bool hasAutoCorrectionCandidate) const; void onTerminal(const int freq, const TerminalAttributes& terminalAttributes, Correction *correction, WordsPriorityQueuePool *queuePool, const bool addToMasterQueue, @@ -128,25 +94,25 @@ class UnigramDictionary { const int currentWordIndex) const; int getMostFrequentWordLike(const int startInputIndex, const int inputLength, Correction *correction, unsigned short *word) const; - int getMostFrequentWordLikeInner(const uint16_t* const inWord, const int length, + int getMostFrequentWordLikeInner(const uint16_t *const inWord, const int length, short unsigned int *outWord) const; int getSubStringSuggestion( ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, const int *codes, const bool useFullEditDistance, Correction *correction, - WordsPriorityQueuePool* queuePool, const int inputLength, + WordsPriorityQueuePool *queuePool, const int inputLength, const bool hasAutoCorrectionCandidate, const int currentWordIndex, const int inputWordStartPos, const int inputWordLength, const int outputWordStartPos, const bool isSpaceProximity, int *freqArray, - int *wordLengthArray, unsigned short* outputWord, int *outputWordLength) const; + int *wordLengthArray, unsigned short *outputWord, int *outputWordLength) const; void getMultiWordsSuggestionRec(ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, const int *codes, const bool useFullEditDistance, const int inputLength, - Correction *correction, WordsPriorityQueuePool* queuePool, + Correction *correction, WordsPriorityQueuePool *queuePool, const bool hasAutoCorrectionCandidate, const int startPos, const int startWordIndex, - const int outputWordLength, int *freqArray, int* wordLengthArray, - unsigned short* outputWord) const; + const int outputWordLength, int *freqArray, int *wordLengthArray, + unsigned short *outputWord) const; - const uint8_t* const DICT_ROOT; + const uint8_t *const DICT_ROOT; const int MAX_WORD_LENGTH; const int MAX_WORDS; const int TYPED_LETTER_MULTIPLIER; @@ -160,5 +126,4 @@ class UnigramDictionary { static const digraph_t FRENCH_LIGATURES_DIGRAPHS[]; }; } // namespace latinime - #endif // LATINIME_UNIGRAM_DICTIONARY_H diff --git a/native/jni/src/words_priority_queue.h b/native/jni/src/words_priority_queue.h index 9c6d28d60..c0dedb59d 100644 --- a/native/jni/src/words_priority_queue.h +++ b/native/jni/src/words_priority_queue.h @@ -18,8 +18,9 @@ #define LATINIME_WORDS_PRIORITY_QUEUE_H #include <cstring> // for memcpy() -#include <iostream> #include <queue> + +#include "correction.h" #include "defines.h" namespace latinime { @@ -33,7 +34,7 @@ class WordsPriorityQueue { int mWordLength; bool mUsed; - void setParams(int score, unsigned short* word, int wordLength) { + void setParams(int score, unsigned short *word, int wordLength) { mScore = score; mWordLength = wordLength; memcpy(mWord, word, sizeof(unsigned short) * wordLength); @@ -55,8 +56,8 @@ class WordsPriorityQueue { delete[] mSuggestedWords; } - void push(int score, unsigned short* word, int wordLength) { - SuggestedWord* sw = 0; + void push(int score, unsigned short *word, int wordLength) { + SuggestedWord *sw = 0; if (mSuggestions.size() >= MAX_WORDS) { sw = mSuggestions.top(); const int minScore = sw->mScore; @@ -86,21 +87,21 @@ class WordsPriorityQueue { } } - SuggestedWord* top() { + SuggestedWord *top() { if (mSuggestions.empty()) return 0; - SuggestedWord* sw = mSuggestions.top(); + SuggestedWord *sw = mSuggestions.top(); return sw; } - int outputSuggestions(const unsigned short* before, const int beforeLength, + int outputSuggestions(const unsigned short *before, const int beforeLength, int *frequencies, unsigned short *outputChars) { mHighestSuggestedWord = 0; const unsigned int size = min( MAX_WORDS, static_cast<unsigned int>(mSuggestions.size())); - SuggestedWord* swBuffer[size]; + SuggestedWord *swBuffer[size]; int index = size - 1; while (!mSuggestions.empty() && index >= 0) { - SuggestedWord* sw = mSuggestions.top(); + SuggestedWord *sw = mSuggestions.top(); if (DEBUG_WORDS_PRIORITY_QUEUE) { AKLOGI("dump word. %d", sw->mScore); DUMP_WORD(sw->mWord, sw->mWordLength); @@ -110,11 +111,11 @@ class WordsPriorityQueue { --index; } if (size >= 2) { - SuggestedWord* nsMaxSw = 0; + SuggestedWord *nsMaxSw = 0; unsigned int maxIndex = 0; float maxNs = 0; for (unsigned int i = 0; i < size; ++i) { - SuggestedWord* tempSw = swBuffer[i]; + SuggestedWord *tempSw = swBuffer[i]; if (!tempSw) { continue; } @@ -131,13 +132,13 @@ class WordsPriorityQueue { } } for (unsigned int i = 0; i < size; ++i) { - SuggestedWord* sw = swBuffer[i]; + SuggestedWord *sw = swBuffer[i]; if (!sw) { AKLOGE("SuggestedWord is null %d", i); continue; } const unsigned int wordLength = sw->mWordLength; - char* targetAdr = (char*) outputChars + i * MAX_WORD_LENGTH * sizeof(short); + char *targetAdr = (char*) outputChars + i * MAX_WORD_LENGTH * sizeof(short); frequencies[i] = sw->mScore; memcpy(targetAdr, sw->mWord, (wordLength) * sizeof(short)); if (wordLength < MAX_WORD_LENGTH) { @@ -155,7 +156,7 @@ class WordsPriorityQueue { void clear() { mHighestSuggestedWord = 0; while (!mSuggestions.empty()) { - SuggestedWord* sw = mSuggestions.top(); + SuggestedWord *sw = mSuggestions.top(); if (DEBUG_WORDS_PRIORITY_QUEUE) { AKLOGI("Clear word. %d", sw->mScore); DUMP_WORD(sw->mWord, sw->mWordLength); @@ -172,8 +173,8 @@ class WordsPriorityQueue { DUMP_WORD(mHighestSuggestedWord->mWord, mHighestSuggestedWord->mWordLength); } - float getHighestNormalizedScore(const unsigned short* before, const int beforeLength, - unsigned short** outWord, int *outScore, int *outLength) { + float getHighestNormalizedScore(const unsigned short *before, const int beforeLength, + unsigned short **outWord, int *outScore, int *outLength) { if (!mHighestSuggestedWord) { return 0.0; } @@ -189,7 +190,7 @@ class WordsPriorityQueue { } }; - SuggestedWord* getFreeSuggestedWord(int score, unsigned short* word, + SuggestedWord *getFreeSuggestedWord(int score, unsigned short *word, int wordLength) { for (unsigned int i = 0; i < MAX_WORD_LENGTH; ++i) { if (!mSuggestedWords[i].mUsed) { @@ -200,10 +201,10 @@ class WordsPriorityQueue { return 0; } - static float getNormalizedScore(SuggestedWord* sw, const unsigned short* before, - const int beforeLength, unsigned short** outWord, int *outScore, int *outLength) { + static float getNormalizedScore(SuggestedWord *sw, const unsigned short *before, + const int beforeLength, unsigned short **outWord, int *outScore, int *outLength) { const int score = sw->mScore; - unsigned short* word = sw->mWord; + unsigned short *word = sw->mWord; const int wordLength = sw->mWordLength; if (outScore) { *outScore = score; @@ -223,9 +224,8 @@ class WordsPriorityQueue { Suggestions mSuggestions; const unsigned int MAX_WORDS; const unsigned int MAX_WORD_LENGTH; - SuggestedWord* mSuggestedWords; - SuggestedWord* mHighestSuggestedWord; + SuggestedWord *mSuggestedWords; + SuggestedWord *mHighestSuggestedWord; }; -} - +} // namespace latinime #endif // LATINIME_WORDS_PRIORITY_QUEUE_H diff --git a/native/jni/src/words_priority_queue_pool.h b/native/jni/src/words_priority_queue_pool.h index b4e2bed26..38887291e 100644 --- a/native/jni/src/words_priority_queue_pool.h +++ b/native/jni/src/words_priority_queue_pool.h @@ -17,8 +17,7 @@ #ifndef LATINIME_WORDS_PRIORITY_QUEUE_POOL_H #define LATINIME_WORDS_PRIORITY_QUEUE_POOL_H -#include <assert.h> -#include <new> +#include <cassert> #include "words_priority_queue.h" namespace latinime { @@ -44,11 +43,11 @@ class WordsPriorityQueuePool { } } - WordsPriorityQueue* getMasterQueue() { + WordsPriorityQueue *getMasterQueue() { return mMasterQueue; } - WordsPriorityQueue* getSubQueue(const int wordIndex, const int inputWordLength) { + WordsPriorityQueue *getSubQueue(const int wordIndex, const int inputWordLength) { if (wordIndex >= MULTIPLE_WORDS_SUGGESTION_MAX_WORDS) { return 0; } @@ -70,7 +69,7 @@ class WordsPriorityQueuePool { inline void clearSubQueue(const int wordIndex) { for (int i = 0; i < SUB_QUEUE_MAX_COUNT; ++i) { - WordsPriorityQueue* queue = getSubQueue(wordIndex, i); + WordsPriorityQueue *queue = getSubQueue(wordIndex, i); if (queue) { queue->clear(); } @@ -86,12 +85,11 @@ class WordsPriorityQueuePool { private: DISALLOW_IMPLICIT_CONSTRUCTORS(WordsPriorityQueuePool); - WordsPriorityQueue* mMasterQueue; - WordsPriorityQueue* mSubQueues[SUB_QUEUE_MAX_COUNT * MULTIPLE_WORDS_SUGGESTION_MAX_WORDS]; + WordsPriorityQueue *mMasterQueue; + WordsPriorityQueue *mSubQueues[SUB_QUEUE_MAX_COUNT * MULTIPLE_WORDS_SUGGESTION_MAX_WORDS]; char mMasterQueueBuf[sizeof(WordsPriorityQueue)]; char mSubQueueBuf[MULTIPLE_WORDS_SUGGESTION_MAX_WORDS * SUB_QUEUE_MAX_COUNT * sizeof(WordsPriorityQueue)]; }; -} - +} // namespace latinime #endif // LATINIME_WORDS_PRIORITY_QUEUE_POOL_H diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml index 38a2ecfeb..6bd46ccfb 100644 --- a/tests/AndroidManifest.xml +++ b/tests/AndroidManifest.xml @@ -17,6 +17,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.inputmethod.latin.tests"> + <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="16" /> + <uses-permission android:name="android.permission.READ_CONTACTS" /> <application> diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java index 7790299b0..38e57aaed 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java @@ -216,6 +216,19 @@ public class InputLogicTests extends InputTestsBase { assertEquals("manual pick then separator", EXPECTED_RESULT, mTextView.getText().toString()); } + public void testManualPickThenStripperThenPick() { + final String WORD_TO_TYPE = "this"; + final String STRIPPER = "\n"; + final String EXPECTED_RESULT = "this\nthis"; + type(WORD_TO_TYPE); + pickSuggestionManually(0, WORD_TO_TYPE); + type(STRIPPER); + type(WORD_TO_TYPE); + pickSuggestionManually(0, WORD_TO_TYPE); + assertEquals("manual pick then \\n then manual pick", EXPECTED_RESULT, + mTextView.getText().toString()); + } + public void testManualPickThenSpaceThenType() { final String WORD1_TO_TYPE = "this"; final String WORD2_TO_TYPE = " is"; diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk index 9e8dbe0f8..e9c11acc4 100644 --- a/tools/dicttool/Android.mk +++ b/tools/dicttool/Android.mk @@ -16,9 +16,16 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-java-files-under,src) +MAKEDICT_CORE_SOURCE_DIRECTORY := ../../java/src/com/android/inputmethod/latin/makedict + +LOCAL_MAIN_SRC_FILES := $(call all-java-files-under,$(MAKEDICT_CORE_SOURCE_DIRECTORY)) +LOCAL_TOOL_SRC_FILES := $(call all-java-files-under,src) +LOCAL_SRC_FILES := $(LOCAL_TOOL_SRC_FILES) \ + $(filter-out $(addprefix %/, $(notdir $(LOCAL_TOOL_SRC_FILES))), $(LOCAL_MAIN_SRC_FILES)) \ + $(call all-java-files-under,tests) LOCAL_JAR_MANIFEST := etc/manifest.txt LOCAL_MODULE := dicttool +LOCAL_JAVA_LIBRARIES := junit LOCAL_MODULE_TAGS := eng include $(BUILD_HOST_JAVA_LIBRARY) diff --git a/tools/dicttool/src/android/inputmethod/latin/dicttool/Compress.java b/tools/dicttool/src/android/inputmethod/latin/dicttool/Compress.java index 307f5964c..a76ec50e0 100644 --- a/tools/dicttool/src/android/inputmethod/latin/dicttool/Compress.java +++ b/tools/dicttool/src/android/inputmethod/latin/dicttool/Compress.java @@ -55,11 +55,10 @@ public class Compress { return "compress <filename>: Compresses a file using gzip compression"; } - public int getArity() { - return 1; - } - public void run() throws IOException { + if (mArgs.length < 1) { + throw new RuntimeException("Not enough arguments for command " + COMMAND); + } final String inFilename = mArgs[0]; final String outFilename = inFilename + SUFFIX; final FileInputStream input = new FileInputStream(new File(inFilename)); @@ -79,11 +78,10 @@ public class Compress { return "uncompress <filename>: Uncompresses a file compressed with gzip compression"; } - public int getArity() { - return 1; - } - public void run() throws IOException { + if (mArgs.length < 1) { + throw new RuntimeException("Not enough arguments for command " + COMMAND); + } final String inFilename = mArgs[0]; final String outFilename = inFilename + SUFFIX; final FileInputStream input = new FileInputStream(new File(inFilename)); diff --git a/tools/makedict/src/com/android/inputmethod/latin/makedict/DictionaryMaker.java b/tools/dicttool/src/android/inputmethod/latin/dicttool/DictionaryMaker.java index 5e3921573..9ebd3bbdd 100644 --- a/tools/makedict/src/com/android/inputmethod/latin/makedict/DictionaryMaker.java +++ b/tools/dicttool/src/android/inputmethod/latin/dicttool/DictionaryMaker.java @@ -14,7 +14,12 @@ * the License. */ -package com.android.inputmethod.latin.makedict; +package com.android.inputmethod.latin.dicttool; + +import com.android.inputmethod.latin.makedict.BinaryDictInputOutput; +import com.android.inputmethod.latin.makedict.FusionDictionary; +import com.android.inputmethod.latin.makedict.MakedictLog; +import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import java.io.File; import java.io.FileInputStream; @@ -102,7 +107,11 @@ public class DictionaryMaker { } private void displayHelp() { - MakedictLog.i("Usage: makedict " + MakedictLog.i(getHelp()); + } + + public static String getHelp() { + return "Usage: makedict " + "[-s <unigrams.xml> [-b <bigrams.xml>] [-c <shortcuts.xml>] " + "| -s <binary input>] [-d <binary output format version 2>] " + "[-d1 <binary output format version 1>] [-x <xml output>] [-2]\n" @@ -114,7 +123,7 @@ public class DictionaryMaker { + " are supported. All three can be output at the same time, but the same\n" + " output format cannot be specified several times. The behavior is\n" + " unspecified if the same file is specified for input and output, or for\n" - + " several outputs."); + + " several outputs."; } public Arguments(String[] argsArray) throws IOException { diff --git a/tools/dicttool/src/android/inputmethod/latin/dicttool/Dicttool.java b/tools/dicttool/src/android/inputmethod/latin/dicttool/Dicttool.java index b78be7975..c14ce7b88 100644 --- a/tools/dicttool/src/android/inputmethod/latin/dicttool/Dicttool.java +++ b/tools/dicttool/src/android/inputmethod/latin/dicttool/Dicttool.java @@ -16,7 +16,6 @@ package com.android.inputmethod.latin.dicttool; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -27,7 +26,6 @@ public class Dicttool { public void setArgs(String[] args) throws IllegalArgumentException { mArgs = args; } - abstract public int getArity(); abstract public String getHelp(); abstract public void run() throws Exception; } @@ -37,6 +35,7 @@ public class Dicttool { sCommands.put("info", Info.class); sCommands.put("compress", Compress.Compressor.class); sCommands.put("uncompress", Compress.Uncompressor.class); + sCommands.put("makedict", Makedict.class); } private static Command getCommandInstance(final String commandName) { @@ -62,59 +61,33 @@ public class Dicttool { return sCommands.containsKey(commandName); } - private String mPreviousCommand = null; // local to the getNextCommand function - private Command getNextCommand(final ArrayList<String> arguments) { - final String firstArgument = arguments.get(0); - final String commandName; - if (isCommand(firstArgument)) { - commandName = firstArgument; - arguments.remove(0); - } else if (isCommand(mPreviousCommand)) { - commandName = mPreviousCommand; - } else { - throw new RuntimeException("Unknown command : " + firstArgument); + private Command getCommand(final String[] arguments) { + final String commandName = arguments[0]; + if (!isCommand(commandName)) { + throw new RuntimeException("Unknown command : " + commandName); } final Command command = getCommandInstance(commandName); - final int arity = command.getArity(); - if (arguments.size() < arity) { - throw new RuntimeException("Not enough arguments to command " + commandName); - } - final String[] argsArray = new String[arity]; - arguments.subList(0, arity).toArray(argsArray); - for (int i = 0; i < arity; ++i) { - // For some reason, ArrayList#removeRange is protected - arguments.remove(0); - } + final String[] argsArray = Arrays.copyOfRange(arguments, 1, arguments.length); command.setArgs(argsArray); - mPreviousCommand = commandName; return command; } - private void execute(final ArrayList<String> arguments) { - ArrayList<Command> commandsToExecute = new ArrayList<Command>(); - while (!arguments.isEmpty()) { - commandsToExecute.add(getNextCommand(arguments)); - } - for (final Command command : commandsToExecute) { - try { - command.run(); - } catch (Exception e) { - System.out.println("Exception while processing command " - + command.getClass().getSimpleName() + " : " + e); - return; - } + private void execute(final String[] arguments) { + final Command command = getCommand(arguments); + try { + command.run(); + } catch (Exception e) { + System.out.println("Exception while processing command " + + command.getClass().getSimpleName() + " : " + e); + return; } } - public static void main(final String[] args) { - if (0 == args.length) { + public static void main(final String[] arguments) { + if (0 == arguments.length) { help(); return; } - if (!isCommand(args[0])) throw new RuntimeException("Unknown command : " + args[0]); - - final ArrayList<String> arguments = new ArrayList<String>(args.length); - arguments.addAll(Arrays.asList(args)); new Dicttool().execute(arguments); } } diff --git a/tools/dicttool/src/android/inputmethod/latin/dicttool/Info.java b/tools/dicttool/src/android/inputmethod/latin/dicttool/Info.java index cb032dd3b..e59261706 100644 --- a/tools/dicttool/src/android/inputmethod/latin/dicttool/Info.java +++ b/tools/dicttool/src/android/inputmethod/latin/dicttool/Info.java @@ -17,6 +17,8 @@ package com.android.inputmethod.latin.dicttool; public class Info extends Dicttool.Command { + public static final String COMMAND = "info"; + public Info() { } @@ -24,12 +26,11 @@ public class Info extends Dicttool.Command { return "info <filename>: prints various information about a dictionary file"; } - public int getArity() { - return 1; - } - public void run() { // TODO: implement this + if (mArgs.length < 1) { + throw new RuntimeException("Not enough arguments for command " + COMMAND); + } System.out.println("Not implemented yet"); } } diff --git a/tools/dicttool/src/android/inputmethod/latin/dicttool/Makedict.java b/tools/dicttool/src/android/inputmethod/latin/dicttool/Makedict.java new file mode 100644 index 000000000..c004cfbe4 --- /dev/null +++ b/tools/dicttool/src/android/inputmethod/latin/dicttool/Makedict.java @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin.dicttool; + +import com.android.inputmethod.latin.makedict.UnsupportedFormatException; + +import java.io.FileNotFoundException; +import java.io.IOException; +import javax.xml.parsers.ParserConfigurationException; +import org.xml.sax.SAXException; + +public class Makedict extends Dicttool.Command { + public static final String COMMAND = "makedict"; + + public Makedict() { + } + + public String getHelp() { + return DictionaryMaker.Arguments.getHelp(); + } + + public void run() throws FileNotFoundException, IOException, ParserConfigurationException, + SAXException, UnsupportedFormatException { + DictionaryMaker.main(mArgs); + } +} diff --git a/tools/makedict/src/com/android/inputmethod/latin/makedict/MakedictLog.java b/tools/dicttool/src/android/inputmethod/latin/dicttool/MakedictLog.java index 7eccff2b4..7eccff2b4 100644 --- a/tools/makedict/src/com/android/inputmethod/latin/makedict/MakedictLog.java +++ b/tools/dicttool/src/android/inputmethod/latin/dicttool/MakedictLog.java diff --git a/tools/makedict/src/com/android/inputmethod/latin/makedict/XmlDictInputOutput.java b/tools/dicttool/src/android/inputmethod/latin/dicttool/XmlDictInputOutput.java index 52f124dfb..8e2e73505 100644 --- a/tools/makedict/src/com/android/inputmethod/latin/makedict/XmlDictInputOutput.java +++ b/tools/dicttool/src/android/inputmethod/latin/dicttool/XmlDictInputOutput.java @@ -14,11 +14,13 @@ * the License. */ -package com.android.inputmethod.latin.makedict; +package com.android.inputmethod.latin.dicttool; +import com.android.inputmethod.latin.makedict.FusionDictionary; import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.Node; import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; +import com.android.inputmethod.latin.makedict.Word; import java.io.IOException; import java.io.InputStream; diff --git a/tools/makedict/tests/com/android/inputmethod/latin/BinaryDictInputOutputTest.java b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictInputOutputTest.java index 24042f120..24042f120 100644 --- a/tools/makedict/tests/com/android/inputmethod/latin/BinaryDictInputOutputTest.java +++ b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictInputOutputTest.java diff --git a/tools/dicttool/tests/etc/test-dicttool.sh b/tools/dicttool/tests/etc/test-dicttool.sh new file mode 100755 index 000000000..8834611cd --- /dev/null +++ b/tools/dicttool/tests/etc/test-dicttool.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright 2012, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +java -classpath ${ANDROID_HOST_OUT}/framework/junit.jar:${ANDROID_HOST_OUT}/../common/obj/JAVA_LIBRARIES/dicttool_intermediates/classes junit.textui.TestRunner com.android.inputmethod.latin.makedict.BinaryDictInputOutputTest diff --git a/tools/makedict/Android.mk b/tools/makedict/Android.mk index 7b5dee2ce..cac3a831c 100644 --- a/tools/makedict/Android.mk +++ b/tools/makedict/Android.mk @@ -20,9 +20,7 @@ MAKEDICT_CORE_SOURCE_DIRECTORY := ../../java/src/com/android/inputmethod/latin/m LOCAL_MAIN_SRC_FILES := $(call all-java-files-under,$(MAKEDICT_CORE_SOURCE_DIRECTORY)) LOCAL_TOOL_SRC_FILES := $(call all-java-files-under,src) -LOCAL_SRC_FILES := $(LOCAL_TOOL_SRC_FILES) \ - $(filter-out $(addprefix %, $(LOCAL_TOOL_SRC_FILES)), $(LOCAL_MAIN_SRC_FILES)) -LOCAL_SRC_FILES += $(call all-java-files-under,tests) +LOCAL_SRC_FILES := $(LOCAL_TOOL_SRC_FILES) LOCAL_JAR_MANIFEST := etc/manifest.txt LOCAL_MODULE := makedict LOCAL_JAVA_LIBRARIES := junit diff --git a/tools/maketext/res/values-af/donottranslate-more-keys.xml b/tools/maketext/res/values-af/donottranslate-more-keys.xml new file mode 100644 index 000000000..ee96f442d --- /dev/null +++ b/tools/maketext/res/values-af/donottranslate-more-keys.xml @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- This is the same as Dutch except more keys of y and demoting vowels with diaeresis. --> + <!-- U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + U+00E6: "æ" LATIN SMALL LETTER AE + U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> + <string name="more_keys_for_a">á,â,ä,à,æ,ã,å,ā</string> + <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> + <string name="more_keys_for_e">é,è,ê,ë,ę,ė,ē</string> + <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + U+0133: "ij" LATIN SMALL LIGATURE IJ --> + <string name="more_keys_for_i">í,ì,ï,î,į,ī,ij</string> + <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + U+0153: "œ" LATIN SMALL LIGATURE OE + U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + U+014D: "ō" LATIN SMALL LETTER O WITH MACRON --> + <string name="more_keys_for_o">ó,ô,ö,ò,õ,œ,ø,ō</string> + <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> + <string name="more_keys_for_u">ú,û,ü,ù,ū</string> + <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> + <string name="more_keys_for_n">ñ,ń</string> + <string name="more_keys_for_y">ý,ŷ,ÿ,ij</string> + <!-- U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + U+0133: "ij" LATIN SMALL LIGATURE IJ --> + <string name="more_keys_for_y">ý,ij</string> +</resources> diff --git a/tools/maketext/res/values-be/donottranslate-more-keys.xml b/tools/maketext/res/values-be/donottranslate-more-keys.xml index 835553a1f..a2056e932 100644 --- a/tools/maketext/res/values-be/donottranslate-more-keys.xml +++ b/tools/maketext/res/values-be/donottranslate-more-keys.xml @@ -20,12 +20,16 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- U+045E: "ў" CYRILLIC SMALL LETTER SHORT U --> <string name="keylabel_for_east_slavic_row1_9">ў</string> + <!-- U+0451: "ё" CYRILLIC SMALL LETTER IO --> + <string name="keylabel_for_east_slavic_row1_12">ё</string> <!-- U+044B: "ы" CYRILLIC SMALL LETTER YERU --> <string name="keylabel_for_east_slavic_row2_1">ы</string> + <!-- U+044D: "э" CYRILLIC SMALL LETTER E --> + <string name="keylabel_for_east_slavic_row2_11">э</string> <!-- U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I --> <string name="keylabel_for_east_slavic_row3_5">і</string> - <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> - <string name="more_keys_for_cyrillic_ha">ъ</string> + <!-- U+0451: "ё" CYRILLIC SMALL LETTER IO --> + <string name="more_keys_for_cyrillic_ie">ё</string> <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> <string name="more_keys_for_cyrillic_soft_sign">ъ</string> </resources> diff --git a/tools/maketext/res/values-ky/donottranslate-more-keys.xml b/tools/maketext/res/values-ky/donottranslate-more-keys.xml index fd90248b2..a11ecf942 100644 --- a/tools/maketext/res/values-ky/donottranslate-more-keys.xml +++ b/tools/maketext/res/values-ky/donottranslate-more-keys.xml @@ -20,16 +20,20 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- U+0449: "щ" CYRILLIC SMALL LETTER SHCHA --> <string name="keylabel_for_east_slavic_row1_9">щ</string> + <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> + <string name="keylabel_for_east_slavic_row1_12">ъ</string> <!-- U+044B: "ы" CYRILLIC SMALL LETTER YERU --> <string name="keylabel_for_east_slavic_row2_1">ы</string> + <!-- U+044D: "э" CYRILLIC SMALL LETTER E --> + <string name="keylabel_for_east_slavic_row2_11">э</string> <!-- U+0438: "и" CYRILLIC SMALL LETTER I --> <string name="keylabel_for_east_slavic_row3_5">и</string> <!-- U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U --> <string name="more_keys_for_cyrillic_u">ү</string> + <!-- U+0451: "ё" CYRILLIC SMALL LETTER IO --> + <string name="more_keys_for_cyrillic_ie">ё</string> <!-- U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER --> <string name="more_keys_for_cyrillic_en">ң</string> - <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> - <string name="more_keys_for_cyrillic_ha">ъ</string> <!-- U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O --> <string name="more_keys_for_cyrillic_o">ө</string> <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> diff --git a/tools/maketext/res/values-ru/donottranslate-more-keys.xml b/tools/maketext/res/values-ru/donottranslate-more-keys.xml index 0bb57074c..82bed784e 100644 --- a/tools/maketext/res/values-ru/donottranslate-more-keys.xml +++ b/tools/maketext/res/values-ru/donottranslate-more-keys.xml @@ -20,14 +20,16 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- U+0449: "щ" CYRILLIC SMALL LETTER SHCHA --> <string name="keylabel_for_east_slavic_row1_9">щ</string> + <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> + <string name="keylabel_for_east_slavic_row1_12">ъ</string> <!-- U+044B: "ы" CYRILLIC SMALL LETTER YERU --> <string name="keylabel_for_east_slavic_row2_1">ы</string> + <!-- U+044D: "э" CYRILLIC SMALL LETTER E --> + <string name="keylabel_for_east_slavic_row2_11">э</string> <!-- U+0438: "и" CYRILLIC SMALL LETTER I --> <string name="keylabel_for_east_slavic_row3_5">и</string> <!-- U+0451: "ё" CYRILLIC SMALL LETTER IO --> - <string name="more_keys_for_cyrillic_ye">ё</string> - <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> - <string name="more_keys_for_cyrillic_ha">ъ</string> + <string name="more_keys_for_cyrillic_ie">ё</string> <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> <string name="more_keys_for_cyrillic_soft_sign">ъ</string> </resources> diff --git a/tools/maketext/res/values-sr/donottranslate-more-keys.xml b/tools/maketext/res/values-sr/donottranslate-more-keys.xml index e85d3d7a2..dcf0e857e 100644 --- a/tools/maketext/res/values-sr/donottranslate-more-keys.xml +++ b/tools/maketext/res/values-sr/donottranslate-more-keys.xml @@ -18,6 +18,24 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- TODO: Move these to sr-Latn once we can handle IETF language tag with script name specified. + BEGIN: More keys definitions for Serbian (Latin) + U+0161: "š" LATIN SMALL LETTER S WITH CARON + U+00DF: "ß" LATIN SMALL LETTER SHARP S + U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + <string name="more_keys_for_s">š,ß,ś</string> + U+010D: "č" LATIN SMALL LETTER C WITH CARON + U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + <string name="more_keys_for_c">č,ç,ć</string> + U+010F: "ď" LATIN SMALL LETTER D WITH CARON + <string name="more_keys_for_d">ď</string> + U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + <string name="more_keys_for_z">ž,ź,ż</string> + END: More keys definitions for Serbian (Latin) --> + <!-- BEGIN: More keys definitions for Serbian (Cyrillic) --> <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE --> <string name="keylabel_for_south_slavic_row1_6">з</string> <!-- U+045B: "ћ" CYRILLIC SMALL LETTER TSHE --> @@ -30,6 +48,7 @@ <string name="more_keys_for_cyrillic_ie">ѐ</string> <!-- U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE --> <string name="more_keys_for_cyrillic_i">ѝ</string> + <!-- END: More keys definitions for Serbian (Cyrillic) --> <!-- U+2018: "‘" LEFT SINGLE QUOTATION MARK U+2019: "’" RIGHT SINGLE QUOTATION MARK U+201A: "‚" SINGLE LOW-9 QUOTATION MARK diff --git a/tools/maketext/res/values-sw/donottranslate-more-keys.xml b/tools/maketext/res/values-sw/donottranslate-more-keys.xml new file mode 100644 index 000000000..968a80c1c --- /dev/null +++ b/tools/maketext/res/values-sw/donottranslate-more-keys.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- This is the same as English except more_keys_for_g. --> + <!-- U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + U+00E6: "æ" LATIN SMALL LETTER AE + U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> + <string name="more_keys_for_a">à,á,â,ä,æ,ã,å,ā</string> + <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> + <string name="more_keys_for_e">è,é,ê,ë,ē</string> + <!-- U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE --> + <string name="more_keys_for_i">î,ï,í,ī,ì</string> + <!-- U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + U+0153: "œ" LATIN SMALL LIGATURE OE + U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE --> + <string name="more_keys_for_o">ô,ö,ò,ó,œ,ø,ō,õ</string> + <!-- U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> + <string name="more_keys_for_u">û,ü,ù,ú,ū</string> + <!-- U+00DF: "ß" LATIN SMALL LETTER SHARP S --> + <string name="more_keys_for_s">ß</string> + <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE --> + <string name="more_keys_for_n">ñ</string> + <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA --> + <string name="more_keys_for_c">ç</string> + <string name="more_keys_for_g">g\'</string> +</resources> diff --git a/tools/maketext/res/values-tl/donottranslate-more-keys.xml b/tools/maketext/res/values-tl/donottranslate-more-keys.xml new file mode 100644 index 000000000..383d55ccf --- /dev/null +++ b/tools/maketext/res/values-tl/donottranslate-more-keys.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + U+00E6: "æ" LATIN SMALL LETTER AE + U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + U+00AA: "ª" FEMININE ORDINAL INDICATOR --> + <string name="more_keys_for_a">á,à,ä,â,ã,å,ą,æ,ā,ª</string> + <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> + <string name="more_keys_for_e">é,è,ë,ê,ę,ė,ē</string> + <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> + <string name="more_keys_for_i">í,ï,ì,î,į,ī</string> + <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + U+0153: "œ" LATIN SMALL LIGATURE OE + U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + U+00BA: "º" MASCULINE ORDINAL INDICATOR --> + <string name="more_keys_for_o">ó,ò,ö,ô,õ,ø,œ,ō,º</string> + <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> + <string name="more_keys_for_u">ú,ü,ù,û,ū</string> + <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> + <string name="more_keys_for_n">ñ,ń</string> + <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + U+010D: "č" LATIN SMALL LETTER C WITH CARON --> + <string name="more_keys_for_c">ç,ć,č</string> +</resources> diff --git a/tools/maketext/res/values-uk/donottranslate-more-keys.xml b/tools/maketext/res/values-uk/donottranslate-more-keys.xml index 32397049a..6d4b5f9e1 100644 --- a/tools/maketext/res/values-uk/donottranslate-more-keys.xml +++ b/tools/maketext/res/values-uk/donottranslate-more-keys.xml @@ -20,12 +20,16 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- U+0449: "щ" CYRILLIC SMALL LETTER SHCHA --> <string name="keylabel_for_east_slavic_row1_9">щ</string> + <!-- U+0457: "ї" CYRILLIC SMALL LETTER YI --> + <string name="keylabel_for_east_slavic_row1_12">ї</string> <!-- U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I --> <string name="keylabel_for_east_slavic_row2_1">і</string> + <!-- U+0454: "є" CYRILLIC SMALL LETTER UKRAINIAN IE --> + <string name="keylabel_for_east_slavic_row2_11">є</string> <!-- U+0438: "и" CYRILLIC SMALL LETTER I --> <string name="keylabel_for_east_slavic_row3_5">и</string> - <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> - <string name="more_keys_for_cyrillic_ha">ъ</string> + <!-- U+0491: "ґ" CYRILLIC SMALL LETTER GHE WITH UPTURN --> + <string name="more_keys_for_cyrillic_ghe">ґ</string> <!-- U+0457: "ї" CYRILLIC SMALL LETTER YI --> <string name="more_keys_for_east_slavic_row2_1">ї</string> <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> diff --git a/tools/maketext/res/values-zu/donottranslate-more-keys.xml b/tools/maketext/res/values-zu/donottranslate-more-keys.xml new file mode 100644 index 000000000..191791530 --- /dev/null +++ b/tools/maketext/res/values-zu/donottranslate-more-keys.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- This is the same as English --> + <!-- U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + U+00E6: "æ" LATIN SMALL LETTER AE + U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> + <string name="more_keys_for_a">à,á,â,ä,æ,ã,å,ā</string> + <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> + <string name="more_keys_for_e">è,é,ê,ë,ē</string> + <!-- U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE --> + <string name="more_keys_for_i">î,ï,í,ī,ì</string> + <!-- U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + U+0153: "œ" LATIN SMALL LIGATURE OE + U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE --> + <string name="more_keys_for_o">ô,ö,ò,ó,œ,ø,ō,õ</string> + <!-- U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> + <string name="more_keys_for_u">û,ü,ù,ú,ū</string> + <!-- U+00DF: "ß" LATIN SMALL LETTER SHARP S --> + <string name="more_keys_for_s">ß</string> + <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE --> + <string name="more_keys_for_n">ñ</string> + <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA --> + <string name="more_keys_for_c">ç</string> +</resources> diff --git a/tools/maketext/res/values/donottranslate-more-keys.xml b/tools/maketext/res/values/donottranslate-more-keys.xml index 7f1940a57..543e93620 100644 --- a/tools/maketext/res/values/donottranslate-more-keys.xml +++ b/tools/maketext/res/values/donottranslate-more-keys.xml @@ -44,12 +44,13 @@ <string name="more_keys_for_nordic_row2_10"></string> <string name="more_keys_for_nordic_row2_11"></string> <string name="keylabel_for_east_slavic_row1_9"></string> + <string name="keylabel_for_east_slavic_row1_12"></string> <string name="keylabel_for_east_slavic_row2_1"></string> + <string name="keylabel_for_east_slavic_row2_11"></string> <string name="keylabel_for_east_slavic_row3_5"></string> <string name="more_keys_for_cyrillic_u"></string> - <string name="more_keys_for_cyrillic_ye"></string> <string name="more_keys_for_cyrillic_en"></string> - <string name="more_keys_for_cyrillic_ha"></string> + <string name="more_keys_for_cyrillic_ghe"></string> <string name="more_keys_for_east_slavic_row2_1"></string> <string name="more_keys_for_cyrillic_o"></string> <string name="more_keys_for_cyrillic_soft_sign"></string> |