From 4bcf70c93106f17e3119fcb4c7ec9eaff6d54e4c Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 4 Jul 2012 17:41:55 +0900 Subject: [PATCH 01/68] Fix a bad interaction with mmap Bug: 6761221 Change-Id: I7e6d98dc9d7cb34a6163c3957e401ff97abb975c --- .../latin/BinaryDictionaryFileDumper.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java index 37eced5d6..236c198ad 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java @@ -149,7 +149,8 @@ public class BinaryDictionaryFileDumper { final int MODE_MAX = NONE; final Uri.Builder wordListUriBuilder = getProviderUriBuilder(id); - final String outputFileName = BinaryDictionaryGetter.getCacheFileName(id, locale, context); + final String finalFileName = BinaryDictionaryGetter.getCacheFileName(id, locale, context); + final String tempFileName = finalFileName + ".tmp"; for (int mode = MODE_MIN; mode <= MODE_MAX; ++mode) { InputStream originalSourceStream = null; @@ -165,7 +166,10 @@ public class BinaryDictionaryFileDumper { if (null == afd) return null; originalSourceStream = afd.createInputStream(); // Open output. - outputFile = new File(outputFileName); + outputFile = new File(tempFileName); + // Just to be sure, delete the file. This may fail silently, and return false: this + // is the right thing to do, as we just want to continue anyway. + outputFile.delete(); outputStream = new FileOutputStream(outputFile); // Get the appropriate decryption method for this try switch (mode) { @@ -194,14 +198,20 @@ public class BinaryDictionaryFileDumper { break; } checkMagicAndCopyFileTo(new BufferedInputStream(inputStream), outputStream); + outputStream.flush(); + outputStream.close(); + final File finalFile = new File(finalFileName); + if (!outputFile.renameTo(finalFile)) { + throw new IOException("Can't move the file to its final name"); + } wordListUriBuilder.appendQueryParameter(QUERY_PARAMETER_DELETE_RESULT, QUERY_PARAMETER_SUCCESS); if (0 >= resolver.delete(wordListUriBuilder.build(), null, null)) { Log.e(TAG, "Could not have the dictionary pack delete a word list"); } - BinaryDictionaryGetter.removeFilesWithIdExcept(context, id, outputFile); + BinaryDictionaryGetter.removeFilesWithIdExcept(context, id, finalFile); // Success! Close files (through the finally{} clause) and return. - return AssetFileAddress.makeFromFileName(outputFileName); + return AssetFileAddress.makeFromFileName(finalFileName); } catch (Exception e) { if (DEBUG) { Log.i(TAG, "Can't open word list in mode " + mode + " : " + e); From bffa6cc1b2730776b2d680ba614bd7bc5cf0b01f Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Wed, 4 Jul 2012 18:22:40 +0900 Subject: [PATCH 02/68] Initialize SubtypeLocale from Settings (DO NOT MERGE) Bug: 6781106 Change-Id: Ic1b2b8363486820eabaa415ab3812c0e8565b7bb --- java/src/com/android/inputmethod/latin/Settings.java | 4 ++++ java/src/com/android/inputmethod/latin/SubtypeLocale.java | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 152d66851..4bb21720b 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -116,6 +116,10 @@ public class Settings extends InputMethodSettingsFragment 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); diff --git a/java/src/com/android/inputmethod/latin/SubtypeLocale.java b/java/src/com/android/inputmethod/latin/SubtypeLocale.java index acc17ef3f..21c9c0d1e 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeLocale.java +++ b/java/src/com/android/inputmethod/latin/SubtypeLocale.java @@ -41,6 +41,7 @@ public class SubtypeLocale { public static final String QWERTY = "qwerty"; public static final int UNKNOWN_KEYBOARD_LAYOUT = R.string.subtype_generic; + private static boolean sInitialized = false; private static String[] sPredefinedKeyboardLayoutSet; // Keyboard layout to its display name map. private static final HashMap sKeyboardLayoutToDisplayNameMap = @@ -69,7 +70,10 @@ public class SubtypeLocale { // Intentional empty constructor for utility class. } - public static void init(Context context) { + // Note that this initialization method can be called multiple times. + public static synchronized void init(Context context) { + if (sInitialized) return; + final Resources res = context.getResources(); final String[] predefinedLayoutSet = res.getStringArray(R.array.predefined_layouts); @@ -109,6 +113,8 @@ public class SubtypeLocale { final String keyboardLayoutSet = keyboardLayoutSetMap[i + 1]; sLocaleAndExtraValueToKeyboardLayoutSetMap.put(key, keyboardLayoutSet); } + + sInitialized = true; } public static String[] getPredefinedKeyboardLayoutSet() { From 69aef47e23828720a394e633c8271e23ac734e1b Mon Sep 17 00:00:00 2001 From: Satoshi Kataoka Date: Mon, 9 Jul 2012 17:27:45 +0900 Subject: [PATCH 03/68] Separate string resource of IME name Change-Id: Ib4afefac0e87c814c9e54cb65e78ee584c3f954c --- java/res/values/strings-appname.xml | 33 +++++++++++++++++++++++++++++ java/res/values/strings.xml | 9 -------- 2 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 java/res/values/strings-appname.xml diff --git a/java/res/values/strings-appname.xml b/java/res/values/strings-appname.xml new file mode 100644 index 000000000..5c1793c40 --- /dev/null +++ b/java/res/values/strings-appname.xml @@ -0,0 +1,33 @@ + + + + + + Android Keyboard + + + Android spell checker + + + Android keyboard settings + + + Spell checking settings + diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 6c66a4844..5fd4af4f4 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -18,25 +18,16 @@ */ --> - - Android keyboard Android keyboard (AOSP) - - Android keyboard settings Input options Research Log Commands - - Android spell checker Android spell checker (AOSP) - - Spell checking settings - Look up contact names From 59205dd270c0fa24626738af1430c38cd45e3383 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Mon, 9 Jul 2012 13:56:48 -0700 Subject: [PATCH 04/68] Import translations. DO NOT MERGE Change-Id: I48fd690e9368a6637c7fa93c15b6ecadcbe47ce8 Auto-generated-cl: translation import --- java/res/values-af/strings.xml | 6 +----- java/res/values-am/strings.xml | 4 ---- java/res/values-ar/strings.xml | 4 ---- java/res/values-be/strings.xml | 4 ---- java/res/values-bg/strings.xml | 4 ---- java/res/values-ca/strings.xml | 4 ---- java/res/values-cs/strings.xml | 4 ---- java/res/values-da/strings.xml | 4 ---- java/res/values-de/strings.xml | 4 ---- java/res/values-el/strings.xml | 4 ---- java/res/values-en-rGB/strings.xml | 4 ---- java/res/values-es-rUS/strings.xml | 4 ---- java/res/values-es/strings.xml | 4 ---- java/res/values-et/strings.xml | 4 ---- java/res/values-fa/strings.xml | 4 ---- java/res/values-fi/strings.xml | 4 ---- java/res/values-fr/strings.xml | 4 ---- java/res/values-hi/strings.xml | 6 +----- java/res/values-hr/strings.xml | 4 ---- java/res/values-hu/strings.xml | 4 ---- java/res/values-in/strings.xml | 4 ---- java/res/values-it/strings.xml | 4 ---- java/res/values-iw/strings.xml | 4 ---- java/res/values-ja/strings.xml | 4 ---- java/res/values-ko/strings.xml | 4 ---- java/res/values-lt/strings.xml | 4 ---- java/res/values-lv/strings.xml | 4 ---- java/res/values-ms/strings.xml | 4 ---- java/res/values-nb/strings.xml | 4 ---- java/res/values-nl/strings.xml | 4 ---- java/res/values-pl/strings.xml | 4 ---- java/res/values-pt-rPT/strings.xml | 4 ---- java/res/values-pt/strings.xml | 4 ---- java/res/values-rm/strings.xml | 6 ------ java/res/values-ro/strings.xml | 4 ---- java/res/values-ru/strings.xml | 4 ---- java/res/values-sk/strings.xml | 4 ---- java/res/values-sl/strings.xml | 4 ---- java/res/values-sr/strings.xml | 4 ---- java/res/values-sv/strings.xml | 4 ---- java/res/values-sw/strings.xml | 4 ---- java/res/values-th/strings.xml | 4 ---- java/res/values-tl/strings.xml | 4 ---- java/res/values-tr/strings.xml | 4 ---- java/res/values-uk/strings.xml | 4 ---- java/res/values-vi/strings.xml | 4 ---- java/res/values-zh-rCN/strings.xml | 4 ---- java/res/values-zh-rTW/strings.xml | 6 +----- java/res/values-zu/strings.xml | 4 ---- 49 files changed, 3 insertions(+), 201 deletions(-) diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml index 273832813..30d5f5da1 100644 --- a/java/res/values-af/strings.xml +++ b/java/res/values-af/strings.xml @@ -20,14 +20,10 @@ - "Android-sleutelbord" "Android-sleutelbord (AOSP)" - "Android-sleutelbordinstellings" "Invoeropsies" "Navorsing-loglêerbevele" - "Android-speltoetser" "Android-speltoetser (AOSP)" - "Speltoetser se instellings" "Soek kontakname op" "Speltoetser gebruik inskrywings uit jou kontaklys" "Vibreer met sleuteldruk" @@ -60,7 +56,7 @@ "Matig" "Aggressief" "Baie aggressief" - "Volgende woordvoorstelle" + "Stel volgende woord voor" "Gebaseer op vorige woord" "%s : Gestoor" "Gaan" diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml index a6373ccb6..69493b750 100644 --- a/java/res/values-am/strings.xml +++ b/java/res/values-am/strings.xml @@ -20,14 +20,10 @@ - "የAndroid ቁልፍሰሌዳ" "የAndroid ቁልፍ ሰሌዳ (AOSP)" - "የAndroid ቁልፍሰሌዳ ቅንብሮች" "ግቤት አማራጮች" "የጥናት የምዝግብ ማስታወሻ ትዕዛዞች" - "Android የፊደል ማረሚያ" "Android የፊደል ማረሚያ (AOSP)" - "የፊደል አራሚ ቅንብሮች" "የእውቅያ ስሞችን ተመልከት" "ፊደል አራሚ ከእውቅያ ዝርዝርህ የገቡትን ይጠቀማል" "በቁልፍመጫንጊዜ አንዝር" diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml index 9e6f1ea51..eb7e30604 100644 --- a/java/res/values-ar/strings.xml +++ b/java/res/values-ar/strings.xml @@ -20,14 +20,10 @@ - "لوحة مفاتيح Android" "لوحة مفاتيح Android ‏(AOSP)" - "إعدادات لوحة مفاتيح Android" "خيارات الإرسال" "أوامر سجلات البحث" - "التدقيق الإملائي في Android" "التدقيق الإملائي في Android‏ (AOSP)" - "إعدادات التدقيق الإملائي" "بحث في أسماء جهات الاتصال" "يستخدم المدقق الإملائي إدخالات من قائمة جهات الاتصال" "اهتزاز عند ضغط مفتاح" diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml index fb371f4c3..d67ddc034 100644 --- a/java/res/values-be/strings.xml +++ b/java/res/values-be/strings.xml @@ -20,14 +20,10 @@ - "Клавіятура Android" "Клавіятура Android (AOSP)" - "Налады клавіятуры Android" "Параметры ўводу" "Каманды гiсторыя даследаванняў" - "Iнструмент праверкi правапiсу для Android" "Iнструмент праверкi правапiсу для Android (AOSP)" - "Налады праверкі арфаграфіі" "Шукаць імёны кантактаў" "Модуль праверкі правапісу выкарыстоўвае запісы са спісу кантактаў" "Вібрацыя пры націску клавіш" diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml index 94945c03b..5cd6fcaa7 100644 --- a/java/res/values-bg/strings.xml +++ b/java/res/values-bg/strings.xml @@ -20,14 +20,10 @@ - "Клавиатура на Android" "Клавиатура на Android (AOSP)" - "Настройки на клавиатурата на Android" "Опции за въвеждане" "Команди за рег. файл за проучвания" - "Програма за правописна проверка за Android" "Програма за правописна проверка за Android (AOSP)" - "Настройки за проверка на правописа" "Търсене на имена" "За проверка на правописа се ползват записи от списъка с контакти" "Да вибрира при натискане на клавиш" diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml index b6fb56093..01cc422c4 100644 --- a/java/res/values-ca/strings.xml +++ b/java/res/values-ca/strings.xml @@ -20,14 +20,10 @@ - "Teclat Android" "Teclat d\'Android (AOSP)" - "Configuració del teclat d\'Android" "Opcions d\'entrada" "Recerca d\'ordres de reg." - "Corrector ortogràfic d\'Android" "Corrector ortogràfic d\'Android (AOSP)" - "Configuració de la correcció ortogràfica" "Cerca noms de contactes" "El corrector ortogràfic utilitza entrades de la llista de cont." "Vibra en prémer tecles" diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml index 5818d5c6f..9764ce501 100644 --- a/java/res/values-cs/strings.xml +++ b/java/res/values-cs/strings.xml @@ -20,14 +20,10 @@ - "Klávesnice Android" "Klávesnice Android (AOSP)" - "Nastavení klávesnice Android" "Možnosti zadávání textu a dat" "Příkazy vývoj. protokolu" - "Kontrola pravopisu Android" "Kontrola pravopisu Android (AOSP)" - "Nastavení kontroly pravopisu" "Vyhledat kontakty" "Kontrola pravopisu používá záznamy z vašeho seznamu kontaktů." "Při stisku klávesy vibrovat" diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml index dc1df0772..e669f7168 100644 --- a/java/res/values-da/strings.xml +++ b/java/res/values-da/strings.xml @@ -20,14 +20,10 @@ - "Android-tastatur" "Android-tastatur (AOSP)" - "Android-tastatur-indstillinger" "Indstillinger for input" "Forskningslogkommandoer" - "Android-stavekontrol" "Android-stavekontrol (AOSP)" - "Indstillinger for stavekontrol" "Slå kontaktnavne op" "Stavekontrollen bruger poster fra listen over kontaktpersoner" "Vibration ved tastetryk" diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml index b24952534..827ff602b 100644 --- a/java/res/values-de/strings.xml +++ b/java/res/values-de/strings.xml @@ -20,14 +20,10 @@ - "Android-Tastatur" "Android-Tastatur (AOSP)" - "Android-Tastatureinstellungen" "Eingabeoptionen" "Forschungsprotokollbefehle" - "Android-Rechtschreibprüfung" "Android-Rechtschreibprüfung (AOSP)" - "Einstellungen für Rechtschreibprüfung" "Kontaktnamen prüfen" "Rechtschreibprüfung verwendet Einträge aus Ihrer Kontaktliste." "Bei Tastendruck vibrieren" diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml index d9e1aa8c4..563e18124 100644 --- a/java/res/values-el/strings.xml +++ b/java/res/values-el/strings.xml @@ -20,14 +20,10 @@ - "Πληκτρολόγιο Android" "Πληκτρολόγιο Android (AOSP)" - "Ρυθμίσεις πληκτρολογίου Android" "Επιλογές εισόδου" "Έρευνα εντολών καταγραφής" - "Ορθογραφικός έλεγχος Android" "Ορθογραφικός έλεγχος Android (AOSP)" - "Ρυθμίσεις ορθογραφικού ελέγχου" "Αναζήτηση ονομάτων επαφών" "Ο ορθογρ. έλεγχος χρησιμοπ. καταχωρίσεις από τη λίστα επαφών σας" "Δόνηση κατά το πάτημα πλήκτρων" diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml index 7241e5df0..513fae4c5 100644 --- a/java/res/values-en-rGB/strings.xml +++ b/java/res/values-en-rGB/strings.xml @@ -20,14 +20,10 @@ - "Android keyboard" "Android keyboard (AOSP)" - "Android keyboard settings" "Input options" "Research Log Commands" - "Android spell checker" "Android spell checker (AOSP)" - "Spellchecking settings" "Look up contact names" "Spell checker uses entries from your contact list" "Vibrate on key-press" diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml index 01d9912da..3eb32c12a 100644 --- a/java/res/values-es-rUS/strings.xml +++ b/java/res/values-es-rUS/strings.xml @@ -20,14 +20,10 @@ - "Teclado de Android" "Teclado de Android (AOSP)" - "Configuración de teclado de Android" "Opciones de entrada" "Comandos registro invest." - "Corrector ortográfico de Android" "Corrector ortográfico de Android (AOSP)" - "Configuración del corrector ortográfico" "Buscar nombres contactos" "El corrector ortográfico usa entradas de tu lista de contactos." "Vibrar al pulsar teclas" diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml index f97d93ddf..1eee5d970 100644 --- a/java/res/values-es/strings.xml +++ b/java/res/values-es/strings.xml @@ -20,14 +20,10 @@ - "Teclado de Android" "Teclado Android (AOSP)" - "Ajustes del teclado de Android" "Opciones entrada texto" "Comandos registro investigación" - "Corrector de Android" "Corrector de Android (AOSP)" - "Ajustes del corrector ortográfico" "Nombres de contactos" "Añadir nombres de tu lista de contactos al corrector" "Vibrar al pulsar tecla" diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml index e4f0f2f58..a68e5656f 100644 --- a/java/res/values-et/strings.xml +++ b/java/res/values-et/strings.xml @@ -20,14 +20,10 @@ - "Androidi klaviatuur" "Android-klaviatuur (AOSP)" - "Androidi klaviatuuriseaded" "Sisestusvalikud" "Uuringulogi käsud" - "Androidi õigekirjakontroll" "Androidi õigekirjakontroll (AOSP)" - "Õigekirjakontrolli seaded" "Kontakti nimede kontroll." "Õigekirjakontroll kasutab teie kontaktisikute loendi sissekandeid" "Vibreeri klahvivajutusel" diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml index 4ad5025eb..d61d7eb62 100644 --- a/java/res/values-fa/strings.xml +++ b/java/res/values-fa/strings.xml @@ -20,14 +20,10 @@ - "صفحه کلید Android" "صفحه کلید (Android (AOSP" - "تنظیمات صفحه کلید Android" "گزینه های ورودی" "فرمان‌های گزارش‌گیری پژوهش" - "غلط‌گیر املای Android" "غلط‌گیر املای Android (AOSP)" - "تنظیمات غلط گیری املایی" "جستجوی نام مخاطبین" "غلط‌گیر املا از ورودی‌های لیست مخاطبین شما استفاده میکند" "لرزش با فشار کلید" diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml index 3ca48be5d..c036142a6 100644 --- a/java/res/values-fi/strings.xml +++ b/java/res/values-fi/strings.xml @@ -20,14 +20,10 @@ - "Android-näppäimistö" "Android-näppäimistö (AOSP)" - "Android-näppäimistön asetukset" "Syöttövalinnat" "Tutkimuslokin komennot" - "Android-oikoluku" "Android-oikoluku (AOSP)" - "Oikoluvun asetukset" "Hae kontaktien nimiä" "Oikeinkirjoituksen tarkistus käyttää kontaktiluettelosi tietoja." "Käytä värinää näppäimiä painettaessa" diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml index e457480c1..b5b1eac64 100644 --- a/java/res/values-fr/strings.xml +++ b/java/res/values-fr/strings.xml @@ -20,14 +20,10 @@ - "Clavier Android" "Clavier Android (AOSP)" - "Paramètres du clavier Android" "Options de saisie" "Commandes journaux rech." - "Correcteur orthographique Android" "Correcteur orthographique Android (AOSP)" - "Paramètre du correcteur orthographique" "Rechercher noms contacts" "Correcteur orthographique utilise entrées de liste de contacts." "Vibrer à chaque touche" diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml index 0b76cfde6..a567faf57 100644 --- a/java/res/values-hi/strings.xml +++ b/java/res/values-hi/strings.xml @@ -20,14 +20,10 @@ - "Android कीबोर्ड" "Android कीबोर्ड (AOSP)" - "Android कीबोर्ड सेटिंग" "इनपुट विकल्‍प" "लॉग आदेशों का शोध करें" - "Android वर्तनी परीक्षक" "Android वर्तनी परीक्षक (AOSP)" - "वर्तनी जांच सेटिंग" "संपर्क नामों को खोजें" "वर्तनी परीक्षक आपकी संपर्क सूची की प्रविष्टियों का उपयोग करता है" "कुंजी दबाने पर कंपन करता है" @@ -61,7 +57,7 @@ "तीव्र" "बहुत तीव्र" "अगले शब्द सुझाव" - "पिछले शब्दों के आधार पर" + "पिछले शब्द के आधार पर" "%s: सहेजा गया" "जाएं" "अगला" diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml index c8649e951..76f6edfa8 100644 --- a/java/res/values-hr/strings.xml +++ b/java/res/values-hr/strings.xml @@ -20,14 +20,10 @@ - "Android tipkovnica" "Android tipkovnica (AOSP)" - "Postavke tipkovnice za Android" "Opcije ulaza" "Istraživanje naredbi dnevnika" - "Androidova provjera pravopisa" "Androidova provjera pravopisa (AOSP)" - "Postavke provjere pravopisa" "Potražite imena kontakata" "Provjera pravopisa upotrebljava unose iz vašeg popisa kontakata" "Vibracija pri pritisku na tipku" diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml index d2a38cb24..4bf9f4280 100644 --- a/java/res/values-hu/strings.xml +++ b/java/res/values-hu/strings.xml @@ -20,14 +20,10 @@ - "Android-billentyűzet" "Android-billentyűzet (AOSP)" - "Android billentyűzetbeállítások" "Beviteli beállítások" "Naplózási parancsok" - "Androidos helyesírás-ellenőrző" "Androidos helyesírás-ellenőrző (AOSP)" - "Helyesírás-ellenőrzés beállításai" "Névjegyek keresése" "A helyesírás-ellenőrző használja a névjegyek bejegyzéseit" "Rezgés billentyű megnyomása esetén" diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml index 2d10e6274..ee4651c9e 100644 --- a/java/res/values-in/strings.xml +++ b/java/res/values-in/strings.xml @@ -20,14 +20,10 @@ - "Keyboard Android" "Keyboard Android (AOSP)" - "Setelan keyboard Android" "Opsi masukan" "Riset Perintah Log" - "Pemeriksa ejaan Android" "Pemeriksa ejaan Android (AOSP)" - "Setelan pemeriksaan ejaan" "Cari nama kontak" "Pemeriksa ejaan menggunakan entri dari daftar kontak Anda" "Getar jika tombol ditekan" diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml index c3a2b5135..e52e250d2 100644 --- a/java/res/values-it/strings.xml +++ b/java/res/values-it/strings.xml @@ -20,14 +20,10 @@ - "Tastiera Android" "Tastiera Android (AOSP)" - "Impostazioni tastiera Android" "Opzioni inserimento" "Ricerca comandi di log" - "Controllo ortografico Android" "Controllo ortografico Android (AOSP)" - "Impostazioni di controllo ortografico" "Cerca in nomi contatti" "La funzione di controllo ortografico usa voci dell\'elenco contatti" "Vibrazione tasti" diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml index 3859993f9..662f2f462 100644 --- a/java/res/values-iw/strings.xml +++ b/java/res/values-iw/strings.xml @@ -20,14 +20,10 @@ - "מקלדת Android" "מקלדת Android ‏(AOSP)" - "הגדרות מקלדת של Android" "אפשרויות קלט" "פקודות יומן מחקר" - "בודק האיות של Android" "בודק האיות של Android ‏(AOSP)" - "הגדרות בדיקת איות" "חפש שמות של אנשי קשר" "בודק האיות משתמש בערכים מרשימת אנשי הקשר שלך" "רטט בלחיצה על מקשים" diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml index f9349f540..050ca66ec 100644 --- a/java/res/values-ja/strings.xml +++ b/java/res/values-ja/strings.xml @@ -20,14 +20,10 @@ - "Androidキーボード" "Androidキーボード(AOSP)" - "Androidキーボードの設定" "入力オプション" "ログコマンドの検索" - "Androidスペルチェッカー" "Androidスペルチェッカー(AOSP)" - "スペルチェックの設定" "連絡先名の検索" "スペルチェッカーでは連絡先リストのエントリを使用します" "キー操作バイブ" diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml index cd8cb6b51..516c8c382 100644 --- a/java/res/values-ko/strings.xml +++ b/java/res/values-ko/strings.xml @@ -20,14 +20,10 @@ - "Android 키보드" "Android 키보드(AOSP)" - "Android 키보드 설정" "입력 옵션" "로그 명령 탐색" - "Android 맞춤법 검사기" "Android 맞춤법 검사기(AOSP)" - "맞춤법 검사 설정" "연락처 이름 조회" "맞춤법 검사기가 주소록의 항목을 사용합니다." "키를 누를 때 진동 발생" diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml index 2f6abc856..08d66595b 100644 --- a/java/res/values-lt/strings.xml +++ b/java/res/values-lt/strings.xml @@ -20,14 +20,10 @@ - "„Android“ klaviatūra" "„Android“ klaviatūra (AOSP)" - "„Android“ klaviatūros nustatymai" "Įvesties parinktys" "Tyrinėti žurnalo komandas" - "„Android“ rašybos tikrinimo programa" "„Android“ rašybos tikrinimo programa (AOSP)" - "Rašybos tikrinimo nustatymai" "Kontaktų vardų paieška" "Rašybos tikrinimo progr. naudoja įrašus, esančius kontaktų sąraše" "Vibruoti, kai paspaudžiami klavišai" diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml index 66dd1473e..3685cccbe 100644 --- a/java/res/values-lv/strings.xml +++ b/java/res/values-lv/strings.xml @@ -20,14 +20,10 @@ - "Android tastatūra" "Android tastatūra (AOSP)" - "Android tastatūras iestatījumi" "Ievades opcijas" "Izpētes žurnāla komandas" - "Android pareizrakstības pārbaudītājs" "Android pareizrakstības pārbaudītājs (AOSP)" - "Pareizrakstības pārbaudes iestatījumi" "Meklēt kontaktp. vārdus" "Pareizrakst. pārbaudītājs lieto ierakstus no kontaktp. saraksta." "Vibrēt, nospiežot taustiņu" diff --git a/java/res/values-ms/strings.xml b/java/res/values-ms/strings.xml index 53c902039..59fec8845 100644 --- a/java/res/values-ms/strings.xml +++ b/java/res/values-ms/strings.xml @@ -20,14 +20,10 @@ - "Papan kekunci Android" "Papan kekunci Android (AOSP)" - "Tetapan papan kekunci Android" "Pilihan input" "Arahan Log Penyelidikan" - "Penyemak ejaan Android" "Penyemak ejaan Android (AOSP)" - "Tetapan penyemakan ejaan" "Cari nama kenalan" "Penyemak ejaan menggunakan entri dari senarai kenalan anda" "Getar pada tekanan kekunci" diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml index bdde36ae8..2f4194ac0 100644 --- a/java/res/values-nb/strings.xml +++ b/java/res/values-nb/strings.xml @@ -20,14 +20,10 @@ - "Skjermtastatur" "Android-tastatur (AOSP)" - "Innstillinger for skjermtastatur" "Inndataalternativer" "Kommandoer for undersøkelseslogging" - "Android-stavekontroll" "Android-stavekontroll (AOSP)" - "Innstillinger for stavekontroll" "Slå opp kontaktnavn" "Stavekontrollen bruker oppføringer fra kontaktlisten din" "Vibrer ved tastetrykk" diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml index 9624e176e..c42cd100b 100644 --- a/java/res/values-nl/strings.xml +++ b/java/res/values-nl/strings.xml @@ -20,14 +20,10 @@ - "Android-toetsenbord" "Android-toetsenbord (AOSP)" - "Instellingen voor Android-toetsenbord" "Invoeropties" "Opdrachten in onderzoekslogbestand" - "Spellingcontrole van Android" "Spellingcontrole van Android (AOSP)" - "Instellingen voor spellingcontrole" "Contactnamen opzoeken" "De spellingcontrole gebruikt items uit uw contactenlijst" "Trillen bij toetsaanslag" diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml index c8a72b77a..7c86dbfdc 100644 --- a/java/res/values-pl/strings.xml +++ b/java/res/values-pl/strings.xml @@ -20,14 +20,10 @@ - "Klawiatura Android" "Klawiatura Androida (AOSP)" - "Ustawienia klawiatury Android" "Opcje wprowadzania" "Polecenia dziennika badań" - "Słownik Androida" "Sprawdzanie pisowni na Androidzie (AOSP)" - "Ustawienia sprawdzania pisowni" "Przeszukaj kontakty" "Sprawdzanie pisowni bierze pod uwagę wpisy z listy kontaktów." "Wibracja przy naciśnięciu" diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml index cef2ce75b..06d7a78d6 100644 --- a/java/res/values-pt-rPT/strings.xml +++ b/java/res/values-pt-rPT/strings.xml @@ -20,14 +20,10 @@ - "Teclado do Android" "Teclado Android (AOSP)" - "Definições de teclado do Android" "Opções de introdução" "Comandos de Reg. Invest." - "Verificador ortográfico do Android" "Verificador ortográfico do Android (AOSP)" - "Definições da verificação ortográfica" "Procurar nomes de contac." "O corretor ortográfico utiliza entradas da sua lista de contactos" "Vibrar ao primir as teclas" diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml index d092879cf..5b7c60fca 100644 --- a/java/res/values-pt/strings.xml +++ b/java/res/values-pt/strings.xml @@ -20,14 +20,10 @@ - "Teclado Android" "Teclado Android (AOSP)" - "Configurações de teclado Android" "Opções de entrada" "Pesq. comandos de reg." - "Corretor ortográfico do Android" "Corretor ortográfico do Android (AOSP)" - "Configurações de verificação ortográfica" "Buscar nomes de contatos" "O corretor ortográfico usa entradas de sua lista de contatos" "Vibrar ao tocar a tecla" diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml index b39691ceb..41be654fe 100644 --- a/java/res/values-rm/strings.xml +++ b/java/res/values-rm/strings.xml @@ -20,20 +20,14 @@ - "Tastatura Android" - "Parameters da la tastatura Android" - - - - diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml index 08275665c..338024c5a 100644 --- a/java/res/values-ro/strings.xml +++ b/java/res/values-ro/strings.xml @@ -20,14 +20,10 @@ - "Tastatură Android" "Tastatură Android (AOSP)" - "Setările tastaturii Android" "Opţiuni de introducere text" "Comenzi jurnal cercetare" - "Verificator ortografic Android" "Verificator ortografic Android (AOSP)" - "Setări de verificare ortografică" "Verificare nume în agendă" "Verificatorul ortografic utilizează intrări din lista de contacte" "Vibrare la apăsarea tastei" diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml index 77ffe7b55..4dd5b31a0 100644 --- a/java/res/values-ru/strings.xml +++ b/java/res/values-ru/strings.xml @@ -20,14 +20,10 @@ - "Клавиатура Android" "Клавиатура Android (AOSP)" - "Клавиатура Android" "Настройки" "Все команды" - "Проверка правописания Android" "Проверка правописания Android (AOSP)" - "Настройка проверки правописания" "Поиск контактов" "Обращаться к списку контактов при проверке правописания" "Виброотклик клавиш" diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml index 2b31bd858..1dced2099 100644 --- a/java/res/values-sk/strings.xml +++ b/java/res/values-sk/strings.xml @@ -20,14 +20,10 @@ - "Klávesnica Android" "Klávesnica Android (AOSP)" - "Nastavenia klávesnice Android" "Možnosti zadávania textu a údajov" "Príkazy denníka výskumu" - "Kontrola pravopisu Android" "Kontrola pravopisu Android (AOSP)" - "Nastavenia kontroly pravopisu" "Vyhľadať kontakty" "Kontrola pravopisu používa záznamy z vášho zoznamu kontaktov" "Pri stlačení klávesu vibrovať" diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml index 05e20b04c..036802d5b 100644 --- a/java/res/values-sl/strings.xml +++ b/java/res/values-sl/strings.xml @@ -20,14 +20,10 @@ - "Tipkovnica Android" "Tipkovnica Android (AOSP)" - "Nastavitve tipkovnice Android" "Možnosti vnosa" "Ukazi za dnevnik raziskav" - "Črkovalnik za Android" "Črkovalnik za Android (AOSP)" - "Nastavitve preverjanja črkovanja" "Iskanje imen stikov" "Črkovalnik uporablja vnose s seznama stikov" "Vibriranje ob pritisku tipke" diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml index 43fe7003d..92f275f2e 100644 --- a/java/res/values-sr/strings.xml +++ b/java/res/values-sr/strings.xml @@ -20,14 +20,10 @@ - "Android тастатура" "Android тастатура (AOSP)" - "Подешавања Android тастатуре" "Опције уноса" "Команде евиденције истраживања" - "Android провера правописа" "Android провера правописа (AOSP)" - "Подешавања провере правописа" "Потражи имена контаката" "Контролор правописа користи уносе са листе контаката" "Вибрирај на притисак тастера" diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml index f24446976..d460b5ba1 100644 --- a/java/res/values-sv/strings.xml +++ b/java/res/values-sv/strings.xml @@ -20,14 +20,10 @@ - "Androids tangentbord" "Androids tangentbord (AOSP)" - "Inställningar för Androids tangentbord" "Inmatningsalternativ" "Loggkommandon" - "Stavningskontroll i Android" "Stavningskontroll i Android (AOSP)" - "Inställningar för stavningskontroll" "Sök namn på kontakter" "I stavningskontrollen används poster från kontaktlistan" "Vibrera vid tangenttryck" diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml index 9cec8679d..9727fda8b 100644 --- a/java/res/values-sw/strings.xml +++ b/java/res/values-sw/strings.xml @@ -20,14 +20,10 @@ - "Kibodi ya Android" "Kicharazio cha Android (AOSP)" - "Mipangilio ya kibodi ya Android" "Chaguo za uingizaji" "Amri za Kumbukumbu za Utafiti" - "Kikagua tahajia cha Android" "Kikagua tahajia cha Android (AOSP)" - "Mipangilio ya kukagua sarufi" "Angalia majina ya wasiliani" "Kikagua tahajia hutumia ingizo kutoka kwa orodha yako ya anwani" "Tetema unabofya kitufe" diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml index 174ee4507..8c365fe95 100644 --- a/java/res/values-th/strings.xml +++ b/java/res/values-th/strings.xml @@ -20,14 +20,10 @@ - "แป้นพิมพ์ Android" "Android keyboard (AOSP)" - "การตั้งค่าแป้นพิมพ์ Android" "ตัวเลือกการป้อนข้อมูล" "คำสั่งบันทึกการวิจัย" - "แอนดรอยด์ตรวจสอบการสะกด" "แอนดรอยด์ตรวจสอบการสะกด (AOSP)" - "การตั้งค่าการตรวจสอบการสะกด" "ค้นหารายชื่อติดต่อ" "เครื่องมือตรวจการสะกดใช้รายการจากรายชื่อติดต่อของคุณ" "สั่นเมื่อกดปุ่ม" diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml index 25801ca7d..832dc2bb7 100644 --- a/java/res/values-tl/strings.xml +++ b/java/res/values-tl/strings.xml @@ -20,14 +20,10 @@ - "Android keyboard" "Android keyboard (AOSP)" - "Mga setting ng Android keyboard" "Mga pagpipilian sa input" "Cmmnd sa Log ng Pnnliksik" - "Pang-check ng pagbabaybay ng Android" "Pang-check ng pagbabaybay ng Android (AOSP)" - "Mga setting ng pang-check ng pagbabaybay" "Maghanap pangalan contact" "Gumagamit pang-check pagbabaybay entry sa iyong listahan contact" "Mag-vibrate sa keypress" diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml index 190736e82..abfa73656 100644 --- a/java/res/values-tr/strings.xml +++ b/java/res/values-tr/strings.xml @@ -20,14 +20,10 @@ - "Android klavyesi" "Android klavye (AOSP)" - "Android klavye ayarları" "Giriş seçenekleri" "Araştırma Günlüğü Komutları" - "Android yazım denetleyici" "Android yazım denetleyici (AOSP)" - "Yazım denetimi ayarları" "Kişi adlarını denetle" "Yazım denetleyici, kişi listenizdeki girişleri kullanır" "Tuşa basıldığında titret" diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml index 04a8a638e..9e4da5b47 100644 --- a/java/res/values-uk/strings.xml +++ b/java/res/values-uk/strings.xml @@ -20,14 +20,10 @@ - "Клавіатура Android" "Клавіатура Android (AOSP)" - "Налашт-ня клавіат. Android" "Парам. введення" "Команди журналу дослідж." - "Засіб перевірки орфографії Android" "Засіб перевірки орфографії Android (AOSP)" - "Налаштування перевірки орфографії" "Шукати імена контактів" "Програма перевірки правопису використ. записи зі списку контактів" "Вібр. при натисканні клавіш" diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml index c9dc0e644..bf096c51f 100644 --- a/java/res/values-vi/strings.xml +++ b/java/res/values-vi/strings.xml @@ -20,14 +20,10 @@ - "Bàn phím Android" "Bàn phím Android (AOSP)" - "Cài đặt bàn phím Android" "Tùy chọn nhập" "Lệnh ghi nhật ký cho nghiên cứu" - "Trình kiểm tra chính tả Android" "Trình kiểm tra chính tả Android (AOSP)" - "Cài đặt kiểm tra chính tả" "Tra cứu tên liên hệ" "Trình kiểm tra chính tả sử dụng các mục nhập từ danh sách liên hệ của bạn" "Rung khi nhấn phím" diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml index 9f5e4633d..a95d32ac0 100644 --- a/java/res/values-zh-rCN/strings.xml +++ b/java/res/values-zh-rCN/strings.xml @@ -20,14 +20,10 @@ - "Android 键盘" "Android 键盘 (AOSP)" - "Android 键盘设置" "输入选项" "研究记录命令" - "Android 拼写检查工具" "Android 拼写检查工具 (AOSP)" - "拼写检查设置" "查找联系人姓名" "拼写检查工具会使用您的联系人列表中的条目" "按键振动" diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml index 20592dc44..b8bb3e5d7 100644 --- a/java/res/values-zh-rTW/strings.xml +++ b/java/res/values-zh-rTW/strings.xml @@ -20,14 +20,10 @@ - "Android 鍵盤" "Android 鍵盤 (AOSP)" - "Android 鍵盤設定" "輸入選項" "研究紀錄指令" - "Android 拼字檢查" "Android 拼字檢查 (AOSP)" - "拼字檢查設定" "查詢聯絡人姓名" "拼字檢查程式使用您的聯絡人清單項目" "按鍵時震動" @@ -61,7 +57,7 @@ "更正範圍大" "更正範圍極大" "下一個字詞建議" - "根據先前字詞產生" + "根據上一個字詞產生" "%s:已儲存" "開始" "繼續" diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml index 35cb99cf8..6984631d3 100644 --- a/java/res/values-zu/strings.xml +++ b/java/res/values-zu/strings.xml @@ -20,14 +20,10 @@ - "Ikhibhodi ye-Android" "Ikhibhodi ye-Android (AOSP)" - "Izilungiselelo zekhibhodi ye-Android" "Okukhethwa kukho kokungenayo" "Imiyalo yefayela lokungena lokucwaninga" - "Isihloli sokupela se-Android" "Isihloli sokupela se-Android (AOSP)" - "Izilungiselelo zokuhlola ukupela" "Bheka amagama woxhumana nabo" "Isihloli sokupela sisebenzisa okungenayo kusuka kuhlu lalabo oxhumana nabo" "Dlidlizelisa ngokucindezela inkinobho" From 0493bb2f101540265ccd49754ed1ecc5dcb7b667 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Mon, 9 Jul 2012 17:47:31 -0700 Subject: [PATCH 05/68] Use TARGET_BUILD_APPS to distinguish It's in a full build or just an unbundled build. Bug: 6790620 Change-Id: Ifa2df86462747acb8b561ebab879e03b1201b4f7 --- native/jni/Android.mk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/native/jni/Android.mk b/native/jni/Android.mk index a7486ae90..613540993 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -68,9 +68,9 @@ endif # FLAG_DO_PROFILE LOCAL_MODULE := libjni_latinime_common_static LOCAL_MODULE_TAGS := optional -ifdef ANDROID_BUILD_TOP # In the platform build system +ifndef TARGET_BUILD_APPS # A full system image build include external/stlport/libstlport.mk -else # In the unbundled build system +else # An unbundled build LOCAL_NDK_VERSION := 7 LOCAL_SDK_VERSION := 14 LOCAL_NDK_STL_VARIANT := stlport_static @@ -96,9 +96,9 @@ endif # FLAG_DO_PROFILE LOCAL_MODULE := libjni_latinime LOCAL_MODULE_TAGS := optional -ifdef ANDROID_BUILD_TOP # In the platform build system +ifndef TARGET_BUILD_APPS # A full system image build LOCAL_STATIC_LIBRARIES += libstlport_static -else # In the unbundled build system +else # An unbundled build LOCAL_NDK_VERSION := 7 LOCAL_SDK_VERSION := 14 LOCAL_NDK_STL_VARIANT := stlport_static From ea92b7b987abbaadf5aa2cccf96e8fab4f3ab612 Mon Sep 17 00:00:00 2001 From: Ken Wakasa Date: Tue, 10 Jul 2012 09:19:07 +0900 Subject: [PATCH 06/68] Avoid LatinIME crash bug: 6790620 Change-Id: I6fd271c6f79790cfb9d875b052854eab60a30b7f --- native/jni/Android.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/native/jni/Android.mk b/native/jni/Android.mk index 613540993..54f61d90d 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -68,6 +68,7 @@ endif # FLAG_DO_PROFILE LOCAL_MODULE := libjni_latinime_common_static LOCAL_MODULE_TAGS := optional +# TODO: Remove this conditional block once we have no issues with building against NDK ifndef TARGET_BUILD_APPS # A full system image build include external/stlport/libstlport.mk else # An unbundled build @@ -96,6 +97,7 @@ endif # FLAG_DO_PROFILE LOCAL_MODULE := libjni_latinime LOCAL_MODULE_TAGS := optional +# TODO: Remove this conditional block once we have no issues with building against NDK ifndef TARGET_BUILD_APPS # A full system image build LOCAL_STATIC_LIBRARIES += libstlport_static else # An unbundled build From 2ad6d12a30cc9f8189936431651dc543db726cfe Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Tue, 10 Jul 2012 10:47:44 +0900 Subject: [PATCH 07/68] A little optimization of InputPointers.copy Change-Id: Id83b34e076ef91e06d7c1dd2b3ee7bb64d01b8cb --- java/proguard.flags | 4 + .../inputmethod/latin/InputPointers.java | 13 +- .../inputmethod/latin/InputPointersTests.java | 173 ++++++++++++++++++ 3 files changed, 183 insertions(+), 7 deletions(-) create mode 100644 tests/src/com/android/inputmethod/latin/InputPointersTests.java diff --git a/java/proguard.flags b/java/proguard.flags index ca205b927..376a0e06c 100644 --- a/java/proguard.flags +++ b/java/proguard.flags @@ -20,6 +20,10 @@ boolean equalsIgnoreCase(...); } +-keep class com.android.inputmethod.latin.InputPointers { + *; +} + -keep class com.android.inputmethod.latin.spellcheck.SpellCheckerSettingsFragment { *; } diff --git a/java/src/com/android/inputmethod/latin/InputPointers.java b/java/src/com/android/inputmethod/latin/InputPointers.java index 9d77d4e96..cd53bcd13 100644 --- a/java/src/com/android/inputmethod/latin/InputPointers.java +++ b/java/src/com/android/inputmethod/latin/InputPointers.java @@ -16,9 +16,6 @@ package com.android.inputmethod.latin; -import java.util.Arrays; - -// TODO: Add unit test public class InputPointers { private final ScalableIntArray mXCoordinates = new ScalableIntArray(); private final ScalableIntArray mYCoordinates = new ScalableIntArray(); @@ -118,9 +115,10 @@ public class InputPointers { } public void add(int val) { - ensureCapacity(mLength); + final int nextLength = mLength + 1; + ensureCapacity(nextLength); mArray[mLength] = val; - ++mLength; + mLength = nextLength; } public void ensureCapacity(int minimumCapacity) { @@ -132,7 +130,7 @@ public class InputPointers { private void grow(int newCapacity) { final int[] newArray = new int[newCapacity]; - System.arraycopy(mArray, 0, newArray, 0, mLength); + System.arraycopy(mArray, 0, newArray, 0, mArray.length); mArray = newArray; } @@ -150,7 +148,8 @@ public class InputPointers { } public void copy(ScalableIntArray ip) { - mArray = Arrays.copyOf(ip.mArray, ip.mArray.length); + ensureCapacity(ip.mLength); + System.arraycopy(ip.mArray, 0, mArray, 0, ip.mLength); mLength = ip.mLength; } diff --git a/tests/src/com/android/inputmethod/latin/InputPointersTests.java b/tests/src/com/android/inputmethod/latin/InputPointersTests.java new file mode 100644 index 000000000..b60c2df58 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/InputPointersTests.java @@ -0,0 +1,173 @@ +/* + * 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.test.AndroidTestCase; + +public class InputPointersTests extends AndroidTestCase { + public void testNewInstance() { + final InputPointers src = new InputPointers(); + assertEquals("newInstance size", 0, src.getPointerSize()); + assertNotNull("new instance xCoordinates", src.getXCoordinates()); + assertNotNull("new instance yCoordinates", src.getYCoordinates()); + assertNotNull("new instance pointerIds", src.getPointerIds()); + assertNotNull("new instance times", src.getTimes()); + } + + public void testReset() { + final InputPointers src = new InputPointers(); + final int[] xCoordinates = src.getXCoordinates(); + final int[] yCoordinates = src.getXCoordinates(); + final int[] pointerIds = src.getXCoordinates(); + final int[] times = src.getXCoordinates(); + + src.reset(); + assertEquals("after reset size", 0, src.getPointerSize()); + assertNotSame("after reset xCoordinates", xCoordinates, src.getXCoordinates()); + assertNotSame("after reset yCoordinates", yCoordinates, src.getYCoordinates()); + assertNotSame("after reset pointerIds", pointerIds, src.getPointerIds()); + assertNotSame("after reset times", times, src.getTimes()); + } + + public void testAdd() { + final InputPointers src = new InputPointers(); + final int limit = src.getXCoordinates().length * 2 + 10; + for (int i = 0; i < limit; i++) { + src.addPointer(i, i * 2, i * 3, i * 4); + assertEquals("after add " + i, i + 1, src.getPointerSize()); + } + for (int i = 0; i < limit; i++) { + assertEquals("xCoordinates at " + i, i, src.getXCoordinates()[i]); + assertEquals("yCoordinates at " + i, i * 2, src.getYCoordinates()[i]); + assertEquals("pointerIds at " + i, i * 3, src.getPointerIds()[i]); + assertEquals("times at " + i, i * 4, src.getTimes()[i]); + } + } + + public void testAddAt() { + final InputPointers src = new InputPointers(); + final int limit = 1000, step = 100; + for (int i = 0; i < limit; i += step) { + src.addPointer(i, i, i * 2, i * 3, i * 4); + assertEquals("after add at " + i, i + 1, src.getPointerSize()); + } + for (int i = 0; i < limit; i += step) { + assertEquals("xCoordinates at " + i, i, src.getXCoordinates()[i]); + assertEquals("yCoordinates at " + i, i * 2, src.getYCoordinates()[i]); + assertEquals("pointerIds at " + i, i * 3, src.getPointerIds()[i]); + assertEquals("times at " + i, i * 4, src.getTimes()[i]); + } + } + + public void testSet() { + final InputPointers src = new InputPointers(); + final int limit = src.getXCoordinates().length * 2 + 10; + for (int i = 0; i < limit; i++) { + src.addPointer(i, i * 2, i * 3, i * 4); + } + final InputPointers dst = new InputPointers(); + dst.set(src); + assertEquals("after set size", dst.getPointerSize(), src.getPointerSize()); + assertSame("after set xCoordinates", dst.getXCoordinates(), src.getXCoordinates()); + assertSame("after set yCoordinates", dst.getYCoordinates(), src.getYCoordinates()); + assertSame("after set pointerIds", dst.getPointerIds(), src.getPointerIds()); + assertSame("after set times", dst.getTimes(), src.getTimes()); + } + + public void testCopy() { + final InputPointers src = new InputPointers(); + final int limit = 100; + for (int i = 0; i < limit; i++) { + src.addPointer(i, i * 2, i * 3, i * 4); + } + final InputPointers dst = new InputPointers(); + dst.copy(src); + assertEquals("after copy size", dst.getPointerSize(), src.getPointerSize()); + assertNotSame("after copy xCoordinates", dst.getXCoordinates(), src.getXCoordinates()); + assertNotSame("after copy yCoordinates", dst.getYCoordinates(), src.getYCoordinates()); + assertNotSame("after copy pointerIds", dst.getPointerIds(), src.getPointerIds()); + assertNotSame("after copy times", dst.getTimes(), src.getTimes()); + final int size = dst.getPointerSize(); + assertArrayEquals("after copy xCoordinates values", + dst.getXCoordinates(), 0, src.getXCoordinates(), 0, size); + assertArrayEquals("after copy yCoordinates values", + dst.getYCoordinates(), 0, src.getYCoordinates(), 0, size); + assertArrayEquals("after copy pointerIds values", + dst.getPointerIds(), 0, src.getPointerIds(), 0, size); + assertArrayEquals("after copy times values", + dst.getTimes(), 0, src.getTimes(), 0, size); + } + + public void testAppend() { + final InputPointers src = new InputPointers(); + final int limit = 100; + for (int i = 0; i < limit; i++) { + src.addPointer(i, i * 2, i * 3, i * 4); + } + final InputPointers dst = new InputPointers(); + for (int i = 0; i < limit; i++) { + final int value = limit - i; + dst.addPointer(value * 4, value * 3, value * 2, value); + } + final InputPointers dstCopy = new InputPointers(); + dstCopy.copy(dst); + + dst.append(src, 0, 0); + assertEquals("after append zero size", limit, dst.getPointerSize()); + assertArrayEquals("affer append zero xCoordinates", dstCopy.getXCoordinates(), 0, + dst.getXCoordinates(), 0, limit); + assertArrayEquals("affer append zero yCoordinates", dstCopy.getYCoordinates(), 0, + dst.getYCoordinates(), 0, limit); + assertArrayEquals("affer append zero pointerIds", dstCopy.getPointerIds(), 0, + dst.getPointerIds(), 0, limit); + assertArrayEquals("affer append zero times", dstCopy.getTimes(), 0, + dst.getTimes(), 0, limit); + + dst.append(src, 0, src.getPointerSize()); + assertEquals("after append size", limit * 2, dst.getPointerSize() + src.getPointerSize()); + assertArrayEquals("affer append xCoordinates", dstCopy.getXCoordinates(), 0, + dst.getXCoordinates(), 0, limit); + assertArrayEquals("affer append yCoordinates", dstCopy.getYCoordinates(), 0, + dst.getYCoordinates(), 0, limit); + assertArrayEquals("affer append pointerIds", dstCopy.getPointerIds(), 0, + dst.getPointerIds(), 0, limit); + assertArrayEquals("affer append times", dstCopy.getTimes(), 0, + dst.getTimes(), 0, limit); + assertArrayEquals("after append xCoordinates", dst.getXCoordinates(), limit, + src.getXCoordinates(), 0, limit); + assertArrayEquals("after append yCoordinates", dst.getYCoordinates(), limit, + src.getYCoordinates(), 0, limit); + assertArrayEquals("after append pointerIds", dst.getPointerIds(), limit, + src.getPointerIds(), 0, limit); + assertArrayEquals("after append times", dst.getTimes(), limit, + src.getTimes(), 0, limit); + } + + private static void assertArrayEquals(String message, int[] expecteds, int expectedPos, + int[] actuals, int actualPos, int length) { + if (expecteds == null && actuals == null) { + return; + } + if (expecteds == null || actuals == null) { + fail(message + ": expecteds=" + expecteds + " actuals=" + actuals); + } + for (int i = 0; i < length; i++) { + assertEquals(message + ": element at " + i, + expecteds[i + expectedPos], actuals[i + actualPos]); + } + } +} From 1e8fb312bffdda448021679cdb5d5ba18779fade Mon Sep 17 00:00:00 2001 From: Ken Wakasa Date: Tue, 10 Jul 2012 14:10:30 +0900 Subject: [PATCH 08/68] Fix app name case Change-Id: Id568adac98135cffceb111000e80f77928c045ea --- java/res/values/strings-appname.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/res/values/strings-appname.xml b/java/res/values/strings-appname.xml index 5c1793c40..19aaa2513 100644 --- a/java/res/values/strings-appname.xml +++ b/java/res/values/strings-appname.xml @@ -20,7 +20,7 @@ - Android Keyboard + Android keyboard Android spell checker From 32f5384fc955f1e9fa8613ca86081f1bf4ccc421 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 6 Jul 2012 16:14:52 +0900 Subject: [PATCH 09/68] Pull up common code in the consolidated method (A76) Change-Id: I3ebecec37b49e139c243cf9da8bfe491e7ddada1 --- .../android/inputmethod/latin/LatinIME.java | 44 ++++++++----------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 4be2a1799..080172982 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1675,35 +1675,36 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } final String typedWord = mWordComposer.getTypedWord(); - final SuggestedWords suggestions; if (!mWordComposer.isComposingWord() && !mCurrentSettings.mBigramPredictionEnabled) { setPunctuationSuggestions(); return; } - if (!mWordComposer.isComposingWord()) { - suggestions = updateBigramPredictions(); - } else { - suggestions = updateSuggestions(typedWord); + // Get the word on which we should search the bigrams. If we are composing a word, it's + // whatever is *before* the half-committed word in the buffer, hence 2; if we aren't, we + // should just skip whitespace if any, so 1. + // TODO: this is slow (2-way IPC) - we should probably cache this instead. + final CharSequence prevWord = + mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, + mWordComposer.isComposingWord() ? 2 : 1); + SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer, + prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), + mCurrentSettings.mCorrectionEnabled, !mWordComposer.isComposingWord()); + + if (mWordComposer.isComposingWord()) { + suggestedWords = maybeRetrieveOlderSuggestions(typedWord, suggestedWords); } - if (null != suggestions && suggestions.size() > 0) { - showSuggestions(suggestions, typedWord); + if (null != suggestedWords && suggestedWords.size() > 0) { + showSuggestions(suggestedWords, typedWord); } else { clearSuggestions(); } } - private SuggestedWords updateSuggestions(final CharSequence typedWord) { - // TODO: May need a better way of retrieving previous word - final CharSequence prevWord = - mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, 2); - // getSuggestedWords handles gracefully a null value of prevWord - final SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer, - prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), - // !mWordComposer.isComposingWord() is known to be false - mCurrentSettings.mCorrectionEnabled, !mWordComposer.isComposingWord()); - + private SuggestedWords maybeRetrieveOlderSuggestions(final CharSequence typedWord, + final SuggestedWords suggestedWords) { + // TODO: consolidate this into getSuggestedWords // Basically, we update the suggestion strip only when suggestion count > 1. However, // there is an exception: We update the suggestion strip whenever typed word's length // is 1 or typed word is found in dictionary, regardless of suggestion count. Actually, @@ -1891,15 +1892,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen separatorCode, prevWord); } - private SuggestedWords updateBigramPredictions() { - final CharSequence prevWord = - mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, 1); - return mSuggest.getSuggestedWords(mWordComposer, - prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), - // !mWordComposer.isComposingWord() is known to be true - mCurrentSettings.mCorrectionEnabled, !mWordComposer.isComposingWord()); - } - public void setPunctuationSuggestions() { if (mCurrentSettings.mBigramPredictionEnabled) { clearSuggestions(); From c466cd3f9902ef999573a3d07a125f08a8908c5a Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 6 Jul 2012 16:15:36 +0900 Subject: [PATCH 10/68] Move a test (A77) Change-Id: I417bd5f1318696aaa39fee18f3e750ea5c231f6b --- java/src/com/android/inputmethod/latin/LatinIME.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 080172982..7b4aedeb6 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1690,10 +1690,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer, prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), mCurrentSettings.mCorrectionEnabled, !mWordComposer.isComposingWord()); - - if (mWordComposer.isComposingWord()) { - suggestedWords = maybeRetrieveOlderSuggestions(typedWord, suggestedWords); - } + suggestedWords = maybeRetrieveOlderSuggestions(typedWord, suggestedWords); if (null != suggestedWords && suggestedWords.size() > 0) { showSuggestions(suggestedWords, typedWord); @@ -1711,7 +1708,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // in most cases, suggestion count is 1 when typed word's length is 1, but we do always // need to clear the previous state when the user starts typing a word (i.e. typed word's // length == 1). - if (suggestedWords.size() > 1 || typedWord.length() == 1 + if (suggestedWords.size() > 1 || typedWord.length() == 1 || !mWordComposer.isComposingWord() || !suggestedWords.mTypedWordValid || mSuggestionsView.isShowingAddToDictionaryHint()) { return suggestedWords; From 84ed0966417d93b07c4da2b295244b160d223ce9 Mon Sep 17 00:00:00 2001 From: Satoshi Kataoka Date: Tue, 10 Jul 2012 15:33:18 +0900 Subject: [PATCH 11/68] Separate SpellCheckerSession from SpellCheckerService Bug: 6789576 Change-Id: I7c55d36afad7ef6046353b3c9e849a54a6dc83ae --- .../AndroidSpellCheckerService.java | 409 +---------------- .../AndroidSpellCheckerSession.java | 420 ++++++++++++++++++ 2 files changed, 436 insertions(+), 393 deletions(-) create mode 100644 java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 5332c066a..42b05592c 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -20,14 +20,9 @@ import android.content.Intent; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.service.textservice.SpellCheckerService; -import android.text.TextUtils; import android.util.Log; -import android.util.LruCache; -import android.view.textservice.SentenceSuggestionsInfo; import android.view.textservice.SuggestionsInfo; -import android.view.textservice.TextInfo; -import com.android.inputmethod.compat.SuggestionsInfoCompatUtils; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.BinaryDictionary; import com.android.inputmethod.latin.ContactsBinaryDictionary; @@ -37,12 +32,10 @@ import com.android.inputmethod.latin.DictionaryFactory; import com.android.inputmethod.latin.LocaleUtils; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StringUtils; -import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.SynchronouslyLoadedContactsBinaryDictionary; import com.android.inputmethod.latin.SynchronouslyLoadedUserBinaryDictionary; import com.android.inputmethod.latin.UserBinaryDictionary; import com.android.inputmethod.latin.WhitelistDictionary; -import com.android.inputmethod.latin.WordComposer; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -65,9 +58,9 @@ public class AndroidSpellCheckerService extends SpellCheckerService public static final String PREF_USE_CONTACTS_KEY = "pref_spellcheck_use_contacts"; - private static final int CAPITALIZE_NONE = 0; // No caps, or mixed case - private static final int CAPITALIZE_FIRST = 1; // First only - private static final int CAPITALIZE_ALL = 2; // All caps + public static final int CAPITALIZE_NONE = 0; // No caps, or mixed case + public static final int CAPITALIZE_FIRST = 1; // First only + public static final int CAPITALIZE_ALL = 2; // All caps private final static String[] EMPTY_STRING_ARRAY = new String[0]; private Map mDictionaryPools = @@ -91,8 +84,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService public static final int SCRIPT_LATIN = 0; public static final int SCRIPT_CYRILLIC = 1; - private static final String SINGLE_QUOTE = "\u0027"; - private static final String APOSTROPHE = "\u2019"; + public static final String SINGLE_QUOTE = "\u0027"; + public static final String APOSTROPHE = "\u2019"; private static final TreeMap mLanguageToScript; static { // List of the supported languages and their associated script. We won't check @@ -129,7 +122,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService onSharedPreferenceChanged(prefs, PREF_USE_CONTACTS_KEY); } - private static int getScriptFromLocale(final Locale locale) { + public static int getScriptFromLocale(final Locale locale) { final Integer script = mLanguageToScript.get(locale.getLanguage()); if (null == script) { throw new RuntimeException("We have been called with an unsupported language: \"" @@ -194,17 +187,22 @@ public class AndroidSpellCheckerService extends SpellCheckerService return new AndroidSpellCheckerSession(this); } - private static SuggestionsInfo getNotInDictEmptySuggestions() { + public static SuggestionsInfo getNotInDictEmptySuggestions() { return new SuggestionsInfo(0, EMPTY_STRING_ARRAY); } - private static SuggestionsInfo getInDictEmptySuggestions() { + public static SuggestionsInfo getInDictEmptySuggestions() { return new SuggestionsInfo(SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY, EMPTY_STRING_ARRAY); } + public SuggestionsGatherer newSuggestionsGatherer(final String text, int maxLength) { + return new SuggestionsGatherer( + text, mSuggestionThreshold, mRecommendedThreshold, maxLength); + } + // TODO: remove this class and replace it by storage local to the session. - private static class SuggestionsGatherer { + public static class SuggestionsGatherer { public static class Result { public final String[] mSuggestions; public final boolean mHasRecommendedSuggestions; @@ -396,7 +394,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService }.start(); } - private DictionaryPool getDictionaryPool(final String locale) { + public DictionaryPool getDictionaryPool(final String locale) { DictionaryPool pool = mDictionaryPools.get(locale); if (null == pool) { final Locale localeObject = LocaleUtils.constructLocaleFromString(locale); @@ -447,7 +445,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService } // This method assumes the text is not empty or null. - private static int getCapitalizationType(String text) { + public static int getCapitalizationType(String text) { // If the first char is not uppercase, then the word is either all lower case, // and in either case we return CAPITALIZE_NONE. if (!Character.isUpperCase(text.codePointAt(0))) return CAPITALIZE_NONE; @@ -464,379 +462,4 @@ public class AndroidSpellCheckerService extends SpellCheckerService if (1 == capsCount) return CAPITALIZE_FIRST; return (len == capsCount ? CAPITALIZE_ALL : CAPITALIZE_NONE); } - - private static class AndroidSpellCheckerSession extends Session { - // Immutable, but need the locale which is not available in the constructor yet - private DictionaryPool mDictionaryPool; - // Likewise - private Locale mLocale; - // Cache this for performance - private int mScript; // One of SCRIPT_LATIN or SCRIPT_CYRILLIC for now. - - private final AndroidSpellCheckerService mService; - - private final SuggestionsCache mSuggestionsCache = new SuggestionsCache(); - - private static class SuggestionsParams { - public final String[] mSuggestions; - public final int mFlags; - public SuggestionsParams(String[] suggestions, int flags) { - mSuggestions = suggestions; - mFlags = flags; - } - } - - private static class SuggestionsCache { - private static final char CHAR_DELIMITER = '\uFFFC'; - private static final int MAX_CACHE_SIZE = 50; - private final LruCache mUnigramSuggestionsInfoCache = - new LruCache(MAX_CACHE_SIZE); - - // TODO: Support n-gram input - private static String generateKey(String query, String prevWord) { - if (TextUtils.isEmpty(query) || TextUtils.isEmpty(prevWord)) { - return query; - } - return query + CHAR_DELIMITER + prevWord; - } - - // TODO: Support n-gram input - public SuggestionsParams getSuggestionsFromCache(String query, String prevWord) { - return mUnigramSuggestionsInfoCache.get(generateKey(query, prevWord)); - } - - // TODO: Support n-gram input - public void putSuggestionsToCache( - String query, String prevWord, String[] suggestions, int flags) { - if (suggestions == null || TextUtils.isEmpty(query)) { - return; - } - mUnigramSuggestionsInfoCache.put( - generateKey(query, prevWord), new SuggestionsParams(suggestions, flags)); - } - } - - AndroidSpellCheckerSession(final AndroidSpellCheckerService service) { - mService = service; - } - - @Override - public void onCreate() { - final String localeString = getLocale(); - mDictionaryPool = mService.getDictionaryPool(localeString); - mLocale = LocaleUtils.constructLocaleFromString(localeString); - mScript = getScriptFromLocale(mLocale); - } - - /* - * Returns whether the code point is a letter that makes sense for the specified - * locale for this spell checker. - * The dictionaries supported by Latin IME are described in res/xml/spellchecker.xml - * and is limited to EFIGS languages and Russian. - * Hence at the moment this explicitly tests for Cyrillic characters or Latin characters - * as appropriate, and explicitly excludes CJK, Arabic and Hebrew characters. - */ - private static boolean isLetterCheckableByLanguage(final int codePoint, - final int script) { - switch (script) { - case SCRIPT_LATIN: - // Our supported latin script dictionaries (EFIGS) at the moment only include - // characters in the C0, C1, Latin Extended A and B, IPA extensions unicode - // blocks. As it happens, those are back-to-back in the code range 0x40 to 0x2AF, - // so the below is a very efficient way to test for it. As for the 0-0x3F, it's - // excluded from isLetter anyway. - return codePoint <= 0x2AF && Character.isLetter(codePoint); - case SCRIPT_CYRILLIC: - // All Cyrillic characters are in the 400~52F block. There are some in the upper - // Unicode range, but they are archaic characters that are not used in modern - // russian and are not used by our dictionary. - return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint); - default: - // Should never come here - throw new RuntimeException("Impossible value of script: " + script); - } - } - - /** - * Finds out whether a particular string should be filtered out of spell checking. - * - * This will loosely match URLs, numbers, symbols. To avoid always underlining words that - * we know we will never recognize, this accepts a script identifier that should be one - * of the SCRIPT_* constants defined above, to rule out quickly characters from very - * different languages. - * - * @param text the string to evaluate. - * @param script the identifier for the script this spell checker recognizes - * @return true if we should filter this text out, false otherwise - */ - private static boolean shouldFilterOut(final String text, final int script) { - if (TextUtils.isEmpty(text) || text.length() <= 1) return true; - - // TODO: check if an equivalent processing can't be done more quickly with a - // compiled regexp. - // Filter by first letter - final int firstCodePoint = text.codePointAt(0); - // Filter out words that don't start with a letter or an apostrophe - if (!isLetterCheckableByLanguage(firstCodePoint, script) - && '\'' != firstCodePoint) return true; - - // Filter contents - final int length = text.length(); - int letterCount = 0; - for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { - final int codePoint = text.codePointAt(i); - // Any word containing a '@' is probably an e-mail address - // Any word containing a '/' is probably either an ad-hoc combination of two - // words or a URI - in either case we don't want to spell check that - if ('@' == codePoint || '/' == codePoint) return true; - if (isLetterCheckableByLanguage(codePoint, script)) ++letterCount; - } - // Guestimate heuristic: perform spell checking if at least 3/4 of the characters - // in this word are letters - return (letterCount * 4 < length * 3); - } - - private SentenceSuggestionsInfo fixWronglyInvalidatedWordWithSingleQuote( - TextInfo ti, SentenceSuggestionsInfo ssi) { - final String typedText = ti.getText(); - if (!typedText.contains(SINGLE_QUOTE)) { - return null; - } - final int N = ssi.getSuggestionsCount(); - final ArrayList additionalOffsets = new ArrayList(); - final ArrayList additionalLengths = new ArrayList(); - final ArrayList additionalSuggestionsInfos = - new ArrayList(); - String currentWord = null; - for (int i = 0; i < N; ++i) { - final SuggestionsInfo si = ssi.getSuggestionsInfoAt(i); - final int flags = si.getSuggestionsAttributes(); - if ((flags & SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY) == 0) { - continue; - } - final int offset = ssi.getOffsetAt(i); - final int length = ssi.getLengthAt(i); - final String subText = typedText.substring(offset, offset + length); - final String prevWord = currentWord; - currentWord = subText; - if (!subText.contains(SINGLE_QUOTE)) { - continue; - } - final String[] splitTexts = subText.split(SINGLE_QUOTE, -1); - if (splitTexts == null || splitTexts.length <= 1) { - continue; - } - final int splitNum = splitTexts.length; - for (int j = 0; j < splitNum; ++j) { - final String splitText = splitTexts[j]; - if (TextUtils.isEmpty(splitText)) { - continue; - } - if (mSuggestionsCache.getSuggestionsFromCache( - splitText, prevWord) == null) { - continue; - } - final int newLength = splitText.length(); - // Neither RESULT_ATTR_IN_THE_DICTIONARY nor RESULT_ATTR_LOOKS_LIKE_TYPO - final int newFlags = 0; - final SuggestionsInfo newSi = new SuggestionsInfo(newFlags, EMPTY_STRING_ARRAY); - newSi.setCookieAndSequence(si.getCookie(), si.getSequence()); - if (DBG) { - Log.d(TAG, "Override and remove old span over: " - + splitText + ", " + offset + "," + newLength); - } - additionalOffsets.add(offset); - additionalLengths.add(newLength); - additionalSuggestionsInfos.add(newSi); - } - } - final int additionalSize = additionalOffsets.size(); - if (additionalSize <= 0) { - return null; - } - final int suggestionsSize = N + additionalSize; - final int[] newOffsets = new int[suggestionsSize]; - final int[] newLengths = new int[suggestionsSize]; - final SuggestionsInfo[] newSuggestionsInfos = new SuggestionsInfo[suggestionsSize]; - int i; - for (i = 0; i < N; ++i) { - newOffsets[i] = ssi.getOffsetAt(i); - newLengths[i] = ssi.getLengthAt(i); - newSuggestionsInfos[i] = ssi.getSuggestionsInfoAt(i); - } - for (; i < suggestionsSize; ++i) { - newOffsets[i] = additionalOffsets.get(i - N); - newLengths[i] = additionalLengths.get(i - N); - newSuggestionsInfos[i] = additionalSuggestionsInfos.get(i - N); - } - return new SentenceSuggestionsInfo(newSuggestionsInfos, newOffsets, newLengths); - } - - @Override - public SentenceSuggestionsInfo[] onGetSentenceSuggestionsMultiple( - TextInfo[] textInfos, int suggestionsLimit) { - final SentenceSuggestionsInfo[] retval = super.onGetSentenceSuggestionsMultiple( - textInfos, suggestionsLimit); - if (retval == null || retval.length != textInfos.length) { - return retval; - } - for (int i = 0; i < retval.length; ++i) { - final SentenceSuggestionsInfo tempSsi = - fixWronglyInvalidatedWordWithSingleQuote(textInfos[i], retval[i]); - if (tempSsi != null) { - retval[i] = tempSsi; - } - } - return retval; - } - - @Override - public SuggestionsInfo[] onGetSuggestionsMultiple(TextInfo[] textInfos, - int suggestionsLimit, boolean sequentialWords) { - final int length = textInfos.length; - final SuggestionsInfo[] retval = new SuggestionsInfo[length]; - for (int i = 0; i < length; ++i) { - final String prevWord; - if (sequentialWords && i > 0) { - final String prevWordCandidate = textInfos[i - 1].getText(); - // Note that an empty string would be used to indicate the initial word - // in the future. - prevWord = TextUtils.isEmpty(prevWordCandidate) ? null : prevWordCandidate; - } else { - prevWord = null; - } - retval[i] = onGetSuggestions(textInfos[i], prevWord, suggestionsLimit); - retval[i].setCookieAndSequence( - textInfos[i].getCookie(), textInfos[i].getSequence()); - } - return retval; - } - - // Note : this must be reentrant - /** - * Gets a list of suggestions for a specific string. This returns a list of possible - * corrections for the text passed as an argument. It may split or group words, and - * even perform grammatical analysis. - */ - @Override - public SuggestionsInfo onGetSuggestions(final TextInfo textInfo, - final int suggestionsLimit) { - return onGetSuggestions(textInfo, null, suggestionsLimit); - } - - private SuggestionsInfo onGetSuggestions( - final TextInfo textInfo, final String prevWord, final int suggestionsLimit) { - try { - final String inText = textInfo.getText(); - final SuggestionsParams cachedSuggestionsParams = - mSuggestionsCache.getSuggestionsFromCache(inText, prevWord); - if (cachedSuggestionsParams != null) { - if (DBG) { - Log.d(TAG, "Cache hit: " + inText + ", " + cachedSuggestionsParams.mFlags); - } - return new SuggestionsInfo( - cachedSuggestionsParams.mFlags, cachedSuggestionsParams.mSuggestions); - } - - if (shouldFilterOut(inText, mScript)) { - DictAndProximity dictInfo = null; - try { - dictInfo = mDictionaryPool.takeOrGetNull(); - if (null == dictInfo) return getNotInDictEmptySuggestions(); - return dictInfo.mDictionary.isValidWord(inText) ? - getInDictEmptySuggestions() : getNotInDictEmptySuggestions(); - } finally { - if (null != dictInfo) { - if (!mDictionaryPool.offer(dictInfo)) { - Log.e(TAG, "Can't re-insert a dictionary into its pool"); - } - } - } - } - final String text = inText.replaceAll(APOSTROPHE, SINGLE_QUOTE); - - // TODO: Don't gather suggestions if the limit is <= 0 unless necessary - final SuggestionsGatherer suggestionsGatherer = new SuggestionsGatherer(text, - mService.mSuggestionThreshold, mService.mRecommendedThreshold, - suggestionsLimit); - final WordComposer composer = new WordComposer(); - final int length = text.length(); - for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { - final int codePoint = text.codePointAt(i); - // The getXYForCodePointAndScript method returns (Y << 16) + X - final int xy = SpellCheckerProximityInfo.getXYForCodePointAndScript( - codePoint, mScript); - if (SpellCheckerProximityInfo.NOT_A_COORDINATE_PAIR == xy) { - composer.add(codePoint, WordComposer.NOT_A_COORDINATE, - WordComposer.NOT_A_COORDINATE); - } else { - composer.add(codePoint, xy & 0xFFFF, xy >> 16); - } - } - - final int capitalizeType = getCapitalizationType(text); - boolean isInDict = true; - DictAndProximity dictInfo = null; - try { - dictInfo = mDictionaryPool.takeOrGetNull(); - if (null == dictInfo) return getNotInDictEmptySuggestions(); - final ArrayList suggestions = dictInfo.mDictionary.getWords( - composer, prevWord, dictInfo.mProximityInfo); - for (final SuggestedWordInfo suggestion : suggestions) { - final String suggestionStr = suggestion.mWord.toString(); - suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0, - suggestionStr.length(), suggestion.mScore); - } - isInDict = dictInfo.mDictionary.isValidWord(text); - if (!isInDict && CAPITALIZE_NONE != capitalizeType) { - // We want to test the word again if it's all caps or first caps only. - // If it's fully down, we already tested it, if it's mixed case, we don't - // want to test a lowercase version of it. - isInDict = dictInfo.mDictionary.isValidWord(text.toLowerCase(mLocale)); - } - } finally { - if (null != dictInfo) { - if (!mDictionaryPool.offer(dictInfo)) { - Log.e(TAG, "Can't re-insert a dictionary into its pool"); - } - } - } - - final SuggestionsGatherer.Result result = suggestionsGatherer.getResults( - capitalizeType, mLocale); - - if (DBG) { - Log.i(TAG, "Spell checking results for " + text + " with suggestion limit " - + suggestionsLimit); - Log.i(TAG, "IsInDict = " + isInDict); - Log.i(TAG, "LooksLikeTypo = " + (!isInDict)); - Log.i(TAG, "HasRecommendedSuggestions = " + result.mHasRecommendedSuggestions); - if (null != result.mSuggestions) { - for (String suggestion : result.mSuggestions) { - Log.i(TAG, suggestion); - } - } - } - - final int flags = - (isInDict ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY - : SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) - | (result.mHasRecommendedSuggestions - ? SuggestionsInfoCompatUtils - .getValueOf_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS() - : 0); - final SuggestionsInfo retval = new SuggestionsInfo(flags, result.mSuggestions); - mSuggestionsCache.putSuggestionsToCache(text, prevWord, result.mSuggestions, flags); - return retval; - } catch (RuntimeException e) { - // Don't kill the keyboard if there is a bug in the spell checker - if (DBG) { - throw e; - } else { - Log.e(TAG, "Exception while spellcheking: " + e); - return getNotInDictEmptySuggestions(); - } - } - } - } } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java new file mode 100644 index 000000000..e0f340879 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java @@ -0,0 +1,420 @@ +/* + * 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.spellcheck; + + +import android.service.textservice.SpellCheckerService.Session; +import android.text.TextUtils; +import android.util.Log; +import android.util.LruCache; +import android.view.textservice.SentenceSuggestionsInfo; +import android.view.textservice.SuggestionsInfo; +import android.view.textservice.TextInfo; + +import com.android.inputmethod.compat.SuggestionsInfoCompatUtils; +import com.android.inputmethod.latin.LocaleUtils; +import com.android.inputmethod.latin.WordComposer; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService.SuggestionsGatherer; + +import java.util.ArrayList; +import java.util.Locale; + +public class AndroidSpellCheckerSession extends Session { + private static final String TAG = AndroidSpellCheckerSession.class.getSimpleName(); + private static final boolean DBG = false; + private final static String[] EMPTY_STRING_ARRAY = new String[0]; + + // Immutable, but need the locale which is not available in the constructor yet + private DictionaryPool mDictionaryPool; + // Likewise + private Locale mLocale; + // Cache this for performance + private int mScript; // One of SCRIPT_LATIN or SCRIPT_CYRILLIC for now. + private final AndroidSpellCheckerService mService; + private final SuggestionsCache mSuggestionsCache = new SuggestionsCache(); + + private static class SuggestionsParams { + public final String[] mSuggestions; + public final int mFlags; + public SuggestionsParams(String[] suggestions, int flags) { + mSuggestions = suggestions; + mFlags = flags; + } + } + + private static class SuggestionsCache { + private static final char CHAR_DELIMITER = '\uFFFC'; + private static final int MAX_CACHE_SIZE = 50; + private final LruCache mUnigramSuggestionsInfoCache = + new LruCache(MAX_CACHE_SIZE); + + // TODO: Support n-gram input + private static String generateKey(String query, String prevWord) { + if (TextUtils.isEmpty(query) || TextUtils.isEmpty(prevWord)) { + return query; + } + return query + CHAR_DELIMITER + prevWord; + } + + // TODO: Support n-gram input + public SuggestionsParams getSuggestionsFromCache(String query, String prevWord) { + return mUnigramSuggestionsInfoCache.get(generateKey(query, prevWord)); + } + + // TODO: Support n-gram input + public void putSuggestionsToCache( + String query, String prevWord, String[] suggestions, int flags) { + if (suggestions == null || TextUtils.isEmpty(query)) { + return; + } + mUnigramSuggestionsInfoCache.put( + generateKey(query, prevWord), new SuggestionsParams(suggestions, flags)); + } + } + + AndroidSpellCheckerSession(final AndroidSpellCheckerService service) { + mService = service; + } + + @Override + public void onCreate() { + final String localeString = getLocale(); + mDictionaryPool = mService.getDictionaryPool(localeString); + mLocale = LocaleUtils.constructLocaleFromString(localeString); + mScript = AndroidSpellCheckerService.getScriptFromLocale(mLocale); + } + + /* + * Returns whether the code point is a letter that makes sense for the specified + * locale for this spell checker. + * The dictionaries supported by Latin IME are described in res/xml/spellchecker.xml + * and is limited to EFIGS languages and Russian. + * Hence at the moment this explicitly tests for Cyrillic characters or Latin characters + * as appropriate, and explicitly excludes CJK, Arabic and Hebrew characters. + */ + private static boolean isLetterCheckableByLanguage(final int codePoint, + final int script) { + switch (script) { + case AndroidSpellCheckerService.SCRIPT_LATIN: + // Our supported latin script dictionaries (EFIGS) at the moment only include + // characters in the C0, C1, Latin Extended A and B, IPA extensions unicode + // blocks. As it happens, those are back-to-back in the code range 0x40 to 0x2AF, + // so the below is a very efficient way to test for it. As for the 0-0x3F, it's + // excluded from isLetter anyway. + return codePoint <= 0x2AF && Character.isLetter(codePoint); + case AndroidSpellCheckerService.SCRIPT_CYRILLIC: + // All Cyrillic characters are in the 400~52F block. There are some in the upper + // Unicode range, but they are archaic characters that are not used in modern + // russian and are not used by our dictionary. + return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint); + default: + // Should never come here + throw new RuntimeException("Impossible value of script: " + script); + } + } + + /** + * Finds out whether a particular string should be filtered out of spell checking. + * + * This will loosely match URLs, numbers, symbols. To avoid always underlining words that + * we know we will never recognize, this accepts a script identifier that should be one + * of the SCRIPT_* constants defined above, to rule out quickly characters from very + * different languages. + * + * @param text the string to evaluate. + * @param script the identifier for the script this spell checker recognizes + * @return true if we should filter this text out, false otherwise + */ + private static boolean shouldFilterOut(final String text, final int script) { + if (TextUtils.isEmpty(text) || text.length() <= 1) return true; + + // TODO: check if an equivalent processing can't be done more quickly with a + // compiled regexp. + // Filter by first letter + final int firstCodePoint = text.codePointAt(0); + // Filter out words that don't start with a letter or an apostrophe + if (!isLetterCheckableByLanguage(firstCodePoint, script) + && '\'' != firstCodePoint) return true; + + // Filter contents + final int length = text.length(); + int letterCount = 0; + for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { + final int codePoint = text.codePointAt(i); + // Any word containing a '@' is probably an e-mail address + // Any word containing a '/' is probably either an ad-hoc combination of two + // words or a URI - in either case we don't want to spell check that + if ('@' == codePoint || '/' == codePoint) return true; + if (isLetterCheckableByLanguage(codePoint, script)) ++letterCount; + } + // Guestimate heuristic: perform spell checking if at least 3/4 of the characters + // in this word are letters + return (letterCount * 4 < length * 3); + } + + private SentenceSuggestionsInfo fixWronglyInvalidatedWordWithSingleQuote( + TextInfo ti, SentenceSuggestionsInfo ssi) { + final String typedText = ti.getText(); + if (!typedText.contains(AndroidSpellCheckerService.SINGLE_QUOTE)) { + return null; + } + final int N = ssi.getSuggestionsCount(); + final ArrayList additionalOffsets = new ArrayList(); + final ArrayList additionalLengths = new ArrayList(); + final ArrayList additionalSuggestionsInfos = + new ArrayList(); + String currentWord = null; + for (int i = 0; i < N; ++i) { + final SuggestionsInfo si = ssi.getSuggestionsInfoAt(i); + final int flags = si.getSuggestionsAttributes(); + if ((flags & SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY) == 0) { + continue; + } + final int offset = ssi.getOffsetAt(i); + final int length = ssi.getLengthAt(i); + final String subText = typedText.substring(offset, offset + length); + final String prevWord = currentWord; + currentWord = subText; + if (!subText.contains(AndroidSpellCheckerService.SINGLE_QUOTE)) { + continue; + } + final String[] splitTexts = subText.split(AndroidSpellCheckerService.SINGLE_QUOTE, -1); + if (splitTexts == null || splitTexts.length <= 1) { + continue; + } + final int splitNum = splitTexts.length; + for (int j = 0; j < splitNum; ++j) { + final String splitText = splitTexts[j]; + if (TextUtils.isEmpty(splitText)) { + continue; + } + if (mSuggestionsCache.getSuggestionsFromCache( + splitText, prevWord) == null) { + continue; + } + final int newLength = splitText.length(); + // Neither RESULT_ATTR_IN_THE_DICTIONARY nor RESULT_ATTR_LOOKS_LIKE_TYPO + final int newFlags = 0; + final SuggestionsInfo newSi = new SuggestionsInfo(newFlags, EMPTY_STRING_ARRAY); + newSi.setCookieAndSequence(si.getCookie(), si.getSequence()); + if (DBG) { + Log.d(TAG, "Override and remove old span over: " + + splitText + ", " + offset + "," + newLength); + } + additionalOffsets.add(offset); + additionalLengths.add(newLength); + additionalSuggestionsInfos.add(newSi); + } + } + final int additionalSize = additionalOffsets.size(); + if (additionalSize <= 0) { + return null; + } + final int suggestionsSize = N + additionalSize; + final int[] newOffsets = new int[suggestionsSize]; + final int[] newLengths = new int[suggestionsSize]; + final SuggestionsInfo[] newSuggestionsInfos = new SuggestionsInfo[suggestionsSize]; + int i; + for (i = 0; i < N; ++i) { + newOffsets[i] = ssi.getOffsetAt(i); + newLengths[i] = ssi.getLengthAt(i); + newSuggestionsInfos[i] = ssi.getSuggestionsInfoAt(i); + } + for (; i < suggestionsSize; ++i) { + newOffsets[i] = additionalOffsets.get(i - N); + newLengths[i] = additionalLengths.get(i - N); + newSuggestionsInfos[i] = additionalSuggestionsInfos.get(i - N); + } + return new SentenceSuggestionsInfo(newSuggestionsInfos, newOffsets, newLengths); + } + + @Override + public SentenceSuggestionsInfo[] onGetSentenceSuggestionsMultiple( + TextInfo[] textInfos, int suggestionsLimit) { + final SentenceSuggestionsInfo[] retval = super.onGetSentenceSuggestionsMultiple( + textInfos, suggestionsLimit); + if (retval == null || retval.length != textInfos.length) { + return retval; + } + for (int i = 0; i < retval.length; ++i) { + final SentenceSuggestionsInfo tempSsi = + fixWronglyInvalidatedWordWithSingleQuote(textInfos[i], retval[i]); + if (tempSsi != null) { + retval[i] = tempSsi; + } + } + return retval; + } + + @Override + public SuggestionsInfo[] onGetSuggestionsMultiple(TextInfo[] textInfos, + int suggestionsLimit, boolean sequentialWords) { + final int length = textInfos.length; + final SuggestionsInfo[] retval = new SuggestionsInfo[length]; + for (int i = 0; i < length; ++i) { + final String prevWord; + if (sequentialWords && i > 0) { + final String prevWordCandidate = textInfos[i - 1].getText(); + // Note that an empty string would be used to indicate the initial word + // in the future. + prevWord = TextUtils.isEmpty(prevWordCandidate) ? null : prevWordCandidate; + } else { + prevWord = null; + } + retval[i] = onGetSuggestions(textInfos[i], prevWord, suggestionsLimit); + retval[i].setCookieAndSequence( + textInfos[i].getCookie(), textInfos[i].getSequence()); + } + return retval; + } + + // Note : this must be reentrant + /** + * Gets a list of suggestions for a specific string. This returns a list of possible + * corrections for the text passed as an argument. It may split or group words, and + * even perform grammatical analysis. + */ + @Override + public SuggestionsInfo onGetSuggestions(final TextInfo textInfo, + final int suggestionsLimit) { + return onGetSuggestions(textInfo, null, suggestionsLimit); + } + + private SuggestionsInfo onGetSuggestions( + final TextInfo textInfo, final String prevWord, final int suggestionsLimit) { + try { + final String inText = textInfo.getText(); + final SuggestionsParams cachedSuggestionsParams = + mSuggestionsCache.getSuggestionsFromCache(inText, prevWord); + if (cachedSuggestionsParams != null) { + if (DBG) { + Log.d(TAG, "Cache hit: " + inText + ", " + cachedSuggestionsParams.mFlags); + } + return new SuggestionsInfo( + cachedSuggestionsParams.mFlags, cachedSuggestionsParams.mSuggestions); + } + + if (shouldFilterOut(inText, mScript)) { + DictAndProximity dictInfo = null; + try { + dictInfo = mDictionaryPool.takeOrGetNull(); + if (null == dictInfo) { + return AndroidSpellCheckerService.getNotInDictEmptySuggestions(); + } + return dictInfo.mDictionary.isValidWord(inText) + ? AndroidSpellCheckerService.getInDictEmptySuggestions() + : AndroidSpellCheckerService.getNotInDictEmptySuggestions(); + } finally { + if (null != dictInfo) { + if (!mDictionaryPool.offer(dictInfo)) { + Log.e(TAG, "Can't re-insert a dictionary into its pool"); + } + } + } + } + final String text = inText.replaceAll( + AndroidSpellCheckerService.APOSTROPHE, AndroidSpellCheckerService.SINGLE_QUOTE); + + // TODO: Don't gather suggestions if the limit is <= 0 unless necessary + //final SuggestionsGatherer suggestionsGatherer = new SuggestionsGatherer(text, + //mService.mSuggestionThreshold, mService.mRecommendedThreshold, + //suggestionsLimit); + final SuggestionsGatherer suggestionsGatherer = mService.newSuggestionsGatherer( + text, suggestionsLimit); + final WordComposer composer = new WordComposer(); + final int length = text.length(); + for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { + final int codePoint = text.codePointAt(i); + // The getXYForCodePointAndScript method returns (Y << 16) + X + final int xy = SpellCheckerProximityInfo.getXYForCodePointAndScript( + codePoint, mScript); + if (SpellCheckerProximityInfo.NOT_A_COORDINATE_PAIR == xy) { + composer.add(codePoint, WordComposer.NOT_A_COORDINATE, + WordComposer.NOT_A_COORDINATE); + } else { + composer.add(codePoint, xy & 0xFFFF, xy >> 16); + } + } + + final int capitalizeType = AndroidSpellCheckerService.getCapitalizationType(text); + boolean isInDict = true; + DictAndProximity dictInfo = null; + try { + dictInfo = mDictionaryPool.takeOrGetNull(); + if (null == dictInfo) { + return AndroidSpellCheckerService.getNotInDictEmptySuggestions(); + } + final ArrayList suggestions = dictInfo.mDictionary.getWords( + composer, prevWord, dictInfo.mProximityInfo); + for (final SuggestedWordInfo suggestion : suggestions) { + final String suggestionStr = suggestion.mWord.toString(); + suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0, + suggestionStr.length(), suggestion.mScore); + } + isInDict = dictInfo.mDictionary.isValidWord(text); + if (!isInDict && AndroidSpellCheckerService.CAPITALIZE_NONE != capitalizeType) { + // We want to test the word again if it's all caps or first caps only. + // If it's fully down, we already tested it, if it's mixed case, we don't + // want to test a lowercase version of it. + isInDict = dictInfo.mDictionary.isValidWord(text.toLowerCase(mLocale)); + } + } finally { + if (null != dictInfo) { + if (!mDictionaryPool.offer(dictInfo)) { + Log.e(TAG, "Can't re-insert a dictionary into its pool"); + } + } + } + + final SuggestionsGatherer.Result result = suggestionsGatherer.getResults( + capitalizeType, mLocale); + + if (DBG) { + Log.i(TAG, "Spell checking results for " + text + " with suggestion limit " + + suggestionsLimit); + Log.i(TAG, "IsInDict = " + isInDict); + Log.i(TAG, "LooksLikeTypo = " + (!isInDict)); + Log.i(TAG, "HasRecommendedSuggestions = " + result.mHasRecommendedSuggestions); + if (null != result.mSuggestions) { + for (String suggestion : result.mSuggestions) { + Log.i(TAG, suggestion); + } + } + } + + final int flags = + (isInDict ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY + : SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) + | (result.mHasRecommendedSuggestions + ? SuggestionsInfoCompatUtils + .getValueOf_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS() + : 0); + final SuggestionsInfo retval = new SuggestionsInfo(flags, result.mSuggestions); + mSuggestionsCache.putSuggestionsToCache(text, prevWord, result.mSuggestions, flags); + return retval; + } catch (RuntimeException e) { + // Don't kill the keyboard if there is a bug in the spell checker + if (DBG) { + throw e; + } else { + Log.e(TAG, "Exception while spellcheking: " + e); + return AndroidSpellCheckerService.getNotInDictEmptySuggestions(); + } + } + } +} From 37b19ffe6c9d8335cc0e1c1c50f5b08c778b287c Mon Sep 17 00:00:00 2001 From: Satoshi Kataoka Date: Tue, 10 Jul 2012 15:51:23 +0900 Subject: [PATCH 12/68] Create AndroidSpellCheckerSessionFactory Bug: 6789576 Change-Id: I6de1e1aa64cf14f38ecb250579418bc518f0d838 --- .../AndroidSpellCheckerService.java | 4 ++- .../AndroidSpellCheckerSession.java | 1 - .../AndroidSpellCheckerSessionFactory.java | 25 +++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSessionFactory.java diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 42b05592c..3bdfe1f27 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -184,7 +184,9 @@ public class AndroidSpellCheckerService extends SpellCheckerService @Override public Session createSession() { - return new AndroidSpellCheckerSession(this); + // Should not refer to AndroidSpellCheckerSession directly considering + // that AndroidSpellCheckerSession may be overlaid. + return AndroidSpellCheckerSessionFactory.newInstance(this); } public static SuggestionsInfo getNotInDictEmptySuggestions() { diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java index e0f340879..c8ad2c699 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java @@ -16,7 +16,6 @@ package com.android.inputmethod.latin.spellcheck; - import android.service.textservice.SpellCheckerService.Session; import android.text.TextUtils; import android.util.Log; diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSessionFactory.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSessionFactory.java new file mode 100644 index 000000000..8eb1eb68e --- /dev/null +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSessionFactory.java @@ -0,0 +1,25 @@ +/* + * 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.spellcheck; + +import android.service.textservice.SpellCheckerService.Session; + +public abstract class AndroidSpellCheckerSessionFactory { + public static Session newInstance(AndroidSpellCheckerService service) { + return new AndroidSpellCheckerSession(service); + } +} From 09fdd30e5261990ace636c52a8330d4c5dbb364b Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 6 Jul 2012 16:20:04 +0900 Subject: [PATCH 13/68] Simplification (A78) Change-Id: I622503af858ef419e94a17f182253cb03da00462 --- .../com/android/inputmethod/latin/LatinIME.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 7b4aedeb6..f30a75b6b 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1702,13 +1702,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private SuggestedWords maybeRetrieveOlderSuggestions(final CharSequence typedWord, final SuggestedWords suggestedWords) { // TODO: consolidate this into getSuggestedWords - // Basically, we update the suggestion strip only when suggestion count > 1. However, - // there is an exception: We update the suggestion strip whenever typed word's length - // is 1 or typed word is found in dictionary, regardless of suggestion count. Actually, - // in most cases, suggestion count is 1 when typed word's length is 1, but we do always - // need to clear the previous state when the user starts typing a word (i.e. typed word's - // length == 1). - if (suggestedWords.size() > 1 || typedWord.length() == 1 || !mWordComposer.isComposingWord() + // We update the suggestion strip only when we have some suggestions to show, i.e. when + // the suggestion count is > 1; else, we leave the old suggestions, with the typed word + // replaced with the new one. However, when the word is a dictionary word, or when the + // length of the typed word is 1 or 0 (after a deletion typically), we do want to remove the + // old suggestions. Also, if we are showing the "add to dictionary" hint, we need to + // revert to suggestions - although it is unclear how we can come here if it's displayed. + if (suggestedWords.size() > 1 || typedWord.length() <= 1 || !suggestedWords.mTypedWordValid || mSuggestionsView.isShowingAddToDictionaryHint()) { return suggestedWords; From 728c0cb251b4a7b7d6d048efc1b0e8cec5ace9e5 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 6 Jul 2012 16:37:47 +0900 Subject: [PATCH 14/68] Remove useless code (A79) We postUpdateSuggestionStrip right away anyway - this only makes the suggestion strip blink Change-Id: I2ebd933e9a4c804ef1e8c62ccdaf4953a98a792e --- java/src/com/android/inputmethod/latin/LatinIME.java | 1 - 1 file changed, 1 deletion(-) diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index f30a75b6b..5ee539cc8 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1505,7 +1505,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // it entirely and resume suggestions on the previous word, we'd like to still // have touch coordinates for it. resetComposingState(false /* alsoResetLastComposedWord */); - clearSuggestions(); } if (isComposingWord) { final int keyX, keyY; From 7fcad7b9b614f43ea974d1bff84b609838ef1f75 Mon Sep 17 00:00:00 2001 From: Satoshi Kataoka Date: Tue, 10 Jul 2012 17:32:39 +0900 Subject: [PATCH 15/68] Separate ICS-dependent code from the spell checker service Bug: 6789576 Change-Id: Ia768258f6fa121c7a7757093eb8a20e665580865 --- .../AndroidSpellCheckerSession.java | 303 ++---------------- .../AndroidWordLevelSpellCheckerSession.java | 301 +++++++++++++++++ 2 files changed, 319 insertions(+), 285 deletions(-) create mode 100644 java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java index c8ad2c699..501a0e221 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java @@ -16,158 +16,25 @@ package com.android.inputmethod.latin.spellcheck; -import android.service.textservice.SpellCheckerService.Session; import android.text.TextUtils; import android.util.Log; -import android.util.LruCache; import android.view.textservice.SentenceSuggestionsInfo; import android.view.textservice.SuggestionsInfo; import android.view.textservice.TextInfo; -import com.android.inputmethod.compat.SuggestionsInfoCompatUtils; -import com.android.inputmethod.latin.LocaleUtils; -import com.android.inputmethod.latin.WordComposer; -import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; -import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService.SuggestionsGatherer; - import java.util.ArrayList; -import java.util.Locale; -public class AndroidSpellCheckerSession extends Session { +public class AndroidSpellCheckerSession extends AndroidWordLevelSpellCheckerSession { private static final String TAG = AndroidSpellCheckerSession.class.getSimpleName(); private static final boolean DBG = false; private final static String[] EMPTY_STRING_ARRAY = new String[0]; - // Immutable, but need the locale which is not available in the constructor yet - private DictionaryPool mDictionaryPool; - // Likewise - private Locale mLocale; - // Cache this for performance - private int mScript; // One of SCRIPT_LATIN or SCRIPT_CYRILLIC for now. - private final AndroidSpellCheckerService mService; - private final SuggestionsCache mSuggestionsCache = new SuggestionsCache(); - - private static class SuggestionsParams { - public final String[] mSuggestions; - public final int mFlags; - public SuggestionsParams(String[] suggestions, int flags) { - mSuggestions = suggestions; - mFlags = flags; - } + public AndroidSpellCheckerSession(AndroidSpellCheckerService service) { + super(service); } - private static class SuggestionsCache { - private static final char CHAR_DELIMITER = '\uFFFC'; - private static final int MAX_CACHE_SIZE = 50; - private final LruCache mUnigramSuggestionsInfoCache = - new LruCache(MAX_CACHE_SIZE); - - // TODO: Support n-gram input - private static String generateKey(String query, String prevWord) { - if (TextUtils.isEmpty(query) || TextUtils.isEmpty(prevWord)) { - return query; - } - return query + CHAR_DELIMITER + prevWord; - } - - // TODO: Support n-gram input - public SuggestionsParams getSuggestionsFromCache(String query, String prevWord) { - return mUnigramSuggestionsInfoCache.get(generateKey(query, prevWord)); - } - - // TODO: Support n-gram input - public void putSuggestionsToCache( - String query, String prevWord, String[] suggestions, int flags) { - if (suggestions == null || TextUtils.isEmpty(query)) { - return; - } - mUnigramSuggestionsInfoCache.put( - generateKey(query, prevWord), new SuggestionsParams(suggestions, flags)); - } - } - - AndroidSpellCheckerSession(final AndroidSpellCheckerService service) { - mService = service; - } - - @Override - public void onCreate() { - final String localeString = getLocale(); - mDictionaryPool = mService.getDictionaryPool(localeString); - mLocale = LocaleUtils.constructLocaleFromString(localeString); - mScript = AndroidSpellCheckerService.getScriptFromLocale(mLocale); - } - - /* - * Returns whether the code point is a letter that makes sense for the specified - * locale for this spell checker. - * The dictionaries supported by Latin IME are described in res/xml/spellchecker.xml - * and is limited to EFIGS languages and Russian. - * Hence at the moment this explicitly tests for Cyrillic characters or Latin characters - * as appropriate, and explicitly excludes CJK, Arabic and Hebrew characters. - */ - private static boolean isLetterCheckableByLanguage(final int codePoint, - final int script) { - switch (script) { - case AndroidSpellCheckerService.SCRIPT_LATIN: - // Our supported latin script dictionaries (EFIGS) at the moment only include - // characters in the C0, C1, Latin Extended A and B, IPA extensions unicode - // blocks. As it happens, those are back-to-back in the code range 0x40 to 0x2AF, - // so the below is a very efficient way to test for it. As for the 0-0x3F, it's - // excluded from isLetter anyway. - return codePoint <= 0x2AF && Character.isLetter(codePoint); - case AndroidSpellCheckerService.SCRIPT_CYRILLIC: - // All Cyrillic characters are in the 400~52F block. There are some in the upper - // Unicode range, but they are archaic characters that are not used in modern - // russian and are not used by our dictionary. - return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint); - default: - // Should never come here - throw new RuntimeException("Impossible value of script: " + script); - } - } - - /** - * Finds out whether a particular string should be filtered out of spell checking. - * - * This will loosely match URLs, numbers, symbols. To avoid always underlining words that - * we know we will never recognize, this accepts a script identifier that should be one - * of the SCRIPT_* constants defined above, to rule out quickly characters from very - * different languages. - * - * @param text the string to evaluate. - * @param script the identifier for the script this spell checker recognizes - * @return true if we should filter this text out, false otherwise - */ - private static boolean shouldFilterOut(final String text, final int script) { - if (TextUtils.isEmpty(text) || text.length() <= 1) return true; - - // TODO: check if an equivalent processing can't be done more quickly with a - // compiled regexp. - // Filter by first letter - final int firstCodePoint = text.codePointAt(0); - // Filter out words that don't start with a letter or an apostrophe - if (!isLetterCheckableByLanguage(firstCodePoint, script) - && '\'' != firstCodePoint) return true; - - // Filter contents - final int length = text.length(); - int letterCount = 0; - for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { - final int codePoint = text.codePointAt(i); - // Any word containing a '@' is probably an e-mail address - // Any word containing a '/' is probably either an ad-hoc combination of two - // words or a URI - in either case we don't want to spell check that - if ('@' == codePoint || '/' == codePoint) return true; - if (isLetterCheckableByLanguage(codePoint, script)) ++letterCount; - } - // Guestimate heuristic: perform spell checking if at least 3/4 of the characters - // in this word are letters - return (letterCount * 4 < length * 3); - } - - private SentenceSuggestionsInfo fixWronglyInvalidatedWordWithSingleQuote( - TextInfo ti, SentenceSuggestionsInfo ssi) { + private SentenceSuggestionsInfo fixWronglyInvalidatedWordWithSingleQuote(TextInfo ti, + SentenceSuggestionsInfo ssi) { final String typedText = ti.getText(); if (!typedText.contains(AndroidSpellCheckerService.SINGLE_QUOTE)) { return null; @@ -192,7 +59,8 @@ public class AndroidSpellCheckerSession extends Session { if (!subText.contains(AndroidSpellCheckerService.SINGLE_QUOTE)) { continue; } - final String[] splitTexts = subText.split(AndroidSpellCheckerService.SINGLE_QUOTE, -1); + final String[] splitTexts = + subText.split(AndroidSpellCheckerService.SINGLE_QUOTE, -1); if (splitTexts == null || splitTexts.length <= 1) { continue; } @@ -202,18 +70,18 @@ public class AndroidSpellCheckerSession extends Session { if (TextUtils.isEmpty(splitText)) { continue; } - if (mSuggestionsCache.getSuggestionsFromCache( - splitText, prevWord) == null) { + if (mSuggestionsCache.getSuggestionsFromCache(splitText, prevWord) == null) { continue; } final int newLength = splitText.length(); // Neither RESULT_ATTR_IN_THE_DICTIONARY nor RESULT_ATTR_LOOKS_LIKE_TYPO final int newFlags = 0; - final SuggestionsInfo newSi = new SuggestionsInfo(newFlags, EMPTY_STRING_ARRAY); + final SuggestionsInfo newSi = + new SuggestionsInfo(newFlags, EMPTY_STRING_ARRAY); newSi.setCookieAndSequence(si.getCookie(), si.getSequence()); if (DBG) { - Log.d(TAG, "Override and remove old span over: " - + splitText + ", " + offset + "," + newLength); + Log.d(TAG, "Override and remove old span over: " + splitText + ", " + + offset + "," + newLength); } additionalOffsets.add(offset); additionalLengths.add(newLength); @@ -243,10 +111,10 @@ public class AndroidSpellCheckerSession extends Session { } @Override - public SentenceSuggestionsInfo[] onGetSentenceSuggestionsMultiple( - TextInfo[] textInfos, int suggestionsLimit) { - final SentenceSuggestionsInfo[] retval = super.onGetSentenceSuggestionsMultiple( - textInfos, suggestionsLimit); + public SentenceSuggestionsInfo[] onGetSentenceSuggestionsMultiple(TextInfo[] textInfos, + int suggestionsLimit) { + final SentenceSuggestionsInfo[] retval = + super.onGetSentenceSuggestionsMultiple(textInfos, suggestionsLimit); if (retval == null || retval.length != textInfos.length) { return retval; } @@ -276,144 +144,9 @@ public class AndroidSpellCheckerSession extends Session { prevWord = null; } retval[i] = onGetSuggestions(textInfos[i], prevWord, suggestionsLimit); - retval[i].setCookieAndSequence( - textInfos[i].getCookie(), textInfos[i].getSequence()); + retval[i].setCookieAndSequence(textInfos[i].getCookie(), + textInfos[i].getSequence()); } return retval; } - - // Note : this must be reentrant - /** - * Gets a list of suggestions for a specific string. This returns a list of possible - * corrections for the text passed as an argument. It may split or group words, and - * even perform grammatical analysis. - */ - @Override - public SuggestionsInfo onGetSuggestions(final TextInfo textInfo, - final int suggestionsLimit) { - return onGetSuggestions(textInfo, null, suggestionsLimit); - } - - private SuggestionsInfo onGetSuggestions( - final TextInfo textInfo, final String prevWord, final int suggestionsLimit) { - try { - final String inText = textInfo.getText(); - final SuggestionsParams cachedSuggestionsParams = - mSuggestionsCache.getSuggestionsFromCache(inText, prevWord); - if (cachedSuggestionsParams != null) { - if (DBG) { - Log.d(TAG, "Cache hit: " + inText + ", " + cachedSuggestionsParams.mFlags); - } - return new SuggestionsInfo( - cachedSuggestionsParams.mFlags, cachedSuggestionsParams.mSuggestions); - } - - if (shouldFilterOut(inText, mScript)) { - DictAndProximity dictInfo = null; - try { - dictInfo = mDictionaryPool.takeOrGetNull(); - if (null == dictInfo) { - return AndroidSpellCheckerService.getNotInDictEmptySuggestions(); - } - return dictInfo.mDictionary.isValidWord(inText) - ? AndroidSpellCheckerService.getInDictEmptySuggestions() - : AndroidSpellCheckerService.getNotInDictEmptySuggestions(); - } finally { - if (null != dictInfo) { - if (!mDictionaryPool.offer(dictInfo)) { - Log.e(TAG, "Can't re-insert a dictionary into its pool"); - } - } - } - } - final String text = inText.replaceAll( - AndroidSpellCheckerService.APOSTROPHE, AndroidSpellCheckerService.SINGLE_QUOTE); - - // TODO: Don't gather suggestions if the limit is <= 0 unless necessary - //final SuggestionsGatherer suggestionsGatherer = new SuggestionsGatherer(text, - //mService.mSuggestionThreshold, mService.mRecommendedThreshold, - //suggestionsLimit); - final SuggestionsGatherer suggestionsGatherer = mService.newSuggestionsGatherer( - text, suggestionsLimit); - final WordComposer composer = new WordComposer(); - final int length = text.length(); - for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { - final int codePoint = text.codePointAt(i); - // The getXYForCodePointAndScript method returns (Y << 16) + X - final int xy = SpellCheckerProximityInfo.getXYForCodePointAndScript( - codePoint, mScript); - if (SpellCheckerProximityInfo.NOT_A_COORDINATE_PAIR == xy) { - composer.add(codePoint, WordComposer.NOT_A_COORDINATE, - WordComposer.NOT_A_COORDINATE); - } else { - composer.add(codePoint, xy & 0xFFFF, xy >> 16); - } - } - - final int capitalizeType = AndroidSpellCheckerService.getCapitalizationType(text); - boolean isInDict = true; - DictAndProximity dictInfo = null; - try { - dictInfo = mDictionaryPool.takeOrGetNull(); - if (null == dictInfo) { - return AndroidSpellCheckerService.getNotInDictEmptySuggestions(); - } - final ArrayList suggestions = dictInfo.mDictionary.getWords( - composer, prevWord, dictInfo.mProximityInfo); - for (final SuggestedWordInfo suggestion : suggestions) { - final String suggestionStr = suggestion.mWord.toString(); - suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0, - suggestionStr.length(), suggestion.mScore); - } - isInDict = dictInfo.mDictionary.isValidWord(text); - if (!isInDict && AndroidSpellCheckerService.CAPITALIZE_NONE != capitalizeType) { - // We want to test the word again if it's all caps or first caps only. - // If it's fully down, we already tested it, if it's mixed case, we don't - // want to test a lowercase version of it. - isInDict = dictInfo.mDictionary.isValidWord(text.toLowerCase(mLocale)); - } - } finally { - if (null != dictInfo) { - if (!mDictionaryPool.offer(dictInfo)) { - Log.e(TAG, "Can't re-insert a dictionary into its pool"); - } - } - } - - final SuggestionsGatherer.Result result = suggestionsGatherer.getResults( - capitalizeType, mLocale); - - if (DBG) { - Log.i(TAG, "Spell checking results for " + text + " with suggestion limit " - + suggestionsLimit); - Log.i(TAG, "IsInDict = " + isInDict); - Log.i(TAG, "LooksLikeTypo = " + (!isInDict)); - Log.i(TAG, "HasRecommendedSuggestions = " + result.mHasRecommendedSuggestions); - if (null != result.mSuggestions) { - for (String suggestion : result.mSuggestions) { - Log.i(TAG, suggestion); - } - } - } - - final int flags = - (isInDict ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY - : SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) - | (result.mHasRecommendedSuggestions - ? SuggestionsInfoCompatUtils - .getValueOf_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS() - : 0); - final SuggestionsInfo retval = new SuggestionsInfo(flags, result.mSuggestions); - mSuggestionsCache.putSuggestionsToCache(text, prevWord, result.mSuggestions, flags); - return retval; - } catch (RuntimeException e) { - // Don't kill the keyboard if there is a bug in the spell checker - if (DBG) { - throw e; - } else { - Log.e(TAG, "Exception while spellcheking: " + e); - return AndroidSpellCheckerService.getNotInDictEmptySuggestions(); - } - } - } } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java new file mode 100644 index 000000000..c94e0081c --- /dev/null +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java @@ -0,0 +1,301 @@ +/* + * 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.spellcheck; + +import android.service.textservice.SpellCheckerService.Session; +import android.text.TextUtils; +import android.util.Log; +import android.util.LruCache; +import android.view.textservice.SuggestionsInfo; +import android.view.textservice.TextInfo; + +import com.android.inputmethod.compat.SuggestionsInfoCompatUtils; +import com.android.inputmethod.latin.LocaleUtils; +import com.android.inputmethod.latin.WordComposer; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService.SuggestionsGatherer; + +import java.util.ArrayList; +import java.util.Locale; + +public abstract class AndroidWordLevelSpellCheckerSession extends Session { + private static final String TAG = AndroidWordLevelSpellCheckerSession.class.getSimpleName(); + private static final boolean DBG = false; + + // Immutable, but need the locale which is not available in the constructor yet + private DictionaryPool mDictionaryPool; + // Likewise + private Locale mLocale; + // Cache this for performance + private int mScript; // One of SCRIPT_LATIN or SCRIPT_CYRILLIC for now. + private final AndroidSpellCheckerService mService; + protected final SuggestionsCache mSuggestionsCache = new SuggestionsCache(); + + private static class SuggestionsParams { + public final String[] mSuggestions; + public final int mFlags; + public SuggestionsParams(String[] suggestions, int flags) { + mSuggestions = suggestions; + mFlags = flags; + } + } + + protected static class SuggestionsCache { + private static final char CHAR_DELIMITER = '\uFFFC'; + private static final int MAX_CACHE_SIZE = 50; + private final LruCache mUnigramSuggestionsInfoCache = + new LruCache(MAX_CACHE_SIZE); + + // TODO: Support n-gram input + private static String generateKey(String query, String prevWord) { + if (TextUtils.isEmpty(query) || TextUtils.isEmpty(prevWord)) { + return query; + } + return query + CHAR_DELIMITER + prevWord; + } + + // TODO: Support n-gram input + public SuggestionsParams getSuggestionsFromCache(String query, String prevWord) { + return mUnigramSuggestionsInfoCache.get(generateKey(query, prevWord)); + } + + // TODO: Support n-gram input + public void putSuggestionsToCache( + String query, String prevWord, String[] suggestions, int flags) { + if (suggestions == null || TextUtils.isEmpty(query)) { + return; + } + mUnigramSuggestionsInfoCache.put( + generateKey(query, prevWord), new SuggestionsParams(suggestions, flags)); + } + } + + AndroidWordLevelSpellCheckerSession(final AndroidSpellCheckerService service) { + mService = service; + } + + @Override + public void onCreate() { + final String localeString = getLocale(); + mDictionaryPool = mService.getDictionaryPool(localeString); + mLocale = LocaleUtils.constructLocaleFromString(localeString); + mScript = AndroidSpellCheckerService.getScriptFromLocale(mLocale); + } + + /* + * Returns whether the code point is a letter that makes sense for the specified + * locale for this spell checker. + * The dictionaries supported by Latin IME are described in res/xml/spellchecker.xml + * and is limited to EFIGS languages and Russian. + * Hence at the moment this explicitly tests for Cyrillic characters or Latin characters + * as appropriate, and explicitly excludes CJK, Arabic and Hebrew characters. + */ + private static boolean isLetterCheckableByLanguage(final int codePoint, + final int script) { + switch (script) { + case AndroidSpellCheckerService.SCRIPT_LATIN: + // Our supported latin script dictionaries (EFIGS) at the moment only include + // characters in the C0, C1, Latin Extended A and B, IPA extensions unicode + // blocks. As it happens, those are back-to-back in the code range 0x40 to 0x2AF, + // so the below is a very efficient way to test for it. As for the 0-0x3F, it's + // excluded from isLetter anyway. + return codePoint <= 0x2AF && Character.isLetter(codePoint); + case AndroidSpellCheckerService.SCRIPT_CYRILLIC: + // All Cyrillic characters are in the 400~52F block. There are some in the upper + // Unicode range, but they are archaic characters that are not used in modern + // russian and are not used by our dictionary. + return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint); + default: + // Should never come here + throw new RuntimeException("Impossible value of script: " + script); + } + } + + /** + * Finds out whether a particular string should be filtered out of spell checking. + * + * This will loosely match URLs, numbers, symbols. To avoid always underlining words that + * we know we will never recognize, this accepts a script identifier that should be one + * of the SCRIPT_* constants defined above, to rule out quickly characters from very + * different languages. + * + * @param text the string to evaluate. + * @param script the identifier for the script this spell checker recognizes + * @return true if we should filter this text out, false otherwise + */ + private static boolean shouldFilterOut(final String text, final int script) { + if (TextUtils.isEmpty(text) || text.length() <= 1) return true; + + // TODO: check if an equivalent processing can't be done more quickly with a + // compiled regexp. + // Filter by first letter + final int firstCodePoint = text.codePointAt(0); + // Filter out words that don't start with a letter or an apostrophe + if (!isLetterCheckableByLanguage(firstCodePoint, script) + && '\'' != firstCodePoint) return true; + + // Filter contents + final int length = text.length(); + int letterCount = 0; + for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { + final int codePoint = text.codePointAt(i); + // Any word containing a '@' is probably an e-mail address + // Any word containing a '/' is probably either an ad-hoc combination of two + // words or a URI - in either case we don't want to spell check that + if ('@' == codePoint || '/' == codePoint) return true; + if (isLetterCheckableByLanguage(codePoint, script)) ++letterCount; + } + // Guestimate heuristic: perform spell checking if at least 3/4 of the characters + // in this word are letters + return (letterCount * 4 < length * 3); + } + + // Note : this must be reentrant + /** + * Gets a list of suggestions for a specific string. This returns a list of possible + * corrections for the text passed as an argument. It may split or group words, and + * even perform grammatical analysis. + */ + @Override + public SuggestionsInfo onGetSuggestions(final TextInfo textInfo, + final int suggestionsLimit) { + return onGetSuggestions(textInfo, null, suggestionsLimit); + } + + protected SuggestionsInfo onGetSuggestions( + final TextInfo textInfo, final String prevWord, final int suggestionsLimit) { + try { + final String inText = textInfo.getText(); + final SuggestionsParams cachedSuggestionsParams = + mSuggestionsCache.getSuggestionsFromCache(inText, prevWord); + if (cachedSuggestionsParams != null) { + if (DBG) { + Log.d(TAG, "Cache hit: " + inText + ", " + cachedSuggestionsParams.mFlags); + } + return new SuggestionsInfo( + cachedSuggestionsParams.mFlags, cachedSuggestionsParams.mSuggestions); + } + + if (shouldFilterOut(inText, mScript)) { + DictAndProximity dictInfo = null; + try { + dictInfo = mDictionaryPool.takeOrGetNull(); + if (null == dictInfo) { + return AndroidSpellCheckerService.getNotInDictEmptySuggestions(); + } + return dictInfo.mDictionary.isValidWord(inText) + ? AndroidSpellCheckerService.getInDictEmptySuggestions() + : AndroidSpellCheckerService.getNotInDictEmptySuggestions(); + } finally { + if (null != dictInfo) { + if (!mDictionaryPool.offer(dictInfo)) { + Log.e(TAG, "Can't re-insert a dictionary into its pool"); + } + } + } + } + final String text = inText.replaceAll( + AndroidSpellCheckerService.APOSTROPHE, AndroidSpellCheckerService.SINGLE_QUOTE); + + // TODO: Don't gather suggestions if the limit is <= 0 unless necessary + //final SuggestionsGatherer suggestionsGatherer = new SuggestionsGatherer(text, + //mService.mSuggestionThreshold, mService.mRecommendedThreshold, + //suggestionsLimit); + final SuggestionsGatherer suggestionsGatherer = mService.newSuggestionsGatherer( + text, suggestionsLimit); + final WordComposer composer = new WordComposer(); + final int length = text.length(); + for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { + final int codePoint = text.codePointAt(i); + // The getXYForCodePointAndScript method returns (Y << 16) + X + final int xy = SpellCheckerProximityInfo.getXYForCodePointAndScript( + codePoint, mScript); + if (SpellCheckerProximityInfo.NOT_A_COORDINATE_PAIR == xy) { + composer.add(codePoint, WordComposer.NOT_A_COORDINATE, + WordComposer.NOT_A_COORDINATE); + } else { + composer.add(codePoint, xy & 0xFFFF, xy >> 16); + } + } + + final int capitalizeType = AndroidSpellCheckerService.getCapitalizationType(text); + boolean isInDict = true; + DictAndProximity dictInfo = null; + try { + dictInfo = mDictionaryPool.takeOrGetNull(); + if (null == dictInfo) { + return AndroidSpellCheckerService.getNotInDictEmptySuggestions(); + } + final ArrayList suggestions = dictInfo.mDictionary.getWords( + composer, prevWord, dictInfo.mProximityInfo); + for (final SuggestedWordInfo suggestion : suggestions) { + final String suggestionStr = suggestion.mWord.toString(); + suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0, + suggestionStr.length(), suggestion.mScore); + } + isInDict = dictInfo.mDictionary.isValidWord(text); + if (!isInDict && AndroidSpellCheckerService.CAPITALIZE_NONE != capitalizeType) { + // We want to test the word again if it's all caps or first caps only. + // If it's fully down, we already tested it, if it's mixed case, we don't + // want to test a lowercase version of it. + isInDict = dictInfo.mDictionary.isValidWord(text.toLowerCase(mLocale)); + } + } finally { + if (null != dictInfo) { + if (!mDictionaryPool.offer(dictInfo)) { + Log.e(TAG, "Can't re-insert a dictionary into its pool"); + } + } + } + + final SuggestionsGatherer.Result result = suggestionsGatherer.getResults( + capitalizeType, mLocale); + + if (DBG) { + Log.i(TAG, "Spell checking results for " + text + " with suggestion limit " + + suggestionsLimit); + Log.i(TAG, "IsInDict = " + isInDict); + Log.i(TAG, "LooksLikeTypo = " + (!isInDict)); + Log.i(TAG, "HasRecommendedSuggestions = " + result.mHasRecommendedSuggestions); + if (null != result.mSuggestions) { + for (String suggestion : result.mSuggestions) { + Log.i(TAG, suggestion); + } + } + } + + final int flags = + (isInDict ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY + : SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) + | (result.mHasRecommendedSuggestions + ? SuggestionsInfoCompatUtils + .getValueOf_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS() + : 0); + final SuggestionsInfo retval = new SuggestionsInfo(flags, result.mSuggestions); + mSuggestionsCache.putSuggestionsToCache(text, prevWord, result.mSuggestions, flags); + return retval; + } catch (RuntimeException e) { + // Don't kill the keyboard if there is a bug in the spell checker + if (DBG) { + throw e; + } else { + Log.e(TAG, "Exception while spellcheking: " + e); + return AndroidSpellCheckerService.getNotInDictEmptySuggestions(); + } + } + } +} From a5bb353de92a6a6d010ba1695b9dd22b3a617b77 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Mon, 9 Jul 2012 12:54:42 +0900 Subject: [PATCH 16/68] Cleanup visibility in LatinIME (A80) Many methods were public but could have been private: change them to private. Also, add a comment above public methods that don't come from the IMF to make it clearer why they are necessary. Change-Id: I574154b015d09c0f8542b81763f497691afdc3c1 --- .../android/inputmethod/latin/LatinIME.java | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 5ee539cc8..47e721fad 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -689,6 +689,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); } + // Callback for the TargetApplicationGetter @Override public void onTargetApplicationKnown(final ApplicationInfo info) { mTargetApplicationInfo = info; @@ -997,7 +998,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; } - public void commitTyped(final int separatorCode) { + private void commitTyped(final int separatorCode) { if (!mWordComposer.isComposingWord()) return; final CharSequence typedWord = mWordComposer.getTypedWord(); if (typedWord.length() > 0) { @@ -1013,6 +1014,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen updateSuggestionsOrPredictions(); } + // 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; @@ -1088,6 +1091,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET; } + // Callback for the SuggestionsView, to call when the "add to dictionary" hint is pressed. @Override public boolean addWordToUserDictionary(String word) { mUserDictionary.addWordToUserDictionary(word, 128); @@ -1285,6 +1289,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mConnection.endBatchEdit(); } + // Called from PointerTracker through the KeyboardActionListener interface @Override public void onTextInput(CharSequence text) { mConnection.beginBatchEdit(); @@ -1348,6 +1353,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } + // Called from PointerTracker through the KeyboardActionListener interface @Override public void onCancelInput() { // User released a finger outside any key @@ -1620,12 +1626,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen inputView.closing(); } - public boolean isShowingPunctuationList() { + // TODO: make this private + // Outside LatinIME, only used by the test suite. + /* package for tests */ boolean isShowingPunctuationList() { if (mSuggestionsView == null) return false; return mCurrentSettings.mSuggestPuncList == mSuggestionsView.getSuggestions(); } - public boolean isSuggestionsStripVisible() { + private boolean isSuggestionsStripVisible() { if (mSuggestionsView == null) return false; if (mSuggestionsView.isShowingAddToDictionaryHint()) @@ -1637,7 +1645,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return mCurrentSettings.isSuggestionsRequested(mDisplayOrientation); } - public void clearSuggestions() { + private void clearSuggestions() { setSuggestions(SuggestedWords.EMPTY, false); setAutoCorrectionIndicator(false); } @@ -1660,7 +1668,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - public void updateSuggestionsOrPredictions() { + private void updateSuggestionsOrPredictions() { mHandler.cancelUpdateSuggestionStrip(); // Check if we have a suggestion engine attached. @@ -1778,6 +1786,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } + // Called from SuggestionsView through the SuggestionsView.Listener interface @Override public void pickSuggestionManually(final int index, final CharSequence suggestion, final int x, final int y) { @@ -1888,7 +1897,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen separatorCode, prevWord); } - public void setPunctuationSuggestions() { + private void setPunctuationSuggestions() { if (mCurrentSettings.mBigramPredictionEnabled) { clearSuggestions(); } else { @@ -1996,16 +2005,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mHandler.postUpdateSuggestionStrip(); } + // Used by the RingCharBuffer public boolean isWordSeparator(int code) { return mCurrentSettings.isWordSeparator(code); } - public boolean preferCapitalization() { - return mWordComposer.isFirstCharCapitalized(); - } - // Notify that language or mode have been changed and toggleLanguage will update KeyboardID - // according to new language or mode. + // according to new language or mode. Called from SubtypeSwitcher. public void onRefreshKeyboard() { // When the device locale is changed in SetupWizard etc., this method may get called via // onConfigurationChanged before SoftInputWindow is shown. @@ -2022,16 +2028,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } // TODO: Remove this method from {@link LatinIME} and move {@link FeedbackManager} to - // {@link KeyboardSwitcher}. + // {@link KeyboardSwitcher}. Called from KeyboardSwitcher public void hapticAndAudioFeedback(final int primaryCode) { mFeedbackManager.hapticAndAudioFeedback(primaryCode, mKeyboardSwitcher.getKeyboardView()); } + // Callback called by PointerTracker through the KeyboardActionListener. This is called when a + // key is depressed; release matching call is onReleaseKey below. @Override public void onPressKey(int primaryCode) { mKeyboardSwitcher.onPressKey(primaryCode); } + // Callback by PointerTracker through the KeyboardActionListener. This is called when a key + // is released; press matching call is onPressKey above. @Override public void onReleaseKey(int primaryCode, boolean withSliding) { mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding); @@ -2076,6 +2086,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen launchSettingsClass(SettingsActivity.class); } + // Called from debug code only public void launchDebugSettings() { launchSettingsClass(DebugSettingsActivity.class); } From 966efe48891cbdd364d94f1e72fa0435ab8f2b77 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Mon, 9 Jul 2012 13:06:12 +0900 Subject: [PATCH 17/68] Fix a bug with suggestion behavior (A81) Bug: 6788235 Change-Id: I5a4212872e0fd3f9e80168fd3abd5c2b3bc4110f --- java/src/com/android/inputmethod/latin/Suggest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index f810eccf4..d7aa87dca 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -174,7 +174,7 @@ public class Suggest { : typedWord; LatinImeLogger.onAddSuggestedWord(typedWord, Dictionary.TYPE_USER_TYPED); - if (wordComposer.size() <= 1 && isCorrectionEnabled) { + if (wordComposer.size() <= 1) { // At first character typed, search only the bigrams if (!TextUtils.isEmpty(prevWordForBigram)) { for (final String key : mDictionaries.keySet()) { @@ -182,7 +182,7 @@ public class Suggest { suggestionsSet.addAll(dictionary.getBigrams(wordComposer, prevWordForBigram)); } } - } else if (wordComposer.size() > 1) { + } else { final WordComposer wordComposerForLookup; if (trailingSingleQuotesCount > 0) { wordComposerForLookup = new WordComposer(wordComposer); @@ -216,6 +216,11 @@ public class Suggest { mWhiteListDictionary.getWhitelistedWord(consideredWord); final boolean hasAutoCorrection; + // TODO: using isCorrectionEnabled here is not very good. It's probably useless, because + // any attempt to do auto-correction is already shielded with a test for this flag; at the + // same time, it feels wrong that the SuggestedWord object includes information about + // the current settings. It may also be useful to know, when the setting is off, whether + // the word *would* have been auto-corrected. if (!isCorrectionEnabled || !allowsToBeAutoCorrected || wordComposer.isMostlyCaps() || wordComposer.isResumed() || !hasMainDictionary()) { // If we don't have a main dictionary, we never want to auto-correct. The reason for From fb6eeeb35ad593926da9b7dc57335f0ba591570c Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Mon, 9 Jul 2012 15:14:19 +0900 Subject: [PATCH 18/68] Refactoring (A82) The user history dictionary should be the one knowing it does not suggest words beyond 2 characters, not Suggest. Change-Id: Ie85ec6116eb495e0c7f51108e4620c5ae536f4bf --- java/src/com/android/inputmethod/latin/Suggest.java | 5 ++--- .../inputmethod/latin/UserHistoryDictionary.java | 11 +++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index d7aa87dca..00ca5aff0 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -194,9 +194,8 @@ public class Suggest { } // At second character typed, search the unigrams (scores being affected by bigrams) for (final String key : mDictionaries.keySet()) { - // Skip UserUnigramDictionary and WhitelistDictionary to lookup - if (key.equals(Dictionary.TYPE_USER_HISTORY) - || key.equals(Dictionary.TYPE_WHITELIST)) + // Skip WhitelistDictionary to lookup + if (key.equals(Dictionary.TYPE_WHITELIST)) continue; final Dictionary dictionary = mDictionaries.get(key); suggestionsSet.addAll(dictionary.getWords( diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java index 73fa83f9a..d742e2190 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java @@ -27,9 +27,12 @@ import android.os.AsyncTask; import android.provider.BaseColumns; import android.util.Log; +import com.android.inputmethod.keyboard.ProximityInfo; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.UserHistoryForgettingCurveUtils.ForgettingCurveParams; import java.lang.ref.SoftReference; +import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; @@ -157,6 +160,14 @@ public class UserHistoryDictionary extends ExpandableDictionary { // super.close(); } + @Override + public ArrayList getWords(final WordComposer composer, + final CharSequence prevWord, final ProximityInfo proximityInfo) { + // User history unigrams are not used at this moment. Implement this method to make them + // useful. + return null; + } + /** * Return whether the passed charsequence is in the dictionary. */ From 1c6693a219d546816d70fd092f887b73a8041ea3 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Mon, 9 Jul 2012 15:18:30 +0900 Subject: [PATCH 19/68] Refactoring for whitelist (A83) Avoid special casing the whitelist dictionary by having it implement the interface it pretends it implements Change-Id: I8b873cb0f3fe13cefd32c8cb756a25c8ae16a2b4 --- java/src/com/android/inputmethod/latin/Suggest.java | 3 --- .../inputmethod/latin/WhitelistDictionary.java | 11 +++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 00ca5aff0..421a44cd2 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -194,9 +194,6 @@ public class Suggest { } // At second character typed, search the unigrams (scores being affected by bigrams) for (final String key : mDictionaries.keySet()) { - // Skip WhitelistDictionary to lookup - if (key.equals(Dictionary.TYPE_WHITELIST)) - continue; final Dictionary dictionary = mDictionaries.get(key); suggestionsSet.addAll(dictionary.getWords( wordComposerForLookup, prevWordForBigram, proximityInfo)); diff --git a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java index 3af22140e..24c94992f 100644 --- a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java +++ b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java @@ -22,8 +22,11 @@ import android.text.TextUtils; import android.util.Log; import android.util.Pair; +import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.LocaleUtils.RunInLocale; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import java.util.ArrayList; import java.util.HashMap; import java.util.Locale; @@ -88,6 +91,14 @@ public class WhitelistDictionary extends ExpandableDictionary { return null; } + @Override + public ArrayList getWords(final WordComposer composer, + final CharSequence prevWord, final ProximityInfo proximityInfo) { + // Whitelist does not supply suggestions (actually it should not even implement the + // Dictionary interface, as it responds to none of it, but it does for legacy reasons) + return null; + } + // See LatinIME#updateSuggestions. This breaks in the (queer) case that the whitelist // lists that word a should autocorrect to word b, and word c would autocorrect to // an upper-cased version of a. In this case, the way this return value is used would From c677b0071d51a277413079b30f2215605637aa6b Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Mon, 9 Jul 2012 15:54:19 +0900 Subject: [PATCH 20/68] Enhance behavior consistency (A84) Use the word the same way for suggestion and prediction. It makes little logical sense that the trailing single quotes be removed for suggestion lookup but not for prediction lookup. Change-Id: I0de4b5f7c5b4c1b4ba1817ff9653d7c03967146d --- .../android/inputmethod/latin/Suggest.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 421a44cd2..855971161 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -174,24 +174,25 @@ public class Suggest { : typedWord; LatinImeLogger.onAddSuggestedWord(typedWord, Dictionary.TYPE_USER_TYPED); - if (wordComposer.size() <= 1) { + final WordComposer wordComposerForLookup; + if (trailingSingleQuotesCount > 0) { + wordComposerForLookup = new WordComposer(wordComposer); + for (int i = trailingSingleQuotesCount - 1; i >= 0; --i) { + wordComposerForLookup.deleteLast(); + } + } else { + wordComposerForLookup = wordComposer; + } + if (wordComposerForLookup.size() <= 1) { // At first character typed, search only the bigrams if (!TextUtils.isEmpty(prevWordForBigram)) { for (final String key : mDictionaries.keySet()) { final Dictionary dictionary = mDictionaries.get(key); - suggestionsSet.addAll(dictionary.getBigrams(wordComposer, prevWordForBigram)); + suggestionsSet.addAll(dictionary.getBigrams(wordComposerForLookup, + prevWordForBigram)); } } } else { - final WordComposer wordComposerForLookup; - if (trailingSingleQuotesCount > 0) { - wordComposerForLookup = new WordComposer(wordComposer); - for (int i = trailingSingleQuotesCount - 1; i >= 0; --i) { - wordComposerForLookup.deleteLast(); - } - } else { - wordComposerForLookup = wordComposer; - } // At second character typed, search the unigrams (scores being affected by bigrams) for (final String key : mDictionaries.keySet()) { final Dictionary dictionary = mDictionaries.get(key); From 2a37fb9d30848aee42757546e8478cb7a9e45bc6 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 10 Jul 2012 18:43:42 +0900 Subject: [PATCH 21/68] Refresh the cached single quotes count on commit Change-Id: I9df5cf95c14da2e11ac709ca5e32dc7db3b02c37 --- java/src/com/android/inputmethod/latin/WordComposer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index bfa41c784..b55c1a546 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -296,6 +296,7 @@ public class WordComposer { lastComposedWord.deactivate(); } mTypedWord.setLength(0); + mTrailingSingleQuotesCount = 0; refreshSize(); mAutoCorrection = null; mIsResumed = false; From 82009901eaa1fd0da95b25c900f8ff12fda9e679 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Mon, 9 Jul 2012 16:34:49 +0900 Subject: [PATCH 22/68] Add a consolidated method to the Dictionary interface (A85) Change-Id: I5d79021e69cc738e3013e31764ab0a59e15decdf --- .../android/inputmethod/latin/Dictionary.java | 21 +++++++++++++++++++ .../android/inputmethod/latin/Suggest.java | 6 +++--- .../AndroidWordLevelSpellCheckerSession.java | 5 +++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index 0835450c1..5229d14fa 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin; +import android.text.TextUtils; + import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; @@ -49,6 +51,25 @@ public abstract class Dictionary { mDictType = dictType; } + /** + * Searches for suggestions for a given context. For the moment the context is only the + * previous word. + * @param composer the key sequence to match with coordinate info, as a WordComposer + * @param prevWord the previous word, or null if none + * @param proximityInfo the object for key proximity. May be ignored by some implementations. + * @return the list of suggestions (possibly null if none) + */ + // TODO: pass more context than just the previous word, to enable better suggestions (n-gram + // and more) + public ArrayList getSuggestions(final WordComposer composer, + final CharSequence prevWord, final ProximityInfo proximityInfo) { + if (composer.size() <= 1) { + return TextUtils.isEmpty(prevWord) ? null : getBigrams(composer, prevWord); + } else { + return getWords(composer, prevWord, proximityInfo); + } + } + /** * Searches for words in the dictionary that match the characters in the composer. Matched * words are returned as an ArrayList. diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 855971161..69b5f055a 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -188,15 +188,15 @@ public class Suggest { if (!TextUtils.isEmpty(prevWordForBigram)) { for (final String key : mDictionaries.keySet()) { final Dictionary dictionary = mDictionaries.get(key); - suggestionsSet.addAll(dictionary.getBigrams(wordComposerForLookup, - prevWordForBigram)); + suggestionsSet.addAll(dictionary.getSuggestions(wordComposerForLookup, + prevWordForBigram, proximityInfo)); } } } else { // At second character typed, search the unigrams (scores being affected by bigrams) for (final String key : mDictionaries.keySet()) { final Dictionary dictionary = mDictionaries.get(key); - suggestionsSet.addAll(dictionary.getWords( + suggestionsSet.addAll(dictionary.getSuggestions( wordComposerForLookup, prevWordForBigram, proximityInfo)); } } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java index c94e0081c..0171dc06d 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java @@ -240,8 +240,9 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { if (null == dictInfo) { return AndroidSpellCheckerService.getNotInDictEmptySuggestions(); } - final ArrayList suggestions = dictInfo.mDictionary.getWords( - composer, prevWord, dictInfo.mProximityInfo); + final ArrayList suggestions = + dictInfo.mDictionary.getSuggestions(composer, prevWord, + dictInfo.mProximityInfo); for (final SuggestedWordInfo suggestion : suggestions) { final String suggestionStr = suggestion.mWord.toString(); suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0, From 4e42e378fa41cfacf2c393a9428d75f6c6a0d7a8 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Mon, 9 Jul 2012 17:35:47 +0900 Subject: [PATCH 23/68] Move stuff around for readability (A86) Change-Id: I5f4a18e43f3012acf96978d625325bf7c69c9c80 --- .../latin/ExpandableDictionary.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 76213c0da..05f3c0d94 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -263,6 +263,27 @@ public class ExpandableDictionary extends Dictionary { return suggestions; } + // @VisibleForTesting + boolean reloadDictionaryIfRequired() { + synchronized (mUpdatingLock) { + // If we need to update, start off a background task + if (mRequiresReload) startDictionaryLoadingTaskLocked(); + // Currently updating contacts, don't return any results. + return mUpdatingDictionary; + } + } + + @Override + public ArrayList getBigrams(final WordComposer codes, + final CharSequence previousWord) { + if (!reloadDictionaryIfRequired()) { + final ArrayList suggestions = new ArrayList(); + runBigramReverseLookUp(previousWord, suggestions); + return suggestions; + } + return null; + } + protected final ArrayList getWordsInner(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { final ArrayList suggestions = new ArrayList(); @@ -589,16 +610,6 @@ public class ExpandableDictionary extends Dictionary { return searchWord(childNode.mChildren, word, depth + 1, childNode); } - // @VisibleForTesting - boolean reloadDictionaryIfRequired() { - synchronized (mUpdatingLock) { - // If we need to update, start off a background task - if (mRequiresReload) startDictionaryLoadingTaskLocked(); - // Currently updating contacts, don't return any results. - return mUpdatingDictionary; - } - } - private void runBigramReverseLookUp(final CharSequence previousWord, final ArrayList suggestions) { // Search for the lowercase version of the word only, because that's where bigrams @@ -610,17 +621,6 @@ public class ExpandableDictionary extends Dictionary { } } - @Override - public ArrayList getBigrams(final WordComposer codes, - final CharSequence previousWord) { - if (!reloadDictionaryIfRequired()) { - final ArrayList suggestions = new ArrayList(); - runBigramReverseLookUp(previousWord, suggestions); - return suggestions; - } - return null; - } - /** * Used for testing purposes and in the spell checker * This function will wait for loading from database to be done From 0f57bdc0e5d1ecebc00bff36d5ce544f343b5589 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Mon, 9 Jul 2012 17:39:34 +0900 Subject: [PATCH 24/68] Factorize code (A87) Why was this copy-pasted :( Change-Id: I6a537c56425ad039d7301a5fe1e0485784f07914 --- .../latin/ExpandableDictionary.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 05f3c0d94..55a25777a 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -249,12 +249,7 @@ public class ExpandableDictionary extends Dictionary { @Override public ArrayList getWords(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { - synchronized (mUpdatingLock) { - // If we need to update, start off a background task - if (mRequiresReload) startDictionaryLoadingTaskLocked(); - // Currently updating contacts, don't return any results. - if (mUpdatingDictionary) return null; - } + if (reloadDictionaryIfRequired()) return null; if (codes.size() >= BinaryDictionary.MAX_WORD_LENGTH) { return null; } @@ -263,12 +258,13 @@ public class ExpandableDictionary extends Dictionary { return suggestions; } + // This reloads the dictionary if required, and returns whether it's currently updating its + // contents or not. // @VisibleForTesting boolean reloadDictionaryIfRequired() { synchronized (mUpdatingLock) { // If we need to update, start off a background task if (mRequiresReload) startDictionaryLoadingTaskLocked(); - // Currently updating contacts, don't return any results. return mUpdatingDictionary; } } @@ -276,12 +272,10 @@ public class ExpandableDictionary extends Dictionary { @Override public ArrayList getBigrams(final WordComposer codes, final CharSequence previousWord) { - if (!reloadDictionaryIfRequired()) { - final ArrayList suggestions = new ArrayList(); - runBigramReverseLookUp(previousWord, suggestions); - return suggestions; - } - return null; + if (reloadDictionaryIfRequired()) return null; + final ArrayList suggestions = new ArrayList(); + runBigramReverseLookUp(previousWord, suggestions); + return suggestions; } protected final ArrayList getWordsInner(final WordComposer codes, From a69f12a246b6c047faf7002a57b1cebc3721d731 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Mon, 9 Jul 2012 17:58:40 +0900 Subject: [PATCH 25/68] Reduce method visibility (A88) Change-Id: I29d6afbcba0998558c9b19287a460d9f0e410994 --- java/src/com/android/inputmethod/latin/BinaryDictionary.java | 4 ++-- java/src/com/android/inputmethod/latin/Dictionary.java | 4 ++-- .../com/android/inputmethod/latin/DictionaryCollection.java | 4 ++-- .../android/inputmethod/latin/ExpandableBinaryDictionary.java | 4 ++-- .../com/android/inputmethod/latin/ExpandableDictionary.java | 4 ++-- .../latin/SynchronouslyLoadedContactsBinaryDictionary.java | 2 +- .../latin/SynchronouslyLoadedUserBinaryDictionary.java | 2 +- .../com/android/inputmethod/latin/UserHistoryDictionary.java | 2 +- .../com/android/inputmethod/latin/WhitelistDictionary.java | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index ae415d0ab..15646b871 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -106,7 +106,7 @@ public class BinaryDictionary extends Dictionary { } @Override - public ArrayList getBigrams(final WordComposer codes, + protected ArrayList getBigrams(final WordComposer codes, final CharSequence previousWord) { if (mNativeDict == 0) return null; @@ -145,7 +145,7 @@ public class BinaryDictionary extends Dictionary { // proximityInfo and/or prevWordForBigrams may not be null. @Override - public ArrayList getWords(final WordComposer codes, + protected ArrayList getWords(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { final int count = getSuggestions(codes, prevWordForBigrams, proximityInfo, mOutputChars, mScores, mSpaceIndices); diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index 5229d14fa..4b02e11bf 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -78,7 +78,7 @@ public abstract class Dictionary { * @param proximityInfo the object for key proximity. May be ignored by some implementations. * @return the list of suggestions */ - abstract public ArrayList getWords(final WordComposer composer, + abstract protected ArrayList getWords(final WordComposer composer, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo); /** @@ -87,7 +87,7 @@ public abstract class Dictionary { * @param previousWord the word before * @return the list of suggestions */ - public abstract ArrayList getBigrams(final WordComposer composer, + abstract protected ArrayList getBigrams(final WordComposer composer, final CharSequence previousWord); /** diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index dcc53c59f..d2ddebf3e 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -55,7 +55,7 @@ public class DictionaryCollection extends Dictionary { } @Override - public ArrayList getWords(final WordComposer composer, + protected ArrayList getWords(final WordComposer composer, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { final CopyOnWriteArrayList dictionaries = mDictionaries; if (dictionaries.isEmpty()) return null; @@ -74,7 +74,7 @@ public class DictionaryCollection extends Dictionary { } @Override - public ArrayList getBigrams(final WordComposer composer, + protected ArrayList getBigrams(final WordComposer composer, final CharSequence previousWord) { final CopyOnWriteArrayList dictionaries = mDictionaries; if (dictionaries.isEmpty()) return null; diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 1cda9f257..40d46a873 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -192,7 +192,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { } @Override - public ArrayList getWords(final WordComposer codes, + protected ArrayList getWords(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { asyncReloadDictionaryIfRequired(); return getWordsInner(codes, prevWordForBigrams, proximityInfo); @@ -215,7 +215,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { } @Override - public ArrayList getBigrams(final WordComposer codes, + protected ArrayList getBigrams(final WordComposer codes, final CharSequence previousWord) { asyncReloadDictionaryIfRequired(); return getBigramsInner(codes, previousWord); diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 55a25777a..a3c183c27 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -247,7 +247,7 @@ public class ExpandableDictionary extends Dictionary { } @Override - public ArrayList getWords(final WordComposer codes, + protected ArrayList getWords(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { if (reloadDictionaryIfRequired()) return null; if (codes.size() >= BinaryDictionary.MAX_WORD_LENGTH) { @@ -270,7 +270,7 @@ public class ExpandableDictionary extends Dictionary { } @Override - public ArrayList getBigrams(final WordComposer codes, + protected ArrayList getBigrams(final WordComposer codes, final CharSequence previousWord) { if (reloadDictionaryIfRequired()) return null; final ArrayList suggestions = new ArrayList(); diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java index 9b20bd690..59bd249e7 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java @@ -32,7 +32,7 @@ public class SynchronouslyLoadedContactsBinaryDictionary extends ContactsBinaryD } @Override - public synchronized ArrayList getWords(final WordComposer codes, + protected synchronized ArrayList getWords(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { syncReloadDictionaryIfRequired(); return getWordsInner(codes, prevWordForBigrams, proximityInfo); diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java index 5b2a6edec..7abc251be 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java @@ -35,7 +35,7 @@ public class SynchronouslyLoadedUserBinaryDictionary extends UserBinaryDictionar } @Override - public synchronized ArrayList getWords(final WordComposer codes, + protected synchronized ArrayList getWords(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { syncReloadDictionaryIfRequired(); return getWordsInner(codes, prevWordForBigrams, proximityInfo); diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java index d742e2190..e26349172 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java @@ -161,7 +161,7 @@ public class UserHistoryDictionary extends ExpandableDictionary { } @Override - public ArrayList getWords(final WordComposer composer, + protected ArrayList getWords(final WordComposer composer, final CharSequence prevWord, final ProximityInfo proximityInfo) { // User history unigrams are not used at this moment. Implement this method to make them // useful. diff --git a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java index 24c94992f..be2c80e0e 100644 --- a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java +++ b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java @@ -92,7 +92,7 @@ public class WhitelistDictionary extends ExpandableDictionary { } @Override - public ArrayList getWords(final WordComposer composer, + protected ArrayList getWords(final WordComposer composer, final CharSequence prevWord, final ProximityInfo proximityInfo) { // Whitelist does not supply suggestions (actually it should not even implement the // Dictionary interface, as it responds to none of it, but it does for legacy reasons) From b30d2185f24e3d531f5d46249e7c97391705e469 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Mon, 9 Jul 2012 18:25:27 +0900 Subject: [PATCH 26/68] Implement the common Dictionary interface (A89) This will de-duplicate a lot of existing code. Change-Id: Idaffb2fde23b9741f057bcb2ecb3dde9d12ea5c5 --- .../inputmethod/latin/BinaryDictionary.java | 12 ++++++++++ .../android/inputmethod/latin/Dictionary.java | 12 ++++------ .../latin/DictionaryCollection.java | 21 ++++++++++++++++++ .../latin/ExpandableBinaryDictionary.java | 19 ++++++++++++++++ .../latin/ExpandableDictionary.java | 22 +++++++++++++++++++ 5 files changed, 78 insertions(+), 8 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 15646b871..03e286240 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -105,6 +105,17 @@ public class BinaryDictionary extends Dictionary { TYPED_LETTER_MULTIPLIER, FULL_WORD_SCORE_MULTIPLIER, MAX_WORD_LENGTH, MAX_WORDS); } + @Override + public ArrayList getSuggestions(final WordComposer composer, + final CharSequence prevWord, final ProximityInfo proximityInfo) { + if (composer.size() <= 1) { + return TextUtils.isEmpty(prevWord) ? null : getBigrams(composer, prevWord); + } else { + return getWords(composer, prevWord, proximityInfo); + } + } + + // TODO: rename this to getBigramsInternal, then move to native code @Override protected ArrayList getBigrams(final WordComposer codes, final CharSequence previousWord) { @@ -143,6 +154,7 @@ public class BinaryDictionary extends Dictionary { return suggestions; } + // TODO: rename this to getWordsInternal, then move to native code // proximityInfo and/or prevWordForBigrams may not be null. @Override protected ArrayList getWords(final WordComposer codes, diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index 4b02e11bf..38ef00da7 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -61,14 +61,8 @@ public abstract class Dictionary { */ // TODO: pass more context than just the previous word, to enable better suggestions (n-gram // and more) - public ArrayList getSuggestions(final WordComposer composer, - final CharSequence prevWord, final ProximityInfo proximityInfo) { - if (composer.size() <= 1) { - return TextUtils.isEmpty(prevWord) ? null : getBigrams(composer, prevWord); - } else { - return getWords(composer, prevWord, proximityInfo); - } - } + abstract public ArrayList getSuggestions(final WordComposer composer, + final CharSequence prevWord, final ProximityInfo proximityInfo); /** * Searches for words in the dictionary that match the characters in the composer. Matched @@ -78,6 +72,7 @@ public abstract class Dictionary { * @param proximityInfo the object for key proximity. May be ignored by some implementations. * @return the list of suggestions */ + // TODO: remove this abstract protected ArrayList getWords(final WordComposer composer, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo); @@ -87,6 +82,7 @@ public abstract class Dictionary { * @param previousWord the word before * @return the list of suggestions */ + // TODO: remove this abstract protected ArrayList getBigrams(final WordComposer composer, final CharSequence previousWord); diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index d2ddebf3e..7c589ef17 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -54,6 +54,26 @@ public class DictionaryCollection extends Dictionary { mDictionaries.removeAll(Collections.singleton(null)); } + @Override + public ArrayList getSuggestions(final WordComposer composer, + final CharSequence prevWord, final ProximityInfo proximityInfo) { + final CopyOnWriteArrayList dictionaries = mDictionaries; + if (dictionaries.isEmpty()) return null; + // To avoid creating unnecessary objects, we get the list out of the first + // dictionary and add the rest to it if not null, hence the get(0) + ArrayList suggestions = dictionaries.get(0).getSuggestions(composer, + prevWord, proximityInfo); + if (null == suggestions) suggestions = new ArrayList(); + final int length = dictionaries.size(); + for (int i = 0; i < length; ++ i) { + final ArrayList sugg = dictionaries.get(i).getSuggestions(composer, + prevWord, proximityInfo); + if (null != sugg) suggestions.addAll(sugg); + } + return suggestions; + } + + // TODO: remove this @Override protected ArrayList getWords(final WordComposer composer, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { @@ -73,6 +93,7 @@ public class DictionaryCollection extends Dictionary { return suggestions; } + // TODO: remove this @Override protected ArrayList getBigrams(final WordComposer composer, final CharSequence previousWord) { diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 40d46a873..dd949f121 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin; import android.content.Context; import android.os.SystemClock; +import android.text.TextUtils; import android.util.Log; import com.android.inputmethod.keyboard.ProximityInfo; @@ -191,6 +192,23 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { mFusionDictionary.setBigram(prevWord, word, frequency); } + @Override + public ArrayList getSuggestions(final WordComposer composer, + final CharSequence prevWord, final ProximityInfo proximityInfo) { + asyncReloadDictionaryIfRequired(); + if (mLocalDictionaryController.tryLock()) { + try { + if (mBinaryDictionary != null) { + return mBinaryDictionary.getSuggestions(composer, prevWord, proximityInfo); + } + } finally { + mLocalDictionaryController.unlock(); + } + } + return null; + } + + // TODO: remove this @Override protected ArrayList getWords(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { @@ -214,6 +232,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { return null; } + // TODO: remove this @Override protected ArrayList getBigrams(final WordComposer codes, final CharSequence previousWord) { diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index a3c183c27..6cd4f65cb 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -17,6 +17,7 @@ package com.android.inputmethod.latin; import android.content.Context; +import android.text.TextUtils; import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; @@ -246,6 +247,26 @@ public class ExpandableDictionary extends Dictionary { addWordRec(childNode.mChildren, word, depth + 1, shortcutTarget, frequency, childNode); } + @Override + public ArrayList getSuggestions(final WordComposer composer, + final CharSequence prevWord, final ProximityInfo proximityInfo) { + if (reloadDictionaryIfRequired()) return null; + if (composer.size() <= 1) { + if (composer.size() >= BinaryDictionary.MAX_WORD_LENGTH) { + return null; + } + final ArrayList suggestions = + getWordsInner(composer, prevWord, proximityInfo); + return suggestions; + } else { + if (TextUtils.isEmpty(prevWord)) return null; + final ArrayList suggestions = new ArrayList(); + runBigramReverseLookUp(prevWord, suggestions); + return suggestions; + } + } + + // TODO: remove this @Override protected ArrayList getWords(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { @@ -269,6 +290,7 @@ public class ExpandableDictionary extends Dictionary { } } + // TODO: remove this @Override protected ArrayList getBigrams(final WordComposer codes, final CharSequence previousWord) { From f5943153ad2ba611feec916119dca2343a1ef6de Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Mon, 9 Jul 2012 20:13:22 +0900 Subject: [PATCH 27/68] Cleanup old methods (A90) Change-Id: I5435cef8ac6be523934ffa394952cb120c8e89d6 --- .../inputmethod/latin/BinaryDictionary.java | 14 +++--- .../android/inputmethod/latin/Dictionary.java | 22 --------- .../latin/DictionaryCollection.java | 40 ---------------- .../latin/ExpandableBinaryDictionary.java | 47 ------------------- .../latin/ExpandableDictionary.java | 25 +--------- ...onouslyLoadedContactsBinaryDictionary.java | 4 +- ...nchronouslyLoadedUserBinaryDictionary.java | 4 +- .../latin/UserHistoryDictionary.java | 6 +-- .../latin/WhitelistDictionary.java | 5 +- 9 files changed, 16 insertions(+), 151 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 03e286240..5c91a1077 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -109,15 +109,14 @@ public class BinaryDictionary extends Dictionary { public ArrayList getSuggestions(final WordComposer composer, final CharSequence prevWord, final ProximityInfo proximityInfo) { if (composer.size() <= 1) { - return TextUtils.isEmpty(prevWord) ? null : getBigrams(composer, prevWord); + return TextUtils.isEmpty(prevWord) ? null : getBigramsInternal(composer, prevWord); } else { - return getWords(composer, prevWord, proximityInfo); + return getWordsInternal(composer, prevWord, proximityInfo); } } - // TODO: rename this to getBigramsInternal, then move to native code - @Override - protected ArrayList getBigrams(final WordComposer codes, + // TODO: move to native code + private ArrayList getBigramsInternal(final WordComposer codes, final CharSequence previousWord) { if (mNativeDict == 0) return null; @@ -154,10 +153,9 @@ public class BinaryDictionary extends Dictionary { return suggestions; } - // TODO: rename this to getWordsInternal, then move to native code + // TODO: move to native code // proximityInfo and/or prevWordForBigrams may not be null. - @Override - protected ArrayList getWords(final WordComposer codes, + private ArrayList getWordsInternal(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { final int count = getSuggestions(codes, prevWordForBigrams, proximityInfo, mOutputChars, mScores, mSpaceIndices); diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index 38ef00da7..fd40aa6da 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -64,28 +64,6 @@ public abstract class Dictionary { abstract public ArrayList getSuggestions(final WordComposer composer, final CharSequence prevWord, final ProximityInfo proximityInfo); - /** - * Searches for words in the dictionary that match the characters in the composer. Matched - * words are returned as an ArrayList. - * @param composer the key sequence to match with coordinate info, as a WordComposer - * @param prevWordForBigrams the previous word, or null if none - * @param proximityInfo the object for key proximity. May be ignored by some implementations. - * @return the list of suggestions - */ - // TODO: remove this - abstract protected ArrayList getWords(final WordComposer composer, - final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo); - - /** - * Searches for pairs in the bigram dictionary that matches the previous word. - * @param composer the key sequence to match - * @param previousWord the word before - * @return the list of suggestions - */ - // TODO: remove this - abstract protected ArrayList getBigrams(final WordComposer composer, - final CharSequence previousWord); - /** * Checks if the given word occurs in the dictionary * @param word the word to search for. The search should be case-insensitive. diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index 7c589ef17..88ac07d7a 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -73,46 +73,6 @@ public class DictionaryCollection extends Dictionary { return suggestions; } - // TODO: remove this - @Override - protected ArrayList getWords(final WordComposer composer, - final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { - final CopyOnWriteArrayList dictionaries = mDictionaries; - if (dictionaries.isEmpty()) return null; - // To avoid creating unnecessary objects, we get the list out of the first - // dictionary and add the rest to it if not null, hence the get(0) - ArrayList suggestions = dictionaries.get(0).getWords(composer, - prevWordForBigrams, proximityInfo); - if (null == suggestions) suggestions = new ArrayList(); - final int length = dictionaries.size(); - for (int i = 0; i < length; ++ i) { - final ArrayList sugg = dictionaries.get(i).getWords(composer, - prevWordForBigrams, proximityInfo); - if (null != sugg) suggestions.addAll(sugg); - } - return suggestions; - } - - // TODO: remove this - @Override - protected ArrayList getBigrams(final WordComposer composer, - final CharSequence previousWord) { - final CopyOnWriteArrayList dictionaries = mDictionaries; - if (dictionaries.isEmpty()) return null; - // To avoid creating unnecessary objects, we get the list out of the first - // dictionary and add the rest to it if not null, hence the get(0) - ArrayList suggestions = dictionaries.get(0).getBigrams(composer, - previousWord); - if (null == suggestions) suggestions = new ArrayList(); - final int length = dictionaries.size(); - for (int i = 0; i < length; ++ i) { - final ArrayList sugg = - dictionaries.get(i).getBigrams(composer, previousWord); - if (null != sugg) suggestions.addAll(sugg); - } - return suggestions; - } - @Override public boolean isValidWord(CharSequence word) { for (int i = mDictionaries.size() - 1; i >= 0; --i) diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index dd949f121..016530abb 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -16,7 +16,6 @@ package com.android.inputmethod.latin; import android.content.Context; import android.os.SystemClock; -import android.text.TextUtils; import android.util.Log; import com.android.inputmethod.keyboard.ProximityInfo; @@ -208,52 +207,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { return null; } - // TODO: remove this - @Override - protected ArrayList getWords(final WordComposer codes, - final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { - asyncReloadDictionaryIfRequired(); - return getWordsInner(codes, prevWordForBigrams, proximityInfo); - } - - protected final ArrayList getWordsInner(final WordComposer codes, - final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { - // Ensure that there are no concurrent calls to getWords. If there are, do nothing and - // return. - if (mLocalDictionaryController.tryLock()) { - try { - if (mBinaryDictionary != null) { - return mBinaryDictionary.getWords(codes, prevWordForBigrams, proximityInfo); - } - } finally { - mLocalDictionaryController.unlock(); - } - } - return null; - } - - // TODO: remove this - @Override - protected ArrayList getBigrams(final WordComposer codes, - final CharSequence previousWord) { - asyncReloadDictionaryIfRequired(); - return getBigramsInner(codes, previousWord); - } - - protected ArrayList getBigramsInner(final WordComposer codes, - final CharSequence previousWord) { - if (mLocalDictionaryController.tryLock()) { - try { - if (mBinaryDictionary != null) { - return mBinaryDictionary.getBigrams(codes, previousWord); - } - } finally { - mLocalDictionaryController.unlock(); - } - } - return null; - } - @Override public boolean isValidWord(final CharSequence word) { asyncReloadDictionaryIfRequired(); diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 6cd4f65cb..5d7995dc2 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -266,19 +266,6 @@ public class ExpandableDictionary extends Dictionary { } } - // TODO: remove this - @Override - protected ArrayList getWords(final WordComposer codes, - final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { - if (reloadDictionaryIfRequired()) return null; - if (codes.size() >= BinaryDictionary.MAX_WORD_LENGTH) { - return null; - } - final ArrayList suggestions = - getWordsInner(codes, prevWordForBigrams, proximityInfo); - return suggestions; - } - // This reloads the dictionary if required, and returns whether it's currently updating its // contents or not. // @VisibleForTesting @@ -290,17 +277,7 @@ public class ExpandableDictionary extends Dictionary { } } - // TODO: remove this - @Override - protected ArrayList getBigrams(final WordComposer codes, - final CharSequence previousWord) { - if (reloadDictionaryIfRequired()) return null; - final ArrayList suggestions = new ArrayList(); - runBigramReverseLookUp(previousWord, suggestions); - return suggestions; - } - - protected final ArrayList getWordsInner(final WordComposer codes, + protected ArrayList getWordsInner(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { final ArrayList suggestions = new ArrayList(); mInputLength = codes.size(); diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java index 59bd249e7..bdd988df2 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java @@ -32,10 +32,10 @@ public class SynchronouslyLoadedContactsBinaryDictionary extends ContactsBinaryD } @Override - protected synchronized ArrayList getWords(final WordComposer codes, + public synchronized ArrayList getSuggestions(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { syncReloadDictionaryIfRequired(); - return getWordsInner(codes, prevWordForBigrams, proximityInfo); + return super.getSuggestions(codes, prevWordForBigrams, proximityInfo); } @Override diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java index 7abc251be..b8cfddd4e 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java @@ -35,10 +35,10 @@ public class SynchronouslyLoadedUserBinaryDictionary extends UserBinaryDictionar } @Override - protected synchronized ArrayList getWords(final WordComposer codes, + public synchronized ArrayList getSuggestions(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { syncReloadDictionaryIfRequired(); - return getWordsInner(codes, prevWordForBigrams, proximityInfo); + return super.getSuggestions(codes, prevWordForBigrams, proximityInfo); } @Override diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java index e26349172..3bb670c9a 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java @@ -161,10 +161,10 @@ public class UserHistoryDictionary extends ExpandableDictionary { } @Override - protected ArrayList getWords(final WordComposer composer, + protected ArrayList getWordsInner(final WordComposer composer, final CharSequence prevWord, final ProximityInfo proximityInfo) { - // User history unigrams are not used at this moment. Implement this method to make them - // useful. + // Inhibit suggestions (not predictions) for user history for now. Removing this method + // is enough to use it through the standard ExpandableDictionary way. return null; } diff --git a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java index be2c80e0e..14476dcf0 100644 --- a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java +++ b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java @@ -92,10 +92,9 @@ public class WhitelistDictionary extends ExpandableDictionary { } @Override - protected ArrayList getWords(final WordComposer composer, + public ArrayList getSuggestions(final WordComposer composer, final CharSequence prevWord, final ProximityInfo proximityInfo) { - // Whitelist does not supply suggestions (actually it should not even implement the - // Dictionary interface, as it responds to none of it, but it does for legacy reasons) + // Whitelist does not supply any suggestions or predictions. return null; } From 5e573a1f0a63c017c7b0e4c4314235bd87c9363c Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 10 Jul 2012 19:31:36 +0900 Subject: [PATCH 28/68] Remove a useless parameter (A91A) Change-Id: I1d1758048649ef337875a5141d825569af7ad38c --- java/src/com/android/inputmethod/latin/LatinIME.java | 2 +- java/src/com/android/inputmethod/latin/Suggest.java | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 47e721fad..6d902b89a 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1696,7 +1696,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mWordComposer.isComposingWord() ? 2 : 1); SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer, prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), - mCurrentSettings.mCorrectionEnabled, !mWordComposer.isComposingWord()); + mCurrentSettings.mCorrectionEnabled); suggestedWords = maybeRetrieveOlderSuggestions(typedWord, suggestedWords); if (null != suggestedWords && suggestedWords.size() > 0) { diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 69b5f055a..c4a7787fa 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -156,10 +156,8 @@ public class Suggest { // TODO: cleanup dictionaries looking up and suggestions building with SuggestedWords.Builder public SuggestedWords getSuggestedWords( final WordComposer wordComposer, CharSequence prevWordForBigram, - final ProximityInfo proximityInfo, final boolean isCorrectionEnabled, - // TODO: remove isPrediction parameter. It effectively means the same thing - // as wordComposer.size() <= 1 - final boolean isPrediction) { + final ProximityInfo proximityInfo, final boolean isCorrectionEnabled) { + final boolean isPrediction = !wordComposer.isComposingWord(); LatinImeLogger.onStartSuggestion(prevWordForBigram); final boolean isFirstCharCapitalized = !isPrediction && wordComposer.isFirstCharCapitalized(); From d82dcdc9246b340c4b355e34efc6079f3278efa6 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Tue, 10 Jul 2012 10:46:13 +0900 Subject: [PATCH 29/68] Add batch input dictionary lookup Change-Id: I4da3c976838e8eb56c9ec80aafaaf54d759b7981 --- .../inputmethod/latin/BinaryDictionary.java | 31 ++++++------- .../android/inputmethod/latin/Suggest.java | 46 ++++++++++++++++++- .../inputmethod/latin/WordComposer.java | 14 ++++++ 3 files changed, 73 insertions(+), 18 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 5c91a1077..4cae6bcdb 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -188,32 +188,31 @@ public class BinaryDictionary extends Dictionary { char[] outputChars, int[] scores, int[] spaceIndices) { if (!isValidDictionary()) return -1; - final int codesSize = codes.size(); - // Won't deal with really long words. - if (codesSize > MAX_WORD_LENGTH - 1) return -1; - Arrays.fill(mInputCodes, WordComposer.NOT_A_CODE); - for (int i = 0; i < codesSize; i++) { - mInputCodes[i] = codes.getCodeAt(i); - } Arrays.fill(outputChars, (char) 0); Arrays.fill(scores, 0); + final InputPointers ips = codes.getInputPointers(); + final boolean isGesture = codes.isBatchMode(); + final int codesSize; + if (isGesture) { + codesSize = ips.getPointerSize(); + } else { + codesSize = codes.size(); + // Won't deal with really long words. + if (codesSize > MAX_WORD_LENGTH - 1) return -1; + for (int i = 0; i < codesSize; i++) { + mInputCodes[i] = codes.getCodeAt(i); + } + } + // TODO: toLowerCase in the native code final int[] prevWordCodePointArray = (null == prevWordForBigrams) ? null : StringUtils.toCodePointArray(prevWordForBigrams.toString()); - int[] emptyArray = new int[codesSize]; - Arrays.fill(emptyArray, 0); - - //final int commitPoint = codes.getCommitPoint(); - //codes.clearCommitPoint(); - - final InputPointers ips = codes.getInputPointers(); - return getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), - mInputCodes, codesSize, 0 /* unused */, false, prevWordCodePointArray, + mInputCodes, codesSize, 0 /* unused */, isGesture, prevWordCodePointArray, mUseFullEditDistance, outputChars, scores, spaceIndices); } diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index c4a7787fa..31c6000e3 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -153,12 +153,23 @@ public class Suggest { mAutoCorrectionThreshold = threshold; } - // TODO: cleanup dictionaries looking up and suggestions building with SuggestedWords.Builder public SuggestedWords getSuggestedWords( final WordComposer wordComposer, CharSequence prevWordForBigram, final ProximityInfo proximityInfo, final boolean isCorrectionEnabled) { - final boolean isPrediction = !wordComposer.isComposingWord(); LatinImeLogger.onStartSuggestion(prevWordForBigram); + if (wordComposer.isBatchMode()) { + return getSuggestedWordsForBatchInput(wordComposer, prevWordForBigram, proximityInfo); + } else { + return getSuggestedWordsForTypingInput(wordComposer, prevWordForBigram, proximityInfo, + isCorrectionEnabled); + } + } + + // Retrieves suggestions for the typing input. + private SuggestedWords getSuggestedWordsForTypingInput( + final WordComposer wordComposer, CharSequence prevWordForBigram, + final ProximityInfo proximityInfo, final boolean isCorrectionEnabled) { + final boolean isPrediction = !wordComposer.isComposingWord(); final boolean isFirstCharCapitalized = !isPrediction && wordComposer.isFirstCharCapitalized(); final boolean isAllUpperCase = !isPrediction && wordComposer.isAllUpperCase(); @@ -285,6 +296,37 @@ public class Suggest { isPrediction); } + // Retrieves suggestions for the batch input. + private SuggestedWords getSuggestedWordsForBatchInput( + final WordComposer wordComposer, CharSequence prevWordForBigram, + final ProximityInfo proximityInfo) { + final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator, + MAX_SUGGESTIONS); + + // At second character typed, search the unigrams (scores being affected by bigrams) + for (final String key : mDictionaries.keySet()) { + // Skip UserUnigramDictionary and WhitelistDictionary to lookup + if (key.equals(Dictionary.TYPE_USER_HISTORY) + || key.equals(Dictionary.TYPE_WHITELIST)) { + continue; + } + final Dictionary dictionary = mDictionaries.get(key); + suggestionsSet.addAll(dictionary.getSuggestions( + wordComposer, prevWordForBigram, proximityInfo)); + } + + final ArrayList suggestionsContainer = + new ArrayList(suggestionsSet); + + SuggestedWordInfo.removeDups(suggestionsContainer); + return new SuggestedWords(suggestionsContainer, + true /* typedWordValid */, + true /* willAutoCorrect */, + false /* isPunctuationSuggestions */, + false /* isObsoleteSuggestions */, + false /* isPrediction */); + } + private static ArrayList getSuggestionsInfoListWithDebugInfo( final String typedWord, final ArrayList suggestions) { final SuggestedWordInfo typedWordInfo = suggestions.get(0); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index b55c1a546..46c892afe 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -37,6 +37,7 @@ public class WordComposer { private final StringBuilder mTypedWord; private CharSequence mAutoCorrection; private boolean mIsResumed; + private boolean mIsBatchMode; // Cache these values for performance private int mCapsCount; @@ -55,6 +56,7 @@ public class WordComposer { mAutoCorrection = null; mTrailingSingleQuotesCount = 0; mIsResumed = false; + mIsBatchMode = false; refreshSize(); } @@ -67,6 +69,7 @@ public class WordComposer { mAutoCapitalized = source.mAutoCapitalized; mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount; mIsResumed = source.mIsResumed; + mIsBatchMode = source.mIsBatchMode; refreshSize(); } @@ -80,6 +83,7 @@ public class WordComposer { mIsFirstCharCapitalized = false; mTrailingSingleQuotesCount = 0; mIsResumed = false; + mIsBatchMode = false; refreshSize(); } @@ -140,6 +144,12 @@ public class WordComposer { mAutoCorrection = null; } + // TODO: We may want to have appendBatchInputPointers() as well. + public void setBatchInputPointers(InputPointers batchPointers) { + mInputPointers.copy(batchPointers); + mIsBatchMode = true; + } + /** * Internal method to retrieve reasonable proximity info for a character. */ @@ -312,4 +322,8 @@ public class WordComposer { mAutoCorrection = null; // This will be filled by the next call to updateSuggestion. mIsResumed = true; } + + public boolean isBatchMode() { + return mIsBatchMode; + } } From 2ae75ed56be5d08979d832cf3ddec16dc61e8dcf Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 10 Jul 2012 20:13:54 +0900 Subject: [PATCH 30/68] Start converging two identical methods (A92) Change-Id: I3c85a80610fde664a328f5606d0724f00d445ebe --- .../com/android/inputmethod/latin/BinaryDictionary.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 4cae6bcdb..37bf3c789 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -118,7 +118,7 @@ public class BinaryDictionary extends Dictionary { // TODO: move to native code private ArrayList getBigramsInternal(final WordComposer codes, final CharSequence previousWord) { - if (mNativeDict == 0) return null; + if (!isValidDictionary()) return null; int[] codePoints = StringUtils.toCodePointArray(previousWord.toString()); Arrays.fill(mOutputChars_bigrams, (char) 0); @@ -157,6 +157,8 @@ public class BinaryDictionary extends Dictionary { // proximityInfo and/or prevWordForBigrams may not be null. private ArrayList getWordsInternal(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { + if (!isValidDictionary()) return null; + final int count = getSuggestions(codes, prevWordForBigrams, proximityInfo, mOutputChars, mScores, mSpaceIndices); @@ -183,11 +185,9 @@ public class BinaryDictionary extends Dictionary { } // proximityInfo may not be null. - /* package for test */ int getSuggestions(final WordComposer codes, + private int getSuggestions(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo, char[] outputChars, int[] scores, int[] spaceIndices) { - if (!isValidDictionary()) return -1; - Arrays.fill(mInputCodes, WordComposer.NOT_A_CODE); Arrays.fill(outputChars, (char) 0); Arrays.fill(scores, 0); From 5e06b8534ffdf5099d2ef4551b113a103cdf7061 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Wed, 27 Jun 2012 09:47:59 +0900 Subject: [PATCH 31/68] Register the key when the finger slides off it in multitouch Moved from jb-dev branch (I807fd6f4). Bug: 6722867 Change-Id: I9764ac72f726396caaac819675d440372c882981 --- .../inputmethod/keyboard/PointerTracker.java | 9 +++++++++ .../keyboard/internal/PointerTrackerQueue.java | 15 +++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 32ef408b4..1ae0020a4 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -610,6 +610,15 @@ public class PointerTracker { onUpEventInternal(); onDownEventInternal(x, y, eventTime); } else { + // HACK: If there are currently multiple touches, register the key even if + // the finger slides off the key. This defends against noise from some + // touch panels when there are close multiple touches. + // Caveat: When in chording input mode with a modifier key, we don't use + // this hack. + if (me != null && me.getPointerCount() > 1 + && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) { + onUpEventInternal(); + } mKeyAlreadyProcessed = true; setReleasedKeyGraphics(oldKey); } diff --git a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java index 5db65c660..d3bb85d4b 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java @@ -28,6 +28,7 @@ public class PointerTrackerQueue { private static final String TAG = PointerTrackerQueue.class.getSimpleName(); private static final boolean DEBUG = false; + // TODO: Use ring buffer instead of {@link LinkedList}. private final LinkedList mQueue = new LinkedList(); public synchronized void add(PointerTracker tracker) { @@ -81,6 +82,20 @@ public class PointerTrackerQueue { } } + public synchronized boolean hasModifierKeyOlderThan(PointerTracker tracker) { + final Iterator it = mQueue.iterator(); + while (it.hasNext()) { + final PointerTracker t = it.next(); + if (t == tracker) { + break; + } + if (t.isModifier()) { + return true; + } + } + return false; + } + public synchronized boolean isAnyInSlidingKeyInput() { for (final PointerTracker tracker : mQueue) { if (tracker.isInSlidingKeyInput()) { From 6f233f7ba1ee924844154515dda208bb9b34acb5 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 10 Jul 2012 20:18:10 +0900 Subject: [PATCH 32/68] Remove useless member variables (A93) Change-Id: Iff0a0e8835f4d630b51a15c0d91881437094e785 --- .../inputmethod/latin/BinaryDictionary.java | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 37bf3c789..291d84975 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -46,16 +46,15 @@ public class BinaryDictionary extends Dictionary { private static final String TAG = "BinaryDictionary"; private static final int MAX_BIGRAMS = 60; + private static final int MAX_RESULTS = MAX_BIGRAMS > MAX_WORDS ? MAX_BIGRAMS : MAX_WORDS; private static final int TYPED_LETTER_MULTIPLIER = 2; private long mNativeDict; private final int[] mInputCodes = new int[MAX_WORD_LENGTH]; - private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS]; - private final char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS]; + private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_RESULTS]; private final int[] mSpaceIndices = new int[MAX_SPACES]; - private final int[] mScores = new int[MAX_WORDS]; - private final int[] mBigramScores = new int[MAX_BIGRAMS]; + private final int[] mOutputScores = new int[MAX_RESULTS]; private final boolean mUseFullEditDistance; @@ -121,8 +120,8 @@ public class BinaryDictionary extends Dictionary { if (!isValidDictionary()) return null; int[] codePoints = StringUtils.toCodePointArray(previousWord.toString()); - Arrays.fill(mOutputChars_bigrams, (char) 0); - Arrays.fill(mBigramScores, 0); + Arrays.fill(mOutputChars, (char) 0); + Arrays.fill(mOutputScores, 0); int codesSize = codes.size(); Arrays.fill(mInputCodes, -1); @@ -131,23 +130,23 @@ public class BinaryDictionary extends Dictionary { } int count = getBigramsNative(mNativeDict, codePoints, codePoints.length, mInputCodes, - codesSize, mOutputChars_bigrams, mBigramScores, MAX_WORD_LENGTH, MAX_BIGRAMS); + codesSize, mOutputChars, mOutputScores, MAX_WORD_LENGTH, MAX_BIGRAMS); if (count > MAX_BIGRAMS) { count = MAX_BIGRAMS; } final ArrayList suggestions = new ArrayList(); for (int j = 0; j < count; ++j) { - if (codesSize > 0 && mBigramScores[j] < 1) break; + if (codesSize > 0 && mOutputScores[j] < 1) break; final int start = j * MAX_WORD_LENGTH; int len = 0; - while (len < MAX_WORD_LENGTH && mOutputChars_bigrams[start + len] != 0) { + while (len < MAX_WORD_LENGTH && mOutputChars[start + len] != 0) { ++len; } if (len > 0) { suggestions.add(new SuggestedWordInfo( - new String(mOutputChars_bigrams, start, len), - mBigramScores[j], SuggestedWordInfo.KIND_CORRECTION, mDictType)); + new String(mOutputChars, start, len), + mOutputScores[j], SuggestedWordInfo.KIND_CORRECTION, mDictType)); } } return suggestions; @@ -160,11 +159,11 @@ public class BinaryDictionary extends Dictionary { if (!isValidDictionary()) return null; final int count = getSuggestions(codes, prevWordForBigrams, proximityInfo, mOutputChars, - mScores, mSpaceIndices); + mOutputScores, mSpaceIndices); final ArrayList suggestions = new ArrayList(); for (int j = 0; j < count; ++j) { - if (mScores[j] < 1) break; + if (mOutputScores[j] < 1) break; final int start = j * MAX_WORD_LENGTH; int len = 0; while (len < MAX_WORD_LENGTH && mOutputChars[start + len] != 0) { @@ -174,7 +173,7 @@ public class BinaryDictionary extends Dictionary { // TODO: actually get the kind from native code suggestions.add(new SuggestedWordInfo( new String(mOutputChars, start, len), - mScores[j], SuggestedWordInfo.KIND_CORRECTION, mDictType)); + mOutputScores[j], SuggestedWordInfo.KIND_CORRECTION, mDictType)); } } return suggestions; From 60baf00b3a910066420e6714afd0052888857b4d Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Tue, 10 Jul 2012 14:20:17 -0700 Subject: [PATCH 33/68] Import translations. DO NOT MERGE Change-Id: I0376c38451de66ff8c40b488ed3a8599326755ad Auto-generated-cl: translation import --- java/res/values-am/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-be/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-ca/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-da/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-de/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-el/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-en-rGB/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-es/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-fa/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-fi/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-fr/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-hi/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-hr/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-it/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-iw/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-lv/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-nb/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-nl/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-sl/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-sr/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-sv/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-sw/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-uk/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-zu/strings-appname.xml | 28 ++++++++++++++++++++++ 24 files changed, 672 insertions(+) create mode 100644 java/res/values-am/strings-appname.xml create mode 100644 java/res/values-be/strings-appname.xml create mode 100644 java/res/values-ca/strings-appname.xml create mode 100644 java/res/values-da/strings-appname.xml create mode 100644 java/res/values-de/strings-appname.xml create mode 100644 java/res/values-el/strings-appname.xml create mode 100644 java/res/values-en-rGB/strings-appname.xml create mode 100644 java/res/values-es/strings-appname.xml create mode 100644 java/res/values-fa/strings-appname.xml create mode 100644 java/res/values-fi/strings-appname.xml create mode 100644 java/res/values-fr/strings-appname.xml create mode 100644 java/res/values-hi/strings-appname.xml create mode 100644 java/res/values-hr/strings-appname.xml create mode 100644 java/res/values-it/strings-appname.xml create mode 100644 java/res/values-iw/strings-appname.xml create mode 100644 java/res/values-lv/strings-appname.xml create mode 100644 java/res/values-nb/strings-appname.xml create mode 100644 java/res/values-nl/strings-appname.xml create mode 100644 java/res/values-sl/strings-appname.xml create mode 100644 java/res/values-sr/strings-appname.xml create mode 100644 java/res/values-sv/strings-appname.xml create mode 100644 java/res/values-sw/strings-appname.xml create mode 100644 java/res/values-uk/strings-appname.xml create mode 100644 java/res/values-zu/strings-appname.xml diff --git a/java/res/values-am/strings-appname.xml b/java/res/values-am/strings-appname.xml new file mode 100644 index 000000000..da0ab2f16 --- /dev/null +++ b/java/res/values-am/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Android የፊደል አራሚ" + "Android የቁልፍ ሰሌዳ ቅንብሮች" + "የፊደል አራሚ ቅንብሮች" + diff --git a/java/res/values-be/strings-appname.xml b/java/res/values-be/strings-appname.xml new file mode 100644 index 000000000..226de7cbd --- /dev/null +++ b/java/res/values-be/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Iнструмент праверкi правапiсу для Android" + "Налады клавіятуры Android" + "Налады праверкі арфаграфіі" + diff --git a/java/res/values-ca/strings-appname.xml b/java/res/values-ca/strings-appname.xml new file mode 100644 index 000000000..6a23c242b --- /dev/null +++ b/java/res/values-ca/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Corrector ortogràfic d\'Android" + "Configuració del teclat d\'Android" + "Configuració de la correcció ortogràfica" + diff --git a/java/res/values-da/strings-appname.xml b/java/res/values-da/strings-appname.xml new file mode 100644 index 000000000..610d88aaa --- /dev/null +++ b/java/res/values-da/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Android-stavekontrol" + "Indstillinger for Android-tastatur" + "Indstillinger for stavekontrol" + diff --git a/java/res/values-de/strings-appname.xml b/java/res/values-de/strings-appname.xml new file mode 100644 index 000000000..bc77f722e --- /dev/null +++ b/java/res/values-de/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Android-Rechtschreibprüfung" + "Android-Tastatureinstellungen" + "Einstellungen für Rechtschreibprüfung" + diff --git a/java/res/values-el/strings-appname.xml b/java/res/values-el/strings-appname.xml new file mode 100644 index 000000000..6daf2d97c --- /dev/null +++ b/java/res/values-el/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Ορθογραφικός έλεγχος Android" + "Ρυθμίσεις πληκτρολογίου Android" + "Ρυθμίσεις ορθογραφικού ελέγχου" + diff --git a/java/res/values-en-rGB/strings-appname.xml b/java/res/values-en-rGB/strings-appname.xml new file mode 100644 index 000000000..53f9e9d0e --- /dev/null +++ b/java/res/values-en-rGB/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Android spell checker" + "Android keyboard settings" + "Spell checking settings" + diff --git a/java/res/values-es/strings-appname.xml b/java/res/values-es/strings-appname.xml new file mode 100644 index 000000000..e716e7d89 --- /dev/null +++ b/java/res/values-es/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Corrector ortográfico de Android" + "Ajustes del teclado de Android" + "Ajustes del corrector ortográfico" + diff --git a/java/res/values-fa/strings-appname.xml b/java/res/values-fa/strings-appname.xml new file mode 100644 index 000000000..263f166f8 --- /dev/null +++ b/java/res/values-fa/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "غلط‌گیر املای Android" + "تنظیمات صفحه کلید Android" + "تنظیمات غلط‌‌ گیر املا" + diff --git a/java/res/values-fi/strings-appname.xml b/java/res/values-fi/strings-appname.xml new file mode 100644 index 000000000..fefb92e15 --- /dev/null +++ b/java/res/values-fi/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Android-oikoluku" + "Android-näppäimistön asetukset" + "Oikolukuasetukset" + diff --git a/java/res/values-fr/strings-appname.xml b/java/res/values-fr/strings-appname.xml new file mode 100644 index 000000000..da7671b1f --- /dev/null +++ b/java/res/values-fr/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Correcteur orthographique Android" + "Paramètres du clavier Android" + "Paramètres du correcteur orthographique" + diff --git a/java/res/values-hi/strings-appname.xml b/java/res/values-hi/strings-appname.xml new file mode 100644 index 000000000..c8d34ec3c --- /dev/null +++ b/java/res/values-hi/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Android वर्तनी परीक्षक" + "Android कीबोर्ड सेटिंग" + "वर्तनी जांच सेटिंग" + diff --git a/java/res/values-hr/strings-appname.xml b/java/res/values-hr/strings-appname.xml new file mode 100644 index 000000000..6457a21cf --- /dev/null +++ b/java/res/values-hr/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Androidova provjera pravopisa" + "Postavke Androidove tipkovnice" + "Postavke provjere pravopisa" + diff --git a/java/res/values-it/strings-appname.xml b/java/res/values-it/strings-appname.xml new file mode 100644 index 000000000..838daaf40 --- /dev/null +++ b/java/res/values-it/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Controllo ortografico Android" + "Impostazioni tastiera Android" + "Impostazioni di controllo ortografico" + diff --git a/java/res/values-iw/strings-appname.xml b/java/res/values-iw/strings-appname.xml new file mode 100644 index 000000000..92bc240f1 --- /dev/null +++ b/java/res/values-iw/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "בודק האיות של Android" + "הגדרות מקלדת Android" + "הגדרות בדיקת איות" + diff --git a/java/res/values-lv/strings-appname.xml b/java/res/values-lv/strings-appname.xml new file mode 100644 index 000000000..fe2f33697 --- /dev/null +++ b/java/res/values-lv/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Android pareizrakstības pārbaudītājs" + "Android tastatūras iestatījumi" + "Pareizrakstības pārbaudes iestatījumi" + diff --git a/java/res/values-nb/strings-appname.xml b/java/res/values-nb/strings-appname.xml new file mode 100644 index 000000000..b5ed18abb --- /dev/null +++ b/java/res/values-nb/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Android-stavekontroll" + "Innstillinger for Android-tastatur" + "Innstillinger for stavekontroll" + diff --git a/java/res/values-nl/strings-appname.xml b/java/res/values-nl/strings-appname.xml new file mode 100644 index 000000000..f1cb252c2 --- /dev/null +++ b/java/res/values-nl/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Spellingcontrole van Android" + "Instellingen voor Android-toetsenbord" + "Instellingen voor spellingcontrole" + diff --git a/java/res/values-sl/strings-appname.xml b/java/res/values-sl/strings-appname.xml new file mode 100644 index 000000000..aa8c8163c --- /dev/null +++ b/java/res/values-sl/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Črkovalnik za Android" + "Nastavitve tipkovnice Android" + "Nastavitve preverjanja črkovanja" + diff --git a/java/res/values-sr/strings-appname.xml b/java/res/values-sr/strings-appname.xml new file mode 100644 index 000000000..01da6d5c0 --- /dev/null +++ b/java/res/values-sr/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Android провера правописа" + "Подешавања Android тастатуре" + "Подешавања провере правописа" + diff --git a/java/res/values-sv/strings-appname.xml b/java/res/values-sv/strings-appname.xml new file mode 100644 index 000000000..edb2af2ad --- /dev/null +++ b/java/res/values-sv/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Stavningskontroll i Android" + "Inställningar för Androids tangentbord" + "Inställningar för stavningskontroll" + diff --git a/java/res/values-sw/strings-appname.xml b/java/res/values-sw/strings-appname.xml new file mode 100644 index 000000000..4a5b2a683 --- /dev/null +++ b/java/res/values-sw/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Kikagua tahajia cha Android" + "Mipangilio ya kibodi ya Android" + "Mipangilio ya kukagua tahajia" + diff --git a/java/res/values-uk/strings-appname.xml b/java/res/values-uk/strings-appname.xml new file mode 100644 index 000000000..d77b617fa --- /dev/null +++ b/java/res/values-uk/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Засіб перевірки орфографії Android" + "Налаштування клавіатури Android" + "Налаштування перевірки орфографії" + diff --git a/java/res/values-zu/strings-appname.xml b/java/res/values-zu/strings-appname.xml new file mode 100644 index 000000000..b5212a5b6 --- /dev/null +++ b/java/res/values-zu/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Isihloli sokupela se-Android" + "Izilungiselelo zekhibhodi ye-Android" + "Izilungiselelo zokuhlola ukupela" + From 223d671ffcfe182130742c8a48185b9362acc6f9 Mon Sep 17 00:00:00 2001 From: Kurt Partridge Date: Fri, 29 Jun 2012 07:02:39 -0700 Subject: [PATCH 34/68] intentional logging - separate ResearchLog from ResearchLogger - fix abort menu to explicitly indicate re-enabling of logging - auto flush entries every 5s - conform to new suggestedWords class multi-project change with I9fe1f8fe59d5891daa4ca84af157f36fb1bb17dc Bug: 6188932 Change-Id: I7e99390f934481c6ed9cea2b259944583edda5bb --- java/proguard.flags | 1 + java/res/values/strings.xml | 10 + .../android/inputmethod/latin/LatinIME.java | 2 +- .../inputmethod/latin/ResearchLog.java | 360 +++++++++++++ .../inputmethod/latin/ResearchLogger.java | 471 +++++++----------- 5 files changed, 548 insertions(+), 296 deletions(-) create mode 100644 java/src/com/android/inputmethod/latin/ResearchLog.java diff --git a/java/proguard.flags b/java/proguard.flags index ca205b927..c562834f2 100644 --- a/java/proguard.flags +++ b/java/proguard.flags @@ -38,6 +38,7 @@ -keep class com.android.inputmethod.latin.ResearchLogger { void flush(); + void publishCurrentLogUnit(...); } -keep class com.android.inputmethod.keyboard.KeyboardLayoutSet$Builder { diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 5fd4af4f4..7272cfe97 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -224,12 +224,22 @@ Do not log this session + + Enable session logging + + Log whole session history Deleting session log Session log deleted Session log NOT deleted + + Session history logged + + Error: Session history NOT logged + + Session logging enabled Input languages diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 4be2a1799..2e0d90881 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -353,7 +353,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mPrefs = prefs; LatinImeLogger.init(this, prefs); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.getInstance().init(this, prefs); + ResearchLogger.getInstance().init(this, prefs, mKeyboardSwitcher); } InputMethodManagerCompatWrapper.init(this); SubtypeSwitcher.init(this); diff --git a/java/src/com/android/inputmethod/latin/ResearchLog.java b/java/src/com/android/inputmethod/latin/ResearchLog.java new file mode 100644 index 000000000..1de5cb36a --- /dev/null +++ b/java/src/com/android/inputmethod/latin/ResearchLog.java @@ -0,0 +1,360 @@ +/* + * 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.SharedPreferences; +import android.os.SystemClock; +import android.util.JsonWriter; +import android.util.Log; +import android.view.inputmethod.CompletionInfo; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.latin.ResearchLogger.LogUnit; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.define.ProductionFlag; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +/** + * Logs the use of the LatinIME keyboard. + * + * This class logs operations on the IME keyboard, including what the user has typed. + * Data is stored locally in a file in app-specific storage. + * + * This functionality is off by default. See {@link ProductionFlag#IS_EXPERIMENTAL}. + */ +public class ResearchLog { + private static final String TAG = ResearchLog.class.getSimpleName(); + private static final JsonWriter NULL_JSON_WRITER = new JsonWriter( + new OutputStreamWriter(new NullOutputStream())); + + final ScheduledExecutorService mExecutor; + /* package */ final File mFile; + private JsonWriter mJsonWriter = NULL_JSON_WRITER; // should never be null + + private int mLoggingState; + private static final int LOGGING_STATE_UNSTARTED = 0; + private static final int LOGGING_STATE_RUNNING = 1; + private static final int LOGGING_STATE_STOPPING = 2; + private static final int LOGGING_STATE_STOPPED = 3; + private static final long FLUSH_DELAY_IN_MS = 1000 * 5; + + private static class NullOutputStream extends OutputStream { + /** {@inheritDoc} */ + @Override + public void write(byte[] buffer, int offset, int count) { + // nop + } + + /** {@inheritDoc} */ + @Override + public void write(byte[] buffer) { + // nop + } + + @Override + public void write(int oneByte) { + } + } + + public ResearchLog(File outputFile) { + mExecutor = Executors.newSingleThreadScheduledExecutor(); + if (outputFile == null) { + throw new IllegalArgumentException(); + } + mFile = outputFile; + mLoggingState = LOGGING_STATE_UNSTARTED; + } + + public synchronized void start() throws IOException { + switch (mLoggingState) { + case LOGGING_STATE_UNSTARTED: + mJsonWriter = new JsonWriter(new BufferedWriter(new FileWriter(mFile))); + mJsonWriter.setLenient(true); + mJsonWriter.beginArray(); + mLoggingState = LOGGING_STATE_RUNNING; + break; + case LOGGING_STATE_RUNNING: + case LOGGING_STATE_STOPPING: + case LOGGING_STATE_STOPPED: + break; + } + } + + public synchronized void stop() { + switch (mLoggingState) { + case LOGGING_STATE_UNSTARTED: + mLoggingState = LOGGING_STATE_STOPPED; + break; + case LOGGING_STATE_RUNNING: + mExecutor.submit(new Callable() { + @Override + public Object call() throws Exception { + try { + mJsonWriter.endArray(); + mJsonWriter.flush(); + mJsonWriter.close(); + } finally { + // the contentprovider only exports data if the writable + // bit is cleared. + boolean success = mFile.setWritable(false, false); + mLoggingState = LOGGING_STATE_STOPPED; + } + return null; + } + }); + mExecutor.shutdown(); + mLoggingState = LOGGING_STATE_STOPPING; + break; + case LOGGING_STATE_STOPPING: + case LOGGING_STATE_STOPPED: + } + } + + public boolean isAlive() { + switch (mLoggingState) { + case LOGGING_STATE_UNSTARTED: + case LOGGING_STATE_RUNNING: + return true; + } + return false; + } + + public void waitUntilStopped(int timeoutInMs) throws InterruptedException { + mExecutor.awaitTermination(timeoutInMs, TimeUnit.MILLISECONDS); + } + + private boolean isAbortSuccessful; + public boolean isAbortSuccessful() { + return isAbortSuccessful; + } + + public synchronized void abort() { + switch (mLoggingState) { + case LOGGING_STATE_UNSTARTED: + mLoggingState = LOGGING_STATE_STOPPED; + isAbortSuccessful = true; + break; + case LOGGING_STATE_RUNNING: + mExecutor.submit(new Callable() { + @Override + public Object call() throws Exception { + try { + mJsonWriter.endArray(); + mJsonWriter.close(); + } finally { + isAbortSuccessful = mFile.delete(); + } + return null; + } + }); + mExecutor.shutdown(); + mLoggingState = LOGGING_STATE_STOPPING; + break; + case LOGGING_STATE_STOPPING: + case LOGGING_STATE_STOPPED: + } + } + + /* package */ synchronized void flush() { + switch (mLoggingState) { + case LOGGING_STATE_UNSTARTED: + break; + case LOGGING_STATE_RUNNING: + removeAnyScheduledFlush(); + mExecutor.submit(mFlushCallable); + break; + case LOGGING_STATE_STOPPING: + case LOGGING_STATE_STOPPED: + } + } + + private Callable mFlushCallable = new Callable() { + @Override + public Object call() throws Exception { + mJsonWriter.flush(); + return null; + } + }; + + private ScheduledFuture mFlushFuture; + + private void removeAnyScheduledFlush() { + if (mFlushFuture != null) { + mFlushFuture.cancel(false); + mFlushFuture = null; + } + } + + private void scheduleFlush() { + removeAnyScheduledFlush(); + mFlushFuture = mExecutor.schedule(mFlushCallable, FLUSH_DELAY_IN_MS, TimeUnit.MILLISECONDS); + } + + public synchronized void publishPublicEvents(final LogUnit logUnit) { + switch (mLoggingState) { + case LOGGING_STATE_UNSTARTED: + break; + case LOGGING_STATE_RUNNING: + mExecutor.submit(new Callable() { + @Override + public Object call() throws Exception { + logUnit.publishPublicEventsTo(ResearchLog.this); + scheduleFlush(); + return null; + } + }); + break; + case LOGGING_STATE_STOPPING: + case LOGGING_STATE_STOPPED: + } + } + + public synchronized void publishAllEvents(final LogUnit logUnit) { + switch (mLoggingState) { + case LOGGING_STATE_UNSTARTED: + break; + case LOGGING_STATE_RUNNING: + mExecutor.submit(new Callable() { + @Override + public Object call() throws Exception { + logUnit.publishAllEventsTo(ResearchLog.this); + scheduleFlush(); + return null; + } + }); + break; + case LOGGING_STATE_STOPPING: + case LOGGING_STATE_STOPPED: + } + } + + private static final String CURRENT_TIME_KEY = "_ct"; + private static final String UPTIME_KEY = "_ut"; + private static final String EVENT_TYPE_KEY = "_ty"; + void outputEvent(final String[] keys, final Object[] values) { + // not thread safe. + try { + mJsonWriter.beginObject(); + mJsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis()); + mJsonWriter.name(UPTIME_KEY).value(SystemClock.uptimeMillis()); + mJsonWriter.name(EVENT_TYPE_KEY).value(keys[0]); + final int length = values.length; + for (int i = 0; i < length; i++) { + mJsonWriter.name(keys[i + 1]); + Object value = values[i]; + if (value instanceof String) { + mJsonWriter.value((String) value); + } else if (value instanceof Number) { + mJsonWriter.value((Number) value); + } else if (value instanceof Boolean) { + mJsonWriter.value((Boolean) value); + } else if (value instanceof CompletionInfo[]) { + CompletionInfo[] ci = (CompletionInfo[]) value; + mJsonWriter.beginArray(); + for (int j = 0; j < ci.length; j++) { + mJsonWriter.value(ci[j].toString()); + } + mJsonWriter.endArray(); + } else if (value instanceof SharedPreferences) { + SharedPreferences prefs = (SharedPreferences) value; + mJsonWriter.beginObject(); + for (Map.Entry entry : prefs.getAll().entrySet()) { + mJsonWriter.name(entry.getKey()); + final Object innerValue = entry.getValue(); + if (innerValue == null) { + mJsonWriter.nullValue(); + } else if (innerValue instanceof Boolean) { + mJsonWriter.value((Boolean) innerValue); + } else if (innerValue instanceof Number) { + mJsonWriter.value((Number) innerValue); + } else { + mJsonWriter.value(innerValue.toString()); + } + } + mJsonWriter.endObject(); + } else if (value instanceof Key[]) { + Key[] keyboardKeys = (Key[]) value; + mJsonWriter.beginArray(); + for (Key keyboardKey : keyboardKeys) { + mJsonWriter.beginObject(); + mJsonWriter.name("code").value(keyboardKey.mCode); + mJsonWriter.name("altCode").value(keyboardKey.mAltCode); + mJsonWriter.name("x").value(keyboardKey.mX); + mJsonWriter.name("y").value(keyboardKey.mY); + mJsonWriter.name("w").value(keyboardKey.mWidth); + mJsonWriter.name("h").value(keyboardKey.mHeight); + mJsonWriter.endObject(); + } + mJsonWriter.endArray(); + } else if (value instanceof SuggestedWords) { + SuggestedWords words = (SuggestedWords) value; + mJsonWriter.beginObject(); + mJsonWriter.name("typedWordValid").value(words.mTypedWordValid); + mJsonWriter.name("willAutoCorrect") + .value(words.mWillAutoCorrect); + mJsonWriter.name("isPunctuationSuggestions") + .value(words.mIsPunctuationSuggestions); + mJsonWriter.name("isObsoleteSuggestions") + .value(words.mIsObsoleteSuggestions); + mJsonWriter.name("isPrediction") + .value(words.mIsPrediction); + mJsonWriter.name("words"); + mJsonWriter.beginArray(); + final int size = words.size(); + for (int j = 0; j < size; j++) { + SuggestedWordInfo wordInfo = words.getWordInfo(j); + mJsonWriter.value(wordInfo.toString()); + } + mJsonWriter.endArray(); + mJsonWriter.endObject(); + } else if (value == null) { + mJsonWriter.nullValue(); + } else { + Log.w(TAG, "Unrecognized type to be logged: " + + (value == null ? "" : value.getClass().getName())); + mJsonWriter.nullValue(); + } + } + mJsonWriter.endObject(); + } catch (IOException e) { + e.printStackTrace(); + Log.w(TAG, "Error in JsonWriter; disabling logging"); + try { + mJsonWriter.close(); + } catch (IllegalStateException e1) { + // assume that this is just the json not being terminated properly. + // ignore + } catch (IOException e1) { + e1.printStackTrace(); + } finally { + mJsonWriter = NULL_JSON_WRITER; + } + } + } +} diff --git a/java/src/com/android/inputmethod/latin/ResearchLogger.java b/java/src/com/android/inputmethod/latin/ResearchLogger.java index 2de0194fd..9055d5d32 100644 --- a/java/src/com/android/inputmethod/latin/ResearchLogger.java +++ b/java/src/com/android/inputmethod/latin/ResearchLogger.java @@ -24,12 +24,7 @@ import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.inputmethodservice.InputMethodService; import android.os.Build; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Process; -import android.os.SystemClock; import android.text.TextUtils; -import android.util.JsonWriter; import android.util.Log; import android.view.MotionEvent; import android.view.inputmethod.CompletionInfo; @@ -40,22 +35,17 @@ import android.widget.Toast; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.latin.RichInputConnection.Range; -import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.define.ProductionFlag; -import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.UUID; /** @@ -68,36 +58,35 @@ import java.util.UUID; */ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = ResearchLogger.class.getSimpleName(); - private static final boolean DEBUG = false; private static final boolean OUTPUT_ENTIRE_BUFFER = false; // true may disclose private info /* package */ static boolean sIsLogging = false; private static final int OUTPUT_FORMAT_VERSION = 1; private static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; private static final String FILENAME_PREFIX = "researchLog"; private static final String FILENAME_SUFFIX = ".txt"; - private static final JsonWriter NULL_JSON_WRITER = new JsonWriter( - new OutputStreamWriter(new NullOutputStream())); private static final SimpleDateFormat TIMESTAMP_DATEFORMAT = - new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); + new SimpleDateFormat("yyyyMMddHHmmssS", Locale.US); // constants related to specific log points private static final String WHITESPACE_SEPARATORS = " \t\n\r"; private static final int MAX_INPUTVIEW_LENGTH_TO_CAPTURE = 8192; // must be >=1 private static final String PREF_RESEARCH_LOGGER_UUID_STRING = "pref_research_logger_uuid"; + private static final int ABORT_TIMEOUT_IN_MS = 10 * 1000; private static final ResearchLogger sInstance = new ResearchLogger(); - private HandlerThread mHandlerThread; - /* package */ Handler mLoggingHandler; // to write to a different filename, e.g., for testing, set mFile before calling start() - private File mFilesDir; - /* package */ File mFile; - private JsonWriter mJsonWriter = NULL_JSON_WRITER; // should never be null + /* package */ File mFilesDir; + /* package */ String mUUIDString; + /* package */ ResearchLog mMainResearchLog; + // The mIntentionalResearchLog records all events for the session, private or not (excepting + // passwords). It is written to permanent storage only if the user explicitly commands + // the system to do so. + /* package */ ResearchLog mIntentionalResearchLog; + // LogUnits are queued here and released only when the user requests the intentional log. + private final List mIntentionalResearchLogQueue = new ArrayList(); - private int mLoggingState; - private static final int LOGGING_STATE_OFF = 0; - private static final int LOGGING_STATE_ON = 1; - private static final int LOGGING_STATE_STOPPING = 2; private boolean mIsPasswordView = false; + private boolean mIsLoggingSuspended = false; // digits entered by the user are replaced with this codepoint. /* package for test */ static final int DIGIT_REPLACEMENT_CODEPOINT = @@ -111,34 +100,17 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang // used to check whether words are not unique private Suggest mSuggest; private Dictionary mDictionary; - - private static class NullOutputStream extends OutputStream { - /** {@inheritDoc} */ - @Override - public void write(byte[] buffer, int offset, int count) { - // nop - } - - /** {@inheritDoc} */ - @Override - public void write(byte[] buffer) { - // nop - } - - @Override - public void write(int oneByte) { - } - } + private KeyboardSwitcher mKeyboardSwitcher; private ResearchLogger() { - mLoggingState = LOGGING_STATE_OFF; } public static ResearchLogger getInstance() { return sInstance; } - public void init(final InputMethodService ims, final SharedPreferences prefs) { + public void init(final InputMethodService ims, final SharedPreferences prefs, + KeyboardSwitcher keyboardSwitcher) { assert ims != null; if (ims == null) { Log.w(TAG, "IMS is null; logging is off"); @@ -149,129 +121,100 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } if (prefs != null) { + mUUIDString = getUUID(prefs); sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false); prefs.registerOnSharedPreferenceChangeListener(this); } + mKeyboardSwitcher = keyboardSwitcher; } - public synchronized void start() { - Log.d(TAG, "start called"); + private File createLogFile(File filesDir) { + final StringBuilder sb = new StringBuilder(); + sb.append(FILENAME_PREFIX).append('-'); + sb.append(mUUIDString).append('-'); + sb.append(TIMESTAMP_DATEFORMAT.format(new Date())); + sb.append(FILENAME_SUFFIX); + return new File(filesDir, sb.toString()); + } + + public void start() { if (!sIsLogging) { // Log.w(TAG, "not in usability mode; not logging"); return; } if (mFilesDir == null || !mFilesDir.exists()) { Log.w(TAG, "IME storage directory does not exist. Cannot start logging."); - } else { - if (mHandlerThread == null || !mHandlerThread.isAlive()) { - mHandlerThread = new HandlerThread("ResearchLogger logging task", - Process.THREAD_PRIORITY_BACKGROUND); - mHandlerThread.start(); - mLoggingHandler = null; - mLoggingState = LOGGING_STATE_OFF; - } - if (mLoggingHandler == null) { - mLoggingHandler = new Handler(mHandlerThread.getLooper()); - mLoggingState = LOGGING_STATE_OFF; - } - if (mFile == null) { - final String timestampString = TIMESTAMP_DATEFORMAT.format(new Date()); - mFile = new File(mFilesDir, FILENAME_PREFIX + timestampString + FILENAME_SUFFIX); - } - if (mLoggingState == LOGGING_STATE_OFF) { - try { - mJsonWriter = new JsonWriter(new BufferedWriter(new FileWriter(mFile))); - mJsonWriter.setLenient(true); - mJsonWriter.beginArray(); - mLoggingState = LOGGING_STATE_ON; - } catch (IOException e) { - Log.w(TAG, "cannot start JsonWriter"); - mJsonWriter = NULL_JSON_WRITER; - e.printStackTrace(); - } - } + return; } - } - - public synchronized void stop() { - Log.d(TAG, "stop called"); - if (mLoggingHandler != null && mLoggingState == LOGGING_STATE_ON) { - mLoggingState = LOGGING_STATE_STOPPING; - flushEventQueue(true); - // put this in the Handler queue so pending writes are processed first. - mLoggingHandler.post(new Runnable() { - @Override - public void run() { - try { - Log.d(TAG, "closing jsonwriter"); - mJsonWriter.endArray(); - mJsonWriter.flush(); - mJsonWriter.close(); - } catch (IllegalStateException e1) { - // assume that this is just the json not being terminated properly. - // ignore - e1.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - mJsonWriter = NULL_JSON_WRITER; - mFile = null; - mLoggingState = LOGGING_STATE_OFF; - if (DEBUG) { - Log.d(TAG, "logfile closed"); - } - Log.d(TAG, "finished stop(), notifying"); - synchronized (ResearchLogger.this) { - ResearchLogger.this.notify(); - } - } - } - }); - try { - wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } + if (mMainResearchLog == null || !mMainResearchLog.isAlive()) { + mMainResearchLog = new ResearchLog(createLogFile(mFilesDir)); } - } - - public synchronized boolean abort() { - Log.d(TAG, "abort called"); - boolean isLogFileDeleted = false; - if (mLoggingHandler != null && mLoggingState == LOGGING_STATE_ON) { - mLoggingState = LOGGING_STATE_STOPPING; - try { - Log.d(TAG, "closing jsonwriter"); - mJsonWriter.endArray(); - mJsonWriter.close(); - } catch (IllegalStateException e1) { - // assume that this is just the json not being terminated properly. - // ignore - e1.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - mJsonWriter = NULL_JSON_WRITER; - // delete file - final boolean isDeleted = mFile.delete(); - if (isDeleted) { - isLogFileDeleted = true; - } - mFile = null; - mLoggingState = LOGGING_STATE_OFF; - if (DEBUG) { - Log.d(TAG, "logfile closed"); - } - } - } - return isLogFileDeleted; - } - - /* package */ synchronized void flush() { try { - mJsonWriter.flush(); + mMainResearchLog.start(); + if (mIntentionalResearchLog == null || !mIntentionalResearchLog.isAlive()) { + mIntentionalResearchLog = new ResearchLog(createLogFile(mFilesDir)); + } + mIntentionalResearchLog.start(); } catch (IOException e) { - e.printStackTrace(); + Log.w(TAG, "Could not start ResearchLogger."); + } + } + + public void stop() { + if (mMainResearchLog != null) { + mMainResearchLog.stop(); + } + } + + public boolean abort() { + mIsLoggingSuspended = true; + requestIndicatorRedraw(); + boolean didAbortMainLog = false; + if (mMainResearchLog != null) { + mMainResearchLog.abort(); + try { + mMainResearchLog.waitUntilStopped(ABORT_TIMEOUT_IN_MS); + } catch (InterruptedException e) { + // interrupted early. carry on. + } + if (mMainResearchLog.isAbortSuccessful()) { + didAbortMainLog = true; + } + } + boolean didAbortIntentionalLog = false; + if (mIntentionalResearchLog != null) { + mIntentionalResearchLog.abort(); + try { + mIntentionalResearchLog.waitUntilStopped(ABORT_TIMEOUT_IN_MS); + } catch (InterruptedException e) { + // interrupted early. carry on. + } + if (mIntentionalResearchLog.isAbortSuccessful()) { + didAbortIntentionalLog = true; + } + } + return didAbortMainLog && didAbortIntentionalLog; + } + + /* package */ void flush() { + if (mMainResearchLog != null) { + mMainResearchLog.flush(); + } + } + + private void logWholeSessionHistory() throws IOException { + try { + LogUnit headerLogUnit = new LogUnit(); + headerLogUnit.addLogAtom(EVENTKEYS_INTENTIONAL_LOG, EVENTKEYS_NULLVALUES, false); + mIntentionalResearchLog.publishAllEvents(headerLogUnit); + for (LogUnit logUnit : mIntentionalResearchLogQueue) { + mIntentionalResearchLog.publishAllEvents(logUnit); + } + mIntentionalResearchLog.stop(); + mIntentionalResearchLog = new ResearchLog(createLogFile(mFilesDir)); + mIntentionalResearchLog.start(); + } finally { + mIntentionalResearchLogQueue.clear(); } } @@ -290,7 +233,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang final CharSequence title = latinIME.getString(R.string.english_ime_research_log); final CharSequence[] items = new CharSequence[] { latinIME.getString(R.string.note_timestamp_for_researchlog), - latinIME.getString(R.string.do_not_log_this_session), + mIsLoggingSuspended ? latinIME.getString(R.string.enable_session_logging) : + latinIME.getString(R.string.do_not_log_this_session), + latinIME.getString(R.string.log_whole_session_history), }; final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { @Override @@ -298,28 +243,46 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang di.dismiss(); switch (position) { case 0: - ResearchLogger.getInstance().userTimestamp(); + userTimestamp(); Toast.makeText(latinIME, R.string.notify_recorded_timestamp, Toast.LENGTH_LONG).show(); break; case 1: - Toast toast = Toast.makeText(latinIME, - R.string.notify_session_log_deleting, Toast.LENGTH_LONG); - toast.show(); - final ResearchLogger logger = ResearchLogger.getInstance(); - boolean isLogDeleted = logger.abort(); - toast.cancel(); - if (isLogDeleted) { - Toast.makeText(latinIME, R.string.notify_session_log_deleted, - Toast.LENGTH_LONG).show(); + if (mIsLoggingSuspended) { + mIsLoggingSuspended = false; + requestIndicatorRedraw(); + Toast toast = Toast.makeText(latinIME, + R.string.notify_session_logging_enabled, Toast.LENGTH_LONG); } else { - Toast.makeText(latinIME, - R.string.notify_session_log_not_deleted, Toast.LENGTH_LONG) - .show(); + Toast toast = Toast.makeText(latinIME, + R.string.notify_session_log_deleting, Toast.LENGTH_LONG); + toast.show(); + boolean isLogDeleted = abort(); + toast.cancel(); + if (isLogDeleted) { + Toast.makeText(latinIME, R.string.notify_session_log_deleted, + Toast.LENGTH_LONG).show(); + } else { + Toast.makeText(latinIME, + R.string.notify_session_log_not_deleted, Toast.LENGTH_LONG) + .show(); + } + } + break; + case 2: + try { + logWholeSessionHistory(); + Toast.makeText(latinIME, R.string.notify_session_history_logged, + Toast.LENGTH_LONG).show(); + } catch (IOException e) { + Toast.makeText(latinIME, R.string.notify_session_history_not_logged, + Toast.LENGTH_LONG).show(); + e.printStackTrace(); } break; } } + }; final AlertDialog.Builder builder = new AlertDialog.Builder(latinIME) .setItems(items, listener) @@ -336,7 +299,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } private boolean isAllowedToLog() { - return mLoggingState == LOGGING_STATE_ON && !mIsPasswordView; + return !mIsPasswordView && !mIsLoggingSuspended; + } + + public void requestIndicatorRedraw() { + // invalidate any existing graphics + if (mKeyboardSwitcher != null) { + mKeyboardSwitcher.getKeyboardView().invalidateAllKeys(); + } } private static final String CURRENT_TIME_KEY = "_ct"; @@ -360,7 +330,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private synchronized void enqueuePotentiallyPrivateEvent(final String[] keys, final Object[] values) { assert values.length + 1 == keys.length; - mCurrentLogUnit.addLogAtom(keys, values, true); + if (isAllowedToLog()) { + mCurrentLogUnit.addLogAtom(keys, values, true); + } } /** @@ -377,7 +349,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang */ private synchronized void enqueueEvent(final String[] keys, final Object[] values) { assert values.length + 1 == keys.length; - mCurrentLogUnit.addLogAtom(keys, values, false); + if (isAllowedToLog()) { + mCurrentLogUnit.addLogAtom(keys, values, false); + } } // Used to track how often words are logged. Too-frequent logging can leak @@ -453,131 +427,33 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } private void onWordComplete(String word) { - final boolean isPrivacyThreat = isPrivacyThreat(word); - flushEventQueue(isPrivacyThreat); - if (isPrivacyThreat) { + if (isPrivacyThreat(word)) { + publishLogUnit(mCurrentLogUnit, true); mLoggingFrequencyState.onWordNotLogged(); } else { + publishLogUnit(mCurrentLogUnit, false); mLoggingFrequencyState.onWordLogged(); } - } - - /** - * Write out enqueued LogEvents to the log, possibly dropping privacy sensitive events. - */ - /* package for test */ synchronized void flushEventQueue( - boolean removePotentiallyPrivateEvents) { - if (isAllowedToLog()) { - mCurrentLogUnit.setRemovePotentiallyPrivateEvents(removePotentiallyPrivateEvents); - mLoggingHandler.post(mCurrentLogUnit); - } mCurrentLogUnit = new LogUnit(); } - private synchronized void outputEvent(final String[] keys, final Object[] values) { - try { - mJsonWriter.beginObject(); - mJsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis()); - mJsonWriter.name(UPTIME_KEY).value(SystemClock.uptimeMillis()); - mJsonWriter.name(EVENT_TYPE_KEY).value(keys[0]); - final int length = values.length; - for (int i = 0; i < length; i++) { - mJsonWriter.name(keys[i + 1]); - Object value = values[i]; - if (value instanceof String) { - mJsonWriter.value((String) value); - } else if (value instanceof Number) { - mJsonWriter.value((Number) value); - } else if (value instanceof Boolean) { - mJsonWriter.value((Boolean) value); - } else if (value instanceof CompletionInfo[]) { - CompletionInfo[] ci = (CompletionInfo[]) value; - mJsonWriter.beginArray(); - for (int j = 0; j < ci.length; j++) { - mJsonWriter.value(ci[j].toString()); - } - mJsonWriter.endArray(); - } else if (value instanceof SharedPreferences) { - SharedPreferences prefs = (SharedPreferences) value; - mJsonWriter.beginObject(); - for (Map.Entry entry : prefs.getAll().entrySet()) { - mJsonWriter.name(entry.getKey()); - final Object innerValue = entry.getValue(); - if (innerValue == null) { - mJsonWriter.nullValue(); - } else if (innerValue instanceof Boolean) { - mJsonWriter.value((Boolean) innerValue); - } else if (innerValue instanceof Number) { - mJsonWriter.value((Number) innerValue); - } else { - mJsonWriter.value(innerValue.toString()); - } - } - mJsonWriter.endObject(); - } else if (value instanceof Key[]) { - Key[] keyboardKeys = (Key[]) value; - mJsonWriter.beginArray(); - for (Key keyboardKey : keyboardKeys) { - mJsonWriter.beginObject(); - mJsonWriter.name("code").value(keyboardKey.mCode); - mJsonWriter.name("altCode").value(keyboardKey.mAltCode); - mJsonWriter.name("x").value(keyboardKey.mX); - mJsonWriter.name("y").value(keyboardKey.mY); - mJsonWriter.name("w").value(keyboardKey.mWidth); - mJsonWriter.name("h").value(keyboardKey.mHeight); - mJsonWriter.endObject(); - } - mJsonWriter.endArray(); - } else if (value instanceof SuggestedWords) { - SuggestedWords words = (SuggestedWords) value; - mJsonWriter.beginObject(); - mJsonWriter.name("typedWordValid").value(words.mTypedWordValid); - mJsonWriter.name("willAutoCorrect").value(words.mWillAutoCorrect); - mJsonWriter.name("isPunctuationSuggestions") - .value(words.mIsPunctuationSuggestions); - mJsonWriter.name("isObsoleteSuggestions") - .value(words.mIsObsoleteSuggestions); - mJsonWriter.name("isPrediction") - .value(words.mIsPrediction); - mJsonWriter.name("words"); - mJsonWriter.beginArray(); - final int size = words.size(); - for (int j = 0; j < size; j++) { - SuggestedWordInfo wordInfo = words.getWordInfo(j); - mJsonWriter.value(wordInfo.toString()); - } - mJsonWriter.endArray(); - mJsonWriter.endObject(); - } else if (value == null) { - mJsonWriter.nullValue(); - } else { - Log.w(TAG, "Unrecognized type to be logged: " + - (value == null ? "" : value.getClass().getName())); - mJsonWriter.nullValue(); - } - } - mJsonWriter.endObject(); - } catch (IOException e) { - e.printStackTrace(); - Log.w(TAG, "Error in JsonWriter; disabling logging"); - try { - mJsonWriter.close(); - } catch (IllegalStateException e1) { - // assume that this is just the json not being terminated properly. - // ignore - } catch (IOException e1) { - e1.printStackTrace(); - } finally { - mJsonWriter = NULL_JSON_WRITER; - } + private void publishLogUnit(LogUnit logUnit, boolean isPrivacySensitive) { + if (isPrivacySensitive) { + mMainResearchLog.publishPublicEvents(logUnit); + } else { + mMainResearchLog.publishAllEvents(logUnit); } + mIntentionalResearchLogQueue.add(logUnit); } - private static class LogUnit implements Runnable { + /* package */ void publishCurrentLogUnit(ResearchLog researchLog, boolean isPrivacySensitive) { + publishLogUnit(mCurrentLogUnit, isPrivacySensitive); + } + + static class LogUnit { private final List mKeysList = new ArrayList(); private final List mValuesList = new ArrayList(); private final List mIsPotentiallyPrivate = new ArrayList(); - private boolean mRemovePotentiallyPrivateEvents = true; private void addLogAtom(final String[] keys, final Object[] values, final Boolean isPotentiallyPrivate) { @@ -586,20 +462,19 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mIsPotentiallyPrivate.add(isPotentiallyPrivate); } - void setRemovePotentiallyPrivateEvents(boolean removePotentiallyPrivateEvents) { - mRemovePotentiallyPrivateEvents = removePotentiallyPrivateEvents; + public void publishPublicEventsTo(ResearchLog researchLog) { + final int size = mKeysList.size(); + for (int i = 0; i < size; i++) { + if (!mIsPotentiallyPrivate.get(i)) { + researchLog.outputEvent(mKeysList.get(i), mValuesList.get(i)); + } + } } - @Override - public void run() { - final int numAtoms = mKeysList.size(); - for (int atomIndex = 0; atomIndex < numAtoms; atomIndex++) { - if (mRemovePotentiallyPrivateEvents && mIsPotentiallyPrivate.get(atomIndex)) { - continue; - } - final String[] keys = mKeysList.get(atomIndex); - final Object[] values = mValuesList.get(atomIndex); - ResearchLogger.getInstance().outputEvent(keys, values); + public void publishAllEventsTo(ResearchLog researchLog) { + final int size = mKeysList.size(); + for (int i = 0; i < size; i++) { + researchLog.outputEvent(mKeysList.get(i), mValuesList.get(i)); } } } @@ -642,6 +517,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return WORD_REPLACEMENT_STRING; } + private static final String[] EVENTKEYS_INTENTIONAL_LOG = { + "IntentionalLog" + }; private static final String[] EVENTKEYS_LATINKEYBOARDVIEW_PROCESSMOTIONEVENT = { "LatinKeyboardViewProcessMotionEvent", "action", "eventTime", "id", "x", "y", "size", "pressure" @@ -792,7 +670,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } final ResearchLogger researchLogger = getInstance(); researchLogger.enqueueEvent(EVENTKEYS_LATINIME_ONWINDOWHIDDEN, values); - researchLogger.flushEventQueue(true); // Play it safe. Remove privacy-sensitive events. + // Play it safe. Remove privacy-sensitive events. + researchLogger.publishLogUnit(researchLogger.mCurrentLogUnit, true); + researchLogger.mCurrentLogUnit = new LogUnit(); } } @@ -804,7 +684,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang final SharedPreferences prefs) { if (editorInfo != null) { final Object[] values = { - getUUID(prefs), editorInfo.packageName, Integer.toHexString(editorInfo.inputType), + getInstance().mUUIDString, editorInfo.packageName, + Integer.toHexString(editorInfo.inputType), Integer.toHexString(editorInfo.imeOptions), editorInfo.fieldId, Build.DISPLAY, Build.MODEL, prefs, OUTPUT_FORMAT_VERSION }; From b4b93dbf3e0912ba26c5c34abba7a5b94c74138c Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 10 Jul 2012 20:21:13 +0900 Subject: [PATCH 35/68] Pull up common code in the caller (A94) Change-Id: I84b97886280eca75d5f2b7546f20f8b1bced55bc --- .../inputmethod/latin/BinaryDictionary.java | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 291d84975..252cdf1f9 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -107,6 +107,10 @@ public class BinaryDictionary extends Dictionary { @Override public ArrayList getSuggestions(final WordComposer composer, final CharSequence prevWord, final ProximityInfo proximityInfo) { + if (!isValidDictionary()) return null; + Arrays.fill(mInputCodes, WordComposer.NOT_A_CODE); + Arrays.fill(mOutputChars, (char) 0); + Arrays.fill(mOutputScores, 0); if (composer.size() <= 1) { return TextUtils.isEmpty(prevWord) ? null : getBigramsInternal(composer, prevWord); } else { @@ -117,14 +121,9 @@ public class BinaryDictionary extends Dictionary { // TODO: move to native code private ArrayList getBigramsInternal(final WordComposer codes, final CharSequence previousWord) { - if (!isValidDictionary()) return null; - int[] codePoints = StringUtils.toCodePointArray(previousWord.toString()); - Arrays.fill(mOutputChars, (char) 0); - Arrays.fill(mOutputScores, 0); int codesSize = codes.size(); - Arrays.fill(mInputCodes, -1); if (codesSize > 0) { mInputCodes[0] = codes.getCodeAt(0); } @@ -156,10 +155,8 @@ public class BinaryDictionary extends Dictionary { // proximityInfo and/or prevWordForBigrams may not be null. private ArrayList getWordsInternal(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { - if (!isValidDictionary()) return null; - - final int count = getSuggestions(codes, prevWordForBigrams, proximityInfo, mOutputChars, - mOutputScores, mSpaceIndices); + final int count = getWordsInternalInternal(codes, prevWordForBigrams, proximityInfo, + mOutputChars, mOutputScores, mSpaceIndices); final ArrayList suggestions = new ArrayList(); for (int j = 0; j < count; ++j) { @@ -184,13 +181,10 @@ public class BinaryDictionary extends Dictionary { } // proximityInfo may not be null. - private int getSuggestions(final WordComposer codes, + // TODO: remove this method by inlining it into getWordsInternal + private int getWordsInternalInternal(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo, char[] outputChars, int[] scores, int[] spaceIndices) { - Arrays.fill(mInputCodes, WordComposer.NOT_A_CODE); - Arrays.fill(outputChars, (char) 0); - Arrays.fill(scores, 0); - final InputPointers ips = codes.getInputPointers(); final boolean isGesture = codes.isBatchMode(); final int codesSize; From ea98e026f1ad7732279aec6d06107f46ea0af93d Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 10 Jul 2012 20:26:34 +0900 Subject: [PATCH 36/68] Pull up some more common code (A95) Change-Id: I3ac7ee823471a6d1da8031e064bce38b0e5a8f5c --- .../inputmethod/latin/BinaryDictionary.java | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 252cdf1f9..c9402d96d 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -111,24 +111,26 @@ public class BinaryDictionary extends Dictionary { Arrays.fill(mInputCodes, WordComposer.NOT_A_CODE); Arrays.fill(mOutputChars, (char) 0); Arrays.fill(mOutputScores, 0); + // TODO: toLowerCase in the native code + final int[] prevWordCodePointArray = (null == prevWord) + ? null : StringUtils.toCodePointArray(prevWord.toString()); if (composer.size() <= 1) { - return TextUtils.isEmpty(prevWord) ? null : getBigramsInternal(composer, prevWord); + return TextUtils.isEmpty(prevWord) ? null : getBigramsInternal(composer, + prevWordCodePointArray); } else { - return getWordsInternal(composer, prevWord, proximityInfo); + return getWordsInternal(composer, prevWordCodePointArray, proximityInfo); } } // TODO: move to native code private ArrayList getBigramsInternal(final WordComposer codes, - final CharSequence previousWord) { - int[] codePoints = StringUtils.toCodePointArray(previousWord.toString()); - + final int[] previousWord) { int codesSize = codes.size(); if (codesSize > 0) { mInputCodes[0] = codes.getCodeAt(0); } - int count = getBigramsNative(mNativeDict, codePoints, codePoints.length, mInputCodes, + int count = getBigramsNative(mNativeDict, previousWord, previousWord.length, mInputCodes, codesSize, mOutputChars, mOutputScores, MAX_WORD_LENGTH, MAX_BIGRAMS); if (count > MAX_BIGRAMS) { count = MAX_BIGRAMS; @@ -154,9 +156,9 @@ public class BinaryDictionary extends Dictionary { // TODO: move to native code // proximityInfo and/or prevWordForBigrams may not be null. private ArrayList getWordsInternal(final WordComposer codes, - final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { - final int count = getWordsInternalInternal(codes, prevWordForBigrams, proximityInfo, - mOutputChars, mOutputScores, mSpaceIndices); + final int[] prevWord, final ProximityInfo proximityInfo) { + final int count = getWordsInternalInternal(codes, prevWord, proximityInfo, mOutputChars, + mOutputScores, mSpaceIndices); final ArrayList suggestions = new ArrayList(); for (int j = 0; j < count; ++j) { @@ -183,7 +185,7 @@ public class BinaryDictionary extends Dictionary { // proximityInfo may not be null. // TODO: remove this method by inlining it into getWordsInternal private int getWordsInternalInternal(final WordComposer codes, - final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo, + final int[] prevWord, final ProximityInfo proximityInfo, char[] outputChars, int[] scores, int[] spaceIndices) { final InputPointers ips = codes.getInputPointers(); final boolean isGesture = codes.isBatchMode(); @@ -199,13 +201,9 @@ public class BinaryDictionary extends Dictionary { } } - // TODO: toLowerCase in the native code - final int[] prevWordCodePointArray = (null == prevWordForBigrams) - ? null : StringUtils.toCodePointArray(prevWordForBigrams.toString()); - return getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), - mInputCodes, codesSize, 0 /* unused */, isGesture, prevWordCodePointArray, + mInputCodes, codesSize, 0 /* unused */, isGesture, prevWord, mUseFullEditDistance, outputChars, scores, spaceIndices); } From cfae32c610e829d88cf618c721e1e3217dd09024 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 10 Jul 2012 20:29:27 +0900 Subject: [PATCH 37/68] Remove parameters for easier inlining (A96) Change-Id: Ied2e291393609300173681e26e82b7dd36b41bd0 --- .../com/android/inputmethod/latin/BinaryDictionary.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index c9402d96d..0747959d6 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -157,8 +157,7 @@ public class BinaryDictionary extends Dictionary { // proximityInfo and/or prevWordForBigrams may not be null. private ArrayList getWordsInternal(final WordComposer codes, final int[] prevWord, final ProximityInfo proximityInfo) { - final int count = getWordsInternalInternal(codes, prevWord, proximityInfo, mOutputChars, - mOutputScores, mSpaceIndices); + final int count = getWordsInternalInternal(codes, prevWord, proximityInfo); final ArrayList suggestions = new ArrayList(); for (int j = 0; j < count; ++j) { @@ -185,8 +184,7 @@ public class BinaryDictionary extends Dictionary { // proximityInfo may not be null. // TODO: remove this method by inlining it into getWordsInternal private int getWordsInternalInternal(final WordComposer codes, - final int[] prevWord, final ProximityInfo proximityInfo, - char[] outputChars, int[] scores, int[] spaceIndices) { + final int[] prevWord, final ProximityInfo proximityInfo) { final InputPointers ips = codes.getInputPointers(); final boolean isGesture = codes.isBatchMode(); final int codesSize; @@ -204,7 +202,7 @@ public class BinaryDictionary extends Dictionary { return getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), mInputCodes, codesSize, 0 /* unused */, isGesture, prevWord, - mUseFullEditDistance, outputChars, scores, spaceIndices); + mUseFullEditDistance, mOutputChars, mOutputScores, mSpaceIndices); } public static float calcNormalizedScore(String before, String after, int score) { From e77f2996ea4eca42fbb46d0ce0a6055233b21c38 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 10 Jul 2012 20:33:37 +0900 Subject: [PATCH 38/68] Inline a method to avoid confusion (A97) Change-Id: I3c3ffcd3d40493f4bfa0f6596f923b3430e605aa --- .../inputmethod/latin/BinaryDictionary.java | 43 ++++++++----------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 0747959d6..42aa28351 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -157,7 +157,24 @@ public class BinaryDictionary extends Dictionary { // proximityInfo and/or prevWordForBigrams may not be null. private ArrayList getWordsInternal(final WordComposer codes, final int[] prevWord, final ProximityInfo proximityInfo) { - final int count = getWordsInternalInternal(codes, prevWord, proximityInfo); + final InputPointers ips = codes.getInputPointers(); + final boolean isGesture = codes.isBatchMode(); + final int codesSize; + if (isGesture) { + codesSize = ips.getPointerSize(); + } else { + codesSize = codes.size(); + // Won't deal with really long words. + if (codesSize > MAX_WORD_LENGTH - 1) return null; + for (int i = 0; i < codesSize; i++) { + mInputCodes[i] = codes.getCodeAt(i); + } + } + + final int count = getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), + ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), + mInputCodes, codesSize, 0 /* unused */, isGesture, prevWord, + mUseFullEditDistance, mOutputChars, mOutputScores, mSpaceIndices); final ArrayList suggestions = new ArrayList(); for (int j = 0; j < count; ++j) { @@ -181,30 +198,6 @@ public class BinaryDictionary extends Dictionary { return mNativeDict != 0; } - // proximityInfo may not be null. - // TODO: remove this method by inlining it into getWordsInternal - private int getWordsInternalInternal(final WordComposer codes, - final int[] prevWord, final ProximityInfo proximityInfo) { - final InputPointers ips = codes.getInputPointers(); - final boolean isGesture = codes.isBatchMode(); - final int codesSize; - if (isGesture) { - codesSize = ips.getPointerSize(); - } else { - codesSize = codes.size(); - // Won't deal with really long words. - if (codesSize > MAX_WORD_LENGTH - 1) return -1; - for (int i = 0; i < codesSize; i++) { - mInputCodes[i] = codes.getCodeAt(i); - } - } - - return getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), - ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), - mInputCodes, codesSize, 0 /* unused */, isGesture, prevWord, - mUseFullEditDistance, mOutputChars, mOutputScores, mSpaceIndices); - } - public static float calcNormalizedScore(String before, String after, int score) { return calcNormalizedScoreNative(before.toCharArray(), before.length(), after.toCharArray(), after.length(), score); From 8eaeb60e7fe930b810dbf5826c40dedf3d328e44 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 10 Jul 2012 20:36:20 +0900 Subject: [PATCH 39/68] Pull up some identical code (A98) Change-Id: I6c265956394cf49e74b0256dfa5af06fe6b30467 --- .../inputmethod/latin/BinaryDictionary.java | 62 +++++++------------ 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 42aa28351..f4a4960d7 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -114,31 +114,16 @@ public class BinaryDictionary extends Dictionary { // TODO: toLowerCase in the native code final int[] prevWordCodePointArray = (null == prevWord) ? null : StringUtils.toCodePointArray(prevWord.toString()); + final int count; if (composer.size() <= 1) { - return TextUtils.isEmpty(prevWord) ? null : getBigramsInternal(composer, + count = TextUtils.isEmpty(prevWord) ? -1 : getBigramsInternal(composer, prevWordCodePointArray); } else { - return getWordsInternal(composer, prevWordCodePointArray, proximityInfo); + count = getWordsInternal(composer, prevWordCodePointArray, proximityInfo); } - } - - // TODO: move to native code - private ArrayList getBigramsInternal(final WordComposer codes, - final int[] previousWord) { - int codesSize = codes.size(); - if (codesSize > 0) { - mInputCodes[0] = codes.getCodeAt(0); - } - - int count = getBigramsNative(mNativeDict, previousWord, previousWord.length, mInputCodes, - codesSize, mOutputChars, mOutputScores, MAX_WORD_LENGTH, MAX_BIGRAMS); - if (count > MAX_BIGRAMS) { - count = MAX_BIGRAMS; - } - final ArrayList suggestions = new ArrayList(); for (int j = 0; j < count; ++j) { - if (codesSize > 0 && mOutputScores[j] < 1) break; + if (composer.size() > 0 && mOutputScores[j] < 1) break; final int start = j * MAX_WORD_LENGTH; int len = 0; while (len < MAX_WORD_LENGTH && mOutputChars[start + len] != 0) { @@ -153,9 +138,25 @@ public class BinaryDictionary extends Dictionary { return suggestions; } + // TODO: move to native code + private int getBigramsInternal(final WordComposer codes, + final int[] previousWord) { + int codesSize = codes.size(); + if (codesSize > 0) { + mInputCodes[0] = codes.getCodeAt(0); + } + + int count = getBigramsNative(mNativeDict, previousWord, previousWord.length, mInputCodes, + codesSize, mOutputChars, mOutputScores, MAX_WORD_LENGTH, MAX_BIGRAMS); + if (count > MAX_BIGRAMS) { + count = MAX_BIGRAMS; + } + return count; + } + // TODO: move to native code // proximityInfo and/or prevWordForBigrams may not be null. - private ArrayList getWordsInternal(final WordComposer codes, + private int getWordsInternal(final WordComposer codes, final int[] prevWord, final ProximityInfo proximityInfo) { final InputPointers ips = codes.getInputPointers(); final boolean isGesture = codes.isBatchMode(); @@ -165,33 +166,16 @@ public class BinaryDictionary extends Dictionary { } else { codesSize = codes.size(); // Won't deal with really long words. - if (codesSize > MAX_WORD_LENGTH - 1) return null; + if (codesSize > MAX_WORD_LENGTH - 1) return -1; for (int i = 0; i < codesSize; i++) { mInputCodes[i] = codes.getCodeAt(i); } } - final int count = getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), + return getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), mInputCodes, codesSize, 0 /* unused */, isGesture, prevWord, mUseFullEditDistance, mOutputChars, mOutputScores, mSpaceIndices); - - final ArrayList suggestions = new ArrayList(); - for (int j = 0; j < count; ++j) { - if (mOutputScores[j] < 1) break; - final int start = j * MAX_WORD_LENGTH; - int len = 0; - while (len < MAX_WORD_LENGTH && mOutputChars[start + len] != 0) { - ++len; - } - if (len > 0) { - // TODO: actually get the kind from native code - suggestions.add(new SuggestedWordInfo( - new String(mOutputChars, start, len), - mOutputScores[j], SuggestedWordInfo.KIND_CORRECTION, mDictType)); - } - } - return suggestions; } /* package for test */ boolean isValidDictionary() { From 860a9f85ff7f2753b7e1bed2e00f86de8eca68e1 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 10 Jul 2012 20:43:19 +0900 Subject: [PATCH 40/68] Pull up some common code again (A99) Change-Id: I9e9f5664bb12bb25d74c8a076a6ee1024c708145 --- .../inputmethod/latin/BinaryDictionary.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index f4a4960d7..7da203544 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -114,6 +114,15 @@ public class BinaryDictionary extends Dictionary { // TODO: toLowerCase in the native code final int[] prevWordCodePointArray = (null == prevWord) ? null : StringUtils.toCodePointArray(prevWord.toString()); + final int composerSize = composer.size(); + + if (composerSize <= 1 || !composer.isBatchMode()) { + if (composerSize > MAX_WORD_LENGTH - 1) return null; + for (int i = 0; i < composerSize; i++) { + mInputCodes[i] = composer.getCodeAt(i); + } + } + final int count; if (composer.size() <= 1) { count = TextUtils.isEmpty(prevWord) ? -1 : getBigramsInternal(composer, @@ -142,9 +151,6 @@ public class BinaryDictionary extends Dictionary { private int getBigramsInternal(final WordComposer codes, final int[] previousWord) { int codesSize = codes.size(); - if (codesSize > 0) { - mInputCodes[0] = codes.getCodeAt(0); - } int count = getBigramsNative(mNativeDict, previousWord, previousWord.length, mInputCodes, codesSize, mOutputChars, mOutputScores, MAX_WORD_LENGTH, MAX_BIGRAMS); @@ -165,11 +171,6 @@ public class BinaryDictionary extends Dictionary { codesSize = ips.getPointerSize(); } else { codesSize = codes.size(); - // Won't deal with really long words. - if (codesSize > MAX_WORD_LENGTH - 1) return -1; - for (int i = 0; i < codesSize; i++) { - mInputCodes[i] = codes.getCodeAt(i); - } } return getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), From 82d5ed6fcda59f27b2016bdf744d4c1372da9d3c Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 10 Jul 2012 20:43:56 +0900 Subject: [PATCH 41/68] Small readability improvement (A100) Change-Id: I6340748654a95d203ed43ceb9a7e6468b5b8ab1c --- java/src/com/android/inputmethod/latin/BinaryDictionary.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 7da203544..5ecebebf8 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -125,8 +125,8 @@ public class BinaryDictionary extends Dictionary { final int count; if (composer.size() <= 1) { - count = TextUtils.isEmpty(prevWord) ? -1 : getBigramsInternal(composer, - prevWordCodePointArray); + if (TextUtils.isEmpty(prevWord)) return null; + count = getBigramsInternal(composer, prevWordCodePointArray); } else { count = getWordsInternal(composer, prevWordCodePointArray, proximityInfo); } From eb1443883f0b645459976f2d0471ccbb42ee946e Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Wed, 11 Jul 2012 14:20:41 +0900 Subject: [PATCH 42/68] Support batch input Change-Id: Ibe63212fe71cdebb5b897bc5018ae75b2a87555a --- java/src/com/android/inputmethod/latin/BinaryDictionary.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 5ecebebf8..3b294462e 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -124,7 +124,7 @@ public class BinaryDictionary extends Dictionary { } final int count; - if (composer.size() <= 1) { + if (!composer.isBatchMode() && composer.size() <= 1) { if (TextUtils.isEmpty(prevWord)) return null; count = getBigramsInternal(composer, prevWordCodePointArray); } else { From d6c610400e910ef2870371439c7d940842a1b73d Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 10 Jul 2012 20:47:01 +0900 Subject: [PATCH 43/68] Inline a wrapper method (A101) Change-Id: I6ce856ff49a8f8c696851b2487590704010fc758 --- .../inputmethod/latin/BinaryDictionary.java | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 3b294462e..90a037372 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -126,7 +126,10 @@ public class BinaryDictionary extends Dictionary { final int count; if (!composer.isBatchMode() && composer.size() <= 1) { if (TextUtils.isEmpty(prevWord)) return null; - count = getBigramsInternal(composer, prevWordCodePointArray); + int tmpCount = getBigramsNative(mNativeDict, prevWordCodePointArray, + prevWordCodePointArray.length, mInputCodes, composerSize, + mOutputChars, mOutputScores, MAX_WORD_LENGTH, MAX_BIGRAMS); + count = Math.min(tmpCount, MAX_BIGRAMS); } else { count = getWordsInternal(composer, prevWordCodePointArray, proximityInfo); } @@ -147,19 +150,6 @@ public class BinaryDictionary extends Dictionary { return suggestions; } - // TODO: move to native code - private int getBigramsInternal(final WordComposer codes, - final int[] previousWord) { - int codesSize = codes.size(); - - int count = getBigramsNative(mNativeDict, previousWord, previousWord.length, mInputCodes, - codesSize, mOutputChars, mOutputScores, MAX_WORD_LENGTH, MAX_BIGRAMS); - if (count > MAX_BIGRAMS) { - count = MAX_BIGRAMS; - } - return count; - } - // TODO: move to native code // proximityInfo and/or prevWordForBigrams may not be null. private int getWordsInternal(final WordComposer codes, From 9c09fd02eb98ebb938e8033371c7e0d4c5ce2f52 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 10 Jul 2012 20:49:18 +0900 Subject: [PATCH 44/68] Inline a method to be able to factorize code (A102) Change-Id: I121071f80c8af3c1053968dc76aaeca3352ca9a8 --- .../inputmethod/latin/BinaryDictionary.java | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 90a037372..255ef3ad1 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -131,7 +131,20 @@ public class BinaryDictionary extends Dictionary { mOutputChars, mOutputScores, MAX_WORD_LENGTH, MAX_BIGRAMS); count = Math.min(tmpCount, MAX_BIGRAMS); } else { - count = getWordsInternal(composer, prevWordCodePointArray, proximityInfo); + final InputPointers ips = composer.getInputPointers(); + final boolean isGesture = composer.isBatchMode(); + final int codesSize; + if (isGesture) { + codesSize = ips.getPointerSize(); + } else { + codesSize = composer.size(); + } + + // proximityInfo and/or prevWordForBigrams may not be null. + count = getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), + ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), + mInputCodes, codesSize, 0 /* unused */, isGesture, prevWordCodePointArray, + mUseFullEditDistance, mOutputChars, mOutputScores, mSpaceIndices); } final ArrayList suggestions = new ArrayList(); for (int j = 0; j < count; ++j) { @@ -150,25 +163,6 @@ public class BinaryDictionary extends Dictionary { return suggestions; } - // TODO: move to native code - // proximityInfo and/or prevWordForBigrams may not be null. - private int getWordsInternal(final WordComposer codes, - final int[] prevWord, final ProximityInfo proximityInfo) { - final InputPointers ips = codes.getInputPointers(); - final boolean isGesture = codes.isBatchMode(); - final int codesSize; - if (isGesture) { - codesSize = ips.getPointerSize(); - } else { - codesSize = codes.size(); - } - - return getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), - ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), - mInputCodes, codesSize, 0 /* unused */, isGesture, prevWord, - mUseFullEditDistance, mOutputChars, mOutputScores, mSpaceIndices); - } - /* package for test */ boolean isValidDictionary() { return mNativeDict != 0; } From 1250cdeab2da2c7f7d9c732a816dbc36e49fd61a Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Wed, 11 Jul 2012 15:11:12 +0900 Subject: [PATCH 45/68] Workaround to avoid a bug in the batch input bigram dictionary lookup Change-Id: I8a5641c88c45918d6bed81a0b03efdcff0b380c5 --- .../android/inputmethod/latin/BinaryDictionary.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 255ef3ad1..8ab047c67 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -111,9 +111,14 @@ public class BinaryDictionary extends Dictionary { Arrays.fill(mInputCodes, WordComposer.NOT_A_CODE); Arrays.fill(mOutputChars, (char) 0); Arrays.fill(mOutputScores, 0); + final boolean isGesture = composer.isBatchMode(); + final boolean isValidPrevWord = (prevWord == null) + // TODO: Remove this check. Unfortunately the current gesture recognition code has + // a double-free bug. + && !isGesture; // TODO: toLowerCase in the native code - final int[] prevWordCodePointArray = (null == prevWord) - ? null : StringUtils.toCodePointArray(prevWord.toString()); + final int[] prevWordCodePointArray = isValidPrevWord + ? StringUtils.toCodePointArray(prevWord.toString()) : null; final int composerSize = composer.size(); if (composerSize <= 1 || !composer.isBatchMode()) { @@ -124,7 +129,7 @@ public class BinaryDictionary extends Dictionary { } final int count; - if (!composer.isBatchMode() && composer.size() <= 1) { + if (!isGesture && composer.size() <= 1) { if (TextUtils.isEmpty(prevWord)) return null; int tmpCount = getBigramsNative(mNativeDict, prevWordCodePointArray, prevWordCodePointArray.length, mInputCodes, composerSize, @@ -132,7 +137,6 @@ public class BinaryDictionary extends Dictionary { count = Math.min(tmpCount, MAX_BIGRAMS); } else { final InputPointers ips = composer.getInputPointers(); - final boolean isGesture = composer.isBatchMode(); final int codesSize; if (isGesture) { codesSize = ips.getPointerSize(); From 5e21ea1a3553000529c288acdf6d6a4b165bedc5 Mon Sep 17 00:00:00 2001 From: Tadashi Takaoka Date: Wed, 11 Jul 2012 00:07:08 -0700 Subject: [PATCH 46/68] Revert "Workaround to avoid a bug in the batch input bigram dictionary lookup" This reverts commit 1250cdeab2da2c7f7d9c732a816dbc36e49fd61a --- .../android/inputmethod/latin/BinaryDictionary.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 8ab047c67..255ef3ad1 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -111,14 +111,9 @@ public class BinaryDictionary extends Dictionary { Arrays.fill(mInputCodes, WordComposer.NOT_A_CODE); Arrays.fill(mOutputChars, (char) 0); Arrays.fill(mOutputScores, 0); - final boolean isGesture = composer.isBatchMode(); - final boolean isValidPrevWord = (prevWord == null) - // TODO: Remove this check. Unfortunately the current gesture recognition code has - // a double-free bug. - && !isGesture; // TODO: toLowerCase in the native code - final int[] prevWordCodePointArray = isValidPrevWord - ? StringUtils.toCodePointArray(prevWord.toString()) : null; + final int[] prevWordCodePointArray = (null == prevWord) + ? null : StringUtils.toCodePointArray(prevWord.toString()); final int composerSize = composer.size(); if (composerSize <= 1 || !composer.isBatchMode()) { @@ -129,7 +124,7 @@ public class BinaryDictionary extends Dictionary { } final int count; - if (!isGesture && composer.size() <= 1) { + if (!composer.isBatchMode() && composer.size() <= 1) { if (TextUtils.isEmpty(prevWord)) return null; int tmpCount = getBigramsNative(mNativeDict, prevWordCodePointArray, prevWordCodePointArray.length, mInputCodes, composerSize, @@ -137,6 +132,7 @@ public class BinaryDictionary extends Dictionary { count = Math.min(tmpCount, MAX_BIGRAMS); } else { final InputPointers ips = composer.getInputPointers(); + final boolean isGesture = composer.isBatchMode(); final int codesSize; if (isGesture) { codesSize = ips.getPointerSize(); From e4e7e5fc82eca67330765510ad0bd29caeb7a1bb Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 10 Jul 2012 20:50:52 +0900 Subject: [PATCH 47/68] Cleanup (A103) Change-Id: Ib5ebddfdb87ef71a2f8d859fb45d3ac78040e97a --- .../inputmethod/latin/BinaryDictionary.java | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 255ef3ad1..20c1b25db 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -116,7 +116,8 @@ public class BinaryDictionary extends Dictionary { ? null : StringUtils.toCodePointArray(prevWord.toString()); final int composerSize = composer.size(); - if (composerSize <= 1 || !composer.isBatchMode()) { + final boolean isGesture = composer.isBatchMode(); + if (composerSize <= 1 || !isGesture) { if (composerSize > MAX_WORD_LENGTH - 1) return null; for (int i = 0; i < composerSize; i++) { mInputCodes[i] = composer.getCodeAt(i); @@ -124,7 +125,7 @@ public class BinaryDictionary extends Dictionary { } final int count; - if (!composer.isBatchMode() && composer.size() <= 1) { + if (!isGesture && composerSize <= 1) { if (TextUtils.isEmpty(prevWord)) return null; int tmpCount = getBigramsNative(mNativeDict, prevWordCodePointArray, prevWordCodePointArray.length, mInputCodes, composerSize, @@ -132,23 +133,17 @@ public class BinaryDictionary extends Dictionary { count = Math.min(tmpCount, MAX_BIGRAMS); } else { final InputPointers ips = composer.getInputPointers(); - final boolean isGesture = composer.isBatchMode(); - final int codesSize; - if (isGesture) { - codesSize = ips.getPointerSize(); - } else { - codesSize = composer.size(); - } - + final int codesSize = isGesture ? ips.getPointerSize() : composerSize; // proximityInfo and/or prevWordForBigrams may not be null. count = getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), mInputCodes, codesSize, 0 /* unused */, isGesture, prevWordCodePointArray, mUseFullEditDistance, mOutputChars, mOutputScores, mSpaceIndices); } + final ArrayList suggestions = new ArrayList(); for (int j = 0; j < count; ++j) { - if (composer.size() > 0 && mOutputScores[j] < 1) break; + if (composerSize > 0 && mOutputScores[j] < 1) break; final int start = j * MAX_WORD_LENGTH; int len = 0; while (len < MAX_WORD_LENGTH && mOutputChars[start + len] != 0) { From 8f7f04fead0a7ce9cabaa6e4ed310d53510b5cd0 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Wed, 11 Jul 2012 15:33:02 -0700 Subject: [PATCH 48/68] Import translations. DO NOT MERGE Change-Id: I056d8d8d630a2b3576462f7900bc39a7f19f5aa0 Auto-generated-cl: translation import --- java/res/values-af/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-af/strings.xml | 10 ++++++++ java/res/values-am/strings-appname.xml | 3 +-- java/res/values-am/strings.xml | 10 ++++++++ java/res/values-ar/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-ar/strings.xml | 10 ++++++++ java/res/values-be/strings.xml | 10 ++++++++ java/res/values-bg/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-bg/strings.xml | 10 ++++++++ java/res/values-ca/strings.xml | 10 ++++++++ java/res/values-cs/strings-appname.xml | 27 +++++++++++++++++++++ java/res/values-cs/strings.xml | 10 ++++++++ java/res/values-da/strings-appname.xml | 3 +-- java/res/values-da/strings.xml | 10 ++++++++ java/res/values-de/strings-appname.xml | 3 +-- java/res/values-de/strings.xml | 10 ++++++++ java/res/values-el/strings-appname.xml | 3 +-- java/res/values-el/strings.xml | 10 ++++++++ java/res/values-en-rGB/strings.xml | 10 ++++++++ java/res/values-es-rUS/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-es-rUS/strings.xml | 10 ++++++++ java/res/values-es/strings-appname.xml | 3 +-- java/res/values-es/strings.xml | 10 ++++++++ java/res/values-et/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-et/strings.xml | 10 ++++++++ java/res/values-fa/strings.xml | 10 ++++++++ java/res/values-fi/strings.xml | 10 ++++++++ java/res/values-fr/strings.xml | 10 ++++++++ java/res/values-hi/strings.xml | 10 ++++++++ java/res/values-hr/strings-appname.xml | 3 +-- java/res/values-hr/strings.xml | 10 ++++++++ java/res/values-hu/strings-appname.xml | 27 +++++++++++++++++++++ java/res/values-hu/strings.xml | 10 ++++++++ java/res/values-in/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-in/strings.xml | 10 ++++++++ java/res/values-it/strings-appname.xml | 3 +-- java/res/values-it/strings.xml | 10 ++++++++ java/res/values-iw/strings-appname.xml | 3 +-- java/res/values-iw/strings.xml | 10 ++++++++ java/res/values-ja/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-ja/strings.xml | 10 ++++++++ java/res/values-ko/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-ko/strings.xml | 10 ++++++++ java/res/values-lt/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-lt/strings.xml | 10 ++++++++ java/res/values-lv/strings.xml | 10 ++++++++ java/res/values-ms/strings.xml | 10 ++++++++ java/res/values-nb/strings.xml | 10 ++++++++ java/res/values-nl/strings-appname.xml | 3 +-- java/res/values-nl/strings.xml | 10 ++++++++ java/res/values-pl/strings.xml | 10 ++++++++ java/res/values-pt-rPT/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-pt-rPT/strings.xml | 10 ++++++++ java/res/values-pt/strings.xml | 10 ++++++++ java/res/values-rm/strings.xml | 10 ++++++++ java/res/values-ro/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-ro/strings.xml | 10 ++++++++ java/res/values-ru/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-ru/strings.xml | 10 ++++++++ java/res/values-sk/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-sk/strings.xml | 10 ++++++++ java/res/values-sl/strings.xml | 10 ++++++++ java/res/values-sr/strings-appname.xml | 3 +-- java/res/values-sr/strings.xml | 10 ++++++++ java/res/values-sv/strings-appname.xml | 3 +-- java/res/values-sv/strings.xml | 10 ++++++++ java/res/values-sw/strings-appname.xml | 3 +-- java/res/values-sw/strings.xml | 10 ++++++++ java/res/values-th/strings.xml | 10 ++++++++ java/res/values-tl/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-tl/strings.xml | 10 ++++++++ java/res/values-tr/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-tr/strings.xml | 10 ++++++++ java/res/values-uk/strings.xml | 10 ++++++++ java/res/values-vi/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-vi/strings.xml | 10 ++++++++ java/res/values-zh-rCN/strings.xml | 10 ++++++++ java/res/values-zh-rTW/strings-appname.xml | 28 ++++++++++++++++++++++ java/res/values-zh-rTW/strings.xml | 10 ++++++++ java/res/values-zu/strings.xml | 10 ++++++++ 80 files changed, 1032 insertions(+), 24 deletions(-) create mode 100644 java/res/values-af/strings-appname.xml create mode 100644 java/res/values-ar/strings-appname.xml create mode 100644 java/res/values-bg/strings-appname.xml create mode 100644 java/res/values-cs/strings-appname.xml create mode 100644 java/res/values-es-rUS/strings-appname.xml create mode 100644 java/res/values-et/strings-appname.xml create mode 100644 java/res/values-hu/strings-appname.xml create mode 100644 java/res/values-in/strings-appname.xml create mode 100644 java/res/values-ja/strings-appname.xml create mode 100644 java/res/values-ko/strings-appname.xml create mode 100644 java/res/values-lt/strings-appname.xml create mode 100644 java/res/values-pt-rPT/strings-appname.xml create mode 100644 java/res/values-ro/strings-appname.xml create mode 100644 java/res/values-ru/strings-appname.xml create mode 100644 java/res/values-sk/strings-appname.xml create mode 100644 java/res/values-tl/strings-appname.xml create mode 100644 java/res/values-tr/strings-appname.xml create mode 100644 java/res/values-vi/strings-appname.xml create mode 100644 java/res/values-zh-rTW/strings-appname.xml diff --git a/java/res/values-af/strings-appname.xml b/java/res/values-af/strings-appname.xml new file mode 100644 index 000000000..1adf723d7 --- /dev/null +++ b/java/res/values-af/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Android-speltoetser" + "Android-sleutelbordinstellings" + "Speltoets tans instellings" + diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml index 30d5f5da1..fb7cf349f 100644 --- a/java/res/values-af/strings.xml +++ b/java/res/values-af/strings.xml @@ -107,9 +107,19 @@ "let op die tydstempel in die loglêer" "Aangetekende tydstempel" "Moenie hierdie sessie aanteken nie" + + + + "Sessie se loglêer uitgevee" "Sessie se loglêer uitgevee" "Sessie se loglêer NIE uitgevee nie" + + + + + + "Invoertale" "Raak weer om te stoor" "Woordeboek beskikbaar" diff --git a/java/res/values-am/strings-appname.xml b/java/res/values-am/strings-appname.xml index da0ab2f16..fd93114f3 100644 --- a/java/res/values-am/strings-appname.xml +++ b/java/res/values-am/strings-appname.xml @@ -20,8 +20,7 @@ - - + "የAndroid ቁልፍ ሰሌዳ" "Android የፊደል አራሚ" "Android የቁልፍ ሰሌዳ ቅንብሮች" "የፊደል አራሚ ቅንብሮች" diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml index 69493b750..1066a2ca9 100644 --- a/java/res/values-am/strings.xml +++ b/java/res/values-am/strings.xml @@ -107,9 +107,19 @@ "የምዝግብ ማስታወሻ ጊዜ ማህተም ማስታወሻ" "የጊዜ ማህተም ተመዝግቧል" "ይህን ክፍለ ጊዜ እንዳትመዘግበው" + + + + "የክፍለጊዜ ምዝግብ ማስታወሻ በመሰረዝ ላይ" "የክፍለ ጊዜ ምዝግብ ማስታወሻ ተሰርዟል" "የክፍለጊዜ ምዝግብ ማስታወሻ አልተሰረዘም" + + + + + + "ቋንቋዎች አግቤት" "ለማስቀመጥ እንደገና ንካ" "መዝገበ ቃላት አለ" diff --git a/java/res/values-ar/strings-appname.xml b/java/res/values-ar/strings-appname.xml new file mode 100644 index 000000000..32be444b3 --- /dev/null +++ b/java/res/values-ar/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "التدقيق الإملائي في Android" + "إعدادات لوحة مفاتيح Android" + "إعدادات التدقيق الإملائي" + diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml index eb7e30604..cea27017f 100644 --- a/java/res/values-ar/strings.xml +++ b/java/res/values-ar/strings.xml @@ -107,9 +107,19 @@ "ملاحظة طابع زمني في سجل" "تم تسجيل الطابع الزمني" "عدم تسجيل هذه الجلسة" + + + + "جارٍ حذف سجل الجلسة" "تم حذف سجل الجلسة" "لم يتم حذف سجل الجلسة" + + + + + + "لغات الإدخال" "المس مرة أخرى للحفظ" "القاموس متاح" diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml index d67ddc034..3ac96f0d6 100644 --- a/java/res/values-be/strings.xml +++ b/java/res/values-be/strings.xml @@ -107,9 +107,19 @@ "Пазначыць час у гiсторыi" "Запiсаныя пазнакі" "Не рэгістраваць гэты сеанс" + + + + "Выдаленне гiсторыi сеанса" "Гiсторыя сеанса выдалена" "Гiсторыя сеанса НЕ выдалена" + + + + + + "Мовы ўводу" "Дакраніцеся зноў, каб захаваць" "Слоўнік даступны" diff --git a/java/res/values-bg/strings-appname.xml b/java/res/values-bg/strings-appname.xml new file mode 100644 index 000000000..9976f099f --- /dev/null +++ b/java/res/values-bg/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Програма за правописна проверка за Android" + "Настройки на клавиатурата на Android" + "Настройки за проверка на правописа" + diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml index 5cd6fcaa7..38ebfe84a 100644 --- a/java/res/values-bg/strings.xml +++ b/java/res/values-bg/strings.xml @@ -107,9 +107,19 @@ "Отбелязване на часа в рег. файл" "Часът е записан" "Без регистр. на сесията" + + + + "Рег. файл на сесията се изтрива" "Рег. файл на сесията е изтрит" "Рег. файл на сесията НЕ Е изтрит" + + + + + + "Езици за въвеждане" "Докоснете отново, за да запазите" "Има достъп до речник" diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml index 01cc422c4..367fdff7d 100644 --- a/java/res/values-ca/strings.xml +++ b/java/res/values-ca/strings.xml @@ -107,9 +107,19 @@ "Indica m. horària al reg." "Marca horària enregistrada" "No enregistris la sessió" + + + + "Suprimint registre de ses." "Registre de ses. suprimit" "Registre de ses. NO sup." + + + + + + "Idiomes d\'entrada" "Torna a tocar per desar" "Diccionari disponible" diff --git a/java/res/values-cs/strings-appname.xml b/java/res/values-cs/strings-appname.xml new file mode 100644 index 000000000..0eeac88b4 --- /dev/null +++ b/java/res/values-cs/strings-appname.xml @@ -0,0 +1,27 @@ + + + + + "Klávesnice Android" + "Kontrola pravopisu Android" + "Nastavení klávesnice Android" + "Nastavení kontroly pravopisu" + diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml index 9764ce501..fa47c5bb1 100644 --- a/java/res/values-cs/strings.xml +++ b/java/res/values-cs/strings.xml @@ -107,9 +107,19 @@ "Uložit čas do protokolu" "Časové razítko vloženo" "Neprotokolovat relaci" + + + + "Mazání protokolu relace" "Protokol relace smazán" "Protokol relace nesmazán" + + + + + + "Vstupní jazyky" "Opětovným dotykem provedete uložení" "Slovník k dispozici" diff --git a/java/res/values-da/strings-appname.xml b/java/res/values-da/strings-appname.xml index 610d88aaa..faef5824b 100644 --- a/java/res/values-da/strings-appname.xml +++ b/java/res/values-da/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Android-tastatur" "Android-stavekontrol" "Indstillinger for Android-tastatur" "Indstillinger for stavekontrol" diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml index e669f7168..4a4e9416d 100644 --- a/java/res/values-da/strings.xml +++ b/java/res/values-da/strings.xml @@ -107,9 +107,19 @@ "Notér tidsstempel i log" "Noteret tidsstempel" "Logfør ikke denne session" + + + + "Sletter sessionslogfil" "Sessionslogfil slettet" "Sessionslog IKKE slettet" + + + + + + "Inputsprog" "Tryk igen for at gemme" "Ordbog er tilgængelig" diff --git a/java/res/values-de/strings-appname.xml b/java/res/values-de/strings-appname.xml index bc77f722e..fc5fb8902 100644 --- a/java/res/values-de/strings-appname.xml +++ b/java/res/values-de/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Android-Tastatur" "Android-Rechtschreibprüfung" "Android-Tastatureinstellungen" "Einstellungen für Rechtschreibprüfung" diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml index 827ff602b..c4b1aeec4 100644 --- a/java/res/values-de/strings.xml +++ b/java/res/values-de/strings.xml @@ -107,9 +107,19 @@ "Zeitstempel im Protokoll" "Zeitstempel aufgenommen" "Nicht protokollieren" + + + + "Protokoll wird gelöscht..." "Protokoll gelöscht" "Protokoll NICHT gelöscht" + + + + + + "Eingabesprachen" "Zum Speichern erneut berühren" "Wörterbuch verfügbar" diff --git a/java/res/values-el/strings-appname.xml b/java/res/values-el/strings-appname.xml index 6daf2d97c..a199655f2 100644 --- a/java/res/values-el/strings-appname.xml +++ b/java/res/values-el/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Πληκτρολόγιο Android" "Ορθογραφικός έλεγχος Android" "Ρυθμίσεις πληκτρολογίου Android" "Ρυθμίσεις ορθογραφικού ελέγχου" diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml index 563e18124..c2df29592 100644 --- a/java/res/values-el/strings.xml +++ b/java/res/values-el/strings.xml @@ -107,9 +107,19 @@ "Χρόνος στο αρχείο καταγρ." "Καταγεγραμμένος χρόνος" "Χωρίς αρχείο καταγραφής" + + + + "Διαγραφή αρχείου σύνδεσης" "Αρχείο καταγρ. διαγράφηκε" "Αρχείο καταγρ. ΔΕΝ διαγρ." + + + + + + "Γλώσσες εισόδου" "Αγγίξτε ξανά για αποθήκευση" "Λεξικό διαθέσιμο" diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml index 513fae4c5..b7e6e0ca4 100644 --- a/java/res/values-en-rGB/strings.xml +++ b/java/res/values-en-rGB/strings.xml @@ -107,9 +107,19 @@ "Note timestamp in log" "Recorded timestamp" "Do not log this session" + + + + "Deleting session log" "Session log deleted" "Session log NOT deleted" + + + + + + "Input languages" "Touch again to save" "Dictionary available" diff --git a/java/res/values-es-rUS/strings-appname.xml b/java/res/values-es-rUS/strings-appname.xml new file mode 100644 index 000000000..91c1b929b --- /dev/null +++ b/java/res/values-es-rUS/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Corrector ortográfico de Android" + "Configuración de teclado de Android" + "Configuración del corrector ortográfico" + diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml index 3eb32c12a..7b1470a64 100644 --- a/java/res/values-es-rUS/strings.xml +++ b/java/res/values-es-rUS/strings.xml @@ -107,9 +107,19 @@ "Marcar tiempo en registro" "Marca tiempo registrada" "No registrar esta sesión" + + + + "Eliminando registro" "Registro sesión eliminado" "NO se eliminó el registro" + + + + + + "Idiomas de entrada" "Vuelve a tocar para guardar." "Diccionario disponible" diff --git a/java/res/values-es/strings-appname.xml b/java/res/values-es/strings-appname.xml index e716e7d89..cce9a176d 100644 --- a/java/res/values-es/strings-appname.xml +++ b/java/res/values-es/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Teclado de Android" "Corrector ortográfico de Android" "Ajustes del teclado de Android" "Ajustes del corrector ortográfico" diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml index 1eee5d970..b86d7fd0e 100644 --- a/java/res/values-es/strings.xml +++ b/java/res/values-es/strings.xml @@ -107,9 +107,19 @@ "Anotar marca tiempo en registro" "Marca de tiempo registrada" "No registrar esta sesión" + + + + "Eliminando registro..." "Registro eliminado" "Registro no eliminado" + + + + + + "Idiomas de entrada" "Toca otra vez para guardar." "Hay un diccionario disponible" diff --git a/java/res/values-et/strings-appname.xml b/java/res/values-et/strings-appname.xml new file mode 100644 index 000000000..2e0780e5b --- /dev/null +++ b/java/res/values-et/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Androidi õigekirjakontroll" + "Androidi klaviatuuri seaded" + "Õigekirjakontrolli seaded" + diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml index a68e5656f..cb010a0e5 100644 --- a/java/res/values-et/strings.xml +++ b/java/res/values-et/strings.xml @@ -107,9 +107,19 @@ "Märgi ajatempel logisse" "Salvestatud ajatemplid" "Ära logi seda seanssi" + + + + "Seansi logi kustutamine" "Seansi logi kustutatud" "Seansi logi EI kustutatud" + + + + + + "Sisestuskeeled" "Salvestamiseks puudutage uuesti" "Sõnastik saadaval" diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml index d61d7eb62..5dd7c31b2 100644 --- a/java/res/values-fa/strings.xml +++ b/java/res/values-fa/strings.xml @@ -111,9 +111,19 @@ "یادداشت مهر زمان در گزارش" "مهر زمان ثبت شده" "از این جلسه گزارش‌گیری نشود" + + + + "در حال حذف گزارش جلسه" "گزارش جلسه حذف شد" "گزارش جلسه حذف نشد" + + + + + + "زبان‌های ورودی" "برای ذخیره دوباره لمس کنید" "دیکشنری موجود است" diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml index c036142a6..8b4e2a418 100644 --- a/java/res/values-fi/strings.xml +++ b/java/res/values-fi/strings.xml @@ -107,9 +107,19 @@ "Merkitse aikaleima lokiin" "Merkitty aikaleima" "Älä tallenna tätä käyttök." + + + + "Poistetaan lokia" "Käyttökertaloki poistettu" "Lokia EI poistettu" + + + + + + "Syöttökielet" "Tallenna koskettamalla uudelleen" "Sanakirja saatavilla" diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml index b5b1eac64..edcb5ba84 100644 --- a/java/res/values-fr/strings.xml +++ b/java/res/values-fr/strings.xml @@ -107,9 +107,19 @@ "Noter heure dans journal" "Heure enregistrée." "Ne pas enregistrer session" + + + + "Suppr. journal session…" "Journal session supprimé." "Journal session PAS suppr." + + + + + + "Langues de saisie" "Appuyer de nouveau pour enregistrer" "Dictionnaire disponible" diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml index a567faf57..81fb684bf 100644 --- a/java/res/values-hi/strings.xml +++ b/java/res/values-hi/strings.xml @@ -107,9 +107,19 @@ "लॉग में टाइमस्‍टैम्‍प नोट करें" "रिकॉर्ड किया गया टाइमस्टैम्प" "इस सत्र को लॉग न करें" + + + + "सत्र लॉग हटाया जा रहा है" "सत्र लॉग हटाया गया" "सत्र लॉग हटाया नहीं गया" + + + + + + "इनपुट भाषाएं" "सहेजने के लिए पुन: स्‍पर्श करें" "शब्‍दकोश उपलब्‍ध है" diff --git a/java/res/values-hr/strings-appname.xml b/java/res/values-hr/strings-appname.xml index 6457a21cf..69fa2e9a1 100644 --- a/java/res/values-hr/strings-appname.xml +++ b/java/res/values-hr/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Androidova tipkovnica" "Androidova provjera pravopisa" "Postavke Androidove tipkovnice" "Postavke provjere pravopisa" diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml index 76f6edfa8..94caf6ea3 100644 --- a/java/res/values-hr/strings.xml +++ b/java/res/values-hr/strings.xml @@ -107,9 +107,19 @@ "Zabilježi razdoblje u dnevniku" "Zabilježeno razdoblje" "Ne bilježi ovu sesiju" + + + + "Brisanje dnevnika sesije" "Izbrisan dnevnik sesije" "Dnevnik sesije NIJE izbrisan" + + + + + + "Jezici unosa" "Dodirnite ponovo za spremanje" "Rječnik je dostupan" diff --git a/java/res/values-hu/strings-appname.xml b/java/res/values-hu/strings-appname.xml new file mode 100644 index 000000000..ad511cfbc --- /dev/null +++ b/java/res/values-hu/strings-appname.xml @@ -0,0 +1,27 @@ + + + + + "Android-billentyűzet" + "Androidos helyesírás-ellenőrző" + "Android-billentyűzet beállításai" + "A helyesírás-ellenőrzés beállításai" + diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml index 4bf9f4280..a0110e49a 100644 --- a/java/res/values-hu/strings.xml +++ b/java/res/values-hu/strings.xml @@ -107,9 +107,19 @@ "Időbélyegző naplózáskor" "Rögzített időbélyegzők" "Ne naplózza" + + + + "Napló törlése folyamatban" "Napló törölve" "Napló NINCS törölve" + + + + + + "Beviteli nyelvek" "Érintse meg újból a mentéshez" "Van elérhető szótár" diff --git a/java/res/values-in/strings-appname.xml b/java/res/values-in/strings-appname.xml new file mode 100644 index 000000000..363d57197 --- /dev/null +++ b/java/res/values-in/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Pemeriksa ejaan Android" + "Setelan keyboard Android" + "Setelan pemeriksa ejaan" + diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml index ee4651c9e..ebc0c3e59 100644 --- a/java/res/values-in/strings.xml +++ b/java/res/values-in/strings.xml @@ -107,9 +107,19 @@ "Catat cap waktu di log" "Cap waktu yang direkam" "Jangan simpan log sesi ini" + + + + "Menghapus log sesi" "Log sesi dihapus" "Log sesi BELUM dihapus" + + + + + + "Bahasa masukan" "Sentuh lagi untuk menyimpan" "Kamus yang tersedia" diff --git a/java/res/values-it/strings-appname.xml b/java/res/values-it/strings-appname.xml index 838daaf40..b84896b9d 100644 --- a/java/res/values-it/strings-appname.xml +++ b/java/res/values-it/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Tastiera Android" "Controllo ortografico Android" "Impostazioni tastiera Android" "Impostazioni di controllo ortografico" diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml index e52e250d2..2345f447e 100644 --- a/java/res/values-it/strings.xml +++ b/java/res/values-it/strings.xml @@ -107,9 +107,19 @@ "Indicazione temporale log" "Indicazione temporale registrata" "Non registrare la sessione" + + + + "Eliminazione log sessione" "Log di sessione eliminato" "Log sessione non eliminato" + + + + + + "Lingue comandi" "Tocca di nuovo per salvare" "Dizionario disponibile" diff --git a/java/res/values-iw/strings-appname.xml b/java/res/values-iw/strings-appname.xml index 92bc240f1..f3f4b674c 100644 --- a/java/res/values-iw/strings-appname.xml +++ b/java/res/values-iw/strings-appname.xml @@ -20,8 +20,7 @@ - - + "מקלדת Android" "בודק האיות של Android" "הגדרות מקלדת Android" "הגדרות בדיקת איות" diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml index 662f2f462..a69ba9f4f 100644 --- a/java/res/values-iw/strings.xml +++ b/java/res/values-iw/strings.xml @@ -107,9 +107,19 @@ "ציין חותמת זמן ביומן" "חותמת זמן מתועדת" "אל תרשום הפעלה זו ביומן" + + + + "מוחק יומן הפעלה" "יומן הפעלה נמחק" "יומן הפעלה לא נמחק" + + + + + + "שפות קלט" "גע שוב כדי לשמור" "מילון זמין" diff --git a/java/res/values-ja/strings-appname.xml b/java/res/values-ja/strings-appname.xml new file mode 100644 index 000000000..fd91575b3 --- /dev/null +++ b/java/res/values-ja/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Androidスペルチェッカー" + "Androidキーボードの設定" + "スペルチェックの設定" + diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml index 050ca66ec..ca13bb9ce 100644 --- a/java/res/values-ja/strings.xml +++ b/java/res/values-ja/strings.xml @@ -107,9 +107,19 @@ "タイムスタンプを記録" "タイムスタンプ記録済み" "セッションを記録しない" + + + + "セッションログ削除中" "セッションログ削除済み" "セッションログ未削除" + + + + + + "入力言語" "保存するにはもう一度タップ" "辞書を利用できます" diff --git a/java/res/values-ko/strings-appname.xml b/java/res/values-ko/strings-appname.xml new file mode 100644 index 000000000..0dc7e6fb9 --- /dev/null +++ b/java/res/values-ko/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Android 맞춤법 검사기" + "Android 키보드 설정" + "맞춤법 검사 설정" + diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml index 516c8c382..3126b2e66 100644 --- a/java/res/values-ko/strings.xml +++ b/java/res/values-ko/strings.xml @@ -107,9 +107,19 @@ "로그에 타임스탬프를 기록" "타임스탬프를 기록함" "이 세션을 로그하지 마세요." + + + + "세션 로그 삭제" "세션 로그가 삭제됨" "세션 로그가 삭제되지 않음" + + + + + + "입력 언어" "저장하려면 다시 터치" "사전 사용 가능" diff --git a/java/res/values-lt/strings-appname.xml b/java/res/values-lt/strings-appname.xml new file mode 100644 index 000000000..e32a94585 --- /dev/null +++ b/java/res/values-lt/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "„Android“ rašybos tikrinimo programa" + "„Android“ klaviatūros nustatymai" + "Rašybos tikrinimo nustatymai" + diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml index 08d66595b..ef17d70d0 100644 --- a/java/res/values-lt/strings.xml +++ b/java/res/values-lt/strings.xml @@ -107,9 +107,19 @@ "Pažym. laiko žymę žurnale" "Įrašyta laiko žymė" "Neįrašyti šios sesijos" + + + + "Ištrinam. sesijos žurnal." "Sesijos žurnalas ištrint." "Sesij. žurnal. NEIŠTRINT." + + + + + + "Įvesties kalbos" "Jei norite išsaugoti, palieskite dar kartą" "Žodynas galimas" diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml index 3685cccbe..d325ef85f 100644 --- a/java/res/values-lv/strings.xml +++ b/java/res/values-lv/strings.xml @@ -107,9 +107,19 @@ "Atzīmēt laiksp. žurnālā" "Laikspied. ir reģistrēts." "Nereģistrēt šo sesiju" + + + + "Not. sesijas žurn. dzēš." "Sesijas žurnāls ir dzēsts" "Sesijas žurn. NAV dzēsts" + + + + + + "Ievades valodas" "Pieskarieties vēlreiz, lai saglabātu." "Ir pieejama vārdnīca." diff --git a/java/res/values-ms/strings.xml b/java/res/values-ms/strings.xml index 59fec8845..cdd23a8de 100644 --- a/java/res/values-ms/strings.xml +++ b/java/res/values-ms/strings.xml @@ -107,9 +107,19 @@ "Tanda cap waktu dalam log" "Cap waktu direkodkan" "Jangan log sesi ini" + + + + "Memadam log sesi" "Log sesi dipadam" "Log sesi TIDAK dipadam" + + + + + + "Bahasa input" "Sentuh lagi untuk menyimpan" "Kamus tersedia" diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml index 2f4194ac0..43b226965 100644 --- a/java/res/values-nb/strings.xml +++ b/java/res/values-nb/strings.xml @@ -107,9 +107,19 @@ "Notér tidsstempel i logg" "Registrerte tidsstempel" "Ikke loggfør denne økten" + + + + "Sletter øktloggen" "Øktloggen ble slettet" "Øktloggen ble IKKE slettet" + + + + + + "Inndataspråk" "Trykk på nytt for å lagre" "Ordbok tilgjengelig" diff --git a/java/res/values-nl/strings-appname.xml b/java/res/values-nl/strings-appname.xml index f1cb252c2..ee288efbb 100644 --- a/java/res/values-nl/strings-appname.xml +++ b/java/res/values-nl/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Android-toetsenbord" "Spellingcontrole van Android" "Instellingen voor Android-toetsenbord" "Instellingen voor spellingcontrole" diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml index c42cd100b..a7188113d 100644 --- a/java/res/values-nl/strings.xml +++ b/java/res/values-nl/strings.xml @@ -107,9 +107,19 @@ "Tijdstempel opnemen in logbestand" "Opgenomen tijdstempel" "Sessie niet registreren" + + + + "Sessielogbestand verwijderen" "Sessielogbestand verwijderd" "Sessielogbestand NIET verwijderd" + + + + + + "Invoertalen" "Raak nogmaals aan om op te slaan" "Woordenboek beschikbaar" diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml index 7c86dbfdc..6ffe8dce3 100644 --- a/java/res/values-pl/strings.xml +++ b/java/res/values-pl/strings.xml @@ -107,9 +107,19 @@ "Znacznik czasu uwagi w dzienniku" "Zapisano znacznik czasu" "Nie rejestruj tej sesji" + + + + "Usuwanie dziennika sesji" "Usunięto dziennik sesji" "Dziennik sesji NIEUSUNIĘTY" + + + + + + "Języki wprowadzania" "Dotknij ponownie, aby zapisać" "Słownik dostępny" diff --git a/java/res/values-pt-rPT/strings-appname.xml b/java/res/values-pt-rPT/strings-appname.xml new file mode 100644 index 000000000..0f6abb97f --- /dev/null +++ b/java/res/values-pt-rPT/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Verificador ortográfico do Android" + "Definições de teclado do Android" + "Definições da verificação ortográfica" + diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml index 06d7a78d6..a1cc6f784 100644 --- a/java/res/values-pt-rPT/strings.xml +++ b/java/res/values-pt-rPT/strings.xml @@ -107,9 +107,19 @@ "Anotar car. data no reg." "Carimbo de data gravado" "Não registar esta sessão" + + + + "A eliminar reg. da sessão" "Reg. de sessão eliminado" "Reg. de sessão NÃO elim." + + + + + + "Idiomas de introdução" "Toque novamente para guardar" "Dicionário disponível" diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml index 5b7c60fca..93666ac3b 100644 --- a/java/res/values-pt/strings.xml +++ b/java/res/values-pt/strings.xml @@ -107,9 +107,19 @@ "Indicar data/hora no reg." "Data/hora registrada" "Não registrar esta sessão" + + + + "Excluindo reg. de sessão" "Registro excluído" "Registro NÃO excluído" + + + + + + "Idiomas de entrada" "Toque novamente para salvar" "Dicionário disponível" diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml index 41be654fe..670ce57f1 100644 --- a/java/res/values-rm/strings.xml +++ b/java/res/values-rm/strings.xml @@ -184,12 +184,22 @@ + + + + + + + + + + diff --git a/java/res/values-ro/strings-appname.xml b/java/res/values-ro/strings-appname.xml new file mode 100644 index 000000000..b1fd29b8a --- /dev/null +++ b/java/res/values-ro/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Verificator ortografic Android" + "Setările tastaturii Android" + "Setările de verificare ortografică" + diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml index 338024c5a..620a5c4a0 100644 --- a/java/res/values-ro/strings.xml +++ b/java/res/values-ro/strings.xml @@ -107,9 +107,19 @@ "Înreg. marc. temp. jurnal" "Marcaj temporal înregis." "Nu înregistraţi sesiunea" + + + + "Se șterge jurnal sesiune" "Jurnal de sesiune șters" "Jurnal sesiune neşters" + + + + + + "Limbi de intrare" "Atingeţi din nou pentru a salva" "Dicţionar disponibil" diff --git a/java/res/values-ru/strings-appname.xml b/java/res/values-ru/strings-appname.xml new file mode 100644 index 000000000..b67c369a7 --- /dev/null +++ b/java/res/values-ru/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Проверка правописания Android" + "Настройки клавиатуры Android" + "Настройки проверки правописания" + diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml index 4dd5b31a0..c50d1dee1 100644 --- a/java/res/values-ru/strings.xml +++ b/java/res/values-ru/strings.xml @@ -107,9 +107,19 @@ "Закладка в журнале" "Закладка сохранена" "Не сохранять этот сеанс" + + + + "Удаление…" "Запись сеанса удалена" "Запись сеанса НЕ удалена" + + + + + + "Языки ввода" "Нажмите, чтобы сохранить" "Доступен словарь" diff --git a/java/res/values-sk/strings-appname.xml b/java/res/values-sk/strings-appname.xml new file mode 100644 index 000000000..d2e150378 --- /dev/null +++ b/java/res/values-sk/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Kontrola pravopisu Android" + "Nastavenia klávesnice Android" + "Nastavenia kontroly pravopisu" + diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml index 1dced2099..d89d1d3b6 100644 --- a/java/res/values-sk/strings.xml +++ b/java/res/values-sk/strings.xml @@ -107,9 +107,19 @@ "Časová pečiatka denníka" "Časová pečiatka zaznamenaná" "Neukl. reláciu do denníka" + + + + "Odstraň. denníka relácie" "Denník relácie odstránený" "Denník relácie NIE JE odstr." + + + + + + "Jazyky vstupu" "Opätovným dotykom uložíte" "K dispozícii je slovník" diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml index 036802d5b..fa6822382 100644 --- a/java/res/values-sl/strings.xml +++ b/java/res/values-sl/strings.xml @@ -107,9 +107,19 @@ "V dnev. zabeleži čas. žig" "Časovni žig zabeležen" "Brez dnevnika za to sejo" + + + + "Brisanje seje dnevnika" "Dnevnik seje izbrisan" "Dnevnik seje NI izbrisan" + + + + + + "Jeziki vnosa" "Dotaknite se še enkrat, da shranite" "Slovar je na voljo" diff --git a/java/res/values-sr/strings-appname.xml b/java/res/values-sr/strings-appname.xml index 01da6d5c0..449fe551a 100644 --- a/java/res/values-sr/strings-appname.xml +++ b/java/res/values-sr/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Android тастатура" "Android провера правописа" "Подешавања Android тастатуре" "Подешавања провере правописа" diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml index 92f275f2e..f5e70ece4 100644 --- a/java/res/values-sr/strings.xml +++ b/java/res/values-sr/strings.xml @@ -107,9 +107,19 @@ "Наведи временску ознаку у евиденцији" "Снимљена временска ознака" "Не евидентирај ову сесију" + + + + "Брисање евиденције сесије" "Евиденција сесије је обрисана" "Евиденција сесије НИЈЕ избрисана" + + + + + + "Језици уноса" "Поново додирните да бисте сачували" "Речник је доступан" diff --git a/java/res/values-sv/strings-appname.xml b/java/res/values-sv/strings-appname.xml index edb2af2ad..9b4a7dbd1 100644 --- a/java/res/values-sv/strings-appname.xml +++ b/java/res/values-sv/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Androids tangentbord" "Stavningskontroll i Android" "Inställningar för Androids tangentbord" "Inställningar för stavningskontroll" diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml index d460b5ba1..d8e55dfb2 100644 --- a/java/res/values-sv/strings.xml +++ b/java/res/values-sv/strings.xml @@ -107,9 +107,19 @@ "Markera tidpunkt i loggen" "Tidpunkten har sparats" "Logga inte detta besök" + + + + "Besöksloggen tas bort" "Besöksloggen togs bort" "Besöksloggen togs EJ bort" + + + + + + "Inmatningsspråk" "Spara genom att trycka igen" "En ordlista är tillgänglig" diff --git a/java/res/values-sw/strings-appname.xml b/java/res/values-sw/strings-appname.xml index 4a5b2a683..51de0a6b8 100644 --- a/java/res/values-sw/strings-appname.xml +++ b/java/res/values-sw/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Kibodi ya Android" "Kikagua tahajia cha Android" "Mipangilio ya kibodi ya Android" "Mipangilio ya kukagua tahajia" diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml index 9727fda8b..2b8c896a2 100644 --- a/java/res/values-sw/strings.xml +++ b/java/res/values-sw/strings.xml @@ -107,9 +107,19 @@ "Dokeza mhuri wa muda kwenye kumbukumbu" "Mhuri wa muda uliorekodiwa" "Usihifadhi kumbukumbu za kipindi hiki" + + + + "Inafuta kumbukumbu za kipindi" "Kumbukumbu za kipindi zimefutwa" "Kumbukumbu za kipindi HAZIJAFUTWA" + + + + + + "Lugha zinazoruhusiwa" "Gusa tena ili kuhifadhi" "Kamusi inapatikana" diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml index 8c365fe95..c47fc0597 100644 --- a/java/res/values-th/strings.xml +++ b/java/res/values-th/strings.xml @@ -107,9 +107,19 @@ "จดเวลาบันทึกไว้ในบันทึก" "บันทึกเวลาบันทึกแล้ว" "อย่าบันทึกเซสชันนี้" + + + + "กำลังลบบันทึกเซสชัน" "ลบบันทึกเซสชันแล้ว" "บันทึกเซสชันไม่ถูกลบ" + + + + + + "ภาษาสำหรับการป้อนข้อมูล" "แตะอีกครั้งเพื่อบัน​​ทึก" "มีพจนานุกรมให้ใช้งาน" diff --git a/java/res/values-tl/strings-appname.xml b/java/res/values-tl/strings-appname.xml new file mode 100644 index 000000000..bfa1b4627 --- /dev/null +++ b/java/res/values-tl/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Spell checker ng Android" + "Mga setting ng keyboard ng Android" + "Mga setting ng pag-spell check" + diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml index 832dc2bb7..766972f46 100644 --- a/java/res/values-tl/strings.xml +++ b/java/res/values-tl/strings.xml @@ -107,9 +107,19 @@ "Tandaan timestamp sa log" "Na-record na timestamp" "Huwag i-log ang session" + + + + "Tinatanggl log ng session" "Tinanggal log ng session" "HND ntnggl log ng session" + + + + + + "Mga wika ng input" "Pinduting muli upang i-save" "Available ang diksyunaryo" diff --git a/java/res/values-tr/strings-appname.xml b/java/res/values-tr/strings-appname.xml new file mode 100644 index 000000000..a499f382e --- /dev/null +++ b/java/res/values-tr/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Android yazım denetleyici" + "Android klavye ayarları" + "Yazım denetimi ayarları" + diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml index abfa73656..0f5857ab3 100644 --- a/java/res/values-tr/strings.xml +++ b/java/res/values-tr/strings.xml @@ -107,9 +107,19 @@ "Günlüğe zaman damgası koy" "Zaman damgası kaydedildi" "Bu oturumu günlüğe kaydetme" + + + + "Oturum günlüğü siliniyor" "Oturum günlüğü silindi" "Oturum günlüğü SİLİNMEDİ" + + + + + + "Giriş dilleri" "Kaydetmek için tekrar dokunun" "Sözlük kullanılabilir" diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml index 9e4da5b47..0ba53ced9 100644 --- a/java/res/values-uk/strings.xml +++ b/java/res/values-uk/strings.xml @@ -107,9 +107,19 @@ "Мітка часу в журналі" "Записана мітка часу" "Не реєструвати цю сесію" + + + + "Видалення журналу сесії" "Журнал сесії видалено" "Журнал сесії НЕ видалено" + + + + + + "Мови введення" "Торкніться знову, щоб зберегти" "Словник доступний" diff --git a/java/res/values-vi/strings-appname.xml b/java/res/values-vi/strings-appname.xml new file mode 100644 index 000000000..411ac02d7 --- /dev/null +++ b/java/res/values-vi/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Trình kiểm tra chính tả Android" + "Cài đặt bàn phím Android" + "Cài đặt kiểm tra chính tả" + diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml index bf096c51f..789d4da48 100644 --- a/java/res/values-vi/strings.xml +++ b/java/res/values-vi/strings.xml @@ -107,9 +107,19 @@ "Dấu thời gian ghi chú trong nhật ký" "Dấu thời gian đã ghi" "Không ghi nhật ký phiên này" + + + + "Đang xóa nhật ký phiên" "Đã xóa nhật ký phiên" "Nhật ký phiên KHÔNG bị xóa" + + + + + + "Ngôn ngữ nhập" "Chạm lại để lưu" "Có sẵn từ điển" diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml index a95d32ac0..ef1c8102e 100644 --- a/java/res/values-zh-rCN/strings.xml +++ b/java/res/values-zh-rCN/strings.xml @@ -107,9 +107,19 @@ "标记记录中的时间" "已标记时间" "不记录本次会话" + + + + "正在删除会话记录" "会话记录已删除" "未能删除会话记录" + + + + + + "输入语言" "再次触摸即可保存" "有可用词典" diff --git a/java/res/values-zh-rTW/strings-appname.xml b/java/res/values-zh-rTW/strings-appname.xml new file mode 100644 index 000000000..dd665590a --- /dev/null +++ b/java/res/values-zh-rTW/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Android 拼字檢查" + "Android 鍵盤設定" + "拼字檢查設定" + diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml index b8bb3e5d7..20c40eb93 100644 --- a/java/res/values-zh-rTW/strings.xml +++ b/java/res/values-zh-rTW/strings.xml @@ -107,9 +107,19 @@ "在紀錄中加註時間戳記" "已記錄時間戳記" "不要記錄這個工作階段" + + + + "正在刪除工作階段紀錄" "已刪除工作階段紀錄" "「未」刪除工作階段紀錄" + + + + + + "輸入語言" "再次輕觸即可儲存" "可使用字典" diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml index 6984631d3..b9771c1e8 100644 --- a/java/res/values-zu/strings.xml +++ b/java/res/values-zu/strings.xml @@ -107,9 +107,19 @@ "Qaphela isitembu sesikhathi efayeleni lokungena" "Isitembu sesikhathi esirekhodiwe" "Ungenzi ifayela lokungena lalesi sikhathi" + + + + "Isusa ifayela lokungena lesikhathi" "Ifayela lokungena lesikhathi lisusiwe" "Ifayela lokungena lesikhathi alisusiwe" + + + + + + "Izilimi zokufakwayo" "Thinta futhi ukuze ulondoloze" "Isichazamazwi siyatholakala" From b7d7c5a369cef80d4319de8e433501ab25b49615 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 11:31:48 +0900 Subject: [PATCH 49/68] Make a constant really constant (A104) Change-Id: Ied1f9f96a574b1e6a8ee0a71bfb1604d9c962e1c --- .../inputmethod/latin/BinaryDictionary.java | 15 ++++++++------- ...android_inputmethod_latin_BinaryDictionary.cpp | 7 ++++--- native/jni/src/bigram_dictionary.cpp | 4 ++-- native/jni/src/bigram_dictionary.h | 3 ++- native/jni/src/dictionary.cpp | 4 ++-- native/jni/src/dictionary.h | 2 +- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 20c1b25db..8eea62676 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -45,8 +45,8 @@ public class BinaryDictionary extends Dictionary { public static final int MAX_SPACES = 16; private static final String TAG = "BinaryDictionary"; - private static final int MAX_BIGRAMS = 60; - private static final int MAX_RESULTS = MAX_BIGRAMS > MAX_WORDS ? MAX_BIGRAMS : MAX_WORDS; + private static final int MAX_PREDICTIONS = 60; + private static final int MAX_RESULTS = Math.max(MAX_PREDICTIONS, MAX_WORDS); private static final int TYPED_LETTER_MULTIPLIER = 2; @@ -82,7 +82,8 @@ public class BinaryDictionary extends Dictionary { } private native long openNative(String sourceDir, long dictOffset, long dictSize, - int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength, int maxWords); + int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength, int maxWords, + int maxPredictions); private native void closeNative(long dict); private native int getFrequencyNative(long dict, int[] word, int wordLength); private native boolean isValidBigramNative(long dict, int[] word1, int[] word2); @@ -100,8 +101,8 @@ public class BinaryDictionary extends Dictionary { char[] before, int beforeLength, char[] after, int afterLength); private final void loadDictionary(String path, long startOffset, long length) { - mNativeDict = openNative(path, startOffset, length, - TYPED_LETTER_MULTIPLIER, FULL_WORD_SCORE_MULTIPLIER, MAX_WORD_LENGTH, MAX_WORDS); + mNativeDict = openNative(path, startOffset, length, TYPED_LETTER_MULTIPLIER, + FULL_WORD_SCORE_MULTIPLIER, MAX_WORD_LENGTH, MAX_WORDS, MAX_PREDICTIONS); } @Override @@ -129,8 +130,8 @@ public class BinaryDictionary extends Dictionary { if (TextUtils.isEmpty(prevWord)) return null; int tmpCount = getBigramsNative(mNativeDict, prevWordCodePointArray, prevWordCodePointArray.length, mInputCodes, composerSize, - mOutputChars, mOutputScores, MAX_WORD_LENGTH, MAX_BIGRAMS); - count = Math.min(tmpCount, MAX_BIGRAMS); + mOutputChars, mOutputScores, MAX_WORD_LENGTH, MAX_PREDICTIONS); + count = Math.min(tmpCount, MAX_PREDICTIONS); } else { final InputPointers ips = composer.getInputPointers(); final int codesSize = isGesture ? ips.getPointerSize() : composerSize; diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index bee0662ee..4b18322d9 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -46,7 +46,8 @@ void releaseDictBuf(void* dictBuf, const size_t length, int fd); static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, jstring sourceDir, jlong dictOffset, jlong dictSize, - jint typedLetterMultiplier, jint fullWordMultiplier, jint maxWordLength, jint maxWords) { + jint typedLetterMultiplier, jint fullWordMultiplier, jint maxWordLength, jint maxWords, + jint maxPredictions) { PROF_OPEN; PROF_START(66); const char *sourceDirChars = env->GetStringUTFChars(sourceDir, 0); @@ -119,7 +120,7 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, #endif // USE_MMAP_FOR_DICTIONARY } else { dictionary = new Dictionary(dictBuf, dictSize, fd, adjust, typedLetterMultiplier, - fullWordMultiplier, maxWordLength, maxWords); + fullWordMultiplier, maxWordLength, maxWords, maxPredictions); } PROF_END(66); PROF_CLOSE; @@ -258,7 +259,7 @@ void releaseDictBuf(void* dictBuf, const size_t length, int fd) { } static JNINativeMethod sMethods[] = { - {"openNative", "(Ljava/lang/String;JJIIII)J", (void*)latinime_BinaryDictionary_open}, + {"openNative", "(Ljava/lang/String;JJIIIII)J", (void*)latinime_BinaryDictionary_open}, {"closeNative", "(J)V", (void*)latinime_BinaryDictionary_close}, {"getSuggestionsNative", "(JJ[I[I[I[I[IIIZ[IZ[C[I[I)I", (void*) latinime_BinaryDictionary_getSuggestions}, diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp index 3bfbfad25..2c3d16583 100644 --- a/native/jni/src/bigram_dictionary.cpp +++ b/native/jni/src/bigram_dictionary.cpp @@ -27,8 +27,8 @@ namespace latinime { -BigramDictionary::BigramDictionary(const unsigned char *dict, int maxWordLength) - : DICT(dict), MAX_WORD_LENGTH(maxWordLength) { +BigramDictionary::BigramDictionary(const unsigned char *dict, int maxWordLength, int maxPredictions) + : DICT(dict), MAX_WORD_LENGTH(maxWordLength), MAX_PREDICTIONS(maxPredictions) { if (DEBUG_DICT) { AKLOGI("BigramDictionary - constructor"); } diff --git a/native/jni/src/bigram_dictionary.h b/native/jni/src/bigram_dictionary.h index 5372276cd..fe5bd9436 100644 --- a/native/jni/src/bigram_dictionary.h +++ b/native/jni/src/bigram_dictionary.h @@ -27,7 +27,7 @@ namespace latinime { class Dictionary; class BigramDictionary { public: - BigramDictionary(const unsigned char *dict, int maxWordLength); + BigramDictionary(const unsigned char *dict, int maxWordLength, int maxPredictions); int getBigrams(const int32_t *word, int length, int *inputCodes, int codesSize, unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams) const; int getBigramListPositionForWord(const int32_t *prevWord, const int prevWordLength, @@ -49,6 +49,7 @@ class BigramDictionary { const unsigned char *DICT; const int MAX_WORD_LENGTH; + const int MAX_PREDICTIONS; // TODO: Re-implement proximity correction for bigram correction static const int MAX_ALTERNATIVES = 1; }; diff --git a/native/jni/src/dictionary.cpp b/native/jni/src/dictionary.cpp index 628a16933..f3166e75a 100644 --- a/native/jni/src/dictionary.cpp +++ b/native/jni/src/dictionary.cpp @@ -29,7 +29,7 @@ namespace latinime { // TODO: Change the type of all keyCodes to uint32_t Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, int typedLetterMultiplier, int fullWordMultiplier, - int maxWordLength, int maxWords) + int maxWordLength, int maxWords, int maxPredictions) : mDict((unsigned char*) dict), mDictSize(dictSize), mMmapFd(mmapFd), mDictBufAdjust(dictBufAdjust) { if (DEBUG_DICT) { @@ -43,7 +43,7 @@ Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, const unsigned int options = BinaryFormat::getFlags(mDict); mUnigramDictionary = new UnigramDictionary(mDict + headerSize, typedLetterMultiplier, fullWordMultiplier, maxWordLength, maxWords, options); - mBigramDictionary = new BigramDictionary(mDict + headerSize, maxWordLength); + mBigramDictionary = new BigramDictionary(mDict + headerSize, maxWordLength, maxPredictions); mGestureDecoder = new GestureDecoderWrapper(maxWordLength, maxWords); mGestureDecoder->setDict(mUnigramDictionary, mBigramDictionary, mDict + headerSize /* dict root */, 0 /* root pos */); diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index 431f10337..6742b48cf 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -32,7 +32,7 @@ namespace latinime { class Dictionary { public: Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, int typedLetterMultipler, - int fullWordMultiplier, int maxWordLength, int maxWords); + int fullWordMultiplier, int maxWordLength, int maxWords, int maxPredictions); int getSuggestions(ProximityInfo *proximityInfo, int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *codes, int codesSize, int *prevWordChars, From 1a69ad5a107792cb01436d2156f8b518aaf0a4d6 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 11:37:36 +0900 Subject: [PATCH 50/68] Remove a constant parameter (A105) Change-Id: I8a09fa2f0649880c943364699a07652e47dede22 --- native/jni/src/bigram_dictionary.cpp | 14 +++++++------- native/jni/src/bigram_dictionary.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp index 2c3d16583..0c1aa70cb 100644 --- a/native/jni/src/bigram_dictionary.cpp +++ b/native/jni/src/bigram_dictionary.cpp @@ -38,7 +38,7 @@ BigramDictionary::~BigramDictionary() { } bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequency, - const int maxBigrams, int *bigramFreq, unsigned short *bigramChars) const { + int *bigramFreq, unsigned short *bigramChars) const { word[length] = 0; if (DEBUG_DICT) { #ifdef FLAG_DBG @@ -50,7 +50,7 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ // Find the right insertion point int insertAt = 0; - while (insertAt < maxBigrams) { + while (insertAt < MAX_PREDICTIONS) { if (frequency > bigramFreq[insertAt] || (bigramFreq[insertAt] == frequency && length < Dictionary::wideStrLen(bigramChars + insertAt * MAX_WORD_LENGTH))) { break; @@ -58,16 +58,16 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ insertAt++; } if (DEBUG_DICT) { - AKLOGI("Bigram: InsertAt -> %d maxBigrams: %d", insertAt, maxBigrams); + AKLOGI("Bigram: InsertAt -> %d MAX_PREDICTIONS: %d", insertAt, MAX_PREDICTIONS); } - if (insertAt < maxBigrams) { + if (insertAt < MAX_PREDICTIONS) { memmove((char*) bigramFreq + (insertAt + 1) * sizeof(bigramFreq[0]), (char*) bigramFreq + insertAt * sizeof(bigramFreq[0]), - (maxBigrams - insertAt - 1) * sizeof(bigramFreq[0])); + (MAX_PREDICTIONS - insertAt - 1) * sizeof(bigramFreq[0])); bigramFreq[insertAt] = frequency; memmove((char*) bigramChars + (insertAt + 1) * MAX_WORD_LENGTH * sizeof(short), (char*) bigramChars + (insertAt ) * MAX_WORD_LENGTH * sizeof(short), - (maxBigrams - insertAt - 1) * sizeof(short) * MAX_WORD_LENGTH); + (MAX_PREDICTIONS - insertAt - 1) * sizeof(short) * MAX_WORD_LENGTH); unsigned short *dest = bigramChars + (insertAt ) * MAX_WORD_LENGTH; while (length--) { *dest++ = *word++; @@ -137,7 +137,7 @@ int BigramDictionary::getBigrams(const int32_t *prevWord, int prevWordLength, in const int frequency = BinaryFormat::computeFrequencyForBigram(unigramFreq, bigramFreqTemp); if (addWordBigram( - bigramBuffer, length, frequency, maxBigrams, bigramFreq, bigramChars)) { + bigramBuffer, length, frequency, bigramFreq, bigramChars)) { ++bigramCount; } } diff --git a/native/jni/src/bigram_dictionary.h b/native/jni/src/bigram_dictionary.h index fe5bd9436..3f397af4d 100644 --- a/native/jni/src/bigram_dictionary.h +++ b/native/jni/src/bigram_dictionary.h @@ -38,7 +38,7 @@ class BigramDictionary { ~BigramDictionary(); private: DISALLOW_IMPLICIT_CONSTRUCTORS(BigramDictionary); - bool addWordBigram(unsigned short *word, int length, int frequency, const int maxBigrams, + bool addWordBigram(unsigned short *word, int length, int frequency, int *bigramFreq, unsigned short *bigramChars) const; int getBigramAddress(int *pos, bool advance); int getBigramFreq(int *pos); From 6a5d17cd2f55cdab01900af8933cb71b97b73a29 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 11:55:25 +0900 Subject: [PATCH 51/68] Remove a useless parameter (A106) Change-Id: Ic0ecea22212fd1a098a3a168da460374e446f4a3 --- .../src/com/android/inputmethod/latin/BinaryDictionary.java | 5 ++--- .../jni/com_android_inputmethod_latin_BinaryDictionary.cpp | 6 +++--- native/jni/src/bigram_dictionary.cpp | 3 +-- native/jni/src/bigram_dictionary.h | 2 +- native/jni/src/dictionary.h | 5 ++--- 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 8eea62676..db8d3077d 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -93,8 +93,7 @@ public class BinaryDictionary extends Dictionary { int[] prevWordCodePointArray, boolean useFullEditDistance, char[] outputChars, int[] scores, int[] outputIndices); private native int getBigramsNative(long dict, int[] prevWord, int prevWordLength, - int[] inputCodes, int inputCodesLength, char[] outputChars, int[] scores, - int maxWordLength, int maxBigrams); + int[] inputCodes, int inputCodesLength, char[] outputChars, int[] scores); private static native float calcNormalizedScoreNative( char[] before, int beforeLength, char[] after, int afterLength, int score); private static native int editDistanceNative( @@ -130,7 +129,7 @@ public class BinaryDictionary extends Dictionary { if (TextUtils.isEmpty(prevWord)) return null; int tmpCount = getBigramsNative(mNativeDict, prevWordCodePointArray, prevWordCodePointArray.length, mInputCodes, composerSize, - mOutputChars, mOutputScores, MAX_WORD_LENGTH, MAX_PREDICTIONS); + mOutputChars, mOutputScores); count = Math.min(tmpCount, MAX_PREDICTIONS); } else { final InputPointers ips = composer.getInputPointers(); diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 4b18322d9..5e3167bc3 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -167,7 +167,7 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, static int latinime_BinaryDictionary_getBigrams(JNIEnv *env, jobject object, jlong dict, jintArray prevWordArray, jint prevWordLength, jintArray inputArray, jint inputArraySize, - jcharArray outputArray, jintArray frequencyArray, jint maxWordLength, jint maxBigrams) { + jcharArray outputArray, jintArray frequencyArray) { Dictionary *dictionary = (Dictionary*)dict; if (!dictionary) return 0; jint *prevWord = env->GetIntArrayElements(prevWordArray, 0); @@ -175,7 +175,7 @@ static int latinime_BinaryDictionary_getBigrams(JNIEnv *env, jobject object, jlo jchar *outputChars = env->GetCharArrayElements(outputArray, 0); int *frequencies = env->GetIntArrayElements(frequencyArray, 0); int count = dictionary->getBigrams(prevWord, prevWordLength, inputCodes, - inputArraySize, (unsigned short*) outputChars, frequencies, maxWordLength, maxBigrams); + inputArraySize, (unsigned short*) outputChars, frequencies); env->ReleaseIntArrayElements(frequencyArray, frequencies, 0); env->ReleaseCharArrayElements(outputArray, outputChars, 0); env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT); @@ -265,7 +265,7 @@ static JNINativeMethod sMethods[] = { (void*) latinime_BinaryDictionary_getSuggestions}, {"getFrequencyNative", "(J[II)I", (void*)latinime_BinaryDictionary_getFrequency}, {"isValidBigramNative", "(J[I[I)Z", (void*)latinime_BinaryDictionary_isValidBigram}, - {"getBigramsNative", "(J[II[II[C[III)I", (void*)latinime_BinaryDictionary_getBigrams}, + {"getBigramsNative", "(J[II[II[C[I)I", (void*)latinime_BinaryDictionary_getBigrams}, {"calcNormalizedScoreNative", "([CI[CII)F", (void*)latinime_BinaryDictionary_calcNormalizedScore}, {"editDistanceNative", "([CI[CI)I", (void*)latinime_BinaryDictionary_editDistance} diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp index 0c1aa70cb..a9ea71813 100644 --- a/native/jni/src/bigram_dictionary.cpp +++ b/native/jni/src/bigram_dictionary.cpp @@ -99,8 +99,7 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ * reduce their scope to the ones that match the first letter. */ int BigramDictionary::getBigrams(const int32_t *prevWord, int prevWordLength, int *inputCodes, - int codesSize, unsigned short *bigramChars, int *bigramFreq, int maxWordLength, - int maxBigrams) const { + int codesSize, unsigned short *bigramChars, int *bigramFreq) const { // TODO: remove unused arguments, and refrain from storing stuff in members of this class // TODO: have "in" arguments before "out" ones, and make out args explicit in the name diff --git a/native/jni/src/bigram_dictionary.h b/native/jni/src/bigram_dictionary.h index 3f397af4d..fa602a18a 100644 --- a/native/jni/src/bigram_dictionary.h +++ b/native/jni/src/bigram_dictionary.h @@ -29,7 +29,7 @@ class BigramDictionary { public: BigramDictionary(const unsigned char *dict, int maxWordLength, int maxPredictions); int getBigrams(const int32_t *word, int length, int *inputCodes, int codesSize, - unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams) const; + unsigned short *outWords, int *frequencies) const; int getBigramListPositionForWord(const int32_t *prevWord, const int prevWordLength, const bool forceLowerCaseSearch) const; void fillBigramAddressToFrequencyMapAndFilter(const int32_t *prevWord, const int prevWordLength, diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index 6742b48cf..eb6cc9681 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -59,9 +59,8 @@ class Dictionary { } int getBigrams(const int32_t *word, int length, int *codes, int codesSize, - unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams) const { - return mBigramDictionary->getBigrams(word, length, codes, codesSize, outWords, frequencies, - maxWordLength, maxBigrams); + unsigned short *outWords, int *frequencies) const { + return mBigramDictionary->getBigrams(word, length, codes, codesSize, outWords, frequencies); } int getFrequency(const int32_t *word, int length) const; From cc470c78e4538ec05ed78959da041e2ce5ba846a Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 12:07:44 +0900 Subject: [PATCH 52/68] Move an implementation detail to native code (A107) Java code does not have to know about this implementation detail: the generic method should do the dispatching, instead of having the caller call either method. Change-Id: Ic13727f0cb18f4ced2c356cce2f8d710588c0421 --- ...android_inputmethod_latin_BinaryDictionary.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 5e3167bc3..8970e671d 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -147,10 +147,17 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jint *prevWordChars = prevWordForBigrams ? env->GetIntArrayElements(prevWordForBigrams, 0) : 0; jsize prevWordLength = prevWordChars ? env->GetArrayLength(prevWordForBigrams) : 0; - int count = dictionary->getSuggestions(pInfo, xCoordinates, yCoordinates, times, pointerIds, - inputCodes, arraySize, prevWordChars, prevWordLength, commitPoint, isGesture, - useFullEditDistance, (unsigned short*) outputChars, - frequencies, spaceIndices); + + int count; + if (isGesture || arraySize > 1) { + count = dictionary->getSuggestions(pInfo, xCoordinates, yCoordinates, times, pointerIds, + inputCodes, arraySize, prevWordChars, prevWordLength, commitPoint, isGesture, + useFullEditDistance, (unsigned short*) outputChars, frequencies, spaceIndices); + } else { + count = dictionary->getBigrams(prevWordChars, prevWordLength, inputCodes, + arraySize, (unsigned short*) outputChars, frequencies); + } + if (prevWordChars) { env->ReleaseIntArrayElements(prevWordForBigrams, prevWordChars, JNI_ABORT); } From 251f302985bc491f4dd54983e9c69c5dc76cb834 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 12:56:57 +0900 Subject: [PATCH 53/68] Stop using a redundant method (A108) Change-Id: Iffc0bae0a273419e7c50d69526c0c8e402c6461c --- .../inputmethod/latin/BinaryDictionary.java | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index db8d3077d..271119bfb 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -124,22 +124,17 @@ public class BinaryDictionary extends Dictionary { } } - final int count; - if (!isGesture && composerSize <= 1) { - if (TextUtils.isEmpty(prevWord)) return null; - int tmpCount = getBigramsNative(mNativeDict, prevWordCodePointArray, - prevWordCodePointArray.length, mInputCodes, composerSize, - mOutputChars, mOutputScores); - count = Math.min(tmpCount, MAX_PREDICTIONS); - } else { - final InputPointers ips = composer.getInputPointers(); - final int codesSize = isGesture ? ips.getPointerSize() : composerSize; - // proximityInfo and/or prevWordForBigrams may not be null. - count = getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), - ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), + // TODO: move this test to native code. + if (composerSize <= 1 && TextUtils.isEmpty(prevWord)) return null; + final InputPointers ips = composer.getInputPointers(); + final int codesSize = isGesture ? ips.getPointerSize() : composerSize; + // proximityInfo and/or prevWordForBigrams may not be null. + final int tmpCount = getSuggestionsNative(mNativeDict, + proximityInfo.getNativeProximityInfo(), ips.getXCoordinates(), + ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), mInputCodes, codesSize, 0 /* unused */, isGesture, prevWordCodePointArray, mUseFullEditDistance, mOutputChars, mOutputScores, mSpaceIndices); - } + final int count = Math.min(tmpCount, MAX_PREDICTIONS); final ArrayList suggestions = new ArrayList(); for (int j = 0; j < count; ++j) { From 18d76afa911f5b236901eed6eba48a801dfdaafa Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 14:28:40 +0900 Subject: [PATCH 54/68] Remove an unused method (A109) Change-Id: Ib785b7e8c554d030395e2c0ca92edb44eb2b245f --- .../inputmethod/latin/BinaryDictionary.java | 2 -- ...oid_inputmethod_latin_BinaryDictionary.cpp | 19 ------------------- 2 files changed, 21 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 271119bfb..3b3315d3a 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -92,8 +92,6 @@ public class BinaryDictionary extends Dictionary { int commitPoint, boolean isGesture, int[] prevWordCodePointArray, boolean useFullEditDistance, char[] outputChars, int[] scores, int[] outputIndices); - private native int getBigramsNative(long dict, int[] prevWord, int prevWordLength, - int[] inputCodes, int inputCodesLength, char[] outputChars, int[] scores); private static native float calcNormalizedScoreNative( char[] before, int beforeLength, char[] after, int afterLength, int score); private static native int editDistanceNative( diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 8970e671d..7b1b39ced 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -172,24 +172,6 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, return count; } -static int latinime_BinaryDictionary_getBigrams(JNIEnv *env, jobject object, jlong dict, - jintArray prevWordArray, jint prevWordLength, jintArray inputArray, jint inputArraySize, - jcharArray outputArray, jintArray frequencyArray) { - Dictionary *dictionary = (Dictionary*)dict; - if (!dictionary) return 0; - jint *prevWord = env->GetIntArrayElements(prevWordArray, 0); - int *inputCodes = env->GetIntArrayElements(inputArray, 0); - jchar *outputChars = env->GetCharArrayElements(outputArray, 0); - int *frequencies = env->GetIntArrayElements(frequencyArray, 0); - int count = dictionary->getBigrams(prevWord, prevWordLength, inputCodes, - inputArraySize, (unsigned short*) outputChars, frequencies); - env->ReleaseIntArrayElements(frequencyArray, frequencies, 0); - env->ReleaseCharArrayElements(outputArray, outputChars, 0); - env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT); - env->ReleaseIntArrayElements(prevWordArray, prevWord, JNI_ABORT); - return count; -} - static jint latinime_BinaryDictionary_getFrequency(JNIEnv *env, jobject object, jlong dict, jintArray wordArray, jint wordLength) { Dictionary *dictionary = (Dictionary*)dict; @@ -272,7 +254,6 @@ static JNINativeMethod sMethods[] = { (void*) latinime_BinaryDictionary_getSuggestions}, {"getFrequencyNative", "(J[II)I", (void*)latinime_BinaryDictionary_getFrequency}, {"isValidBigramNative", "(J[I[I)Z", (void*)latinime_BinaryDictionary_isValidBigram}, - {"getBigramsNative", "(J[II[II[C[I)I", (void*)latinime_BinaryDictionary_getBigrams}, {"calcNormalizedScoreNative", "([CI[CII)F", (void*)latinime_BinaryDictionary_calcNormalizedScore}, {"editDistanceNative", "([CI[CI)I", (void*)latinime_BinaryDictionary_editDistance} From 3b57631b60c696d407a73e7594f6ab2418932229 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 16:47:22 +0900 Subject: [PATCH 55/68] Resolve a TODO: bury some implementation detail in native (A110) The fact that prediction does not accept a null argument is an implementation detail, it should not be visible to Java code. Change-Id: I3a156b323b6db9353de898d33f3f7c81751cecb1 --- .../android/inputmethod/latin/BinaryDictionary.java | 2 -- java/src/com/android/inputmethod/latin/Suggest.java | 10 ++++------ native/jni/src/dictionary.h | 1 + 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 3b3315d3a..feff2f2c9 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -122,8 +122,6 @@ public class BinaryDictionary extends Dictionary { } } - // TODO: move this test to native code. - if (composerSize <= 1 && TextUtils.isEmpty(prevWord)) return null; final InputPointers ips = composer.getInputPointers(); final int codesSize = isGesture ? ips.getPointerSize() : composerSize; // proximityInfo and/or prevWordForBigrams may not be null. diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 31c6000e3..bbd415f68 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -194,12 +194,10 @@ public class Suggest { } if (wordComposerForLookup.size() <= 1) { // At first character typed, search only the bigrams - if (!TextUtils.isEmpty(prevWordForBigram)) { - for (final String key : mDictionaries.keySet()) { - final Dictionary dictionary = mDictionaries.get(key); - suggestionsSet.addAll(dictionary.getSuggestions(wordComposerForLookup, - prevWordForBigram, proximityInfo)); - } + for (final String key : mDictionaries.keySet()) { + final Dictionary dictionary = mDictionaries.get(key); + suggestionsSet.addAll(dictionary.getSuggestions( + wordComposerForLookup, prevWordForBigram, proximityInfo)); } } else { // At second character typed, search the unigrams (scores being affected by bigrams) diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index eb6cc9681..c8a21e0ae 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -60,6 +60,7 @@ class Dictionary { int getBigrams(const int32_t *word, int length, int *codes, int codesSize, unsigned short *outWords, int *frequencies) const { + if (length <= 0) return 0; return mBigramDictionary->getBigrams(word, length, codes, codesSize, outWords, frequencies); } From d8afa2fbe13adf9f512fd294056a884a0edb0573 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 16:56:25 +0900 Subject: [PATCH 56/68] Remove the ultimate code duplication (A111) Change-Id: I7c76613df8f148feb02765f187db3ca6dc577977 --- .../android/inputmethod/latin/Suggest.java | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index bbd415f68..38094a518 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -192,20 +192,11 @@ public class Suggest { } else { wordComposerForLookup = wordComposer; } - if (wordComposerForLookup.size() <= 1) { - // At first character typed, search only the bigrams - for (final String key : mDictionaries.keySet()) { - final Dictionary dictionary = mDictionaries.get(key); - suggestionsSet.addAll(dictionary.getSuggestions( - wordComposerForLookup, prevWordForBigram, proximityInfo)); - } - } else { - // At second character typed, search the unigrams (scores being affected by bigrams) - for (final String key : mDictionaries.keySet()) { - final Dictionary dictionary = mDictionaries.get(key); - suggestionsSet.addAll(dictionary.getSuggestions( - wordComposerForLookup, prevWordForBigram, proximityInfo)); - } + + for (final String key : mDictionaries.keySet()) { + final Dictionary dictionary = mDictionaries.get(key); + suggestionsSet.addAll(dictionary.getSuggestions( + wordComposerForLookup, prevWordForBigram, proximityInfo)); } // TODO: Change this scheme - a boolean is not enough. A whitelisted word may be "valid" From ae13061245e6a82863416456a461207d871a89ff Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 17:18:05 +0900 Subject: [PATCH 57/68] Simplification (A112) If we are not composing a word, that isFirstCharCapitalized and isAllUpperCase are guaranteed to return false. Change-Id: Ic4a0be9574acf4653c729a9594f963f5bcf0c757 --- java/src/com/android/inputmethod/latin/Suggest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 38094a518..1d1d07e17 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -170,9 +170,8 @@ public class Suggest { final WordComposer wordComposer, CharSequence prevWordForBigram, final ProximityInfo proximityInfo, final boolean isCorrectionEnabled) { final boolean isPrediction = !wordComposer.isComposingWord(); - final boolean isFirstCharCapitalized = - !isPrediction && wordComposer.isFirstCharCapitalized(); - final boolean isAllUpperCase = !isPrediction && wordComposer.isAllUpperCase(); + final boolean isFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); + final boolean isAllUpperCase = wordComposer.isAllUpperCase(); final int trailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount(); final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator, MAX_SUGGESTIONS); From 02f1c1534c2060aaea7a9a020ce87f6c5ff5d8e0 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 17:21:37 +0900 Subject: [PATCH 58/68] Cleanup (A113) If not composing a word, then consideredWord is always the empty string. Hence, it's never whitelisted, but it's also always "NotAWord", so isWhitelistedOrNotAWord returns always true, so allowsToBeAutoCorrected is always true. Which means that isPrediction implies allowsToBeAutoCorrected == true. Thus, !isPrediction && !allowsToBeAutoCorrected is strictly equivalent to !allowsToBeAutocorrected. Change-Id: I4ad7a7c3447851c539646d97cf55ff065e6ee115 --- java/src/com/android/inputmethod/latin/Suggest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 1d1d07e17..7ebbbabe8 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -277,7 +277,7 @@ public class Suggest { // TODO: this first argument is lying. If this is a whitelisted word which is an // actual word, it says typedWordValid = false, which looks wrong. We should either // rename the attribute or change the value. - !isPrediction && !allowsToBeAutoCorrected /* typedWordValid */, + !allowsToBeAutoCorrected /* typedWordValid */, !isPrediction && hasAutoCorrection, /* willAutoCorrect */ false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, From 2549b4978e5b0460d0f34a5e4016374ac2198753 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 17:32:23 +0900 Subject: [PATCH 59/68] Cleanup (A114) Change-Id: I7e24e0aeae7c004cae310ae9f46cf90dac2d4d14 --- java/src/com/android/inputmethod/latin/Suggest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 7ebbbabe8..fdc172af2 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -215,8 +215,9 @@ public class Suggest { // same time, it feels wrong that the SuggestedWord object includes information about // the current settings. It may also be useful to know, when the setting is off, whether // the word *would* have been auto-corrected. - if (!isCorrectionEnabled || !allowsToBeAutoCorrected || wordComposer.isMostlyCaps() - || wordComposer.isResumed() || !hasMainDictionary()) { + if (!isCorrectionEnabled || !allowsToBeAutoCorrected || !wordComposer.isComposingWord() + || wordComposer.isMostlyCaps() || wordComposer.isResumed() + || !hasMainDictionary()) { // If we don't have a main dictionary, we never want to auto-correct. The reason for // this is, the user may have a contact whose name happens to match a valid word in // their language, and it will unexpectedly auto-correct. For example, if the user @@ -278,7 +279,7 @@ public class Suggest { // actual word, it says typedWordValid = false, which looks wrong. We should either // rename the attribute or change the value. !allowsToBeAutoCorrected /* typedWordValid */, - !isPrediction && hasAutoCorrection, /* willAutoCorrect */ + hasAutoCorrection, /* willAutoCorrect */ false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, isPrediction); From f5b55cb70c9d6012e1aa2b201c4785530afab168 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 18:40:54 +0900 Subject: [PATCH 60/68] Compute variables closer to where they are used (A115) This improves locality, it's better for readability/performance Change-Id: Ibb1efaf86e362dd2c9398722d0da2144df96b333 --- java/src/com/android/inputmethod/latin/Suggest.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index fdc172af2..071daea38 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -169,9 +169,6 @@ public class Suggest { private SuggestedWords getSuggestedWordsForTypingInput( final WordComposer wordComposer, CharSequence prevWordForBigram, final ProximityInfo proximityInfo, final boolean isCorrectionEnabled) { - final boolean isPrediction = !wordComposer.isComposingWord(); - final boolean isFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); - final boolean isAllUpperCase = wordComposer.isAllUpperCase(); final int trailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount(); final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator, MAX_SUGGESTIONS); @@ -245,6 +242,8 @@ public class Suggest { final ArrayList suggestionsContainer = new ArrayList(suggestionsSet); final int suggestionsCount = suggestionsContainer.size(); + final boolean isFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); + final boolean isAllUpperCase = wordComposer.isAllUpperCase(); if (isFirstCharCapitalized || isAllUpperCase || 0 != trailingSingleQuotesCount) { for (int i = 0; i < suggestionsCount; ++i) { final SuggestedWordInfo wordInfo = suggestionsContainer.get(i); @@ -282,7 +281,7 @@ public class Suggest { hasAutoCorrection, /* willAutoCorrect */ false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, - isPrediction); + !wordComposer.isComposingWord() /* isPrediction */); } // Retrieves suggestions for the batch input. From 24a63b5537ea4872ec10676d147ddccabda6a1f6 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 18:43:26 +0900 Subject: [PATCH 61/68] Simplification (A116) Change-Id: I97cf92a7b0dabc251dd241b24978ea00d1e5f047 --- .../android/inputmethod/latin/AutoCorrection.java | 3 ++- .../src/com/android/inputmethod/latin/Suggest.java | 14 ++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java index c78974dac..a66337404 100644 --- a/java/src/com/android/inputmethod/latin/AutoCorrection.java +++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java @@ -92,7 +92,8 @@ public class AutoCorrection { public static boolean suggestionExceedsAutoCorrectionThreshold(SuggestedWordInfo suggestion, CharSequence consideredWord, float autoCorrectionThreshold) { if (null != suggestion) { - //final int autoCorrectionSuggestionScore = sortedScores[0]; + // Shortlist a whitelisted word + if (suggestion.mKind == SuggestedWordInfo.KIND_WHITELIST) return true; final int autoCorrectionSuggestionScore = suggestion.mScore; // TODO: when the normalized score of the first suggestion is nearly equals to // the normalized score of the second suggestion, behave less aggressive. diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 071daea38..7dbba9454 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -205,6 +205,12 @@ public class Suggest { final CharSequence whitelistedWord = mWhiteListDictionary.getWhitelistedWord(consideredWord); + if (whitelistedWord != null) { + // MAX_SCORE ensures this will be considered strong enough to be auto-corrected + suggestionsSet.add(new SuggestedWordInfo(whitelistedWord, + SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_WHITELIST, + Dictionary.TYPE_WHITELIST)); + } final boolean hasAutoCorrection; // TODO: using isCorrectionEnabled here is not very good. It's probably useless, because @@ -222,8 +228,6 @@ public class Suggest { // would always auto-correct to "Will" which is unwanted. Hence, no main dict => no // auto-correct. hasAutoCorrection = false; - } else if (null != whitelistedWord) { - hasAutoCorrection = true; } else if (suggestionsSet.isEmpty()) { hasAutoCorrection = false; } else if (AutoCorrection.suggestionExceedsAutoCorrectionThreshold(suggestionsSet.first(), @@ -233,12 +237,6 @@ public class Suggest { hasAutoCorrection = false; } - if (whitelistedWord != null) { - suggestionsSet.add(new SuggestedWordInfo(whitelistedWord, - SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_WHITELIST, - Dictionary.TYPE_WHITELIST)); - } - final ArrayList suggestionsContainer = new ArrayList(suggestionsSet); final int suggestionsCount = suggestionsContainer.size(); From 1343d27de30c4010c54576d6c8bbb052c7630cbe Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 18:47:35 +0900 Subject: [PATCH 62/68] Readability improvement (A117) Change-Id: I6f8bb05a23edb40a079da60b7136170ec9043282 --- java/src/com/android/inputmethod/latin/Suggest.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 7dbba9454..31566bf13 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -219,6 +219,7 @@ public class Suggest { // the current settings. It may also be useful to know, when the setting is off, whether // the word *would* have been auto-corrected. if (!isCorrectionEnabled || !allowsToBeAutoCorrected || !wordComposer.isComposingWord() + || suggestionsSet.isEmpty() || wordComposer.isMostlyCaps() || wordComposer.isResumed() || !hasMainDictionary()) { // If we don't have a main dictionary, we never want to auto-correct. The reason for @@ -228,13 +229,9 @@ public class Suggest { // would always auto-correct to "Will" which is unwanted. Hence, no main dict => no // auto-correct. hasAutoCorrection = false; - } else if (suggestionsSet.isEmpty()) { - hasAutoCorrection = false; - } else if (AutoCorrection.suggestionExceedsAutoCorrectionThreshold(suggestionsSet.first(), - consideredWord, mAutoCorrectionThreshold)) { - hasAutoCorrection = true; } else { - hasAutoCorrection = false; + hasAutoCorrection = AutoCorrection.suggestionExceedsAutoCorrectionThreshold( + suggestionsSet.first(), consideredWord, mAutoCorrectionThreshold); } final ArrayList suggestionsContainer = From 2c5cf744e554cbe0872f1b3e18cbd1383b0189f9 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 11 Jul 2012 18:49:44 +0900 Subject: [PATCH 63/68] Increase encapsulation (A118) showSuggestions is only ever called by updateSuggestionsOrPredictions. It only feels natural that, when called with a 0-sized or null suggestion list, it clears the suggestions. Change-Id: I5b52bc9151afca1bb6c6f0a7f81e3255add92177 --- java/src/com/android/inputmethod/latin/LatinIME.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 3014e7f2b..f27d32150 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1668,6 +1668,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } + // TODO: rename this method to updateSuggestionStrip or simply updateSuggestions private void updateSuggestionsOrPredictions() { mHandler.cancelUpdateSuggestionStrip(); @@ -1699,11 +1700,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mCurrentSettings.mCorrectionEnabled); suggestedWords = maybeRetrieveOlderSuggestions(typedWord, suggestedWords); - if (null != suggestedWords && suggestedWords.size() > 0) { - showSuggestions(suggestedWords, typedWord); - } else { - clearSuggestions(); - } + showSuggestions(suggestedWords, typedWord); } private SuggestedWords maybeRetrieveOlderSuggestions(final CharSequence typedWord, @@ -1738,7 +1735,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private void showSuggestions(final SuggestedWords suggestedWords, final CharSequence typedWord) { - // This method is only ever called by updateSuggestions or updateBigramPredictions. + if (null == suggestedWords || suggestedWords.size() <= 0) { + clearSuggestions(); + return; + } final CharSequence autoCorrection; if (suggestedWords.size() > 0) { if (suggestedWords.mWillAutoCorrect) { From 6931df9c17aaeb04288f937cabf956c1b9eb0cc9 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 12 Jul 2012 12:55:48 +0900 Subject: [PATCH 64/68] Pass an array to output suggestion types (A119a) This needs the matching A119b change to not break the build. The array is passed, but not used yet. Bug: 6166228 Change-Id: Ia91d658461d989ee8c94e9b31bb06f4a36f4c5b6 --- .../android/inputmethod/latin/BinaryDictionary.java | 7 ++++--- ...com_android_inputmethod_latin_BinaryDictionary.cpp | 11 +++++++---- native/jni/src/bigram_dictionary.cpp | 5 ++--- native/jni/src/bigram_dictionary.h | 2 +- native/jni/src/dictionary.h | 11 ++++++----- native/jni/src/gesture/gesture_decoder_wrapper.h | 4 ++-- .../jni/src/gesture/incremental_decoder_interface.h | 2 +- native/jni/src/unigram_dictionary.cpp | 3 ++- native/jni/src/unigram_dictionary.h | 2 +- 9 files changed, 26 insertions(+), 21 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index feff2f2c9..534cffb2d 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -55,6 +55,7 @@ public class BinaryDictionary extends Dictionary { private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_RESULTS]; private final int[] mSpaceIndices = new int[MAX_SPACES]; private final int[] mOutputScores = new int[MAX_RESULTS]; + private final int[] mOutputTypes = new int[MAX_RESULTS]; private final boolean mUseFullEditDistance; @@ -91,7 +92,7 @@ public class BinaryDictionary extends Dictionary { int[] yCoordinates, int[] times, int[] pointerIds, int[] inputCodes, int codesSize, int commitPoint, boolean isGesture, int[] prevWordCodePointArray, boolean useFullEditDistance, char[] outputChars, - int[] scores, int[] outputIndices); + int[] outputScores, int[] outputIndices, int[] outputTypes); private static native float calcNormalizedScoreNative( char[] before, int beforeLength, char[] after, int afterLength, int score); private static native int editDistanceNative( @@ -128,8 +129,8 @@ public class BinaryDictionary extends Dictionary { final int tmpCount = getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), - mInputCodes, codesSize, 0 /* unused */, isGesture, prevWordCodePointArray, - mUseFullEditDistance, mOutputChars, mOutputScores, mSpaceIndices); + mInputCodes, codesSize, 0 /* commitPoint */, isGesture, prevWordCodePointArray, + mUseFullEditDistance, mOutputChars, mOutputScores, mSpaceIndices, mOutputTypes); final int count = Math.min(tmpCount, MAX_PREDICTIONS); final ArrayList suggestions = new ArrayList(); diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 7b1b39ced..0a282b865 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -132,7 +132,7 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jintArray timesArray, jintArray pointerIdArray, jintArray inputArray, jint arraySize, jint commitPoint, jboolean isGesture, jintArray prevWordForBigrams, jboolean useFullEditDistance, jcharArray outputArray, - jintArray frequencyArray, jintArray spaceIndexArray) { + jintArray frequencyArray, jintArray spaceIndexArray, jintArray outputTypesArray) { Dictionary *dictionary = (Dictionary*) dict; if (!dictionary) return 0; ProximityInfo *pInfo = (ProximityInfo*)proximityInfo; @@ -144,6 +144,7 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, int *inputCodes = env->GetIntArrayElements(inputArray, 0); jchar *outputChars = env->GetCharArrayElements(outputArray, 0); int *spaceIndices = env->GetIntArrayElements(spaceIndexArray, 0); + int *outputTypes = env->GetIntArrayElements(outputTypesArray, 0); jint *prevWordChars = prevWordForBigrams ? env->GetIntArrayElements(prevWordForBigrams, 0) : 0; jsize prevWordLength = prevWordChars ? env->GetArrayLength(prevWordForBigrams) : 0; @@ -152,15 +153,17 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, if (isGesture || arraySize > 1) { count = dictionary->getSuggestions(pInfo, xCoordinates, yCoordinates, times, pointerIds, inputCodes, arraySize, prevWordChars, prevWordLength, commitPoint, isGesture, - useFullEditDistance, (unsigned short*) outputChars, frequencies, spaceIndices); + useFullEditDistance, (unsigned short*) outputChars, frequencies, spaceIndices, + outputTypes); } else { count = dictionary->getBigrams(prevWordChars, prevWordLength, inputCodes, - arraySize, (unsigned short*) outputChars, frequencies); + arraySize, (unsigned short*) outputChars, frequencies, outputTypes); } if (prevWordChars) { env->ReleaseIntArrayElements(prevWordForBigrams, prevWordChars, JNI_ABORT); } + env->ReleaseIntArrayElements(outputTypesArray, outputTypes, 0); env->ReleaseIntArrayElements(spaceIndexArray, spaceIndices, 0); env->ReleaseCharArrayElements(outputArray, outputChars, 0); env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT); @@ -250,7 +253,7 @@ void releaseDictBuf(void* dictBuf, const size_t length, int fd) { static JNINativeMethod sMethods[] = { {"openNative", "(Ljava/lang/String;JJIIIII)J", (void*)latinime_BinaryDictionary_open}, {"closeNative", "(J)V", (void*)latinime_BinaryDictionary_close}, - {"getSuggestionsNative", "(JJ[I[I[I[I[IIIZ[IZ[C[I[I)I", + {"getSuggestionsNative", "(JJ[I[I[I[I[IIIZ[IZ[C[I[I[I)I", (void*) latinime_BinaryDictionary_getSuggestions}, {"getFrequencyNative", "(J[II)I", (void*)latinime_BinaryDictionary_getFrequency}, {"isValidBigramNative", "(J[I[I)Z", (void*)latinime_BinaryDictionary_isValidBigram}, diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp index a9ea71813..d468f2aaf 100644 --- a/native/jni/src/bigram_dictionary.cpp +++ b/native/jni/src/bigram_dictionary.cpp @@ -88,8 +88,7 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ * codesSize: the size of the codes array. * bigramChars: an array for output, at the same format as outwords for getSuggestions. * bigramFreq: an array to output frequencies. - * maxWordLength: the maximum size of a word. - * maxBigrams: the maximum number of bigrams fitting in the bigramChars array. + * outputTypes: an array to output types. * This method returns the number of bigrams this word has, for backward compatibility. * Note: this is not the number of bigrams output in the array, which is the number of * bigrams this word has WHOSE first letter also matches the letter the user typed. @@ -99,7 +98,7 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ * reduce their scope to the ones that match the first letter. */ int BigramDictionary::getBigrams(const int32_t *prevWord, int prevWordLength, int *inputCodes, - int codesSize, unsigned short *bigramChars, int *bigramFreq) const { + int codesSize, unsigned short *bigramChars, int *bigramFreq, int *outputTypes) const { // TODO: remove unused arguments, and refrain from storing stuff in members of this class // TODO: have "in" arguments before "out" ones, and make out args explicit in the name diff --git a/native/jni/src/bigram_dictionary.h b/native/jni/src/bigram_dictionary.h index fa602a18a..e09b24945 100644 --- a/native/jni/src/bigram_dictionary.h +++ b/native/jni/src/bigram_dictionary.h @@ -29,7 +29,7 @@ class BigramDictionary { public: BigramDictionary(const unsigned char *dict, int maxWordLength, int maxPredictions); int getBigrams(const int32_t *word, int length, int *inputCodes, int codesSize, - unsigned short *outWords, int *frequencies) const; + unsigned short *outWords, int *frequencies, int *outputTypes) const; int getBigramListPositionForWord(const int32_t *prevWord, const int prevWordLength, const bool forceLowerCaseSearch) const; void fillBigramAddressToFrequencyMapAndFilter(const int32_t *prevWord, const int prevWordLength, diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index c8a21e0ae..1292268b8 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -38,13 +38,13 @@ class Dictionary { int *times, int *pointerIds, int *codes, int codesSize, int *prevWordChars, int prevWordLength, int commitPoint, bool isGesture, bool useFullEditDistance, unsigned short *outWords, - int *frequencies, int *spaceIndices) { + int *frequencies, int *spaceIndices, int *outputTypes) { int result = 0; if (isGesture) { mGestureDecoder->setPrevWord(prevWordChars, prevWordLength); result = mGestureDecoder->getSuggestions(proximityInfo, xcoordinates, ycoordinates, times, pointerIds, codes, codesSize, commitPoint, - outWords, frequencies, spaceIndices); + outWords, frequencies, spaceIndices, outputTypes); return result; } else { std::map bigramMap; @@ -53,15 +53,16 @@ class Dictionary { prevWordLength, &bigramMap, bigramFilter); result = mUnigramDictionary->getSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, codesSize, &bigramMap, bigramFilter, - useFullEditDistance, outWords, frequencies); + useFullEditDistance, outWords, frequencies, outputTypes); return result; } } int getBigrams(const int32_t *word, int length, int *codes, int codesSize, - unsigned short *outWords, int *frequencies) const { + unsigned short *outWords, int *frequencies, int *outputTypes) const { if (length <= 0) return 0; - return mBigramDictionary->getBigrams(word, length, codes, codesSize, outWords, frequencies); + return mBigramDictionary->getBigrams(word, length, codes, codesSize, outWords, frequencies, + outputTypes); } int getFrequency(const int32_t *word, int length) const; diff --git a/native/jni/src/gesture/gesture_decoder_wrapper.h b/native/jni/src/gesture/gesture_decoder_wrapper.h index 35982f03d..03c84b5fd 100644 --- a/native/jni/src/gesture/gesture_decoder_wrapper.h +++ b/native/jni/src/gesture/gesture_decoder_wrapper.h @@ -39,13 +39,13 @@ class GestureDecoderWrapper : public IncrementalDecoderInterface { int getSuggestions(ProximityInfo *pInfo, int *inputXs, int *inputYs, int *times, int *pointerIds, int *codes, int inputSize, int commitPoint, - unsigned short *outWords, int *frequencies, int *outputIndices) { + unsigned short *outWords, int *frequencies, int *outputIndices, int *outputTypes) { if (!mIncrementalDecoderInterface) { return 0; } return mIncrementalDecoderInterface->getSuggestions( pInfo, inputXs, inputYs, times, pointerIds, codes, inputSize, commitPoint, - outWords, frequencies, outputIndices); + outWords, frequencies, outputIndices, outputTypes); } void reset() { diff --git a/native/jni/src/gesture/incremental_decoder_interface.h b/native/jni/src/gesture/incremental_decoder_interface.h index 957f1ebbe..6d2e273da 100644 --- a/native/jni/src/gesture/incremental_decoder_interface.h +++ b/native/jni/src/gesture/incremental_decoder_interface.h @@ -30,7 +30,7 @@ class IncrementalDecoderInterface { public: virtual int getSuggestions(ProximityInfo *pInfo, int *inputXs, int *inputYs, int *times, int *pointerIds, int *codes, int inputSize, int commitPoint, - unsigned short *outWords, int *frequencies, int *outputIndices) = 0; + unsigned short *outWords, int *frequencies, int *outputIndices, int *outputTypes) = 0; virtual void reset() = 0; virtual void setDict(const UnigramDictionary *dict, const BigramDictionary *bigram, const uint8_t *dictRoot, int rootPos) = 0; diff --git a/native/jni/src/unigram_dictionary.cpp b/native/jni/src/unigram_dictionary.cpp index 22f1657ef..0ffb3eb63 100644 --- a/native/jni/src/unigram_dictionary.cpp +++ b/native/jni/src/unigram_dictionary.cpp @@ -173,7 +173,8 @@ int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, const int *codes, const int codesSize, const std::map *bigramMap, const uint8_t *bigramFilter, - const bool useFullEditDistance, unsigned short *outWords, int *frequencies) const { + const bool useFullEditDistance, unsigned short *outWords, int *frequencies, + int *outputTypes) const { WordsPriorityQueuePool queuePool(MAX_WORDS, SUB_QUEUE_MAX_WORDS, MAX_WORD_LENGTH); queuePool.clearAll(); diff --git a/native/jni/src/unigram_dictionary.h b/native/jni/src/unigram_dictionary.h index 8352c5494..ac14fc0bc 100644 --- a/native/jni/src/unigram_dictionary.h +++ b/native/jni/src/unigram_dictionary.h @@ -81,7 +81,7 @@ class UnigramDictionary { ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, const int *codes, const int codesSize, const std::map *bigramMap, const uint8_t *bigramFilter, const bool useFullEditDistance, unsigned short *outWords, - int *frequencies) const; + int *frequencies, int *outputTypes) const; virtual ~UnigramDictionary(); private: From c7387a4fd065ad6782b0705e56f9556ac9cf127f Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 12 Jul 2012 15:21:11 +0900 Subject: [PATCH 65/68] Add values for suggestion types (A120) Also, use it in getBigrams. Change-Id: Ia0be9b57d1b7effcd8a936e01e957d1195b39c68 --- .../com/android/inputmethod/latin/SuggestedWords.java | 1 + native/jni/src/bigram_dictionary.cpp | 7 ++++--- native/jni/src/bigram_dictionary.h | 2 +- native/jni/src/dictionary.h | 11 +++++++++++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index f079c2112..88fc006df 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -125,6 +125,7 @@ public class SuggestedWords { public static final int KIND_HARDCODED = 5; // Hardcoded suggestion, e.g. punctuation public static final int KIND_APP_DEFINED = 6; // Suggested by the application public static final int KIND_SHORTCUT = 7; // A shortcut + public static final int KIND_PREDICTION = 8; // A prediction (== a suggestion with no input) public final String mWord; public final int mScore; public final int mKind; // one of the KIND_* constants above diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp index d468f2aaf..8057e410a 100644 --- a/native/jni/src/bigram_dictionary.cpp +++ b/native/jni/src/bigram_dictionary.cpp @@ -38,7 +38,7 @@ BigramDictionary::~BigramDictionary() { } bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequency, - int *bigramFreq, unsigned short *bigramChars) const { + int *bigramFreq, unsigned short *bigramChars, int *outputTypes) const { word[length] = 0; if (DEBUG_DICT) { #ifdef FLAG_DBG @@ -65,6 +65,7 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ (char*) bigramFreq + insertAt * sizeof(bigramFreq[0]), (MAX_PREDICTIONS - insertAt - 1) * sizeof(bigramFreq[0])); bigramFreq[insertAt] = frequency; + outputTypes[insertAt] = Dictionary::KIND_PREDICTION; memmove((char*) bigramChars + (insertAt + 1) * MAX_WORD_LENGTH * sizeof(short), (char*) bigramChars + (insertAt ) * MAX_WORD_LENGTH * sizeof(short), (MAX_PREDICTIONS - insertAt - 1) * sizeof(short) * MAX_WORD_LENGTH); @@ -134,8 +135,8 @@ int BigramDictionary::getBigrams(const int32_t *prevWord, int prevWordLength, in // here, but it can't get too bad. const int frequency = BinaryFormat::computeFrequencyForBigram(unigramFreq, bigramFreqTemp); - if (addWordBigram( - bigramBuffer, length, frequency, bigramFreq, bigramChars)) { + if (addWordBigram(bigramBuffer, length, frequency, bigramFreq, bigramChars, + outputTypes)) { ++bigramCount; } } diff --git a/native/jni/src/bigram_dictionary.h b/native/jni/src/bigram_dictionary.h index e09b24945..0b3577ad8 100644 --- a/native/jni/src/bigram_dictionary.h +++ b/native/jni/src/bigram_dictionary.h @@ -39,7 +39,7 @@ class BigramDictionary { private: DISALLOW_IMPLICIT_CONSTRUCTORS(BigramDictionary); bool addWordBigram(unsigned short *word, int length, int frequency, - int *bigramFreq, unsigned short *bigramChars) const; + int *bigramFreq, unsigned short *bigramChars, int *outputTypes) const; int getBigramAddress(int *pos, bool advance); int getBigramFreq(int *pos); void searchForTerminalNode(int addressLookingFor, int frequency); diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index 1292268b8..7911403dc 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -31,6 +31,17 @@ namespace latinime { class Dictionary { public: + // Taken from SuggestedWords.java + const static int KIND_TYPED = 0; // What user typed + const static int KIND_CORRECTION = 1; // Simple correction/suggestion + const static int KIND_COMPLETION = 2; // Completion (suggestion with appended chars) + const static int KIND_WHITELIST = 3; // Whitelisted word + const static int KIND_BLACKLIST = 4; // Blacklisted word + const static int KIND_HARDCODED = 5; // Hardcoded suggestion, e.g. punctuation + const static int KIND_APP_DEFINED = 6; // Suggested by the application + const static int KIND_SHORTCUT = 7; // A shortcut + const static int KIND_PREDICTION = 8; // A prediction (== a suggestion with no input) + Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, int typedLetterMultipler, int fullWordMultiplier, int maxWordLength, int maxWords, int maxPredictions); From fa2287f86c05740d451ae3d08c0976968491c577 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Thu, 12 Jul 2012 13:53:24 -0700 Subject: [PATCH 66/68] Import translations. DO NOT MERGE Change-Id: Ie03bf1e866e2b93cade6f02ce3ce14fa4864097d Auto-generated-cl: translation import --- java/res/values-am/strings.xml | 15 ++++------- java/res/values-ar/strings-appname.xml | 3 +-- java/res/values-ar/strings.xml | 15 ++++------- java/res/values-be/strings-appname.xml | 3 +-- java/res/values-be/strings.xml | 15 ++++------- java/res/values-bg/strings-appname.xml | 3 +-- java/res/values-ca/strings-appname.xml | 3 +-- java/res/values-ca/strings.xml | 15 ++++------- java/res/values-cs/strings.xml | 15 ++++------- java/res/values-da/strings.xml | 15 ++++------- java/res/values-de/strings.xml | 15 ++++------- java/res/values-el/strings.xml | 15 ++++------- java/res/values-en-rGB/strings-appname.xml | 3 +-- java/res/values-en-rGB/strings.xml | 15 ++++------- java/res/values-es-rUS/strings-appname.xml | 3 +-- java/res/values-es-rUS/strings.xml | 15 ++++------- java/res/values-es/strings.xml | 15 ++++------- java/res/values-et/strings-appname.xml | 3 +-- java/res/values-et/strings.xml | 15 ++++------- java/res/values-fa/strings-appname.xml | 3 +-- java/res/values-fa/strings.xml | 10 ++++---- java/res/values-fi/strings-appname.xml | 3 +-- java/res/values-fi/strings.xml | 15 ++++------- java/res/values-fr/strings-appname.xml | 3 +-- java/res/values-fr/strings.xml | 15 ++++------- java/res/values-hi/strings-appname.xml | 3 +-- java/res/values-hr/strings.xml | 15 ++++------- java/res/values-in/strings-appname.xml | 3 +-- java/res/values-in/strings.xml | 15 ++++------- java/res/values-it/strings.xml | 15 ++++------- java/res/values-iw/strings.xml | 15 ++++------- java/res/values-ja/strings-appname.xml | 3 +-- java/res/values-ko/strings-appname.xml | 3 +-- java/res/values-lt/strings-appname.xml | 3 +-- java/res/values-lt/strings.xml | 15 ++++------- java/res/values-lv/strings-appname.xml | 3 +-- java/res/values-lv/strings.xml | 15 ++++------- java/res/values-ms/strings-appname.xml | 28 ++++++++++++++++++++ java/res/values-nb/strings-appname.xml | 3 +-- java/res/values-nb/strings.xml | 15 ++++------- java/res/values-nl/strings.xml | 15 ++++------- java/res/values-pt-rPT/strings-appname.xml | 3 +-- java/res/values-pt-rPT/strings.xml | 15 ++++------- java/res/values-pt/strings-appname.xml | 28 ++++++++++++++++++++ java/res/values-ro/strings-appname.xml | 3 +-- java/res/values-ru/strings-appname.xml | 3 +-- java/res/values-sk/strings-appname.xml | 3 +-- java/res/values-sl/strings-appname.xml | 3 +-- java/res/values-sl/strings.xml | 15 ++++------- java/res/values-sr/strings.xml | 15 ++++------- java/res/values-sv/strings.xml | 15 ++++------- java/res/values-sw/strings.xml | 15 ++++------- java/res/values-th/strings-appname.xml | 30 ++++++++++++++++++++++ java/res/values-tl/strings-appname.xml | 3 +-- java/res/values-tr/strings-appname.xml | 3 +-- java/res/values-uk/strings-appname.xml | 3 +-- java/res/values-uk/strings.xml | 15 ++++------- java/res/values-vi/strings-appname.xml | 3 +-- java/res/values-zh-rCN/strings-appname.xml | 28 ++++++++++++++++++++ java/res/values-zh-rTW/strings-appname.xml | 3 +-- java/res/values-zu/strings-appname.xml | 3 +-- java/res/values-zu/strings.xml | 15 ++++------- 62 files changed, 292 insertions(+), 351 deletions(-) create mode 100644 java/res/values-ms/strings-appname.xml create mode 100644 java/res/values-pt/strings-appname.xml create mode 100644 java/res/values-th/strings-appname.xml create mode 100644 java/res/values-zh-rCN/strings-appname.xml diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml index 1066a2ca9..d36b9a68b 100644 --- a/java/res/values-am/strings.xml +++ b/java/res/values-am/strings.xml @@ -107,19 +107,14 @@ "የምዝግብ ማስታወሻ ጊዜ ማህተም ማስታወሻ" "የጊዜ ማህተም ተመዝግቧል" "ይህን ክፍለ ጊዜ እንዳትመዘግበው" - - - - + "ክፍለ ጊዜ ምዝገባን አንቃ" + "ሙሉውን የክፍለጊዜ ታሪክ መዝግብ" "የክፍለጊዜ ምዝግብ ማስታወሻ በመሰረዝ ላይ" "የክፍለ ጊዜ ምዝግብ ማስታወሻ ተሰርዟል" "የክፍለጊዜ ምዝግብ ማስታወሻ አልተሰረዘም" - - - - - - + "የክፍለጊዜ ታሪክ ተመዝግቧል" + "ስህተት፦ክፍለጊዜ ታሪክ አልተመዘገበም" + "ክፍለጊዜ ምዝገባ ነቅቷል" "ቋንቋዎች አግቤት" "ለማስቀመጥ እንደገና ንካ" "መዝገበ ቃላት አለ" diff --git a/java/res/values-ar/strings-appname.xml b/java/res/values-ar/strings-appname.xml index 32be444b3..3d81e5d4b 100644 --- a/java/res/values-ar/strings-appname.xml +++ b/java/res/values-ar/strings-appname.xml @@ -20,8 +20,7 @@ - - + "لوحة مفاتيح Android" "التدقيق الإملائي في Android" "إعدادات لوحة مفاتيح Android" "إعدادات التدقيق الإملائي" diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml index cea27017f..9490704a6 100644 --- a/java/res/values-ar/strings.xml +++ b/java/res/values-ar/strings.xml @@ -107,19 +107,14 @@ "ملاحظة طابع زمني في سجل" "تم تسجيل الطابع الزمني" "عدم تسجيل هذه الجلسة" - - - - + "تمكين تسجيل الجلسة" + "تسجيل سجل الجلسة بالكامل" "جارٍ حذف سجل الجلسة" "تم حذف سجل الجلسة" "لم يتم حذف سجل الجلسة" - - - - - - + "تم تسجيل سجل الجلسة" + "الخطأ: لم يتم تسجيل سجل الجلسة" + "تم تمكين تسجيل الجلسة" "لغات الإدخال" "المس مرة أخرى للحفظ" "القاموس متاح" diff --git a/java/res/values-be/strings-appname.xml b/java/res/values-be/strings-appname.xml index 226de7cbd..e0aadfa3c 100644 --- a/java/res/values-be/strings-appname.xml +++ b/java/res/values-be/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Клавіятура Android" "Iнструмент праверкi правапiсу для Android" "Налады клавіятуры Android" "Налады праверкі арфаграфіі" diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml index 3ac96f0d6..0d563f330 100644 --- a/java/res/values-be/strings.xml +++ b/java/res/values-be/strings.xml @@ -107,19 +107,14 @@ "Пазначыць час у гiсторыi" "Запiсаныя пазнакі" "Не рэгістраваць гэты сеанс" - - - - + "Уключыць гiсторыю сеанса" + "Запiс усёй гiсторыi сеанса" "Выдаленне гiсторыi сеанса" "Гiсторыя сеанса выдалена" "Гiсторыя сеанса НЕ выдалена" - - - - - - + "Гiсторыя сеанса запiсана" + "Памылка: гiсторыя сеанса НЕ запiсана" + "Уключаны запiс сеанса" "Мовы ўводу" "Дакраніцеся зноў, каб захаваць" "Слоўнік даступны" diff --git a/java/res/values-bg/strings-appname.xml b/java/res/values-bg/strings-appname.xml index 9976f099f..49e301d32 100644 --- a/java/res/values-bg/strings-appname.xml +++ b/java/res/values-bg/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Клавиатура на Android" "Програма за правописна проверка за Android" "Настройки на клавиатурата на Android" "Настройки за проверка на правописа" diff --git a/java/res/values-ca/strings-appname.xml b/java/res/values-ca/strings-appname.xml index 6a23c242b..add5c3f2f 100644 --- a/java/res/values-ca/strings-appname.xml +++ b/java/res/values-ca/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Teclat Android" "Corrector ortogràfic d\'Android" "Configuració del teclat d\'Android" "Configuració de la correcció ortogràfica" diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml index 367fdff7d..252441062 100644 --- a/java/res/values-ca/strings.xml +++ b/java/res/values-ca/strings.xml @@ -107,19 +107,14 @@ "Indica m. horària al reg." "Marca horària enregistrada" "No enregistris la sessió" - - - - + "Activa el registre de sessió" + "Registra tot l\'historial de sessió" "Suprimint registre de ses." "Registre de ses. suprimit" "Registre de ses. NO sup." - - - - - - + "Historial de sessió registrat" + "Error: historial de sessió NO registrat" + "Registre de sessió activat" "Idiomes d\'entrada" "Torna a tocar per desar" "Diccionari disponible" diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml index fa47c5bb1..4697d43ec 100644 --- a/java/res/values-cs/strings.xml +++ b/java/res/values-cs/strings.xml @@ -107,19 +107,14 @@ "Uložit čas do protokolu" "Časové razítko vloženo" "Neprotokolovat relaci" - - - - + "Povolit protokolování relace" + "Protokolovat celou historii relace" "Mazání protokolu relace" "Protokol relace smazán" "Protokol relace nesmazán" - - - - - - + "Historie relace protokolována" + "Historie relace NENÍ protokolována" + "Protokolování relace povoleno" "Vstupní jazyky" "Opětovným dotykem provedete uložení" "Slovník k dispozici" diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml index 4a4e9416d..5a128ee58 100644 --- a/java/res/values-da/strings.xml +++ b/java/res/values-da/strings.xml @@ -107,19 +107,14 @@ "Notér tidsstempel i log" "Noteret tidsstempel" "Logfør ikke denne session" - - - - + "Aktivér logføring af sessioner" + "Logfør hele sessionshistorikken" "Sletter sessionslogfil" "Sessionslogfil slettet" "Sessionslog IKKE slettet" - - - - - - + "Sessionshistorikken er logført" + "Fejl: Sessionshistorik IKKE logført" + "Logføring af sessioner er aktiveret" "Inputsprog" "Tryk igen for at gemme" "Ordbog er tilgængelig" diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml index c4b1aeec4..9381ecb56 100644 --- a/java/res/values-de/strings.xml +++ b/java/res/values-de/strings.xml @@ -107,19 +107,14 @@ "Zeitstempel im Protokoll" "Zeitstempel aufgenommen" "Nicht protokollieren" - - - - + "Sitzungsprotokoll aktivieren" + "Gesamten Sitzungsverlauf speichern" "Protokoll wird gelöscht..." "Protokoll gelöscht" "Protokoll NICHT gelöscht" - - - - - - + "Sitzungsverlauf gespeichert" + "Sitzungsverlauf NICHT gespeichert" + "Sitzungsprotokoll aktiviert" "Eingabesprachen" "Zum Speichern erneut berühren" "Wörterbuch verfügbar" diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml index c2df29592..8125bc4bd 100644 --- a/java/res/values-el/strings.xml +++ b/java/res/values-el/strings.xml @@ -107,19 +107,14 @@ "Χρόνος στο αρχείο καταγρ." "Καταγεγραμμένος χρόνος" "Χωρίς αρχείο καταγραφής" - - - - + "Ενεργοποίηση καταγραφής περιόδου" + "Καταγραφή ολόκλ. ιστορικού περιόδου" "Διαγραφή αρχείου σύνδεσης" "Αρχείο καταγρ. διαγράφηκε" "Αρχείο καταγρ. ΔΕΝ διαγρ." - - - - - - + "Το ιστορικό περιόδου καταγράφηκε" + "Σφάλμα: ΜΗ καταγραφή ιστορ. περιόδου" + "Ενεργοποίηση καταγραφής περιόδου" "Γλώσσες εισόδου" "Αγγίξτε ξανά για αποθήκευση" "Λεξικό διαθέσιμο" diff --git a/java/res/values-en-rGB/strings-appname.xml b/java/res/values-en-rGB/strings-appname.xml index 53f9e9d0e..ad9e782b0 100644 --- a/java/res/values-en-rGB/strings-appname.xml +++ b/java/res/values-en-rGB/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Android keyboard" "Android spell checker" "Android keyboard settings" "Spell checking settings" diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml index b7e6e0ca4..9697cc792 100644 --- a/java/res/values-en-rGB/strings.xml +++ b/java/res/values-en-rGB/strings.xml @@ -107,19 +107,14 @@ "Note timestamp in log" "Recorded timestamp" "Do not log this session" - - - - + "Enable session logging" + "Log whole session history" "Deleting session log" "Session log deleted" "Session log NOT deleted" - - - - - - + "Session history logged" + "Error: Session history NOT logged" + "Session logging enabled" "Input languages" "Touch again to save" "Dictionary available" diff --git a/java/res/values-es-rUS/strings-appname.xml b/java/res/values-es-rUS/strings-appname.xml index 91c1b929b..5f08afba4 100644 --- a/java/res/values-es-rUS/strings-appname.xml +++ b/java/res/values-es-rUS/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Teclado de Android" "Corrector ortográfico de Android" "Configuración de teclado de Android" "Configuración del corrector ortográfico" diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml index 7b1470a64..00fce612b 100644 --- a/java/res/values-es-rUS/strings.xml +++ b/java/res/values-es-rUS/strings.xml @@ -107,19 +107,14 @@ "Marcar tiempo en registro" "Marca tiempo registrada" "No registrar esta sesión" - - - - + "Activar registro de sesión" + "Registrar his. de sesión completo" "Eliminando registro" "Registro sesión eliminado" "NO se eliminó el registro" - - - - - - + "Se registró el historial de sesión." + "Error al registrar his. de sesión" + "Se activó el historial de sesión." "Idiomas de entrada" "Vuelve a tocar para guardar." "Diccionario disponible" diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml index b86d7fd0e..7625003c8 100644 --- a/java/res/values-es/strings.xml +++ b/java/res/values-es/strings.xml @@ -107,19 +107,14 @@ "Anotar marca tiempo en registro" "Marca de tiempo registrada" "No registrar esta sesión" - - - - + "Habilitar registro de sesión" + "Registrar historial de sesión" "Eliminando registro..." "Registro eliminado" "Registro no eliminado" - - - - - - + "Historial de sesión registrado" + "Error: historial NO registrado" + "Registro de sesión habilitado" "Idiomas de entrada" "Toca otra vez para guardar." "Hay un diccionario disponible" diff --git a/java/res/values-et/strings-appname.xml b/java/res/values-et/strings-appname.xml index 2e0780e5b..181d597f9 100644 --- a/java/res/values-et/strings-appname.xml +++ b/java/res/values-et/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Androidi klaviatuur" "Androidi õigekirjakontroll" "Androidi klaviatuuri seaded" "Õigekirjakontrolli seaded" diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml index cb010a0e5..ae98198ce 100644 --- a/java/res/values-et/strings.xml +++ b/java/res/values-et/strings.xml @@ -107,19 +107,14 @@ "Märgi ajatempel logisse" "Salvestatud ajatemplid" "Ära logi seda seanssi" - - - - + "Lubage seansi logimine" + "Logige kogu seansi ajalugu" "Seansi logi kustutamine" "Seansi logi kustutatud" "Seansi logi EI kustutatud" - - - - - - + "Seansi ajalugu on logitud" + "Viga: seansi ajalugu EI OLE logitud" + "Seansi logimine on lubatud" "Sisestuskeeled" "Salvestamiseks puudutage uuesti" "Sõnastik saadaval" diff --git a/java/res/values-fa/strings-appname.xml b/java/res/values-fa/strings-appname.xml index 263f166f8..366d56d92 100644 --- a/java/res/values-fa/strings-appname.xml +++ b/java/res/values-fa/strings-appname.xml @@ -20,8 +20,7 @@ - - + "صفحه کلید Android" "غلط‌گیر املای Android" "تنظیمات صفحه کلید Android" "تنظیمات غلط‌‌ گیر املا" diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml index 5dd7c31b2..bfdabab04 100644 --- a/java/res/values-fa/strings.xml +++ b/java/res/values-fa/strings.xml @@ -31,7 +31,7 @@ "بازشدن با فشار کلید" "کلی" "تصحیح متن" - "سایر گزینه ها" + "سایر گزینه‌ها" "تنظیمات پیشرفته" "گزینه‌هایی برای حرفه‌ای‌ها" "تغییر به دیگر روشهای ورودی" @@ -51,7 +51,7 @@ "نمایش در حالت عمودی" "همیشه پنهان شود" "تصحیح خودکار" - "کلید فاصله و علائم نگارشی به صورت خودکار کلماتی را که غلط تایپ شده اند تصحیح می کنند" + "کلید فاصله و علائم نگارشی به صورت خودکار کلماتی را که غلط تایپ شده‌اند تصحیح می کنند" "خاموش" "متوسط" "فعال" @@ -130,12 +130,12 @@ "فعال کردن بازخورد کاربر" "با ارسال خودکار آمارهای کاربرد و گزارش های خرابی به Google، به بهبود این ویرایشگر روش ورودی کمک کنید." "طرح زمینه صفحه کلید" - "انگیسی (UK)" - "انگیسی (US)" + "انگلیسی (بریتانیا)" + "انگلیسی (امریکا)" "انگلیسی (انگلستان) (%s)" "انگلیسی (ایالات متحده) (%s)" "زبانی موجود نیست" - "هیچ کدام از زبانها (QWERTY)" + "بدون زبان (QWERTY)" "هیچکدام از زبان‌ها (QWERTZ)" "هیچکدام از زبان‌ها (AZERTY)" "هیچکدام از زبان‌ها (Dvorak)" diff --git a/java/res/values-fi/strings-appname.xml b/java/res/values-fi/strings-appname.xml index fefb92e15..b2e23d552 100644 --- a/java/res/values-fi/strings-appname.xml +++ b/java/res/values-fi/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Android-näppäimistö" "Android-oikoluku" "Android-näppäimistön asetukset" "Oikolukuasetukset" diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml index 8b4e2a418..b19b0624e 100644 --- a/java/res/values-fi/strings.xml +++ b/java/res/values-fi/strings.xml @@ -107,19 +107,14 @@ "Merkitse aikaleima lokiin" "Merkitty aikaleima" "Älä tallenna tätä käyttök." - - - - + "Ota käyttökertaloki käyttöön" + "Kirjaa koko käyttökerran historia" "Poistetaan lokia" "Käyttökertaloki poistettu" "Lokia EI poistettu" - - - - - - + "Käyttökerran historia kirjattu" + "Virhe: käyttök. historiaa EI kirj." + "Käyttökertaloki käytössä" "Syöttökielet" "Tallenna koskettamalla uudelleen" "Sanakirja saatavilla" diff --git a/java/res/values-fr/strings-appname.xml b/java/res/values-fr/strings-appname.xml index da7671b1f..8e2a6e088 100644 --- a/java/res/values-fr/strings-appname.xml +++ b/java/res/values-fr/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Clavier Android" "Correcteur orthographique Android" "Paramètres du clavier Android" "Paramètres du correcteur orthographique" diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml index edcb5ba84..99c6e0337 100644 --- a/java/res/values-fr/strings.xml +++ b/java/res/values-fr/strings.xml @@ -107,19 +107,14 @@ "Noter heure dans journal" "Heure enregistrée." "Ne pas enregistrer session" - - - - + "Activer l\'enregistrement de session" + "Enregistrer historique de la session" "Suppr. journal session…" "Journal session supprimé." "Journal session PAS suppr." - - - - - - + "Historique de la session enregistré." + "Historique session NON enregistré." + "Enregistrement de session activé." "Langues de saisie" "Appuyer de nouveau pour enregistrer" "Dictionnaire disponible" diff --git a/java/res/values-hi/strings-appname.xml b/java/res/values-hi/strings-appname.xml index c8d34ec3c..02283af9a 100644 --- a/java/res/values-hi/strings-appname.xml +++ b/java/res/values-hi/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Android कीबोर्ड" "Android वर्तनी परीक्षक" "Android कीबोर्ड सेटिंग" "वर्तनी जांच सेटिंग" diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml index 94caf6ea3..5a1eefc5e 100644 --- a/java/res/values-hr/strings.xml +++ b/java/res/values-hr/strings.xml @@ -107,19 +107,14 @@ "Zabilježi razdoblje u dnevniku" "Zabilježeno razdoblje" "Ne bilježi ovu sesiju" - - - - + "Omogući bilježenje sesije" + "Bilježi cijelu povijest sesije" "Brisanje dnevnika sesije" "Izbrisan dnevnik sesije" "Dnevnik sesije NIJE izbrisan" - - - - - - + "Povijest sesije zabilježena je" + "Pogr.: pov. sesije NIJE zabilježena" + "Omogućeno je bilježenje sesije" "Jezici unosa" "Dodirnite ponovo za spremanje" "Rječnik je dostupan" diff --git a/java/res/values-in/strings-appname.xml b/java/res/values-in/strings-appname.xml index 363d57197..283d69247 100644 --- a/java/res/values-in/strings-appname.xml +++ b/java/res/values-in/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Keyboard Android" "Pemeriksa ejaan Android" "Setelan keyboard Android" "Setelan pemeriksa ejaan" diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml index ebc0c3e59..b02656c6e 100644 --- a/java/res/values-in/strings.xml +++ b/java/res/values-in/strings.xml @@ -107,19 +107,14 @@ "Catat cap waktu di log" "Cap waktu yang direkam" "Jangan simpan log sesi ini" - - - - + "Aktifkan log sesi" + "Rekam log seluruh riwayat sesi" "Menghapus log sesi" "Log sesi dihapus" "Log sesi BELUM dihapus" - - - - - - + "Log riwayat sesi direkam" + "Ksalahn: Log rwyat sesi TAK direkam" + "Perekaman log sesi diaktifkan" "Bahasa masukan" "Sentuh lagi untuk menyimpan" "Kamus yang tersedia" diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml index 2345f447e..b23c516e9 100644 --- a/java/res/values-it/strings.xml +++ b/java/res/values-it/strings.xml @@ -107,19 +107,14 @@ "Indicazione temporale log" "Indicazione temporale registrata" "Non registrare la sessione" - - - - + "Attiva registrazione sessioni" + "Registra intera cronologia sessione" "Eliminazione log sessione" "Log di sessione eliminato" "Log sessione non eliminato" - - - - - - + "Cronologia sessione registrata" + "Errore: cron. sessione NON registr." + "Registrazione sessioni attivata" "Lingue comandi" "Tocca di nuovo per salvare" "Dizionario disponibile" diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml index a69ba9f4f..29bd615b4 100644 --- a/java/res/values-iw/strings.xml +++ b/java/res/values-iw/strings.xml @@ -107,19 +107,14 @@ "ציין חותמת זמן ביומן" "חותמת זמן מתועדת" "אל תרשום הפעלה זו ביומן" - - - - + "הפעל רישום הפעלה" + "רשום את כל היסטוריית ההפעלה" "מוחק יומן הפעלה" "יומן הפעלה נמחק" "יומן הפעלה לא נמחק" - - - - - - + "היסטוריית הפעלה נרשמה" + "שגיאה: היסטוריית ההפעלה לא נרשמה" + "רישום הפעלה הופעל" "שפות קלט" "גע שוב כדי לשמור" "מילון זמין" diff --git a/java/res/values-ja/strings-appname.xml b/java/res/values-ja/strings-appname.xml index fd91575b3..16c1c05c6 100644 --- a/java/res/values-ja/strings-appname.xml +++ b/java/res/values-ja/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Androidキーボード" "Androidスペルチェッカー" "Androidキーボードの設定" "スペルチェックの設定" diff --git a/java/res/values-ko/strings-appname.xml b/java/res/values-ko/strings-appname.xml index 0dc7e6fb9..3d7db6136 100644 --- a/java/res/values-ko/strings-appname.xml +++ b/java/res/values-ko/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Android 키보드" "Android 맞춤법 검사기" "Android 키보드 설정" "맞춤법 검사 설정" diff --git a/java/res/values-lt/strings-appname.xml b/java/res/values-lt/strings-appname.xml index e32a94585..668d27531 100644 --- a/java/res/values-lt/strings-appname.xml +++ b/java/res/values-lt/strings-appname.xml @@ -20,8 +20,7 @@ - - + "„Android“ klaviatūra" "„Android“ rašybos tikrinimo programa" "„Android“ klaviatūros nustatymai" "Rašybos tikrinimo nustatymai" diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml index ef17d70d0..7d7b54c8f 100644 --- a/java/res/values-lt/strings.xml +++ b/java/res/values-lt/strings.xml @@ -107,19 +107,14 @@ "Pažym. laiko žymę žurnale" "Įrašyta laiko žymė" "Neįrašyti šios sesijos" - - - - + "Įgalinti sesijos įrašymą į žurnalą" + "Įrašyti sesijos istoriją į žurnalą" "Ištrinam. sesijos žurnal." "Sesijos žurnalas ištrint." "Sesij. žurnal. NEIŠTRINT." - - - - - - + "Sesijos istorija įrašyta į žurnalą" + "Klaida: sesijos istorija NEĮRAŠYTA" + "Sesijos įrašymas žurnale įgalintas" "Įvesties kalbos" "Jei norite išsaugoti, palieskite dar kartą" "Žodynas galimas" diff --git a/java/res/values-lv/strings-appname.xml b/java/res/values-lv/strings-appname.xml index fe2f33697..e5657a237 100644 --- a/java/res/values-lv/strings-appname.xml +++ b/java/res/values-lv/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Android tastatūra" "Android pareizrakstības pārbaudītājs" "Android tastatūras iestatījumi" "Pareizrakstības pārbaudes iestatījumi" diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml index d325ef85f..e5e61e39c 100644 --- a/java/res/values-lv/strings.xml +++ b/java/res/values-lv/strings.xml @@ -107,19 +107,14 @@ "Atzīmēt laiksp. žurnālā" "Laikspied. ir reģistrēts." "Nereģistrēt šo sesiju" - - - - + "Sesijas reģistrēšanas iespējošana" + "Visas sesijas vēstures reģistrēšana" "Not. sesijas žurn. dzēš." "Sesijas žurnāls ir dzēsts" "Sesijas žurn. NAV dzēsts" - - - - - - + "Sesijas vēsture ir reģistrēta." + "Kļūda: sesijas vēsture NAV reģistr." + "Sesijas reģistrēšana ir iespējota." "Ievades valodas" "Pieskarieties vēlreiz, lai saglabātu." "Ir pieejama vārdnīca." diff --git a/java/res/values-ms/strings-appname.xml b/java/res/values-ms/strings-appname.xml new file mode 100644 index 000000000..6273c6595 --- /dev/null +++ b/java/res/values-ms/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Penyemak ejaan Android" + "Tetapan papan kekunci Android" + "Tetapan penyemakan ejaan" + diff --git a/java/res/values-nb/strings-appname.xml b/java/res/values-nb/strings-appname.xml index b5ed18abb..56c1c3c71 100644 --- a/java/res/values-nb/strings-appname.xml +++ b/java/res/values-nb/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Android-tastatur" "Android-stavekontroll" "Innstillinger for Android-tastatur" "Innstillinger for stavekontroll" diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml index 43b226965..5f7519a8d 100644 --- a/java/res/values-nb/strings.xml +++ b/java/res/values-nb/strings.xml @@ -107,19 +107,14 @@ "Notér tidsstempel i logg" "Registrerte tidsstempel" "Ikke loggfør denne økten" - - - - + "Aktiver lagring av økter" + "Lagre hele øktloggen" "Sletter øktloggen" "Øktloggen ble slettet" "Øktloggen ble IKKE slettet" - - - - - - + "Øktloggen er lagret" + "Feil: Øktloggen er IKKE lagret" + "Øktlagring er aktivert" "Inndataspråk" "Trykk på nytt for å lagre" "Ordbok tilgjengelig" diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml index a7188113d..19c9eda1c 100644 --- a/java/res/values-nl/strings.xml +++ b/java/res/values-nl/strings.xml @@ -107,19 +107,14 @@ "Tijdstempel opnemen in logbestand" "Opgenomen tijdstempel" "Sessie niet registreren" - - - - + "Sessieregistratie inschakelen" + "Hele sessiegeschiedenis registreren" "Sessielogbestand verwijderen" "Sessielogbestand verwijderd" "Sessielogbestand NIET verwijderd" - - - - - - + "Sessiegeschiedenis geregistreerd" + "Fout: sessiegesch. NIET geregistr." + "Sessieregistratie ingeschakeld" "Invoertalen" "Raak nogmaals aan om op te slaan" "Woordenboek beschikbaar" diff --git a/java/res/values-pt-rPT/strings-appname.xml b/java/res/values-pt-rPT/strings-appname.xml index 0f6abb97f..1b88acb69 100644 --- a/java/res/values-pt-rPT/strings-appname.xml +++ b/java/res/values-pt-rPT/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Teclado do Android" "Verificador ortográfico do Android" "Definições de teclado do Android" "Definições da verificação ortográfica" diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml index a1cc6f784..f16070bb4 100644 --- a/java/res/values-pt-rPT/strings.xml +++ b/java/res/values-pt-rPT/strings.xml @@ -107,19 +107,14 @@ "Anotar car. data no reg." "Carimbo de data gravado" "Não registar esta sessão" - - - - + "Ativar registos de sessão" + "Registar hist. de sessões completo" "A eliminar reg. da sessão" "Reg. de sessão eliminado" "Reg. de sessão NÃO elim." - - - - - - + "Histórico de sessões registado" + "Erro: hist. de sessões NÃO regist." + "Registo de sessões ativado" "Idiomas de introdução" "Toque novamente para guardar" "Dicionário disponível" diff --git a/java/res/values-pt/strings-appname.xml b/java/res/values-pt/strings-appname.xml new file mode 100644 index 000000000..3987a6dea --- /dev/null +++ b/java/res/values-pt/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Corretor ortográfico do Android" + "Configurações de teclado do Android" + "Configurações de verificação ortográfica" + diff --git a/java/res/values-ro/strings-appname.xml b/java/res/values-ro/strings-appname.xml index b1fd29b8a..dfa642204 100644 --- a/java/res/values-ro/strings-appname.xml +++ b/java/res/values-ro/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Tastatură Android" "Verificator ortografic Android" "Setările tastaturii Android" "Setările de verificare ortografică" diff --git a/java/res/values-ru/strings-appname.xml b/java/res/values-ru/strings-appname.xml index b67c369a7..5db1d0bc9 100644 --- a/java/res/values-ru/strings-appname.xml +++ b/java/res/values-ru/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Клавиатура Android" "Проверка правописания Android" "Настройки клавиатуры Android" "Настройки проверки правописания" diff --git a/java/res/values-sk/strings-appname.xml b/java/res/values-sk/strings-appname.xml index d2e150378..5b5590000 100644 --- a/java/res/values-sk/strings-appname.xml +++ b/java/res/values-sk/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Klávesnica Android" "Kontrola pravopisu Android" "Nastavenia klávesnice Android" "Nastavenia kontroly pravopisu" diff --git a/java/res/values-sl/strings-appname.xml b/java/res/values-sl/strings-appname.xml index aa8c8163c..fd303d8dd 100644 --- a/java/res/values-sl/strings-appname.xml +++ b/java/res/values-sl/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Tipkovnica Android" "Črkovalnik za Android" "Nastavitve tipkovnice Android" "Nastavitve preverjanja črkovanja" diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml index fa6822382..ad3e7395f 100644 --- a/java/res/values-sl/strings.xml +++ b/java/res/values-sl/strings.xml @@ -107,19 +107,14 @@ "V dnev. zabeleži čas. žig" "Časovni žig zabeležen" "Brez dnevnika za to sejo" - - - - + "Omogoči zapisovanje seje v dnevnik" + "Zapiši celotno zgodovino seje v dnevnik" "Brisanje seje dnevnika" "Dnevnik seje izbrisan" "Dnevnik seje NI izbrisan" - - - - - - + "Zgodovina seje zapisana v dnevnik" + "Napaka: zgodovina seje NI zapisana v dnevnik" + "Zapisovanje seje v dnevnik omogočeno" "Jeziki vnosa" "Dotaknite se še enkrat, da shranite" "Slovar je na voljo" diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml index f5e70ece4..d1c440d07 100644 --- a/java/res/values-sr/strings.xml +++ b/java/res/values-sr/strings.xml @@ -107,19 +107,14 @@ "Наведи временску ознаку у евиденцији" "Снимљена временска ознака" "Не евидентирај ову сесију" - - - - + "Омогући евидентирање сесија" + "Евидентирај целу историју сесија" "Брисање евиденције сесије" "Евиденција сесије је обрисана" "Евиденција сесије НИЈЕ избрисана" - - - - - - + "Историја сесија је евидентирана" + "Грешка: Историја сесија НИЈЕ евидентирана" + "Евидентирање сесија је омогућено" "Језици уноса" "Поново додирните да бисте сачували" "Речник је доступан" diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml index d8e55dfb2..0da487723 100644 --- a/java/res/values-sv/strings.xml +++ b/java/res/values-sv/strings.xml @@ -107,19 +107,14 @@ "Markera tidpunkt i loggen" "Tidpunkten har sparats" "Logga inte detta besök" - - - - + "Aktivera sessionsloggning" + "Logga hela sessionshistoriken" "Besöksloggen tas bort" "Besöksloggen togs bort" "Besöksloggen togs EJ bort" - - - - - - + "Sessionshistoriken har loggats" + "Fel: historiken har INTE loggats" + "Sessionsloggning är aktiverat" "Inmatningsspråk" "Spara genom att trycka igen" "En ordlista är tillgänglig" diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml index 2b8c896a2..545c41157 100644 --- a/java/res/values-sw/strings.xml +++ b/java/res/values-sw/strings.xml @@ -107,19 +107,14 @@ "Dokeza mhuri wa muda kwenye kumbukumbu" "Mhuri wa muda uliorekodiwa" "Usihifadhi kumbukumbu za kipindi hiki" - - - - + "Wezesha kuingia kwenye kipindi" + "Ingia kwenye historia ya kipindi kizima" "Inafuta kumbukumbu za kipindi" "Kumbukumbu za kipindi zimefutwa" "Kumbukumbu za kipindi HAZIJAFUTWA" - - - - - - + "Historia ya kipindi imeingia" + "Hitilafu: Historia ya kipindi HAIJAINGIA" + "Kuingia kwa kipindi kumewezeshwa" "Lugha zinazoruhusiwa" "Gusa tena ili kuhifadhi" "Kamusi inapatikana" diff --git a/java/res/values-th/strings-appname.xml b/java/res/values-th/strings-appname.xml new file mode 100644 index 000000000..87205d0eb --- /dev/null +++ b/java/res/values-th/strings-appname.xml @@ -0,0 +1,30 @@ + + + + + "แป้นพิมพ์แอนดรอยด์" + + + + + + + diff --git a/java/res/values-tl/strings-appname.xml b/java/res/values-tl/strings-appname.xml index bfa1b4627..fd2b3f55b 100644 --- a/java/res/values-tl/strings-appname.xml +++ b/java/res/values-tl/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Keyboard ng Android" "Spell checker ng Android" "Mga setting ng keyboard ng Android" "Mga setting ng pag-spell check" diff --git a/java/res/values-tr/strings-appname.xml b/java/res/values-tr/strings-appname.xml index a499f382e..f5e36d2e8 100644 --- a/java/res/values-tr/strings-appname.xml +++ b/java/res/values-tr/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Android klavyesi" "Android yazım denetleyici" "Android klavye ayarları" "Yazım denetimi ayarları" diff --git a/java/res/values-uk/strings-appname.xml b/java/res/values-uk/strings-appname.xml index d77b617fa..fdbb89fd9 100644 --- a/java/res/values-uk/strings-appname.xml +++ b/java/res/values-uk/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Клавіатура Android" "Засіб перевірки орфографії Android" "Налаштування клавіатури Android" "Налаштування перевірки орфографії" diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml index 0ba53ced9..d2f9091f6 100644 --- a/java/res/values-uk/strings.xml +++ b/java/res/values-uk/strings.xml @@ -107,19 +107,14 @@ "Мітка часу в журналі" "Записана мітка часу" "Не реєструвати цю сесію" - - - - + "Увімкнути запис журналу сеансу" + "Записувати історію всього сеансу" "Видалення журналу сесії" "Журнал сесії видалено" "Журнал сесії НЕ видалено" - - - - - - + "Історію сеансу записано" + "Помилка. Історію сеансу НЕ записано" + "Запис журналу сеансу ввімкнено" "Мови введення" "Торкніться знову, щоб зберегти" "Словник доступний" diff --git a/java/res/values-vi/strings-appname.xml b/java/res/values-vi/strings-appname.xml index 411ac02d7..6e32d0370 100644 --- a/java/res/values-vi/strings-appname.xml +++ b/java/res/values-vi/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Bàn phím Android" "Trình kiểm tra chính tả Android" "Cài đặt bàn phím Android" "Cài đặt kiểm tra chính tả" diff --git a/java/res/values-zh-rCN/strings-appname.xml b/java/res/values-zh-rCN/strings-appname.xml new file mode 100644 index 000000000..2c1064ad6 --- /dev/null +++ b/java/res/values-zh-rCN/strings-appname.xml @@ -0,0 +1,28 @@ + + + + + + + "Android 拼写检查工具" + "Android 键盘设置" + "拼写检查设置" + diff --git a/java/res/values-zh-rTW/strings-appname.xml b/java/res/values-zh-rTW/strings-appname.xml index dd665590a..8cc663826 100644 --- a/java/res/values-zh-rTW/strings-appname.xml +++ b/java/res/values-zh-rTW/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Android 鍵盤" "Android 拼字檢查" "Android 鍵盤設定" "拼字檢查設定" diff --git a/java/res/values-zu/strings-appname.xml b/java/res/values-zu/strings-appname.xml index b5212a5b6..a0fb51716 100644 --- a/java/res/values-zu/strings-appname.xml +++ b/java/res/values-zu/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Ikhibhodi ye-Android" "Isihloli sokupela se-Android" "Izilungiselelo zekhibhodi ye-Android" "Izilungiselelo zokuhlola ukupela" diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml index b9771c1e8..da222092e 100644 --- a/java/res/values-zu/strings.xml +++ b/java/res/values-zu/strings.xml @@ -107,19 +107,14 @@ "Qaphela isitembu sesikhathi efayeleni lokungena" "Isitembu sesikhathi esirekhodiwe" "Ungenzi ifayela lokungena lalesi sikhathi" - - - - + "Nika amandla ukungena ngemvume kwesikhathi" + "Umlando wesikhathi sonke sefayela lokungena" "Isusa ifayela lokungena lesikhathi" "Ifayela lokungena lesikhathi lisusiwe" "Ifayela lokungena lesikhathi alisusiwe" - - - - - - + "Umlando wesikhathi ukhiyiwe" + "Iphutha: Umlando wesikhathi awukhiyiwe" + "Ukungena kwesikhathi kunikwe amandla" "Izilimi zokufakwayo" "Thinta futhi ukuze ulondoloze" "Isichazamazwi siyatholakala" From 7247bff6d6d488640ac752127148e7746c43469d Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Fri, 13 Jul 2012 11:17:25 +0900 Subject: [PATCH 67/68] Fix InputPointers.append Change-Id: I6995f9b2ed00b9f948e1299e576a5e24725d58f8 --- .../inputmethod/latin/InputPointers.java | 47 +++++++------- .../inputmethod/latin/InputPointersTests.java | 65 ++++++++++--------- 2 files changed, 59 insertions(+), 53 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/InputPointers.java b/java/src/com/android/inputmethod/latin/InputPointers.java index cd53bcd13..5ad53480f 100644 --- a/java/src/com/android/inputmethod/latin/InputPointers.java +++ b/java/src/com/android/inputmethod/latin/InputPointers.java @@ -16,6 +16,9 @@ package com.android.inputmethod.latin; +import java.util.Arrays; + +// TODO: This class is not thread-safe. public class InputPointers { private final ScalableIntArray mXCoordinates = new ScalableIntArray(); private final ScalableIntArray mYCoordinates = new ScalableIntArray(); @@ -52,21 +55,15 @@ public class InputPointers { /** * Append the pointers in the specified {@link InputPointers} to the end of this. - * @param src the source {@link InputPointers} to append the pointers. + * @param src the source {@link InputPointers} to read the data from. * @param startPos the starting index of the pointers in {@code src}. * @param length the number of pointers to be appended. */ public void append(InputPointers src, int startPos, int length) { - final int currentLength = getPointerSize(); - final int newLength = currentLength + length; - mXCoordinates.ensureCapacity(newLength); - mYCoordinates.ensureCapacity(newLength); - mPointerIds.ensureCapacity(newLength); - mTimes.ensureCapacity(newLength); - System.arraycopy(src.getXCoordinates(), startPos, getXCoordinates(), currentLength, length); - System.arraycopy(src.getYCoordinates(), startPos, getYCoordinates(), currentLength, length); - System.arraycopy(src.getPointerIds(), startPos, getPointerIds(), currentLength, length); - System.arraycopy(src.getTimes(), startPos, getTimes(), currentLength, length); + mXCoordinates.append(src.mXCoordinates, startPos, length); + mYCoordinates.append(src.mYCoordinates, startPos, length); + mPointerIds.append(src.mPointerIds, startPos, length); + mTimes.append(src.mTimes, startPos, length); } public void reset() { @@ -121,19 +118,17 @@ public class InputPointers { mLength = nextLength; } - public void ensureCapacity(int minimumCapacity) { + private void ensureCapacity(int minimumCapacity) { if (mArray.length < minimumCapacity) { final int nextCapacity = mArray.length * 2; - grow(minimumCapacity > nextCapacity ? minimumCapacity : nextCapacity); + // The following is the same as newLength = Math.max(minimumCapacity, nextCapacity); + final int newLength = minimumCapacity > nextCapacity + ? minimumCapacity + : nextCapacity; + mArray = Arrays.copyOf(mArray, newLength); } } - private void grow(int newCapacity) { - final int[] newArray = new int[newCapacity]; - System.arraycopy(mArray, 0, newArray, 0, mArray.length); - mArray = newArray; - } - public int getLength() { return mLength; } @@ -147,15 +142,23 @@ public class InputPointers { return mArray; } + public void set(ScalableIntArray ip) { + mArray = ip.mArray; + mLength = ip.mLength; + } + public void copy(ScalableIntArray ip) { ensureCapacity(ip.mLength); System.arraycopy(ip.mArray, 0, mArray, 0, ip.mLength); mLength = ip.mLength; } - public void set(ScalableIntArray ip) { - mArray = ip.mArray; - mLength = ip.mLength; + public void append(ScalableIntArray src, int startPos, int length) { + final int currentLength = mLength; + final int newLength = currentLength + length; + ensureCapacity(newLength); + System.arraycopy(src.mArray, startPos, mArray, currentLength, length); + mLength = newLength; } } } diff --git a/tests/src/com/android/inputmethod/latin/InputPointersTests.java b/tests/src/com/android/inputmethod/latin/InputPointersTests.java index b60c2df58..524921e25 100644 --- a/tests/src/com/android/inputmethod/latin/InputPointersTests.java +++ b/tests/src/com/android/inputmethod/latin/InputPointersTests.java @@ -114,47 +114,50 @@ public class InputPointersTests extends AndroidTestCase { public void testAppend() { final InputPointers src = new InputPointers(); - final int limit = 100; - for (int i = 0; i < limit; i++) { + final int srcLen = 100; + for (int i = 0; i < srcLen; i++) { src.addPointer(i, i * 2, i * 3, i * 4); } + final int dstLen = 50; final InputPointers dst = new InputPointers(); - for (int i = 0; i < limit; i++) { - final int value = limit - i; + for (int i = 0; i < dstLen; i++) { + final int value = -i - 1; dst.addPointer(value * 4, value * 3, value * 2, value); } final InputPointers dstCopy = new InputPointers(); dstCopy.copy(dst); dst.append(src, 0, 0); - assertEquals("after append zero size", limit, dst.getPointerSize()); - assertArrayEquals("affer append zero xCoordinates", dstCopy.getXCoordinates(), 0, - dst.getXCoordinates(), 0, limit); - assertArrayEquals("affer append zero yCoordinates", dstCopy.getYCoordinates(), 0, - dst.getYCoordinates(), 0, limit); - assertArrayEquals("affer append zero pointerIds", dstCopy.getPointerIds(), 0, - dst.getPointerIds(), 0, limit); - assertArrayEquals("affer append zero times", dstCopy.getTimes(), 0, - dst.getTimes(), 0, limit); + assertEquals("after append zero size", dstLen, dst.getPointerSize()); + assertArrayEquals("after append zero xCoordinates", dstCopy.getXCoordinates(), 0, + dst.getXCoordinates(), 0, dstLen); + assertArrayEquals("after append zero yCoordinates", dstCopy.getYCoordinates(), 0, + dst.getYCoordinates(), 0, dstLen); + assertArrayEquals("after append zero pointerIds", dstCopy.getPointerIds(), 0, + dst.getPointerIds(), 0, dstLen); + assertArrayEquals("after append zero times", dstCopy.getTimes(), 0, + dst.getTimes(), 0, dstLen); - dst.append(src, 0, src.getPointerSize()); - assertEquals("after append size", limit * 2, dst.getPointerSize() + src.getPointerSize()); - assertArrayEquals("affer append xCoordinates", dstCopy.getXCoordinates(), 0, - dst.getXCoordinates(), 0, limit); - assertArrayEquals("affer append yCoordinates", dstCopy.getYCoordinates(), 0, - dst.getYCoordinates(), 0, limit); - assertArrayEquals("affer append pointerIds", dstCopy.getPointerIds(), 0, - dst.getPointerIds(), 0, limit); - assertArrayEquals("affer append times", dstCopy.getTimes(), 0, - dst.getTimes(), 0, limit); - assertArrayEquals("after append xCoordinates", dst.getXCoordinates(), limit, - src.getXCoordinates(), 0, limit); - assertArrayEquals("after append yCoordinates", dst.getYCoordinates(), limit, - src.getYCoordinates(), 0, limit); - assertArrayEquals("after append pointerIds", dst.getPointerIds(), limit, - src.getPointerIds(), 0, limit); - assertArrayEquals("after append times", dst.getTimes(), limit, - src.getTimes(), 0, limit); + dst.append(src, 0, srcLen); + assertEquals("after append size", dstLen + srcLen, dst.getPointerSize()); + assertTrue("after append size primitive length", + dst.getPointerIds().length >= dstLen + srcLen); + assertArrayEquals("after append xCoordinates", dstCopy.getXCoordinates(), 0, + dst.getXCoordinates(), 0, dstLen); + assertArrayEquals("after append yCoordinates", dstCopy.getYCoordinates(), 0, + dst.getYCoordinates(), 0, dstLen); + assertArrayEquals("after append pointerIds", dstCopy.getPointerIds(), 0, + dst.getPointerIds(), 0, dstLen); + assertArrayEquals("after append times", dstCopy.getTimes(), 0, + dst.getTimes(), 0, dstLen); + assertArrayEquals("after append xCoordinates", dst.getXCoordinates(), dstLen, + src.getXCoordinates(), 0, srcLen); + assertArrayEquals("after append yCoordinates", dst.getYCoordinates(), dstLen, + src.getYCoordinates(), 0, srcLen); + assertArrayEquals("after append pointerIds", dst.getPointerIds(), dstLen, + src.getPointerIds(), 0, srcLen); + assertArrayEquals("after append times", dst.getTimes(), dstLen, + src.getTimes(), 0, srcLen); } private static void assertArrayEquals(String message, int[] expecteds, int expectedPos, From e9808694fecbf7be776cd5cf8ec0333e158286b1 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 13 Jul 2012 13:31:27 +0900 Subject: [PATCH 68/68] Fix a bug where the word composer is not correctly reset ...upon commit Change-Id: I1fea87cb4c133a0884329eb9b61bf3053c36cd1b --- java/src/com/android/inputmethod/latin/WordComposer.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 46c892afe..25e29008e 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -305,8 +305,11 @@ public class WordComposer { && type != LastComposedWord.COMMIT_TYPE_MANUAL_PICK) { lastComposedWord.deactivate(); } + mCapsCount = 0; + mIsBatchMode = false; mTypedWord.setLength(0); mTrailingSingleQuotesCount = 0; + mIsFirstCharCapitalized = false; refreshSize(); mAutoCorrection = null; mIsResumed = false;