diff options
Diffstat (limited to 'java')
117 files changed, 1790 insertions, 1205 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/raw/main_fr.dict b/java/res/raw/main_fr.dict Binary files differindex 5aed479c6..c2941b73a 100644 --- a/java/res/raw/main_fr.dict +++ b/java/res/raw/main_fr.dict 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..1088fdab4 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; } @@ -65,7 +66,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { new KeyboardTheme(5, R.style.KeyboardTheme_IceCreamSandwich), }; - private AudioAndHapticFeedbackManager mFeedbackManager; + private final AudioAndHapticFeedbackManager mFeedbackManager = + AudioAndHapticFeedbackManager.getInstance(); private SubtypeSwitcher mSubtypeSwitcher; private SharedPreferences mPrefs; @@ -95,21 +97,22 @@ 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); mPrefs = prefs; mSubtypeSwitcher = SubtypeSwitcher.getInstance(); mState = new KeyboardState(this); 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/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 61d38745e..b7bee3430 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -50,6 +50,7 @@ import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; import com.android.inputmethod.latin.StringUtils; +import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.research.ResearchLogger; @@ -870,9 +871,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, mPreviewPlacerView.dismissSlidingKeyInputPreview(); } - public void showGestureFloatingPreviewText(final String gestureFloatingPreviewText) { + public void showGestureFloatingPreviewText(final SuggestedWords suggestedWords) { locatePreviewPlacerView(); - mPreviewPlacerView.setGestureFloatingPreviewText(gestureFloatingPreviewText); + mPreviewPlacerView.setGestureFloatingPreviewText(suggestedWords); } public void dismissGestureFloatingPreviewText() { 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/internal/AbstractDrawingPreview.java b/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java new file mode 100644 index 000000000..8a3f0645f --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.keyboard.internal; + +import android.graphics.Canvas; + +import com.android.inputmethod.keyboard.PointerTracker; + +/** + * Abstract base class for previews that are drawn on PreviewPlacerView, e.g., + * GestureFloatingPrevewText, GestureTrail, and SlidingKeyInputPreview. + */ +public abstract class AbstractDrawingPreview { + private boolean mPreviewEnabled; + + public void setPreviewEnabled(final boolean enabled) { + mPreviewEnabled = enabled; + } + + public boolean isPreviewEnabled() { + return mPreviewEnabled; + } + + /** + * Draws the preview + * @param canvas The canvas where the preview is drawn. + */ + public abstract void onDraw(final Canvas canvas); + + /** + * Set the position of the preview. + * @param pt The new location of the preview is based on the points in PointerTracker pt. + */ + public abstract void setPreviewPosition(final PointerTracker pt); +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java new file mode 100644 index 000000000..84cfb389c --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.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.keyboard.internal; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Paint.Align; +import android.graphics.Rect; +import android.graphics.RectF; +import android.text.TextUtils; + +import com.android.inputmethod.keyboard.PointerTracker; +import com.android.inputmethod.latin.CoordinateUtils; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.ResizableIntArray; +import com.android.inputmethod.latin.SuggestedWords; + +/** + * The class for single gesture preview text. The class for multiple gesture preview text will be + * derived from it. + */ +public class GestureFloatingPreviewText extends AbstractDrawingPreview { + private static final class GesturePreviewTextParams { + public final int mGesturePreviewTextSize; + public final int mGesturePreviewTextColor; + public final int mGesturePreviewTextDimmedColor; + public final int mGesturePreviewTextOffset; + public final int mGesturePreviewTextHeight; + public final int mGesturePreviewColor; + public final float mGesturePreviewHorizontalPadding; + public final float mGesturePreviewVerticalPadding; + public final float mGesturePreviewRoundRadius; + public final Paint mTextPaint; + + private static final char[] TEXT_HEIGHT_REFERENCE_CHAR = { 'M' }; + + public GesturePreviewTextParams(final TypedArray keyboardViewAttr) { + mGesturePreviewTextSize = keyboardViewAttr.getDimensionPixelSize( + R.styleable.KeyboardView_gestureFloatingPreviewTextSize, 0); + mGesturePreviewTextColor = keyboardViewAttr.getColor( + R.styleable.KeyboardView_gestureFloatingPreviewTextColor, 0); + mGesturePreviewTextOffset = keyboardViewAttr.getDimensionPixelOffset( + R.styleable.KeyboardView_gestureFloatingPreviewTextOffset, 0); + mGesturePreviewColor = keyboardViewAttr.getColor( + R.styleable.KeyboardView_gestureFloatingPreviewColor, 0); + mGesturePreviewHorizontalPadding = keyboardViewAttr.getDimension( + R.styleable.KeyboardView_gestureFloatingPreviewHorizontalPadding, 0.0f); + mGesturePreviewVerticalPadding = keyboardViewAttr.getDimension( + R.styleable.KeyboardView_gestureFloatingPreviewVerticalPadding, 0.0f); + mGesturePreviewRoundRadius = keyboardViewAttr.getDimension( + R.styleable.KeyboardView_gestureFloatingPreviewRoundRadius, 0.0f); + mGesturePreviewTextDimmedColor = Color.GRAY; + + final Paint textPaint = new Paint(); + textPaint.setAntiAlias(true); + textPaint.setTextAlign(Align.CENTER); + textPaint.setTextSize(mGesturePreviewTextSize); + mTextPaint = textPaint; + final Rect textRect = new Rect(); + textPaint.getTextBounds(TEXT_HEIGHT_REFERENCE_CHAR, 0, 1, textRect); + mGesturePreviewTextHeight = textRect.height(); + } + } + + protected final GesturePreviewTextParams mParams; + protected int mPreviewWordNum; + protected final RectF mGesturePreviewRectangle = new RectF(); + protected int mHighlightedWordIndex; + + private static final int PREVIEW_TEXT_ARRAY_CAPACITY = 10; + // These variables store the positions of preview words. In multi-preview mode, the gesture + // floating preview at most shows PREVIEW_TEXT_ARRAY_CAPACITY words. + protected final ResizableIntArray mPreviewTextXArray = new ResizableIntArray( + PREVIEW_TEXT_ARRAY_CAPACITY); + protected final ResizableIntArray mPreviewTextYArray = new ResizableIntArray( + PREVIEW_TEXT_ARRAY_CAPACITY); + + protected SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; + protected final Context mContext; + public final int[] mLastPointerCoords = CoordinateUtils.newInstance(); + + public GestureFloatingPreviewText(final TypedArray typedArray, final Context context) { + mParams = new GesturePreviewTextParams(typedArray); + mHighlightedWordIndex = 0; + mContext = context; + } + + public void setSuggetedWords(final SuggestedWords suggestedWords) { + if (suggestedWords == null) { + mSuggestedWords = SuggestedWords.EMPTY; + } else { + mSuggestedWords = suggestedWords; + } + updatePreviewPosition(); + } + + protected void drawText(final Canvas canvas, final String text, final float textX, + final float textY, final int color) { + final Paint paint = mParams.mTextPaint; + paint.setColor(color); + canvas.drawText(text, textX, textY, paint); + } + + @Override + public void setPreviewPosition(final PointerTracker pt) { + pt.getLastCoordinates(mLastPointerCoords); + updatePreviewPosition(); + } + + /** + * Draws gesture preview text + * @param canvas The canvas where preview text is drawn. + */ + @Override + public void onDraw(final Canvas canvas) { + if (!isPreviewEnabled() || mSuggestedWords.isEmpty() + || TextUtils.isEmpty(mSuggestedWords.getWord(0))) { + return; + } + final Paint paint = mParams.mTextPaint; + paint.setColor(mParams.mGesturePreviewColor); + final float round = mParams.mGesturePreviewRoundRadius; + canvas.drawRoundRect(mGesturePreviewRectangle, round, round, paint); + final String text = mSuggestedWords.getWord(0); + final int textX = mPreviewTextXArray.get(0); + final int textY = mPreviewTextYArray.get(0); + drawText(canvas, text, textX, textY, mParams.mGesturePreviewTextColor); + } + + /** + * Updates gesture preview text position based on mLastPointerCoords. + */ + protected void updatePreviewPosition() { + if (mSuggestedWords.isEmpty() || TextUtils.isEmpty(mSuggestedWords.getWord(0))) { + return; + } + final String text = mSuggestedWords.getWord(0); + + final Paint paint = mParams.mTextPaint; + final RectF rectangle = mGesturePreviewRectangle; + + final int textHeight = mParams.mGesturePreviewTextHeight; + final float textWidth = paint.measureText(text); + final float hPad = mParams.mGesturePreviewHorizontalPadding; + final float vPad = mParams.mGesturePreviewVerticalPadding; + final float rectWidth = textWidth + hPad * 2.0f; + final float rectHeight = textHeight + vPad * 2.0f; + + final int displayWidth = mContext.getResources().getDisplayMetrics().widthPixels; + final float rectX = Math.min( + Math.max(CoordinateUtils.x(mLastPointerCoords) - rectWidth / 2.0f, 0.0f), + displayWidth - rectWidth); + final float rectY = CoordinateUtils.y(mLastPointerCoords) + - mParams.mGesturePreviewTextOffset - rectHeight; + rectangle.set(rectX, rectY, rectX + rectWidth, rectY + rectHeight); + + final int textX = (int)(rectX + hPad + textWidth / 2.0f); + final int textY = (int)(rectY + vPad) + textHeight; + mPreviewTextXArray.add(0, textX); + mPreviewTextYArray.add(0, textY); + } +} 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/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java index bc734b08d..a005dc975 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java @@ -22,13 +22,10 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import android.graphics.Paint.Align; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; -import android.graphics.RectF; import android.os.Message; -import android.text.TextUtils; import android.util.AttributeSet; import android.util.SparseArray; import android.widget.RelativeLayout; @@ -39,15 +36,9 @@ import com.android.inputmethod.latin.CollectionUtils; import com.android.inputmethod.latin.CoordinateUtils; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; +import com.android.inputmethod.latin.SuggestedWords; public final class PreviewPlacerView extends RelativeLayout { - private final int mGestureFloatingPreviewTextColor; - private final int mGestureFloatingPreviewTextOffset; - private final int mGestureFloatingPreviewColor; - private final float mGestureFloatingPreviewHorizontalPadding; - private final float mGestureFloatingPreviewVerticalPadding; - private final float mGestureFloatingPreviewRoundRadius; - private final int[] mKeyboardViewOrigin = CoordinateUtils.newInstance(); private final SparseArray<GesturePreviewTrail> mGesturePreviewTrails = @@ -62,16 +53,7 @@ public final class PreviewPlacerView extends RelativeLayout { private final Canvas mOffscreenCanvas = new Canvas(); private final Rect mOffscreenDirtyRect = new Rect(); private final Rect mGesturePreviewTrailBoundsRect = new Rect(); // per trail - - private final Paint mTextPaint; - private String mGestureFloatingPreviewText; - private final int mGestureFloatingPreviewTextHeight; - // {@link RectF} is needed for {@link Canvas#drawRoundRect(RectF, float, float, Paint)}. - private final RectF mGestureFloatingPreviewRectangle = new RectF(); - private final int[] mLastPointerCoords = CoordinateUtils.newInstance(); - private static final char[] TEXT_HEIGHT_REFERENCE_CHAR = { 'M' }; - private boolean mDrawsGestureFloatingPreviewText; - + private final GestureFloatingPreviewText mGestureFloatingPreviewText; private boolean mShowSlidingKeyInputPreview; private final int[] mRubberBandFrom = CoordinateUtils.newInstance(); private final int[] mRubberBandTo = CoordinateUtils.newInstance(); @@ -130,22 +112,11 @@ public final class PreviewPlacerView extends RelativeLayout { final TypedArray keyboardViewAttr = context.obtainStyledAttributes( attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); - final int gestureFloatingPreviewTextSize = keyboardViewAttr.getDimensionPixelSize( - R.styleable.KeyboardView_gestureFloatingPreviewTextSize, 0); - mGestureFloatingPreviewTextColor = keyboardViewAttr.getColor( - R.styleable.KeyboardView_gestureFloatingPreviewTextColor, 0); - mGestureFloatingPreviewTextOffset = keyboardViewAttr.getDimensionPixelOffset( - R.styleable.KeyboardView_gestureFloatingPreviewTextOffset, 0); - mGestureFloatingPreviewColor = keyboardViewAttr.getColor( - R.styleable.KeyboardView_gestureFloatingPreviewColor, 0); - mGestureFloatingPreviewHorizontalPadding = keyboardViewAttr.getDimension( - R.styleable.KeyboardView_gestureFloatingPreviewHorizontalPadding, 0.0f); - mGestureFloatingPreviewVerticalPadding = keyboardViewAttr.getDimension( - R.styleable.KeyboardView_gestureFloatingPreviewVerticalPadding, 0.0f); - mGestureFloatingPreviewRoundRadius = keyboardViewAttr.getDimension( - R.styleable.KeyboardView_gestureFloatingPreviewRoundRadius, 0.0f); final int gestureFloatingPreviewTextLingerTimeout = keyboardViewAttr.getInt( R.styleable.KeyboardView_gestureFloatingPreviewTextLingerTimeout, 0); + // TODO: mGestureFloatingPreviewText could be an instance of GestureFloatingPreviewText or + // MultiGesturePreviewText, depending on the user's choice in the settings. + mGestureFloatingPreviewText = new GestureFloatingPreviewText(keyboardViewAttr, context); mGesturePreviewTrailParams = new Params(keyboardViewAttr); keyboardViewAttr.recycle(); @@ -157,15 +128,6 @@ public final class PreviewPlacerView extends RelativeLayout { gesturePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); mGesturePaint = gesturePaint; - final Paint textPaint = new Paint(); - textPaint.setAntiAlias(true); - textPaint.setTextAlign(Align.CENTER); - textPaint.setTextSize(gestureFloatingPreviewTextSize); - mTextPaint = textPaint; - final Rect textRect = new Rect(); - textPaint.getTextBounds(TEXT_HEIGHT_REFERENCE_CHAR, 0, 1, textRect); - mGestureFloatingPreviewTextHeight = textRect.height(); - final Paint layerPaint = new Paint(); layerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER)); setLayerType(LAYER_TYPE_HARDWARE, layerPaint); @@ -181,14 +143,14 @@ public final class PreviewPlacerView extends RelativeLayout { public void setGesturePreviewMode(final boolean drawsGesturePreviewTrail, final boolean drawsGestureFloatingPreviewText) { mDrawsGesturePreviewTrail = drawsGesturePreviewTrail; - mDrawsGestureFloatingPreviewText = drawsGestureFloatingPreviewText; + mGestureFloatingPreviewText.setPreviewEnabled(drawsGestureFloatingPreviewText); } public void invalidatePointer(final PointerTracker tracker, final boolean isOldestTracker) { final boolean needsToUpdateLastPointer = - isOldestTracker && mDrawsGestureFloatingPreviewText; + isOldestTracker && mGestureFloatingPreviewText.isPreviewEnabled(); if (needsToUpdateLastPointer) { - tracker.getLastCoordinates(mLastPointerCoords); + mGestureFloatingPreviewText.setPreviewPosition(tracker); } if (mDrawsGesturePreviewTrail) { @@ -252,6 +214,7 @@ public final class PreviewPlacerView extends RelativeLayout { super.onDraw(canvas); final int originX = CoordinateUtils.x(mKeyboardViewOrigin); final int originY = CoordinateUtils.y(mKeyboardViewOrigin); + canvas.translate(originX, originY); if (mDrawsGesturePreviewTrail) { mayAllocateOffscreenBuffer(); // Draw gesture trails to offscreen buffer. @@ -259,11 +222,10 @@ public final class PreviewPlacerView extends RelativeLayout { mOffscreenCanvas, mGesturePaint, mOffscreenDirtyRect); // Transfer offscreen buffer to screen. if (!mOffscreenDirtyRect.isEmpty()) { - final int offsetY = originY - mOffscreenOffsetY; - canvas.translate(originX, offsetY); + canvas.translate(0, - mOffscreenOffsetY); canvas.drawBitmap(mOffscreenBuffer, mOffscreenDirtyRect, mOffscreenDirtyRect, mGesturePaint); - canvas.translate(-originX, -offsetY); + canvas.translate(0, mOffscreenOffsetY); // Note: Defer clearing the dirty rectangle here because we will get cleared // rectangle on the canvas. } @@ -271,16 +233,11 @@ public final class PreviewPlacerView extends RelativeLayout { mDrawingHandler.postUpdateGestureTrailPreview(); } } - if (mDrawsGestureFloatingPreviewText) { - canvas.translate(originX, originY); - drawGestureFloatingPreviewText(canvas, mGestureFloatingPreviewText); - canvas.translate(-originX, -originY); - } + mGestureFloatingPreviewText.onDraw(canvas); if (mShowSlidingKeyInputPreview) { - canvas.translate(originX, originY); drawSlidingKeyInputPreview(canvas); - canvas.translate(-originX, -originY); } + canvas.translate(-originX, -originY); } private boolean drawGestureTrails(final Canvas offscreenCanvas, final Paint paint, @@ -322,9 +279,9 @@ public final class PreviewPlacerView extends RelativeLayout { Math.min(out.bottom, bottom)); } - public void setGestureFloatingPreviewText(final String gestureFloatingPreviewText) { - if (!mDrawsGestureFloatingPreviewText) return; - mGestureFloatingPreviewText = gestureFloatingPreviewText; + public void setGestureFloatingPreviewText(final SuggestedWords suggestedWords) { + if (!mGestureFloatingPreviewText.isPreviewEnabled()) return; + mGestureFloatingPreviewText.setSuggetedWords(suggestedWords); invalidate(); } @@ -332,39 +289,6 @@ public final class PreviewPlacerView extends RelativeLayout { mDrawingHandler.dismissGestureFloatingPreviewText(); } - private void drawGestureFloatingPreviewText(final Canvas canvas, - final String gestureFloatingPreviewText) { - if (TextUtils.isEmpty(gestureFloatingPreviewText)) { - return; - } - - final Paint paint = mTextPaint; - final RectF rectangle = mGestureFloatingPreviewRectangle; - - // Paint the round rectangle background. - final int textHeight = mGestureFloatingPreviewTextHeight; - final float textWidth = paint.measureText(gestureFloatingPreviewText); - final float hPad = mGestureFloatingPreviewHorizontalPadding; - final float vPad = mGestureFloatingPreviewVerticalPadding; - final float rectWidth = textWidth + hPad * 2.0f; - final float rectHeight = textHeight + vPad * 2.0f; - final int canvasWidth = canvas.getWidth(); - final float rectX = Math.min( - Math.max(CoordinateUtils.x(mLastPointerCoords) - rectWidth / 2.0f, 0.0f), - canvasWidth - rectWidth); - final float rectY = CoordinateUtils.y(mLastPointerCoords) - - mGestureFloatingPreviewTextOffset - rectHeight; - rectangle.set(rectX, rectY, rectX + rectWidth, rectY + rectHeight); - final float round = mGestureFloatingPreviewRoundRadius; - paint.setColor(mGestureFloatingPreviewColor); - canvas.drawRoundRect(rectangle, round, round, paint); - // Paint the text preview - paint.setColor(mGestureFloatingPreviewTextColor); - final float textX = rectX + hPad + textWidth / 2.0f; - final float textY = rectY + vPad + textHeight; - canvas.drawText(gestureFloatingPreviewText, textX, textY, paint); - } - private void drawSlidingKeyInputPreview(final Canvas canvas) { // TODO: Implement rubber band preview } 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..6367156ef 100644 --- a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java +++ b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java @@ -18,11 +18,10 @@ package com.android.inputmethod.latin; import android.content.Context; import android.media.AudioManager; +import android.os.Vibrator; import android.view.HapticFeedbackConstants; import android.view.View; -import com.android.inputmethod.latin.VibratorUtils; - /** * This class gathers audio feedback and haptic feedback functions. * @@ -30,34 +29,63 @@ import com.android.inputmethod.latin.VibratorUtils; * complexity of settings and the like. */ public final class AudioAndHapticFeedbackManager { - private final AudioManager mAudioManager; - private final VibratorUtils mVibratorUtils; + public static final int MAX_KEYPRESS_VIBRATION_DURATION = 250; // millisecond + + private AudioManager mAudioManager; + private Vibrator mVibrator; private SettingsValues mSettingsValues; private boolean mSoundOn; - public AudioAndHapticFeedbackManager(final LatinIME latinIme) { - mVibratorUtils = VibratorUtils.getInstance(latinIme); - mAudioManager = (AudioManager) latinIme.getSystemService(Context.AUDIO_SERVICE); + private static final AudioAndHapticFeedbackManager sInstance = + new AudioAndHapticFeedbackManager(); + + public static AudioAndHapticFeedbackManager getInstance() { + return sInstance; + } + + private AudioAndHapticFeedbackManager() { + // Intentional empty constructor for singleton. + } + + public static void init(final Context context) { + sInstance.initInternal(context); + } + + private void initInternal(final Context context) { + mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); } public void hapticAndAudioFeedback(final int primaryCode, final View viewToPerformHapticFeedbackOn) { - vibrate(viewToPerformHapticFeedbackOn); + vibrateInternal(viewToPerformHapticFeedbackOn); playKeyClick(primaryCode); } + public boolean hasVibrator() { + return mVibrator != null && mVibrator.hasVibrator(); + } + + public void vibrate(final long milliseconds) { + if (mVibrator == null) { + return; + } + mVibrator.vibrate(milliseconds); + } + private boolean reevaluateIfSoundIsOn() { if (mSettingsValues == null || !mSettingsValues.mSoundOn || mAudioManager == null) { return false; - } else { - return mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL; } + return mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL; } - private void playKeyClick(int primaryCode) { + private void playKeyClick(final int primaryCode) { // if mAudioManager is null, we can't play a sound anyway, so return - if (mAudioManager == null) return; + if (mAudioManager == null) { + return; + } if (mSoundOn) { final int sound; switch (primaryCode) { @@ -78,7 +106,7 @@ public final class AudioAndHapticFeedbackManager { } } - private void vibrate(final View viewToPerformHapticFeedbackOn) { + private void vibrateInternal(final View viewToPerformHapticFeedbackOn) { if (!mSettingsValues.mVibrateOn) { return; } @@ -89,9 +117,9 @@ public final class AudioAndHapticFeedbackManager { HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } - } else if (mVibratorUtils != null) { - mVibratorUtils.vibrate(mSettingsValues.mKeypressVibrationDuration); + return; } + vibrate(mSettingsValues.mKeypressVibrationDuration); } public void onSettingsChanged(final SettingsValues settingsValues) { diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java index 16ec5b5db..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}, 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 dcc131fc5..28994dc8e 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; @@ -72,7 +73,6 @@ import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.keyboard.MainKeyboardView; -import com.android.inputmethod.latin.LocaleUtils.RunInLocale; import com.android.inputmethod.latin.Utils.Stats; import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.latin.suggestions.SuggestionStripView; @@ -127,7 +127,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // Current space state of the input method. This can be any of the above constants. private int mSpaceState; - private SettingsValues mCurrentSettings; + private final Settings mSettings; private View mExtractArea; private View mKeyPreviewBackingView; @@ -138,14 +138,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction private ApplicationInfo mTargetApplicationInfo; private RichInputMethodManager mRichImm; - private Resources mResources; - private SharedPreferences mPrefs; @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; private final SubtypeSwitcher mSubtypeSwitcher; 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; @@ -400,6 +398,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction public LatinIME() { super(); + mSettings = Settings.getInstance(); mSubtypeSwitcher = SubtypeSwitcher.getInstance(); mKeyboardSwitcher = KeyboardSwitcher.getInstance(); mIsHardwareAcceleratedDrawingEnabled = @@ -409,17 +408,16 @@ public final class LatinIME extends InputMethodService implements KeyboardAction @Override public void onCreate() { - mPrefs = PreferenceManager.getDefaultSharedPreferences(this); - mResources = getResources(); - - LatinImeLogger.init(this, mPrefs); + Settings.init(this); + 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); + AudioAndHapticFeedbackManager.init(this); AccessibilityUtils.init(this); super.onCreate(); @@ -430,7 +428,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction loadSettings(); initSuggest(); - mDisplayOrientation = mResources.getConfiguration().orientation; + mDisplayOrientation = getResources().getConfiguration().orientation; // Register to receive ringer mode change and network state change. // Also receive installation and removal of a dictionary pack. @@ -457,18 +455,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // Has to be package-visible for unit tests @UsedForTesting void loadSettings() { - // 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. - if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); + final Locale locale = mSubtypeSwitcher.getCurrentSubtypeLocale(); final InputAttributes inputAttributes = new InputAttributes(getCurrentInputEditorInfo(), isFullscreenMode()); - final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() { - @Override - protected SettingsValues job(Resources res) { - return new SettingsValues(mPrefs, inputAttributes, LatinIME.this); - } - }; - mCurrentSettings = job.runInLocale(mResources, mSubtypeSwitcher.getCurrentSubtypeLocale()); + mSettings.loadSettings(locale, inputAttributes); resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary()); } @@ -495,8 +485,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } mSuggest = new Suggest(this /* Context */, subtypeLocale, this /* SuggestInitializationListener */); - if (mCurrentSettings.mCorrectionEnabled) { - mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold); + if (mSettings.getCurrent().mCorrectionEnabled) { + mSuggest.setAutoCorrectionThreshold(mSettings.getCurrent().mAutoCorrectionThreshold); } mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); @@ -510,10 +500,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction resetContactsDictionary(oldContactsDictionary); - // 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. - if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); - mUserHistoryDictionary = UserHistoryDictionary.getInstance(this, localeStr, mPrefs); + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + mUserHistoryDictionary = UserHistoryDictionary.getInstance(this, localeStr, prefs); mSuggest.setUserHistoryDictionary(mUserHistoryDictionary); } @@ -526,7 +514,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction * @param oldContactsDictionary an optional dictionary to use, or null */ private void resetContactsDictionary(final ContactsBinaryDictionary oldContactsDictionary) { - final boolean shouldSetDictionary = (null != mSuggest && mCurrentSettings.mUseContactsDict); + final boolean shouldSetDictionary = + (null != mSuggest && mSettings.getCurrent().mUseContactsDict); final ContactsBinaryDictionary dictionaryToUse; if (!shouldSetDictionary) { @@ -570,6 +559,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mSuggest.close(); mSuggest = null; } + mSettings.onDestroy(); unregisterReceiver(mReceiver); // TODO: The experimental version is not supported by the Dictionary Pack Service yet. if (!ProductionFlag.IS_EXPERIMENTAL) { @@ -582,10 +572,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 +637,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(); } @@ -684,7 +670,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0)); } if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, mPrefs); + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, prefs); } if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) { Log.w(TAG, "Deprecated private IME option specified: " @@ -716,18 +703,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction accessUtils.onStartInputViewInternal(mainKeyboardView, editorInfo, restarting); } - final boolean inputTypeChanged = !mCurrentSettings.isSameInputType(editorInfo); + final boolean inputTypeChanged = !mSettings.getCurrent().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. @@ -754,11 +733,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mainKeyboardView.closing(); loadSettings(); - if (mSuggest != null && mCurrentSettings.mCorrectionEnabled) { - mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold); + if (mSuggest != null && mSettings.getCurrent().mCorrectionEnabled) { + mSuggest.setAutoCorrectionThreshold( + mSettings.getCurrent().mAutoCorrectionThreshold); } - switcher.loadKeyboard(editorInfo, mCurrentSettings); + switcher.loadKeyboard(editorInfo, mSettings.getCurrent()); } else if (restarting) { // TODO: Come up with a more comprehensive way to reset the keyboard layout when // a keyboard layout set doesn't get reloaded in this method. @@ -779,11 +759,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mHandler.cancelDoubleSpacePeriodTimer(); mainKeyboardView.setMainDictionaryAvailability(mIsMainDictionaryAvailable); - mainKeyboardView.setKeyPreviewPopupEnabled(mCurrentSettings.mKeyPreviewPopupOn, - mCurrentSettings.mKeyPreviewPopupDismissDelay); - mainKeyboardView.setGestureHandlingEnabledByUser(mCurrentSettings.mGestureInputEnabled); - mainKeyboardView.setGesturePreviewMode(mCurrentSettings.mGesturePreviewTrailEnabled, - mCurrentSettings.mGestureFloatingPreviewTextEnabled); + mainKeyboardView.setKeyPreviewPopupEnabled(mSettings.getCurrent().mKeyPreviewPopupOn, + mSettings.getCurrent().mKeyPreviewPopupDismissDelay); + mainKeyboardView.setGestureHandlingEnabledByUser( + mSettings.getCurrent().mGestureInputEnabled); + mainKeyboardView.setGesturePreviewMode(mSettings.getCurrent().mGesturePreviewTrailEnabled, + mSettings.getCurrent().mGestureFloatingPreviewTextEnabled); // If we have a user dictionary addition in progress, we should check now if we should // replace the previously committed string with the word that has actually been added @@ -941,7 +922,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction */ @Override public void onExtractedTextClicked() { - if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) return; + if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) return; super.onExtractedTextClicked(); } @@ -957,7 +938,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction */ @Override public void onExtractedCursorMovement(final int dx, final int dy) { - if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) return; + if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) return; super.onExtractedCursorMovement(dx, dy); } @@ -985,7 +966,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } } } - if (!mCurrentSettings.isApplicationSpecifiedCompletionsOn()) return; + if (!mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) return; mApplicationSpecifiedCompletions = applicationSpecifiedCompletions; if (applicationSpecifiedCompletions == null) { clearSuggestionStrip(); @@ -1009,9 +990,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); @@ -1053,7 +1031,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } final int keyboardHeight = mainKeyboardView.getHeight(); final int suggestionsHeight = mSuggestionsContainer.getHeight(); - final int displayHeight = mResources.getDisplayMetrics().heightPixels; + final int displayHeight = getResources().getDisplayMetrics().heightPixels; final Rect rect = new Rect(); mKeyPreviewBackingView.getWindowVisibleDisplayFrame(rect); final int notificationBarHeight = rect.top; @@ -1132,10 +1110,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // the composing word, reset the last composed word, tell the inputconnection about it. private void resetEntireInputState(final int newCursorPosition) { resetComposingState(true /* alsoResetLastComposedWord */); - if (mCurrentSettings.mBigramPredictionEnabled) { + if (mSettings.getCurrent().mBigramPredictionEnabled) { clearSuggestionStrip(); } else { - setSuggestionStrip(mCurrentSettings.mSuggestPuncList, false); + setSuggestionStrip(mSettings.getCurrent().mSuggestPuncList, false); } mConnection.resetCachesUponCursorMove(newCursorPosition); } @@ -1152,13 +1130,16 @@ 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); + } } } // Called from the KeyboardSwitcher which needs to know auto caps state to display // the right layout. public int getCurrentAutoCapsState() { - if (!mCurrentSettings.mAutoCap) return Constants.TextUtils.CAP_MODE_OFF; + if (!mSettings.getCurrent().mAutoCap) return Constants.TextUtils.CAP_MODE_OFF; final EditorInfo ei = getCurrentInputEditorInfo(); if (ei == null) return Constants.TextUtils.CAP_MODE_OFF; @@ -1187,8 +1168,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(); @@ -1196,8 +1179,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } private boolean maybeDoubleSpacePeriod() { - if (!mCurrentSettings.mCorrectionEnabled) return false; - if (!mCurrentSettings.mUseDoubleSpacePeriod) return false; + if (!mSettings.getCurrent().mCorrectionEnabled) return false; + if (!mSettings.getCurrent().mUseDoubleSpacePeriod) return false; if (!mHandler.isAcceptingDoubleSpacePeriod()) return false; final CharSequence lastThree = mConnection.getTextBeforeCursor(3, 0); if (lastThree != null && lastThree.length() == 3 @@ -1206,7 +1189,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; } @@ -1296,7 +1283,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // TODO: Revise the language switch key behavior to make it much smarter and more reasonable. private void handleLanguageSwitchKey() { final IBinder token = getWindow().getWindow().getAttributes().token; - if (mCurrentSettings.mIncludesOtherImesInLanguageSwitchList) { + if (mSettings.getCurrent().mIncludesOtherImesInLanguageSwitchList) { mRichImm.switchToNextInputMethod(token, false /* onlyCurrentIme */); return; } @@ -1324,10 +1311,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 @@ -1400,7 +1385,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction break; default: mSpaceState = SPACE_STATE_NONE; - if (mCurrentSettings.isWordSeparator(primaryCode)) { + if (mSettings.getCurrent().isWordSeparator(primaryCode)) { didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState); } else { if (SPACE_STATE_PHANTOM == spaceState) { @@ -1445,7 +1430,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 +1440,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; @@ -1495,8 +1483,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // should usually be followed by a space, and it should be more readable. if (Constants.NOT_A_CODE != codePointBeforeCursor && !Character.isWhitespace(codePointBeforeCursor) - && !mCurrentSettings.isPhantomSpacePromotingSymbol(codePointBeforeCursor) - && !mCurrentSettings.isWeakSpaceStripper(codePointBeforeCursor)) { + && !mSettings.getCurrent().isPhantomSpacePromotingSymbol(codePointBeforeCursor) + && !mSettings.getCurrent().isWeakSpaceStripper(codePointBeforeCursor)) { mSpaceState = SPACE_STATE_PHANTOM; } } @@ -1603,9 +1591,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction if (dismissGestureFloatingPreviewText) { mainKeyboardView.dismissGestureFloatingPreviewText(); } else { - final String batchInputText = suggestedWords.isEmpty() - ? null : suggestedWords.getWord(0); - mainKeyboardView.showGestureFloatingPreviewText(batchInputText); + mainKeyboardView.showGestureFloatingPreviewText(suggestedWords); } } @@ -1739,10 +1725,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 @@ -1755,7 +1739,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mConnection.deleteSurroundingText(1, 0); } } - if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) { + if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) { restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(); } } @@ -1769,10 +1753,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } else if ((SPACE_STATE_WEAK == spaceState || SPACE_STATE_SWAP_PUNCTUATION == spaceState) && isFromSuggestionStrip) { - if (mCurrentSettings.isWeakSpaceSwapper(code)) { + if (mSettings.getCurrent().isWeakSpaceSwapper(code)) { return true; } else { - if (mCurrentSettings.isWeakSpaceStripper(code)) { + if (mSettings.getCurrent().isWeakSpaceStripper(code)) { mConnection.removeTrailingSpace(); } return false; @@ -1787,7 +1771,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction boolean isComposingWord = mWordComposer.isComposingWord(); if (SPACE_STATE_PHANTOM == spaceState && - !mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode)) { + !mSettings.getCurrent().isSymbolExcludedFromWordSeparators(primaryCode)) { if (isComposingWord) { // Sanity check throw new RuntimeException("Should not be composing here"); @@ -1799,9 +1783,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // dozen milliseconds. Avoid calling it as much as possible, since we are on the UI // thread here. if (!isComposingWord && (isAlphabet(primaryCode) - || mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode)) - && mCurrentSettings.isSuggestionsRequested(mDisplayOrientation) && - !mConnection.isCursorTouchingWord(mCurrentSettings)) { + || mSettings.getCurrent().isSymbolExcludedFromWordSeparators(primaryCode)) + && mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation) && + !mConnection.isCursorTouchingWord(mSettings.getCurrent())) { // Reset entirely the composing state anyway, then start composing a new word unless // the character is a single quote. The idea here is, single quote is not a // separator and it should be treated as a normal character, except in the first @@ -1855,7 +1839,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction boolean didAutoCorrect = false; // Handle separator if (mWordComposer.isComposingWord()) { - if (mCurrentSettings.mCorrectionEnabled) { + if (mSettings.getCurrent().mCorrectionEnabled) { // TODO: maybe cache Strings in an <String> sparse array or something commitCurrentAutoCorrection(new String(new int[]{primaryCode}, 0, 1)); didAutoCorrect = true; @@ -1868,13 +1852,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction Constants.SUGGESTION_STRIP_COORDINATE == x); if (SPACE_STATE_PHANTOM == spaceState && - mCurrentSettings.isPhantomSpacePromotingSymbol(primaryCode)) { + mSettings.getCurrent().isPhantomSpacePromotingSymbol(primaryCode)) { promotePhantomSpace(); } sendKeyCodePoint(primaryCode); if (Constants.CODE_SPACE == primaryCode) { - if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) { + if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) { if (maybeDoubleSpacePeriod()) { mSpaceState = SPACE_STATE_DOUBLE; } else if (!isShowingPunctuationList()) { @@ -1883,7 +1867,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } mHandler.startDoubleSpacePeriodTimer(); - if (!mConnection.isCursorTouchingWord(mCurrentSettings)) { + if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) { mHandler.postUpdateSuggestionStrip(); } } else { @@ -1891,8 +1875,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction swapSwapperAndSpace(); mSpaceState = SPACE_STATE_SWAP_PUNCTUATION; } else if (SPACE_STATE_PHANTOM == spaceState - && !mCurrentSettings.isWeakSpaceStripper(primaryCode) - && !mCurrentSettings.isPhantomSpacePromotingSymbol(primaryCode)) { + && !mSettings.getCurrent().isWeakSpaceStripper(primaryCode) + && !mSettings.getCurrent().isPhantomSpacePromotingSymbol(primaryCode)) { // If we are in phantom space state, and the user presses a separator, we want to // stay in phantom space state so that the next keypress has a chance to add the // space. For example, if I type "Good dat", pick "day" from the suggestion strip @@ -1925,6 +1909,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(); @@ -1938,7 +1923,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction @UsedForTesting boolean isShowingPunctuationList() { if (mSuggestionStripView == null) return false; - return mCurrentSettings.mSuggestPuncList == mSuggestionStripView.getSuggestions(); + return mSettings.getCurrent().mSuggestPuncList == mSuggestionStripView.getSuggestions(); } private boolean isSuggestionsStripVisible() { @@ -1946,11 +1931,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction return false; if (mSuggestionStripView.isShowingAddToDictionaryHint()) return true; - if (!mCurrentSettings.isSuggestionStripVisibleInOrientation(mDisplayOrientation)) + if (!mSettings.getCurrent().isSuggestionStripVisibleInOrientation(mDisplayOrientation)) return false; - if (mCurrentSettings.isApplicationSpecifiedCompletionsOn()) + if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) return true; - return mCurrentSettings.isSuggestionsRequested(mDisplayOrientation); + return mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation); } private void clearSuggestionStrip() { @@ -1984,16 +1969,16 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mHandler.cancelUpdateSuggestionStrip(); // Check if we have a suggestion engine attached. - if (mSuggest == null || !mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) { + if (mSuggest == null + || !mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) { if (mWordComposer.isComposingWord()) { Log.w(TAG, "Called updateSuggestionsOrPredictions but suggestions were not " + "requested!"); - mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); } return; } - if (!mWordComposer.isComposingWord() && !mCurrentSettings.mBigramPredictionEnabled) { + if (!mWordComposer.isComposingWord() && !mSettings.getCurrent().mBigramPredictionEnabled) { setPunctuationSuggestions(); return; } @@ -2014,10 +1999,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // should just skip whitespace if any, so 1. // TODO: this is slow (2-way IPC) - we should probably cache this instead. final String prevWord = - mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, + mConnection.getNthPreviousWord(mSettings.getCurrent().mWordSeparators, mWordComposer.isComposingWord() ? 2 : 1); final SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer, - prevWord, keyboard.getProximityInfo(), mCurrentSettings.mCorrectionEnabled, + prevWord, keyboard.getProximityInfo(), mSettings.getCurrent().mCorrectionEnabled, sessionId); return maybeRetrieveOlderSuggestions(typedWord, suggestedWords); } @@ -2042,7 +2027,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction private SuggestedWords getOlderSuggestions(final String typedWord) { SuggestedWords previousSuggestions = mSuggestionStripView.getSuggestions(); - if (previousSuggestions == mCurrentSettings.mSuggestPuncList) { + if (previousSuggestions == mSettings.getCurrent().mSuggestPuncList) { previousSuggestions = SuggestedWords.EMPTY; } if (typedWord == null) { @@ -2091,8 +2076,7 @@ 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); } if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection, @@ -2124,7 +2108,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, @@ -2141,13 +2125,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // the current batch input text and there is no need for a phantom space. && !mWordComposer.isBatchMode()) { int firstChar = Character.codePointAt(suggestion, 0); - if ((!mCurrentSettings.isWeakSpaceStripper(firstChar)) - && (!mCurrentSettings.isWeakSpaceSwapper(firstChar))) { + if ((!mSettings.getCurrent().isWeakSpaceStripper(firstChar)) + && (!mSettings.getCurrent().isWeakSpaceSwapper(firstChar))) { promotePhantomSpace(); } } - if (mCurrentSettings.isApplicationSpecifiedCompletionsOn() + if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn() && mApplicationSpecifiedCompletions != null && index >= 0 && index < mApplicationSpecifiedCompletions.length) { if (mSuggestionStripView != null) { @@ -2163,9 +2147,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); @@ -2193,7 +2176,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } if (showingAddToDictionaryHint && mIsUserDictionaryAvailable) { mSuggestionStripView.showAddToDictionaryHint( - suggestion, mCurrentSettings.mHintToSaveText); + suggestion, mSettings.getCurrent().mHintToSaveText); } else { // If we're not showing the "Touch again to save", then update the suggestion strip. mHandler.postUpdateSuggestionStrip(); @@ -2214,15 +2197,15 @@ 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() { - if (mCurrentSettings.mBigramPredictionEnabled) { + if (mSettings.getCurrent().mBigramPredictionEnabled) { clearSuggestionStrip(); } else { - setSuggestionStrip(mCurrentSettings.mSuggestPuncList, false); + setSuggestionStrip(mSettings.getCurrent().mSuggestPuncList, false); } setAutoCorrectionIndicator(false); setSuggestionStripShown(isSuggestionsStripVisible()); @@ -2235,12 +2218,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // If correction is not enabled, we don't add words to the user history dictionary. // That's to avoid unintended additions in some sensitive fields, or fields that // expect to receive non-words. - if (!mCurrentSettings.mCorrectionEnabled) return null; + if (!mSettings.getCurrent().mCorrectionEnabled) return null; final UserHistoryDictionary userHistoryDictionary = mUserHistoryDictionary; if (userHistoryDictionary != null) { - final CharSequence prevWord - = mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, 2); + final String prevWord + = mConnection.getNthPreviousWord(mSettings.getCurrent().mWordSeparators, 2); final String secondWord; if (mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps()) { secondWord = suggestion.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale()); @@ -2252,9 +2235,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; } @@ -2264,7 +2246,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction * word, else do nothing. */ private void restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() { - final CharSequence word = mConnection.getWordBeforeCursorIfAtEndOfWord(mCurrentSettings); + final CharSequence word = + mConnection.getWordBeforeCursorIfAtEndOfWord(mSettings.getCurrent()); if (null != word) { restartSuggestionsOnWordBeforeCursor(word); } @@ -2302,8 +2285,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) { @@ -2311,7 +2293,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. @@ -2322,14 +2305,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // This essentially inserts a space, and that's it. public void promotePhantomSpace() { - if (mCurrentSettings.shouldInsertSpacesAutomatically()) { + if (mSettings.getCurrent().shouldInsertSpacesAutomatically()) { sendKeyCodePoint(Constants.CODE_SPACE); } } // Used by the RingCharBuffer public boolean isWordSeparator(final int code) { - return mCurrentSettings.isWordSeparator(code); + return mSettings.getCurrent().isWordSeparator(code); } // TODO: Make this private @@ -2342,7 +2325,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction loadSettings(); if (mKeyboardSwitcher.getMainKeyboardView() != null) { // Reload keyboard because the current language has been changed. - mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mCurrentSettings); + mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettings.getCurrent()); } // Since we just changed languages, we should re-evaluate suggestions with whatever word // we are currently composing. If we are not composing anything, we may want to display @@ -2399,7 +2382,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); } @@ -2504,7 +2486,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction .append("\nPackage : ").append(mTargetApplicationInfo.packageName) .append("\nTarget app sdk version : ") .append(mTargetApplicationInfo.targetSdkVersion) - .append("\nAttributes : ").append(mCurrentSettings.getInputAttributesDebugString()) + .append("\nAttributes : ").append(mSettings.getCurrent().mInputAttributes) .append("\nContext : ").append(context); throw new RuntimeException(s.toString()); } @@ -2518,13 +2500,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1; p.println(" Keyboard mode = " + keyboardMode); + final SettingsValues settingsValues = mSettings.getCurrent(); p.println(" mIsSuggestionsSuggestionsRequested = " - + mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)); - p.println(" mCorrectionEnabled=" + mCurrentSettings.mCorrectionEnabled); + + settingsValues.isSuggestionsRequested(mDisplayOrientation)); + p.println(" mCorrectionEnabled=" + settingsValues.mCorrectionEnabled); p.println(" isComposingWord=" + mWordComposer.isComposingWord()); - p.println(" mSoundOn=" + mCurrentSettings.mSoundOn); - p.println(" mVibrateOn=" + mCurrentSettings.mVibrateOn); - p.println(" mKeyPreviewPopupOn=" + mCurrentSettings.mKeyPreviewPopupOn); - p.println(" inputAttributes=" + mCurrentSettings.getInputAttributesDebugString()); + p.println(" mSoundOn=" + settingsValues.mSoundOn); + p.println(" mVibrateOn=" + settingsValues.mVibrateOn); + p.println(" mKeyPreviewPopupOn=" + settingsValues.mKeyPreviewPopupOn); + p.println(" inputAttributes=" + settingsValues.mInputAttributes); } } 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..1d9d85b47 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -16,34 +16,16 @@ 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; -import android.media.AudioManager; -import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.ListPreference; -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 android.preference.PreferenceManager; -import com.android.inputmethod.latin.define.ProductionFlag; -import com.android.inputmethodcommon.InputMethodSettingsFragment; +import com.android.inputmethod.latin.LocaleUtils.RunInLocale; -public final class Settings extends InputMethodSettingsFragment - implements SharedPreferences.OnSharedPreferenceChangeListener { +import java.util.Locale; +public final class Settings implements SharedPreferences.OnSharedPreferenceChangeListener { // In the same order as xml/prefs.xml public static final String PREF_GENERAL_SETTINGS = "general_settings"; public static final String PREF_AUTO_CAP = "auto_cap"; @@ -84,387 +66,54 @@ public final class Settings extends InputMethodSettingsFragment public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; public static final String PREF_DEBUG_SETTINGS = "debug_settings"; - private PreferenceScreen mKeypressVibrationDurationSettingsPref; - private PreferenceScreen mKeypressSoundVolumeSettingsPref; - private ListPreference mVoicePreference; - private ListPreference mShowCorrectionSuggestionsPreference; - private ListPreference mAutoCorrectionThresholdPreference; - private ListPreference mKeyPreviewPopupDismissDelay; - // Use bigrams to predict the next word when there is no input for it yet - private CheckBoxPreference mBigramPrediction; - private Preference mDebugSettingsPreference; + private Resources mRes; + private SharedPreferences mPrefs; + private Locale mCurrentLocale; + private SettingsValues mSettingsValues; - private TextView mKeypressVibrationDurationSettingsTextView; - private TextView mKeypressSoundVolumeSettingsTextView; + private static final Settings sInstance = new Settings(); - private static void setPreferenceEnabled(final Preference preference, final boolean enabled) { - if (preference != null) { - preference.setEnabled(enabled); - } + public static Settings getInstance() { + return sInstance; } - private void ensureConsistencyOfAutoCorrectionSettings() { - final String autoCorrectionOff = getResources().getString( - R.string.auto_correction_threshold_mode_index_off); - final String currentSetting = mAutoCorrectionThresholdPreference.getValue(); - setPreferenceEnabled(mBigramPrediction, !currentSetting.equals(autoCorrectionOff)); + public static void init(final Context context) { + sInstance.onCreate(context); } - @Override - public void onCreate(final Bundle icicle) { - super.onCreate(icicle); - setInputMethodSettingsCategoryTitle(R.string.language_selection_title); - setSubtypeEnablerTitle(R.string.select_language); - addPreferencesFromResource(R.xml.prefs); - - final Resources res = getResources(); - final Context context = getActivity(); - - // When we are called from the Settings application but we are not already running, the - // {@link SubtypeLocale} class may not have been initialized. It is safe to call - // {@link SubtypeLocale#init(Context)} multiple times. - SubtypeLocale.init(context); - mVoicePreference = (ListPreference) findPreference(PREF_VOICE_MODE); - mShowCorrectionSuggestionsPreference = - (ListPreference) findPreference(PREF_SHOW_SUGGESTIONS_SETTING); - SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); - prefs.registerOnSharedPreferenceChangeListener(this); - - mAutoCorrectionThresholdPreference = - (ListPreference) findPreference(PREF_AUTO_CORRECTION_THRESHOLD); - mBigramPrediction = (CheckBoxPreference) findPreference(PREF_BIGRAM_PREDICTIONS); - ensureConsistencyOfAutoCorrectionSettings(); - - final PreferenceGroup generalSettings = - (PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS); - final PreferenceGroup textCorrectionGroup = - (PreferenceGroup) findPreference(PREF_CORRECTION_SETTINGS); - final PreferenceGroup gestureTypingSettings = - (PreferenceGroup) findPreference(PREF_GESTURE_SETTINGS); - final PreferenceGroup miscSettings = - (PreferenceGroup) findPreference(PREF_MISC_SETTINGS); - - mDebugSettingsPreference = findPreference(PREF_DEBUG_SETTINGS); - if (mDebugSettingsPreference != null) { - if (ProductionFlag.IS_INTERNAL) { - final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN); - debugSettingsIntent.setClassName( - context.getPackageName(), DebugSettingsActivity.class.getName()); - mDebugSettingsPreference.setIntent(debugSettingsIntent); - } else { - miscSettings.removePreference(mDebugSettingsPreference); - } - } - - final boolean showVoiceKeyOption = res.getBoolean( - R.bool.config_enable_show_voice_key_option); - if (!showVoiceKeyOption) { - generalSettings.removePreference(mVoicePreference); - } - - final PreferenceGroup advancedSettings = - (PreferenceGroup) findPreference(PREF_ADVANCED_SETTINGS); - if (!VibratorUtils.getInstance(context).hasVibrator()) { - generalSettings.removePreference(findPreference(PREF_VIBRATE_ON)); - if (null != advancedSettings) { // Theoretically advancedSettings cannot be null - advancedSettings.removePreference(findPreference(PREF_VIBRATION_DURATION_SETTINGS)); - } - } - - final boolean showKeyPreviewPopupOption = res.getBoolean( - R.bool.config_enable_show_popup_on_keypress_option); - mKeyPreviewPopupDismissDelay = - (ListPreference) findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); - if (!showKeyPreviewPopupOption) { - generalSettings.removePreference(findPreference(PREF_POPUP_ON)); - if (null != advancedSettings) { // Theoretically advancedSettings cannot be null - advancedSettings.removePreference(mKeyPreviewPopupDismissDelay); - } - } else { - final String[] entries = new String[] { - res.getString(R.string.key_preview_popup_dismiss_no_delay), - res.getString(R.string.key_preview_popup_dismiss_default_delay), - }; - final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger( - R.integer.config_key_preview_linger_timeout)); - mKeyPreviewPopupDismissDelay.setEntries(entries); - mKeyPreviewPopupDismissDelay.setEntryValues( - new String[] { "0", popupDismissDelayDefaultValue }); - if (null == mKeyPreviewPopupDismissDelay.getValue()) { - mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue); - } - setPreferenceEnabled(mKeyPreviewPopupDismissDelay, - SettingsValues.isKeyPreviewPopupEnabled(prefs, res)); - } - - setPreferenceEnabled(findPreference(PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST), - SettingsValues.showsLanguageSwitchKey(prefs)); - - final PreferenceScreen dictionaryLink = - (PreferenceScreen) findPreference(PREF_CONFIGURE_DICTIONARIES_KEY); - final Intent intent = dictionaryLink.getIntent(); - - final int number = context.getPackageManager().queryIntentActivities(intent, 0).size(); - // TODO: The experimental version is not supported by the Dictionary Pack Service yet - if (ProductionFlag.IS_EXPERIMENTAL || 0 >= number) { - textCorrectionGroup.removePreference(dictionaryLink); - } - - final boolean gestureInputEnabledByBuildConfig = res.getBoolean( - R.bool.config_gesture_input_enabled_by_build_config); - if (!gestureInputEnabledByBuildConfig) { - getPreferenceScreen().removePreference(gestureTypingSettings); - } - - mKeypressVibrationDurationSettingsPref = - (PreferenceScreen) findPreference(PREF_VIBRATION_DURATION_SETTINGS); - if (mKeypressVibrationDurationSettingsPref != null) { - mKeypressVibrationDurationSettingsPref.setOnPreferenceClickListener( - new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference arg0) { - showKeypressVibrationDurationSettingsDialog(); - return true; - } - }); - updateKeypressVibrationDurationSettingsSummary(prefs, res); - } - - mKeypressSoundVolumeSettingsPref = - (PreferenceScreen) findPreference(PREF_KEYPRESS_SOUND_VOLUME); - if (mKeypressSoundVolumeSettingsPref != null) { - mKeypressSoundVolumeSettingsPref.setOnPreferenceClickListener( - new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference arg0) { - showKeypressSoundVolumeSettingDialog(); - return true; - } - }); - updateKeypressSoundVolumeSummary(prefs, res); - } - refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res); + private Settings() { + // Intentional empty constructor for singleton. } - @Override - public void onResume() { - super.onResume(); - final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled(); - if (isShortcutImeEnabled) { - updateVoiceModeSummary(); - } else { - getPreferenceScreen().removePreference(mVoicePreference); - } - updateShowCorrectionSuggestionsSummary(); - updateKeyPreviewPopupDelaySummary(); - updateCustomInputStylesSummary(); + private void onCreate(final Context context) { + mRes = context.getResources(); + mPrefs = PreferenceManager.getDefaultSharedPreferences(context); + mPrefs.registerOnSharedPreferenceChangeListener(this); } - @Override public void onDestroy() { - getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener( - this); - super.onDestroy(); + mPrefs.unregisterOnSharedPreferenceChangeListener(this); } @Override public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { - (new BackupManager(getActivity())).dataChanged(); - if (key.equals(PREF_POPUP_ON)) { - setPreferenceEnabled(findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY), - prefs.getBoolean(PREF_POPUP_ON, true)); - } else if (key.equals(PREF_SHOW_LANGUAGE_SWITCH_KEY)) { - setPreferenceEnabled(findPreference(PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST), - SettingsValues.showsLanguageSwitchKey(prefs)); - } else if (key.equals(PREF_GESTURE_INPUT)) { - final boolean gestureInputEnabledByConfig = getResources().getBoolean( - R.bool.config_gesture_input_enabled_by_build_config); - if (gestureInputEnabledByConfig) { - final boolean gestureInputEnabledByUser = prefs.getBoolean( - PREF_GESTURE_INPUT, true); - setPreferenceEnabled(findPreference(PREF_GESTURE_PREVIEW_TRAIL), - gestureInputEnabledByUser); - setPreferenceEnabled(findPreference(PREF_GESTURE_FLOATING_PREVIEW_TEXT), - gestureInputEnabledByUser); - } - } - ensureConsistencyOfAutoCorrectionSettings(); - updateVoiceModeSummary(); - updateShowCorrectionSuggestionsSummary(); - updateKeyPreviewPopupDelaySummary(); - refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources()); - } - - private void updateShowCorrectionSuggestionsSummary() { - mShowCorrectionSuggestionsPreference.setSummary( - getResources().getStringArray(R.array.prefs_suggestion_visibilities) - [mShowCorrectionSuggestionsPreference.findIndexOfValue( - mShowCorrectionSuggestionsPreference.getValue())]); - } - - private void updateCustomInputStylesSummary() { - final PreferenceScreen customInputStyles = - (PreferenceScreen)findPreference(PREF_CUSTOM_INPUT_STYLES); - final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); - final Resources res = getResources(); - final String prefSubtype = SettingsValues.getPrefAdditionalSubtypes(prefs, res); - final InputMethodSubtype[] subtypes = - AdditionalSubtype.createAdditionalSubtypesArray(prefSubtype); - final StringBuilder styles = new StringBuilder(); - for (final InputMethodSubtype subtype : subtypes) { - if (styles.length() > 0) styles.append(", "); - styles.append(SubtypeLocale.getSubtypeDisplayName(subtype, res)); - } - customInputStyles.setSummary(styles); - } - - private void updateKeyPreviewPopupDelaySummary() { - final ListPreference lp = mKeyPreviewPopupDismissDelay; - final CharSequence[] entries = lp.getEntries(); - if (entries == null || entries.length <= 0) return; - lp.setSummary(entries[lp.findIndexOfValue(lp.getValue())]); - } - - private void updateVoiceModeSummary() { - mVoicePreference.setSummary( - getResources().getStringArray(R.array.voice_input_modes_summary) - [mVoicePreference.findIndexOfValue(mVoicePreference.getValue())]); + loadSettings(mCurrentLocale, mSettingsValues.mInputAttributes); } - private void refreshEnablingsOfKeypressSoundAndVibrationSettings( - final SharedPreferences sp, final Resources res) { - if (mKeypressVibrationDurationSettingsPref != null) { - final boolean hasVibratorHardware = VibratorUtils.getInstance(getActivity()) - .hasVibrator(); - final boolean vibrateOnByUser = sp.getBoolean(Settings.PREF_VIBRATE_ON, - res.getBoolean(R.bool.config_default_vibration_enabled)); - setPreferenceEnabled(mKeypressVibrationDurationSettingsPref, - hasVibratorHardware && vibrateOnByUser); - } - - if (mKeypressSoundVolumeSettingsPref != null) { - final boolean soundOn = sp.getBoolean(Settings.PREF_SOUND_ON, - res.getBoolean(R.bool.config_default_sound_enabled)); - setPreferenceEnabled(mKeypressSoundVolumeSettingsPref, soundOn); - } - } - - 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() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - final int ms = Integer.valueOf( - mKeypressVibrationDurationSettingsTextView.getText().toString()); - 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) { - } - + public void loadSettings(final Locale locale, final InputAttributes inputAttributes) { + mCurrentLocale = locale; + final SharedPreferences prefs = mPrefs; + final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() { @Override - public void onStopTrackingTouch(SeekBar arg0) { - final int tempMs = arg0.getProgress(); - VibratorUtils.getInstance(context).vibrate(tempMs); + protected SettingsValues job(final Resources res) { + return new SettingsValues(prefs, res, inputAttributes); } - }); - sb.setProgress(currentMs); - mKeypressVibrationDurationSettingsTextView.setText(String.valueOf(currentMs)); - builder.setView(v); - builder.create().show(); + }; + mSettingsValues = job.runInLocale(mRes, locale); } - private void updateKeypressSoundVolumeSummary(final SharedPreferences sp, final Resources res) { - if (mKeypressSoundVolumeSettingsPref != null) { - mKeypressSoundVolumeSettingsPref.setSummary(String.valueOf( - (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * 100))); - } - } - - private void showKeypressSoundVolumeSettingDialog() { - 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() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - final float volume = - ((float)Integer.valueOf( - mKeypressSoundVolumeSettingsTextView.getText().toString())) / 100; - 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) { - } - - @Override - public void onStopTrackingTouch(SeekBar arg0) { - final float tempVolume = ((float)arg0.getProgress()) / 100; - am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, tempVolume); - } - }); - sb.setProgress(currentVolumeInt); - mKeypressSoundVolumeSettingsTextView.setText(String.valueOf(currentVolumeInt)); - builder.setView(v); - builder.create().show(); + // TODO: Remove this method and add proxy method to SettingsValues. + public SettingsValues getCurrent() { + return mSettingsValues; } } diff --git a/java/src/com/android/inputmethod/latin/SettingsActivity.java b/java/src/com/android/inputmethod/latin/SettingsActivity.java index 0d3c8ebb7..3aeb10113 100644 --- a/java/src/com/android/inputmethod/latin/SettingsActivity.java +++ b/java/src/com/android/inputmethod/latin/SettingsActivity.java @@ -20,7 +20,7 @@ import android.content.Intent; import android.preference.PreferenceActivity; public final class SettingsActivity extends PreferenceActivity { - private static final String DEFAULT_FRAGMENT = Settings.class.getName(); + private static final String DEFAULT_FRAGMENT = SettingsFragment.class.getName(); @Override public Intent getIntent() { diff --git a/java/src/com/android/inputmethod/latin/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java new file mode 100644 index 000000000..a2980bfa2 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2008 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.backup.BackupManager; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.media.AudioManager; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.ListPreference; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceClickListener; +import android.preference.PreferenceGroup; +import android.preference.PreferenceScreen; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.inputmethod.latin.define.ProductionFlag; +import com.android.inputmethodcommon.InputMethodSettingsFragment; + +public final class SettingsFragment extends InputMethodSettingsFragment + implements SharedPreferences.OnSharedPreferenceChangeListener { + private PreferenceScreen mKeypressVibrationDurationSettingsPref; + private PreferenceScreen mKeypressSoundVolumeSettingsPref; + private ListPreference mVoicePreference; + private ListPreference mShowCorrectionSuggestionsPreference; + private ListPreference mAutoCorrectionThresholdPreference; + private ListPreference mKeyPreviewPopupDismissDelay; + // Use bigrams to predict the next word when there is no input for it yet + private CheckBoxPreference mBigramPrediction; + private Preference mDebugSettingsPreference; + + private void setPreferenceEnabled(final String preferenceKey, final boolean enabled) { + final Preference preference = findPreference(preferenceKey); + if (preference != null) { + preference.setEnabled(enabled); + } + } + + private void ensureConsistencyOfAutoCorrectionSettings() { + final String autoCorrectionOff = getResources().getString( + R.string.auto_correction_threshold_mode_index_off); + final String currentSetting = mAutoCorrectionThresholdPreference.getValue(); + mBigramPrediction.setEnabled(!currentSetting.equals(autoCorrectionOff)); + } + + @Override + public void onCreate(final Bundle icicle) { + super.onCreate(icicle); + setInputMethodSettingsCategoryTitle(R.string.language_selection_title); + setSubtypeEnablerTitle(R.string.select_language); + addPreferencesFromResource(R.xml.prefs); + + final Resources res = getResources(); + final Context context = getActivity(); + + // When we are called from the Settings application but we are not already running, the + // {@link SubtypeLocale} class may not have been initialized. It is safe to call + // {@link SubtypeLocale#init(Context)} multiple times. + SubtypeLocale.init(context); + mVoicePreference = (ListPreference) findPreference(Settings.PREF_VOICE_MODE); + mShowCorrectionSuggestionsPreference = + (ListPreference) findPreference(Settings.PREF_SHOW_SUGGESTIONS_SETTING); + final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); + prefs.registerOnSharedPreferenceChangeListener(this); + + mAutoCorrectionThresholdPreference = + (ListPreference) findPreference(Settings.PREF_AUTO_CORRECTION_THRESHOLD); + mBigramPrediction = (CheckBoxPreference) findPreference(Settings.PREF_BIGRAM_PREDICTIONS); + ensureConsistencyOfAutoCorrectionSettings(); + + final PreferenceGroup generalSettings = + (PreferenceGroup) findPreference(Settings.PREF_GENERAL_SETTINGS); + final PreferenceGroup textCorrectionGroup = + (PreferenceGroup) findPreference(Settings.PREF_CORRECTION_SETTINGS); + final PreferenceGroup gestureTypingSettings = + (PreferenceGroup) findPreference(Settings.PREF_GESTURE_SETTINGS); + final PreferenceGroup miscSettings = + (PreferenceGroup) findPreference(Settings.PREF_MISC_SETTINGS); + + mDebugSettingsPreference = findPreference(Settings.PREF_DEBUG_SETTINGS); + if (mDebugSettingsPreference != null) { + if (ProductionFlag.IS_INTERNAL) { + final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN); + debugSettingsIntent.setClassName( + context.getPackageName(), DebugSettingsActivity.class.getName()); + mDebugSettingsPreference.setIntent(debugSettingsIntent); + } else { + miscSettings.removePreference(mDebugSettingsPreference); + } + } + + final boolean showVoiceKeyOption = res.getBoolean( + R.bool.config_enable_show_voice_key_option); + if (!showVoiceKeyOption) { + generalSettings.removePreference(mVoicePreference); + } + + final PreferenceGroup advancedSettings = + (PreferenceGroup) findPreference(Settings.PREF_ADVANCED_SETTINGS); + if (!AudioAndHapticFeedbackManager.getInstance().hasVibrator()) { + generalSettings.removePreference(findPreference(Settings.PREF_VIBRATE_ON)); + if (null != advancedSettings) { // Theoretically advancedSettings cannot be null + advancedSettings.removePreference( + findPreference(Settings.PREF_VIBRATION_DURATION_SETTINGS)); + } + } + + final boolean showKeyPreviewPopupOption = res.getBoolean( + R.bool.config_enable_show_popup_on_keypress_option); + mKeyPreviewPopupDismissDelay = + (ListPreference) findPreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); + if (!showKeyPreviewPopupOption) { + generalSettings.removePreference(findPreference(Settings.PREF_POPUP_ON)); + if (null != advancedSettings) { // Theoretically advancedSettings cannot be null + advancedSettings.removePreference(mKeyPreviewPopupDismissDelay); + } + } else { + final String[] entries = new String[] { + res.getString(R.string.key_preview_popup_dismiss_no_delay), + res.getString(R.string.key_preview_popup_dismiss_default_delay), + }; + final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger( + R.integer.config_key_preview_linger_timeout)); + mKeyPreviewPopupDismissDelay.setEntries(entries); + mKeyPreviewPopupDismissDelay.setEntryValues( + new String[] { "0", popupDismissDelayDefaultValue }); + if (null == mKeyPreviewPopupDismissDelay.getValue()) { + mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue); + } + mKeyPreviewPopupDismissDelay.setEnabled( + SettingsValues.isKeyPreviewPopupEnabled(prefs, res)); + } + + setPreferenceEnabled(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, + SettingsValues.showsLanguageSwitchKey(prefs)); + + final PreferenceScreen dictionaryLink = + (PreferenceScreen) findPreference(Settings.PREF_CONFIGURE_DICTIONARIES_KEY); + final Intent intent = dictionaryLink.getIntent(); + + final int number = context.getPackageManager().queryIntentActivities(intent, 0).size(); + // TODO: The experimental version is not supported by the Dictionary Pack Service yet + if (ProductionFlag.IS_EXPERIMENTAL || 0 >= number) { + textCorrectionGroup.removePreference(dictionaryLink); + } + + final boolean gestureInputEnabledByBuildConfig = res.getBoolean( + R.bool.config_gesture_input_enabled_by_build_config); + if (!gestureInputEnabledByBuildConfig) { + getPreferenceScreen().removePreference(gestureTypingSettings); + } + + mKeypressVibrationDurationSettingsPref = + (PreferenceScreen) findPreference(Settings.PREF_VIBRATION_DURATION_SETTINGS); + if (mKeypressVibrationDurationSettingsPref != null) { + mKeypressVibrationDurationSettingsPref.setOnPreferenceClickListener( + new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference arg0) { + showKeypressVibrationDurationSettingsDialog(); + return true; + } + }); + mKeypressVibrationDurationSettingsPref.setSummary( + res.getString(R.string.settings_keypress_vibration_duration, + SettingsValues.getCurrentVibrationDuration(prefs, res))); + } + + mKeypressSoundVolumeSettingsPref = + (PreferenceScreen) findPreference(Settings.PREF_KEYPRESS_SOUND_VOLUME); + if (mKeypressSoundVolumeSettingsPref != null) { + mKeypressSoundVolumeSettingsPref.setOnPreferenceClickListener( + new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference arg0) { + showKeypressSoundVolumeSettingDialog(); + return true; + } + }); + mKeypressSoundVolumeSettingsPref.setSummary(String.valueOf( + getCurrentKeyPressSoundVolumePercent(prefs, res))); + } + refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res); + } + + @Override + public void onResume() { + super.onResume(); + final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled(); + if (isShortcutImeEnabled) { + updateVoiceModeSummary(); + } else { + getPreferenceScreen().removePreference(mVoicePreference); + } + updateShowCorrectionSuggestionsSummary(); + updateKeyPreviewPopupDelaySummary(); + updateCustomInputStylesSummary(); + } + + @Override + public void onDestroy() { + getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener( + this); + super.onDestroy(); + } + + @Override + public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { + (new BackupManager(getActivity())).dataChanged(); + if (key.equals(Settings.PREF_POPUP_ON)) { + setPreferenceEnabled(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, + prefs.getBoolean(Settings.PREF_POPUP_ON, true)); + } else if (key.equals(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY)) { + setPreferenceEnabled(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, + SettingsValues.showsLanguageSwitchKey(prefs)); + } else if (key.equals(Settings.PREF_GESTURE_INPUT)) { + final boolean gestureInputEnabledByConfig = getResources().getBoolean( + R.bool.config_gesture_input_enabled_by_build_config); + if (gestureInputEnabledByConfig) { + final boolean gestureInputEnabledByUser = prefs.getBoolean( + Settings.PREF_GESTURE_INPUT, true); + setPreferenceEnabled(Settings.PREF_GESTURE_PREVIEW_TRAIL, + gestureInputEnabledByUser); + setPreferenceEnabled(Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, + gestureInputEnabledByUser); + } + } + ensureConsistencyOfAutoCorrectionSettings(); + updateVoiceModeSummary(); + updateShowCorrectionSuggestionsSummary(); + updateKeyPreviewPopupDelaySummary(); + refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources()); + } + + private void updateShowCorrectionSuggestionsSummary() { + mShowCorrectionSuggestionsPreference.setSummary( + getResources().getStringArray(R.array.prefs_suggestion_visibilities) + [mShowCorrectionSuggestionsPreference.findIndexOfValue( + mShowCorrectionSuggestionsPreference.getValue())]); + } + + private void updateCustomInputStylesSummary() { + final PreferenceScreen customInputStyles = + (PreferenceScreen)findPreference(Settings.PREF_CUSTOM_INPUT_STYLES); + final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); + final Resources res = getResources(); + final String prefSubtype = SettingsValues.getPrefAdditionalSubtypes(prefs, res); + final InputMethodSubtype[] subtypes = + AdditionalSubtype.createAdditionalSubtypesArray(prefSubtype); + final StringBuilder styles = new StringBuilder(); + for (final InputMethodSubtype subtype : subtypes) { + if (styles.length() > 0) styles.append(", "); + styles.append(SubtypeLocale.getSubtypeDisplayName(subtype, res)); + } + customInputStyles.setSummary(styles); + } + + private void updateKeyPreviewPopupDelaySummary() { + final ListPreference lp = mKeyPreviewPopupDismissDelay; + final CharSequence[] entries = lp.getEntries(); + if (entries == null || entries.length <= 0) return; + lp.setSummary(entries[lp.findIndexOfValue(lp.getValue())]); + } + + private void updateVoiceModeSummary() { + mVoicePreference.setSummary( + getResources().getStringArray(R.array.voice_input_modes_summary) + [mVoicePreference.findIndexOfValue(mVoicePreference.getValue())]); + } + + private void refreshEnablingsOfKeypressSoundAndVibrationSettings( + final SharedPreferences sp, final Resources res) { + if (mKeypressVibrationDurationSettingsPref != null) { + final boolean hasVibratorHardware = + AudioAndHapticFeedbackManager.getInstance().hasVibrator(); + final boolean vibrateOnByUser = sp.getBoolean(Settings.PREF_VIBRATE_ON, + res.getBoolean(R.bool.config_default_vibration_enabled)); + mKeypressVibrationDurationSettingsPref.setEnabled( + hasVibratorHardware && vibrateOnByUser); + } + + if (mKeypressSoundVolumeSettingsPref != null) { + final boolean soundOn = sp.getBoolean(Settings.PREF_SOUND_ON, + res.getBoolean(R.bool.config_default_sound_enabled)); + mKeypressSoundVolumeSettingsPref.setEnabled(soundOn); + } + } + + private void showKeypressVibrationDurationSettingsDialog() { + final SharedPreferences sp = getPreferenceManager().getSharedPreferences(); + final Context context = getActivity(); + final PreferenceScreen settingsPref = mKeypressVibrationDurationSettingsPref; + final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() { + @Override + public void onPositiveButtonClick(final SeekBarDialog dialog) { + final int ms = dialog.getValue(); + sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, ms).apply(); + if (settingsPref != null) { + settingsPref.setSummary(dialog.getValueText()); + } + } + + @Override + public void onStopTrackingTouch(final SeekBarDialog dialog) { + final int ms = dialog.getValue(); + AudioAndHapticFeedbackManager.getInstance().vibrate(ms); + } + }; + 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 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 PreferenceScreen settingsPref = mKeypressSoundVolumeSettingsPref; + final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() { + @Override + public void onPositiveButtonClick(final SeekBarDialog dialog) { + final float volume = dialog.getValue() / PERCENT_FLOAT; + sp.edit().putFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, volume).apply(); + if (settingsPref != null) { + settingsPref.setSummary(dialog.getValueText()); + } + } + + @Override + public void onStopTrackingTouch(final SeekBarDialog dialog) { + final float volume = dialog.getValue() / PERCENT_FLOAT; + am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, volume); + } + }; + 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..39406621c 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -16,7 +16,6 @@ package com.android.inputmethod.latin; -import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; @@ -78,16 +77,12 @@ 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; // From the input box - private final InputAttributes mInputAttributes; + public final InputAttributes mInputAttributes; // Deduced settings public final int mKeypressVibrationDuration; @@ -100,10 +95,8 @@ public final class SettingsValues { private final boolean mVoiceKeyEnabled; private final boolean mVoiceKeyOnMain; - public SettingsValues(final SharedPreferences prefs, final InputAttributes inputAttributes, - final Context context) { - final Resources res = context.getResources(); - + public SettingsValues(final SharedPreferences prefs, final Resources res, + final InputAttributes inputAttributes) { // Get the resources mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions); mWeakSpaceStrippers = res.getString(R.string.weak_space_stripping_symbols); @@ -125,7 +118,7 @@ public final class SettingsValues { res.getString(R.string.symbols_excluded_from_word_separators); mWordSeparators = createWordSeparators(mWeakSpaceStrippers, mWeakSpaceSwappers, mSymbolsExcludedFromWordSeparators, res); - mHintToSaveText = context.getText(R.string.hint_add_to_dictionary); + mHintToSaveText = res.getText(R.string.hint_add_to_dictionary); // Store the input attributes if (null == inputAttributes) { @@ -136,7 +129,7 @@ public final class SettingsValues { // Get the settings preferences mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true); - mVibrateOn = isVibrateOn(context, prefs, res); + mVibrateOn = isVibrateOn(prefs, res); mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON, res.getBoolean(R.bool.config_default_sound_enabled)); mKeyPreviewPopupOn = isKeyPreviewPopupEnabled(prefs, res); @@ -158,9 +151,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); @@ -221,9 +211,8 @@ public final class SettingsValues { throw new RuntimeException("Bug: visibility string is not configured correctly"); } - private static boolean isVibrateOn(final Context context, final SharedPreferences prefs, - final Resources res) { - final boolean hasVibrator = VibratorUtils.getInstance(context).hasVibrator(); + private static boolean isVibrateOn(final SharedPreferences prefs, final Resources res) { + final boolean hasVibrator = AudioAndHapticFeedbackManager.getInstance().hasVibrator(); return hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON, res.getBoolean(R.bool.config_default_vibration_enabled)); } @@ -280,6 +269,7 @@ public final class SettingsValues { return !currentAutoCorrectionSetting.equals(autoCorrectionOff); } + // TODO: Clean up and move public helper methods to Settings class. // Public to access from KeyboardSwitcher. Should it have access to some // process-global instance instead? public static boolean isKeyPreviewPopupEnabled(final SharedPreferences prefs, @@ -383,27 +373,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 @@ -434,9 +420,4 @@ public final class SettingsValues { public boolean isSameInputType(final EditorInfo editorInfo) { return mInputAttributes.isSameInputType(editorInfo); } - - // For debug. - public String getInputAttributesDebugString() { - return mInputAttributes.toString(); - } } 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..a16784985 100644 --- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java @@ -24,27 +24,28 @@ 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; import java.util.Arrays; /** - * An expandable dictionary that stores the words in the user unigram dictionary. - * - * Largely a copy of UserDictionary, will replace that class in the future. + * An expandable dictionary that stores the words in the user dictionary provider into a binary + * dictionary file to use it from native code. */ public class UserBinaryDictionary extends ExpandableBinaryDictionary { // The user dictionary provider uses an empty string to mean "all languages". private static final String USER_DICTIONARY_ALL_LANGUAGES = ""; + private static final int HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY = 250; + private static final int LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY = 160; // TODO: use Words.SHORTCUT when we target JellyBean or above 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 +91,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); @@ -232,9 +234,21 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { mContext.startActivity(intent); } + private int scaleFrequencyFromDefaultToLatinIme(final int defaultFrequency) { + // The default frequency for the user dictionary is 250 for historical reasons. + // Latin IME considers a good value for the default user dictionary frequency + // is about 160 considering the scale we use. So we are scaling down the values. + if (defaultFrequency > Integer.MAX_VALUE / LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY) { + return (defaultFrequency / HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY) + * LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY; + } else { + return (defaultFrequency * LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY) + / HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY; + } + } + 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()) { @@ -245,12 +259,13 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { final String word = cursor.getString(indexWord); final String shortcut = hasShortcutColumn ? cursor.getString(indexShortcut) : null; final int frequency = cursor.getInt(indexFrequency); + final int adjustedFrequency = scaleFrequencyFromDefaultToLatinIme(frequency); // Safeguard against adding really long words. if (word.length() < MAX_WORD_LENGTH) { - super.addWord(word, null, frequency); + super.addWord(word, null, adjustedFrequency); } if (null != shortcut && shortcut.length() < MAX_WORD_LENGTH) { - super.addWord(shortcut, word, frequency); + super.addWord(shortcut, word, adjustedFrequency); } cursor.moveToNext(); } 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/VibratorUtils.java b/java/src/com/android/inputmethod/latin/VibratorUtils.java deleted file mode 100644 index b6696cec0..000000000 --- a/java/src/com/android/inputmethod/latin/VibratorUtils.java +++ /dev/null @@ -1,50 +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. - */ - -package com.android.inputmethod.latin; - -import android.content.Context; -import android.os.Vibrator; - -public final class VibratorUtils { - private static final VibratorUtils sInstance = new VibratorUtils(); - private Vibrator mVibrator; - - private VibratorUtils() { - // This utility class is not publicly instantiable. - } - - public static VibratorUtils getInstance(Context context) { - if (sInstance.mVibrator == null) { - sInstance.mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); - } - return sInstance; - } - - public boolean hasVibrator() { - if (mVibrator == null) { - return false; - } - return mVibrator.hasVibrator(); - } - - public void vibrate(long milliseconds) { - if (mVibrator == null) { - return; - } - mVibrator.vibrate(milliseconds); - } -} 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/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index f5465d7b0..2fc18eab1 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -38,6 +38,7 @@ 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; @@ -161,7 +162,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return sInstance; } - public void init(final LatinIME latinIME, final SharedPreferences prefs) { + public void init(final LatinIME latinIME) { assert latinIME != null; if (latinIME == null) { Log.w(TAG, "IMS is null; logging is off"); @@ -171,6 +172,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang 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)) { @@ -741,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); @@ -751,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; } @@ -1049,12 +1046,15 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang 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(); } /** @@ -1065,10 +1065,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang 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); } /** @@ -1147,9 +1148,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * 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(); } /** @@ -1259,17 +1265,27 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang final ResearchLogger researchLogger = getInstance(); researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_COMMITCURRENTAUTOCORRECTION, scrubbedTypedWord, scrubbedAutoCorrection, separatorString); - researchLogger.onWordComplete(scrubbedAutoCorrection, Long.MAX_VALUE, - false /* isPartial */); + 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(); } /** @@ -1287,7 +1303,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (!researchLogger.isExpectingCommitText) { researchLogger.enqueueEvent(LOGSTATEMENT_RICHINPUTCONNECTIONCOMMITTEXT, newCursorPosition); - researchLogger.onWordComplete(scrubbedWord, Long.MAX_VALUE, false /* isPartial */); + researchLogger.onWordComplete(scrubbedWord, Long.MAX_VALUE); } researchLogger.isExpectingCommitText = false; } @@ -1465,7 +1481,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang "isEmptinessStateKnown", "averageTimeBetweenKeys", "averageTimeBeforeDelete", "averageTimeDuringRepeatedDelete", "averageTimeAfterDelete", "dictionaryWordCount", "splitWordsCount", "gestureInputCount", - "gestureCharsCount", "gesturesDeletedCount"); + "gestureCharsCount", "gesturesDeletedCount", "manualSuggestionsCount", + "revertCommitsCount"); private static void logStatistics() { final ResearchLogger researchLogger = getInstance(); final Statistics statistics = researchLogger.mStatistics; @@ -1477,8 +1494,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang statistics.mDuringRepeatedDeleteKeysCounter.getAverageTime(), statistics.mAfterDeleteKeyCounter.getAverageTime(), statistics.mDictionaryWordCount, statistics.mSplitWordsCount, - statistics.mGesturesInputCount, - statistics.mGesturesCharsCount, - statistics.mGesturesDeletedCount); + 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 a02aabf3c..e9c02c919 100644 --- a/java/src/com/android/inputmethod/research/Statistics.java +++ b/java/src/com/android/inputmethod/research/Statistics.java @@ -47,6 +47,10 @@ public class Statistics { 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; @@ -111,6 +115,8 @@ public class Statistics { mSplitWordsCount = 0; mGesturesInputCount = 0; mGesturesDeletedCount = 0; + mManualSuggestionsCount = 0; + mRevertCommitsCount = 0; mIsEmptyUponStarting = true; mIsEmptinessStateKnown = false; mKeyCounter.reset(); @@ -184,4 +190,11 @@ public class Statistics { public void recordGestureDelete() { mGesturesDeletedCount++; } + public void recordManualSuggestion() { + mManualSuggestionsCount++; + } + + public void recordRevertCommit() { + mRevertCommitsCount++; + } } |