diff options
129 files changed, 1737 insertions, 964 deletions
diff --git a/java/res/layout/sound_effect_volume_dialog.xml b/java/res/layout/seek_bar_dialog.xml index 294663006..a47e9a038 100644 --- a/java/res/layout/sound_effect_volume_dialog.xml +++ b/java/res/layout/seek_bar_dialog.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2011, The Android Open Source Project +** 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. @@ -30,15 +30,14 @@ android:layout_height="wrap_content" android:gravity="center_horizontal" android:layout_margin="10dp"> - <TextView android:id="@+id/sound_effect_volume_value" + <TextView android:id="@+id/seek_bar_dialog_value" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20dp"/> </LinearLayout> <SeekBar - android:id="@+id/sound_effect_volume_bar" + android:id="@+id/seek_bar_dialog_bar" android:layout_width="match_parent" android:layout_height="wrap_content" - android:max="100" android:layout_margin="10dp"/> </LinearLayout> diff --git a/java/res/layout/vibration_settings_dialog.xml b/java/res/layout/vibration_settings_dialog.xml deleted file mode 100644 index c9fb6ec4e..000000000 --- a/java/res/layout/vibration_settings_dialog.xml +++ /dev/null @@ -1,49 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** 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. -*/ ---> - -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_margin="10dp"> - <LinearLayout - android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center_horizontal" - android:layout_margin="10dp"> - <TextView android:id="@+id/vibration_value" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textSize="20dp"/> - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/settings_ms" - android:textSize="20dp"/> - </LinearLayout> - <SeekBar - android:id="@+id/vibration_settings" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:max="250" - android:layout_margin="10dp"/> -</LinearLayout> diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml index 18e63f317..80b92320a 100644 --- a/java/res/values-af/strings.xml +++ b/java/res/values-af/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Sleutelopspringer-wagperiode"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Geen wagperiode nie"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Verstek"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Stel kontakname voor"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Gebruik name van kontakte vir voorstelle en korreksies"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dubbelspasie-punt"</string> diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml index 4f66a1676..a59e757ef 100644 --- a/java/res/values-am/strings.xml +++ b/java/res/values-am/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"የቁልፍ ብቅ ባይ መዘግየትን ያስወገዳል"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"የዘገየ የለም"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ነባሪ"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"የዕውቂያ ስም ጠቁም"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"ከዕውቂያዎች ለጥቆማዎች እና ማስተካከያዎች ስሞች ተጠቀም"</string> <string name="use_double_space_period" msgid="8781529969425082860">"የድርብ-ክፍተት ነጥብ"</string> diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml index a3877ed49..c3691cd7a 100644 --- a/java/res/values-ar/strings.xml +++ b/java/res/values-ar/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"تأخير إزالة النافذة المنبثقة الأساسية"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"بلا تأخير"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"افتراضي"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"اقتراح أسماء جهات الاتصال"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"استخدام الأسماء من جهات الاتصال للاقتراحات والتصحيحات"</string> <string name="use_double_space_period" msgid="8781529969425082860">"نقطة المسافة المزدوجة"</string> diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml index bf396943f..edbd9c3ac 100644 --- a/java/res/values-be/strings.xml +++ b/java/res/values-be/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Затрым. скр. падк. клав."</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Няма затрымкі"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Па змаўчанні"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Прапан. імёны кантактаў"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Выкарыстоўваць імёны са спісу кантактаў для прапаноў і выпраўл."</string> <string name="use_double_space_period" msgid="8781529969425082860">"Падвойны iнтэрвал"</string> diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml index 27d3ac7d5..25030d2b2 100644 --- a/java/res/values-bg/strings.xml +++ b/java/res/values-bg/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Отхвърляне на подсказката"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без задържане"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"По подразбиране"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Предложения за контакти"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Използване на имена от „Контакти“ за предложения и поправки"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Точка чрез двоен интервал"</string> diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml index 0182dd492..3f73e9085 100644 --- a/java/res/values-ca/strings.xml +++ b/java/res/values-ca/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Retard en ampliar tecla"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sense retard"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predeterminat"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Suggereix noms de contactes"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilitza els noms de contactes per fer suggeriments i correccions"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punt amb doble espai"</string> diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml index 806ac1291..d438ad6e5 100644 --- a/java/res/values-cs/strings.xml +++ b/java/res/values-cs/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Prodleva vysk. okna klávesnice"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez prodlevy"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Výchozí"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Navrhovat jména kontaktů"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Použít jména ze seznamu kontaktů k návrhům a opravám"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Tečka dvojitým mezerníkem"</string> diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml index 4fbfe905d..da83d1cac 100644 --- a/java/res/values-da/strings.xml +++ b/java/res/values-da/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Forsink. afvis. af taste-pop op"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Ingen forsink."</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Foreslå navne på kontakter"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Brug navne fra Kontaktpersoner til forslag og rettelser"</string> <string name="use_double_space_period" msgid="8781529969425082860">"To mellemrum for punktum"</string> diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml index 1fad9e710..3cdb039af 100644 --- a/java/res/values-de/strings.xml +++ b/java/res/values-de/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Tasten-Pop-up"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Keine Verzögerung"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Kontakte vorschlagen"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Namen aus \"Kontakte\" als Vorschläge und Korrekturmöglichkeiten anzeigen"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punkt plus Leerzeichen"</string> diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml index 2b99e7e00..8dcc202ce 100644 --- a/java/res/values-el/strings.xml +++ b/java/res/values-el/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Χρόνος εξαφ. αναδ. παραθ."</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Χωρίς καθυστέρ."</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Προεπιλογή"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Πρόταση ονομάτων επαφών"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Χρησιμοποιήστε ονόματα από τις Επαφές για προτάσεις και διορθ."</string> <string name="use_double_space_period" msgid="8781529969425082860">"Τελεία με διπλό πάτημα πλήκτρ.διαστ."</string> diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml index 652d5aa46..7a3b3e612 100644 --- a/java/res/values-en-rGB/strings.xml +++ b/java/res/values-en-rGB/strings.xml @@ -42,12 +42,12 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Key pop-up dismiss delay"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"No delay"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Default"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Suggest Contact names"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Use names from Contacts for suggestions and corrections"</string> - <!-- no translation found for use_double_space_period (8781529969425082860) --> - <skip /> - <!-- no translation found for use_double_space_period_summary (6532892187247952799) --> - <skip /> + <string name="use_double_space_period" msgid="8781529969425082860">"Double-space full stop"</string> + <string name="use_double_space_period_summary" msgid="6532892187247952799">"Double tap on spacebar inserts a full stop followed by a space"</string> <string name="auto_cap" msgid="1719746674854628252">"Auto-capitalisation"</string> <string name="auto_cap_summary" msgid="7934452761022946874">"Capitalise the first word of each sentence"</string> <string name="configure_dictionaries_title" msgid="4238652338556902049">"Add-on dictionaries"</string> diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml index 9e87970de..ec9614fbe 100644 --- a/java/res/values-es-rUS/strings.xml +++ b/java/res/values-es-rUS/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Retraso en rechazo de alerta de tecla"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sin demora"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predeterminada"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nombres de contacto"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Usar nombres de los contactos para sugerencias y correcciones"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punto y doble espacio"</string> @@ -63,7 +65,7 @@ <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Muy agresivo"</string> <string name="bigram_prediction" msgid="1084449187723948550">"Sugerencias para la palabra siguiente"</string> <string name="bigram_prediction_summary" msgid="3896362682751109677">"Usa la palabra anterior para hacer sugerencias"</string> - <string name="gesture_input" msgid="826951152254563827">"Habilitar escritura gestual"</string> + <string name="gesture_input" msgid="826951152254563827">"Activar escritura gestual"</string> <string name="gesture_input_summary" msgid="9180350639305731231">"Ingresa una palabra al deslizarte sobre las letras."</string> <string name="gesture_preview_trail" msgid="3802333369335722221">"Mostrar recorrido de gesto"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Vista previa dinámica flotante"</string> diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml index 24335e65a..061516a62 100644 --- a/java/res/values-es/strings.xml +++ b/java/res/values-es/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Retraso al ampliar tecla"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sin retraso"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predeterminado"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir contactos"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizar nombres de contactos para sugerencias y correcciones"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punto y espacio"</string> diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml index 25dcdca73..1158a2126 100644 --- a/java/res/values-et/strings.xml +++ b/java/res/values-et/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Hüpiku loobumisviivitus"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Viivituseta"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Vaikeseade"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Soovita kontaktkirjeid"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Kasuta soovitusteks ja parandusteks nimesid kontaktiloendist"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punkt tühikuklahviga"</string> diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml index d4a0e66b0..1fb577cd9 100644 --- a/java/res/values-fa/strings.xml +++ b/java/res/values-fa/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"تأخیر در رد کردن کلید نمایشی"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"بدون تأخیر"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"پیشفرض"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"پیشنهاد نامهای مخاطب"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"برای پیشنهاد و تصحیح از نام مخاطبین استفاده شود"</string> <string name="use_double_space_period" msgid="8781529969425082860">"نقطه با دو فاصله"</string> diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml index 36890d95a..9064e4a83 100644 --- a/java/res/values-fi/strings.xml +++ b/java/res/values-fi/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Näppäimen hylkäysviive"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Ei viivettä"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Oletus"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Ehdota yhteystietojen nimiä"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Käytä yhteystietojen nimiä ehdotuksissa ja korjauksissa"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Kaksoisvälilyönti = piste"</string> diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml index 3f895325e..c251d27dc 100644 --- a/java/res/values-fr/strings.xml +++ b/java/res/values-fr/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Masquer touche agrandie"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sans délai"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Par défaut"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Proposer noms de contacts"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utiliser des noms de contacts pour les suggestions et corrections"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Point et espace"</string> diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml index 6537b859e..738368205 100644 --- a/java/res/values-hi/strings.xml +++ b/java/res/values-hi/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"कुंजी पॉपअप खारिज़ विलंब"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"कोई विलंब नहीं"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"डिफ़ॉल्ट"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"संपर्क नाम सुझाएं"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"सुझाव और सुधार के लिए संपर्क से नामों का उपयोग करें"</string> <string name="use_double_space_period" msgid="8781529969425082860">"दोहरे स्पेस वाला पीरियड"</string> diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml index d788c1f0e..014481ae9 100644 --- a/java/res/values-hr/strings.xml +++ b/java/res/values-hr/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Odgoda prikaza tipki"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez odgode"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Zadano"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Predlaži imena kontakata"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Upotreba imena iz Kontakata za prijedloge i ispravke"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Točka s dva razmaka"</string> diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml index 1df863927..f146c82ae 100644 --- a/java/res/values-hu/strings.xml +++ b/java/res/values-hu/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Gombeltüntetés késése"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Nincs késés"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Alapbeállítás"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Javasolt névjegyek"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"A névjegyek használata a javaslatokhoz és javításokhoz"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dupla szóköz: pont"</string> diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml index f26ad38a4..d3ae9a18d 100644 --- a/java/res/values-in/strings.xml +++ b/java/res/values-in/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Tundaan singkir munculan kunci"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Tanpa penundaan"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Default"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Sarankan nama Kontak"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Menggunakan nama dari Kontak untuk saran dan koreksi"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Titik spasi ganda"</string> diff --git a/java/res/values-is/strings.xml b/java/res/values-is/strings.xml index 8ea7461c2..016a1d1e5 100644 --- a/java/res/values-is/strings.xml +++ b/java/res/values-is/strings.xml @@ -64,6 +64,8 @@ <skip /> <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) --> <skip /> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <!-- no translation found for use_contacts_dict (4435317977804180815) --> <skip /> <!-- no translation found for use_contacts_dict_summary (6599983334507879959) --> diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml index a78c5c56a..3efed919d 100644 --- a/java/res/values-it/strings.xml +++ b/java/res/values-it/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Ritardo eliminaz. popup tasto"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Nessun ritardo"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predefinito"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Suggerisci nomi di contatti"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizza nomi di Contatti per suggerimenti e correzioni"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Doppio spazio per punto"</string> diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml index 6542b9fb4..2fec99439 100644 --- a/java/res/values-iw/strings.xml +++ b/java/res/values-iw/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"עיכוב סגירת חלון קופץ של מקש"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"ללא עיכוב"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ברירת מחדל"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"הצע שמות של אנשי קשר"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"השתמש בשמות מרשימת אנשי הקשר עבור הצעות ותיקונים"</string> <string name="use_double_space_period" msgid="8781529969425082860">"רווח כפול לנקודה"</string> diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml index 2b341e116..8d01e75a3 100644 --- a/java/res/values-ja/strings.xml +++ b/java/res/values-ja/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"キーのポップアップ時間"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"すぐに消去"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"デフォルト"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"候補の連絡先名を表示"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"連絡先の名前を使用して候補表示や自動修正を行います"</string> <string name="use_double_space_period" msgid="8781529969425082860">"ダブルスペースピリオド"</string> diff --git a/java/res/values-ka/strings.xml b/java/res/values-ka/strings.xml index ef3014401..b9ffbf6de 100644 --- a/java/res/values-ka/strings.xml +++ b/java/res/values-ka/strings.xml @@ -64,6 +64,8 @@ <skip /> <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) --> <skip /> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <!-- no translation found for use_contacts_dict (4435317977804180815) --> <skip /> <!-- no translation found for use_contacts_dict_summary (6599983334507879959) --> diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml index e7b9d5a75..c0c313a74 100644 --- a/java/res/values-ko/strings.xml +++ b/java/res/values-ko/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"키 팝업 해제 지연"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"지연 없음"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"기본값"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"주소록 이름 활용"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"추천 및 수정에 주소록의 이름 사용"</string> <string name="use_double_space_period" msgid="8781529969425082860">"더블스페이스 마침표"</string> diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml index 5c66e1f22..39fbda6df 100644 --- a/java/res/values-lt/strings.xml +++ b/java/res/values-lt/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Pagr. išš. l. atsis. d."</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Be delsos"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Numatytasis"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Siūlyti kontaktų vardus"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Siūlant ir taisant naudoti vardus iš „Kontaktų“"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Tšk. ir tarp. pal. dukart"</string> diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml index a0cf78e89..6bc47714d 100644 --- a/java/res/values-lv/strings.xml +++ b/java/res/values-lv/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Taust. uzn. loga noraid. aizk."</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez aizkaves"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Noklusējums"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Ieteikt kontaktp. vārdus"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Izmantot kontaktpersonu vārdus kā ieteikumus un labojumus"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dubultpiesk. = punkts"</string> diff --git a/java/res/values-mk/strings.xml b/java/res/values-mk/strings.xml index e199e0316..7758dbbe3 100644 --- a/java/res/values-mk/strings.xml +++ b/java/res/values-mk/strings.xml @@ -64,6 +64,8 @@ <skip /> <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) --> <skip /> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <!-- no translation found for use_contacts_dict (4435317977804180815) --> <skip /> <!-- no translation found for use_contacts_dict_summary (6599983334507879959) --> diff --git a/java/res/values-mn/strings.xml b/java/res/values-mn/strings.xml index 41bf551ba..4d38079aa 100644 --- a/java/res/values-mn/strings.xml +++ b/java/res/values-mn/strings.xml @@ -64,6 +64,8 @@ <skip /> <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) --> <skip /> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <!-- no translation found for use_contacts_dict (4435317977804180815) --> <skip /> <!-- no translation found for use_contacts_dict_summary (6599983334507879959) --> diff --git a/java/res/values-ms/strings.xml b/java/res/values-ms/strings.xml index c1a2f0d09..a0b498369 100644 --- a/java/res/values-ms/strings.xml +++ b/java/res/values-ms/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Pop tmbl knci ketpkn lengah"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Tiada lengah"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Lalai"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Cadangkan nama Kenalan"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Menggunakan nama daripada Kenalan untuk cadangan dan pembetulan"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Titik ruang berganda"</string> diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml index f56ce1127..5bcedc11c 100644 --- a/java/res/values-nb/strings.xml +++ b/java/res/values-nb/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Tregt tastevindu"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"U/ forsinkelse"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Foreslå kontaktnavn"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Bruk navn fra Kontakter til forslag og korrigeringer"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punktum ved doble mellomrom"</string> diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml index 6bd474a19..034b352a2 100644 --- a/java/res/values-nl/strings.xml +++ b/java/res/values-nl/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Afwijz.vertr. toetspop-up"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Geen vertraging"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standaard"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Contactnamen suggereren"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Namen uit Contacten gebruiken voor suggesties en correcties"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dubbeltik is punt, spatie"</string> diff --git a/java/res/values-pl/strings-appname.xml b/java/res/values-pl/strings-appname.xml index e460644a3..4d244d705 100644 --- a/java/res/values-pl/strings-appname.xml +++ b/java/res/values-pl/strings-appname.xml @@ -21,10 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="178705338187710493">"Klawiatura Android"</string> - <!-- no translation found for spell_checker_service_name (6268342166872202903) --> - <skip /> - <!-- no translation found for english_ime_settings (7470027018752707691) --> - <skip /> - <!-- no translation found for android_spell_checker_settings (8397842018475560441) --> - <skip /> + <string name="spell_checker_service_name" msgid="6268342166872202903">"Sprawdzanie pisowni w Androidzie"</string> + <string name="english_ime_settings" msgid="7470027018752707691">"Ustawienia klawiatury Android"</string> + <string name="android_spell_checker_settings" msgid="8397842018475560441">"Ustawienia sprawdzania pisowni"</string> </resources> diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml index 27fcf60ba..4ddfa8d28 100644 --- a/java/res/values-pl/strings.xml +++ b/java/res/values-pl/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Opóźnienie znikania klawiszy"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez opóźnienia"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Wartość domyślna"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Proponuj osoby z kontaktów"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"W propozycjach i poprawkach użyj nazwisk z kontaktów"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Szybka kropka ze spacją"</string> diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml index 46bd34d72..136470b85 100644 --- a/java/res/values-pt-rPT/strings.xml +++ b/java/res/values-pt-rPT/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Atraso p/ ignorar pop-up"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sem atraso"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predefinido"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nomes de Contactos"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizar nomes dos Contactos para sugestões e correções"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Ponto de espaço duplo"</string> diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml index ce61e0c17..3408dde06 100644 --- a/java/res/values-pt/strings.xml +++ b/java/res/values-pt/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Dispens. atraso chave princ."</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sem atraso"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Padrão"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nomes de contato"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Usar nomes dos Contatos para sugestões e correções"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Duplo espaço p/ ponto"</string> diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml index 5a315f502..90d7357c3 100644 --- a/java/res/values-rm/strings.xml +++ b/java/res/values-rm/strings.xml @@ -61,6 +61,8 @@ <skip /> <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) --> <skip /> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <!-- no translation found for use_contacts_dict (4435317977804180815) --> <skip /> <!-- no translation found for use_contacts_dict_summary (6599983334507879959) --> diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml index 99b82a537..1b0176868 100644 --- a/java/res/values-ro/strings.xml +++ b/java/res/values-ro/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Înt. înch. pop-up esenţ."</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Fără întârziere"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Prestabilit"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugeraţi nume din Agendă"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizaţi numele din Agendă pentru sugestii şi corecţii"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Inserează punct spațiu"</string> diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml index 1075d2994..2f1f7e6e3 100644 --- a/java/res/values-ru/strings.xml +++ b/java/res/values-ru/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Задержка закрытия"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без задержки"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"По умолчанию"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Подсказывать имена"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Подсказывать исправления на основе имен из списка контактов"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Точка с пробелом"</string> diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml index 1ee4f3324..55fae954b 100644 --- a/java/res/values-sk/strings.xml +++ b/java/res/values-sk/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Onesk. zrušenia kľúč. kon. okna"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez oneskorenia"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predvolená"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Navrhnúť mená kontaktov"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Používať mená z Kontaktov na návrhy a opravy"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Bodka s medzerou"</string> diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml index 6ac740651..f8fd82121 100644 --- a/java/res/values-sl/strings.xml +++ b/java/res/values-sl/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Trajanje povečanja tipke"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Brez zakasnitve"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Privzeto"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Predlagaj imena stikov"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Uporaba imen iz stikov za predloge in popravke"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dva presl. za vnos pike"</string> diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml index 1456ae96f..f22fc2fc2 100644 --- a/java/res/values-sr/strings.xml +++ b/java/res/values-sr/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Одложи одбац. иск. прозора тастера"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без одлагања"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Подразумевано"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Предложи имена контаката"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Користи имена из Контаката за предлоге и исправке"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Тачка и размак"</string> diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml index f6426f9a2..ff72c1ab6 100644 --- a/java/res/values-sv/strings.xml +++ b/java/res/values-sv/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Ta bort popup-fördröjning"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Fördröj inte"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Föreslå kontaktnamn"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Använd namn från Kontakter för förslag och korrigeringar"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dubbelt blanksteg = punkt"</string> diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml index 81b9003e8..5d84409c0 100644 --- a/java/res/values-sw/strings.xml +++ b/java/res/values-sw/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Kuchelewesha kutupa kitufe ibukizi"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Hakuna kuchelewa"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Chaguo-msingi"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Pendekeza majini ya Anwani"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Tumia majina kutoka kwa Anwani kwa mapendekezo na marekebisho"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Kitone baada ya nafasi mbili"</string> diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml index d0890987e..6414e8fef 100644 --- a/java/res/values-th/strings.xml +++ b/java/res/values-th/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"หน่วงเวลาก่อนปิดป๊อปอัพหลัก"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"ไม่มีการหน่วงเวลา"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ค่าเริ่มต้น"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"แนะนำชื่อผู้ติดต่อ"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"ใช้ชื่อจากรายชื่อติดต่อสำหรับคำแนะนำและการแก้ไข"</string> <string name="use_double_space_period" msgid="8781529969425082860">"แตะ Space สองครั้งแทรกจุด"</string> diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml index a16032e80..4c6c5329a 100644 --- a/java/res/values-tl/strings.xml +++ b/java/res/values-tl/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Balewala antala key popup"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Walang antala"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Default"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Mungkahi pangalan Contact"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Gamitin pangalan mula Mga Contact sa mga mungkahi\'t pagwawasto"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Double-space period"</string> diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml index 7b3748c84..462f7c938 100644 --- a/java/res/values-tr/strings.xml +++ b/java/res/values-tr/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Tuş popup\'ının kapatılmasını geciktirme"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Gecikme yok"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Varsayılan"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Kişi Adları öner"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Öneri ve düzeltmeler için Kişiler\'deki adları kullan"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Çift boşlukla nokta ekleme"</string> diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml index 532f67147..819b6eaea 100644 --- a/java/res/values-uk/strings.xml +++ b/java/res/values-uk/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Затримка клавіши закриття"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без затримки"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"За умовчанням"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Пропон. імена контактів"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Використ. імена зі списку контактів для пропозицій і виправлень"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Крапка подвійним пробілом"</string> diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml index 2b29120c3..052f60c97 100644 --- a/java/res/values-vi/strings.xml +++ b/java/res/values-vi/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Loại bỏ hiển thị phím trễ"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Không có tgian trễ"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Mặc định"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Đề xuất tên liên hệ"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Sử dụng tên từ Danh bạ cho các đề xuất và chỉnh sửa"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dấu cách đôi"</string> diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml index ed663b753..b119ccdbd 100644 --- a/java/res/values-zh-rCN/strings.xml +++ b/java/res/values-zh-rCN/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"弹出字符隐藏延迟"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"无延迟"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"默认"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"联系人姓名建议"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"使用联系人中的姓名提供建议和更正"</string> <string name="use_double_space_period" msgid="8781529969425082860">"双击空格插入句号"</string> diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml index 28d32cf38..02737c4a7 100644 --- a/java/res/values-zh-rTW/strings.xml +++ b/java/res/values-zh-rTW/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"關閉彈出式鍵盤的延遲時間"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"不延遲"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"預設"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"建議聯絡人名稱"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"根據「聯絡人」名稱提供建議與修正"</string> <string name="use_double_space_period" msgid="8781529969425082860">"輕按兩下空格鍵即插入句號"</string> diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml index 575a687b5..65d23515e 100644 --- a/java/res/values-zu/strings.xml +++ b/java/res/values-zu/strings.xml @@ -42,6 +42,8 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Ukuvela kokhiye cashisa ukulibazisa"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Cha ukulibazisa"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Okuzenzakalelayo"</string> + <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> + <skip /> <string name="use_contacts_dict" msgid="4435317977804180815">"Sikisela amagama Othintana nabo"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Amagama abasebenzisi kusuka Kothintana nabo bokusikisela nokulungisa"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Isikhathi se-Double-space"</string> diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml index a6ea8a061..193a0191e 100644 --- a/java/res/values/donottranslate.xml +++ b/java/res/values/donottranslate.xml @@ -233,6 +233,5 @@ <!-- dictionary pack package name /settings activity (for shared prefs and settings) --> <string name="dictionary_pack_package_name">com.google.android.inputmethod.latin.dictionarypack</string> <string name="dictionary_pack_settings_activity">com.google.android.inputmethod.latin.dictionarypack.DictionarySettingsActivity</string> - <string name="settings_ms">ms</string> <string name="settings_warning_researcher_mode">Attention! You are using the special keyboard for research purposes.</string> </resources> diff --git a/java/res/values/keyboard-heights.xml b/java/res/values/keyboard-heights.xml index 7d85994be..418d3e5b6 100644 --- a/java/res/values/keyboard-heights.xml +++ b/java/res/values/keyboard-heights.xml @@ -33,5 +33,7 @@ <!-- Preferable keyboard height in absolute scale: 48.0mm --> <!-- Xoom --> <item>stingray,283.1337</item> + <!-- Default value for unknown device: empty string --> + <item>DEFAULT,</item> </string-array> </resources> diff --git a/java/res/values/keypress-vibration-durations.xml b/java/res/values/keypress-vibration-durations.xml index 370959c1a..9b1d5431e 100644 --- a/java/res/values/keypress-vibration-durations.xml +++ b/java/res/values/keypress-vibration-durations.xml @@ -24,5 +24,7 @@ <item>tuna,5</item> <item>mako,5</item> <item>manta,16</item> + <!-- Default value for unknown device --> + <item>DEFAULT,10</item> </string-array> </resources> diff --git a/java/res/values/keypress-volumes.xml b/java/res/values/keypress-volumes.xml index d1120694b..047fe0c5f 100644 --- a/java/res/values/keypress-volumes.xml +++ b/java/res/values/keypress-volumes.xml @@ -20,11 +20,13 @@ <resources> <string-array name="keypress_volumes" translatable="false"> <!-- Build.HARDWARE,volume --> - <item>herring,0.5</item> - <item>tuna,0.5</item> - <item>stingray,0.4</item> - <item>grouper,0.3</item> - <item>mako,0.3</item> - <item>manta,0.2</item> + <item>herring,0.5f</item> + <item>tuna,0.5f</item> + <item>stingray,0.4f</item> + <item>grouper,0.3f</item> + <item>mako,0.3f</item> + <item>manta,0.2f</item> + <!-- Default value for unknown device --> + <item>DEFAULT,0.2f</item> </string-array> </resources> diff --git a/java/res/values/phantom-sudden-move-event-device-list.xml b/java/res/values/phantom-sudden-move-event-device-list.xml index 63d12e96e..22f510229 100644 --- a/java/res/values/phantom-sudden-move-event-device-list.xml +++ b/java/res/values/phantom-sudden-move-event-device-list.xml @@ -21,6 +21,9 @@ <string-array name="phantom_sudden_move_event_device_list" translatable="false"> <!-- "Build.HARDWARE,true" that needs "phantom sudden move event" hack. See {@link com.android.inputmethod.keyboard.PointerTracker}. --> - <item>stingray,true</item> <!-- Xoom --> + <!-- Xoom --> + <item>stingray,true</item> + <!-- Default value for unknown device --> + <item>DEFAULT,false</item> </string-array> </resources> diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 2affdebed..5c5442708 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -76,6 +76,9 @@ <!-- Description for delay for dismissing a popup on screen: default value of the delay [CHAR LIMIT=15] --> <string name="key_preview_popup_dismiss_default_delay">Default</string> + <!-- Units abbreviation for the keypress vibration duration (milliseconds) [CHAR LIMIT=10] --> + <string name="settings_keypress_vibration_duration"><xliff:g id="milliseconds">%s</xliff:g>ms</string> + <!-- Option name for enabling or disabling the use of names of people in Contacts for suggestion and correction [CHAR LIMIT=25] --> <string name="use_contacts_dict">Suggest Contact names</string> <!-- Description for option enabling or disabling the use of names of people in Contacts for suggestion and correction [CHAR LIMIT=65] --> diff --git a/java/res/values/sudden-jumping-touch-event-device-list.xml b/java/res/values/sudden-jumping-touch-event-device-list.xml index 543992a81..3fdc0c7e3 100644 --- a/java/res/values/sudden-jumping-touch-event-device-list.xml +++ b/java/res/values/sudden-jumping-touch-event-device-list.xml @@ -21,7 +21,11 @@ <string-array name="sudden_jumping_touch_event_device_list" translatable="false"> <!-- "Build.HARDWARE,true" that needs "sudden jump touch event" hack. See {@link com.android.inputmethod.keyboard.SuddenJumpingTouchEventHandler}. --> - <item>mahimahi,true</item> <!-- Nexus One --> - <item>sholes,true</item> <!-- Droid --> + <!-- Nexus One --> + <item>mahimahi,true</item> + <!-- Droid --> + <item>sholes,true</item> + <!-- Default value for unknown device --> + <item>DEFAULT,false</item> </string-array> </resources> diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java index 0ab84f7b5..0576f666c 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java @@ -71,12 +71,11 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider /** The current keyboard view. */ private KeyboardView mKeyboardView; - public AccessibilityEntityProvider(KeyboardView keyboardView, InputMethodService inputMethod) { + public AccessibilityEntityProvider(final KeyboardView keyboardView, + final InputMethodService inputMethod) { mInputMethodService = inputMethod; - mKeyCodeDescriptionMapper = KeyCodeDescriptionMapper.getInstance(); mAccessibilityUtils = AccessibilityUtils.getInstance(); - setView(keyboardView); } @@ -85,21 +84,19 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider * * @param keyboardView The keyboard view to represent. */ - public void setView(KeyboardView keyboardView) { + public void setView(final KeyboardView keyboardView) { mKeyboardView = keyboardView; updateParentLocation(); // Since this class is constructed lazily, we might not get a subsequent // call to setKeyboard() and therefore need to call it now. - setKeyboard(mKeyboardView.getKeyboard()); + setKeyboard(); } /** * Sets the keyboard represented by this node provider. - * - * @param keyboard The keyboard to represent. */ - public void setKeyboard(Keyboard keyboard) { + public void setKeyboard() { assignVirtualViewIds(); } @@ -112,19 +109,16 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider * @return A populated {@link AccessibilityEvent} for the key. * @see AccessibilityEvent */ - public AccessibilityEvent createAccessibilityEvent(Key key, int eventType) { + public AccessibilityEvent createAccessibilityEvent(final Key key, final int eventType) { final int virtualViewId = generateVirtualViewIdForKey(key); final String keyDescription = getKeyDescription(key); - final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); event.setPackageName(mKeyboardView.getContext().getPackageName()); event.setClassName(key.getClass().getName()); event.setContentDescription(keyDescription); event.setEnabled(true); - final AccessibilityRecordCompat record = new AccessibilityRecordCompat(event); record.setSource(mKeyboardView, virtualViewId); - return event; } @@ -145,68 +139,65 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider * </p> * * @param virtualViewId A client defined virtual view id. - * @return A populated {@link AccessibilityNodeInfoCompat} for a virtual - * descendant or the host View. + * @return A populated {@link AccessibilityNodeInfoCompat} for a virtual descendant or the host + * View. * @see AccessibilityNodeInfoCompat */ @Override - public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int virtualViewId) { - AccessibilityNodeInfoCompat info = null; - + public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(final int virtualViewId) { if (virtualViewId == UNDEFINED) { return null; - } else if (virtualViewId == View.NO_ID) { + } + if (virtualViewId == View.NO_ID) { // We are requested to create an AccessibilityNodeInfo describing // this View, i.e. the root of the virtual sub-tree. - info = AccessibilityNodeInfoCompat.obtain(mKeyboardView); - ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, info); + final AccessibilityNodeInfoCompat rootInfo = + AccessibilityNodeInfoCompat.obtain(mKeyboardView); + ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, rootInfo); // Add the virtual children of the root View. final Keyboard keyboard = mKeyboardView.getKeyboard(); final Key[] keys = keyboard.mKeys; for (Key key : keys) { final int childVirtualViewId = generateVirtualViewIdForKey(key); - info.addChild(mKeyboardView, childVirtualViewId); - } - } else { - // Find the view that corresponds to the given id. - final Key key = mVirtualViewIdToKey.get(virtualViewId); - if (key == null) { - Log.e(TAG, "Invalid virtual view ID: " + virtualViewId); - return null; - } - - final String keyDescription = getKeyDescription(key); - final Rect boundsInParent = key.mHitBox; - - // Calculate the key's in-screen bounds. - mTempBoundsInScreen.set(boundsInParent); - mTempBoundsInScreen.offset( - CoordinateUtils.x(mParentLocation), CoordinateUtils.y(mParentLocation)); - - final Rect boundsInScreen = mTempBoundsInScreen; - - // Obtain and initialize an AccessibilityNodeInfo with - // information about the virtual view. - info = AccessibilityNodeInfoCompat.obtain(); - info.setPackageName(mKeyboardView.getContext().getPackageName()); - info.setClassName(key.getClass().getName()); - info.setContentDescription(keyDescription); - info.setBoundsInParent(boundsInParent); - info.setBoundsInScreen(boundsInScreen); - info.setParent(mKeyboardView); - info.setSource(mKeyboardView, virtualViewId); - info.setBoundsInScreen(boundsInScreen); - info.setEnabled(true); - info.setVisibleToUser(true); - - if (mAccessibilityFocusedView == virtualViewId) { - info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS); - } else { - info.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS); + rootInfo.addChild(mKeyboardView, childVirtualViewId); } + return rootInfo; } + // Find the view that corresponds to the given id. + final Key key = mVirtualViewIdToKey.get(virtualViewId); + if (key == null) { + Log.e(TAG, "Invalid virtual view ID: " + virtualViewId); + return null; + } + final String keyDescription = getKeyDescription(key); + final Rect boundsInParent = key.mHitBox; + + // Calculate the key's in-screen bounds. + mTempBoundsInScreen.set(boundsInParent); + mTempBoundsInScreen.offset( + CoordinateUtils.x(mParentLocation), CoordinateUtils.y(mParentLocation)); + final Rect boundsInScreen = mTempBoundsInScreen; + + // Obtain and initialize an AccessibilityNodeInfo with information about the virtual view. + final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); + info.setPackageName(mKeyboardView.getContext().getPackageName()); + info.setClassName(key.getClass().getName()); + info.setContentDescription(keyDescription); + info.setBoundsInParent(boundsInParent); + info.setBoundsInScreen(boundsInScreen); + info.setParent(mKeyboardView); + info.setSource(mKeyboardView, virtualViewId); + info.setBoundsInScreen(boundsInScreen); + info.setEnabled(true); + info.setVisibleToUser(true); + + if (mAccessibilityFocusedView == virtualViewId) { + info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS); + } else { + info.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS); + } return info; } @@ -216,7 +207,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider * * @param key The key to press. */ - void simulateKeyPress(Key key) { + void simulateKeyPress(final Key key) { final int x = key.mHitBox.centerX(); final int y = key.mHitBox.centerY(); final long downTime = SystemClock.uptimeMillis(); @@ -227,19 +218,17 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider mKeyboardView.onTouchEvent(downEvent); mKeyboardView.onTouchEvent(upEvent); - downEvent.recycle(); upEvent.recycle(); } @Override - public boolean performAction(int virtualViewId, int action, Bundle arguments) { + public boolean performAction(final int virtualViewId, final int action, + final Bundle arguments) { final Key key = mVirtualViewIdToKey.get(virtualViewId); - if (key == null) { return false; } - return performActionForKey(key, action, arguments); } @@ -249,10 +238,9 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider * @param key The on which to perform the action. * @param action The action to perform. * @param arguments The action's arguments. - * @return The result of performing the action, or false if the action is - * not supported. + * @return The result of performing the action, or false if the action is not supported. */ - boolean performActionForKey(Key key, int action, Bundle arguments) { + boolean performActionForKey(final Key key, final int action, final Bundle arguments) { final int virtualViewId = generateVirtualViewIdForKey(key); switch (action) { @@ -272,9 +260,9 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider sendAccessibilityEventForKey( key, AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); return true; + default: + return false; } - - return false; } /** @@ -283,7 +271,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider * @param key The key that's sending the event. * @param eventType The type of event to send. */ - void sendAccessibilityEventForKey(Key key, int eventType) { + void sendAccessibilityEventForKey(final Key key, final int eventType) { final AccessibilityEvent event = createAccessibilityEvent(key, eventType); mAccessibilityUtils.requestSendAccessibilityEvent(event); } @@ -294,12 +282,11 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider * @param key The key to describe. * @return The context-specific description of the key. */ - private String getKeyDescription(Key key) { + private String getKeyDescription(final Key key) { final EditorInfo editorInfo = mInputMethodService.getCurrentInputEditorInfo(); final boolean shouldObscure = mAccessibilityUtils.shouldObscureInput(editorInfo); final String keyDescription = mKeyCodeDescriptionMapper.getDescriptionForKey( mKeyboardView.getContext(), mKeyboardView.getKeyboard(), key, shouldObscure); - return keyDescription; } @@ -311,7 +298,6 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider if (keyboard == null) { return; } - mVirtualViewIdToKey.clear(); final Key[] keys = keyboard.mKeys; @@ -335,7 +321,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider * @param key The key to identify. * @return A virtual view identifier. */ - private static int generateVirtualViewIdForKey(Key key) { + private static int generateVirtualViewIdForKey(final Key key) { // The key x- and y-coordinates are stable between layout changes. // Generate an identifier by bit-shifting the x-coordinate to the // left-half of the integer and OR'ing with the y-coordinate. diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java index 0a700bda4..bf1cea9c3 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java @@ -55,7 +55,7 @@ public final class AccessibilityUtils { */ private static final boolean ENABLE_ACCESSIBILITY = true; - public static void init(InputMethodService inputMethod) { + public static void init(final InputMethodService inputMethod) { if (!ENABLE_ACCESSIBILITY) return; // These only need to be initialized if the kill switch is off. @@ -72,7 +72,7 @@ public final class AccessibilityUtils { // This class is not publicly instantiable. } - private void initInternal(Context context) { + private void initInternal(final Context context) { mContext = context; mAccessibilityManager = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); @@ -100,9 +100,8 @@ public final class AccessibilityUtils { * @param event The event to check. * @return {@true} is the event is a touch exploration event */ - public boolean isTouchExplorationEvent(MotionEvent event) { + public boolean isTouchExplorationEvent(final MotionEvent event) { final int action = event.getAction(); - return action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_EXIT || action == MotionEvent.ACTION_HOVER_MOVE; @@ -114,7 +113,7 @@ public final class AccessibilityUtils { * * @return {@code true} if the device should obscure password characters. */ - public boolean shouldObscureInput(EditorInfo editorInfo) { + public boolean shouldObscureInput(final EditorInfo editorInfo) { if (editorInfo == null) return false; // The user can optionally force speaking passwords. @@ -140,7 +139,7 @@ public final class AccessibilityUtils { * @param view The source view. * @param text The text to speak. */ - public void announceForAccessibility(View view, CharSequence text) { + public void announceForAccessibility(final View view, final CharSequence text) { if (!mAccessibilityManager.isEnabled()) { Log.e(TAG, "Attempted to speak when accessibility was disabled!"); return; @@ -157,8 +156,9 @@ public final class AccessibilityUtils { event.setEnabled(true); event.getText().add(text); - // Platforms starting at SDK 16 should use announce events. - if (Build.VERSION.SDK_INT >= 16) { + // Platforms starting at SDK version 16 (Build.VERSION_CODES.JELLY_BEAN) should use + // announce events. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { event.setEventType(AccessibilityEventCompat.TYPE_ANNOUNCEMENT); } else { event.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED); @@ -181,7 +181,8 @@ public final class AccessibilityUtils { * @param editorInfo The input connection's editor info attribute. * @param restarting Whether the connection is being restarted. */ - public void onStartInputViewInternal(View view, EditorInfo editorInfo, boolean restarting) { + public void onStartInputViewInternal(final View view, final EditorInfo editorInfo, + final boolean restarting) { if (shouldObscureInput(editorInfo)) { final CharSequence text = mContext.getText(R.string.spoken_use_headphones); announceForAccessibility(view, text); @@ -194,7 +195,7 @@ public final class AccessibilityUtils { * * @param event The event to send. */ - public void requestSendAccessibilityEvent(AccessibilityEvent event) { + public void requestSendAccessibilityEvent(final AccessibilityEvent event) { if (mAccessibilityManager.isEnabled()) { mAccessibilityManager.sendAccessibilityEvent(event); } diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java index fcfa6d4e4..d73924d92 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java @@ -42,12 +42,11 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp private Key mLastHoverKey = null; /** - * Inset in pixels to look for keys when the user's finger exits the - * keyboard area. + * Inset in pixels to look for keys when the user's finger exits the keyboard area. */ private int mEdgeSlop; - public static void init(InputMethodService inputMethod) { + public static void init(final InputMethodService inputMethod) { sInstance.initInternal(inputMethod); } @@ -59,7 +58,7 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp // Not publicly instantiable. } - private void initInternal(InputMethodService inputMethod) { + private void initInternal(final InputMethodService inputMethod) { mInputMethod = inputMethod; mEdgeSlop = inputMethod.getResources().getDimensionPixelSize( R.dimen.accessibility_edge_slop); @@ -70,61 +69,61 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp * * @param view The view to wrap. */ - public void setView(MainKeyboardView view) { + public void setView(final MainKeyboardView view) { if (view == null) { // Ignore null views. return; } - mView = view; // Ensure that the view has an accessibility delegate. ViewCompat.setAccessibilityDelegate(view, this); - if (mAccessibilityNodeProvider != null) { - mAccessibilityNodeProvider.setView(view); + if (mAccessibilityNodeProvider == null) { + return; } + mAccessibilityNodeProvider.setView(view); } - public void setKeyboard(Keyboard keyboard) { - if (mAccessibilityNodeProvider != null) { - mAccessibilityNodeProvider.setKeyboard(keyboard); + public void setKeyboard() { + if (mAccessibilityNodeProvider == null) { + return; } + mAccessibilityNodeProvider.setKeyboard(); } /** - * Proxy method for View.getAccessibilityNodeProvider(). This method is - * called in SDK version 15 and higher to obtain the virtual node hierarchy - * provider. + * Proxy method for View.getAccessibilityNodeProvider(). This method is called in SDK + * version 15 (Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) and higher to obtain the virtual + * node hierarchy provider. * * @return The accessibility node provider for the current keyboard. */ @Override - public AccessibilityEntityProvider getAccessibilityNodeProvider(View host) { + public AccessibilityEntityProvider getAccessibilityNodeProvider(final View host) { return getAccessibilityNodeProvider(); } /** - * Intercepts touch events before dispatch when touch exploration is turned - * on in ICS and higher. + * Intercepts touch events before dispatch when touch exploration is turned on in ICS and + * higher. * * @param event The motion event being dispatched. * @return {@code true} if the event is handled */ - public boolean dispatchTouchEvent(MotionEvent event) { + public boolean dispatchTouchEvent(final MotionEvent event) { // To avoid accidental key presses during touch exploration, always drop // touch events generated by the user. return false; } /** - * Receives hover events when touch exploration is turned on in SDK versions - * ICS and higher. + * Receives hover events when touch exploration is turned on in SDK versions ICS and higher. * * @param event The hover event. * @return {@code true} if the event is handled */ - public boolean dispatchHoverEvent(MotionEvent event, PointerTracker tracker) { + public boolean dispatchHoverEvent(final MotionEvent event, final PointerTracker tracker) { final int x = (int) event.getX(); final int y = (int) event.getY(); final Key previousKey = mLastHoverKey; @@ -135,7 +134,6 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp } else { key = null; } - mLastHoverKey = key; switch (event.getAction()) { @@ -173,30 +171,29 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp } /** - * Utility method to determine whether the given point, in local - * coordinates, is inside the view, where the area of the view is contracted - * by the edge slop factor. + * Utility method to determine whether the given point, in local coordinates, is inside the + * view, where the area of the view is contracted by the edge slop factor. * * @param localX The local x-coordinate. * @param localY The local y-coordinate. */ - private boolean pointInView(int localX, int localY) { + private boolean pointInView(final int localX, final int localY) { return (localX >= mEdgeSlop) && (localY >= mEdgeSlop) && (localX < (mView.getWidth() - mEdgeSlop)) && (localY < (mView.getHeight() - mEdgeSlop)); } /** - * Simulates a transition between two {@link Key}s by sending a HOVER_EXIT - * on the previous key, a HOVER_ENTER on the current key, and a HOVER_MOVE - * on the current key. + * Simulates a transition between two {@link Key}s by sending a HOVER_EXIT on the previous key, + * a HOVER_ENTER on the current key, and a HOVER_MOVE on the current key. * * @param currentKey The currently hovered key. * @param previousKey The previously hovered key. * @param event The event that triggered the transition. * @return {@code true} if the event was handled. */ - private boolean onTransitionKey(Key currentKey, Key previousKey, MotionEvent event) { + private boolean onTransitionKey(final Key currentKey, final Key previousKey, + final MotionEvent event) { final int savedAction = event.getAction(); event.setAction(MotionEvent.ACTION_HOVER_EXIT); @@ -214,19 +211,18 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp } /** - * Handles a hover event on a key. If {@link Key} extended View, this would - * be analogous to calling View.onHoverEvent(MotionEvent). + * Handles a hover event on a key. If {@link Key} extended View, this would be analogous to + * calling View.onHoverEvent(MotionEvent). * * @param key The currently hovered key. * @param event The hover event. * @return {@code true} if the event was handled. */ - private boolean onHoverKey(Key key, MotionEvent event) { + private boolean onHoverKey(final Key key, final MotionEvent event) { // Null keys can't receive events. if (key == null) { return false; } - final AccessibilityEntityProvider provider = getAccessibilityNodeProvider(); switch (event.getAction()) { @@ -241,7 +237,6 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp key, AccessibilityEventCompat.TYPE_VIEW_HOVER_EXIT); break; } - return true; } @@ -268,7 +263,6 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp default: text = context.getText(R.string.spoken_description_shiftmode_off); } - AccessibilityUtils.getInstance().announceForAccessibility(mView, text); } @@ -307,7 +301,6 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp if (resId < 0) { return; } - final String text = context.getString(resId); AccessibilityUtils.getInstance().announceForAccessibility(mView, text); } diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java index b87ae3a15..6a01b0190 100644 --- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java +++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java @@ -93,17 +93,17 @@ public final class KeyCodeDescriptionMapper { * @param keyboard The keyboard on which the key resides. * @param key The key from which to obtain a description. * @param shouldObscure {@true} if text (e.g. non-control) characters should be obscured. - * @return a character sequence describing the action performed by pressing - * the key + * @return a character sequence describing the action performed by pressing the key */ - public String getDescriptionForKey(Context context, Keyboard keyboard, Key key, - boolean shouldObscure) { + public String getDescriptionForKey(final Context context, final Keyboard keyboard, + final Key key, final boolean shouldObscure) { final int code = key.mCode; if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) { final String description = getDescriptionForSwitchAlphaSymbol(context, keyboard); - if (description != null) + if (description != null) { return description; + } } if (code == Constants.CODE_SHIFT) { @@ -127,7 +127,6 @@ public final class KeyCodeDescriptionMapper { if (key.mCode != Constants.CODE_UNSPECIFIED) { return getDescriptionForKeyCode(context, keyboard, key, shouldObscure); } - return null; } @@ -138,10 +137,10 @@ public final class KeyCodeDescriptionMapper { * * @param context The package's context. * @param keyboard The keyboard on which the key resides. - * @return a character sequence describing the action performed by pressing - * the key + * @return a character sequence describing the action performed by pressing the key */ - private String getDescriptionForSwitchAlphaSymbol(Context context, Keyboard keyboard) { + private String getDescriptionForSwitchAlphaSymbol(final Context context, + final Keyboard keyboard) { final KeyboardId keyboardId = keyboard.mId; final int elementId = keyboardId.mElementId; final int resId; @@ -168,7 +167,6 @@ public final class KeyCodeDescriptionMapper { Log.e(TAG, "Missing description for keyboard element ID:" + elementId); return null; } - return context.getString(resId); } @@ -179,7 +177,7 @@ public final class KeyCodeDescriptionMapper { * @param keyboard The keyboard on which the key resides. * @return A context-sensitive description of the "Shift" key. */ - private String getDescriptionForShiftKey(Context context, Keyboard keyboard) { + private String getDescriptionForShiftKey(final Context context, final Keyboard keyboard) { final KeyboardId keyboardId = keyboard.mId; final int elementId = keyboardId.mElementId; final int resId; @@ -197,7 +195,6 @@ public final class KeyCodeDescriptionMapper { default: resId = R.string.spoken_description_shift; } - return context.getString(resId); } @@ -207,10 +204,10 @@ public final class KeyCodeDescriptionMapper { * @param context The package's context. * @param keyboard The keyboard on which the key resides. * @param key The key to describe. - * @return Returns a context-sensitive description of the "Enter" action - * key. + * @return Returns a context-sensitive description of the "Enter" action key. */ - private String getDescriptionForActionKey(Context context, Keyboard keyboard, Key key) { + private String getDescriptionForActionKey(final Context context, final Keyboard keyboard, + final Key key) { final KeyboardId keyboardId = keyboard.mId; final int actionId = keyboardId.imeActionId(); final int resId; @@ -243,7 +240,6 @@ public final class KeyCodeDescriptionMapper { default: resId = R.string.spoken_description_return; } - return context.getString(resId); } @@ -265,11 +261,10 @@ public final class KeyCodeDescriptionMapper { * @param keyboard The keyboard on which the key resides. * @param key The key from which to obtain a description. * @param shouldObscure {@true} if text (e.g. non-control) characters should be obscured. - * @return a character sequence describing the action performed by pressing - * the key + * @return a character sequence describing the action performed by pressing the key */ - private String getDescriptionForKeyCode(Context context, Keyboard keyboard, Key key, - boolean shouldObscure) { + private String getDescriptionForKeyCode(final Context context, final Keyboard keyboard, + final Key key, final boolean shouldObscure) { final int code = key.mCode; // If the key description should be obscured, now is the time to do it. @@ -277,15 +272,15 @@ public final class KeyCodeDescriptionMapper { if (shouldObscure && isDefinedNonCtrl) { return context.getString(OBSCURED_KEY_RES_ID); } - if (mKeyCodeMap.indexOfKey(code) >= 0) { return context.getString(mKeyCodeMap.get(code)); - } else if (isDefinedNonCtrl) { + } + if (isDefinedNonCtrl) { return Character.toString((char) code); - } else if (!TextUtils.isEmpty(key.mLabel)) { + } + if (!TextUtils.isEmpty(key.mLabel)) { return key.mLabel; - } else { - return context.getString(R.string.spoken_description_unknown, code); } + return context.getString(R.string.spoken_description_unknown, code); } } diff --git a/java/src/com/android/inputmethod/compat/CompatUtils.java b/java/src/com/android/inputmethod/compat/CompatUtils.java index ffed6ecb1..a82103ab3 100644 --- a/java/src/com/android/inputmethod/compat/CompatUtils.java +++ b/java/src/com/android/inputmethod/compat/CompatUtils.java @@ -31,8 +31,8 @@ public final class CompatUtils { private static final String INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS"; - public static Intent getInputLanguageSelectionIntent(String inputMethodId, - int flagsForSubtypeSettings) { + public static Intent getInputLanguageSelectionIntent(final String inputMethodId, + final int flagsForSubtypeSettings) { // Refer to android.provider.Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS final String action = INPUT_METHOD_SUBTYPE_SETTINGS; final Intent intent = new Intent(action); @@ -45,7 +45,7 @@ public final class CompatUtils { return intent; } - public static Class<?> getClass(String className) { + public static Class<?> getClass(final String className) { try { return Class.forName(className); } catch (ClassNotFoundException e) { @@ -53,8 +53,8 @@ public final class CompatUtils { } } - public static Method getMethod(Class<?> targetClass, String name, - Class<?>... parameterTypes) { + public static Method getMethod(final Class<?> targetClass, final String name, + final Class<?>... parameterTypes) { if (targetClass == null || TextUtils.isEmpty(name)) return null; try { return targetClass.getMethod(name, parameterTypes); @@ -66,7 +66,7 @@ public final class CompatUtils { return null; } - public static Field getField(Class<?> targetClass, String name) { + public static Field getField(final Class<?> targetClass, final String name) { if (targetClass == null || TextUtils.isEmpty(name)) return null; try { return targetClass.getField(name); @@ -78,7 +78,8 @@ public final class CompatUtils { return null; } - public static Constructor<?> getConstructor(Class<?> targetClass, Class<?> ... types) { + public static Constructor<?> getConstructor(final Class<?> targetClass, + final Class<?> ... types) { if (targetClass == null || types == null) return null; try { return targetClass.getConstructor(types); @@ -90,7 +91,7 @@ public final class CompatUtils { return null; } - public static Object newInstance(Constructor<?> constructor, Object ... args) { + public static Object newInstance(final Constructor<?> constructor, final Object ... args) { if (constructor == null) return null; try { return constructor.newInstance(args); @@ -100,8 +101,8 @@ public final class CompatUtils { return null; } - public static Object invoke( - Object receiver, Object defaultValue, Method method, Object... args) { + public static Object invoke(final Object receiver, final Object defaultValue, + final Method method, final Object... args) { if (method == null) return defaultValue; try { return method.invoke(receiver, args); @@ -111,7 +112,8 @@ public final class CompatUtils { return defaultValue; } - public static Object getFieldValue(Object receiver, Object defaultValue, Field field) { + public static Object getFieldValue(final Object receiver, final Object defaultValue, + final Field field) { if (field == null) return defaultValue; try { return field.get(receiver); @@ -121,7 +123,7 @@ public final class CompatUtils { return defaultValue; } - public static void setFieldValue(Object receiver, Field field, Object value) { + public static void setFieldValue(final Object receiver, final Field field, final Object value) { if (field == null) return; try { field.set(receiver, value); diff --git a/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java b/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java index 210058bec..7eefa221a 100644 --- a/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java @@ -21,23 +21,23 @@ import android.view.inputmethod.EditorInfo; import java.lang.reflect.Field; public final class EditorInfoCompatUtils { - // EditorInfo.IME_FLAG_FORCE_ASCII has been introduced since API#16 (JellyBean). + // Note that EditorInfo.IME_FLAG_FORCE_ASCII has been introduced + // in API level 16 (Build.VERSION_CODES.JELLY_BEAN). private static final Field FIELD_IME_FLAG_FORCE_ASCII = CompatUtils.getField( EditorInfo.class, "IME_FLAG_FORCE_ASCII"); - private static final Integer OBJ_IME_FLAG_FORCE_ASCII = (Integer) CompatUtils - .getFieldValue(null, null, FIELD_IME_FLAG_FORCE_ASCII); + private static final Integer OBJ_IME_FLAG_FORCE_ASCII = (Integer) CompatUtils.getFieldValue( + null /* receiver */, null /* defaultValue */, FIELD_IME_FLAG_FORCE_ASCII); private EditorInfoCompatUtils() { // This utility class is not publicly instantiable. } - public static boolean hasFlagForceAscii(int imeOptions) { - if (OBJ_IME_FLAG_FORCE_ASCII == null) - return false; + public static boolean hasFlagForceAscii(final int imeOptions) { + if (OBJ_IME_FLAG_FORCE_ASCII == null) return false; return (imeOptions & OBJ_IME_FLAG_FORCE_ASCII) != 0; } - public static String imeActionName(int imeOptions) { + public static String imeActionName(final int imeOptions) { final int actionId = imeOptions & EditorInfo.IME_MASK_ACTION; switch (actionId) { case EditorInfo.IME_ACTION_UNSPECIFIED: @@ -61,7 +61,7 @@ public final class EditorInfoCompatUtils { } } - public static String imeOptionsName(int imeOptions) { + public static String imeOptionsName(final int imeOptions) { final String action = imeActionName(imeOptions); final StringBuilder flags = new StringBuilder(); if ((imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) { diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java index 8bd1e5208..a80c3fefe 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java @@ -23,6 +23,8 @@ import android.view.inputmethod.InputMethodManager; import java.lang.reflect.Method; public final class InputMethodManagerCompatWrapper { + // Note that InputMethodManager.switchToNextInputMethod() has been introduced + // in API level 16 (Build.VERSION_CODES.JELLY_BEAN). private static final Method METHOD_switchToNextInputMethod = CompatUtils.getMethod( InputMethodManager.class, "switchToNextInputMethod", IBinder.class, Boolean.TYPE); @@ -33,7 +35,7 @@ public final class InputMethodManagerCompatWrapper { } public boolean switchToNextInputMethod(final IBinder token, final boolean onlyCurrentIme) { - return (Boolean)CompatUtils.invoke(mImm, false, METHOD_switchToNextInputMethod, token, - onlyCurrentIme); + return (Boolean)CompatUtils.invoke(mImm, false /* defaultValue */, + METHOD_switchToNextInputMethod, token, onlyCurrentIme); } } diff --git a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatUtils.java b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatUtils.java index 8eea31ed2..14ee654f3 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatUtils.java @@ -21,6 +21,8 @@ import android.inputmethodservice.InputMethodService; import java.lang.reflect.Method; public final class InputMethodServiceCompatUtils { + // Note that InputMethodService.enableHardwareAcceleration() has been introduced + // in API level 17 (Build.VERSION_CODES.JELLY_BEAN_MR1). private static final Method METHOD_enableHardwareAcceleration = CompatUtils.getMethod(InputMethodService.class, "enableHardwareAcceleration"); @@ -28,7 +30,8 @@ public final class InputMethodServiceCompatUtils { // This utility class is not publicly instantiable. } - public static boolean enableHardwareAcceleration(InputMethodService ims) { - return (Boolean)CompatUtils.invoke(ims, false, METHOD_enableHardwareAcceleration); + public static boolean enableHardwareAcceleration(final InputMethodService ims) { + return (Boolean)CompatUtils.invoke(ims, false /* defaultValue */, + METHOD_enableHardwareAcceleration); } } diff --git a/java/src/com/android/inputmethod/compat/SettingsSecureCompatUtils.java b/java/src/com/android/inputmethod/compat/SettingsSecureCompatUtils.java index db5abd0fe..cfaf7ec77 100644 --- a/java/src/com/android/inputmethod/compat/SettingsSecureCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/SettingsSecureCompatUtils.java @@ -19,6 +19,8 @@ package com.android.inputmethod.compat; import java.lang.reflect.Field; public final class SettingsSecureCompatUtils { + // Note that Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD has been introduced + // in API level 15 (Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1). private static final Field FIELD_ACCESSIBILITY_SPEAK_PASSWORD = CompatUtils.getField( android.provider.Settings.Secure.class, "ACCESSIBILITY_SPEAK_PASSWORD"); @@ -30,5 +32,5 @@ public final class SettingsSecureCompatUtils { * Whether to speak passwords while in accessibility mode. */ public static final String ACCESSIBILITY_SPEAK_PASSWORD = (String) CompatUtils.getFieldValue( - null, null, FIELD_ACCESSIBILITY_SPEAK_PASSWORD); + null /* receiver */, null /* defaultValue */, FIELD_ACCESSIBILITY_SPEAK_PASSWORD); } diff --git a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java index 0e3634d52..141e08a8d 100644 --- a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java +++ b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java @@ -34,11 +34,12 @@ import java.util.ArrayList; public final class SuggestionSpanUtils { private static final String TAG = SuggestionSpanUtils.class.getSimpleName(); - // Note that SuggestionSpan.FLAG_AUTO_CORRECTION was added in API level 15. - public static final Field FIELD_FLAG_AUTO_CORRECTION = - CompatUtils.getField(SuggestionSpan.class, "FLAG_AUTO_CORRECTION"); - public static final Integer OBJ_FLAG_AUTO_CORRECTION = - (Integer) CompatUtils.getFieldValue(null, null, FIELD_FLAG_AUTO_CORRECTION); + // Note that SuggestionSpan.FLAG_AUTO_CORRECTION has been introduced + // in API level 15 (Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1). + public static final Field FIELD_FLAG_AUTO_CORRECTION = CompatUtils.getField( + SuggestionSpan.class, "FLAG_AUTO_CORRECTION"); + public static final Integer OBJ_FLAG_AUTO_CORRECTION = (Integer) CompatUtils.getFieldValue( + null /* receiver */, null /* defaultValue */, FIELD_FLAG_AUTO_CORRECTION); static { if (LatinImeLogger.sDBG) { @@ -58,8 +59,9 @@ public final class SuggestionSpanUtils { return text; } final Spannable spannable = new SpannableString(text); - final SuggestionSpan suggestionSpan = new SuggestionSpan(context, null, new String[] {}, - (int)OBJ_FLAG_AUTO_CORRECTION, SuggestionSpanPickedNotificationReceiver.class); + final SuggestionSpan suggestionSpan = new SuggestionSpan(context, null /* locale */, + new String[] {} /* suggestions */, (int)OBJ_FLAG_AUTO_CORRECTION, + SuggestionSpanPickedNotificationReceiver.class); spannable.setSpan(suggestionSpan, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING); return spannable; @@ -87,8 +89,8 @@ public final class SuggestionSpanUtils { // TODO: We should avoid adding suggestion span candidates that came from the bigram // prediction. - final SuggestionSpan suggestionSpan = new SuggestionSpan(context, null, - suggestionsList.toArray(new String[suggestionsList.size()]), 0, + final SuggestionSpan suggestionSpan = new SuggestionSpan(context, null /* locale */, + suggestionsList.toArray(new String[suggestionsList.size()]), 0 /* flags */, SuggestionSpanPickedNotificationReceiver.class); spannable.setSpan(suggestionSpan, 0, pickedWord.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return spannable; diff --git a/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java b/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java index 8314212c9..d8d2be04c 100644 --- a/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java @@ -21,10 +21,13 @@ import android.view.textservice.SuggestionsInfo; import java.lang.reflect.Field; public final class SuggestionsInfoCompatUtils { - private static final Field FIELD_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = CompatUtils.getField( - SuggestionsInfo.class, "RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS"); - private static final Integer OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = (Integer) CompatUtils - .getFieldValue(null, null, FIELD_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS); + // Note that SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS has been introduced + // in API level 15 (Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1). + private static final Field FIELD_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = + CompatUtils.getField(SuggestionsInfo.class, "RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS"); + private static final Integer OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = + (Integer) CompatUtils.getFieldValue(null /* receiver */, null /* defaultValue */, + FIELD_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS); private static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS != null ? OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS : 0; diff --git a/java/src/com/android/inputmethod/event/Event.java b/java/src/com/android/inputmethod/event/Event.java index c96a3362d..215e4dee5 100644 --- a/java/src/com/android/inputmethod/event/Event.java +++ b/java/src/com/android/inputmethod/event/Event.java @@ -29,8 +29,64 @@ package com.android.inputmethod.event; * The combiner should figure out what to do with this. */ public class Event { + // Should the types below be represented by separate classes instead? It would be cleaner + // but probably a bit too much + // An event we don't handle in Latin IME, for example pressing Ctrl on a hardware keyboard. + final public static int EVENT_NOT_HANDLED = 0; + // A character that is already final, for example pressing an alphabetic character on a + // hardware qwerty keyboard. + final public static int EVENT_COMMITTABLE = 1; + // A dead key, which means a character that should combine with what is coming next. Examples + // include the "^" character on an azerty keyboard which combines with "e" to make "ê", or + // AltGr+' on a dvorak international keyboard which combines with "e" to make "é". This is + // true regardless of the language or combining mode, and should be seen as a property of the + // key - a dead key followed by another key with which it can combine should be regarded as if + // the keyboard actually had such a key. + final public static int EVENT_DEAD = 2; + // A toggle event is triggered by a key that affects the previous character. An example would + // be a numeric key on a 10-key keyboard, which would toggle between 1 - a - b - c with + // repeated presses. + final public static int EVENT_TOGGLE = 3; + // A mode event instructs the combiner to change modes. The canonical example would be the + // hankaku/zenkaku key on a Japanese keyboard, or even the caps lock key on a qwerty keyboard + // if handled at the combiner level. + final public static int EVENT_MODE_KEY = 4; + + final private static int NOT_A_CODE_POINT = 0; + + private int mType; // The type of event - one of the constants above + // The code point associated with the event, if relevant. This is a unicode code point, and + // has nothing to do with other representations of the key. It is only relevant if this event + // is the right type: COMMITTABLE or DEAD or TOGGLE, but for a mode key like hankaku/zenkaku or + // ctrl, there is no code point associated so this should be NOT_A_CODE_POINT to avoid + // unintentional use of its value when it's not relevant. + private int mCodePoint; + static Event obtainEvent() { // TODO: create an event pool instead return new Event(); } + + public void setDeadEvent(final int codePoint) { + mType = EVENT_DEAD; + mCodePoint = codePoint; + } + + public void setCommittableEvent(final int codePoint) { + mType = EVENT_COMMITTABLE; + mCodePoint = codePoint; + } + + public void setNotHandledEvent() { + mType = EVENT_NOT_HANDLED; + mCodePoint = NOT_A_CODE_POINT; // Just in case + } + + public boolean isCommittable() { + return EVENT_COMMITTABLE == mType; + } + + public int getCodePoint() { + return mCodePoint; + } } diff --git a/java/src/com/android/inputmethod/event/EventInterpreter.java b/java/src/com/android/inputmethod/event/EventInterpreter.java index 443c269a2..1bd0cca00 100644 --- a/java/src/com/android/inputmethod/event/EventInterpreter.java +++ b/java/src/com/android/inputmethod/event/EventInterpreter.java @@ -16,8 +16,12 @@ package com.android.inputmethod.event; +import android.util.SparseArray; import android.view.KeyEvent; +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.LatinIME; + /** * This class implements the logic between receiving events and generating code points. * @@ -32,18 +36,45 @@ public class EventInterpreter { // TODO: Create an object type to represent input material + visual feedback + decoding state // TODO: Create an interface to call back to Latin IME through the above object - // TODO: replace this with an associative container to bind device id -> decoder - HardwareEventDecoder mHardwareEventDecoder; - SoftwareEventDecoder mSoftwareEventDecoder; + final EventDecoderSpec mDecoderSpec; + final SparseArray<HardwareEventDecoder> mHardwareEventDecoders; + final SoftwareEventDecoder mSoftwareEventDecoder; + final LatinIME mLatinIme; - public EventInterpreter() { - this(null); + /** + * Create a default interpreter. + * + * This creates a default interpreter that does nothing. A default interpreter should normally + * only be used for fallback purposes, when we really don't know what we want to do with input. + * + * @param latinIme a reference to the ime. + */ + public EventInterpreter(final LatinIME latinIme) { + this(null, latinIme); } - public EventInterpreter(final EventDecoderSpec specification) { - // TODO: create the decoding chain from a specification. The decoders should be - // created lazily - mHardwareEventDecoder = new HardwareKeyboardEventDecoder(0); + /** + * Create an event interpreter according to a specification. + * + * The specification contains information about what to do with events. Typically, it will + * contain information about the type of keyboards - for example, if hardware keyboard(s) is/are + * attached, their type will be included here so that the decoder knows what to do with each + * keypress (a 10-key keyboard is not handled like a qwerty-ish keyboard). + * It also contains information for combining characters. For example, if the input language + * is Japanese, the specification will typically request kana conversion. + * Also note that the specification can be null. This means that we need to create a default + * interpreter that does no specific combining, and assumes the most common cases. + * + * @param specification the specification for event interpretation. null for default. + * @param latinIme a reference to the ime. + */ + public EventInterpreter(final EventDecoderSpec specification, final LatinIME latinIme) { + mDecoderSpec = null != specification ? specification : new EventDecoderSpec(); + // For both, we expect to have only one decoder in almost all cases, hence the default + // capacity of 1. + mHardwareEventDecoders = new SparseArray<HardwareEventDecoder>(1); + mSoftwareEventDecoder = new SoftwareKeyboardEventDecoder(); + mLatinIme = latinIme; } // Helper method to decode a hardware key event into a generic event, and execute any @@ -60,15 +91,26 @@ public class EventInterpreter { } private HardwareEventDecoder getHardwareKeyEventDecoder(final int deviceId) { - // TODO: look up the decoder by device id. It should be created lazily - return mHardwareEventDecoder; + final HardwareEventDecoder decoder = mHardwareEventDecoders.get(deviceId); + if (null != decoder) return decoder; + // TODO: create the decoder according to the specification + final HardwareEventDecoder newDecoder = new HardwareKeyboardEventDecoder(deviceId); + mHardwareEventDecoders.put(deviceId, newDecoder); + return newDecoder; } private SoftwareEventDecoder getSoftwareEventDecoder() { + // Within the context of Latin IME, since we never present several software interfaces + // at the time, we should never need multiple software event decoders at a time. return mSoftwareEventDecoder; } private boolean onEvent(final Event event) { + if (event.isCommittable()) { + mLatinIme.onCodeInput(event.getCodePoint(), + Constants.EXTERNAL_KEYBOARD_COORDINATE, Constants.EXTERNAL_KEYBOARD_COORDINATE); + return true; + } // TODO: Classify the event - input or non-input (see design doc) // TODO: IF action event // Send decoded action back to LatinIME diff --git a/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java b/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java index 9aa6a273e..2dbc9f00b 100644 --- a/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java +++ b/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java @@ -16,10 +16,17 @@ package com.android.inputmethod.event; +import android.view.KeyCharacterMap; import android.view.KeyEvent; +import com.android.inputmethod.latin.Constants; + /** * A hardware event decoder for a hardware qwerty-ish keyboard. + * + * The events are always hardware keypresses, but they can be key down or key up events, they + * can be dead keys, they can be meta keys like shift or ctrl... This does not deal with + * 10-key like keyboards; a different decoder is used for this. */ public class HardwareKeyboardEventDecoder implements HardwareEventDecoder { final int mDeviceId; @@ -30,7 +37,33 @@ public class HardwareKeyboardEventDecoder implements HardwareEventDecoder { } @Override - public Event decodeHardwareKey(KeyEvent keyEvent) { - return Event.obtainEvent(); + public Event decodeHardwareKey(final KeyEvent keyEvent) { + final Event event = Event.obtainEvent(); + // KeyEvent#getUnicodeChar() does not exactly returns a unicode char, but rather a value + // that includes both the unicode char in the lower 21 bits and flags in the upper bits, + // hence the name "codePointAndFlags". {@see KeyEvent#getUnicodeChar()} for more info. + final int codePointAndFlags = keyEvent.getUnicodeChar(); + // The keyCode is the abstraction used by the KeyEvent to represent different keys that + // do not necessarily map to a unicode character. This represents a physical key, like + // the key for 'A' or Space, but also Backspace or Ctrl or Caps Lock. + final int keyCode = keyEvent.getKeyCode(); + if (KeyEvent.KEYCODE_DEL == keyCode) { + event.setCommittableEvent(Constants.CODE_DELETE); + return event; + } + if (keyEvent.isPrintingKey() || KeyEvent.KEYCODE_SPACE == keyCode + || KeyEvent.KEYCODE_ENTER == keyCode) { + if (0 != (codePointAndFlags & KeyCharacterMap.COMBINING_ACCENT)) { + // A dead key. + event.setDeadEvent(codePointAndFlags & KeyCharacterMap.COMBINING_ACCENT_MASK); + } else { + // A committable character. This should be committed right away, taking into + // account the current state. + event.setCommittableEvent(codePointAndFlags); + } + } else { + event.setNotHandledEvent(); + } + return event; } } diff --git a/java/src/com/android/inputmethod/event/SoftwareEventDecoder.java b/java/src/com/android/inputmethod/event/SoftwareEventDecoder.java index 0b80d5c0e..d81ee0b37 100644 --- a/java/src/com/android/inputmethod/event/SoftwareEventDecoder.java +++ b/java/src/com/android/inputmethod/event/SoftwareEventDecoder.java @@ -17,7 +17,12 @@ package com.android.inputmethod.event; /** - * An event decoder for software events. + * An event decoder for events out of a software keyboard. + * + * This defines the interface for an event decoder that supports events out of a software keyboard. + * This differs significantly from hardware keyboard event decoders in several respects. First, + * a software keyboard does not have a scancode/layout system; the keypresses that insert + * characters output unicode characters directly. */ public interface SoftwareEventDecoder extends EventDecoder { public Event decodeSoftwareEvent(); diff --git a/java/src/com/android/inputmethod/event/SoftwareKeyboardEventDecoder.java b/java/src/com/android/inputmethod/event/SoftwareKeyboardEventDecoder.java new file mode 100644 index 000000000..de91567c7 --- /dev/null +++ b/java/src/com/android/inputmethod/event/SoftwareKeyboardEventDecoder.java @@ -0,0 +1,27 @@ +/* + * 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.event; + +/** + * A decoder for events from software keyboard, like the ones displayed by Latin IME. + */ +public class SoftwareKeyboardEventDecoder implements SoftwareEventDecoder { + @Override + public Event decodeSoftwareEvent() { + return null; + } +} diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index c1c105e8d..51517823a 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -19,6 +19,7 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; +import android.preference.PreferenceManager; import android.util.Log; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; @@ -50,7 +51,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { // Note: The themeId should be aligned with "themeId" attribute of Keyboard style // in values/style.xml. - public KeyboardTheme(int themeId, int styleId) { + public KeyboardTheme(final int themeId, final int styleId) { mThemeId = themeId; mStyleId = styleId; } @@ -95,11 +96,12 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { // Intentional empty constructor for singleton. } - public static void init(LatinIME latinIme, SharedPreferences prefs) { + public static void init(final LatinIME latinIme) { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(latinIme); sInstance.initInternal(latinIme, prefs); } - private void initInternal(LatinIME latinIme, SharedPreferences prefs) { + private void initInternal(final LatinIME latinIme, final SharedPreferences prefs) { mLatinIME = latinIme; mResources = latinIme.getResources(); mFeedbackManager = new AudioAndHapticFeedbackManager(latinIme); @@ -109,7 +111,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { setContextThemeWrapper(latinIme, getKeyboardTheme(latinIme, prefs)); } - private static KeyboardTheme getKeyboardTheme(Context context, SharedPreferences prefs) { + private static KeyboardTheme getKeyboardTheme(final Context context, + final SharedPreferences prefs) { final String defaultIndex = context.getString(R.string.config_default_keyboard_theme_index); final String themeIndex = prefs.getString(PREF_KEYBOARD_LAYOUT, defaultIndex); try { @@ -124,7 +127,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { return KEYBOARD_THEMES[0]; } - private void setContextThemeWrapper(Context context, KeyboardTheme keyboardTheme) { + private void setContextThemeWrapper(final Context context, final KeyboardTheme keyboardTheme) { if (mThemeContext == null || mKeyboardTheme.mThemeId != keyboardTheme.mThemeId) { mKeyboardTheme = keyboardTheme; mThemeContext = new ContextThemeWrapper(context, keyboardTheme.mStyleId); @@ -132,7 +135,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { } } - public void loadKeyboard(EditorInfo editorInfo, SettingsValues settingsValues) { + public void loadKeyboard(final EditorInfo editorInfo, final SettingsValues settingsValues) { final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder( mThemeContext, editorInfo); final Resources res = mThemeContext.getResources(); @@ -210,14 +213,14 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { mState.onResetKeyboardStateToAlphabet(); } - public void onPressKey(int code) { + public void onPressKey(final int code) { if (isVibrateAndSoundFeedbackRequired()) { mFeedbackManager.hapticAndAudioFeedback(code, mKeyboardView); } mState.onPressKey(code, isSinglePointer(), mLatinIME.getCurrentAutoCapsState()); } - public void onReleaseKey(int code, boolean withSliding) { + public void onReleaseKey(final int code, final boolean withSliding) { mState.onReleaseKey(code, withSliding); } @@ -303,7 +306,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { // Implements {@link KeyboardState.SwitchActions}. @Override - public void startLongPressTimer(int code) { + public void startLongPressTimer(final int code) { final MainKeyboardView keyboardView = getMainKeyboardView(); if (keyboardView != null) { final TimerProxy timer = keyboardView.getTimerProxy(); @@ -323,11 +326,11 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { // Implements {@link KeyboardState.SwitchActions}. @Override - public void hapticAndAudioFeedback(int code) { + public void hapticAndAudioFeedback(final int code) { mFeedbackManager.hapticAndAudioFeedback(code, mKeyboardView); } - public void onLongPressTimeout(int code) { + public void onLongPressTimeout(final int code) { mState.onLongPressTimeout(code); } @@ -346,7 +349,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { /** * Updates state machine to figure out when to automatically switch back to the previous mode. */ - public void onCodeInput(int code) { + public void onCodeInput(final int code) { mState.onCodeInput(code, isSinglePointer(), mLatinIME.getCurrentAutoCapsState()); } @@ -354,7 +357,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { return mKeyboardView; } - public View onCreateInputView(boolean isHardwareAcceleratedDrawingEnabled) { + public View onCreateInputView(final boolean isHardwareAcceleratedDrawingEnabled) { if (mKeyboardView != null) { mKeyboardView.closing(); } @@ -383,7 +386,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { } } - public void onAutoCorrectionStateChanged(boolean isAutoCorrection) { + public void onAutoCorrectionStateChanged(final boolean isAutoCorrection) { if (mIsAutoCorrectionActive != isAutoCorrection) { mIsAutoCorrectionActive = isAutoCorrection; if (mKeyboardView != null) { diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 584d2fe46..79aab9c76 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -393,8 +393,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack mHasDistinctMultitouch = hasDistinctMultitouch && !forceNonDistinctMultitouch; final Resources res = getResources(); final boolean needsPhantomSuddenMoveEventHack = Boolean.parseBoolean( - ResourceUtils.getDeviceOverrideValue(res, - R.array.phantom_sudden_move_event_device_list, "false")); + ResourceUtils.getDeviceOverrideValue( + res, R.array.phantom_sudden_move_event_device_list)); PointerTracker.init(needsPhantomSuddenMoveEventHack); final TypedArray a = context.obtainStyledAttributes( @@ -530,7 +530,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack // This always needs to be set since the accessibility state can // potentially change without the keyboard being set again. - AccessibleKeyboardViewProxy.getInstance().setKeyboard(keyboard); + AccessibleKeyboardViewProxy.getInstance().setKeyboard(); } // Note that this method is called from a non-UI thread. diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 0f55607a0..59a3c99aa 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -791,6 +791,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private void cancelBatchInput() { sPointerTrackerQueue.cancelAllPointerTracker(); + if (!sInGesture) { + return; + } sInGesture = false; if (DEBUG_LISTENER) { Log.d(TAG, String.format("[%d] onCancelBatchInput", mPointerId)); @@ -1208,9 +1211,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { printTouchEvent("onCancelEvt:", x, y, eventTime); } - if (sInGesture) { - cancelBatchInput(); - } + cancelBatchInput(); sPointerTrackerQueue.cancelAllPointerTracker(); sPointerTrackerQueue.releaseAllPointers(eventTime); onCancelEventInternal(); diff --git a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java index 3a57f673a..f8949b2ad 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java @@ -101,6 +101,16 @@ final class GesturePreviewTrail { } } + /** + * Calculate the alpha of a gesture trail. + * A gesture trail starts from fully opaque. After mFadeStartDelay has been passed, the alpha + * of a trail reduces in proportion to the elapsed time. Then after mFadeDuration has been + * passed, a trail becomes fully transparent. + * + * @param elapsedTime the elapsed time since a trail has been made. + * @param params gesture trail display parameters + * @return the width of a gesture trail + */ private static int getAlpha(final int elapsedTime, final Params params) { if (elapsedTime < params.mFadeoutStartDelay) { return Constants.Color.ALPHA_OPAQUE; @@ -111,10 +121,19 @@ final class GesturePreviewTrail { return Constants.Color.ALPHA_OPAQUE - decreasingAlpha; } + /** + * Calculate the width of a gesture trail. + * A gesture trail starts from the width of mTrailStartWidth and reduces its width in proportion + * to the elapsed time. After mTrailEndWidth has been passed, the width becomes mTraiLEndWidth. + * + * @param elapsedTime the elapsed time since a trail has been made. + * @param params gesture trail display parameters + * @return the width of a gesture trail + */ private static float getWidth(final int elapsedTime, final Params params) { - return Math.max((params.mTrailLingerDuration - elapsedTime) - * (params.mTrailStartWidth - params.mTrailEndWidth) - / params.mTrailLingerDuration, 0.0f); + final int deltaTime = params.mTrailLingerDuration - elapsedTime; + final float deltaWidth = params.mTrailStartWidth - params.mTrailEndWidth; + return (deltaTime * deltaWidth) / params.mTrailLingerDuration + params.mTrailEndWidth; } private final RoundedLine mRoundedLine = new RoundedLine(); @@ -154,7 +173,7 @@ final class GesturePreviewTrail { final RoundedLine line = mRoundedLine; int p1x = getXCoordValue(xCoords[startIndex]); int p1y = yCoords[startIndex]; - int lastTime = sinceDown - eventTimes[startIndex]; + final int lastTime = sinceDown - eventTimes[startIndex]; float maxWidth = getWidth(lastTime, params); float r1 = maxWidth / 2.0f; // Initialize bounds rectangle. @@ -167,20 +186,19 @@ final class GesturePreviewTrail { final float r2 = width / 2.0f; // Draw trail line only when the current point isn't a down point. if (!isDownEventXCoord(xCoords[i])) { - final int alpha = getAlpha(elapsedTime, params); - paint.setAlpha(alpha); final Path path = line.makePath(p1x, p1y, r1, p2x, p2y, r2); if (path != null) { + final int alpha = getAlpha(elapsedTime, params); + paint.setAlpha(alpha); canvas.drawPath(path, paint); + // Take union for the bounds. outBoundsRect.union(p2x, p2y); + maxWidth = Math.max(maxWidth, width); } - // Take union for the bounds. - maxWidth = Math.max(maxWidth, width); } p1x = p2x; p1y = p2y; r1 = r2; - lastTime = elapsedTime; } // Take care of trail line width. final int inset = -((int)maxWidth + 1); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java index da418f41a..0f1d5cc80 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; @@ -240,14 +241,14 @@ public class KeyboardBuilder<KP extends KeyboardParams> { try { final int displayHeight = mDisplayMetrics.heightPixels; final String keyboardHeightString = ResourceUtils.getDeviceOverrideValue( - mResources, R.array.keyboard_heights, null); + mResources, R.array.keyboard_heights); final float keyboardHeight; - if (keyboardHeightString != null) { - keyboardHeight = Float.parseFloat(keyboardHeightString) - * mDisplayMetrics.density; - } else { + if (TextUtils.isEmpty(keyboardHeightString)) { keyboardHeight = keyboardAttr.getDimension( R.styleable.Keyboard_keyboardHeight, displayHeight / 2); + } else { + keyboardHeight = Float.parseFloat(keyboardHeightString) + * mDisplayMetrics.density; } final float maxKeyboardHeight = ResourceUtils.getDimensionOrFraction(keyboardAttr, R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2); diff --git a/java/src/com/android/inputmethod/keyboard/internal/TouchScreenRegulator.java b/java/src/com/android/inputmethod/keyboard/internal/TouchScreenRegulator.java index c795d5322..e7a0a70d1 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/TouchScreenRegulator.java +++ b/java/src/com/android/inputmethod/keyboard/internal/TouchScreenRegulator.java @@ -55,7 +55,7 @@ public final class TouchScreenRegulator { public TouchScreenRegulator(final Context context, final ProcessMotionEvent view) { mView = view; mNeedsSuddenJumpingHack = Boolean.parseBoolean(ResourceUtils.getDeviceOverrideValue( - context.getResources(), R.array.sudden_jumping_touch_event_device_list, "false")); + context.getResources(), R.array.sudden_jumping_touch_event_device_list)); } public void setKeyboardGeometry(final int keyboardWidth) { diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtype.java b/java/src/com/android/inputmethod/latin/AdditionalSubtype.java index 509fc1ba3..820733bdc 100644 --- a/java/src/com/android/inputmethod/latin/AdditionalSubtype.java +++ b/java/src/com/android/inputmethod/latin/AdditionalSubtype.java @@ -45,7 +45,7 @@ public final class AdditionalSubtype { final String keyboardLayoutSetName, final String extraValue) { final String layoutExtraValue = KEYBOARD_LAYOUT_SET + "=" + keyboardLayoutSetName; final String layoutDisplayNameExtraValue; - if (Build.VERSION.SDK_INT >= /* JELLY_BEAN */ 15 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && SubtypeLocale.isExceptionalLocale(localeString)) { final String layoutDisplayName = SubtypeLocale.getKeyboardLayoutSetDisplayName( keyboardLayoutSetName); diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java index 08f08d24e..6ac5a9b94 100644 --- a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java +++ b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java @@ -387,7 +387,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment { super.onCreate(savedInstanceState); mPrefs = getPreferenceManager().getSharedPreferences(); - RichInputMethodManager.init(getActivity(), mPrefs); + RichInputMethodManager.init(getActivity()); mRichImm = RichInputMethodManager.getInstance(); addPreferencesFromResource(R.xml.additional_subtype_settings); setHasOptionsMenu(true); diff --git a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java index 024726391..0e7f891ff 100644 --- a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java +++ b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java @@ -30,6 +30,8 @@ import com.android.inputmethod.latin.VibratorUtils; * complexity of settings and the like. */ public final class AudioAndHapticFeedbackManager { + public static final int MAX_KEYPRESS_VIBRATION_DURATION = 250; // millisecond + private final AudioManager mAudioManager; private final VibratorUtils mVibratorUtils; diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java index ba932e590..3a7772452 100644 --- a/java/src/com/android/inputmethod/latin/Constants.java +++ b/java/src/com/android/inputmethod/latin/Constants.java @@ -111,7 +111,7 @@ public final class Constants { } } - public static class TextUtils { + public static final class TextUtils { /** * Capitalization mode for {@link android.text.TextUtils#getCapsMode}: don't capitalize * characters. This value may be used with @@ -126,7 +126,7 @@ public final class Constants { } } - public static class Dictionary { + public static final class Dictionary { public static final int MAX_WORD_LENGTH = 48; private Dictionary() { @@ -139,6 +139,7 @@ public final class Constants { public static final int NOT_A_COORDINATE = -1; public static final int SUGGESTION_STRIP_COORDINATE = -2; public static final int SPELL_CHECKER_COORDINATE = -3; + public static final int EXTERNAL_KEYBOARD_COORDINATE = -4; public static boolean isValidCoordinate(final int coordinate) { // Detect {@link NOT_A_COORDINATE}, {@link SUGGESTION_STRIP_COORDINATE}, @@ -204,6 +205,7 @@ public final class Constants { case CODE_UNSPECIFIED: return "unspec"; case CODE_TAB: return "tab"; case CODE_ENTER: return "enter"; + case CODE_RESEARCH: return "research"; default: if (code < CODE_SPACE) return String.format("'\\u%02x'", code); if (code < 0x100) return String.format("'%c'", code); diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index 7f78ac8a2..9a771cf1e 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -38,7 +38,7 @@ public final class DictionaryCollection extends Dictionary { mDictionaries = CollectionUtils.newCopyOnWriteArrayList(); } - public DictionaryCollection(final String dictType, Dictionary... dictionaries) { + public DictionaryCollection(final String dictType, final Dictionary... dictionaries) { super(dictType); if (null == dictionaries) { mDictionaries = CollectionUtils.newCopyOnWriteArrayList(); @@ -48,7 +48,7 @@ public final class DictionaryCollection extends Dictionary { } } - public DictionaryCollection(final String dictType, Collection<Dictionary> dictionaries) { + public DictionaryCollection(final String dictType, final Collection<Dictionary> dictionaries) { super(dictType); mDictionaries = CollectionUtils.newCopyOnWriteArrayList(dictionaries); mDictionaries.removeAll(Collections.singleton(null)); diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 8196a97f8..f65bbe4a1 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -35,6 +35,7 @@ import android.graphics.Rect; import android.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.net.ConnectivityManager; +import android.os.Build.VERSION_CODES; import android.os.Debug; import android.os.Handler; import android.os.HandlerThread; @@ -145,7 +146,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction private final SubtypeState mSubtypeState = new SubtypeState(); // At start, create a default event interpreter that does nothing by passing it no decoder spec. // The event interpreter should never be null. - private EventInterpreter mEventInterpreter = new EventInterpreter(); + private EventInterpreter mEventInterpreter = new EventInterpreter(this); private boolean mIsMainDictionaryAvailable; private UserBinaryDictionary mUserDictionary; @@ -412,14 +413,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mPrefs = PreferenceManager.getDefaultSharedPreferences(this); mResources = getResources(); - LatinImeLogger.init(this, mPrefs); + LatinImeLogger.init(this); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.getInstance().init(this, mPrefs); + ResearchLogger.getInstance().init(this); } - RichInputMethodManager.init(this, mPrefs); + RichInputMethodManager.init(this); mRichImm = RichInputMethodManager.getInstance(); SubtypeSwitcher.init(this); - KeyboardSwitcher.init(this, mPrefs); + KeyboardSwitcher.init(this); AccessibilityUtils.init(this); super.onCreate(); @@ -582,10 +583,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction @Override public void onConfigurationChanged(final Configuration conf) { - // System locale has been changed. Needs to reload keyboard. - if (mSubtypeSwitcher.onConfigurationChanged(conf)) { - loadKeyboard(); - } // If orientation changed while predicting, commit the change if (mDisplayOrientation != conf.orientation) { mDisplayOrientation = conf.orientation; @@ -651,7 +648,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction public void onCurrentInputMethodSubtypeChanged(final InputMethodSubtype subtype) { // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() // is not guaranteed. It may even be called at the same time on a different thread. - mSubtypeSwitcher.updateSubtype(subtype); + mSubtypeSwitcher.onSubtypeChanged(subtype); loadKeyboard(); } @@ -719,15 +716,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final boolean inputTypeChanged = !mCurrentSettings.isSameInputType(editorInfo); final boolean isDifferentTextField = !restarting || inputTypeChanged; if (isDifferentTextField) { - final boolean currentSubtypeEnabled = mSubtypeSwitcher - .updateParametersOnStartInputViewAndReturnIfCurrentSubtypeEnabled(); - if (!currentSubtypeEnabled) { - // Current subtype is disabled. Needs to update subtype and keyboard. - final InputMethodSubtype newSubtype = mRichImm.getCurrentInputMethodSubtype( - mSubtypeSwitcher.getNoLanguageSubtype()); - mSubtypeSwitcher.updateSubtype(newSubtype); - loadKeyboard(); - } + mSubtypeSwitcher.updateParametersOnStartInputView(); } // The EditorInfo might have a flag that affects fullscreen mode. @@ -1009,9 +998,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final boolean isAutoCorrection = false; setSuggestionStrip(suggestedWords, isAutoCorrection); setAutoCorrectionIndicator(isAutoCorrection); - // TODO: is this the right thing to do? What should we auto-correct to in - // this case? This says to keep whatever the user typed. - mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); setSuggestionStripShown(true); if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions); @@ -1152,6 +1138,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction if (typedWord.length() > 0) { commitChosenWord(typedWord, LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, separatorString); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.getInstance().onWordComplete(typedWord, Long.MAX_VALUE); + } } } @@ -1187,8 +1176,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction if (lastTwo != null && lastTwo.length() == 2 && lastTwo.charAt(0) == Constants.CODE_SPACE) { mConnection.deleteSurroundingText(2, 0); - mConnection.commitText(lastTwo.charAt(1) + " ", 1); + final String text = lastTwo.charAt(1) + " "; + mConnection.commitText(text, 1); if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.getInstance().onWordComplete(text, Long.MAX_VALUE); ResearchLogger.latinIME_swapSwapperAndSpace(); } mKeyboardSwitcher.updateShiftState(); @@ -1206,7 +1197,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction && lastThree.charAt(2) == Constants.CODE_SPACE) { mHandler.cancelDoubleSpacePeriodTimer(); mConnection.deleteSurroundingText(2, 0); - mConnection.commitText(". ", 1); + final String textToInsert = ". "; + mConnection.commitText(textToInsert, 1); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.getInstance().onWordComplete(textToInsert, Long.MAX_VALUE); + } mKeyboardSwitcher.updateShiftState(); return true; } @@ -1324,10 +1319,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction return; } - // 16 is android.os.Build.VERSION_CODES.JELLY_BEAN but we can't write it because - // we want to be able to compile against the Ice Cream Sandwich SDK. if (Constants.CODE_ENTER == code && mTargetApplicationInfo != null - && mTargetApplicationInfo.targetSdkVersion < 16) { + && mTargetApplicationInfo.targetSdkVersion < VERSION_CODES.JELLY_BEAN) { // Backward compatibility mode. Before Jelly bean, the keyboard would simulate // a hardware keyboard event on pressing enter or delete. This is bad for many // reasons (there are race conditions with commits) but some applications are @@ -1445,7 +1438,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction public void onTextInput(final String rawText) { mConnection.beginBatchEdit(); if (mWordComposer.isComposingWord()) { - commitCurrentAutoCorrection(rawText.toString()); + commitCurrentAutoCorrection(rawText); } else { resetComposingState(true /* alsoResetLastComposedWord */); } @@ -1455,6 +1448,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction promotePhantomSpace(); } mConnection.commitText(text, 1); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.getInstance().onWordComplete(text, Long.MAX_VALUE); + } mConnection.endBatchEdit(); // Space state must be updated before calling updateShiftState mSpaceState = SPACE_STATE_NONE; @@ -1679,6 +1675,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction if (length > 0) { if (mWordComposer.isBatchMode()) { mWordComposer.reset(); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.latinIME_handleBackspace_batch(mWordComposer.getTypedWord()); + } } else { mWordComposer.deleteLast(); } @@ -1734,10 +1733,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // This should never happen. Log.e(TAG, "Backspace when we don't know the selection position"); } - // 16 is android.os.Build.VERSION_CODES.JELLY_BEAN but we can't write it because - // we want to be able to compile against the Ice Cream Sandwich SDK. if (mTargetApplicationInfo != null - && mTargetApplicationInfo.targetSdkVersion < 16) { + && mTargetApplicationInfo.targetSdkVersion < VERSION_CODES.JELLY_BEAN) { // Backward compatibility mode. Before Jelly bean, the keyboard would simulate // a hardware keyboard event on pressing enter or delete. This is bad for many // reasons (there are race conditions with commits) but some applications are @@ -1920,6 +1917,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } private void handleClose() { + // TODO: Verify that words are logged properly when IME is closed. commitTyped(LastComposedWord.NOT_A_SEPARATOR); requestHideSelf(0); final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); @@ -1983,7 +1981,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction if (mWordComposer.isComposingWord()) { Log.w(TAG, "Called updateSuggestionsOrPredictions but suggestions were not " + "requested!"); - mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); } return; } @@ -2086,10 +2083,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction + "is empty? Impossible! I must commit suicide."); } if (ProductionFlag.IS_INTERNAL) { - Stats.onAutoCorrection( - typedWord, autoCorrection.toString(), separatorString, mWordComposer); + Stats.onAutoCorrection(typedWord, autoCorrection, separatorString, mWordComposer); } mExpectingUpdateSelection = true; + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection, + separatorString); + } + commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, separatorString); if (!typedWord.equals(autoCorrection)) { @@ -2115,7 +2116,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction if (suggestion.length() == 1 && isShowingPunctuationList()) { // Word separators are suggested before the user inputs something. // So, LatinImeLogger logs "" as a user's input. - LatinImeLogger.logOnManualSuggestion("", suggestion.toString(), index, suggestedWords); + LatinImeLogger.logOnManualSuggestion("", suggestion, index, suggestedWords); // Rely on onCodeInput to do the complicated swapping/stripping logic consistently. final int primaryCode = suggestion.charAt(0); onCodeInput(primaryCode, @@ -2154,9 +2155,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // We need to log before we commit, because the word composer will store away the user // typed word. - final String replacedWord = mWordComposer.getTypedWord().toString(); - LatinImeLogger.logOnManualSuggestion(replacedWord, - suggestion.toString(), index, suggestedWords); + final String replacedWord = mWordComposer.getTypedWord(); + LatinImeLogger.logOnManualSuggestion(replacedWord, suggestion, index, suggestedWords); mExpectingUpdateSelection = true; commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, LastComposedWord.NOT_A_SEPARATOR); @@ -2205,8 +2205,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // what user typed. Note: currently this is done much later in // LastComposedWord#didCommitTypedWord by string equality of the remembered // strings. - mLastComposedWord = mWordComposer.commitWord(commitType, chosenWord.toString(), - separatorString, prevWord); + mLastComposedWord = mWordComposer.commitWord(commitType, chosenWord, separatorString, + prevWord); } private void setPunctuationSuggestions() { @@ -2230,7 +2230,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final UserHistoryDictionary userHistoryDictionary = mUserHistoryDictionary; if (userHistoryDictionary != null) { - final CharSequence prevWord + final String prevWord = mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, 2); final String secondWord; if (mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps()) { @@ -2243,9 +2243,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final int maxFreq = AutoCorrection.getMaxFrequency( mSuggest.getUnigramDictionaries(), suggestion); if (maxFreq == 0) return null; - final String prevWordString = (null == prevWord) ? null : prevWord.toString(); - userHistoryDictionary.addToUserHistory(prevWordString, secondWord, maxFreq > 0); - return prevWordString; + userHistoryDictionary.addToUserHistory(prevWord, secondWord, maxFreq > 0); + return prevWord; } return null; } @@ -2293,8 +2292,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } mConnection.deleteSurroundingText(deleteLength, 0); if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) { - mUserHistoryDictionary.cancelAddingUserHistory( - previousWord.toString(), committedWord.toString()); + mUserHistoryDictionary.cancelAddingUserHistory(previousWord, committedWord); } mConnection.commitText(originallyTypedWord + mLastComposedWord.mSeparatorString, 1); if (ProductionFlag.IS_INTERNAL) { @@ -2302,7 +2300,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); } if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_revertCommit(originallyTypedWord); + ResearchLogger.latinIME_revertCommit(committedWord, originallyTypedWord); + ResearchLogger.getInstance().onWordComplete(originallyTypedWord, Long.MAX_VALUE); } // Don't restart suggestion yet. We'll restart if the user deletes the // separator. @@ -2390,7 +2389,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction @Override public boolean onKeyUp(final int keyCode, final KeyEvent event) { - if (mEventInterpreter.onHardwareKeyEvent(event)) return true; return super.onKeyUp(keyCode, event); } diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java index 394a9c7aa..e4e8b94b2 100644 --- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java +++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java @@ -31,7 +31,7 @@ public final class LatinImeLogger implements SharedPreferences.OnSharedPreferenc public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { } - public static void init(LatinIME context, SharedPreferences prefs) { + public static void init(LatinIME context) { } public static void commit() { diff --git a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java b/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java index 8a2d22256..1fd25636c 100644 --- a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java +++ b/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java @@ -29,7 +29,7 @@ import android.view.inputmethod.EditorInfo; * the IME needs to take a note of what it has to replace and where it is. * This class encapsulates this data. */ -public class PositionalInfoForUserDictPendingAddition { +public final class PositionalInfoForUserDictPendingAddition { final private String mOriginalWord; final private int mCursorPos; // Position of the cursor after the word final private EditorInfo mEditorInfo; // On what binding this has been added diff --git a/java/src/com/android/inputmethod/latin/ResourceUtils.java b/java/src/com/android/inputmethod/latin/ResourceUtils.java index 5021ad384..b74b979b5 100644 --- a/java/src/com/android/inputmethod/latin/ResourceUtils.java +++ b/java/src/com/android/inputmethod/latin/ResourceUtils.java @@ -19,11 +19,15 @@ package com.android.inputmethod.latin; import android.content.res.Resources; import android.content.res.TypedArray; import android.os.Build; +import android.util.Log; import android.util.TypedValue; import java.util.HashMap; public final class ResourceUtils { + private static final String TAG = ResourceUtils.class.getSimpleName(); + private static final boolean DEBUG = false; + public static final float UNDEFINED_RATIO = -1.0f; public static final int UNDEFINED_DIMENSION = -1; @@ -31,24 +35,44 @@ public final class ResourceUtils { // This utility class is not publicly instantiable. } + private static final String DEFAULT_PREFIX = "DEFAULT,"; private static final String HARDWARE_PREFIX = Build.HARDWARE + ","; private static final HashMap<String, String> sDeviceOverrideValueMap = CollectionUtils.newHashMap(); - public static String getDeviceOverrideValue(Resources res, int overrideResId, String defValue) { + public static String getDeviceOverrideValue(final Resources res, final int overrideResId) { final int orientation = res.getConfiguration().orientation; final String key = overrideResId + "-" + orientation; - if (!sDeviceOverrideValueMap.containsKey(key)) { - String overrideValue = defValue; - for (final String element : res.getStringArray(overrideResId)) { - if (element.startsWith(HARDWARE_PREFIX)) { - overrideValue = element.substring(HARDWARE_PREFIX.length()); - break; - } + if (sDeviceOverrideValueMap.containsKey(key)) { + return sDeviceOverrideValueMap.get(key); + } + + final String[] overrideArray = res.getStringArray(overrideResId); + final String overrideValue = StringUtils.findPrefixedString(HARDWARE_PREFIX, overrideArray); + // The overrideValue might be an empty string. + if (overrideValue != null) { + if (DEBUG) { + Log.d(TAG, "Find override value:" + + " resource="+ res.getResourceEntryName(overrideResId) + + " Build.HARDWARE=" + Build.HARDWARE + " override=" + overrideValue); } sDeviceOverrideValueMap.put(key, overrideValue); + return overrideValue; + } + + final String defaultValue = StringUtils.findPrefixedString(DEFAULT_PREFIX, overrideArray); + // The defaultValue might be an empty string. + if (defaultValue == null) { + Log.w(TAG, "Couldn't find override value nor default value:" + + " resource="+ res.getResourceEntryName(overrideResId) + + " Build.HARDWARE=" + Build.HARDWARE); + } else if (DEBUG) { + Log.d(TAG, "Found default value:" + + " resource="+ res.getResourceEntryName(overrideResId) + + " Build.HARDWARE=" + Build.HARDWARE + " default=" + defaultValue); } - return sDeviceOverrideValueMap.get(key); + sDeviceOverrideValueMap.put(key, defaultValue); + return defaultValue; } public static boolean isValidFraction(final float fraction) { @@ -85,8 +109,8 @@ public final class ResourceUtils { return a.getDimensionPixelSize(index, ResourceUtils.UNDEFINED_DIMENSION); } - public static float getDimensionOrFraction(TypedArray a, int index, int base, - float defValue) { + public static float getDimensionOrFraction(final TypedArray a, final int index, final int base, + final float defValue) { final TypedValue value = a.peekValue(index); if (value == null) { return defValue; @@ -99,7 +123,7 @@ public final class ResourceUtils { return defValue; } - public static int getEnumValue(TypedArray a, int index, int defValue) { + public static int getEnumValue(final TypedArray a, final int index, final int defValue) { final TypedValue value = a.peekValue(index); if (value == null) { return defValue; @@ -110,19 +134,19 @@ public final class ResourceUtils { return defValue; } - public static boolean isFractionValue(TypedValue v) { + public static boolean isFractionValue(final TypedValue v) { return v.type == TypedValue.TYPE_FRACTION; } - public static boolean isDimensionValue(TypedValue v) { + public static boolean isDimensionValue(final TypedValue v) { return v.type == TypedValue.TYPE_DIMENSION; } - public static boolean isIntegerValue(TypedValue v) { + public static boolean isIntegerValue(final TypedValue v) { return v.type >= TypedValue.TYPE_FIRST_INT && v.type <= TypedValue.TYPE_LAST_INT; } - public static boolean isStringValue(TypedValue v) { + public static boolean isStringValue(final TypedValue v) { return v.type == TypedValue.TYPE_STRING; } } diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index e9c81dab0..9cb24b54e 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -178,9 +178,6 @@ public final class RichInputConnection { mComposingText.setLength(0); if (null != mIC) { mIC.commitText(text, i); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.richInputConnection_commitText(text, i); - } } } @@ -287,40 +284,40 @@ public final class RichInputConnection { if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) { if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); - // This method is only called for enter or backspace when speaking to old - // applications (target SDK <= 15), or for digits. + // This method is only called for enter or backspace when speaking to old applications + // (target SDK <= 15 (Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)), or for digits. // When talking to new applications we never use this method because it's inherently // racy and has unpredictable results, but for backward compatibility we continue // sending the key events for only Enter and Backspace because some applications // mistakenly catch them to do some stuff. switch (keyEvent.getKeyCode()) { - case KeyEvent.KEYCODE_ENTER: - mCommittedTextBeforeComposingText.append("\n"); - mCurrentCursorPosition += 1; - break; - case KeyEvent.KEYCODE_DEL: - if (0 == mComposingText.length()) { - if (mCommittedTextBeforeComposingText.length() > 0) { - mCommittedTextBeforeComposingText.delete( - mCommittedTextBeforeComposingText.length() - 1, - mCommittedTextBeforeComposingText.length()); - } - } else { - mComposingText.delete(mComposingText.length() - 1, mComposingText.length()); - } - if (mCurrentCursorPosition > 0) mCurrentCursorPosition -= 1; - break; - case KeyEvent.KEYCODE_UNKNOWN: - if (null != keyEvent.getCharacters()) { - mCommittedTextBeforeComposingText.append(keyEvent.getCharacters()); - mCurrentCursorPosition += keyEvent.getCharacters().length(); + case KeyEvent.KEYCODE_ENTER: + mCommittedTextBeforeComposingText.append("\n"); + mCurrentCursorPosition += 1; + break; + case KeyEvent.KEYCODE_DEL: + if (0 == mComposingText.length()) { + if (mCommittedTextBeforeComposingText.length() > 0) { + mCommittedTextBeforeComposingText.delete( + mCommittedTextBeforeComposingText.length() - 1, + mCommittedTextBeforeComposingText.length()); } - break; - default: - final String text = new String(new int[] { keyEvent.getUnicodeChar() }, 0, 1); - mCommittedTextBeforeComposingText.append(text); - mCurrentCursorPosition += text.length(); - break; + } else { + mComposingText.delete(mComposingText.length() - 1, mComposingText.length()); + } + if (mCurrentCursorPosition > 0) mCurrentCursorPosition -= 1; + break; + case KeyEvent.KEYCODE_UNKNOWN: + if (null != keyEvent.getCharacters()) { + mCommittedTextBeforeComposingText.append(keyEvent.getCharacters()); + mCurrentCursorPosition += keyEvent.getCharacters().length(); + } + break; + default: + final String text = new String(new int[] { keyEvent.getUnicodeChar() }, 0, 1); + mCommittedTextBeforeComposingText.append(text); + mCurrentCursorPosition += text.length(); + break; } } if (null != mIC) { @@ -537,17 +534,17 @@ public final class RichInputConnection { // Going backward, alternate skipping non-separators and separators until enough words // have been read. int count = additionalPrecedingWordsCount; - int start = before.length(); + int startIndexInBefore = before.length(); boolean isStoppingAtWhitespace = true; // toggles to indicate what to stop at while (true) { // see comments below for why this is guaranteed to halt - while (start > 0) { - final int codePoint = Character.codePointBefore(before, start); + while (startIndexInBefore > 0) { + final int codePoint = Character.codePointBefore(before, startIndexInBefore); if (isStoppingAtWhitespace == isSeparator(codePoint, sep)) { break; // inner loop } - --start; + --startIndexInBefore; if (Character.isSupplementaryCodePoint(codePoint)) { - --start; + --startIndexInBefore; } } // isStoppingAtWhitespace is true every other time through the loop, @@ -560,25 +557,20 @@ public final class RichInputConnection { } // Find last word separator after the cursor - int end = -1; - while (++end < after.length()) { - final int codePoint = Character.codePointAt(after, end); + int endIndexInAfter = -1; + while (++endIndexInAfter < after.length()) { + final int codePoint = Character.codePointAt(after, endIndexInAfter); if (isSeparator(codePoint, sep)) { break; } if (Character.isSupplementaryCodePoint(codePoint)) { - ++end; + ++endIndexInAfter; } } - final int cursor = getCursorPosition(); - if (start >= 0 && cursor + end <= after.length() + before.length()) { - String word = before.toString().substring(start, before.length()) - + after.toString().substring(0, end); - return new Range(before.length() - start, end, word); - } - - return null; + final String word = before.toString().substring(startIndexInBefore, before.length()) + + after.toString().substring(0, endIndexInAfter); + return new Range(before.length() - startIndexInBefore, endIndexInAfter, word); } public boolean isCursorTouchingWord(final SettingsValues settingsValues) { @@ -665,7 +657,11 @@ public final class RichInputConnection { return false; } deleteSurroundingText(2, 0); - commitText(" ", 1); + final String doubleSpace = " "; + commitText(doubleSpace, 1); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.getInstance().onWordComplete(doubleSpace, Long.MAX_VALUE); + } return true; } @@ -686,7 +682,11 @@ public final class RichInputConnection { return false; } deleteSurroundingText(2, 0); - commitText(" " + textBeforeCursor.subSequence(0, 1), 1); + final String text = " " + textBeforeCursor.subSequence(0, 1); + commitText(text, 1); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.getInstance().onWordComplete(text, Long.MAX_VALUE); + } return true; } diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java index af0d61cc7..637916f76 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java @@ -21,6 +21,7 @@ import static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE; import android.content.Context; import android.content.SharedPreferences; import android.os.IBinder; +import android.preference.PreferenceManager; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; @@ -50,7 +51,8 @@ public final class RichInputMethodManager { return sInstance; } - public static void init(final Context context, final SharedPreferences prefs) { + public static void init(final Context context) { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); sInstance.initInternal(context, prefs); } diff --git a/java/src/com/android/inputmethod/latin/SeekBarDialog.java b/java/src/com/android/inputmethod/latin/SeekBarDialog.java new file mode 100644 index 000000000..e576c0984 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/SeekBarDialog.java @@ -0,0 +1,179 @@ +/* + * 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; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; +import android.widget.TextView; + +public final class SeekBarDialog implements DialogInterface.OnClickListener, + OnSeekBarChangeListener { + public interface Listener { + public void onPositiveButtonClick(final SeekBarDialog dialog); + public void onNegativeButtonClick(final SeekBarDialog dialog); + public void onProgressChanged(final SeekBarDialog dialog); + public void onStartTrackingTouch(final SeekBarDialog dialog); + public void onStopTrackingTouch(final SeekBarDialog dialog); + } + + public static class Adapter implements Listener { + @Override + public void onPositiveButtonClick(final SeekBarDialog dialog) {} + @Override + public void onNegativeButtonClick(final SeekBarDialog dialog) { dialog.dismiss(); } + @Override + public void onProgressChanged(final SeekBarDialog dialog) {} + @Override + public void onStartTrackingTouch(final SeekBarDialog dialog) {} + @Override + public void onStopTrackingTouch(final SeekBarDialog dialog) {} + } + + private static final Listener EMPTY_ADAPTER = new Adapter(); + + private final AlertDialog mDialog; + private final Listener mListener; + private final TextView mValueView; + private final SeekBar mSeekBar; + private final String mValueFormat; + + private int mValue; + + private SeekBarDialog(final Builder builder) { + final AlertDialog.Builder dialogBuilder = builder.mDialogBuilder; + dialogBuilder.setView(builder.mView); + dialogBuilder.setPositiveButton(android.R.string.ok, this); + dialogBuilder.setNegativeButton(android.R.string.cancel, this); + mDialog = dialogBuilder.create(); + mListener = (builder.mListener == null) ? EMPTY_ADAPTER : builder.mListener; + mValueView = (TextView)builder.mView.findViewById(R.id.seek_bar_dialog_value); + mSeekBar = (SeekBar)builder.mView.findViewById(R.id.seek_bar_dialog_bar); + mSeekBar.setMax(builder.mMaxValue); + mSeekBar.setOnSeekBarChangeListener(this); + if (builder.mValueFormatResId == 0) { + mValueFormat = "%s"; + } else { + mValueFormat = mDialog.getContext().getString(builder.mValueFormatResId); + } + } + + public void setValue(final int value, final boolean fromUser) { + mValue = value; + mValueView.setText(String.format(mValueFormat, value)); + if (!fromUser) { + mSeekBar.setProgress(value); + } + } + + public int getValue() { + return mValue; + } + + public CharSequence getValueText() { + return mValueView.getText(); + } + + public void show() { + mDialog.show(); + } + + public void dismiss() { + mDialog.dismiss(); + } + + @Override + public void onClick(final DialogInterface dialog, int which) { + if (which == DialogInterface.BUTTON_POSITIVE) { + mListener.onPositiveButtonClick(this); + return; + } + if (which == DialogInterface.BUTTON_NEGATIVE) { + mListener.onNegativeButtonClick(this); + return; + } + } + + @Override + public void onProgressChanged(final SeekBar seekBar, final int progress, + final boolean fromUser) { + setValue(progress, fromUser); + if (fromUser) { + mListener.onProgressChanged(this); + } + } + + @Override + public void onStartTrackingTouch(final SeekBar seekBar) { + mListener.onStartTrackingTouch(this); + } + + @Override + public void onStopTrackingTouch(final SeekBar seekBar) { + mListener.onStopTrackingTouch(this); + } + + public static final class Builder { + final AlertDialog.Builder mDialogBuilder; + final View mView; + + int mMaxValue; + int mValueFormatResId; + int mValue; + Listener mListener; + + public Builder(final Context context) { + mDialogBuilder = new AlertDialog.Builder(context); + mView = LayoutInflater.from(context).inflate(R.layout.seek_bar_dialog, null); + } + + public Builder setTitle(final int resId) { + mDialogBuilder.setTitle(resId); + return this; + } + + public Builder setMaxValue(final int max) { + mMaxValue = max; + return this; + } + + public Builder setValueFromat(final int resId) { + mValueFormatResId = resId; + return this; + } + + public Builder setValue(final int value) { + mValue = value; + return this; + } + + public Builder setListener(final Listener listener) { + mListener = listener; + return this; + } + + public SeekBarDialog create() { + final SeekBarDialog dialog = new SeekBarDialog(this); + dialog.setValue(mValue, false /* fromUser */); + return dialog; + } + } +} diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 7a73cade3..222adcb2e 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -16,10 +16,8 @@ package com.android.inputmethod.latin; -import android.app.AlertDialog; import android.app.backup.BackupManager; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; @@ -31,12 +29,7 @@ import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; -import android.view.LayoutInflater; -import android.view.View; import android.view.inputmethod.InputMethodSubtype; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; -import android.widget.TextView; import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethodcommon.InputMethodSettingsFragment; @@ -94,9 +87,6 @@ public final class Settings extends InputMethodSettingsFragment private CheckBoxPreference mBigramPrediction; private Preference mDebugSettingsPreference; - private TextView mKeypressVibrationDurationSettingsTextView; - private TextView mKeypressSoundVolumeSettingsTextView; - private static void setPreferenceEnabled(final Preference preference, final boolean enabled) { if (preference != null) { preference.setEnabled(enabled); @@ -127,7 +117,7 @@ public final class Settings extends InputMethodSettingsFragment mVoicePreference = (ListPreference) findPreference(PREF_VOICE_MODE); mShowCorrectionSuggestionsPreference = (ListPreference) findPreference(PREF_SHOW_SUGGESTIONS_SETTING); - SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); + final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); prefs.registerOnSharedPreferenceChangeListener(this); mAutoCorrectionThresholdPreference = @@ -227,7 +217,9 @@ public final class Settings extends InputMethodSettingsFragment return true; } }); - updateKeypressVibrationDurationSettingsSummary(prefs, res); + mKeypressVibrationDurationSettingsPref.setSummary( + res.getString(R.string.settings_keypress_vibration_duration, + SettingsValues.getCurrentVibrationDuration(prefs, res))); } mKeypressSoundVolumeSettingsPref = @@ -241,7 +233,8 @@ public final class Settings extends InputMethodSettingsFragment return true; } }); - updateKeypressSoundVolumeSummary(prefs, res); + mKeypressSoundVolumeSettingsPref.setSummary(String.valueOf( + getCurrentKeyPressSoundVolumePercent(prefs, res))); } refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res); } @@ -349,122 +342,73 @@ public final class Settings extends InputMethodSettingsFragment } } - private void updateKeypressVibrationDurationSettingsSummary( - final SharedPreferences sp, final Resources res) { - if (mKeypressVibrationDurationSettingsPref != null) { - mKeypressVibrationDurationSettingsPref.setSummary( - SettingsValues.getCurrentVibrationDuration(sp, res) - + res.getString(R.string.settings_ms)); - } - } - private void showKeypressVibrationDurationSettingsDialog() { final SharedPreferences sp = getPreferenceManager().getSharedPreferences(); final Context context = getActivity(); - final Resources res = context.getResources(); - final AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.prefs_keypress_vibration_duration_settings); - builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + final PreferenceScreen settingsPref = mKeypressVibrationDurationSettingsPref; + final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() { @Override - public void onClick(DialogInterface dialog, int whichButton) { - final int ms = Integer.valueOf( - mKeypressVibrationDurationSettingsTextView.getText().toString()); + public void onPositiveButtonClick(final SeekBarDialog dialog) { + final int ms = dialog.getValue(); sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, ms).apply(); - updateKeypressVibrationDurationSettingsSummary(sp, res); - } - }); - builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - dialog.dismiss(); - } - }); - final View v = LayoutInflater.from(context).inflate( - R.layout.vibration_settings_dialog, null); - final int currentMs = SettingsValues.getCurrentVibrationDuration( - getPreferenceManager().getSharedPreferences(), getResources()); - mKeypressVibrationDurationSettingsTextView = (TextView)v.findViewById(R.id.vibration_value); - final SeekBar sb = (SeekBar)v.findViewById(R.id.vibration_settings); - sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) { - final int tempMs = arg1; - mKeypressVibrationDurationSettingsTextView.setText(String.valueOf(tempMs)); - } - - @Override - public void onStartTrackingTouch(SeekBar arg0) { + if (settingsPref != null) { + settingsPref.setSummary(dialog.getValueText()); + } } @Override - public void onStopTrackingTouch(SeekBar arg0) { - final int tempMs = arg0.getProgress(); - VibratorUtils.getInstance(context).vibrate(tempMs); + public void onStopTrackingTouch(final SeekBarDialog dialog) { + final int ms = dialog.getValue(); + VibratorUtils.getInstance(context).vibrate(ms); } - }); - sb.setProgress(currentMs); - mKeypressVibrationDurationSettingsTextView.setText(String.valueOf(currentMs)); - builder.setView(v); - builder.create().show(); + }; + final int currentMs = SettingsValues.getCurrentVibrationDuration(sp, getResources()); + final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context); + builder.setTitle(R.string.prefs_keypress_vibration_duration_settings) + .setListener(listener) + .setMaxValue(AudioAndHapticFeedbackManager.MAX_KEYPRESS_VIBRATION_DURATION) + .setValueFromat(R.string.settings_keypress_vibration_duration) + .setValue(currentMs) + .create() + .show(); } - private void updateKeypressSoundVolumeSummary(final SharedPreferences sp, final Resources res) { - if (mKeypressSoundVolumeSettingsPref != null) { - mKeypressSoundVolumeSettingsPref.setSummary(String.valueOf( - (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * 100))); - } + private static final int PERCENT_INT = 100; + private static final float PERCENT_FLOAT = 100.0f; + + private static int getCurrentKeyPressSoundVolumePercent(final SharedPreferences sp, + final Resources res) { + return (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * PERCENT_FLOAT); } private void showKeypressSoundVolumeSettingDialog() { + final SharedPreferences sp = getPreferenceManager().getSharedPreferences(); final Context context = getActivity(); final AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - final SharedPreferences sp = getPreferenceManager().getSharedPreferences(); - final Resources res = context.getResources(); - final AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.prefs_keypress_sound_volume_settings); - builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + final PreferenceScreen settingsPref = mKeypressSoundVolumeSettingsPref; + final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() { @Override - public void onClick(DialogInterface dialog, int whichButton) { - final float volume = - ((float)Integer.valueOf( - mKeypressSoundVolumeSettingsTextView.getText().toString())) / 100; + public void onPositiveButtonClick(final SeekBarDialog dialog) { + final float volume = dialog.getValue() / PERCENT_FLOAT; sp.edit().putFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, volume).apply(); - updateKeypressSoundVolumeSummary(sp, res); - } - }); - builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - dialog.dismiss(); - } - }); - final View v = LayoutInflater.from(context).inflate( - R.layout.sound_effect_volume_dialog, null); - final int currentVolumeInt = - (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * 100); - mKeypressSoundVolumeSettingsTextView = - (TextView)v.findViewById(R.id.sound_effect_volume_value); - final SeekBar sb = (SeekBar)v.findViewById(R.id.sound_effect_volume_bar); - sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) { - final int tempVolume = arg1; - mKeypressSoundVolumeSettingsTextView.setText(String.valueOf(tempVolume)); - } - - @Override - public void onStartTrackingTouch(SeekBar arg0) { + if (settingsPref != null) { + settingsPref.setSummary(dialog.getValueText()); + } } @Override - public void onStopTrackingTouch(SeekBar arg0) { - final float tempVolume = ((float)arg0.getProgress()) / 100; - am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, tempVolume); + public void onStopTrackingTouch(final SeekBarDialog dialog) { + final float volume = dialog.getValue() / PERCENT_FLOAT; + am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, volume); } - }); - sb.setProgress(currentVolumeInt); - mKeypressSoundVolumeSettingsTextView.setText(String.valueOf(currentVolumeInt)); - builder.setView(v); - builder.create().show(); + }; + final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context); + final int currentVolumeInt = getCurrentKeyPressSoundVolumePercent(sp, getResources()); + builder.setTitle(R.string.prefs_keypress_sound_volume_settings) + .setListener(listener) + .setMaxValue(PERCENT_INT) + .setValue(currentVolumeInt) + .create() + .show(); } } diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index a23876722..157684437 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -78,10 +78,6 @@ public final class SettingsValues { public final boolean mUseDoubleSpacePeriod; // Use bigrams to predict the next word when there is no input for it yet public final boolean mBigramPredictionEnabled; - @SuppressWarnings("unused") // TODO: Use this - private final int mVibrationDurationSettingsRawValue; - @SuppressWarnings("unused") // TODO: Use this - private final float mKeypressSoundVolumeRawValue; public final boolean mGestureInputEnabled; public final boolean mGesturePreviewTrailEnabled; public final boolean mGestureFloatingPreviewTextEnabled; @@ -158,9 +154,6 @@ public final class SettingsValues { mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true); mAutoCorrectEnabled = isAutoCorrectEnabled(res, mAutoCorrectionThresholdRawValue); mBigramPredictionEnabled = isBigramPredictionEnabled(prefs, res); - mVibrationDurationSettingsRawValue = - prefs.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1); - mKeypressSoundVolumeRawValue = prefs.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f); // Compute other readable settings mKeypressVibrationDuration = getCurrentVibrationDuration(prefs, res); @@ -383,27 +376,23 @@ public final class SettingsValues { // Accessed from the settings interface, hence public public static float getCurrentKeypressSoundVolume(final SharedPreferences prefs, final Resources res) { - // TODO: use mVibrationDurationSettingsRawValue instead of reading it again here final float volume = prefs.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f); if (volume >= 0) { return volume; } - - return Float.parseFloat(ResourceUtils.getDeviceOverrideValue( - res, R.array.keypress_volumes, "-1.0f")); + return Float.parseFloat( + ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_volumes)); } // Likewise public static int getCurrentVibrationDuration(final SharedPreferences prefs, final Resources res) { - // TODO: use mKeypressVibrationDuration instead of reading it again here final int ms = prefs.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1); if (ms >= 0) { return ms; } - - return Integer.parseInt(ResourceUtils.getDeviceOverrideValue( - res, R.array.keypress_vibration_durations, "-1")); + return Integer.parseInt( + ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_vibration_durations)); } // Likewise diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index 043043cef..ddaa5ff5b 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -62,6 +62,23 @@ public final class StringUtils { } /** + * Find a string that start with specified prefix from an array. + * + * @param prefix a prefix string to find. + * @param array an string array to be searched. + * @return the rest part of the string that starts with the prefix. + * Returns null if it couldn't be found. + */ + public static String findPrefixedString(final String prefix, final String[] array) { + for (final String element : array) { + if (element.startsWith(prefix)) { + return element.substring(prefix.length()); + } + } + return null; + } + + /** * Remove duplicates from an array of strings. * * This method will always keep the first occurrence of all strings at their position diff --git a/java/src/com/android/inputmethod/latin/SubtypeLocale.java b/java/src/com/android/inputmethod/latin/SubtypeLocale.java index 5d8c0b17d..370a6594b 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeLocale.java +++ b/java/src/com/android/inputmethod/latin/SubtypeLocale.java @@ -130,7 +130,8 @@ public final class SubtypeLocale { } public static int getSubtypeNameId(String localeString, String keyboardLayoutName) { - if (Build.VERSION.SDK_INT >= /* JELLY_BEAN */ 15 && isExceptionalLocale(localeString)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN + && isExceptionalLocale(localeString)) { return sExceptionalLocaleToWithLayoutNameIdsMap.get(localeString); } final String key = localeString.equals(NO_LANGUAGE) @@ -166,8 +167,9 @@ public final class SubtypeLocale { // zz azerty T No language (AZERTY) in system locale public static String getSubtypeDisplayName(final InputMethodSubtype subtype, Resources res) { - final String replacementString = (Build.VERSION.SDK_INT >= /* JELLY_BEAN */ 15 - && subtype.containsExtraValueKey(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME)) + final String replacementString = + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN + && subtype.containsExtraValueKey(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME)) ? subtype.getExtraValueOf(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME) : getSubtypeLocaleDisplayName(subtype.getLocale()); final int nameResId = subtype.getNameResId(); diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 8f2e27549..fe2908428 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -20,7 +20,6 @@ import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.REQ_NET import android.content.Context; import android.content.Intent; -import android.content.res.Configuration; import android.content.res.Resources; import android.inputmethodservice.InputMethodService; import android.net.ConnectivityManager; @@ -53,9 +52,6 @@ public final class SubtypeSwitcher { private InputMethodInfo mShortcutInputMethodInfo; private InputMethodSubtype mShortcutSubtype; private InputMethodSubtype mNoLanguageSubtype; - // Note: This variable is always non-null after {@link #initialize(LatinIME)}. - private InputMethodSubtype mCurrentSubtype; - private Locale mCurrentSystemLocale; /*-----------------------------------------------------------*/ private boolean mIsNetworkConnected; @@ -84,7 +80,6 @@ public final class SubtypeSwitcher { public static void init(final Context context) { SubtypeLocale.init(context); sInstance.initialize(context); - sInstance.updateAllParameters(); } private SubtypeSwitcher() { @@ -96,60 +91,28 @@ public final class SubtypeSwitcher { mRichImm = RichInputMethodManager.getInstance(); mConnectivityManager = (ConnectivityManager) service.getSystemService( Context.CONNECTIVITY_SERVICE); - mCurrentSystemLocale = mResources.getConfiguration().locale; mNoLanguageSubtype = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( SubtypeLocale.NO_LANGUAGE, SubtypeLocale.QWERTY); - mCurrentSubtype = mRichImm.getCurrentInputMethodSubtype(mNoLanguageSubtype); if (mNoLanguageSubtype == null) { throw new RuntimeException("Can't find no lanugage with QWERTY subtype"); } final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); mIsNetworkConnected = (info != null && info.isConnected()); - } - - // Update all parameters stored in SubtypeSwitcher. - // Only configuration changed event is allowed to call this because this is heavy. - private void updateAllParameters() { - mCurrentSystemLocale = mResources.getConfiguration().locale; - updateSubtype(mRichImm.getCurrentInputMethodSubtype(mNoLanguageSubtype)); - updateParametersOnStartInputViewAndReturnIfCurrentSubtypeEnabled(); - } - /** - * Update parameters which are changed outside LatinIME. This parameters affect UI so they - * should be updated every time onStartInputView. - * - * @return true if the current subtype is enabled. - */ - public boolean updateParametersOnStartInputViewAndReturnIfCurrentSubtypeEnabled() { - final boolean currentSubtypeEnabled = - updateEnabledSubtypesAndReturnIfEnabled(mCurrentSubtype); - updateShortcutIME(); - return currentSubtypeEnabled; + onSubtypeChanged(getCurrentSubtype()); + updateParametersOnStartInputView(); } /** - * Update enabled subtypes from the framework. - * - * @param subtype the subtype to be checked - * @return true if the {@code subtype} is enabled. + * Update parameters which are changed outside LatinIME. This parameters affect UI so that they + * should be updated every time onStartInputView is called. */ - private boolean updateEnabledSubtypesAndReturnIfEnabled(final InputMethodSubtype subtype) { + public void updateParametersOnStartInputView() { final List<InputMethodSubtype> enabledSubtypesOfThisIme = mRichImm.getInputMethodManager().getEnabledInputMethodSubtypeList(null, true); mNeedsToDisplayLanguage.updateEnabledSubtypeCount(enabledSubtypesOfThisIme.size()); - - for (final InputMethodSubtype ims : enabledSubtypesOfThisIme) { - if (ims.equals(subtype)) { - return true; - } - } - if (DBG) { - Log.w(TAG, "Subtype: " + subtype.getLocale() + "/" + subtype.getExtraValue() - + " was disabled"); - } - return false; + updateShortcutIME(); } private void updateShortcutIME() { @@ -185,25 +148,21 @@ public final class SubtypeSwitcher { } // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function. - public void updateSubtype(InputMethodSubtype newSubtype) { + public void onSubtypeChanged(final InputMethodSubtype newSubtype) { if (DBG) { - Log.w(TAG, "onCurrentInputMethodSubtypeChanged: to: " - + newSubtype.getLocale() + "/" + newSubtype.getExtraValue() + ", from: " - + mCurrentSubtype.getLocale() + "/" + mCurrentSubtype.getExtraValue()); + Log.w(TAG, "onSubtypeChanged: " + SubtypeLocale.getSubtypeDisplayName( + newSubtype, mResources)); } final Locale newLocale = SubtypeLocale.getSubtypeLocale(newSubtype); - final boolean sameLocale = mCurrentSystemLocale.equals(newLocale); - final boolean sameLanguage = mCurrentSystemLocale.getLanguage().equals( - newLocale.getLanguage()); + final Locale systemLocale = mResources.getConfiguration().locale; + final boolean sameLocale = systemLocale.equals(newLocale); + final boolean sameLanguage = systemLocale.getLanguage().equals(newLocale.getLanguage()); final boolean implicitlyEnabled = mRichImm.checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype); mNeedsToDisplayLanguage.updateIsSystemLanguageSameAsInputLanguage( sameLocale || (sameLanguage && implicitlyEnabled)); - if (newSubtype.equals(mCurrentSubtype)) return; - - mCurrentSubtype = newSubtype; updateShortcutIME(); } @@ -281,21 +240,11 @@ public final class SubtypeSwitcher { } public Locale getCurrentSubtypeLocale() { - return SubtypeLocale.getSubtypeLocale(mCurrentSubtype); - } - - public boolean onConfigurationChanged(final Configuration conf) { - final Locale systemLocale = conf.locale; - final boolean systemLocaleChanged = !systemLocale.equals(mCurrentSystemLocale); - // If system configuration was changed, update all parameters. - if (systemLocaleChanged) { - updateAllParameters(); - } - return systemLocaleChanged; + return SubtypeLocale.getSubtypeLocale(getCurrentSubtype()); } public InputMethodSubtype getCurrentSubtype() { - return mCurrentSubtype; + return mRichImm.getCurrentInputMethodSubtype(mNoLanguageSubtype); } public InputMethodSubtype getNoLanguageSubtype() { diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java index ddae5ac48..6cb39426d 100644 --- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java @@ -24,6 +24,7 @@ import android.content.Intent; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; +import android.os.Build; import android.provider.UserDictionary.Words; import android.text.TextUtils; @@ -43,8 +44,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { final static String SHORTCUT = "shortcut"; private static final String[] PROJECTION_QUERY; static { - // 16 is JellyBean, but we want this to compile against ICS. - if (android.os.Build.VERSION.SDK_INT >= 16) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { PROJECTION_QUERY = new String[] { Words.WORD, SHORTCUT, @@ -90,13 +90,14 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { mObserver = new ContentObserver(null) { @Override public void onChange(final boolean self) { - // This hook is deprecated as of API level 16, but should still be supported for - // cases where the IME is running on an older version of the platform. + // This hook is deprecated as of API level 16 (Build.VERSION_CODES.JELLY_BEAN), + // but should still be supported for cases where the IME is running on an older + // version of the platform. onChange(self, null); } - // The following hook is only available as of API level 16, and as such it will only - // work on JellyBean+ devices. On older versions of the platform, the hook - // above will be called instead. + // The following hook is only available as of API level 16 + // (Build.VERSION_CODES.JELLY_BEAN), and as such it will only work on JellyBean+ + // devices. On older versions of the platform, the hook above will be called instead. @Override public void onChange(final boolean self, final Uri uri) { setRequiresReload(true); @@ -233,8 +234,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { } private void addWords(final Cursor cursor) { - // 16 is JellyBean, but we want this to compile against ICS. - final boolean hasShortcutColumn = android.os.Build.VERSION.SDK_INT >= 16; + final boolean hasShortcutColumn = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; clearFusionDictionary(); if (cursor == null) return; if (cursor.moveToFirst()) { diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java b/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java index 100e377f6..4fa3d7df8 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java @@ -48,6 +48,7 @@ public final class UserHistoryDictIOUtils { public void setBigram(final String word1, final String word2, final int frequency); } + @UsedForTesting public interface BigramDictionaryInterface { public int getFrequency(final String word1, final String word2); } @@ -214,4 +215,4 @@ public final class UserHistoryDictIOUtils { } } -}
\ No newline at end of file +} diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java index df44948f9..316f09603 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java @@ -18,6 +18,8 @@ package com.android.inputmethod.latin; import android.util.Log; +import com.android.inputmethod.annotations.UsedForTesting; + import java.util.HashMap; import java.util.Set; @@ -26,6 +28,7 @@ import java.util.Set; * All bigrams including stale ones in SQL DB should be stored in this class to avoid adding stale * bigrams when we write to the SQL DB. */ +@UsedForTesting public final class UserHistoryDictionaryBigramList { public static final byte FORGETTING_CURVE_INITIAL_VALUE = 0; private static final String TAG = UserHistoryDictionaryBigramList.class.getSimpleName(); diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 3eac6a237..acfcd5354 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -61,7 +61,7 @@ public final class Utils { } } - /* package */ static class RingCharBuffer { + /* package */ static final class RingCharBuffer { private static RingCharBuffer sRingCharBuffer = new RingCharBuffer(); private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC'; private static final int INVALID_COORDINATE = -2; @@ -203,7 +203,7 @@ public final class Utils { } // Initialization-on-demand holder - private static class OnDemandInitializationHolder { + private static final class OnDemandInitializationHolder { public static final UsabilityStudyLogUtils sInstance = new UsabilityStudyLogUtils(); } diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index f1a7e97e8..937d7ab34 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java @@ -56,6 +56,7 @@ public final class BinaryDictInputOutput { private static final int MAX_PASSES = 24; private static final int MAX_JUMPS = 12; + @UsedForTesting public interface FusionDictionaryBufferInterface { public int readUnsignedByte(); public int readUnsignedShort(); diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java index f7cc69359..bfc275df5 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java +++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin.makedict; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.Constants; import java.util.ArrayList; @@ -29,6 +30,7 @@ import java.util.LinkedList; /** * A dictionary that can fusion heads and tails of words for more compression. */ +@UsedForTesting public final class FusionDictionary implements Iterable<Word> { private static final boolean DBG = MakedictLog.DBG; diff --git a/java/src/com/android/inputmethod/research/JsonUtils.java b/java/src/com/android/inputmethod/research/JsonUtils.java new file mode 100644 index 000000000..cb331d7f9 --- /dev/null +++ b/java/src/com/android/inputmethod/research/JsonUtils.java @@ -0,0 +1,103 @@ +/* + * 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 android.content.SharedPreferences; +import android.util.JsonWriter; +import android.view.inputmethod.CompletionInfo; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; + +import java.io.IOException; +import java.util.Map; + +/* package */ class JsonUtils { + private JsonUtils() { + // This utility class is not publicly instantiable. + } + + /* package */ static void writeJson(final CompletionInfo[] ci, final JsonWriter jsonWriter) + throws IOException { + jsonWriter.beginArray(); + for (int j = 0; j < ci.length; j++) { + jsonWriter.value(ci[j].toString()); + } + jsonWriter.endArray(); + } + + /* package */ static void writeJson(final SharedPreferences prefs, final JsonWriter jsonWriter) + throws IOException { + jsonWriter.beginObject(); + for (Map.Entry<String,?> entry : prefs.getAll().entrySet()) { + jsonWriter.name(entry.getKey()); + final Object innerValue = entry.getValue(); + if (innerValue == null) { + jsonWriter.nullValue(); + } else if (innerValue instanceof Boolean) { + jsonWriter.value((Boolean) innerValue); + } else if (innerValue instanceof Number) { + jsonWriter.value((Number) innerValue); + } else { + jsonWriter.value(innerValue.toString()); + } + } + jsonWriter.endObject(); + } + + /* package */ static void writeJson(final Key[] keys, final JsonWriter jsonWriter) + throws IOException { + jsonWriter.beginArray(); + for (Key key : keys) { + writeJson(key, jsonWriter); + } + jsonWriter.endArray(); + } + + private static void writeJson(final Key key, final JsonWriter jsonWriter) throws IOException { + jsonWriter.beginObject(); + jsonWriter.name("code").value(key.mCode); + jsonWriter.name("altCode").value(key.getAltCode()); + jsonWriter.name("x").value(key.mX); + jsonWriter.name("y").value(key.mY); + jsonWriter.name("w").value(key.mWidth); + jsonWriter.name("h").value(key.mHeight); + jsonWriter.endObject(); + } + + /* package */ static void writeJson(final SuggestedWords words, final JsonWriter jsonWriter) + throws IOException { + jsonWriter.beginObject(); + jsonWriter.name("typedWordValid").value(words.mTypedWordValid); + jsonWriter.name("willAutoCorrect") + .value(words.mWillAutoCorrect); + jsonWriter.name("isPunctuationSuggestions") + .value(words.mIsPunctuationSuggestions); + jsonWriter.name("isObsoleteSuggestions").value(words.mIsObsoleteSuggestions); + jsonWriter.name("isPrediction").value(words.mIsPrediction); + jsonWriter.name("words"); + jsonWriter.beginArray(); + final int size = words.size(); + for (int j = 0; j < size; j++) { + final SuggestedWordInfo wordInfo = words.getWordInfo(j); + jsonWriter.value(wordInfo.toString()); + } + jsonWriter.endArray(); + jsonWriter.endObject(); + } +} diff --git a/java/src/com/android/inputmethod/research/LogBuffer.java b/java/src/com/android/inputmethod/research/LogBuffer.java index ae7b1579a..a3c3e89de 100644 --- a/java/src/com/android/inputmethod/research/LogBuffer.java +++ b/java/src/com/android/inputmethod/research/LogBuffer.java @@ -110,4 +110,8 @@ public class LogBuffer { } return logUnit; } + + public boolean isEmpty() { + return mLogUnits.isEmpty(); + } } diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java index ab9d2f857..27c4027de 100644 --- a/java/src/com/android/inputmethod/research/LogUnit.java +++ b/java/src/com/android/inputmethod/research/LogUnit.java @@ -16,10 +16,23 @@ package com.android.inputmethod.research; +import android.content.SharedPreferences; +import android.util.JsonWriter; +import android.util.Log; +import android.view.inputmethod.CompletionInfo; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.research.ResearchLogger.LogStatement; +import java.io.IOException; +import java.io.StringWriter; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * A group of log statements related to each other. @@ -36,6 +49,8 @@ import java.util.List; * been published recently, or whether the LogUnit contains numbers, etc. */ /* package */ class LogUnit { + private static final String TAG = LogUnit.class.getSimpleName(); + private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG; private final ArrayList<LogStatement> mLogStatementList; private final ArrayList<Object[]> mValuesList; // Assume that mTimeList is sorted in increasing order. Do not insert null values into @@ -77,8 +92,29 @@ import java.util.List; mTimeList.add(time); } - public void publishTo(final ResearchLog researchLog, final boolean isIncludingPrivateData) { + /** + * Publish the contents of this LogUnit to researchLog. + */ + public synchronized void publishTo(final ResearchLog researchLog, + final boolean isIncludingPrivateData) { + // Prepare debugging output if necessary + final StringWriter debugStringWriter; + final JsonWriter debugJsonWriter; + if (DEBUG) { + debugStringWriter = new StringWriter(); + debugJsonWriter = new JsonWriter(debugStringWriter); + debugJsonWriter.setIndent(" "); + try { + debugJsonWriter.beginArray(); + } catch (IOException e) { + Log.e(TAG, "Could not open array in JsonWriter", e); + } + } else { + debugStringWriter = null; + debugJsonWriter = null; + } final int size = mLogStatementList.size(); + // Write out any logStatement that passes the privacy filter. for (int i = 0; i < size; i++) { final LogStatement logStatement = mLogStatementList.get(i); if (!isIncludingPrivateData && logStatement.mIsPotentiallyPrivate) { @@ -87,8 +123,87 @@ import java.util.List; if (mIsPartOfMegaword && logStatement.mIsPotentiallyRevealing) { continue; } - researchLog.outputEvent(mLogStatementList.get(i), mValuesList.get(i), mTimeList.get(i)); + // Only retrieve the jsonWriter if we need to. If we don't get this far, then + // researchLog.getValidJsonWriter() will not open the file for writing. + final JsonWriter jsonWriter = researchLog.getValidJsonWriterLocked(); + outputLogStatementToLocked(jsonWriter, mLogStatementList.get(i), mValuesList.get(i), + mTimeList.get(i)); + if (DEBUG) { + outputLogStatementToLocked(debugJsonWriter, mLogStatementList.get(i), + mValuesList.get(i), mTimeList.get(i)); + } + } + if (DEBUG) { + try { + debugJsonWriter.endArray(); + debugJsonWriter.flush(); + } catch (IOException e) { + Log.e(TAG, "Could not close array in JsonWriter", e); + } + final String bigString = debugStringWriter.getBuffer().toString(); + final String[] lines = bigString.split("\n"); + for (String line : lines) { + Log.d(TAG, line); + } + } + } + + private static final String CURRENT_TIME_KEY = "_ct"; + private static final String UPTIME_KEY = "_ut"; + private static final String EVENT_TYPE_KEY = "_ty"; + + /** + * Write the logStatement and its contents out through jsonWriter. + * + * Note that this method is not thread safe for the same jsonWriter. Callers must ensure + * thread safety. + */ + private boolean outputLogStatementToLocked(final JsonWriter jsonWriter, + final LogStatement logStatement, final Object[] values, final Long time) { + if (DEBUG) { + if (logStatement.mKeys.length != values.length) { + Log.d(TAG, "Key and Value list sizes do not match. " + logStatement.mName); + } + } + try { + jsonWriter.beginObject(); + jsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis()); + jsonWriter.name(UPTIME_KEY).value(time); + jsonWriter.name(EVENT_TYPE_KEY).value(logStatement.mName); + final String[] keys = logStatement.mKeys; + final int length = values.length; + for (int i = 0; i < length; i++) { + jsonWriter.name(keys[i]); + final Object value = values[i]; + if (value instanceof CharSequence) { + jsonWriter.value(value.toString()); + } else if (value instanceof Number) { + jsonWriter.value((Number) value); + } else if (value instanceof Boolean) { + jsonWriter.value((Boolean) value); + } else if (value instanceof CompletionInfo[]) { + JsonUtils.writeJson((CompletionInfo[]) value, jsonWriter); + } else if (value instanceof SharedPreferences) { + JsonUtils.writeJson((SharedPreferences) value, jsonWriter); + } else if (value instanceof Key[]) { + JsonUtils.writeJson((Key[]) value, jsonWriter); + } else if (value instanceof SuggestedWords) { + JsonUtils.writeJson((SuggestedWords) value, jsonWriter); + } else if (value == null) { + jsonWriter.nullValue(); + } else { + Log.w(TAG, "Unrecognized type to be logged: " + + (value == null ? "<null>" : value.getClass().getName())); + jsonWriter.nullValue(); + } + } + jsonWriter.endObject(); + } catch (IOException e) { + e.printStackTrace(); + Log.w(TAG, "Error in JsonWriter; skipping LogStatement"); + return false; } + return true; } public void setWord(String word) { diff --git a/java/src/com/android/inputmethod/research/ResearchLog.java b/java/src/com/android/inputmethod/research/ResearchLog.java index 3c8731995..a6b1b889f 100644 --- a/java/src/com/android/inputmethod/research/ResearchLog.java +++ b/java/src/com/android/inputmethod/research/ResearchLog.java @@ -16,17 +16,10 @@ package com.android.inputmethod.research; -import android.content.SharedPreferences; -import android.os.SystemClock; import android.util.JsonWriter; import android.util.Log; -import android.view.inputmethod.CompletionInfo; -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.LogStatement; import java.io.BufferedWriter; import java.io.File; @@ -34,7 +27,6 @@ import java.io.FileWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; -import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; @@ -204,103 +196,17 @@ public class ResearchLog { } } - 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 LogStatement logStatement, final Object[] values, final long time) { - // Not thread safe. - if (DEBUG) { - if (logStatement.mKeys.length != values.length) { - Log.d(TAG, "Key and Value list sizes do not match. " + logStatement.mName); - } - } + /** + * Return a JsonWriter for this ResearchLog. It is initialized the first time this method is + * called. The cached value is returned in future calls. + */ + public JsonWriter getValidJsonWriterLocked() { try { if (mJsonWriter == NULL_JSON_WRITER) { mJsonWriter = new JsonWriter(new BufferedWriter(new FileWriter(mFile))); mJsonWriter.beginArray(); mHasWrittenData = true; } - mJsonWriter.beginObject(); - mJsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis()); - mJsonWriter.name(UPTIME_KEY).value(time); - mJsonWriter.name(EVENT_TYPE_KEY).value(logStatement.mName); - final String[] keys = logStatement.mKeys; - final int length = values.length; - for (int i = 0; i < length; i++) { - mJsonWriter.name(keys[i]); - Object value = values[i]; - if (value instanceof CharSequence) { - mJsonWriter.value(value.toString()); - } else if (value instanceof Number) { - mJsonWriter.value((Number) value); - } else if (value instanceof Boolean) { - mJsonWriter.value((Boolean) value); - } else if (value instanceof CompletionInfo[]) { - CompletionInfo[] ci = (CompletionInfo[]) value; - mJsonWriter.beginArray(); - for (int j = 0; j < ci.length; j++) { - mJsonWriter.value(ci[j].toString()); - } - mJsonWriter.endArray(); - } else if (value instanceof SharedPreferences) { - SharedPreferences prefs = (SharedPreferences) value; - mJsonWriter.beginObject(); - for (Map.Entry<String,?> entry : prefs.getAll().entrySet()) { - mJsonWriter.name(entry.getKey()); - final Object innerValue = entry.getValue(); - if (innerValue == null) { - mJsonWriter.nullValue(); - } else if (innerValue instanceof Boolean) { - mJsonWriter.value((Boolean) innerValue); - } else if (innerValue instanceof Number) { - mJsonWriter.value((Number) innerValue); - } else { - mJsonWriter.value(innerValue.toString()); - } - } - mJsonWriter.endObject(); - } else if (value instanceof Key[]) { - Key[] keyboardKeys = (Key[]) value; - mJsonWriter.beginArray(); - for (Key keyboardKey : keyboardKeys) { - mJsonWriter.beginObject(); - mJsonWriter.name("code").value(keyboardKey.mCode); - mJsonWriter.name("altCode").value(keyboardKey.getAltCode()); - mJsonWriter.name("x").value(keyboardKey.mX); - mJsonWriter.name("y").value(keyboardKey.mY); - mJsonWriter.name("w").value(keyboardKey.mWidth); - mJsonWriter.name("h").value(keyboardKey.mHeight); - mJsonWriter.endObject(); - } - mJsonWriter.endArray(); - } else if (value instanceof SuggestedWords) { - SuggestedWords words = (SuggestedWords) value; - mJsonWriter.beginObject(); - mJsonWriter.name("typedWordValid").value(words.mTypedWordValid); - mJsonWriter.name("willAutoCorrect").value(words.mWillAutoCorrect); - mJsonWriter.name("isPunctuationSuggestions") - .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(); - for (int j = 0; j < size; j++) { - SuggestedWordInfo wordInfo = words.getWordInfo(j); - mJsonWriter.value(wordInfo.toString()); - } - mJsonWriter.endArray(); - mJsonWriter.endObject(); - } else if (value == null) { - mJsonWriter.nullValue(); - } else { - Log.w(TAG, "Unrecognized type to be logged: " + - (value == null ? "<null>" : value.getClass().getName())); - mJsonWriter.nullValue(); - } - } - mJsonWriter.endObject(); } catch (IOException e) { e.printStackTrace(); Log.w(TAG, "Error in JsonWriter; disabling logging"); @@ -315,5 +221,6 @@ public class ResearchLog { mJsonWriter = NULL_JSON_WRITER; } } + return mJsonWriter; } } diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index 9f65f5d3f..709746ee3 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -34,11 +34,11 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; -import android.inputmethodservice.InputMethodService; import android.net.Uri; import android.os.Build; import android.os.IBinder; import android.os.SystemClock; +import android.preference.PreferenceManager; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; @@ -84,7 +84,13 @@ import java.util.UUID; public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = ResearchLogger.class.getSimpleName(); private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG; - private static final boolean LOG_EVERYTHING = false; // true will disclose private info + // Whether all n-grams should be logged. true will disclose private info. + private static final boolean LOG_EVERYTHING = false + && ProductionFlag.IS_EXPERIMENTAL_DEBUG; + // Whether the TextView contents are logged at the end of the session. true will disclose + // private info. + private static final boolean LOG_FULL_TEXTVIEW_CONTENTS = false + && ProductionFlag.IS_EXPERIMENTAL_DEBUG; public static final boolean DEFAULT_USABILITY_STUDY_MODE = false; /* package */ static boolean sIsLogging = false; private static final int OUTPUT_FORMAT_VERSION = 5; @@ -94,8 +100,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final String FILENAME_SUFFIX = ".txt"; private static final SimpleDateFormat TIMESTAMP_DATEFORMAT = new SimpleDateFormat("yyyyMMddHHmmssS", Locale.US); + // Whether to show an indicator on the screen that logging is on. Currently a very small red + // dot in the lower right hand corner. Most users should not notice it. private static final boolean IS_SHOWING_INDICATOR = true; - private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false; + // Change the default indicator to something very visible. Currently two red vertical bars on + // either side of they keyboard. + private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false || LOG_EVERYTHING; public static final int FEEDBACK_WORD_BUFFER_SIZE = 5; // constants related to specific log points @@ -137,7 +147,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang // used to check whether words are not unique private Suggest mSuggest; private MainKeyboardView mMainKeyboardView; - private InputMethodService mInputMethodService; + private LatinIME mLatinIME; private final Statistics mStatistics; private Intent mUploadIntent; @@ -152,16 +162,17 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return sInstance; } - public void init(final InputMethodService ims, final SharedPreferences prefs) { - assert ims != null; - if (ims == null) { + public void init(final LatinIME latinIME) { + assert latinIME != null; + if (latinIME == null) { Log.w(TAG, "IMS is null; logging is off"); } else { - mFilesDir = ims.getFilesDir(); + mFilesDir = latinIME.getFilesDir(); if (mFilesDir == null || !mFilesDir.exists()) { Log.w(TAG, "IME storage directory does not exist."); } } + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(latinIME); if (prefs != null) { mUUIDString = getUUID(prefs); if (!prefs.contains(PREF_USABILITY_STUDY_MODE)) { @@ -182,12 +193,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang e.apply(); } } - mInputMethodService = ims; + mLatinIME = latinIME; mPrefs = prefs; - mUploadIntent = new Intent(mInputMethodService, UploaderService.class); + mUploadIntent = new Intent(mLatinIME, UploaderService.class); if (ProductionFlag.IS_EXPERIMENTAL) { - scheduleUploadingService(mInputMethodService); + scheduleUploadingService(mLatinIME); } } @@ -246,7 +257,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (windowToken == null) { return; } - final AlertDialog.Builder builder = new AlertDialog.Builder(mInputMethodService) + final AlertDialog.Builder builder = new AlertDialog.Builder(mLatinIME) .setTitle(R.string.research_splash_title) .setMessage(R.string.research_splash_content) .setPositiveButton(android.R.string.yes, @@ -261,12 +272,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - final String packageName = mInputMethodService.getPackageName(); + final String packageName = mLatinIME.getPackageName(); final Uri packageUri = Uri.parse("package:" + packageName); final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mInputMethodService.startActivity(intent); + mLatinIME.startActivity(intent); } }) .setCancelable(true) @@ -274,7 +285,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang new OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { - mInputMethodService.requestHideSelf(0); + mLatinIME.requestHideSelf(0); } }); mSplashDialog = builder.create(); @@ -318,10 +329,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } private void checkForEmptyEditor() { - if (mInputMethodService == null) { + if (mLatinIME == null) { return; } - final InputConnection ic = mInputMethodService.getCurrentInputConnection(); + final InputConnection ic = mLatinIME.getCurrentInputConnection(); if (ic == null) { return; } @@ -374,7 +385,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (DEBUG) { Log.d(TAG, "stop called"); } - logStatistics(); commitCurrentLogUnit(); if (mMainLogBuffer != null) { @@ -582,7 +592,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (DEBUG) { Log.d(TAG, "calling uploadNow()"); } - mInputMethodService.startService(mUploadIntent); + mLatinIME.startService(mUploadIntent); } public void onLeavingSendFeedbackDialog() { @@ -643,7 +653,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang final float savedStrokeWidth = paint.getStrokeWidth(); if (IS_SHOWING_INDICATOR_CLEARLY) { paint.setStrokeWidth(5); - canvas.drawRect(0, 0, width, height, paint); + canvas.drawLine(0, 0, 0, height, paint); + canvas.drawLine(width, 0, width, height, paint); } else { // Put a tiny red dot on the screen so a knowledgeable user can check whether // it is enabled. The dot is actually a zero-width, zero-height rectangle, @@ -681,7 +692,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (!mCurrentLogUnit.isEmpty()) { if (mMainLogBuffer != null) { mMainLogBuffer.shiftIn(mCurrentLogUnit); - if (mMainLogBuffer.isSafeToLog() && mMainResearchLog != null) { + if ((mMainLogBuffer.isSafeToLog() || LOG_EVERYTHING) && mMainResearchLog != null) { publishLogBuffer(mMainLogBuffer, mMainResearchLog, true /* isIncludingPrivateData */); mMainLogBuffer.resetWordCounter(); @@ -701,6 +712,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang /* package for test */ void publishLogBuffer(final LogBuffer logBuffer, final ResearchLog researchLog, final boolean isIncludingPrivateData) { final LogUnit openingLogUnit = new LogUnit(); + if (logBuffer.isEmpty()) return; openingLogUnit.addLogStatement(LOGSTATEMENT_LOG_SEGMENT_OPENING, SystemClock.uptimeMillis(), isIncludingPrivateData); researchLog.publish(openingLogUnit, true /* isIncludingPrivateData */); @@ -731,7 +743,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final LogStatement LOGSTATEMENT_COMMIT_RECORD_SPLIT_WORDS = new LogStatement("recordSplitWords", true, false); - private void onWordComplete(final String word, final long maxTime, final boolean isSplitWords) { + public void onWordComplete(final String word, final long maxTime) { final Dictionary dictionary = getDictionary(); if (word != null && word.length() > 0 && hasLetters(word)) { mCurrentLogUnit.setWord(word); @@ -741,11 +753,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } final LogUnit newLogUnit = mCurrentLogUnit.splitByTime(maxTime); enqueueCommitText(word); - if (isSplitWords) { - enqueueEvent(LOGSTATEMENT_COMMIT_RECORD_SPLIT_WORDS); - enqueueCommitText(" "); - mStatistics.recordSplitWords(); - } commitCurrentLogUnit(); mCurrentLogUnit = newLogUnit; } @@ -801,6 +808,21 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return WORD_REPLACEMENT_STRING; } + // Specific logging methods follow below. The comments for each logging method should + // indicate what specific method is logged, and how to trigger it from the user interface. + // + // Logging methods can be generally classified into two flavors, "UserAction", which should + // correspond closely to an event that is sensed by the IME, and is usually generated + // directly by the user, and "SystemResponse" which corresponds to an event that the IME + // generates, often after much processing of user input. SystemResponses should correspond + // closely to user-visible events. + // TODO: Consider exposing the UserAction classification in the log output. + + /** + * Log a call to LatinIME.onStartInputViewInternal(). + * + * UserAction: called each time the keyboard is opened up. + */ private static final LogStatement LOGSTATEMENT_LATIN_IME_ON_START_INPUT_VIEW_INTERNAL = new LogStatement("LatinImeOnStartInputViewInternal", false, false, "uuid", "packageName", "inputType", "imeOptions", "fieldId", "display", "model", @@ -814,7 +836,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang || InputTypeUtils.isVisiblePasswordInputType(editorInfo.inputType); getInstance().setIsPasswordView(isPassword); researchLogger.start(); - final Context context = researchLogger.mInputMethodService; + final Context context = researchLogger.mLatinIME; try { final PackageInfo packageInfo; packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), @@ -835,9 +857,15 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } public void latinIME_onFinishInputViewInternal() { + logStatistics(); stop(); } + /** + * Log a change in preferences. + * + * UserAction: called when the user changes the settings. + */ private static final LogStatement LOGSTATEMENT_PREFS_CHANGED = new LogStatement("PrefsChanged", false, false, "prefs"); public static void prefsChanged(final SharedPreferences prefs) { @@ -845,8 +873,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang researchLogger.enqueueEvent(LOGSTATEMENT_PREFS_CHANGED, prefs); } - // Regular logging methods - + /** + * Log a call to MainKeyboardView.processMotionEvent(). + * + * UserAction: called when the user puts their finger onto the screen (ACTION_DOWN). + * + */ private static final LogStatement LOGSTATEMENT_MAIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENT = new LogStatement("MainKeyboardViewProcessMotionEvent", true, false, "action", "eventTime", "id", "x", "y", "size", "pressure"); @@ -871,6 +903,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } + /** + * Log a call to LatinIME.onCodeInput(). + * + * SystemResponse: The main processing step for entering text. Called when the user performs a + * tap, a flick, a long press, releases a gesture, or taps a punctuation suggestion. + */ private static final LogStatement LOGSTATEMENT_LATIN_IME_ON_CODE_INPUT = new LogStatement("LatinImeOnCodeInput", true, false, "code", "x", "y"); public static void latinIME_onCodeInput(final int code, final int x, final int y) { @@ -883,6 +921,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } researchLogger.mStatistics.recordChar(code, time); } + /** + * Log a call to LatinIME.onDisplayCompletions(). + * + * SystemResponse: The IME has displayed application-specific completions. They may show up + * in the suggestion strip, such as a landscape phone. + */ private static final LogStatement LOGSTATEMENT_LATINIME_ONDISPLAYCOMPLETIONS = new LogStatement("LatinIMEOnDisplayCompletions", true, true, "applicationSpecifiedCompletions"); @@ -900,6 +944,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return returnValue; } + /** + * Log a call to LatinIME.onWindowHidden(). + * + * UserAction: The user has performed an action that has caused the IME to be closed. They may + * have focused on something other than a text field, or explicitly closed it. + */ private static final LogStatement LOGSTATEMENT_LATINIME_ONWINDOWHIDDEN = new LogStatement("LatinIMEOnWindowHidden", false, false, "isTextTruncated", "text"); public static void latinIME_onWindowHidden(final int savedSelectionStart, @@ -907,7 +957,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (ic != null) { final boolean isTextTruncated; final String text; - if (LOG_EVERYTHING) { + if (LOG_FULL_TEXTVIEW_CONTENTS) { // 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 @@ -955,6 +1005,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } + /** + * Log a call to LatinIME.onUpdateSelection(). + * + * UserAction/SystemResponse: The user has moved the cursor or selection. This function may + * be called, however, when the system has moved the cursor, say by inserting a character. + */ private static final LogStatement LOGSTATEMENT_LATINIME_ONUPDATESELECTION = new LogStatement("LatinIMEOnUpdateSelection", true, false, "lastSelectionStart", "lastSelectionEnd", "oldSelStart", "oldSelEnd", "newSelStart", "newSelEnd", @@ -981,27 +1037,48 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang expectingUpdateSelectionFromLogger, scrubbedWord); } + /** + * Log a call to LatinIME.pickSuggestionManually(). + * + * UserAction: The user has chosen a specific word from the suggestion strip. + */ private static final LogStatement LOGSTATEMENT_LATINIME_PICKSUGGESTIONMANUALLY = new LogStatement("LatinIMEPickSuggestionManually", true, false, "replacedWord", "index", "suggestion", "x", "y"); public static void latinIME_pickSuggestionManually(final String replacedWord, - final int index, CharSequence suggestion) { + final int index, final String suggestion) { + final String scrubbedWord = scrubDigitsFromString(suggestion); final ResearchLogger researchLogger = getInstance(); researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_PICKSUGGESTIONMANUALLY, scrubDigitsFromString(replacedWord), index, - suggestion == null ? null : scrubDigitsFromString(suggestion.toString()), - Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE); + suggestion == null ? null : scrubbedWord, Constants.SUGGESTION_STRIP_COORDINATE, + Constants.SUGGESTION_STRIP_COORDINATE); + researchLogger.onWordComplete(scrubbedWord, Long.MAX_VALUE); + researchLogger.mStatistics.recordManualSuggestion(); } + /** + * Log a call to LatinIME.punctuationSuggestion(). + * + * UserAction: The user has chosen punctuation from the punctuation suggestion strip. + */ private static final LogStatement LOGSTATEMENT_LATINIME_PUNCTUATIONSUGGESTION = new LogStatement("LatinIMEPunctuationSuggestion", false, false, "index", "suggestion", "x", "y"); - public static void latinIME_punctuationSuggestion(final int index, - final CharSequence suggestion) { - getInstance().enqueueEvent(LOGSTATEMENT_LATINIME_PUNCTUATIONSUGGESTION, index, suggestion, + public static void latinIME_punctuationSuggestion(final int index, final String suggestion) { + final ResearchLogger researchLogger = getInstance(); + researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_PUNCTUATIONSUGGESTION, index, suggestion, Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE); + researchLogger.onWordComplete(suggestion, Long.MAX_VALUE); } + /** + * Log a call to LatinIME.sendKeyCodePoint(). + * + * SystemResponse: The IME is simulating a hardware keypress. This happens for numbers; other + * input typically goes through RichInputConnection.setComposingText() and + * RichInputConnection.commitText(). + */ private static final LogStatement LOGSTATEMENT_LATINIME_SENDKEYCODEPOINT = new LogStatement("LatinIMESendKeyCodePoint", true, false, "code"); public static void latinIME_sendKeyCodePoint(final int code) { @@ -1013,18 +1090,36 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } + /** + * Log a call to LatinIME.swapSwapperAndSpace(). + * + * SystemResponse: A symbol has been swapped with a space character. E.g. punctuation may swap + * if a soft space is inserted after a word. + */ private static final LogStatement LOGSTATEMENT_LATINIME_SWAPSWAPPERANDSPACE = new LogStatement("LatinIMESwapSwapperAndSpace", false, false); public static void latinIME_swapSwapperAndSpace() { getInstance().enqueueEvent(LOGSTATEMENT_LATINIME_SWAPSWAPPERANDSPACE); } + /** + * Log a call to MainKeyboardView.onLongPress(). + * + * UserAction: The user has performed a long-press on a key. + */ private static final LogStatement LOGSTATEMENT_MAINKEYBOARDVIEW_ONLONGPRESS = new LogStatement("MainKeyboardViewOnLongPress", false, false); public static void mainKeyboardView_onLongPress() { getInstance().enqueueEvent(LOGSTATEMENT_MAINKEYBOARDVIEW_ONLONGPRESS); } + /** + * Log a call to MainKeyboardView.setKeyboard(). + * + * SystemResponse: The IME has switched to a new keyboard (e.g. French, English). + * This is typically called right after LatinIME.onStartInputViewInternal (when starting a new + * IME), but may happen at other times if the user explicitly requests a keyboard change. + */ private static final LogStatement LOGSTATEMENT_MAINKEYBOARDVIEW_SETKEYBOARD = new LogStatement("MainKeyboardViewSetKeyboard", false, false, "elementId", "locale", "orientation", "width", "modeName", "action", "navigateNext", @@ -1045,18 +1140,43 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang keyboard.mOccupiedHeight, keyboard.mKeys); } + /** + * Log a call to LatinIME.revertCommit(). + * + * SystemResponse: The IME has reverted commited text. This happens when the user enters + * a word, commits it by pressing space or punctuation, and then reverts the commit by hitting + * backspace. + */ private static final LogStatement LOGSTATEMENT_LATINIME_REVERTCOMMIT = - new LogStatement("LatinIMERevertCommit", true, false, "originallyTypedWord"); - public static void latinIME_revertCommit(final String originallyTypedWord) { - getInstance().enqueueEvent(LOGSTATEMENT_LATINIME_REVERTCOMMIT, originallyTypedWord); + new LogStatement("LatinIMERevertCommit", true, false, "committedWord", + "originallyTypedWord"); + public static void latinIME_revertCommit(final String committedWord, + final String originallyTypedWord) { + final ResearchLogger researchLogger = getInstance(); + researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_REVERTCOMMIT, committedWord, + originallyTypedWord); + researchLogger.mStatistics.recordRevertCommit(); } + /** + * Log a call to PointerTracker.callListenerOnCancelInput(). + * + * UserAction: The user has canceled the input, e.g., by pressing down, but then removing + * outside the keyboard area. + * TODO: Verify + */ private static final LogStatement LOGSTATEMENT_POINTERTRACKER_CALLLISTENERONCANCELINPUT = new LogStatement("PointerTrackerCallListenerOnCancelInput", false, false); public static void pointerTracker_callListenerOnCancelInput() { getInstance().enqueueEvent(LOGSTATEMENT_POINTERTRACKER_CALLLISTENERONCANCELINPUT); } + /** + * Log a call to PointerTracker.callListenerOnCodeInput(). + * + * SystemResponse: The user has entered a key through the normal tapping mechanism. + * LatinIME.onCodeInput will also be called. + */ private static final LogStatement LOGSTATEMENT_POINTERTRACKER_CALLLISTENERONCODEINPUT = new LogStatement("PointerTrackerCallListenerOnCodeInput", true, false, "code", "outputText", "x", "y", "ignoreModifierKey", "altersCode", "isEnabled"); @@ -1072,6 +1192,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } + /** + * Log a call to PointerTracker.callListenerCallListenerOnRelease(). + * + * UserAction: The user has released their finger or thumb from the screen. + */ private static final LogStatement LOGSTATEMENT_POINTERTRACKER_CALLLISTENERONRELEASE = new LogStatement("PointerTrackerCallListenerOnRelease", true, false, "code", "withSliding", "ignoreModifierKey", "isEnabled"); @@ -1084,6 +1209,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } + /** + * Log a call to PointerTracker.onDownEvent(). + * + * UserAction: The user has pressed down on a key. + * TODO: Differentiate with LatinIME.processMotionEvent. + */ private static final LogStatement LOGSTATEMENT_POINTERTRACKER_ONDOWNEVENT = new LogStatement("PointerTrackerOnDownEvent", true, false, "deltaT", "distanceSquared"); public static void pointerTracker_onDownEvent(long deltaT, int distanceSquared) { @@ -1091,6 +1222,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang distanceSquared); } + /** + * Log a call to PointerTracker.onMoveEvent(). + * + * UserAction: The user has moved their finger while pressing on the screen. + * TODO: Differentiate with LatinIME.processMotionEvent(). + */ private static final LogStatement LOGSTATEMENT_POINTERTRACKER_ONMOVEEVENT = new LogStatement("PointerTrackerOnMoveEvent", true, false, "x", "y", "lastX", "lastY"); public static void pointerTracker_onMoveEvent(final int x, final int y, final int lastX, @@ -1098,6 +1235,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang getInstance().enqueueEvent(LOGSTATEMENT_POINTERTRACKER_ONMOVEEVENT, x, y, lastX, lastY); } + /** + * Log a call to RichInputConnection.commitCompletion(). + * + * SystemResponse: The IME has committed a completion. A completion is an application- + * specific suggestion that is presented in a pop-up menu in the TextView. + */ private static final LogStatement LOGSTATEMENT_RICHINPUTCONNECTION_COMMITCOMPLETION = new LogStatement("RichInputConnectionCommitCompletion", true, false, "completionInfo"); public static void richInputConnection_commitCompletion(final CompletionInfo completionInfo) { @@ -1106,34 +1249,79 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang completionInfo); } + /** + * Log a call to LatinIME.commitCurrentAutoCorrection(). + * + * SystemResponse: The IME has committed an auto-correction. An auto-correction changes the raw + * text input to another word that the user more likely desired to type. + */ + private static final LogStatement LOGSTATEMENT_LATINIME_COMMITCURRENTAUTOCORRECTION = + new LogStatement("LatinIMECommitCurrentAutoCorrection", true, false, "typedWord", + "autoCorrection", "separatorString"); + public static void latinIme_commitCurrentAutoCorrection(final String typedWord, + final String autoCorrection, final String separatorString) { + final String scrubbedTypedWord = scrubDigitsFromString(typedWord); + final String scrubbedAutoCorrection = scrubDigitsFromString(autoCorrection); + final ResearchLogger researchLogger = getInstance(); + researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_COMMITCURRENTAUTOCORRECTION, + scrubbedTypedWord, scrubbedAutoCorrection, separatorString); + researchLogger.onWordComplete(scrubbedAutoCorrection, Long.MAX_VALUE); + } + private boolean isExpectingCommitText = false; + /** + * Log a call to RichInputConnection.commitPartialText + * + * SystemResponse: The IME is committing part of a word. This happens if a space is + * automatically inserted to split a single typed string into two or more words. + */ + // TODO: This method is currently unused. Find where it should be called from in the IME and + // add invocations. + private static final LogStatement LOGSTATEMENT_LATINIME_COMMIT_PARTIAL_TEXT = + new LogStatement("LatinIMECommitPartialText", true, false, "newCursorPosition"); public static void latinIME_commitPartialText(final CharSequence committedWord, final long lastTimestampOfWordData) { final ResearchLogger researchLogger = getInstance(); final String scrubbedWord = scrubDigitsFromString(committedWord.toString()); - researchLogger.onWordComplete(scrubbedWord, lastTimestampOfWordData, true /* isPartial */); - researchLogger.isExpectingCommitText = true; + researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_COMMIT_PARTIAL_TEXT); + researchLogger.onWordComplete(scrubbedWord, lastTimestampOfWordData); + researchLogger.mStatistics.recordSplitWords(); } - private static final LogStatement LOGSTATEMENT_COMMITTEXT_UPDATECURSOR = - new LogStatement("CommitTextUpdateCursor", true, false, "newCursorPosition"); + /** + * Log a call to RichInputConnection.commitText(). + * + * SystemResponse: The IME is committing text. This happens after the user has typed a word + * and then a space or punctuation key. + */ + private static final LogStatement LOGSTATEMENT_RICHINPUTCONNECTIONCOMMITTEXT = + new LogStatement("RichInputConnectionCommitText", true, false, "newCursorPosition"); public static void richInputConnection_commitText(final CharSequence committedWord, final int newCursorPosition) { final ResearchLogger researchLogger = getInstance(); final String scrubbedWord = scrubDigitsFromString(committedWord.toString()); if (!researchLogger.isExpectingCommitText) { - researchLogger.onWordComplete(scrubbedWord, Long.MAX_VALUE, false /* isPartial */); - researchLogger.enqueueEvent(LOGSTATEMENT_COMMITTEXT_UPDATECURSOR, newCursorPosition); + researchLogger.enqueueEvent(LOGSTATEMENT_RICHINPUTCONNECTIONCOMMITTEXT, + newCursorPosition); + researchLogger.onWordComplete(scrubbedWord, Long.MAX_VALUE); } researchLogger.isExpectingCommitText = false; } + /** + * Shared event for logging committed text. + */ private static final LogStatement LOGSTATEMENT_COMMITTEXT = new LogStatement("CommitText", true, false, "committedText"); private void enqueueCommitText(final CharSequence word) { enqueueEvent(LOGSTATEMENT_COMMITTEXT, word); } + /** + * Log a call to RichInputConnection.deleteSurroundingText(). + * + * SystemResponse: The IME has deleted text. + */ private static final LogStatement LOGSTATEMENT_RICHINPUTCONNECTION_DELETESURROUNDINGTEXT = new LogStatement("RichInputConnectionDeleteSurroundingText", true, false, "beforeLength", "afterLength"); @@ -1143,20 +1331,37 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang beforeLength, afterLength); } + /** + * Log a call to RichInputConnection.finishComposingText(). + * + * SystemResponse: The IME has left the composing text as-is. + */ private static final LogStatement LOGSTATEMENT_RICHINPUTCONNECTION_FINISHCOMPOSINGTEXT = new LogStatement("RichInputConnectionFinishComposingText", false, false); public static void richInputConnection_finishComposingText() { getInstance().enqueueEvent(LOGSTATEMENT_RICHINPUTCONNECTION_FINISHCOMPOSINGTEXT); } + /** + * Log a call to RichInputConnection.performEditorAction(). + * + * SystemResponse: The IME is invoking an action specific to the editor. + */ private static final LogStatement LOGSTATEMENT_RICHINPUTCONNECTION_PERFORMEDITORACTION = new LogStatement("RichInputConnectionPerformEditorAction", false, false, - "imeActionNext"); - public static void richInputConnection_performEditorAction(final int imeActionNext) { + "imeActionId"); + public static void richInputConnection_performEditorAction(final int imeActionId) { getInstance().enqueueEvent(LOGSTATEMENT_RICHINPUTCONNECTION_PERFORMEDITORACTION, - imeActionNext); + imeActionId); } + /** + * Log a call to RichInputConnection.sendKeyEvent(). + * + * SystemResponse: The IME is telling the TextView that a key is being pressed through an + * alternate channel. + * TODO: only for hardware keys? + */ private static final LogStatement LOGSTATEMENT_RICHINPUTCONNECTION_SENDKEYEVENT = new LogStatement("RichInputConnectionSendKeyEvent", true, false, "eventTime", "action", "code"); @@ -1165,6 +1370,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang keyEvent.getEventTime(), keyEvent.getAction(), keyEvent.getKeyCode()); } + /** + * Log a call to RichInputConnection.setComposingText(). + * + * SystemResponse: The IME is setting the composing text. Happens each time a character is + * entered. + */ private static final LogStatement LOGSTATEMENT_RICHINPUTCONNECTION_SETCOMPOSINGTEXT = new LogStatement("RichInputConnectionSetComposingText", true, true, "text", "newCursorPosition"); @@ -1177,12 +1388,24 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang newCursorPosition); } + /** + * Log a call to RichInputConnection.setSelection(). + * + * SystemResponse: The IME is requesting that the selection change. User-initiated selection- + * change requests do not go through this method -- it's only when the system wants to change + * the selection. + */ private static final LogStatement LOGSTATEMENT_RICHINPUTCONNECTION_SETSELECTION = new LogStatement("RichInputConnectionSetSelection", true, false, "from", "to"); public static void richInputConnection_setSelection(final int from, final int to) { getInstance().enqueueEvent(LOGSTATEMENT_RICHINPUTCONNECTION_SETSELECTION, from, to); } + /** + * Log a call to SuddenJumpingTouchEventHandler.onTouchEvent(). + * + * SystemResponse: The IME has filtered input events in case of an erroneous sensor reading. + */ private static final LogStatement LOGSTATEMENT_SUDDENJUMPINGTOUCHEVENTHANDLER_ONTOUCHEVENT = new LogStatement("SuddenJumpingTouchEventHandlerOnTouchEvent", true, false, "motionEvent"); @@ -1193,6 +1416,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } + /** + * Log a call to SuggestionsView.setSuggestions(). + * + * SystemResponse: The IME is setting the suggestions in the suggestion strip. + */ private static final LogStatement LOGSTATEMENT_SUGGESTIONSTRIPVIEW_SETSUGGESTIONS = new LogStatement("SuggestionStripViewSetSuggestions", true, true, "suggestedWords"); public static void suggestionStripView_setSuggestions(final SuggestedWords suggestedWords) { @@ -1202,12 +1430,22 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } + /** + * The user has indicated a particular point in the log that is of interest. + * + * UserAction: From direct menu invocation. + */ private static final LogStatement LOGSTATEMENT_USER_TIMESTAMP = new LogStatement("UserTimestamp", false, false); public void userTimestamp() { getInstance().enqueueEvent(LOGSTATEMENT_USER_TIMESTAMP); } + /** + * Log a call to LatinIME.onEndBatchInput(). + * + * SystemResponse: The system has completed a gesture. + */ private static final LogStatement LOGSTATEMENT_LATINIME_ONENDBATCHINPUT = new LogStatement("LatinIMEOnEndBatchInput", true, false, "enteredText", "enteredWordPos"); @@ -1216,15 +1454,35 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang final ResearchLogger researchLogger = getInstance(); researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_ONENDBATCHINPUT, enteredText, enteredWordPos); - researchLogger.mStatistics.recordGestureInput(); + researchLogger.mStatistics.recordGestureInput(enteredText.length()); } + /** + * Log a call to LatinIME.handleBackspace(). + * + * UserInput: The user is deleting a gestured word by hitting the backspace key once. + */ + private static final LogStatement LOGSTATEMENT_LATINIME_HANDLEBACKSPACE_BATCH = + new LogStatement("LatinIMEHandleBackspaceBatch", true, false, "deletedText"); + public static void latinIME_handleBackspace_batch(final CharSequence deletedText) { + final ResearchLogger researchLogger = getInstance(); + researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_HANDLEBACKSPACE_BATCH, deletedText); + researchLogger.mStatistics.recordGestureDelete(); + } + + /** + * Log statistics. + * + * ContextualData, recorded at the end of a session. + */ private static final LogStatement LOGSTATEMENT_STATISTICS = new LogStatement("Statistics", false, false, "charCount", "letterCount", "numberCount", "spaceCount", "deleteOpsCount", "wordCount", "isEmptyUponStarting", "isEmptinessStateKnown", "averageTimeBetweenKeys", "averageTimeBeforeDelete", "averageTimeDuringRepeatedDelete", "averageTimeAfterDelete", - "dictionaryWordCount", "splitWordsCount", "gestureInputCount"); + "dictionaryWordCount", "splitWordsCount", "gestureInputCount", + "gestureCharsCount", "gesturesDeletedCount", "manualSuggestionsCount", + "revertCommitsCount"); private static void logStatistics() { final ResearchLogger researchLogger = getInstance(); final Statistics statistics = researchLogger.mStatistics; @@ -1236,6 +1494,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang statistics.mDuringRepeatedDeleteKeysCounter.getAverageTime(), statistics.mAfterDeleteKeyCounter.getAverageTime(), statistics.mDictionaryWordCount, statistics.mSplitWordsCount, - statistics.mGestureInputCount); + statistics.mGesturesInputCount, statistics.mGesturesCharsCount, + statistics.mGesturesDeletedCount, statistics.mManualSuggestionsCount, + statistics.mRevertCommitsCount); } } diff --git a/java/src/com/android/inputmethod/research/Statistics.java b/java/src/com/android/inputmethod/research/Statistics.java index 23d1050cb..e9c02c919 100644 --- a/java/src/com/android/inputmethod/research/Statistics.java +++ b/java/src/com/android/inputmethod/research/Statistics.java @@ -42,7 +42,15 @@ public class Statistics { // Number of words split and spaces automatically entered. int mSplitWordsCount; // Number of gestures that were input. - int mGestureInputCount; + int mGesturesInputCount; + // Number of gestures that were deleted. + int mGesturesDeletedCount; + // Total number of characters in words entered by gesture. + int mGesturesCharsCount; + // Number of manual suggestions chosen. + int mManualSuggestionsCount; + // Number of times a commit was reverted in this session. + int mRevertCommitsCount; // Whether the text field was empty upon editing boolean mIsEmptyUponStarting; boolean mIsEmptinessStateKnown; @@ -103,12 +111,20 @@ public class Statistics { mSpaceCount = 0; mDeleteKeyCount = 0; mWordCount = 0; + mDictionaryWordCount = 0; + mSplitWordsCount = 0; + mGesturesInputCount = 0; + mGesturesDeletedCount = 0; + mManualSuggestionsCount = 0; + mRevertCommitsCount = 0; mIsEmptyUponStarting = true; mIsEmptinessStateKnown = false; mKeyCounter.reset(); mBeforeDeleteKeyCounter.reset(); mDuringRepeatedDeleteKeysCounter.reset(); mAfterDeleteKeyCounter.reset(); + mGesturesCharsCount = 0; + mGesturesDeletedCount = 0; mLastTapTime = 0; mIsLastKeyDeleteKey = false; @@ -161,12 +177,24 @@ public class Statistics { mSplitWordsCount++; } - public void recordGestureInput() { - mGestureInputCount++; + public void recordGestureInput(final int numCharsEntered) { + mGesturesInputCount++; + mGesturesCharsCount += numCharsEntered; } public void setIsEmptyUponStarting(final boolean isEmpty) { mIsEmptyUponStarting = isEmpty; mIsEmptinessStateKnown = true; } + + public void recordGestureDelete() { + mGesturesDeletedCount++; + } + public void recordManualSuggestion() { + mManualSuggestionsCount++; + } + + public void recordRevertCommit() { + mRevertCommitsCount++; + } } diff --git a/java/src/com/android/inputmethod/research/UploaderService.java b/java/src/com/android/inputmethod/research/UploaderService.java index 7a5749096..a1ecc1118 100644 --- a/java/src/com/android/inputmethod/research/UploaderService.java +++ b/java/src/com/android/inputmethod/research/UploaderService.java @@ -30,6 +30,7 @@ import android.os.Bundle; import android.util.Log; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.define.ProductionFlag; import java.io.BufferedReader; import java.io.File; @@ -45,6 +46,10 @@ import java.net.URL; public final class UploaderService extends IntentService { private static final String TAG = UploaderService.class.getSimpleName(); + private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG; + // Set IS_INHIBITING_AUTO_UPLOAD to true for local testing + private static final boolean IS_INHIBITING_AUTO_UPLOAD = false + && ProductionFlag.IS_EXPERIMENTAL_DEBUG; // Force false in production public static final long RUN_INTERVAL = AlarmManager.INTERVAL_HOUR; private static final String EXTRA_UPLOAD_UNCONDITIONALLY = UploaderService.class.getName() + ".extra.UPLOAD_UNCONDITIONALLY"; @@ -116,7 +121,8 @@ public final class UploaderService extends IntentService { } private void doUpload(final boolean isUploadingUnconditionally) { - if (!isUploadingUnconditionally && (!isExternallyPowered() || !hasWifiConnection())) { + if (!isUploadingUnconditionally && (!isExternallyPowered() || !hasWifiConnection() + || IS_INHIBITING_AUTO_UPLOAD)) { return; } if (mFilesDir == null) { @@ -141,7 +147,9 @@ public final class UploaderService extends IntentService { } private boolean uploadFile(File file) { - Log.d(TAG, "attempting upload of " + file.getAbsolutePath()); + if (DEBUG) { + Log.d(TAG, "attempting upload of " + file.getAbsolutePath()); + } boolean success = false; final int contentLength = (int) file.length(); HttpURLConnection connection = null; @@ -157,6 +165,9 @@ public final class UploaderService extends IntentService { int numBytesRead; while ((numBytesRead = fileInputStream.read(buf)) != -1) { os.write(buf, 0, numBytesRead); + if (DEBUG) { + Log.d(TAG, new String(buf)); + } } if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { Log.d(TAG, "upload failed: " + connection.getResponseCode()); @@ -171,7 +182,9 @@ public final class UploaderService extends IntentService { } file.delete(); success = true; - Log.d(TAG, "upload successful"); + if (DEBUG) { + Log.d(TAG, "upload successful"); + } } catch (Exception e) { e.printStackTrace(); } finally { diff --git a/native/jni/Android.mk b/native/jni/Android.mk index c616be56e..c99f291d0 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -26,7 +26,7 @@ include $(CLEAR_VARS) LATIN_IME_SRC_DIR := src LATIN_IME_SRC_FULLPATH_DIR := $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR) -LOCAL_C_INCLUDES += $(LATIN_IME_SRC_FULLPATH_DIR) $(LATIN_IME_SRC_FULLPATH_DIR)/gesture +LOCAL_C_INCLUDES += $(LATIN_IME_SRC_FULLPATH_DIR) $(LATIN_IME_SRC_FULLPATH_DIR)/suggest LOCAL_CFLAGS += -Werror -Wall -Wextra -Weffc++ -Wformat=2 -Wcast-qual -Wcast-align \ -Wwrite-strings -Wfloat-equal -Wpointer-arith -Winit-self -Wredundant-decls -Wno-system-headers @@ -57,8 +57,8 @@ LATIN_IME_CORE_SRC_FILES := \ proximity_info_state.cpp \ unigram_dictionary.cpp \ words_priority_queue.cpp \ - gesture/gesture_decoder_wrapper.cpp \ - gesture/incremental_decoder_wrapper.cpp + suggest/gesture_suggest.cpp \ + suggest/typing_suggest.cpp LOCAL_SRC_FILES := \ $(LATIN_IME_JNI_SRC_FILES) \ @@ -102,6 +102,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SDK_VERSION := 14 LOCAL_NDK_STL_VARIANT := stlport_static +LOCAL_LDFLAGS += -ldl include $(BUILD_SHARED_LIBRARY) diff --git a/native/jni/src/dictionary.cpp b/native/jni/src/dictionary.cpp index 8210aa0ff..167b36f11 100644 --- a/native/jni/src/dictionary.cpp +++ b/native/jni/src/dictionary.cpp @@ -23,7 +23,7 @@ #include "defines.h" #include "dictionary.h" #include "dic_traverse_wrapper.h" -#include "gesture_decoder_wrapper.h" +#include "gesture_suggest.h" #include "unigram_dictionary.h" namespace latinime { @@ -36,7 +36,7 @@ Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, mUnigramDictionary(new UnigramDictionary(mOffsetDict, maxWordLength, maxWords, BinaryFormat::getFlags(mDict))), mBigramDictionary(new BigramDictionary(mOffsetDict, maxWordLength, maxPredictions)), - mGestureDecoder(new GestureDecoderWrapper(maxWordLength, maxWords)) { + mGestureSuggest(new GestureSuggest(maxWordLength, maxWords)) { if (DEBUG_DICT) { if (MAX_WORD_LENGTH_INTERNAL < maxWordLength) { AKLOGI("Max word length (%d) is greater than %d", @@ -49,7 +49,7 @@ Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, Dictionary::~Dictionary() { delete mUnigramDictionary; delete mBigramDictionary; - delete mGestureDecoder; + delete mGestureSuggest; } int Dictionary::getSuggestions(ProximityInfo *proximityInfo, void *traverseSession, @@ -61,7 +61,7 @@ int Dictionary::getSuggestions(ProximityInfo *proximityInfo, void *traverseSessi if (isGesture) { DicTraverseWrapper::initDicTraverseSession( traverseSession, this, prevWordChars, prevWordLength); - result = mGestureDecoder->getSuggestions(proximityInfo, traverseSession, + result = mGestureSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates, ycoordinates, times, pointerIds, codes, codesSize, commitPoint, outWords, frequencies, spaceIndices, outputTypes); if (DEBUG_DICT) { diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index e9660002e..26edc4f2f 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -24,8 +24,8 @@ namespace latinime { class BigramDictionary; -class IncrementalDecoderInterface; class ProximityInfo; +class SuggestInterface; class UnigramDictionary; class Dictionary { @@ -83,7 +83,7 @@ class Dictionary { const UnigramDictionary *mUnigramDictionary; const BigramDictionary *mBigramDictionary; - IncrementalDecoderInterface *mGestureDecoder; + SuggestInterface *mGestureSuggest; }; // public static utility methods diff --git a/native/jni/src/geometry_utils.h b/native/jni/src/geometry_utils.h index 38b91cc50..4060a7bd3 100644 --- a/native/jni/src/geometry_utils.h +++ b/native/jni/src/geometry_utils.h @@ -54,7 +54,7 @@ static AK_FORCE_INLINE int getDistanceInt(const int x1, const int y1, const int static AK_FORCE_INLINE float getAngle(const int x1, const int y1, const int x2, const int y2) { const int dx = x1 - x2; const int dy = y1 - y2; - if (dx == 0 && dy == 0) return 0; + if (dx == 0 && dy == 0) return 0.0f; return atan2f(static_cast<float>(dy), static_cast<float>(dx)); } @@ -96,6 +96,7 @@ static inline float pointToLineSegSquaredDistanceFloat(const float x, const floa // Normal distribution N(u, sigma^2). struct NormalDistribution { + public: NormalDistribution(const float u, const float sigma) : mU(u), mSigma(sigma), mPreComputedNonExpPart(1.0f / sqrtf(2.0f * M_PI_F * SQUARE_FLOAT(sigma))), @@ -108,10 +109,10 @@ struct NormalDistribution { private: DISALLOW_IMPLICIT_CONSTRUCTORS(NormalDistribution); - float mU; // mean value - float mSigma; // standard deviation - float mPreComputedNonExpPart; // = 1 / sqrt(2 * PI * sigma^2) - float mPreComputedExponentPart; // = -1 / (2 * sigma^2) + const float mU; // mean value + const float mSigma; // standard deviation + const float mPreComputedNonExpPart; // = 1 / sqrt(2 * PI * sigma^2) + const float mPreComputedExponentPart; // = -1 / (2 * sigma^2) }; // struct NormalDistribution } // namespace latinime #endif // LATINIME_GEOMETRY_UTILS_H diff --git a/native/jni/src/gesture/gesture_decoder_wrapper.h b/native/jni/src/gesture/gesture_decoder_wrapper.h deleted file mode 100644 index b96814907..000000000 --- a/native/jni/src/gesture/gesture_decoder_wrapper.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LATINIME_GESTURE_DECODER_WRAPPER_H -#define LATINIME_GESTURE_DECODER_WRAPPER_H - -#include "defines.h" -#include "incremental_decoder_interface.h" - -namespace latinime { - -class UnigramDictionary; -class BigramDictionary; -class ProximityInfo; - -class GestureDecoderWrapper : public IncrementalDecoderInterface { - public: - GestureDecoderWrapper(const int maxWordLength, const int maxWords) - : mIncrementalDecoderInterface(getGestureDecoderInstance(maxWordLength, maxWords)) { - } - - virtual ~GestureDecoderWrapper(); - - int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs, - int *times, int *pointerIds, int *codes, int inputSize, int commitPoint, int *outWords, - int *frequencies, int *outputIndices, int *outputTypes) const { - if (!mIncrementalDecoderInterface) { - return 0; - } - return mIncrementalDecoderInterface->getSuggestions(pInfo, traverseSession, inputXs, - inputYs, times, pointerIds, codes, inputSize, commitPoint, outWords, frequencies, - outputIndices, outputTypes); - } - - static void setGestureDecoderFactoryMethod( - IncrementalDecoderInterface *(*factoryMethod)(int, int)) { - sGestureDecoderFactoryMethod = factoryMethod; - } - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(GestureDecoderWrapper); - static IncrementalDecoderInterface *getGestureDecoderInstance(int maxWordLength, int maxWords) { - if (sGestureDecoderFactoryMethod) { - return sGestureDecoderFactoryMethod(maxWordLength, maxWords); - } - return 0; - } - - static IncrementalDecoderInterface *(*sGestureDecoderFactoryMethod)(int, int); - IncrementalDecoderInterface *mIncrementalDecoderInterface; -}; -} // namespace latinime -#endif // LATINIME_GESTURE_DECODER_WRAPPER_H diff --git a/native/jni/src/gesture/incremental_decoder_wrapper.h b/native/jni/src/gesture/incremental_decoder_wrapper.h deleted file mode 100644 index c15b439fa..000000000 --- a/native/jni/src/gesture/incremental_decoder_wrapper.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LATINIME_INCREMENTAL_DECODER_WRAPPER_H -#define LATINIME_INCREMENTAL_DECODER_WRAPPER_H - -#include "defines.h" -#include "incremental_decoder_interface.h" - -namespace latinime { - -class UnigramDictionary; -class BigramDictionary; -class ProximityInfo; - -class IncrementalDecoderWrapper : public IncrementalDecoderInterface { - public: - IncrementalDecoderWrapper(const int maxWordLength, const int maxWords) - : mIncrementalDecoderInterface(getIncrementalDecoderInstance(maxWordLength, maxWords)) { - } - - virtual ~IncrementalDecoderWrapper(); - - int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs, - int *times, int *pointerIds, int *codes, int inputSize, int commitPoint, int *outWords, - int *frequencies, int *outputIndices, int *outputTypes) const { - if (!mIncrementalDecoderInterface) { - return 0; - } - return mIncrementalDecoderInterface->getSuggestions(pInfo, traverseSession, inputXs, - inputYs, times, pointerIds, codes, inputSize, commitPoint, outWords, frequencies, - outputIndices, outputTypes); - } - - static void setIncrementalDecoderFactoryMethod( - IncrementalDecoderInterface *(*factoryMethod)(int, int)) { - sIncrementalDecoderFactoryMethod = factoryMethod; - } - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(IncrementalDecoderWrapper); - static IncrementalDecoderInterface *getIncrementalDecoderInstance(int maxWordLength, - int maxWords) { - if (sIncrementalDecoderFactoryMethod) { - return sIncrementalDecoderFactoryMethod(maxWordLength, maxWords); - } - return 0; - } - - static IncrementalDecoderInterface *(*sIncrementalDecoderFactoryMethod)(int, int); - IncrementalDecoderInterface *mIncrementalDecoderInterface; -}; -} // namespace latinime -#endif // LATINIME_INCREMENTAL_DECODER_WRAPPER_H diff --git a/native/jni/src/gesture/gesture_decoder_wrapper.cpp b/native/jni/src/suggest/gesture_suggest.cpp index 20ad4a58c..2a604b8ab 100644 --- a/native/jni/src/gesture/gesture_decoder_wrapper.cpp +++ b/native/jni/src/suggest/gesture_suggest.cpp @@ -14,13 +14,12 @@ * limitations under the License. */ -#include "gesture_decoder_wrapper.h" +#include "gesture_suggest.h" namespace latinime { - IncrementalDecoderInterface * - (*GestureDecoderWrapper::sGestureDecoderFactoryMethod)(int, int) = 0; + SuggestInterface *(*GestureSuggest::sGestureSuggestFactoryMethod)(int, int) = 0; - GestureDecoderWrapper::~GestureDecoderWrapper() { - delete mIncrementalDecoderInterface; + GestureSuggest::~GestureSuggest() { + delete mSuggestInterface; } } // namespace latinime diff --git a/native/jni/src/suggest/gesture_suggest.h b/native/jni/src/suggest/gesture_suggest.h new file mode 100644 index 000000000..e4af03fb8 --- /dev/null +++ b/native/jni/src/suggest/gesture_suggest.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LATINIME_GESTURE_SUGGEST_H +#define LATINIME_GESTURE_SUGGEST_H + +#include "defines.h" +#include "suggest_interface.h" + +namespace latinime { + +class ProximityInfo; + +class GestureSuggest : public SuggestInterface { + public: + GestureSuggest(const int maxWordLength, const int maxWords) + : mSuggestInterface(getGestureSuggestInstance(maxWordLength, maxWords)) { + } + + virtual ~GestureSuggest(); + + int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs, + int *times, int *pointerIds, int *codes, int inputSize, int commitPoint, int *outWords, + int *frequencies, int *outputIndices, int *outputTypes) const { + if (!mSuggestInterface) { + return 0; + } + return mSuggestInterface->getSuggestions(pInfo, traverseSession, inputXs, inputYs, times, + pointerIds, codes, inputSize, commitPoint, outWords, frequencies, outputIndices, + outputTypes); + } + + static void setGestureSuggestFactoryMethod(SuggestInterface *(*factoryMethod)(int, int)) { + sGestureSuggestFactoryMethod = factoryMethod; + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(GestureSuggest); + static SuggestInterface *getGestureSuggestInstance(int maxWordLength, int maxWords) { + if (!sGestureSuggestFactoryMethod) { + return 0; + } + return sGestureSuggestFactoryMethod(maxWordLength, maxWords); + } + + static SuggestInterface *(*sGestureSuggestFactoryMethod)(int, int); + SuggestInterface *mSuggestInterface; +}; +} // namespace latinime +#endif // LATINIME_GESTURE_SUGGEST_H diff --git a/native/jni/src/gesture/incremental_decoder_interface.h b/native/jni/src/suggest/suggest_interface.h index ff85adc61..de58e7918 100644 --- a/native/jni/src/gesture/incremental_decoder_interface.h +++ b/native/jni/src/suggest/suggest_interface.h @@ -14,26 +14,24 @@ * limitations under the License. */ -#ifndef LATINIME_INCREMENTAL_DECODER_INTERFACE_H -#define LATINIME_INCREMENTAL_DECODER_INTERFACE_H +#ifndef LATINIME_SUGGEST_INTERFACE_H +#define LATINIME_SUGGEST_INTERFACE_H #include "defines.h" namespace latinime { -class UnigramDictionary; -class BigramDictionary; class ProximityInfo; -class IncrementalDecoderInterface { +class SuggestInterface { public: virtual int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs, int *times, int *pointerIds, int *codes, int inputSize, int commitPoint, int *outWords, int *frequencies, int *outputIndices, int *outputTypes) const = 0; - IncrementalDecoderInterface() { }; - virtual ~IncrementalDecoderInterface() { }; + SuggestInterface() {}; + virtual ~SuggestInterface() {}; private: - DISALLOW_COPY_AND_ASSIGN(IncrementalDecoderInterface); + DISALLOW_COPY_AND_ASSIGN(SuggestInterface); }; } // namespace latinime -#endif // LATINIME_INCREMENTAL_DECODER_INTERFACE_H +#endif // LATINIME_SUGGEST_INTERFACE_H diff --git a/native/jni/src/gesture/incremental_decoder_wrapper.cpp b/native/jni/src/suggest/typing_suggest.cpp index f6e45623a..40d4a98b0 100644 --- a/native/jni/src/gesture/incremental_decoder_wrapper.cpp +++ b/native/jni/src/suggest/typing_suggest.cpp @@ -14,13 +14,12 @@ * limitations under the License. */ -#include "incremental_decoder_wrapper.h" +#include "typing_suggest.h" namespace latinime { - IncrementalDecoderInterface * - (*IncrementalDecoderWrapper::sIncrementalDecoderFactoryMethod)(int, int) = 0; + SuggestInterface *(*TypingSuggest::sTypingSuggestFactoryMethod)(int, int) = 0; - IncrementalDecoderWrapper::~IncrementalDecoderWrapper() { - delete mIncrementalDecoderInterface; + TypingSuggest::~TypingSuggest() { + delete mSuggestInterface; } } // namespace latinime diff --git a/native/jni/src/suggest/typing_suggest.h b/native/jni/src/suggest/typing_suggest.h new file mode 100644 index 000000000..9de4158f5 --- /dev/null +++ b/native/jni/src/suggest/typing_suggest.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LATINIME_TYPING_SUGGEST_H +#define LATINIME_TYPING_SUGGEST_H + +#include "defines.h" +#include "suggest_interface.h" + +namespace latinime { + +class ProximityInfo; + +class TypingSuggest : public SuggestInterface { + public: + TypingSuggest(const int maxWordLength, const int maxWords) + : mSuggestInterface(getTypingSuggestInstance(maxWordLength, maxWords)) { + } + + virtual ~TypingSuggest(); + + int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs, + int *times, int *pointerIds, int *codes, int inputSize, int commitPoint, int *outWords, + int *frequencies, int *outputIndices, int *outputTypes) const { + if (!mSuggestInterface) { + return 0; + } + return mSuggestInterface->getSuggestions(pInfo, traverseSession, inputXs, inputYs, times, + pointerIds, codes, inputSize, commitPoint, outWords, frequencies, outputIndices, + outputTypes); + } + + static void setTypingSuggestFactoryMethod(SuggestInterface *(*factoryMethod)(int, int)) { + sTypingSuggestFactoryMethod = factoryMethod; + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(TypingSuggest); + static SuggestInterface *getTypingSuggestInstance(int maxWordLength, int maxWords) { + if (!sTypingSuggestFactoryMethod) { + return 0; + } + return sTypingSuggestFactoryMethod(maxWordLength, maxWords); + } + + static SuggestInterface *(*sTypingSuggestFactoryMethod)(int, int); + SuggestInterface *mSuggestInterface; +}; +} // namespace latinime +#endif // LATINIME_TYPING_SUGGEST_H diff --git a/tests/src/com/android/inputmethod/keyboard/SpacebarTextTests.java b/tests/src/com/android/inputmethod/keyboard/SpacebarTextTests.java index de323b0d7..015c2711c 100644 --- a/tests/src/com/android/inputmethod/keyboard/SpacebarTextTests.java +++ b/tests/src/com/android/inputmethod/keyboard/SpacebarTextTests.java @@ -18,7 +18,6 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.res.Resources; -import android.preference.PreferenceManager; import android.test.AndroidTestCase; import android.view.inputmethod.InputMethodSubtype; @@ -42,8 +41,7 @@ public class SpacebarTextTests extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); final Context context = getContext(); - RichInputMethodManager.init( - context, PreferenceManager.getDefaultSharedPreferences(context)); + RichInputMethodManager.init(context); mRichImm = RichInputMethodManager.getInstance(); mRes = context.getResources(); SubtypeLocale.init(context); diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java index 70330509f..86298674b 100644 --- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java +++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java @@ -275,7 +275,7 @@ public class InputTestsBase extends ServiceTestCase<LatinIME> { if (subtype == null) { fail("InputMethodSubtype for locale " + locale + " is not enabled"); } - SubtypeSwitcher.getInstance().updateSubtype(subtype); + SubtypeSwitcher.getInstance().onSubtypeChanged(subtype); mLatinIME.loadKeyboard(); mKeyboard = mLatinIME.mKeyboardSwitcher.getKeyboard(); waitForDictionaryToBeLoaded(); diff --git a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java index 0f6fb7371..4e81de668 100644 --- a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java +++ b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java @@ -18,7 +18,6 @@ package com.android.inputmethod.latin; import android.content.Context; import android.content.res.Resources; -import android.preference.PreferenceManager; import android.test.AndroidTestCase; import android.view.inputmethod.InputMethodSubtype; @@ -38,8 +37,7 @@ public class SubtypeLocaleTests extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); final Context context = getContext(); - RichInputMethodManager.init( - context, PreferenceManager.getDefaultSharedPreferences(context)); + RichInputMethodManager.init(context); mRichImm = RichInputMethodManager.getInstance(); mRes = context.getResources(); SubtypeLocale.init(context); |