aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/AndroidManifest.xml1
-rw-r--r--java/proguard.flags69
-rw-r--r--java/res/drawable-hdpi/suggestion_feedback_background.9.pngbin1607 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/suggestion_feedback_background.9.pngbin1182 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/suggestion_feedback_background.9.pngbin1676 -> 0 bytes
-rw-r--r--java/res/layout/suggestion_word.xml3
-rw-r--r--java/res/raw/main_en.dictbin1069793 -> 1069823 bytes
-rw-r--r--java/res/raw/main_es.dictbin1138874 -> 1138885 bytes
-rw-r--r--java/res/raw/main_fr.dictbin1329601 -> 1329621 bytes
-rw-r--r--java/res/raw/main_ru.dictbin2239641 -> 2223791 bytes
-rw-r--r--java/res/values-af/strings.xml5
-rw-r--r--java/res/values-am/strings.xml5
-rw-r--r--java/res/values-ar/strings.xml5
-rw-r--r--java/res/values-be/strings.xml5
-rw-r--r--java/res/values-bg/strings.xml5
-rw-r--r--java/res/values-ca/strings.xml5
-rw-r--r--java/res/values-cs/strings.xml5
-rw-r--r--java/res/values-da/strings.xml5
-rw-r--r--java/res/values-de/strings.xml9
-rw-r--r--java/res/values-el/strings.xml5
-rw-r--r--java/res/values-en-rGB/strings.xml7
-rw-r--r--java/res/values-es-rUS/strings.xml5
-rw-r--r--java/res/values-es/strings.xml5
-rw-r--r--java/res/values-et/strings.xml5
-rw-r--r--java/res/values-fa/strings.xml5
-rw-r--r--java/res/values-fi/strings.xml5
-rw-r--r--java/res/values-fr/strings.xml5
-rw-r--r--java/res/values-hi/strings.xml5
-rw-r--r--java/res/values-hr/strings.xml5
-rw-r--r--java/res/values-hu/strings.xml5
-rw-r--r--java/res/values-in/strings.xml5
-rw-r--r--java/res/values-is/strings.xml9
-rw-r--r--java/res/values-it/strings.xml5
-rw-r--r--java/res/values-iw/strings.xml5
-rw-r--r--java/res/values-ja/strings.xml5
-rw-r--r--java/res/values-ka/strings.xml9
-rw-r--r--java/res/values-ko/strings.xml5
-rw-r--r--java/res/values-lt/strings.xml5
-rw-r--r--java/res/values-lv/strings.xml5
-rw-r--r--java/res/values-mk/strings.xml9
-rw-r--r--java/res/values-mn/strings.xml268
-rw-r--r--java/res/values-ms/strings.xml5
-rw-r--r--java/res/values-nb/strings.xml5
-rw-r--r--java/res/values-nl/strings.xml5
-rw-r--r--java/res/values-pl/strings.xml5
-rw-r--r--java/res/values-pt-rPT/strings.xml5
-rw-r--r--java/res/values-pt/strings.xml5
-rw-r--r--java/res/values-rm/strings.xml10
-rw-r--r--java/res/values-ro/strings.xml5
-rw-r--r--java/res/values-ru/strings.xml11
-rw-r--r--java/res/values-sk/strings.xml9
-rw-r--r--java/res/values-sl/strings.xml5
-rw-r--r--java/res/values-sr/strings.xml5
-rw-r--r--java/res/values-sv/strings.xml5
-rw-r--r--java/res/values-sw/strings.xml5
-rw-r--r--java/res/values-sw600dp/config.xml2
-rw-r--r--java/res/values-sw768dp/config.xml2
-rw-r--r--java/res/values-th/strings.xml5
-rw-r--r--java/res/values-tl/strings.xml5
-rw-r--r--java/res/values-tr/strings.xml5
-rw-r--r--java/res/values-uk/strings.xml7
-rw-r--r--java/res/values-vi/strings.xml5
-rw-r--r--java/res/values-zh-rCN/strings.xml5
-rw-r--r--java/res/values-zh-rTW/strings.xml5
-rw-r--r--java/res/values-zu/strings.xml5
-rw-r--r--java/res/values/attrs.xml3
-rw-r--r--java/res/values/colors.xml53
-rw-r--r--java/res/values/config.xml5
-rw-r--r--java/res/values/donottranslate.xml2
-rw-r--r--java/res/values/strings.xml12
-rw-r--r--java/res/values/styles.xml106
-rw-r--r--java/res/values/themes-basic-highcontrast.xml1
-rw-r--r--java/res/values/themes-basic.xml1
-rw-r--r--java/res/values/themes-gingerbread.xml1
-rw-r--r--java/res/values/themes-ics.xml1
-rw-r--r--java/res/values/themes-stone-bold.xml1
-rw-r--r--java/res/values/themes-stone.xml1
-rw-r--r--java/res/xml-sw600dp/key_styles_common.xml19
-rw-r--r--java/res/xml-sw600dp/rowkeys_pcqwerty1.xml4
-rw-r--r--java/res/xml-sw600dp/rowkeys_symbols2.xml6
-rw-r--r--java/res/xml-sw600dp/rows_mongolian.xml58
-rw-r--r--java/res/xml-sw600dp/rows_number_normal.xml2
-rw-r--r--java/res/xml-sw600dp/rows_phone.xml2
-rw-r--r--java/res/xml-sw768dp/key_styles_common.xml21
-rw-r--r--java/res/xml-sw768dp/rows_mongolian.xml69
-rw-r--r--java/res/xml-sw768dp/rows_number_normal.xml2
-rw-r--r--java/res/xml-sw768dp/rows_phone.xml2
-rw-r--r--java/res/xml/kbd_mongolian.xml (renamed from java/res/layout/suggestion_preview.xml)18
-rw-r--r--java/res/xml/key_styles_common.xml36
-rw-r--r--java/res/xml/key_styles_currency.xml95
-rw-r--r--java/res/xml/key_styles_currency_euro.xml5
-rw-r--r--java/res/xml/keyboard_layout_set_mongolian.xml42
-rw-r--r--java/res/xml/keys_pcqwerty_symbols1.xml2
-rw-r--r--java/res/xml/method.xml128
-rw-r--r--java/res/xml/prefs.xml6
-rw-r--r--java/res/xml/rowkeys_mongolian1.xml83
-rw-r--r--java/res/xml/rowkeys_mongolian2.xml57
-rw-r--r--java/res/xml/rowkeys_mongolian3.xml57
-rw-r--r--java/res/xml/rowkeys_pcqwerty1.xml2
-rw-r--r--java/res/xml/rowkeys_symbols2.xml6
-rw-r--r--java/res/xml/rows_mongolian.xml52
-rw-r--r--java/res/xml/rows_number_normal.xml2
-rw-r--r--java/res/xml/rows_phone.xml2
-rw-r--r--java/res/xml/rows_phone_symbols.xml4
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java6
-rw-r--r--java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java33
-rw-r--r--java/src/com/android/inputmethod/annotations/ExternallyReferenced.java24
-rw-r--r--java/src/com/android/inputmethod/annotations/UsedForTesting.java24
-rw-r--r--java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java48
-rw-r--r--java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java23
-rw-r--r--java/src/com/android/inputmethod/keyboard/Key.java11
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyDetector.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java73
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java20
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardId.java70
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java30
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java31
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java65
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java337
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java3
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java239
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java86
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java591
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityInfo.java128
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java127
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java36
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java10
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java13
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java15
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java32
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java35
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java682
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java10
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java10
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java69
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/RoundedLine.java103
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/TouchPositionCorrection.java3
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/TouchScreenRegulator.java (renamed from java/src/com/android/inputmethod/keyboard/internal/SuddenJumpingTouchEventHandler.java)20
-rw-r--r--java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java24
-rw-r--r--java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java29
-rw-r--r--java/src/com/android/inputmethod/latin/AutoCorrection.java23
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java75
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java8
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java17
-rw-r--r--java/src/com/android/inputmethod/latin/Constants.java72
-rw-r--r--java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java19
-rw-r--r--java/src/com/android/inputmethod/latin/CoordinateUtils.java49
-rw-r--r--java/src/com/android/inputmethod/latin/DebugSettings.java18
-rw-r--r--java/src/com/android/inputmethod/latin/Dictionary.java15
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryCollection.java6
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java14
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableDictionary.java81
-rw-r--r--java/src/com/android/inputmethod/latin/ImfUtils.java186
-rw-r--r--java/src/com/android/inputmethod/latin/InputAttributes.java80
-rw-r--r--java/src/com/android/inputmethod/latin/InputPointers.java8
-rw-r--r--java/src/com/android/inputmethod/latin/LastComposedWord.java4
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java348
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java45
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputMethodManager.java248
-rw-r--r--java/src/com/android/inputmethod/latin/Settings.java5
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsValues.java19
-rw-r--r--java/src/com/android/inputmethod/latin/StringUtils.java119
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeLocale.java25
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeSwitcher.java43
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java46
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestedWords.java29
-rw-r--r--java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java4
-rw-r--r--java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java4
-rw-r--r--java/src/com/android/inputmethod/latin/UserBinaryDictionary.java2
-rw-r--r--java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java9
-rw-r--r--java/src/com/android/inputmethod/latin/UserHistoryDictionary.java32
-rw-r--r--java/src/com/android/inputmethod/latin/Utils.java15
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java25
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java728
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java207
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/FormatSpec.java18
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java74
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java28
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java43
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java4
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java3
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java11
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java186
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java252
-rw-r--r--java/src/com/android/inputmethod/research/LogUnit.java67
-rw-r--r--java/src/com/android/inputmethod/research/MainLogBuffer.java13
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLog.java4
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java117
-rw-r--r--java/src/com/android/inputmethod/research/Statistics.java12
190 files changed, 5116 insertions, 3021 deletions
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index 8ffa29d71..5f64768d4 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -27,7 +27,6 @@
<application android:label="@string/aosp_android_keyboard_ime_name"
android:icon="@mipmap/ic_ime_settings"
- android:backupAgent="BackupAgent"
android:killAfterRestore="false"
android:supportsRtl="true">
diff --git a/java/proguard.flags b/java/proguard.flags
index ac5b7df16..d65924f7c 100644
--- a/java/proguard.flags
+++ b/java/proguard.flags
@@ -1,64 +1,11 @@
--keep class com.android.inputmethod.latin.BinaryDictionary {
- int mDictLength;
- <init>(...);
+# Keep classes and methods that have the @UsedForTesting annotation
+-keep @com.android.inputmethod.annotations.UsedForTesting class *
+-keepclassmembers class * {
+@com.android.inputmethod.annotations.UsedForTesting *;
}
--keep class com.android.inputmethod.keyboard.ProximityInfo {
- <init>(com.android.inputmethod.keyboard.ProximityInfo);
+# Keep classes and methods that have the @ExternallyReferenced annotation
+-keep @com.android.inputmethod.annotations.ExternallyReferenced class *
+-keepclassmembers class * {
+@com.android.inputmethod.annotations.ExternallyReferenced *;
}
-
--keep class com.android.inputmethod.latin.Suggest {
- <init>(...);
- com.android.inputmethod.latin.SuggestedWords getSuggestions(...);
-}
-
--keep class com.android.inputmethod.latin.AutoCorrection {
- java.lang.CharSequence getAutoCorrectionWord();
-}
-
--keep class com.android.inputmethod.latin.Utils {
- boolean equalsIgnoreCase(...);
-}
-
--keep class com.android.inputmethod.latin.InputPointers {
- *;
-}
-
--keep class com.android.inputmethod.latin.ResizableIntArray {
- *;
-}
-
--keep class com.android.inputmethod.latin.spellcheck.SpellCheckerSettingsFragment {
- *;
-}
-
--keep class com.android.inputmethod.keyboard.MainKeyboardView {
- # Keep getter/setter methods for ObjectAnimator
- int getLanguageOnSpacebarAnimAlpha();
- void setLanguageOnSpacebarAnimAlpha(int);
- int getAltCodeKeyWhileTypingAnimAlpha();
- void setAltCodeKeyWhileTypingAnimAlpha(int);
-}
-
--keep class com.android.inputmethod.keyboard.MoreKeysKeyboard$Builder$MoreKeysKeyboardParams {
- <init>(...);
-}
-
--keepclasseswithmembernames class * {
- native <methods>;
-}
-
--keep class com.android.inputmethod.research.ResearchLogger {
- void flush();
- void publishCurrentLogUnit(...);
-}
-
--keep class com.android.inputmethod.keyboard.KeyboardLayoutSet$Builder {
- void setTouchPositionCorrectionEnabled(...);
-}
-
-# The support library contains references to newer platform versions.
-# Don't warn about those in case this app is linking against an older
-# platform version. We know about them, and they are safe.
--dontwarn android.support.v4.**
--dontwarn android.support.v13.**
diff --git a/java/res/drawable-hdpi/suggestion_feedback_background.9.png b/java/res/drawable-hdpi/suggestion_feedback_background.9.png
deleted file mode 100644
index 16499002e..000000000
--- a/java/res/drawable-hdpi/suggestion_feedback_background.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/suggestion_feedback_background.9.png b/java/res/drawable-mdpi/suggestion_feedback_background.9.png
deleted file mode 100644
index 2a80f096d..000000000
--- a/java/res/drawable-mdpi/suggestion_feedback_background.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/suggestion_feedback_background.9.png b/java/res/drawable-xhdpi/suggestion_feedback_background.9.png
deleted file mode 100644
index 0ec90e5ea..000000000
--- a/java/res/drawable-xhdpi/suggestion_feedback_background.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/layout/suggestion_word.xml b/java/res/layout/suggestion_word.xml
index d64cacf04..fa00e041e 100644
--- a/java/res/layout/suggestion_word.xml
+++ b/java/res/layout/suggestion_word.xml
@@ -18,6 +18,8 @@
*/
-->
+<!-- Provide a haptic feedback by ourselves based on the keyboard settings.
+ We just need to ignore the system's haptic feedback settings. -->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
@@ -29,6 +31,7 @@
android:paddingTop="0dp"
android:paddingRight="@dimen/suggestion_padding"
android:paddingBottom="0dp"
+ android:hapticFeedbackEnabled="false"
android:focusable="false"
android:clickable="false"
android:singleLine="true"
diff --git a/java/res/raw/main_en.dict b/java/res/raw/main_en.dict
index 85ee809de..14dda8d83 100644
--- a/java/res/raw/main_en.dict
+++ b/java/res/raw/main_en.dict
Binary files differ
diff --git a/java/res/raw/main_es.dict b/java/res/raw/main_es.dict
index cb17926e0..c010da343 100644
--- a/java/res/raw/main_es.dict
+++ b/java/res/raw/main_es.dict
Binary files differ
diff --git a/java/res/raw/main_fr.dict b/java/res/raw/main_fr.dict
index 53fd8d139..ce4e199b4 100644
--- a/java/res/raw/main_fr.dict
+++ b/java/res/raw/main_fr.dict
Binary files differ
diff --git a/java/res/raw/main_ru.dict b/java/res/raw/main_ru.dict
index 1cddb05ab..8a1d215a3 100644
--- a/java/res/raw/main_ru.dict
+++ b/java/res/raw/main_ru.dict
Binary files differ
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml
index a2de92ed6..18e63f317 100644
--- a/java/res/values-af/strings.xml
+++ b/java/res/values-af/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Verstek"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Stel kontakname voor"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Gebruik name van kontakte vir voorstelle en korreksies"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Dubbelspasie-punt"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dubbeltik op spasiebalk voeg \'n punt in, gevolg deur \'n spasie"</string>
<string name="auto_cap" msgid="1719746674854628252">"Outohoofletters"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Die eerste woord van elke sin moet met \'n hoofletter begin"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Voeg woordeboeke by"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Vorige"</string>
<string name="label_done_key" msgid="2441578748772529288">"Klaar"</string>
<string name="label_send_key" msgid="2815056534433717444">"Stuur"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Laat wag"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Wag"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Koppel \'n kopstuk om te hoor hoe wagwoordsleutels hardop gesê word."</string>
diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml
index df75c10b8..4f66a1676 100644
--- a/java/res/values-am/strings.xml
+++ b/java/res/values-am/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ነባሪ"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"የዕውቂያ ስም ጠቁም"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"ከዕውቂያዎች ለጥቆማዎች እና ማስተካከያዎች ስሞች ተጠቀም"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"የድርብ-ክፍተት ነጥብ"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"የክፍተት አሞሌው ላይ ሁለቴ መታ ማድረግ አንድ ነጥብ እና ክፍተት አስከትሎ ያስገባል"</string>
<string name="auto_cap" msgid="1719746674854628252">"ራስ-ሰር አቢይ ማድረግ"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"የእያንዳንዱ ዓረፍተ ነገር የመጀመሪያ ቃል በአቢይ ሆሄ ያስቀምጡ"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"መዝገበ ቃላቶች ጨምር"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"ቀዳሚ"</string>
<string name="label_done_key" msgid="2441578748772529288">"ተከናውኗል"</string>
<string name="label_send_key" msgid="2815056534433717444">" ይላኩ"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"ላፍታ አቁም"</string>
<string name="label_wait_key" msgid="6402152600878093134">"ቆይ"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"የይለፍቃል ቁልፎች ጮክ በለው ሲነገሩ ለመስማት የጆሮ ማዳመጫ ሰካ::"</string>
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
index 14a6a0751..a3877ed49 100644
--- a/java/res/values-ar/strings.xml
+++ b/java/res/values-ar/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"افتراضي"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"اقتراح أسماء جهات الاتصال"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"استخدام الأسماء من جهات الاتصال للاقتراحات والتصحيحات"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"نقطة المسافة المزدوجة"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"يؤدي النقر نقرًا مزدوجًا على مفتاح المسافة إلى إدخال نقطة متبوعة بمسافة"</string>
<string name="auto_cap" msgid="1719746674854628252">"أحرف كبيرة تلقائيًا"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"كتابة الحرف الأول من كل جملة بحرف كبير."</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"القواميس الإضافية"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"السابق"</string>
<string name="label_done_key" msgid="2441578748772529288">"تم"</string>
<string name="label_send_key" msgid="2815056534433717444">"إرسال"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"أ ب ج"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"٣٢١؟"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"٣٢١"</string>
<string name="label_pause_key" msgid="181098308428035340">"توقف مؤقت"</string>
<string name="label_wait_key" msgid="6402152600878093134">"انتظار"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"يمكنك توصيل سماعة رأس لسماع مفاتيح كلمة المرور منطوقة بصوت عالٍ."</string>
diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml
index f43840832..bf396943f 100644
--- a/java/res/values-be/strings.xml
+++ b/java/res/values-be/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Па змаўчанні"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Прапан. імёны кантактаў"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Выкарыстоўваць імёны са спісу кантактаў для прапаноў і выпраўл."</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Падвойны iнтэрвал"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Падвойнае нацiсканне на прабел ўстаўляе iнтэрвал з наступным прабелам"</string>
<string name="auto_cap" msgid="1719746674854628252">"Аўтаматычна рабіць вялікія літары"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Пісаць з загалоўнай літары першае слова ў кожным сказе"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Дадатковыя слоўнікі"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Назад"</string>
<string name="label_done_key" msgid="2441578748772529288">"Гатова"</string>
<string name="label_send_key" msgid="2815056534433717444">"Адправіць"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"АБВ"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Паўза"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Чакае"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Каб праслухаць паролi, падключыце гарнiтуру."</string>
diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml
index 8d9c36e02..27d3ac7d5 100644
--- a/java/res/values-bg/strings.xml
+++ b/java/res/values-bg/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"По подразбиране"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Предложения за контакти"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Използване на имена от „Контакти“ за предложения и поправки"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Точка чрез двоен интервал"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Двукр. докосване на клав. за интервал вмъква точка, следвана от интервал"</string>
<string name="auto_cap" msgid="1719746674854628252">"Автоматично поставяне на главни букви"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Правене на първата дума от всяко изречение главна"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Добавени речници"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Пред."</string>
<string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
<string name="label_send_key" msgid="2815056534433717444">"Изпращане"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"АБВ"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Пауза"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Чака"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Включете слушалки, за да чуете клавишите за паролата на висок глас."</string>
diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml
index ba6589268..0182dd492 100644
--- a/java/res/values-ca/strings.xml
+++ b/java/res/values-ca/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predeterminat"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Suggereix noms de contactes"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilitza els noms de contactes per fer suggeriments i correccions"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Punt amb doble espai"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Picar dues vegades la barra d\'espai insereix punt i espai blanc"</string>
<string name="auto_cap" msgid="1719746674854628252">"Majúscules automàtiques"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Posa en majúscula la primera paraula de cada frase"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Diccionaris complementaris"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Ant."</string>
<string name="label_done_key" msgid="2441578748772529288">"Fet"</string>
<string name="label_send_key" msgid="2815056534433717444">"Envia"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Espera"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Connecta un auricular per escoltar les claus de la contrasenya en veu alta."</string>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
index 1cd59f52a..806ac1291 100644
--- a/java/res/values-cs/strings.xml
+++ b/java/res/values-cs/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Výchozí"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Navrhovat jména kontaktů"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Použít jména ze seznamu kontaktů k návrhům a opravám"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Tečka dvojitým mezerníkem"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dvojím klepnutím na mezerník vložíte tečku následovanou mezerou."</string>
<string name="auto_cap" msgid="1719746674854628252">"Velká písmena automaticky"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Kapitalizace prvního slova každé věty"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Doplňkové slovníky"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Před."</string>
<string name="label_done_key" msgid="2441578748772529288">"Hotovo"</string>
<string name="label_send_key" msgid="2815056534433717444">"Odeslat"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pauza"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Čekat"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Chcete-li slyšet, které klávesy jste při zadávání hesla stiskli, připojte sluchátka."</string>
diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml
index 7e4e0fa00..4fbfe905d 100644
--- a/java/res/values-da/strings.xml
+++ b/java/res/values-da/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Foreslå navne på kontakter"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Brug navne fra Kontaktpersoner til forslag og rettelser"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"To mellemrum for punktum"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"To tryk på mellemrumstasten indsætter et punktum og et mellemrum"</string>
<string name="auto_cap" msgid="1719746674854628252">"Skriv aut. med stort"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Skriv det første ord i hver sætning med stort"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Tillægsordbøger"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Forr."</string>
<string name="label_done_key" msgid="2441578748772529288">"Udfør"</string>
<string name="label_send_key" msgid="2815056534433717444">"Send"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Vent"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Tilslut et headset for at høre indtastningen blive læst højt ved angivelse af adgangskode."</string>
diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml
index 897bfb712..1fad9e710 100644
--- a/java/res/values-de/strings.xml
+++ b/java/res/values-de/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Kontakte vorschlagen"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Namen aus \"Kontakte\" als Vorschläge und Korrekturmöglichkeiten anzeigen"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Punkt plus Leerzeichen"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Für Punkt plus Leerzeichen zweimal auf die Leertaste tippen"</string>
<string name="auto_cap" msgid="1719746674854628252">"Autom. Groß-/Kleinschreibung"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Das erste Wort jedes Satzes großschreiben"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Erweiterte Wörterbücher"</string>
@@ -69,12 +71,9 @@
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: gespeichert"</string>
<string name="label_go_key" msgid="1635148082137219148">"Los"</string>
<string name="label_next_key" msgid="362972844525672568">"Weiter"</string>
- <string name="label_previous_key" msgid="1211868118071386787">"Vorh."</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"Zurück"</string>
<string name="label_done_key" msgid="2441578748772529288">"Fertig"</string>
<string name="label_send_key" msgid="2815056534433717444">"Senden"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Warten"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Schließen Sie ein Headset an, um das Passwort gesprochen zu hören."</string>
@@ -121,7 +120,7 @@
<string name="prefs_enable_log" msgid="6620424505072963557">"Nutzer-Feedback aktivieren"</string>
<string name="prefs_description_log" msgid="5827825607258246003">"Tragen Sie zur Verbesserung dieses Eingabemethodeneditors bei, indem Sie automatisch Nutzungsstatistiken und Absturzberichte an Google senden."</string>
<string name="keyboard_layout" msgid="8451164783510487501">"Tastaturdesign"</string>
- <string name="subtype_en_GB" msgid="88170601942311355">"Englisch (Großbritannien)"</string>
+ <string name="subtype_en_GB" msgid="88170601942311355">"Englisch (UK)"</string>
<string name="subtype_en_US" msgid="6160452336634534239">"Englisch (USA)"</string>
<string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Englisch (GB) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
<string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Englisch (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
index 2ce68b5d7..2b99e7e00 100644
--- a/java/res/values-el/strings.xml
+++ b/java/res/values-el/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Προεπιλογή"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Πρόταση ονομάτων επαφών"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Χρησιμοποιήστε ονόματα από τις Επαφές για προτάσεις και διορθ."</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Τελεία με διπλό πάτημα πλήκτρ.διαστ."</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Το διπλό πάτημα του πλήκτρ.διαστ. εισάγει μια τελεία και ένα κενό"</string>
<string name="auto_cap" msgid="1719746674854628252">"Αυτόματη χρήση κεφαλαίων"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Χρήση κεφαλαίου στην πρώτη λέξη κάθε πρότασης"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Πρόσθετα λεξικά"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Προηγ"</string>
<string name="label_done_key" msgid="2441578748772529288">"Τέλος"</string>
<string name="label_send_key" msgid="2815056534433717444">"Αποστολή"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ΑΒΓ"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Παύση"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Αναμ."</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Συνδέστε ένα σετ ακουστικών για να ακούσετε τα πλήκτρα του κωδικού πρόσβασης να εκφωνούνται δυνατά."</string>
diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml
index f9af2a739..652d5aa46 100644
--- a/java/res/values-en-rGB/strings.xml
+++ b/java/res/values-en-rGB/strings.xml
@@ -44,6 +44,10 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Default"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Suggest Contact names"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Use names from Contacts for suggestions and corrections"</string>
+ <!-- no translation found for use_double_space_period (8781529969425082860) -->
+ <skip />
+ <!-- no translation found for use_double_space_period_summary (6532892187247952799) -->
+ <skip />
<string name="auto_cap" msgid="1719746674854628252">"Auto-capitalisation"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Capitalise the first word of each sentence"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Add-on dictionaries"</string>
@@ -72,9 +76,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Prev"</string>
<string name="label_done_key" msgid="2441578748772529288">"Done"</string>
<string name="label_send_key" msgid="2815056534433717444">"Send"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Wait"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Plug in a headset to hear password keys spoken aloud."</string>
diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml
index bc9b0c30a..9e87970de 100644
--- a/java/res/values-es-rUS/strings.xml
+++ b/java/res/values-es-rUS/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predeterminada"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nombres de contacto"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Usar nombres de los contactos para sugerencias y correcciones"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Punto y doble espacio"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Tocar dos veces la barra espaciadora inserta un punto y espacio."</string>
<string name="auto_cap" msgid="1719746674854628252">"Mayúsculas automáticas"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Escribe con mayúscula la primera palabra de cada frase"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Diccionarios complementarios"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Ant."</string>
<string name="label_done_key" msgid="2441578748772529288">"Listo"</string>
<string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Espera"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Enchufa tus auriculares para escuchar en voz alta qué teclas presionas al ingresar una contraseña."</string>
diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml
index d5196a597..24335e65a 100644
--- a/java/res/values-es/strings.xml
+++ b/java/res/values-es/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predeterminado"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir contactos"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizar nombres de contactos para sugerencias y correcciones"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Punto y espacio"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Si tocas dos veces el espacio, se inserta un punto seguido de un espacio."</string>
<string name="auto_cap" msgid="1719746674854628252">"Mayúsculas automáticas"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Poner la primera letra de cada palabra en mayúscula"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Diccionarios complementarios"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Anterior"</string>
<string name="label_done_key" msgid="2441578748772529288">"Ok"</string>
<string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Espera"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Conecta un auricular para escuchar las contraseñas en voz alta."</string>
diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml
index 4aa31ef2b..25dcdca73 100644
--- a/java/res/values-et/strings.xml
+++ b/java/res/values-et/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Vaikeseade"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Soovita kontaktkirjeid"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Kasuta soovitusteks ja parandusteks nimesid kontaktiloendist"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Punkt tühikuklahviga"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Tühikuklahvi kaks korda puudutades sisestatakse punkt ja tühik"</string>
<string name="auto_cap" msgid="1719746674854628252">"Automaatne suurtähtede kasutamine"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Iga lause esimese sõna kirjutamine suure algustähega"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Pistiksõnaraamatud"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Eelm."</string>
<string name="label_done_key" msgid="2441578748772529288">"Valmis"</string>
<string name="label_send_key" msgid="2815056534433717444">"Saada"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Peata"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Oota"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Ühendage peakomplekt, et kuulata paroole."</string>
diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml
index dacfd1efe..d4a0e66b0 100644
--- a/java/res/values-fa/strings.xml
+++ b/java/res/values-fa/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"پیش‌فرض"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"پیشنهاد نام‌های مخاطب"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"برای پیشنهاد و تصحیح از نام مخاطبین استفاده شود"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"نقطه با دو فاصله"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"با دوبار ضربه روی دکمه فاصله نقطه با یک فاصله بعد آن درج می‌شود"</string>
<string name="auto_cap" msgid="1719746674854628252">"بزرگ‌کردن خودکار حروف"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"بزرگ‌نویسی کلمه اول هر جمله"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"فرهنگ‌های لغت افزودنی"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"قبلی"</string>
<string name="label_done_key" msgid="2441578748772529288">"انجام شد"</string>
<string name="label_send_key" msgid="2815056534433717444">"ارسال"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"اب‌پ"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"۳۲۱؟"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"۳۲۱"</string>
<string name="label_pause_key" msgid="181098308428035340">"توقف موقت"</string>
<string name="label_wait_key" msgid="6402152600878093134">"منتظر بمانید"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"برای شنیدن کلیدهای گذرواژه که با صدای بلند خوانده می‌شوند، از هدست استفاده کنید."</string>
diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml
index 61763bf0e..36890d95a 100644
--- a/java/res/values-fi/strings.xml
+++ b/java/res/values-fi/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Oletus"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Ehdota yhteystietojen nimiä"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Käytä yhteystietojen nimiä ehdotuksissa ja korjauksissa"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Kaksoisvälilyönti = piste"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Välilyönnin kaksoisnapautus lisää tekstiin pisteen ja välilyönnin"</string>
<string name="auto_cap" msgid="1719746674854628252">"Automaattiset isot kirjaimet"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Kirjoita jokaisen lauseen ensimmäinen sana isolla alkukirjaimella"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Lisäsanakirjat"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Edell"</string>
<string name="label_done_key" msgid="2441578748772529288">"Valmis"</string>
<string name="label_send_key" msgid="2815056534433717444">"Lähetä"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Tauko"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Odota"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Liitä kuulokkeet kuullaksesi, mitä näppäimiä painat kirjoittaessasi salasanaa."</string>
diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml
index 58393b041..3f895325e 100644
--- a/java/res/values-fr/strings.xml
+++ b/java/res/values-fr/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Par défaut"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Proposer noms de contacts"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utiliser des noms de contacts pour les suggestions et corrections"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Point et espace"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Appuyez deux fois sur la barre d\'espace pour insérer un point et un espace."</string>
<string name="auto_cap" msgid="1719746674854628252">"Majuscules auto"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Majuscule au premier mot de chaque phrase"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Dictionnaires complémentaires"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Préc."</string>
<string name="label_done_key" msgid="2441578748772529288">"OK"</string>
<string name="label_send_key" msgid="2815056534433717444">"Envoi"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Délai"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Branchez des écouteurs pour entendre l\'énoncé à haute voix des touches lors de la saisie du mot de passe."</string>
diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml
index 7e463f758..6537b859e 100644
--- a/java/res/values-hi/strings.xml
+++ b/java/res/values-hi/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"डिफ़ॉल्ट"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"संपर्क नाम सुझाएं"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"सुझाव और सुधार के लिए संपर्क से नामों का उपयोग करें"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"दोहरे स्पेस वाला पीरियड"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"स्पेसबार पर डबल टैप करने से पीरियड शामिल हो जाता है जिसके बाद एक रिक्ति होती है"</string>
<string name="auto_cap" msgid="1719746674854628252">"स्‍वत: अक्षर बड़े करना"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"प्रत्येक वाक्य के पहले शब्द को बड़ा लिखें"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"एड-ऑन डिक्शनरी"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"पिछला"</string>
<string name="label_done_key" msgid="2441578748772529288">"पूर्ण"</string>
<string name="label_send_key" msgid="2815056534433717444">"भेजें"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"कखग"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?१२३"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"१२३"</string>
<string name="label_pause_key" msgid="181098308428035340">"पॉज़ करें"</string>
<string name="label_wait_key" msgid="6402152600878093134">"प्रतीक्षा करें"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"ज़ोर से बोली गई पासवर्ड कुंजियां सुनने के लिए हेडसेट प्‍लग इन करें."</string>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
index bae1fc202..d788c1f0e 100644
--- a/java/res/values-hr/strings.xml
+++ b/java/res/values-hr/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Zadano"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Predlaži imena kontakata"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Upotreba imena iz Kontakata za prijedloge i ispravke"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Točka s dva razmaka"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dvostrukim dodirivanjem razmaknice umeću se točka i razmak"</string>
<string name="auto_cap" msgid="1719746674854628252">"Automatsko pisanje velikih slova"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Napiši velikim slovom prvu riječ svake rečenice"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Rječnici-dodaci"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Pret."</string>
<string name="label_done_key" msgid="2441578748772529288">"Gotovo"</string>
<string name="label_send_key" msgid="2815056534433717444">"Pošalji"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pauza"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Pričekaj"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Priključite slušalice da biste čuli tipke zaporke izgovorene naglas."</string>
diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml
index d1b715796..1df863927 100644
--- a/java/res/values-hu/strings.xml
+++ b/java/res/values-hu/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Alapbeállítás"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Javasolt névjegyek"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"A névjegyek használata a javaslatokhoz és javításokhoz"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Dupla szóköz: pont"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"A szóköz kétszeri megérintése beszúr egy pontot, majd egy szóközt"</string>
<string name="auto_cap" msgid="1719746674854628252">"Automatikusan nagy kezdőbetű"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Minden mondat első szava nagybetűvel"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Bővítmények: szótárak"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Előző"</string>
<string name="label_done_key" msgid="2441578748772529288">"Kész"</string>
<string name="label_send_key" msgid="2815056534433717444">"Küldés"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Szün."</string>
<string name="label_wait_key" msgid="6402152600878093134">"Vár"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Csatlakoztasson egy headsetet, ha hallani szeretné a jelszót felolvasva."</string>
diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml
index b8a957314..f26ad38a4 100644
--- a/java/res/values-in/strings.xml
+++ b/java/res/values-in/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Default"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Sarankan nama Kontak"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Menggunakan nama dari Kontak untuk saran dan koreksi"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Titik spasi ganda"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Mengetuk tombol spasi dua kali akan memasukkan titik diikuti satu spasi"</string>
<string name="auto_cap" msgid="1719746674854628252">"Kapitalisasi otomatis"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Kapitalisasi kata pertama di setiap kalimat"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Kamus pengaya"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Sblm"</string>
<string name="label_done_key" msgid="2441578748772529288">"Selesai"</string>
<string name="label_send_key" msgid="2815056534433717444">"Kirimkan"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Jeda"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Tunggu"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Pasang headset untuk mendengar tombol sandi yang diucapkan dengan keras."</string>
diff --git a/java/res/values-is/strings.xml b/java/res/values-is/strings.xml
index a53e727f3..8ea7461c2 100644
--- a/java/res/values-is/strings.xml
+++ b/java/res/values-is/strings.xml
@@ -68,6 +68,10 @@
<skip />
<!-- no translation found for use_contacts_dict_summary (6599983334507879959) -->
<skip />
+ <!-- no translation found for use_double_space_period (8781529969425082860) -->
+ <skip />
+ <!-- no translation found for use_double_space_period_summary (6532892187247952799) -->
+ <skip />
<!-- no translation found for auto_cap (1719746674854628252) -->
<skip />
<!-- no translation found for auto_cap_summary (7934452761022946874) -->
@@ -119,11 +123,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Fyrra"</string>
<string name="label_done_key" msgid="2441578748772529288">"Lokið"</string>
<string name="label_send_key" msgid="2815056534433717444">"Senda"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
- <skip />
- <!-- no translation found for label_to_symbol_with_microphone_key (9035925553010061906) -->
- <skip />
<!-- no translation found for label_pause_key (181098308428035340) -->
<skip />
<!-- no translation found for label_wait_key (6402152600878093134) -->
diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml
index 50941cb39..a78c5c56a 100644
--- a/java/res/values-it/strings.xml
+++ b/java/res/values-it/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predefinito"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Suggerisci nomi di contatti"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizza nomi di Contatti per suggerimenti e correzioni"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Doppio spazio per punto"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Tocca due volte barra spaziatr. per inserire punto seguito da spazio"</string>
<string name="auto_cap" msgid="1719746674854628252">"Maiuscole automatiche"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Iniziale maiuscola per la prima parola di ogni frase"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Dizionari aggiuntivi"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Indietro"</string>
<string name="label_done_key" msgid="2441578748772529288">"Fine"</string>
<string name="label_send_key" msgid="2815056534433717444">"Invia"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Attesa"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Collega gli auricolari per ascoltare la pronuncia dei tasti premuti per la password."</string>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
index 645b0c5a8..6542b9fb4 100644
--- a/java/res/values-iw/strings.xml
+++ b/java/res/values-iw/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ברירת מחדל"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"הצע שמות של אנשי קשר"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"השתמש בשמות מרשימת אנשי הקשר עבור הצעות ותיקונים"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"רווח כפול לנקודה"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"הקשה פעמיים על מקש הרווח מזינה נקודה ואחריה רווח"</string>
<string name="auto_cap" msgid="1719746674854628252">"הפיכת אותיות לרישיות באופן אוטומטי"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"השתמש באות גדולה במילה הראשונה של כל משפט"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"הוספת מילונים"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"הקודם"</string>
<string name="label_done_key" msgid="2441578748772529288">"סיום"</string>
<string name="label_send_key" msgid="2815056534433717444">"שלח"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"אבג"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"השהה"</string>
<string name="label_wait_key" msgid="6402152600878093134">"המתן"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"חבר אוזניות כדי לשמוע הקראה של מפתחות סיסמה."</string>
diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml
index d7ae04f07..2b341e116 100644
--- a/java/res/values-ja/strings.xml
+++ b/java/res/values-ja/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"デフォルト"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"候補の連絡先名を表示"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"連絡先の名前を使用して候補表示や自動修正を行います"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"ダブルスペースピリオド"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"スペースバーをダブルタップするとピリオドとスペースを挿入できます"</string>
<string name="auto_cap" msgid="1719746674854628252">"自動大文字変換"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"英字入力で各文の最初の単語を大文字にします"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"アドオン辞書"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"前へ"</string>
<string name="label_done_key" msgid="2441578748772529288">"完了"</string>
<string name="label_send_key" msgid="2815056534433717444">"送信"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"停止"</string>
<string name="label_wait_key" msgid="6402152600878093134">"待機"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"パスワードのキーが音声出力されるのでヘッドセットを接続してください。"</string>
diff --git a/java/res/values-ka/strings.xml b/java/res/values-ka/strings.xml
index cd4dfd903..ef3014401 100644
--- a/java/res/values-ka/strings.xml
+++ b/java/res/values-ka/strings.xml
@@ -68,6 +68,10 @@
<skip />
<!-- no translation found for use_contacts_dict_summary (6599983334507879959) -->
<skip />
+ <!-- no translation found for use_double_space_period (8781529969425082860) -->
+ <skip />
+ <!-- no translation found for use_double_space_period_summary (6532892187247952799) -->
+ <skip />
<!-- no translation found for auto_cap (1719746674854628252) -->
<skip />
<!-- no translation found for auto_cap_summary (7934452761022946874) -->
@@ -119,11 +123,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"წინა"</string>
<string name="label_done_key" msgid="2441578748772529288">"შესრულებულია"</string>
<string name="label_send_key" msgid="2815056534433717444">"გაგზავნა"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
- <skip />
- <!-- no translation found for label_to_symbol_with_microphone_key (9035925553010061906) -->
- <skip />
<!-- no translation found for label_pause_key (181098308428035340) -->
<skip />
<!-- no translation found for label_wait_key (6402152600878093134) -->
diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml
index 2be5db2ab..e7b9d5a75 100644
--- a/java/res/values-ko/strings.xml
+++ b/java/res/values-ko/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"기본값"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"주소록 이름 활용"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"추천 및 수정에 주소록의 이름 사용"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"더블스페이스 마침표"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"스페이스바를 두 번 탭하면 마침표와 공백 한 개가 삽입됩니다."</string>
<string name="auto_cap" msgid="1719746674854628252">"자동 대문자화"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"문장의 첫 단어를 대문자로 표시"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"사전 추가"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"이전"</string>
<string name="label_done_key" msgid="2441578748772529288">"완료"</string>
<string name="label_send_key" msgid="2815056534433717444">"전송"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"일시 중지"</string>
<string name="label_wait_key" msgid="6402152600878093134">"대기"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"비밀번호 키를 음성으로 들으려면 헤드셋을 연결하세요."</string>
diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml
index dee3479aa..5c66e1f22 100644
--- a/java/res/values-lt/strings.xml
+++ b/java/res/values-lt/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Numatytasis"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Siūlyti kontaktų vardus"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Siūlant ir taisant naudoti vardus iš „Kontaktų“"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Tšk. ir tarp. pal. dukart"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dukart palietus tarpo klavišą įterpiamas taškas ir tarpas."</string>
<string name="auto_cap" msgid="1719746674854628252">"Automatinis didžiųjų raidžių rašymas"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Kiekvieno sakinio pirmą žodį rašyti iš didžiosios raidės"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Papildomi žodynai"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Anks."</string>
<string name="label_done_key" msgid="2441578748772529288">"Atlikta"</string>
<string name="label_send_key" msgid="2815056534433717444">"Siųsti"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Prist."</string>
<string name="label_wait_key" msgid="6402152600878093134">"Lauk."</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Prijunkite ausines, kad išgirstumėte sakomus slaptažodžio klavišus."</string>
diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml
index b548444b9..a0cf78e89 100644
--- a/java/res/values-lv/strings.xml
+++ b/java/res/values-lv/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Noklusējums"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Ieteikt kontaktp. vārdus"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Izmantot kontaktpersonu vārdus kā ieteikumus un labojumus"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Dubultpiesk. = punkts"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Divreiz pieskaroties atst. taustiņam, ievada punktu un atstarpi."</string>
<string name="auto_cap" msgid="1719746674854628252">"Automātiska lielo burtu lietošana"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Katra teikuma pirmo vārdu rakstīt ar lielo burtu."</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Papildinājumu vārdnīcas"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Iepr."</string>
<string name="label_done_key" msgid="2441578748772529288">"Gatavs"</string>
<string name="label_send_key" msgid="2815056534433717444">"Sūtīt"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pauze"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Gaidīt"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Pievienojiet austiņas, lai dzirdētu paroles rakstzīmes."</string>
diff --git a/java/res/values-mk/strings.xml b/java/res/values-mk/strings.xml
index 824107785..e199e0316 100644
--- a/java/res/values-mk/strings.xml
+++ b/java/res/values-mk/strings.xml
@@ -68,6 +68,10 @@
<skip />
<!-- no translation found for use_contacts_dict_summary (6599983334507879959) -->
<skip />
+ <!-- no translation found for use_double_space_period (8781529969425082860) -->
+ <skip />
+ <!-- no translation found for use_double_space_period_summary (6532892187247952799) -->
+ <skip />
<!-- no translation found for auto_cap (1719746674854628252) -->
<skip />
<!-- no translation found for auto_cap_summary (7934452761022946874) -->
@@ -119,11 +123,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Претходно"</string>
<string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
<string name="label_send_key" msgid="2815056534433717444">"Испрати"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"АБВ"</string>
- <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
- <skip />
- <!-- no translation found for label_to_symbol_with_microphone_key (9035925553010061906) -->
- <skip />
<!-- no translation found for label_pause_key (181098308428035340) -->
<skip />
<!-- no translation found for label_wait_key (6402152600878093134) -->
diff --git a/java/res/values-mn/strings.xml b/java/res/values-mn/strings.xml
new file mode 100644
index 000000000..41bf551ba
--- /dev/null
+++ b/java/res/values-mn/strings.xml
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for aosp_android_keyboard_ime_name (7877134937939182296) -->
+ <skip />
+ <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+ <skip />
+ <!-- no translation found for english_ime_research_log (8492602295696577851) -->
+ <skip />
+ <!-- no translation found for aosp_spell_checker_service_name (6985142605330377819) -->
+ <skip />
+ <!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
+ <skip />
+ <!-- no translation found for use_contacts_for_spellchecking_option_summary (8754413382543307713) -->
+ <skip />
+ <!-- no translation found for vibrate_on_keypress (5258079494276955460) -->
+ <skip />
+ <!-- no translation found for sound_on_keypress (6093592297198243644) -->
+ <skip />
+ <!-- no translation found for popup_on_keypress (123894815723512944) -->
+ <skip />
+ <!-- no translation found for general_category (1859088467017573195) -->
+ <skip />
+ <!-- no translation found for correction_category (2236750915056607613) -->
+ <skip />
+ <!-- no translation found for gesture_typing_category (497263612130532630) -->
+ <skip />
+ <!-- no translation found for misc_category (6894192814868233453) -->
+ <skip />
+ <!-- no translation found for advanced_settings (362895144495591463) -->
+ <skip />
+ <!-- no translation found for advanced_settings_summary (4487980456152830271) -->
+ <skip />
+ <!-- no translation found for include_other_imes_in_language_switch_list (4533689960308565519) -->
+ <skip />
+ <!-- no translation found for include_other_imes_in_language_switch_list_summary (840637129103317635) -->
+ <skip />
+ <!-- no translation found for show_language_switch_key (5915478828318774384) -->
+ <skip />
+ <!-- no translation found for show_language_switch_key_summary (7343403647474265713) -->
+ <skip />
+ <!-- no translation found for key_preview_popup_dismiss_delay (6213164897443068248) -->
+ <skip />
+ <!-- no translation found for key_preview_popup_dismiss_no_delay (2096123151571458064) -->
+ <skip />
+ <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) -->
+ <skip />
+ <!-- no translation found for use_contacts_dict (4435317977804180815) -->
+ <skip />
+ <!-- no translation found for use_contacts_dict_summary (6599983334507879959) -->
+ <skip />
+ <!-- no translation found for use_double_space_period (8781529969425082860) -->
+ <skip />
+ <!-- no translation found for use_double_space_period_summary (6532892187247952799) -->
+ <skip />
+ <!-- no translation found for auto_cap (1719746674854628252) -->
+ <skip />
+ <!-- no translation found for auto_cap_summary (7934452761022946874) -->
+ <skip />
+ <!-- no translation found for configure_dictionaries_title (4238652338556902049) -->
+ <skip />
+ <!-- no translation found for main_dictionary (4798763781818361168) -->
+ <skip />
+ <!-- no translation found for prefs_show_suggestions (8026799663445531637) -->
+ <skip />
+ <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+ <skip />
+ <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+ <skip />
+ <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3859783767435239118) -->
+ <skip />
+ <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+ <skip />
+ <!-- no translation found for auto_correction (7630720885194996950) -->
+ <skip />
+ <!-- no translation found for auto_correction_summary (5625751551134658006) -->
+ <skip />
+ <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
+ <skip />
+ <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
+ <skip />
+ <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
+ <skip />
+ <!-- no translation found for auto_correction_threshold_mode_very_aggeressive (3386782235540547678) -->
+ <skip />
+ <!-- no translation found for bigram_prediction (1084449187723948550) -->
+ <skip />
+ <!-- no translation found for bigram_prediction_summary (3896362682751109677) -->
+ <skip />
+ <!-- no translation found for gesture_input (826951152254563827) -->
+ <skip />
+ <!-- no translation found for gesture_input_summary (9180350639305731231) -->
+ <skip />
+ <!-- no translation found for gesture_preview_trail (3802333369335722221) -->
+ <skip />
+ <!-- no translation found for gesture_floating_preview_text (4443240334739381053) -->
+ <skip />
+ <!-- no translation found for gesture_floating_preview_text_summary (4472696213996203533) -->
+ <skip />
+ <!-- no translation found for added_word (8993883354622484372) -->
+ <skip />
+ <string name="label_go_key" msgid="1635148082137219148">"Очих"</string>
+ <string name="label_next_key" msgid="362972844525672568">"Дараагийн"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"Өмнөх"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"Хийгдлээ"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"Илгээх"</string>
+ <!-- no translation found for label_pause_key (181098308428035340) -->
+ <skip />
+ <!-- no translation found for label_wait_key (6402152600878093134) -->
+ <skip />
+ <!-- no translation found for spoken_use_headphones (896961781287283493) -->
+ <skip />
+ <!-- no translation found for spoken_current_text_is (2485723011272583845) -->
+ <skip />
+ <!-- no translation found for spoken_no_text_entered (7479685225597344496) -->
+ <skip />
+ <!-- no translation found for spoken_description_unknown (3197434010402179157) -->
+ <skip />
+ <!-- no translation found for spoken_description_shift (244197883292549308) -->
+ <skip />
+ <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) -->
+ <skip />
+ <!-- no translation found for spoken_description_caps_lock (3276478269526304432) -->
+ <skip />
+ <!-- no translation found for spoken_description_delete (8740376944276199801) -->
+ <skip />
+ <!-- no translation found for spoken_description_to_symbol (5486340107500448969) -->
+ <skip />
+ <!-- no translation found for spoken_description_to_alpha (23129338819771807) -->
+ <skip />
+ <!-- no translation found for spoken_description_to_numeric (591752092685161732) -->
+ <skip />
+ <!-- no translation found for spoken_description_settings (4627462689603838099) -->
+ <skip />
+ <!-- no translation found for spoken_description_tab (2667716002663482248) -->
+ <skip />
+ <!-- no translation found for spoken_description_space (2582521050049860859) -->
+ <skip />
+ <!-- no translation found for spoken_description_mic (615536748882611950) -->
+ <skip />
+ <!-- no translation found for spoken_description_smiley (2256309826200113918) -->
+ <skip />
+ <!-- no translation found for spoken_description_return (8178083177238315647) -->
+ <skip />
+ <!-- no translation found for spoken_description_search (1247236163755920808) -->
+ <skip />
+ <!-- no translation found for spoken_description_dot (40711082435231673) -->
+ <skip />
+ <!-- no translation found for spoken_description_language_switch (5507091328222331316) -->
+ <skip />
+ <!-- no translation found for spoken_description_action_next (8636078276664150324) -->
+ <skip />
+ <!-- no translation found for spoken_description_action_previous (800872415009336208) -->
+ <skip />
+ <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) -->
+ <skip />
+ <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) -->
+ <skip />
+ <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) -->
+ <skip />
+ <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) -->
+ <skip />
+ <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) -->
+ <skip />
+ <!-- no translation found for spoken_description_mode_phone (6520207943132026264) -->
+ <skip />
+ <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) -->
+ <skip />
+ <!-- no translation found for voice_input (3583258583521397548) -->
+ <skip />
+ <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
+ <skip />
+ <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
+ <skip />
+ <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
+ <skip />
+ <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
+ <skip />
+ <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
+ <skip />
+ <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
+ <skip />
+ <!-- no translation found for configure_input_method (373356270290742459) -->
+ <skip />
+ <!-- no translation found for language_selection_title (1651299598555326750) -->
+ <skip />
+ <!-- no translation found for select_language (3693815588777926848) -->
+ <skip />
+ <!-- no translation found for hint_add_to_dictionary (573678656946085380) -->
+ <skip />
+ <!-- no translation found for has_dictionary (6071847973466625007) -->
+ <skip />
+ <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+ <skip />
+ <!-- no translation found for prefs_description_log (5827825607258246003) -->
+ <skip />
+ <!-- no translation found for keyboard_layout (8451164783510487501) -->
+ <skip />
+ <!-- no translation found for subtype_en_GB (88170601942311355) -->
+ <skip />
+ <!-- no translation found for subtype_en_US (6160452336634534239) -->
+ <skip />
+ <!-- no translation found for subtype_with_layout_en_GB (2179097748724725906) -->
+ <skip />
+ <!-- no translation found for subtype_with_layout_en_US (1362581347576714579) -->
+ <skip />
+ <!-- no translation found for subtype_no_language (141420857808801746) -->
+ <skip />
+ <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
+ <skip />
+ <!-- no translation found for subtype_no_language_qwertz (1177848172397202890) -->
+ <skip />
+ <!-- no translation found for subtype_no_language_azerty (8721460968141187394) -->
+ <skip />
+ <!-- no translation found for subtype_no_language_dvorak (3122976737669823935) -->
+ <skip />
+ <!-- no translation found for subtype_no_language_colemak (4205992994906097244) -->
+ <skip />
+ <!-- no translation found for subtype_no_language_pcqwerty (8840928374394180189) -->
+ <skip />
+ <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+ <skip />
+ <!-- no translation found for add_style (6163126614514489951) -->
+ <skip />
+ <!-- no translation found for add (8299699805688017798) -->
+ <skip />
+ <!-- no translation found for remove (4486081658752944606) -->
+ <skip />
+ <!-- no translation found for save (7646738597196767214) -->
+ <skip />
+ <!-- no translation found for subtype_locale (8576443440738143764) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+ <skip />
+ <!-- no translation found for custom_input_style_note_message (8826731320846363423) -->
+ <skip />
+ <!-- no translation found for enable (5031294444630523247) -->
+ <skip />
+ <!-- no translation found for not_now (6172462888202790482) -->
+ <skip />
+ <!-- no translation found for custom_input_style_already_exists (8008728952215449707) -->
+ <skip />
+ <!-- no translation found for prefs_usability_study_mode (1261130555134595254) -->
+ <skip />
+ <!-- no translation found for prefs_keypress_vibration_duration_settings (1829950405285211668) -->
+ <skip />
+ <!-- no translation found for prefs_keypress_sound_volume_settings (5875933757082305040) -->
+ <skip />
+</resources>
diff --git a/java/res/values-ms/strings.xml b/java/res/values-ms/strings.xml
index 9b9d6ad80..c1a2f0d09 100644
--- a/java/res/values-ms/strings.xml
+++ b/java/res/values-ms/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Lalai"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Cadangkan nama Kenalan"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Menggunakan nama daripada Kenalan untuk cadangan dan pembetulan"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Titik ruang berganda"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Mengetik 2X pada bar ruang memasukkan titik diikuti dengan ruang"</string>
<string name="auto_cap" msgid="1719746674854628252">"Huruf besar auto"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Besarkan perkataan pertama setiap ayat"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Kamus tambahan"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Sblm"</string>
<string name="label_done_key" msgid="2441578748772529288">"Selesai"</string>
<string name="label_send_key" msgid="2815056534433717444">"Hantar"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Jeda"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Tnggu"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Pasangkan set kepala untuk mendengar kekunci kata laluan disebut dengan kuat."</string>
diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml
index 90a5dfba7..f56ce1127 100644
--- a/java/res/values-nb/strings.xml
+++ b/java/res/values-nb/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Foreslå kontaktnavn"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Bruk navn fra Kontakter til forslag og korrigeringer"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Punktum ved doble mellomrom"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dobbeltrykk på mellomromstasten for punktum etterfulgt av mellomrom"</string>
<string name="auto_cap" msgid="1719746674854628252">"Stor forbokstav"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Sett stor bokstav i det første ordet i hver setning"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Tilleggsordbøker"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Forr."</string>
<string name="label_done_key" msgid="2441578748772529288">"Utfør"</string>
<string name="label_send_key" msgid="2815056534433717444">"Send"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Vent"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Koble til hodetelefoner for å høre opplesing av bokstavene i passordet."</string>
diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml
index f564b1b6b..6bd474a19 100644
--- a/java/res/values-nl/strings.xml
+++ b/java/res/values-nl/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standaard"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Contactnamen suggereren"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Namen uit Contacten gebruiken voor suggesties en correcties"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Dubbeltik is punt, spatie"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dubbeltik op spatiebalk voor een punt gevolgd door een spatie"</string>
<string name="auto_cap" msgid="1719746674854628252">"Auto-hoofdlettergebruik"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Het eerste woord van elke zin met een hoofdletter schrijven"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Woordenboeken toevoegen"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Vorig"</string>
<string name="label_done_key" msgid="2441578748772529288">"Gereed"</string>
<string name="label_send_key" msgid="2815056534433717444">"Zenden"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pauze"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Wacht"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Sluit een headset aan om wachtwoordtoetsen hardop te laten voorlezen."</string>
diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml
index 9b73ad12d..27fcf60ba 100644
--- a/java/res/values-pl/strings.xml
+++ b/java/res/values-pl/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Wartość domyślna"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Proponuj osoby z kontaktów"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"W propozycjach i poprawkach użyj nazwisk z kontaktów"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Szybka kropka ze spacją"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dwukrotne kliknięcie spacji wstawia kropkę ze spacją"</string>
<string name="auto_cap" msgid="1719746674854628252">"Wstawiaj wielkie litery"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Zaczynaj każde zdanie wielką literą"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Dodatkowe słowniki"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Wstecz"</string>
<string name="label_done_key" msgid="2441578748772529288">"OK"</string>
<string name="label_send_key" msgid="2815056534433717444">"Wyślij"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pauza"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Czekaj"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Podłącz zestaw słuchawkowy, aby usłyszeć znaki hasła wypowiadane na głos."</string>
diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml
index 0f5490057..46bd34d72 100644
--- a/java/res/values-pt-rPT/strings.xml
+++ b/java/res/values-pt-rPT/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predefinido"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nomes de Contactos"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizar nomes dos Contactos para sugestões e correções"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Ponto de espaço duplo"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Tocar duas vezes na barra espaço insere ponto seguido de espaço"</string>
<string name="auto_cap" msgid="1719746674854628252">"Letras maiúsculas automáticas"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Maiúscula no início da frase"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Dicionários extras"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Ant."</string>
<string name="label_done_key" msgid="2441578748772529288">"Feito"</string>
<string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Esp."</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Ligar auscultadores com microfone integrado para ouvir as teclas da palavra-passe."</string>
diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml
index 098d24565..ce61e0c17 100644
--- a/java/res/values-pt/strings.xml
+++ b/java/res/values-pt/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Padrão"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nomes de contato"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Usar nomes dos Contatos para sugestões e correções"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Duplo espaço p/ ponto"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Toque duplo na barra de espaço insere um ponto seguido de espaço"</string>
<string name="auto_cap" msgid="1719746674854628252">"Capitaliz. automática"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Iniciar a primeira palavra de cada frase com letra maiúscula"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Dicionários complementares"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Volt."</string>
<string name="label_done_key" msgid="2441578748772529288">"Feito"</string>
<string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Esp."</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Conecte um fone de ouvido para ouvir as chaves de senha em voz alta."</string>
diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml
index 26cf8f877..5a315f502 100644
--- a/java/res/values-rm/strings.xml
+++ b/java/res/values-rm/strings.xml
@@ -65,6 +65,10 @@
<skip />
<!-- no translation found for use_contacts_dict_summary (6599983334507879959) -->
<skip />
+ <!-- no translation found for use_double_space_period (8781529969425082860) -->
+ <skip />
+ <!-- no translation found for use_double_space_period_summary (6532892187247952799) -->
+ <skip />
<string name="auto_cap" msgid="1719746674854628252">"Maiusclas automaticas"</string>
<!-- no translation found for auto_cap_summary (7934452761022946874) -->
<skip />
@@ -115,12 +119,6 @@
<skip />
<string name="label_done_key" msgid="2441578748772529288">"Finì"</string>
<string name="label_send_key" msgid="2815056534433717444">"Trametter"</string>
- <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
- <skip />
- <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
- <skip />
- <!-- no translation found for label_to_symbol_with_microphone_key (9035925553010061906) -->
- <skip />
<!-- no translation found for label_pause_key (181098308428035340) -->
<skip />
<!-- no translation found for label_wait_key (6402152600878093134) -->
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index 44f2bb1bd..99b82a537 100644
--- a/java/res/values-ro/strings.xml
+++ b/java/res/values-ro/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Prestabilit"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Sugeraţi nume din Agendă"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizaţi numele din Agendă pentru sugestii şi corecţii"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Inserează punct spațiu"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dubla atingere a barei de spațiu inserează punct urmat de spațiu"</string>
<string name="auto_cap" msgid="1719746674854628252">"Auto-capitalizare"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Scrie cu majusculă primul cuvânt din fiecare propoziţie"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Dicţionare suplimentare"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Înapoi"</string>
<string name="label_done_key" msgid="2441578748772529288">"Terminat"</string>
<string name="label_send_key" msgid="2815056534433717444">"Trimiteţi"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pauză"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Aşt."</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Conectaţi un set căşti-microfon pentru a auzi tastele apăsate când introduceţi parola."</string>
diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml
index 00e574e90..1075d2994 100644
--- a/java/res/values-ru/strings.xml
+++ b/java/res/values-ru/strings.xml
@@ -37,13 +37,15 @@
<string name="advanced_settings_summary" msgid="4487980456152830271">"Для опытных пользователей"</string>
<string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Другой способ ввода"</string>
<string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Клавиша переключения языков также служит для смены способа ввода"</string>
- <string name="show_language_switch_key" msgid="5915478828318774384">"Клавиша переключения языков"</string>
+ <string name="show_language_switch_key" msgid="5915478828318774384">"Клавиша смены языка"</string>
<string name="show_language_switch_key_summary" msgid="7343403647474265713">"Показывать, когда включено несколько раскладок"</string>
<string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Задержка закрытия"</string>
<string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без задержки"</string>
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"По умолчанию"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Подсказывать имена"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Подсказывать исправления на основе имен из списка контактов"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Точка с пробелом"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Вводить точку с пробелом двойным нажатием кнопки \"Пробел\"."</string>
<string name="auto_cap" msgid="1719746674854628252">"Заглавные автоматически"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Писать первое слово предложения с прописной буквы"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Дополнительные словари"</string>
@@ -59,7 +61,7 @@
<string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Умеренное"</string>
<string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Активное"</string>
<string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Очень активно"</string>
- <string name="bigram_prediction" msgid="1084449187723948550">"Подсказка следующего слова"</string>
+ <string name="bigram_prediction" msgid="1084449187723948550">"Подсказывать слова"</string>
<string name="bigram_prediction_summary" msgid="3896362682751109677">"Предлагать подсказки на основе предыдущего слова"</string>
<string name="gesture_input" msgid="826951152254563827">"Включить функцию"</string>
<string name="gesture_input_summary" msgid="9180350639305731231">"Вводите слова, не отрывая пальца от клавиатуры"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Пред."</string>
<string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
<string name="label_send_key" msgid="2815056534433717444">"Отправить"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"АБВ"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Пауза"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Ждать"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Подключите гарнитуру, чтобы услышать пароль."</string>
@@ -106,7 +105,7 @@
<string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Режим ввода текста"</string>
<string name="spoken_description_mode_phone" msgid="6520207943132026264">"Режим набора номера"</string>
<string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Режим телефонных символов"</string>
- <string name="voice_input" msgid="3583258583521397548">"Ключ голосового ввода"</string>
+ <string name="voice_input" msgid="3583258583521397548">"Кнопка голосового ввода"</string>
<string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Значок на основной клавиатуре"</string>
<string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Значок на клавиатуре символов"</string>
<string name="voice_input_modes_off" msgid="3745699748218082014">"Выкл."</string>
diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml
index 915fe14b7..1ee4f3324 100644
--- a/java/res/values-sk/strings.xml
+++ b/java/res/values-sk/strings.xml
@@ -31,7 +31,7 @@
<string name="popup_on_keypress" msgid="123894815723512944">"Zobraziť znaky pri stlačení klávesu"</string>
<string name="general_category" msgid="1859088467017573195">"Všeobecné"</string>
<string name="correction_category" msgid="2236750915056607613">"Oprava textu"</string>
- <string name="gesture_typing_category" msgid="497263612130532630">"Písanie gest"</string>
+ <string name="gesture_typing_category" msgid="497263612130532630">"Písanie gestami"</string>
<string name="misc_category" msgid="6894192814868233453">"Ďalšie možnosti"</string>
<string name="advanced_settings" msgid="362895144495591463">"Rozšírené nastavenia"</string>
<string name="advanced_settings_summary" msgid="4487980456152830271">"Možnosti pre odborníkov"</string>
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predvolená"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Navrhnúť mená kontaktov"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Používať mená z Kontaktov na návrhy a opravy"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Bodka s medzerou"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dvojitým klepnutím na medzerník vložíte bodku a medzeru."</string>
<string name="auto_cap" msgid="1719746674854628252">"Veľké písmená automaticky"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Písanie prvého slova v každej vete veľkým písmenom"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Doplnkové slovníky"</string>
@@ -61,7 +63,7 @@
<string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Veľmi agresívne"</string>
<string name="bigram_prediction" msgid="1084449187723948550">"Návrhy ďalšieho slova"</string>
<string name="bigram_prediction_summary" msgid="3896362682751109677">"Návrhy podľa predchádzajúceho slova"</string>
- <string name="gesture_input" msgid="826951152254563827">"Povoliť písanie gest"</string>
+ <string name="gesture_input" msgid="826951152254563827">"Povoliť písanie gestami"</string>
<string name="gesture_input_summary" msgid="9180350639305731231">"Vkladanie slov prejdením prstom po písmenách"</string>
<string name="gesture_preview_trail" msgid="3802333369335722221">"Zobrazovať stopu gesta"</string>
<string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dynamická plávajúca ukážka"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Pred."</string>
<string name="label_done_key" msgid="2441578748772529288">"Hotovo"</string>
<string name="label_send_key" msgid="2815056534433717444">"Odoslať"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pozastaviť"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Čakajte"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Ak si chcete pri zadávaní hesla vypočuť nahlas vyslovené klávesy, pripojte náhlavnú súpravu."</string>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
index f90cbab4f..6ac740651 100644
--- a/java/res/values-sl/strings.xml
+++ b/java/res/values-sl/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Privzeto"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Predlagaj imena stikov"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Uporaba imen iz stikov za predloge in popravke"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Dva presl. za vnos pike"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Z dvojnim dotikom preslednice vstavite piko in za njo presledek"</string>
<string name="auto_cap" msgid="1719746674854628252">"Samod. velike začetnice"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Prvo besedo stavka piši z veliko začetnico"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Dodatni slovarji"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Nazaj"</string>
<string name="label_done_key" msgid="2441578748772529288">"Dokončano"</string>
<string name="label_send_key" msgid="2815056534433717444">"Pošlji"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Premor"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Čakaj"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Priključite slušalke, če želite slišati izgovorjene tipke gesla."</string>
diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml
index 1f10380ca..1456ae96f 100644
--- a/java/res/values-sr/strings.xml
+++ b/java/res/values-sr/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Подразумевано"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Предложи имена контаката"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Користи имена из Контаката за предлоге и исправке"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Тачка и размак"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Двоструким додиром размака умеће се тачка праћена размаком"</string>
<string name="auto_cap" msgid="1719746674854628252">"Аутоматски унос великих слова"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Писање великог слова на почетку сваке реченице"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Помоћни речници"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Прет."</string>
<string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
<string name="label_send_key" msgid="2815056534433717444">"Пошаљи"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"АБВ"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Пауза"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Чекај"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Укључите слушалице да бисте чули наглас изговорене тастере за лозинку."</string>
diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml
index e986a79dd..f6426f9a2 100644
--- a/java/res/values-sv/strings.xml
+++ b/java/res/values-sv/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Föreslå kontaktnamn"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Använd namn från Kontakter för förslag och korrigeringar"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Dubbelt blanksteg = punkt"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dubbelt blanksteg ger en punkt följt av mellanslag"</string>
<string name="auto_cap" msgid="1719746674854628252">"Automatiska versaler"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Automatisk stor bokstav först i varje mening"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Tilläggsordlistor"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Föreg"</string>
<string name="label_done_key" msgid="2441578748772529288">"Färdig"</string>
<string name="label_send_key" msgid="2815056534433717444">"Skicka"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Vänta"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Anslut hörlurar om du vill att lösenordet ska läsas upp."</string>
diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml
index 4388a27fd..81b9003e8 100644
--- a/java/res/values-sw/strings.xml
+++ b/java/res/values-sw/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Chaguo-msingi"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Pendekeza majini ya Anwani"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Tumia majina kutoka kwa Anwani kwa mapendekezo na marekebisho"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Kitone baada ya nafasi mbili"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Kugonga mara mbili kwenye upau nafasi kunaingiza kitone kikifuatiwa na nafasi"</string>
<string name="auto_cap" msgid="1719746674854628252">"Uwekaji wa herufi kubwa kiotomatiki"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Fanya herufi kubwa neno la kwanza la kila sentensi"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Nyongeza za kamusi"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Iliyotangulia"</string>
<string name="label_done_key" msgid="2441578748772529288">"Kwisha"</string>
<string name="label_send_key" msgid="2815056534433717444">"Tuma"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"? 123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pumzisha"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Subiri"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Chomeka plagi ya kifaa cha kichwa cha kusikiza ili kusikiliza msimbo wa nenosiri inayozungumwa kwa sauti ya juu."</string>
diff --git a/java/res/values-sw600dp/config.xml b/java/res/values-sw600dp/config.xml
index e296623b2..b47eacb15 100644
--- a/java/res/values-sw600dp/config.xml
+++ b/java/res/values-sw600dp/config.xml
@@ -19,7 +19,7 @@
-->
<resources>
- <!-- Device form factor. This value must be aligned with {@link KeyboardId.DEVICE_FORM_FACTOR_TABLET7} -->
+ <!-- Device form factor. This value must be aligned with {@link KeyboardId.FORM_FACTOR_TABLET7} -->
<integer name="config_device_form_factor">1</integer>
<bool name="config_enable_show_voice_key_option">false</bool>
<bool name="config_enable_show_popup_on_keypress_option">false</bool>
diff --git a/java/res/values-sw768dp/config.xml b/java/res/values-sw768dp/config.xml
index 346fa9979..5e7954106 100644
--- a/java/res/values-sw768dp/config.xml
+++ b/java/res/values-sw768dp/config.xml
@@ -19,7 +19,7 @@
-->
<resources>
- <!-- Device form factor. This value must be aligned with {@link KeyboardId.DEVICE_FORM_FACTOR_TABLET10} -->
+ <!-- Device form factor. This value must be aligned with {@link KeyboardId.FORM_FACTOR_TABLET10} -->
<integer name="config_device_form_factor">2</integer>
<bool name="config_enable_show_voice_key_option">false</bool>
<bool name="config_enable_show_popup_on_keypress_option">false</bool>
diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml
index 9c63a13f7..d0890987e 100644
--- a/java/res/values-th/strings.xml
+++ b/java/res/values-th/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ค่าเริ่มต้น"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"แนะนำชื่อผู้ติดต่อ"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"ใช้ชื่อจากรายชื่อติดต่อสำหรับคำแนะนำและการแก้ไข"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"แตะ Space สองครั้งแทรกจุด"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"แตะ Spacebar สองครั้งจะแทรกจุดตามด้วยช่องว่างหนึ่งช่อง"</string>
<string name="auto_cap" msgid="1719746674854628252">"ปรับเป็นตัวพิมพ์ใหญ่อัตโนมัติ"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"ทำให้คำแรกของทุกประโยคเป็นตัวพิมพ์ใหญ่"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"พจนานุกรม Add-On"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"ก่อนหน้า"</string>
<string name="label_done_key" msgid="2441578748772529288">"เสร็จสิ้น"</string>
<string name="label_send_key" msgid="2815056534433717444">"ส่ง"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"กขค"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"หยุดชั่วคราว"</string>
<string name="label_wait_key" msgid="6402152600878093134">"รอ"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"เสียบชุดหูฟังเพื่อฟังเสียงเมื่อพิมพ์รหัสผ่าน"</string>
diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml
index 18cd0afb3..a16032e80 100644
--- a/java/res/values-tl/strings.xml
+++ b/java/res/values-tl/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Default"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Mungkahi pangalan Contact"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Gamitin pangalan mula Mga Contact sa mga mungkahi\'t pagwawasto"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Double-space period"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Naglalagay ng tuldok na may puwang ang pag-double tap sa spacebar"</string>
<string name="auto_cap" msgid="1719746674854628252">"Auto-capitalization"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"I-capitalize ang unang salita ng bawat pangungusap"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Mga diksyunaryo na add-on"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Nkrn"</string>
<string name="label_done_key" msgid="2441578748772529288">"Tapos na"</string>
<string name="label_send_key" msgid="2815056534433717444">"Ipadala"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Intay"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Mag-plug in ng headset upang marinig ang mga password key na binabanggit nang malakas."</string>
diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml
index a57c58ab3..7b3748c84 100644
--- a/java/res/values-tr/strings.xml
+++ b/java/res/values-tr/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Varsayılan"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Kişi Adları öner"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Öneri ve düzeltmeler için Kişiler\'deki adları kullan"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Çift boşlukla nokta ekleme"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Boşluk çubuğuna iki kez vurmak nokta ve ardından bir boşluk ekler"</string>
<string name="auto_cap" msgid="1719746674854628252">"Otomatik olarak büyük fark yap"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Her cümlenin ilk kelimesini büyük harf yap"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Ek sözlükler"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Önceki"</string>
<string name="label_done_key" msgid="2441578748772529288">"Bitti"</string>
<string name="label_send_key" msgid="2815056534433717444">"Gönder"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Durkl"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Bekle"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Şifre tuşlarının sesli okunmasını dinlemek için mikrofonlu kulaklık takın."</string>
diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml
index cd9fdfa66..532f67147 100644
--- a/java/res/values-uk/strings.xml
+++ b/java/res/values-uk/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"За умовчанням"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Пропон. імена контактів"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Використ. імена зі списку контактів для пропозицій і виправлень"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Крапка подвійним пробілом"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Подвійне натискання пробілу вставляє крапку з пробілом після неї"</string>
<string name="auto_cap" msgid="1719746674854628252">"Авто викор. вел. літер"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Писати перше слово в кожному реченні з великої літери"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Додані словники"</string>
@@ -67,14 +69,11 @@
<string name="gesture_floating_preview_text" msgid="4443240334739381053">"Динамічний спливаючий перегляд"</string>
<string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Показувати пропоноване слово під час введення тексту жестами"</string>
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : збережено"</string>
- <string name="label_go_key" msgid="1635148082137219148">"Іти"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"OK"</string>
<string name="label_next_key" msgid="362972844525672568">"Далі"</string>
<string name="label_previous_key" msgid="1211868118071386787">"Назад"</string>
<string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
<string name="label_send_key" msgid="2815056534433717444">"Надісл."</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"АБВ"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Пауза"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Чек."</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Підключіть гарнітуру, щоб прослухати відтворені вголос символи пароля."</string>
diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml
index 658a4c4ff..2b29120c3 100644
--- a/java/res/values-vi/strings.xml
+++ b/java/res/values-vi/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Mặc định"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Đề xuất tên liên hệ"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Sử dụng tên từ Danh bạ cho các đề xuất và chỉnh sửa"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Dấu cách đôi"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Nhấn đúp vào phím cách sẽ chèn thêm một dấu sau dấu cách"</string>
<string name="auto_cap" msgid="1719746674854628252">"Tự động viết hoa"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Viết hoa chữ đầu tiên của mỗi câu"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Thêm từ điển"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Trước"</string>
<string name="label_done_key" msgid="2441578748772529288">"Xong"</string>
<string name="label_send_key" msgid="2815056534433717444">"Gửi"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Tạm dừng"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Đợi"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Cắm tai nghe để nghe mật khẩu."</string>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index 98fdef036..ed663b753 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"默认"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"联系人姓名建议"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"使用联系人中的姓名提供建议和更正"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"双击空格插入句号"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"双击空格键可插入句号并后跟空格"</string>
<string name="auto_cap" msgid="1719746674854628252">"自动大写"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"句首字词大写"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"附加词典"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"后退"</string>
<string name="label_done_key" msgid="2441578748772529288">"完成"</string>
<string name="label_send_key" msgid="2815056534433717444">"发送"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"暂停"</string>
<string name="label_wait_key" msgid="6402152600878093134">"等待"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"需要插入耳机才能听到密码的按键声。"</string>
diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index d030d506d..28d32cf38 100644
--- a/java/res/values-zh-rTW/strings.xml
+++ b/java/res/values-zh-rTW/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"預設"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"建議聯絡人名稱"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"根據「聯絡人」名稱提供建議與修正"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"輕按兩下空格鍵即插入句號"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"輕按兩下空格鍵可插入句號另加一個空格"</string>
<string name="auto_cap" msgid="1719746674854628252">"自動大寫"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"句首字詞大寫"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"外掛字典"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"上一步"</string>
<string name="label_done_key" msgid="2441578748772529288">"完成"</string>
<string name="label_send_key" msgid="2815056534433717444">"傳送"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"暫停"</string>
<string name="label_wait_key" msgid="6402152600878093134">"等候"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"連接耳機即可聽取系統朗讀密碼按鍵。"</string>
diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml
index 8b8b4da61..575a687b5 100644
--- a/java/res/values-zu/strings.xml
+++ b/java/res/values-zu/strings.xml
@@ -44,6 +44,8 @@
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Okuzenzakalelayo"</string>
<string name="use_contacts_dict" msgid="4435317977804180815">"Sikisela amagama Othintana nabo"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Amagama abasebenzisi kusuka Kothintana nabo bokusikisela nokulungisa"</string>
+ <string name="use_double_space_period" msgid="8781529969425082860">"Isikhathi se-Double-space"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Ukuthepha kabili kubha yesikhala kufaka isikhathi esilandelwa yisikhala"</string>
<string name="auto_cap" msgid="1719746674854628252">"Ukwenza ofeleba okuzenzakalelayo"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Yenza ufeleba wegama lokuqala lomusho ngamunye"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Faka izichazamazwi"</string>
@@ -72,9 +74,6 @@
<string name="label_previous_key" msgid="1211868118071386787">"Eledlule"</string>
<string name="label_done_key" msgid="2441578748772529288">"Kwenziwe"</string>
<string name="label_send_key" msgid="2815056534433717444">"Thumela"</string>
- <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
- <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
- <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
<string name="label_pause_key" msgid="181098308428035340">"Misa okwesikhashana"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Linda"</string>
<string name="spoken_use_headphones" msgid="896961781287283493">"Plaka ku-headset ukuze uzwe okhiye bephasiwedi ezindlebeni zakho bezwakala kakhulu."</string>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 53051d033..2f1a209fc 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -32,7 +32,6 @@
<attr name="suggestionStripViewStyle" format="reference" />
<attr name="moreSuggestionsViewStyle" format="reference" />
<attr name="suggestionBackgroundStyle" format="reference" />
- <attr name="suggestionPreviewBackgroundStyle" format="reference" />
</declare-styleable>
<declare-styleable name="KeyboardView">
@@ -145,6 +144,7 @@
<attr name="gestureSamplingMinimumDistance" format="fraction" />
<!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) -->
<attr name="gestureRecognitionMinimumTime" format="integer" />
+ <attr name="gestureRecognitionUpdateTime" format="integer" />
<attr name="gestureRecognitionSpeedThreshold" format="fraction" />
<!-- Suppress showing key preview duration after batch input in millisecond -->
<attr name="suppressKeyPreviewAfterBatchInputDuration" format="integer" />
@@ -389,6 +389,7 @@
<attr name="passwordInput" format="boolean" />
<attr name="clobberSettingsKey" format="boolean" />
<attr name="shortcutKeyEnabled" format="boolean" />
+ <attr name="shortcutKeyOnSymbols" format="boolean" />
<attr name="hasShortcutKey" format="boolean" />
<attr name="languageSwitchKeyEnabled" format="boolean" />
<attr name="isMultiLine" format="boolean" />
diff --git a/java/res/values/colors.xml b/java/res/values/colors.xml
new file mode 100644
index 000000000..da4d87cca
--- /dev/null
+++ b/java/res/values/colors.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Color resources for default, and Gingerbread theme. -->
+ <color name="highlight_color_default">#FFFCAE00</color>
+ <color name="key_text_color_default">@android:color/white</color>
+ <color name="key_text_shadow_color_default">#BB000000</color>
+ <color name="key_text_inactivated_color_default">@android:color/white</color>
+ <color name="key_hint_letter_color_default">#80000000</color>
+ <color name="key_hint_label_color_default">#E0E0E4E5</color>
+ <color name="key_shifted_letter_hint_inactivated_color_default">#66E0E4E5</color>
+ <color name="key_shifted_letter_hint_activated_color_default">#CCE0E4E5</color>
+ <color name="spacebar_text_color_default">#FFC0C0C0</color>
+ <color name="spacebar_text_shadow_color_default">#80000000</color>
+ <color name="typed_word_color_default">@android:color/white</color>
+ <color name="gesture_floating_preview_color_default">#C0000000</color>
+ <!-- Color resources for Stone theme. -->
+ <color name="key_text_color_stone">@android:color/black</color>
+ <color name="key_text_shadow_color_stone">@android:color/white</color>
+ <color name="key_text_inactivated_color_stone">#FF808080</color>
+ <color name="key_hint_letter_color_stone">#80000000</color>
+ <color name="key_hint_label_color_stone">#E0000000</color>
+ <color name="key_shifted_letter_hint_inactivated_color_stone">#66000000</color>
+ <color name="key_shifted_letter_hint_activated_color_stone">#CC000000</color>
+ <color name="spacebar_text_color_stone">@android:color/black</color>
+ <color name="spacebar_text_shadow_color_stone">#D0FFFFFF</color>
+ <!-- Color resources for IceCreamSandwich theme. -->
+ <color name="highlight_color_ics">@android:color/holo_blue_light</color>
+ <color name="key_text_color_ics">@android:color/white</color>
+ <color name="key_text_shadow_color_ics">@android:color/transparent</color>
+ <color name="key_text_inactivated_color_ics">#66E0E4E5</color>
+ <color name="key_hint_letter_color_ics">#80000000</color>
+ <color name="key_hint_label_color_ics">#A0FFFFFF</color>
+ <color name="key_shifted_letter_hint_inactivated_color_ics">#66E0E4E5</color>
+ <color name="key_shifted_letter_hint_activated_color_ics">@android:color/white</color>
+ <color name="spacebar_text_color_ics">#FFC0C0C0</color>
+ <color name="spacebar_text_shadow_color_ics">#80000000</color>
+ <color name="typed_word_color_ics">@color/highlight_color_ics</color>
+</resources>
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index cb1358726..dca370a9a 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -19,7 +19,7 @@
-->
<resources>
- <!-- Device form factor. This value must be aligned with {@link KeyboardId.DEVICE_FORM_FACTOR_PHONE} -->
+ <!-- Device form factor. This value must be aligned with {@link KeyboardId.FORM_FACTOR_PHONE} -->
<integer name="config_device_form_factor">0</integer>
<bool name="config_use_fullscreen_mode">false</bool>
<bool name="config_enable_show_voice_key_option">true</bool>
@@ -41,7 +41,7 @@
<integer name="config_more_keys_keyboard_fadeout_anim_time">100</integer>
<integer name="config_keyboard_grid_width">32</integer>
<integer name="config_keyboard_grid_height">16</integer>
- <integer name="config_double_spaces_turn_into_period_timeout">1100</integer>
+ <integer name="config_double_space_period_timeout">1100</integer>
<!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. -->
<string name="config_default_keyboard_theme_index" translatable="false">5</string>
<integer name="config_max_more_keys_column">5</integer>
@@ -86,6 +86,7 @@
<fraction name="config_gesture_sampling_minimum_distance">16.6666%</fraction>
<!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) -->
<integer name="config_gesture_recognition_minimum_time">100</integer>
+ <integer name="config_gesture_recognition_update_time">100</integer>
<fraction name="config_gesture_recognition_speed_threshold">550%</fraction>
<!-- Suppress showing key preview duration after batch input in millisecond -->
<integer name="config_suppress_key_preview_after_batch_input_duration">1000</integer>
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml
index a9c5e5d12..a6ea8a061 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -141,10 +141,12 @@
<string-array name="subtype_locale_exception_keys">
<item>en_US</item>
<item>en_GB</item>
+ <item>es_US</item>
</string-array>
<string-array name="subtype_locale_exception_values">
<item>English (US)</item>
<item>English (UK)</item>
+ <item>Español (EE.UU.)</item>
</string-array>
<!-- Generic subtype label -->
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 13aca717f..2affdebed 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -81,6 +81,11 @@
<!-- Description for option enabling or disabling the use of names of people in Contacts for suggestion and correction [CHAR LIMIT=65] -->
<string name="use_contacts_dict_summary">Use names from Contacts for suggestions and corrections</string>
+ <!-- Option name for enabling or disabling the double-space period feature that lets double tap on spacebar insert a period followed by a space [CHAR LIMIT=30] -->
+ <string name="use_double_space_period">Double-space period</string>
+ <!-- Description for option enabling or disabling the double-space period feature that lets double tap on spacebar insert a period followed by a space [CHAR LIMIT=65] -->
+ <string name="use_double_space_period_summary">Double tap on spacebar inserts a period followed by a space</string>
+
<!-- Option to enable auto capitalization of sentences -->
<string name="auto_cap">Auto-capitalization</string>
<!-- Description for option to enable auto capitalization of sentences -->
@@ -142,13 +147,6 @@
<string name="label_done_key">Done</string>
<!-- Label for soft enter key when it performs SEND action. Must be short to fit on key! [CHAR LIMIT=5] -->
<string name="label_send_key">Send</string>
- <!-- Label for "switch to alphabetic" key. Must be short to fit on key! [CHAR LIMIT=3] -->
- <string name="label_to_alpha_key">ABC</string>
- <!-- Label for "switch to symbols" key. Must be short to fit on key! [CHAR LIMIT=4] -->
- <string name="label_to_symbol_key">\?123</string>
- <!-- Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
- part because it'll be appended by the code. Must be short to fit on key! [CHAR LIMIT=3] -->
- <string name="label_to_symbol_with_microphone_key">123</string>
<!-- Label for "Pause" key of phone number keyboard. Must be short to fit on key! [CHAR LIMIT=5] -->
<string name="label_pause_key">Pause</string>
<!-- Label for "Wait" key of phone number keyboard. Must be short to fit on key! [CHAR LIMIT=5]-->
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index dbb56ab4d..0bcf943e4 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -43,32 +43,31 @@
<item name="keyHintLabelRatio">@fraction/key_hint_label_ratio</item>
<item name="keyShiftedLetterHintRatio">@fraction/key_uppercase_letter_ratio</item>
<item name="keyTypeface">normal</item>
- <item name="keyTextColor">#FFFFFFFF</item>
- <item name="keyTextInactivatedColor">#FFFFFFFF</item>
- <item name="keyHintLetterColor">#80000000</item>
- <item name="keyHintLabelColor">#E0E0E4E5</item>
- <item name="keyShiftedLetterHintInactivatedColor">#66E0E4E5</item>
- <item name="keyShiftedLetterHintActivatedColor">#CCE0E4E5</item>
+ <item name="keyTextColor">@color/key_text_color_default</item>
+ <item name="keyTextInactivatedColor">@color/key_text_color_default</item>
+ <item name="keyHintLetterColor">@color/key_hint_letter_color_default</item>
+ <item name="keyHintLabelColor">@color/key_hint_label_color_default</item>
+ <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_default</item>
+ <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_default</item>
<item name="keyLabelHorizontalPadding">@dimen/key_label_horizontal_padding</item>
<item name="keyHintLetterPadding">@dimen/key_hint_letter_padding</item>
<item name="keyPopupHintLetterPadding">@dimen/key_popup_hint_letter_padding</item>
<item name="keyShiftedLetterHintPadding">@dimen/key_uppercase_letter_padding</item>
<item name="keyPreviewLayout">@layout/key_preview</item>
- <item name="keyPreviewTextColor">#FFFFFFFF</item>
+ <item name="keyPreviewTextColor">@color/key_text_color_default</item>
<item name="keyPreviewOffset">@dimen/key_preview_offset</item>
<item name="keyPreviewHeight">@dimen/key_preview_height</item>
<item name="keyPreviewTextRatio">@fraction/key_preview_text_ratio</item>
<item name="keyPreviewLingerTimeout">@integer/config_key_preview_linger_timeout</item>
<item name="moreKeysLayout">@layout/more_keys_keyboard</item>
<item name="verticalCorrection">@dimen/keyboard_vertical_correction</item>
- <item name="keyTextShadowColor">#BB000000</item>
+ <item name="keyTextShadowColor">@color/key_text_shadow_color_default</item>
<item name="keyTextShadowRadius">2.75</item>
<item name="backgroundDimAlpha">128</item>
- <!-- android:color/holo_blue_light=#FF33B5E5 -->
<item name="gestureFloatingPreviewTextSize">@dimen/gesture_floating_preview_text_size</item>
- <item name="gestureFloatingPreviewTextColor">@android:color/holo_blue_light</item>
+ <item name="gestureFloatingPreviewTextColor">@color/highlight_color_default</item>
<item name="gestureFloatingPreviewTextOffset">@dimen/gesture_floating_preview_text_offset</item>
- <item name="gestureFloatingPreviewColor">#C0000000</item>
+ <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_default</item>
<item name="gestureFloatingPreviewHorizontalPadding">@dimen/gesture_floating_preview_horizontal_padding</item>
<item name="gestureFloatingPreviewVerticalPadding">@dimen/gesture_floating_preview_vertical_padding</item>
<item name="gestureFloatingPreviewRoundRadius">@dimen/gesture_floating_preview_round_radius</item>
@@ -76,7 +75,7 @@
<item name="gesturePreviewTrailFadeoutStartDelay">@integer/config_gesture_preview_trail_fadeout_start_delay</item>
<item name="gesturePreviewTrailFadeoutDuration">@integer/config_gesture_preview_trail_fadeout_duration</item>
<item name="gesturePreviewTrailUpdateInterval">@integer/config_gesture_preview_trail_update_interval</item>
- <item name="gesturePreviewTrailColor">@android:color/holo_blue_light</item>
+ <item name="gesturePreviewTrailColor">@color/highlight_color_default</item>
<item name="gesturePreviewTrailStartWidth">@dimen/gesture_preview_trail_start_width</item>
<item name="gesturePreviewTrailEndWidth">@dimen/gesture_preview_trail_end_width</item>
<!-- Common attributes of MainKeyboardView -->
@@ -105,6 +104,7 @@
<item name="gestureDynamicDistanceThresholdTo">@fraction/config_gesture_dynamic_distance_threshold_to</item>
<item name="gestureSamplingMinimumDistance">@fraction/config_gesture_sampling_minimum_distance</item>
<item name="gestureRecognitionMinimumTime">@integer/config_gesture_recognition_minimum_time</item>
+ <item name="gestureRecognitionUpdateTime">@integer/config_gesture_recognition_update_time</item>
<item name="gestureRecognitionSpeedThreshold">@fraction/config_gesture_recognition_speed_threshold</item>
<item name="suppressKeyPreviewAfterBatchInputDuration">@integer/config_suppress_key_preview_after_batch_input_duration</item>
</style>
@@ -114,8 +114,8 @@
<item name="autoCorrectionSpacebarLedEnabled">true</item>
<item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
<item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
- <item name="spacebarTextColor">#FFC0C0C0</item>
- <item name="spacebarTextShadowColor">#80000000</item>
+ <item name="spacebarTextColor">@color/spacebar_text_color_default</item>
+ <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_default</item>
</style>
<style
name="MoreKeysKeyboard"
@@ -124,6 +124,7 @@
<item name="keyboardTopPadding">0dp</item>
<item name="keyboardBottomPadding">0dp</item>
<item name="horizontalGap">0dp</item>
+ <item name="touchPositionCorrectionData">@null</item>
</style>
<style
name="MoreKeysKeyboardView"
@@ -143,10 +144,10 @@
parent="SuggestionsStripBackgroundStyle"
>
<item name="suggestionStripOption">autoCorrectBold|validTypedWordBold</item>
- <item name="colorValidTypedWord">#FFFCAE00</item>
- <item name="colorTypedWord">@android:color/white</item>
- <item name="colorAutoCorrect">#FFFCAE00</item>
- <item name="colorSuggested">#FFFCAE00</item>
+ <item name="colorValidTypedWord">@color/highlight_color_default</item>
+ <item name="colorTypedWord">@color/typed_word_color_default</item>
+ <item name="colorAutoCorrect">@color/highlight_color_default</item>
+ <item name="colorSuggested">@color/highlight_color_default</item>
<item name="alphaObsoleted">50%</item>
<item name="suggestionsCountInStrip">@integer/suggestions_count_in_strip</item>
<item name="centerSuggestionPercentile">@fraction/center_suggestion_percentile</item>
@@ -161,9 +162,6 @@
<style name="SuggestionBackgroundStyle">
<item name="android:background">@drawable/btn_suggestion</item>
</style>
- <style name="SuggestionPreviewBackgroundStyle">
- <item name="android:background">@drawable/suggestion_feedback_background</item>
- </style>
<!-- Theme "Basic high contrast" -->
<style
name="Keyboard.HighContrast"
@@ -186,8 +184,8 @@
<item name="autoCorrectionSpacebarLedEnabled">true</item>
<item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
<item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
- <item name="spacebarTextColor">#FFC0C0C0</item>
- <item name="spacebarTextShadowColor">#80000000</item>
+ <item name="spacebarTextColor">@color/spacebar_text_color_default</item>
+ <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_default</item>
</style>
<!-- Theme "Stone" -->
<style
@@ -206,13 +204,13 @@
parent="KeyboardView"
>
<item name="keyBackground">@drawable/btn_keyboard_key_stone</item>
- <item name="keyTextColor">#FF000000</item>
- <item name="keyTextInactivatedColor">#FF808080</item>
- <item name="keyHintLetterColor">#80000000</item>
- <item name="keyHintLabelColor">#E0000000</item>
- <item name="keyShiftedLetterHintInactivatedColor">#66000000</item>
- <item name="keyShiftedLetterHintActivatedColor">#CC000000</item>
- <item name="keyTextShadowColor">#FFFFFFFF</item>
+ <item name="keyTextColor">@color/key_text_color_stone</item>
+ <item name="keyTextInactivatedColor">@color/key_text_inactivated_color_stone</item>
+ <item name="keyHintLetterColor">@color/key_hint_letter_color_stone</item>
+ <item name="keyHintLabelColor">@color/key_hint_label_color_stone</item>
+ <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_stone</item>
+ <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_stone</item>
+ <item name="keyTextShadowColor">@color/key_text_shadow_color_stone</item>
</style>
<style
name="MainKeyboardView.Stone"
@@ -221,8 +219,8 @@
<item name="autoCorrectionSpacebarLedEnabled">true</item>
<item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
<item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
- <item name="spacebarTextColor">#FF000000</item>
- <item name="spacebarTextShadowColor">#D0FFFFFF</item>
+ <item name="spacebarTextColor">@color/spacebar_text_color_stone</item>
+ <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_stone</item>
</style>
<style
name="MoreKeysKeyboard.Stone"
@@ -231,14 +229,15 @@
<item name="keyboardTopPadding">0dp</item>
<item name="keyboardBottomPadding">0dp</item>
<item name="horizontalGap">0dp</item>
+ <item name="touchPositionCorrectionData">@null</item>
</style>
<style
name="MoreKeysKeyboardView.Stone"
parent="MoreKeysKeyboardView"
>
<item name="keyBackground">@drawable/btn_keyboard_key_stone</item>
- <item name="keyTextColor">#FF000000</item>
- <item name="keyTextShadowColor">#FFFFFFFF</item>
+ <item name="keyTextColor">@color/key_text_color_stone</item>
+ <item name="keyTextShadowColor">@color/key_text_shadow_color_stone</item>
</style>
<!-- Theme "Stone bold" -->
<style
@@ -261,8 +260,8 @@
<item name="autoCorrectionSpacebarLedEnabled">true</item>
<item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
<item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
- <item name="spacebarTextColor">#FF000000</item>
- <item name="spacebarTextShadowColor">#D0FFFFFF</item>
+ <item name="spacebarTextColor">@color/spacebar_text_color_stone</item>
+ <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_stone</item>
</style>
<!-- Theme "Gingerbread" -->
<style
@@ -290,8 +289,8 @@
<item name="autoCorrectionSpacebarLedEnabled">true</item>
<item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
<item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
- <item name="spacebarTextColor">#FFC0C0C0</item>
- <item name="spacebarTextShadowColor">#80000000</item>
+ <item name="spacebarTextColor">@color/spacebar_text_color_default</item>
+ <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_default</item>
</style>
<style
name="MoreKeysKeyboard.Gingerbread"
@@ -300,6 +299,7 @@
<item name="keyboardTopPadding">0dp</item>
<item name="keyboardBottomPadding">0dp</item>
<item name="horizontalGap">0dp</item>
+ <item name="touchPositionCorrectionData">@null</item>
</style>
<style
name="MoreKeysKeyboardView.Gingerbread"
@@ -327,16 +327,18 @@
<item name="android:background">@drawable/keyboard_background_holo</item>
<item name="keyBackground">@drawable/btn_keyboard_key_ics</item>
<item name="keyTypeface">bold</item>
- <item name="keyTextInactivatedColor">#66E0E4E5</item>
- <item name="keyHintLetterColor">#80000000</item>
- <item name="keyHintLabelColor">#A0FFFFFF</item>
- <item name="keyShiftedLetterHintInactivatedColor">#66E0E4E5</item>
- <item name="keyShiftedLetterHintActivatedColor">#FFFFFFFF</item>
+ <item name="keyTextInactivatedColor">@color/key_text_inactivated_color_ics</item>
+ <item name="keyHintLetterColor">@color/key_hint_letter_color_ics</item>
+ <item name="keyHintLabelColor">@color/key_hint_label_color_ics</item>
+ <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_ics</item>
+ <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_ics</item>
<item name="keyPreviewLayout">@layout/key_preview_ics</item>
- <item name="keyPreviewTextColor">#FFFFFFFF</item>
+ <item name="keyPreviewTextColor">@color/key_text_color_ics</item>
<item name="keyPreviewOffset">@dimen/key_preview_offset_ics</item>
- <item name="keyTextShadowColor">#00000000</item>
+ <item name="keyTextShadowColor">@color/key_text_shadow_color_ics</item>
<item name="keyTextShadowRadius">0.0</item>
+ <item name="gestureFloatingPreviewTextColor">@color/highlight_color_ics</item>
+ <item name="gesturePreviewTrailColor">@color/highlight_color_ics</item>
</style>
<style
name="MainKeyboardView.IceCreamSandwich"
@@ -345,8 +347,8 @@
<item name="autoCorrectionSpacebarLedEnabled">false</item>
<item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_holo</item>
<item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
- <item name="spacebarTextColor">#FFC0C0C0</item>
- <item name="spacebarTextShadowColor">#80000000</item>
+ <item name="spacebarTextColor">@color/spacebar_text_color_ics</item>
+ <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_ics</item>
</style>
<style
name="MoreKeysKeyboard.IceCreamSandwich"
@@ -355,6 +357,7 @@
<item name="keyboardTopPadding">0dp</item>
<item name="keyboardBottomPadding">0dp</item>
<item name="horizontalGap">0dp</item>
+ <item name="touchPositionCorrectionData">@null</item>
</style>
<style
name="MoreKeysKeyboardView.IceCreamSandwich"
@@ -375,11 +378,10 @@
parent="SuggestionsStripBackgroundStyle.IceCreamSandwich"
>
<item name="suggestionStripOption">autoCorrectBold|validTypedWordBold</item>
- <!-- android:color/holo_blue_light=#FF33B5E5 -->
- <item name="colorValidTypedWord">@android:color/holo_blue_light</item>
- <item name="colorTypedWord">@android:color/holo_blue_light</item>
- <item name="colorAutoCorrect">@android:color/holo_blue_light</item>
- <item name="colorSuggested">@android:color/holo_blue_light</item>
+ <item name="colorValidTypedWord">@color/highlight_color_ics</item>
+ <item name="colorTypedWord">@color/highlight_color_ics</item>
+ <item name="colorAutoCorrect">@color/highlight_color_ics</item>
+ <item name="colorSuggested">@color/highlight_color_ics</item>
<item name="alphaValidTypedWord">85%</item>
<item name="alphaTypedWord">85%</item>
<item name="alphaSuggested">70%</item>
diff --git a/java/res/values/themes-basic-highcontrast.xml b/java/res/values/themes-basic-highcontrast.xml
index b3ea05045..48df0a1b6 100644
--- a/java/res/values/themes-basic-highcontrast.xml
+++ b/java/res/values/themes-basic-highcontrast.xml
@@ -26,6 +26,5 @@
<item name="suggestionStripViewStyle">@style/SuggestionStripViewStyle</item>
<item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
<item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
- <item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
</style>
</resources>
diff --git a/java/res/values/themes-basic.xml b/java/res/values/themes-basic.xml
index ff6a70a08..88a0c5d8d 100644
--- a/java/res/values/themes-basic.xml
+++ b/java/res/values/themes-basic.xml
@@ -26,6 +26,5 @@
<item name="suggestionStripViewStyle">@style/SuggestionStripViewStyle</item>
<item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
<item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
- <item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
</style>
</resources>
diff --git a/java/res/values/themes-gingerbread.xml b/java/res/values/themes-gingerbread.xml
index 0ce0b8a9b..51f680a7a 100644
--- a/java/res/values/themes-gingerbread.xml
+++ b/java/res/values/themes-gingerbread.xml
@@ -26,6 +26,5 @@
<item name="suggestionStripViewStyle">@style/SuggestionStripViewStyle</item>
<item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
<item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
- <item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
</style>
</resources>
diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml
index 8df58c594..d9c59a180 100644
--- a/java/res/values/themes-ics.xml
+++ b/java/res/values/themes-ics.xml
@@ -26,6 +26,5 @@
<item name="suggestionStripViewStyle">@style/SuggestionStripViewStyle.IceCreamSandwich</item>
<item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle.IceCreamSandwich</item>
<item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle.IceCreamSandwich</item>
- <item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle.IceCreamSandwich</item>
</style>
</resources>
diff --git a/java/res/values/themes-stone-bold.xml b/java/res/values/themes-stone-bold.xml
index 355a97f7b..6ace9d673 100644
--- a/java/res/values/themes-stone-bold.xml
+++ b/java/res/values/themes-stone-bold.xml
@@ -26,6 +26,5 @@
<item name="suggestionStripViewStyle">@style/SuggestionStripViewStyle</item>
<item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
<item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
- <item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
</style>
</resources>
diff --git a/java/res/values/themes-stone.xml b/java/res/values/themes-stone.xml
index 23437f780..3c3826b1a 100644
--- a/java/res/values/themes-stone.xml
+++ b/java/res/values/themes-stone.xml
@@ -26,6 +26,5 @@
<item name="suggestionStripViewStyle">@style/SuggestionStripViewStyle</item>
<item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
<item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
- <item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
</style>
</resources>
diff --git a/java/res/xml-sw600dp/key_styles_common.xml b/java/res/xml-sw600dp/key_styles_common.xml
index bf2e76a6b..6b06ce77a 100644
--- a/java/res/xml-sw600dp/key_styles_common.xml
+++ b/java/res/xml-sw600dp/key_styles_common.xml
@@ -154,31 +154,30 @@
</default>
</switch>
<key-style
- latin:styleName="toSymbolKeyStyle"
- latin:code="!code/key_switch_alpha_symbol"
- latin:keyLabel="!text/label_to_symbol_key"
+ latin:styleName="baseForLayoutSwitchKeyStyle"
latin:keyLabelFlags="preserveCase"
latin:keyActionFlags="noKeyPreview"
latin:backgroundType="functional" />
<key-style
+ latin:styleName="toSymbolKeyStyle"
+ latin:code="!code/key_switch_alpha_symbol"
+ latin:keyLabel="!text/label_to_symbol_key"
+ latin:parentStyle="baseForLayoutSwitchKeyStyle" />
+ <key-style
latin:styleName="toAlphaKeyStyle"
latin:code="!code/key_switch_alpha_symbol"
latin:keyLabel="!text/label_to_alpha_key"
- latin:keyLabelFlags="preserveCase"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional" />
+ latin:parentStyle="baseForLayoutSwitchKeyStyle" />
<key-style
latin:styleName="toMoreSymbolKeyStyle"
latin:code="!code/key_shift"
latin:keyLabel="!text/label_to_more_symbol_for_tablet_key"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional" />
+ latin:parentStyle="baseForLayoutSwitchKeyStyle" />
<key-style
latin:styleName="backFromMoreSymbolKeyStyle"
latin:code="!code/key_shift"
latin:keyLabel="!text/label_to_symbol_key"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional" />
+ latin:parentStyle="baseForLayoutSwitchKeyStyle" />
<key-style
latin:styleName="comKeyStyle"
latin:keyLabel="!text/keylabel_for_popular_domain"
diff --git a/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml b/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml
index d486b9df0..b11bbba1b 100644
--- a/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml
+++ b/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml
@@ -52,8 +52,8 @@
latin:keyStyle="hasShiftedLetterHintStyle" />
<Key
latin:keyLabel="3"
- latin:keyHintLabel="#"
- latin:additionalMoreKeys="#"
+ latin:keyHintLabel="\#"
+ latin:additionalMoreKeys="\#"
latin:moreKeys="!text/more_keys_for_symbols_3"
latin:keyStyle="hasShiftedLetterHintStyle" />
<Key
diff --git a/java/res/xml-sw600dp/rowkeys_symbols2.xml b/java/res/xml-sw600dp/rowkeys_symbols2.xml
index d7067e0cf..7d7dcfe31 100644
--- a/java/res/xml-sw600dp/rowkeys_symbols2.xml
+++ b/java/res/xml-sw600dp/rowkeys_symbols2.xml
@@ -34,7 +34,7 @@
</case>
<default>
<Key
- latin:keyLabel="#" />
+ latin:keyLabel="\#" />
</default>
</switch>
<Key
@@ -49,9 +49,9 @@
<!-- U+066B: "٫" ARABIC DECIMAL SEPARATOR -->
<Key
latin:keyLabel="&#x066B;"
- latin:keyHintLabel="#"
+ latin:keyHintLabel="\#"
latin:keyLabelFlags="hasPopupHint|hasShiftedLetterHint"
- latin:moreKeys="#" />
+ latin:moreKeys="\#" />
</case>
<default>
<Key
diff --git a/java/res/xml-sw600dp/rows_mongolian.xml b/java/res/xml-sw600dp/rows_mongolian.xml
new file mode 100644
index 000000000..cfd8c8c39
--- /dev/null
+++ b/java/res/xml-sw600dp/rows_mongolian.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <include
+ latin:keyboardLayout="@xml/key_styles_common" />
+ <Row
+ latin:keyWidth="8.182%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_mongolian1"
+ latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+ <Key
+ latin:keyStyle="deleteKeyStyle"
+ latin:keyWidth="fillRight" />
+ </Row>
+ <Row
+ latin:keyWidth="8.182%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_mongolian2" />
+ <Key
+ latin:keyStyle="enterKeyStyle"
+ latin:keyWidth="fillRight" />
+ </Row>
+ <Row
+ latin:keyWidth="8.182%p"
+ >
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="10.0%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_mongolian3" />
+ <include
+ latin:keyboardLayout="@xml/keys_comma_period" />
+ </Row>
+ <include
+ latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/res/xml-sw600dp/rows_number_normal.xml b/java/res/xml-sw600dp/rows_number_normal.xml
index f69239456..37bf2e808 100644
--- a/java/res/xml-sw600dp/rows_number_normal.xml
+++ b/java/res/xml-sw600dp/rows_number_normal.xml
@@ -151,7 +151,7 @@
latin:keyLabel="0"
latin:keyStyle="numKeyStyle" />
<Key
- latin:keyLabel="#"
+ latin:keyLabel="\#"
latin:keyStyle="numKeyStyle" />
<!-- Note: This Spacer prevents the above key from being marked as a right edge key. -->
<Spacer
diff --git a/java/res/xml-sw600dp/rows_phone.xml b/java/res/xml-sw600dp/rows_phone.xml
index dcc4fde7d..c4799bbcd 100644
--- a/java/res/xml-sw600dp/rows_phone.xml
+++ b/java/res/xml-sw600dp/rows_phone.xml
@@ -116,7 +116,7 @@
<Key
latin:keyStyle="num0KeyStyle" />
<Key
- latin:keyLabel="#"
+ latin:keyLabel="\#"
latin:keyStyle="numKeyStyle" />
</Row>
</merge>
diff --git a/java/res/xml-sw768dp/key_styles_common.xml b/java/res/xml-sw768dp/key_styles_common.xml
index 537e76800..4d10f5b60 100644
--- a/java/res/xml-sw768dp/key_styles_common.xml
+++ b/java/res/xml-sw768dp/key_styles_common.xml
@@ -144,33 +144,30 @@
</default>
</switch>
<key-style
- latin:styleName="toSymbolKeyStyle"
- latin:code="!code/key_switch_alpha_symbol"
- latin:keyLabel="!text/label_to_symbol_key"
+ latin:styleName="baseForLayoutSwitchKeyStyle"
latin:keyLabelFlags="fontNormal|preserveCase"
latin:keyActionFlags="noKeyPreview"
latin:backgroundType="functional" />
<key-style
+ latin:styleName="toSymbolKeyStyle"
+ latin:code="!code/key_switch_alpha_symbol"
+ latin:keyLabel="!text/label_to_symbol_key"
+ latin:parentStyle="baseForLayoutSwitchKeyStyle" />
+ <key-style
latin:styleName="toAlphaKeyStyle"
latin:code="!code/key_switch_alpha_symbol"
latin:keyLabel="!text/label_to_alpha_key"
- latin:keyLabelFlags="fontNormal|preserveCase"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional" />
+ latin:parentStyle="baseForLayoutSwitchKeyStyle" />
<key-style
latin:styleName="toMoreSymbolKeyStyle"
latin:code="!code/key_shift"
latin:keyLabel="!text/label_to_more_symbol_for_tablet_key"
- latin:keyLabelFlags="fontNormal"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional" />
+ latin:parentStyle="baseForLayoutSwitchKeyStyle" />
<key-style
latin:styleName="backFromMoreSymbolKeyStyle"
latin:code="!code/key_shift"
latin:keyLabel="!text/label_to_symbol_key"
- latin:keyLabelFlags="fontNormal"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional" />
+ latin:parentStyle="baseForLayoutSwitchKeyStyle" />
<key-style
latin:styleName="comKeyStyle"
latin:keyLabel="!text/keylabel_for_popular_domain"
diff --git a/java/res/xml-sw768dp/rows_mongolian.xml b/java/res/xml-sw768dp/rows_mongolian.xml
new file mode 100644
index 000000000..9afd4e2db
--- /dev/null
+++ b/java/res/xml-sw768dp/rows_mongolian.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <include
+ latin:keyboardLayout="@xml/key_styles_common" />
+ <Row
+ latin:keyWidth="7.375%p"
+ >
+ <Key
+ latin:keyStyle="tabKeyStyle"
+ latin:keyLabelFlags="alignLeft"
+ latin:keyWidth="7.969%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_mongolian1"
+ latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+ <Key
+ latin:keyStyle="deleteKeyStyle"
+ latin:keyWidth="fillRight" />
+ </Row>
+ <Row
+ latin:keyWidth="7.227%p"
+ >
+ <Key
+ latin:keyStyle="toSymbolKeyStyle"
+ latin:keyLabelFlags="alignLeft"
+ latin:keyWidth="11.172%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_mongolian2" />
+ <Key
+ latin:keyStyle="enterKeyStyle"
+ latin:keyWidth="fillRight" />
+ </Row>
+ <Row
+ latin:keyWidth="7.000%p"
+ >
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="13.829%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_mongolian3" />
+ <include
+ latin:keyboardLayout="@xml/keys_comma_period" />
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="fillRight" />
+ </Row>
+ <include
+ latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/res/xml-sw768dp/rows_number_normal.xml b/java/res/xml-sw768dp/rows_number_normal.xml
index d4d7c722a..de49aba91 100644
--- a/java/res/xml-sw768dp/rows_number_normal.xml
+++ b/java/res/xml-sw768dp/rows_number_normal.xml
@@ -166,7 +166,7 @@
latin:keyLabel="0"
latin:keyStyle="numKeyStyle" />
<Key
- latin:keyLabel="#"
+ latin:keyLabel="\#"
latin:keyStyle="numKeyStyle" />
<!-- Note: This Spacer prevents the above key from being marked as a right edge key. -->
<Spacer
diff --git a/java/res/xml-sw768dp/rows_phone.xml b/java/res/xml-sw768dp/rows_phone.xml
index 2f718db62..d06a63b2c 100644
--- a/java/res/xml-sw768dp/rows_phone.xml
+++ b/java/res/xml-sw768dp/rows_phone.xml
@@ -132,7 +132,7 @@
<Key
latin:keyStyle="num0KeyStyle" />
<Key
- latin:keyLabel="#"
+ latin:keyLabel="\#"
latin:keyStyle="numKeyStyle" />
</Row>
</merge>
diff --git a/java/res/layout/suggestion_preview.xml b/java/res/xml/kbd_mongolian.xml
index 856447bba..1d0352175 100644
--- a/java/res/layout/suggestion_preview.xml
+++ b/java/res/xml/kbd_mongolian.xml
@@ -2,9 +2,9 @@
<!--
/*
**
-** Copyright 2011, The Android Open Source Project
+** Copyright 2012, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
+** 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
**
@@ -18,11 +18,9 @@
*/
-->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="18dp"
- android:textColor="?android:attr/textColorPrimaryInverse"
- android:minWidth="32dp"
- android:gravity="center"
- style="?attr/suggestionPreviewBackgroundStyle" />
+<Keyboard
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <include
+ latin:keyboardLayout="@xml/rows_mongolian" />
+</Keyboard>
diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml
index 162119dab..91ebac1da 100644
--- a/java/res/xml/key_styles_common.xml
+++ b/java/res/xml/key_styles_common.xml
@@ -134,52 +134,50 @@
latin:code="!code/key_tab"
latin:keyIcon="!icon/tab_key"
latin:keyIconPreview="!icon/tab_key_preview" />
+ <key-style
+ latin:styleName="baseForLayoutSwitchKeyStyle"
+ latin:keyLabelFlags="preserveCase"
+ latin:keyActionFlags="noKeyPreview"
+ latin:backgroundType="functional" />
<switch>
<!-- When this qwerty keyboard has no shortcut keys but shortcut key is enabled, then symbol
keyboard will have a shortcut key. That means we should use label_to_symbol_key label
and shortcut_for_label icon. -->
<case
- latin:shortcutKeyEnabled="true"
- latin:hasShortcutKey="false"
+ latin:shortcutKeyOnSymbols="true"
>
<key-style
- latin:styleName="toSymbolKeyStyle"
- latin:code="!code/key_switch_alpha_symbol"
+ latin:styleName="baseForToSymbolKeyStyle"
latin:keyIcon="!icon/shortcut_for_label"
latin:keyLabel="!text/label_to_symbol_with_microphone_key"
latin:keyLabelFlags="withIconRight|preserveCase"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional" />
+ latin:parentStyle="baseForLayoutSwitchKeyStyle" />
</case>
<default>
<key-style
- latin:styleName="toSymbolKeyStyle"
- latin:code="!code/key_switch_alpha_symbol"
+ latin:styleName="baseForToSymbolKeyStyle"
latin:keyLabel="!text/label_to_symbol_key"
- latin:keyLabelFlags="preserveCase"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional" />
+ latin:parentStyle="baseForLayoutSwitchKeyStyle" />
</default>
</switch>
<key-style
+ latin:styleName="toSymbolKeyStyle"
+ latin:code="!code/key_switch_alpha_symbol"
+ latin:parentStyle="baseForToSymbolKeyStyle" />
+ <key-style
latin:styleName="toAlphaKeyStyle"
latin:code="!code/key_switch_alpha_symbol"
latin:keyLabel="!text/label_to_alpha_key"
- latin:keyLabelFlags="preserveCase"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional" />
+ latin:parentStyle="baseForLayoutSwitchKeyStyle" />
<key-style
latin:styleName="toMoreSymbolKeyStyle"
latin:code="!code/key_shift"
latin:keyLabel="!text/label_to_more_symbol_key"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional" />
+ latin:parentStyle="baseForLayoutSwitchKeyStyle" />
<key-style
latin:styleName="backFromMoreSymbolKeyStyle"
latin:code="!code/key_shift"
- latin:keyLabel="!text/label_to_symbol_key"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional" />
+ latin:parentStyle="baseForToSymbolKeyStyle" />
<key-style
latin:styleName="punctuationKeyStyle"
latin:keyLabel="."
diff --git a/java/res/xml/key_styles_currency.xml b/java/res/xml/key_styles_currency.xml
index 6dea16f89..76fe0e6b0 100644
--- a/java/res/xml/key_styles_currency.xml
+++ b/java/res/xml/key_styles_currency.xml
@@ -28,7 +28,7 @@
<include
latin:keyboardLayout="@xml/key_styles_currency_dollar" />
</case>
- <!-- Countries using Euro currency, 23 countries as for January 2011. -->
+ <!-- Countries using Euro currency, 23 countries as of November 2012.
1. Andorra (ca_AD, ca_ES)
2. Austria (de_AT)
3. Belgium (nl_BE, fr_BE, de_BE)
@@ -40,80 +40,77 @@
9. Greece (el_GR)
10. Ireland (ga_IE, en_IE)
11. Italy (it_IT)
- 12. Kosovo (??_XK) ??
+ 12. Kosovo (sq_XK, sr_XK)
13. Luxembourg (lb_LU, fr_LU, de_LU)
14. Malta (mt_MT, en_MT)
15. Monaco (fr_MO)
- 16. Montenegro (sla_ME)
+ 16. Montenegro (??_ME)
17. Netherlands (nl_NL)
18. Portugal (pt_PT)
19. San Marino (it_SM)
20. Slovakia (sk_SK)
21. Slovenia (sl_SI)
22. Spain (es_ES, ca_ES)
- 23. Vatican City (it_VA)
- -->
- <!-- Though Denmark and Turkey don't using Euro as their currencies, but having Euro sign on
- the symbol keyboard might be useful. Especially Danish krone (kr) and Turkish lira
- (TL) can be represented by usual alphabet letters. -->
- <!-- Note: Some locales may not have country code, and it it supposed to indicate the
- country where the language originally/mainly spoken. -->
+ 23. Vatican City (it_VA) -->
<case
- latin:localeCode="da|de|es|el|fi|fr|it|nl|sk|sl|pt_PT|tr"
+ latin:countryCode="AD|AT|BE|CY|EE|FI|FR|DE|GR|IE|IT|XK|LU|MT|MO|ME|NL|PT|SM|SK|SI|ES|VA"
>
<include
latin:keyboardLayout="@xml/key_styles_currency_euro" />
</case>
+ <!-- Note: Some subtype locale may not have country code, and it it supposed to indicate the
+ country where the language originally/mainly spoken. -->
+ <!-- Though Denmark, Sweden and Turkey don't use Euro as their currency, having the Euro
+ sign on the symbol keyboard might be useful. Especially Danish krone (kr), Swedish
+ krona (kr) and Turkish lira (TL) can be represented by usual alphabet letters. -->
+ <!-- TODO: The currency sign of Turkish Lira was created in 2012 and assigned U+20BA for
+ its unicode, although there is no font glyph for it as of November 2012. -->
+ <!-- da: Denmark (da_DK)
+ de: Germany (de_DE)
+ es: Spain (es_ES)
+ fi: Finland (fi_FI)
+ fr: France(fr_FR)
+ it: Italy (it_IT)
+ nl: Netherlands (nl_NL)
+ sk: Slovakia (sk_SK)
+ sl: Slovenia (sl_SL)
+ sv: Sweden (sv_SV)
+ tr: Trukey (tr_TR) -->
<case
- latin:languageCode="ca|et|lb|mt|sla"
+ latin:localeCode="da|de|es|el|fi|fr|it|nl|sk|sl|sv|tr"
>
<include
latin:keyboardLayout="@xml/key_styles_currency_euro" />
</case>
+ <!-- ca: Catalan (Andorra, Spain)
+ et: Estonian (Estonia)
+ lb: Luxembougish (Luxembourg)
+ mt: Maltese (Malta) -->
<case
- latin:countryCode="AD|AT|BE|CY|EE|FI|FR|DE|GR|IE|IT|XK|LU|MT|MO|ME|NL|PT|SM|SK|SI|ES|VA"
+ latin:languageCode="ca|et|lb|mt"
>
<include
latin:keyboardLayout="@xml/key_styles_currency_euro" />
</case>
+ <!-- fa: Persian (Rial and Afgahni)
+ hi: Hindi (Indian Rupee)
+ iw: Hebrew (New Sheqel)
+ mn: Mongolian (Tugrik)
+ th: Thai (Baht)
+ uk: Ukrainian (Hryvnia)
+ vi: Vietnamese (Dong) -->
+ <!-- TODO: The currency sign of Turkish Lira was created in 2012 and assigned U+20BA for
+ its unicode, although there is no font glyph for it as of November 2012. -->
<case
- latin:languageCode="iw"
- >
- <!-- U+20AA: "₪" NEW SHEQEL SIGN
- U+00A3: "£" POUND SIGN
- U+20AC: "€" EURO SIGN
- U+00A2: "¢" CENT SIGN -->
- <key-style
- latin:styleName="currencyKeyStyle"
- latin:keyLabel="&#x20AA;"
- latin:moreKeys="!text/more_keys_for_currency_general" />
- <key-style
- latin:styleName="moreCurrency1KeyStyle"
- latin:keyLabel="&#x00A3;" />
- <key-style
- latin:styleName="moreCurrency2KeyStyle"
- latin:keyLabel="&#x20AC;" />
- <key-style
- latin:styleName="moreCurrency3KeyStyle"
- latin:keyLabel="$"
- latin:moreKeys="&#x00A2;" />
- <key-style
- latin:styleName="moreCurrency4KeyStyle"
- latin:keyLabel="&#x00A2;" />
- </case>
- <case
- latin:languageCode="fa"
+ latin:languageCode="fa|hi|iw|mn|th|uk|vi"
>
- <!-- U+FDFC: "﷼" RIAL SIGN
- U+060B: "؋" AFGHANI SIGN
- U+00A3: "£" POUND SIGN
+ <!-- U+00A3: "£" POUND SIGN
U+20AC: "€" EURO SIGN
U+00A2: "¢" CENT SIGN -->
- <!-- TODO: DroidSansArabic lacks the glyph of U+FCDC: RIAL SIGN -->
<key-style
latin:styleName="currencyKeyStyle"
- latin:keyLabel="&#xFDFC;"
- latin:moreKeys="!text/more_keys_for_currency_general,&#x060B;" />
+ latin:keyLabel="!text/keylabel_for_currency_generic"
+ latin:moreKeys="!text/more_keys_for_currency_generic" />
<key-style
latin:styleName="moreCurrency1KeyStyle"
latin:keyLabel="&#x00A3;" />
@@ -128,18 +125,19 @@
latin:styleName="moreCurrency4KeyStyle"
latin:keyLabel="&#x00A2;" />
</case>
- <!-- United Kingdom -->
+ <!-- GB: United Kingdom (Pound) -->
<case
latin:countryCode="GB"
>
<!-- U+00A3: "£" POUND SIGN
U+20AC: "€" EURO SIGN
U+00A5: "¥" YEN SIGN
- U+00A2: "¢" CENT SIGN -->
+ U+00A2: "¢" CENT SIGN
+ U+20B1: "₱" PESO SIGN -->
<key-style
latin:styleName="currencyKeyStyle"
latin:keyLabel="&#x00A3;"
- latin:moreKeys="!text/more_keys_for_currency_pound" />
+ latin:moreKeys="&#x00A2;,$,&#x20AC;,&#x00A5;,&#x20B1;" />
<key-style
latin:styleName="moreCurrency1KeyStyle"
latin:keyLabel="&#x20AC;" />
@@ -154,6 +152,7 @@
latin:styleName="moreCurrency4KeyStyle"
latin:keyLabel="&#x00A2;" />
</case>
+ <!-- ar: Arabic (Dollar and Rial) -->
<default>
<include
latin:keyboardLayout="@xml/key_styles_currency_dollar" />
diff --git a/java/res/xml/key_styles_currency_euro.xml b/java/res/xml/key_styles_currency_euro.xml
index 686fb3033..c1b5e0384 100644
--- a/java/res/xml/key_styles_currency_euro.xml
+++ b/java/res/xml/key_styles_currency_euro.xml
@@ -20,13 +20,14 @@
<merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
<!-- U+20AC: "€" EURO SIGN
+ U+00A2: "¢" CENT SIGN
U+00A3: "£" POUND SIGN
U+00A5: "¥" YEN SIGN
- U+00A2: "¢" CENT SIGN -->
+ U+20B1: "₱" PESO SIGN -->
<key-style
latin:styleName="currencyKeyStyle"
latin:keyLabel="&#x20AC;"
- latin:moreKeys="!text/more_keys_for_currency_euro" />
+ latin:moreKeys="&#x00A2;,&#x00A3;,$,&#x00A5;,&#x20B1;" />
<key-style
latin:styleName="moreCurrency1KeyStyle"
latin:keyLabel="&#x00A3;" />
diff --git a/java/res/xml/keyboard_layout_set_mongolian.xml b/java/res/xml/keyboard_layout_set_mongolian.xml
new file mode 100644
index 000000000..2d364f682
--- /dev/null
+++ b/java/res/xml/keyboard_layout_set_mongolian.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<KeyboardLayoutSet
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Element
+ latin:elementName="alphabet"
+ latin:elementKeyboard="@xml/kbd_mongolian"
+ latin:enableProximityCharsCorrection="true" />
+ <Element
+ latin:elementName="symbols"
+ latin:elementKeyboard="@xml/kbd_symbols" />
+ <Element
+ latin:elementName="symbolsShifted"
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
+ <Element
+ latin:elementName="phone"
+ latin:elementKeyboard="@xml/kbd_phone" />
+ <Element
+ latin:elementName="phoneSymbols"
+ latin:elementKeyboard="@xml/kbd_phone_symbols" />
+ <Element
+ latin:elementName="number"
+ latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardLayoutSet>
diff --git a/java/res/xml/keys_pcqwerty_symbols1.xml b/java/res/xml/keys_pcqwerty_symbols1.xml
index bf48b1f17..2364e1087 100644
--- a/java/res/xml/keys_pcqwerty_symbols1.xml
+++ b/java/res/xml/keys_pcqwerty_symbols1.xml
@@ -32,7 +32,7 @@
<Key
latin:keyLabel="\@" />
<Key
- latin:keyLabel="#" />
+ latin:keyLabel="\#" />
<Key
latin:keyLabel="$" />
<!-- U+2030: "‰" PER MILLE SIGN -->
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index 038707134..aa59c577c 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -37,6 +37,7 @@
eo: Esperanto/spanish
es: Spanish/spanish
es_US: Spanish United States/spanish
+ (es_419: Spanish Latin America/qwerty)
et: Estonian/nordic
fa: Persian/arabic
fi: Finnish/nordic
@@ -54,6 +55,7 @@
lt: Lithuanian/qwerty
lv: Latvian/qwerty
mk: Macedonian/south_slavic
+ mn: Mongolian/mongolian
ms: Malay/qwerty
nb: Norwegian Bokmål/nordic
nl: Dutch/qwerty
@@ -87,161 +89,170 @@
android:isDefault="@bool/im_is_default">
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_en_US"
- android:subtypeId="-921088104"
+ android:subtypeId="0xc9194f98"
android:imeSubtypeLocale="en_US"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_en_GB"
- android:subtypeId="-1337596075"
+ android:subtypeId="0xb045e755"
android:imeSubtypeLocale="en_GB"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="1872175968"
+ android:subtypeId="0x6f972360"
android:imeSubtypeLocale="af"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="1494081088"
+ android:subtypeId="0x590dde40"
android:imeSubtypeLocale="ar"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="499361881"
+ android:subtypeId="0x1dc3a859"
android:imeSubtypeLocale="be"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="195674344"
+ android:subtypeId="0x0ba9c0e8"
android:imeSubtypeLocale="bg"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=bulgarian"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_bulgarian_bds"
- android:subtypeId="1599191706"
+ android:subtypeId="0x5f51ba9a"
android:imeSubtypeLocale="bg"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=bulgarian_bds"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-756735787"
+ android:subtypeId="0xd2e520d5"
android:imeSubtypeLocale="ca"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="758984400"
+ android:subtypeId="0x2d3d2ed0"
android:imeSubtypeLocale="cs"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="770990173"
+ android:subtypeId="0x2df4605d"
android:imeSubtypeLocale="da"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="774684257"
+ android:subtypeId="0x2e2cbe61"
android:imeSubtypeLocale="de"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="242746067"
+ android:subtypeId="0x0e7802d3"
android:imeSubtypeLocale="el"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=greek"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="1083200842"
+ android:subtypeId="0x4090554a"
android:imeSubtypeLocale="eo"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="816242702"
+ android:subtypeId="0x30a6e00e"
android:imeSubtypeLocale="es"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-2066550842"
+ android:subtypeId="0x84d2efc6"
android:imeSubtypeLocale="es_US"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable"
/>
+ <!--
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-332580523"
+ android:subtypeId="0x623f9286"
+ android:imeSubtypeLocale="es_419"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable"
+ />
+ -->
+ <subtype android:icon="@drawable/ic_subtype_keyboard"
+ android:label="@string/subtype_generic"
+ android:subtypeId="0xec2d3955"
android:imeSubtypeLocale="et"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=nordic,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-1100561836"
+ android:subtypeId="0xbe66c254"
android:imeSubtypeLocale="fa"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=farsi"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="835636643"
+ android:subtypeId="0x31cecda3"
android:imeSubtypeLocale="fi"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="843948332"
+ android:subtypeId="0x324da12c"
android:imeSubtypeLocale="fr"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-354699631"
+ android:subtypeId="0xeadbb691"
android:imeSubtypeLocale="fr_CA"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="963984255"
+ android:subtypeId="0x39753b7f"
android:imeSubtypeLocale="hi"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=hindi"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="901206634"
+ android:subtypeId="0x35b7526a"
android:imeSubtypeLocale="hr"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="903977197"
+ android:subtypeId="0x35e198ed"
android:imeSubtypeLocale="hu"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
@@ -249,21 +260,21 @@
<!-- Java uses the deprecated "in" code instead of the standard "id" code for Indonesian. -->
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="2108597344"
+ android:subtypeId="0x7daea460"
android:imeSubtypeLocale="in"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="2113214949"
+ android:subtypeId="0x7df519e5"
android:imeSubtypeLocale="is"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="931682827"
+ android:subtypeId="0x37885a0b"
android:imeSubtypeLocale="it"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
@@ -271,126 +282,133 @@
<!-- Java uses the deprecated "iw" code instead of the standard "he" code for Hebrew. -->
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="1727731901"
+ android:subtypeId="0x66fb18bd"
android:imeSubtypeLocale="iw"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="1846648426"
+ android:subtypeId="0x6e119e6a"
android:imeSubtypeLocale="ka"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=georgian"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="775494660"
+ android:subtypeId="0x2e391c04"
android:imeSubtypeLocale="ky"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-2094941373"
+ android:subtypeId="0x8321bb43"
android:imeSubtypeLocale="lt"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-2093094331"
+ android:subtypeId="0x833dea45"
android:imeSubtypeLocale="lv"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-1353667716"
+ android:subtypeId="0xaf50ab7c"
android:imeSubtypeLocale="mk"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=south_slavic"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-2067235743"
+ android:subtypeId="0xcdcfc3ab"
+ android:imeSubtypeLocale="mn"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=mongolian"
+ />
+ <subtype android:icon="@drawable/ic_subtype_keyboard"
+ android:label="@string/subtype_generic"
+ android:subtypeId="0x84c87c61"
android:imeSubtypeLocale="ms"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="1058205204"
+ android:subtypeId="0x3f12ee14"
android:imeSubtypeLocale="nb"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="1067440414"
+ android:subtypeId="0x3f9fd91e"
android:imeSubtypeLocale="nl"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="1343007020"
+ android:subtypeId="0x500ca92c"
android:imeSubtypeLocale="nl_BE"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=azerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="1124698716"
+ android:subtypeId="0x43098a5c"
android:imeSubtypeLocale="pl"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-889195354"
+ android:subtypeId="0xcafff4a6"
android:imeSubtypeLocale="pt_BR"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-486540198"
+ android:subtypeId="0xe2fffc5a"
android:imeSubtypeLocale="pt_PT"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-1927784072"
+ android:subtypeId="0x8d185978"
android:imeSubtypeLocale="ro"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="1983547218"
+ android:subtypeId="0x763a8752"
android:imeSubtypeLocale="ru"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-1902849005"
+ android:subtypeId="0x8e94d413"
android:imeSubtypeLocale="sk"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-1901925484"
+ android:subtypeId="0x8ea2eb94"
android:imeSubtypeLocale="sl"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="2009405806"
+ android:subtypeId="0x77c5196e"
android:imeSubtypeLocale="sr"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
@@ -398,14 +416,14 @@
<!-- TODO: Uncomment once we can handle IETF language tag with script name specified.
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_serbian_cyrillic"
- android:subtypeId="XXXXXX"
+ android:subtypeId="0xXXXXXXXX"
android:imeSubtypeLocale="sr"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_serbian_latin"
- android:subtypeId="XXXXXX"
+ android:subtypeId="0xXXXXXXXX"
android:imeSubtypeLocale="sr-Latn"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
@@ -413,63 +431,63 @@
-->
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="1219821379"
+ android:subtypeId="0x48b4ff43"
android:imeSubtypeLocale="sv"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-1891766753"
+ android:subtypeId="0x8f3dee1f"
android:imeSubtypeLocale="sw"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="529847764"
+ android:subtypeId="0x1f94d5d4"
android:imeSubtypeLocale="th"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=thai"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-259881489"
+ android:subtypeId="0xf08285ef"
android:imeSubtypeLocale="tl"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="1244756446"
+ android:subtypeId="0x4a3179de"
android:imeSubtypeLocale="tr"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="1048856876"
+ android:subtypeId="0x3e84492c"
android:imeSubtypeLocale="uk"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-1818808594"
+ android:subtypeId="0x93972eee"
android:imeSubtypeLocale="vi"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
- android:subtypeId="-1693209738"
+ android:subtypeId="0x9b13ab76"
android:imeSubtypeLocale="zu"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_no_language_qwerty"
- android:subtypeId="-1573262419"
+ android:subtypeId="0xa239ebad"
android:imeSubtypeLocale="zz"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EnabledWhenDefaultIsNotAsciiCapable"
diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml
index 9172b2415..4ffbf14d5 100644
--- a/java/res/xml/prefs.xml
+++ b/java/res/xml/prefs.xml
@@ -119,6 +119,12 @@
android:persistent="true"
android:defaultValue="true" />
<CheckBoxPreference
+ android:key="pref_key_use_double_space_period"
+ android:title="@string/use_double_space_period"
+ android:summary="@string/use_double_space_period_summary"
+ android:persistent="true"
+ android:defaultValue="true" />
+ <CheckBoxPreference
android:key="pref_show_language_switch_key"
android:title="@string/show_language_switch_key"
android:summary="@string/show_language_switch_key_summary"
diff --git a/java/res/xml/rowkeys_mongolian1.xml b/java/res/xml/rowkeys_mongolian1.xml
new file mode 100644
index 000000000..6c8c8e2fd
--- /dev/null
+++ b/java/res/xml/rowkeys_mongolian1.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+0444: "ф" CYRILLIC SMALL LETTER EF -->
+ <Key
+ latin:keyLabel="&#x0444;"
+ latin:keyHintLabel="1"
+ latin:additionalMoreKeys="1" />
+ <!-- U+0446: "ц" CYRILLIC SMALL LETTER TSE -->
+ <Key
+ latin:keyLabel="&#x0446;"
+ latin:keyHintLabel="2"
+ latin:additionalMoreKeys="2" />
+ <!-- U+0443: "у" CYRILLIC SMALL LETTER U -->
+ <Key
+ latin:keyLabel="&#x0443;"
+ latin:keyHintLabel="3"
+ latin:additionalMoreKeys="3"
+ latin:moreKeys="!text/more_keys_for_cyrillic_u" />
+ <!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE -->
+ <Key
+ latin:keyLabel="&#x0436;"
+ latin:keyHintLabel="4"
+ latin:additionalMoreKeys="4" />
+ <!-- U+044D: "э" CYRILLIC SMALL LETTER E -->
+ <Key
+ latin:keyLabel="&#x044D;"
+ latin:keyHintLabel="5"
+ latin:additionalMoreKeys="5"
+ latin:moreKeys="!text/more_keys_for_cyrillic_ie" />
+ <!-- U+043D: "н" CYRILLIC SMALL LETTER EN -->
+ <Key
+ latin:keyLabel="&#x043D;"
+ latin:keyHintLabel="6"
+ latin:additionalMoreKeys="6"
+ latin:moreKeys="!text/more_keys_for_cyrillic_en" />
+ <!-- U+0433: "г" CYRILLIC SMALL LETTER GHE -->
+ <Key
+ latin:keyLabel="&#x0433;"
+ latin:keyHintLabel="7"
+ latin:additionalMoreKeys="7"
+ latin:moreKeys="!text/more_keys_for_cyrillic_ghe" />
+ <!-- U+0448: "ш" CYRILLIC SMALL LETTER SHA
+ U+0449: "щ" CYRILLIC SMALL LETTER SHCHA -->
+ <Key
+ latin:keyLabel="&#x0448;"
+ latin:keyHintLabel="8"
+ latin:additionalMoreKeys="8"
+ latin:moreKeys="&#x0449;" />
+ <!-- U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U -->
+ <Key
+ latin:keyLabel="&#x04AF;"
+ latin:keyHintLabel="9"
+ latin:additionalMoreKeys="9" />
+ <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE -->
+ <Key
+ latin:keyLabel="&#x0437;"
+ latin:keyHintLabel="0"
+ latin:additionalMoreKeys="0" />
+ <!-- U+043A: "к" CYRILLIC SMALL LETTER KA -->
+ <Key
+ latin:keyLabel="&#x043A;" />
+</merge>
diff --git a/java/res/xml/rowkeys_mongolian2.xml b/java/res/xml/rowkeys_mongolian2.xml
new file mode 100644
index 000000000..a8aa00620
--- /dev/null
+++ b/java/res/xml/rowkeys_mongolian2.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+0439: "й" CYRILLIC SMALL LETTER SHORT I -->
+ <Key
+ latin:keyLabel="&#x0439;" />
+ <!-- U+044B: "ы" CYRILLIC SMALL LETTER YERU -->
+ <Key
+ latin:keyLabel="&#x044B;" />
+ <!-- U+0431: "б" CYRILLIC SMALL LETTER BE -->
+ <Key
+ latin:keyLabel="&#x0431;" />
+ <!-- U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O -->
+ <Key
+ latin:keyLabel="&#x04E9;" />
+ <!-- U+0430: "а" CYRILLIC SMALL LETTER A -->
+ <Key
+ latin:keyLabel="&#x0430;" />
+ <!-- U+0445: "х" CYRILLIC SMALL LETTER HA -->
+ <Key
+ latin:keyLabel="&#x0445;" />
+ <!-- U+0440: "р" CYRILLIC SMALL LETTER ER -->
+ <Key
+ latin:keyLabel="&#x0440;" />
+ <!-- U+043E: "о" CYRILLIC SMALL LETTER O -->
+ <Key
+ latin:keyLabel="&#x043E;" />
+ <!-- U+043B: "л" CYRILLIC SMALL LETTER EL -->
+ <Key
+ latin:keyLabel="&#x043B;" />
+ <!-- U+0434: "д" CYRILLIC SMALL LETTER DE -->
+ <Key
+ latin:keyLabel="&#x0434;" />
+ <!-- U+043F: "п" CYRILLIC SMALL LETTER PE -->
+ <Key
+ latin:keyLabel="&#x043F;" />
+</merge>
diff --git a/java/res/xml/rowkeys_mongolian3.xml b/java/res/xml/rowkeys_mongolian3.xml
new file mode 100644
index 000000000..dc80c37ab
--- /dev/null
+++ b/java/res/xml/rowkeys_mongolian3.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+044F: "я" CYRILLIC SMALL LETTER YA -->
+ <Key
+ latin:keyLabel="&#x044F;" />
+ <!-- U+0447: "ч" CYRILLIC SMALL LETTER CHE -->
+ <Key
+ latin:keyLabel="&#x0447;" />
+ <!-- U+0451: "ё" CYRILLIC SMALL LETTER IO
+ U+0435: "е" CYRILLIC SMALL LETTER IE -->
+ <Key
+ latin:keyLabel="&#x0451;"
+ latin:moreKeys="&#x0435;" />
+ <!-- U+0441: "с" CYRILLIC SMALL LETTER ES -->
+ <Key
+ latin:keyLabel="&#x0441;" />
+ <!-- U+043C: "м" CYRILLIC SMALL LETTER EM -->
+ <Key
+ latin:keyLabel="&#x043C;" />
+ <!-- U+0438: "и" CYRILLIC SMALL LETTER I -->
+ <Key
+ latin:keyLabel="&#x0438;" />
+ <!-- U+0442: "т" CYRILLIC SMALL LETTER TE -->
+ <Key
+ latin:keyLabel="&#x0442;" />
+ <!-- U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN
+ U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN -->
+ <Key
+ latin:keyLabel="&#x044C;"
+ latin:moreKeys="&#x044A;" />
+ <!-- U+0432: "в" CYRILLIC SMALL LETTER VE
+ U+044E: "ю" CYRILLIC SMALL LETTER YU -->
+ <Key
+ latin:keyLabel="&#x0432;"
+ latin:moreKeys="&#x044E;" />
+</merge>
diff --git a/java/res/xml/rowkeys_pcqwerty1.xml b/java/res/xml/rowkeys_pcqwerty1.xml
index 0ecda3550..b2d1d374b 100644
--- a/java/res/xml/rowkeys_pcqwerty1.xml
+++ b/java/res/xml/rowkeys_pcqwerty1.xml
@@ -41,7 +41,7 @@
latin:moreKeys="!text/more_keys_for_symbols_2" />
<Key
latin:keyLabel="3"
- latin:additionalMoreKeys="#"
+ latin:additionalMoreKeys="\#"
latin:moreKeys="!text/more_keys_for_symbols_3" />
<Key
latin:keyLabel="4"
diff --git a/java/res/xml/rowkeys_symbols2.xml b/java/res/xml/rowkeys_symbols2.xml
index 425e20470..d3c1278da 100644
--- a/java/res/xml/rowkeys_symbols2.xml
+++ b/java/res/xml/rowkeys_symbols2.xml
@@ -33,14 +33,14 @@
latin:moreKeys="\@" />
<Key
latin:keyLabel="&#x066B;"
- latin:keyHintLabel="#"
- latin:moreKeys="#" />
+ latin:keyHintLabel="\#"
+ latin:moreKeys="\#" />
</case>
<default>
<Key
latin:keyLabel="\@" />
<Key
- latin:keyLabel="#" />
+ latin:keyLabel="\#" />
</default>
</switch>
<Key
diff --git a/java/res/xml/rows_mongolian.xml b/java/res/xml/rows_mongolian.xml
new file mode 100644
index 000000000..a6a890a9b
--- /dev/null
+++ b/java/res/xml/rows_mongolian.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <include
+ latin:keyboardLayout="@xml/key_styles_common" />
+ <Row
+ latin:keyWidth="9.091%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_mongolian1" />
+ </Row>
+ <Row
+ latin:keyWidth="9.091%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_mongolian2" />
+ </Row>
+ <Row
+ latin:keyWidth="8.711%p"
+ >
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="10.8%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_mongolian3" />
+ <Key
+ latin:keyStyle="deleteKeyStyle"
+ latin:keyWidth="fillRight" />
+ </Row>
+ <include
+ latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/res/xml/rows_number_normal.xml b/java/res/xml/rows_number_normal.xml
index c59e26247..b77544bc3 100644
--- a/java/res/xml/rows_number_normal.xml
+++ b/java/res/xml/rows_number_normal.xml
@@ -33,6 +33,8 @@
latin:keyStyle="numKeyStyle" />
<Key
latin:keyLabel="-"
+ latin:moreKeys="+"
+ latin:keyLabelFlags="hasPopupHint"
latin:keyStyle="numFunctionalKeyStyle"
latin:keyWidth="fillRight" />
</Row>
diff --git a/java/res/xml/rows_phone.xml b/java/res/xml/rows_phone.xml
index 630b24ea4..9299c2aa5 100644
--- a/java/res/xml/rows_phone.xml
+++ b/java/res/xml/rows_phone.xml
@@ -34,6 +34,8 @@
latin:keyStyle="num3KeyStyle" />
<Key
latin:keyLabel="-"
+ latin:moreKeys="+"
+ latin:keyLabelFlags="hasPopupHint"
latin:keyStyle="numFunctionalKeyStyle"
latin:keyWidth="fillRight" />
</Row>
diff --git a/java/res/xml/rows_phone_symbols.xml b/java/res/xml/rows_phone_symbols.xml
index 7841c56e5..8c10a2d71 100644
--- a/java/res/xml/rows_phone_symbols.xml
+++ b/java/res/xml/rows_phone_symbols.xml
@@ -37,6 +37,8 @@
latin:keyStyle="numKeyStyle" />
<Key
latin:keyLabel="-"
+ latin:moreKeys="+"
+ latin:keyLabelFlags="hasPopupHint"
latin:keyStyle="numFunctionalKeyStyle"
latin:keyWidth="fillRight" />
</Row>
@@ -63,7 +65,7 @@
<Key
latin:keyStyle="numWaitKeyStyle" />
<Key
- latin:keyLabel="#"
+ latin:keyLabel="\#"
latin:keyStyle="numKeyStyle" />
<Key
latin:keyStyle="deleteKeyStyle"
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
index b9b6362fc..0ab84f7b5 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
@@ -36,6 +36,7 @@ import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.CoordinateUtils;
/**
* Exposes a virtual view sub-tree for {@link KeyboardView} and generates
@@ -62,7 +63,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
private final Rect mTempBoundsInScreen = new Rect();
/** The parent view's cached on-screen location. */
- private final int[] mParentLocation = new int[2];
+ private final int[] mParentLocation = CoordinateUtils.newInstance();
/** The virtual view identifier for the focused node. */
private int mAccessibilityFocusedView = UNDEFINED;
@@ -180,7 +181,8 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
// Calculate the key's in-screen bounds.
mTempBoundsInScreen.set(boundsInParent);
- mTempBoundsInScreen.offset(mParentLocation[0], mParentLocation[1]);
+ mTempBoundsInScreen.offset(
+ CoordinateUtils.x(mParentLocation), CoordinateUtils.y(mParentLocation));
final Rect boundsInScreen = mTempBoundsInScreen;
diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
index 32618ad85..b87ae3a15 100644
--- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
+++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
@@ -26,6 +26,7 @@ import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.R;
import java.util.HashMap;
@@ -61,17 +62,19 @@ public final class KeyCodeDescriptionMapper {
mKeyLabelMap.put(":-)", R.string.spoken_description_smiley);
// Special non-character codes defined in Keyboard
- mKeyCodeMap.put(Keyboard.CODE_SPACE, R.string.spoken_description_space);
- mKeyCodeMap.put(Keyboard.CODE_DELETE, R.string.spoken_description_delete);
- mKeyCodeMap.put(Keyboard.CODE_ENTER, R.string.spoken_description_return);
- mKeyCodeMap.put(Keyboard.CODE_SETTINGS, R.string.spoken_description_settings);
- mKeyCodeMap.put(Keyboard.CODE_SHIFT, R.string.spoken_description_shift);
- mKeyCodeMap.put(Keyboard.CODE_SHORTCUT, R.string.spoken_description_mic);
- mKeyCodeMap.put(Keyboard.CODE_SWITCH_ALPHA_SYMBOL, R.string.spoken_description_to_symbol);
- mKeyCodeMap.put(Keyboard.CODE_TAB, R.string.spoken_description_tab);
- mKeyCodeMap.put(Keyboard.CODE_LANGUAGE_SWITCH, R.string.spoken_description_language_switch);
- mKeyCodeMap.put(Keyboard.CODE_ACTION_NEXT, R.string.spoken_description_action_next);
- mKeyCodeMap.put(Keyboard.CODE_ACTION_PREVIOUS, R.string.spoken_description_action_previous);
+ mKeyCodeMap.put(Constants.CODE_SPACE, R.string.spoken_description_space);
+ mKeyCodeMap.put(Constants.CODE_DELETE, R.string.spoken_description_delete);
+ mKeyCodeMap.put(Constants.CODE_ENTER, R.string.spoken_description_return);
+ mKeyCodeMap.put(Constants.CODE_SETTINGS, R.string.spoken_description_settings);
+ mKeyCodeMap.put(Constants.CODE_SHIFT, R.string.spoken_description_shift);
+ mKeyCodeMap.put(Constants.CODE_SHORTCUT, R.string.spoken_description_mic);
+ mKeyCodeMap.put(Constants.CODE_SWITCH_ALPHA_SYMBOL, R.string.spoken_description_to_symbol);
+ mKeyCodeMap.put(Constants.CODE_TAB, R.string.spoken_description_tab);
+ mKeyCodeMap.put(Constants.CODE_LANGUAGE_SWITCH,
+ R.string.spoken_description_language_switch);
+ mKeyCodeMap.put(Constants.CODE_ACTION_NEXT, R.string.spoken_description_action_next);
+ mKeyCodeMap.put(Constants.CODE_ACTION_PREVIOUS,
+ R.string.spoken_description_action_previous);
}
/**
@@ -97,17 +100,17 @@ public final class KeyCodeDescriptionMapper {
boolean shouldObscure) {
final int code = key.mCode;
- if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
+ if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) {
final String description = getDescriptionForSwitchAlphaSymbol(context, keyboard);
if (description != null)
return description;
}
- if (code == Keyboard.CODE_SHIFT) {
+ if (code == Constants.CODE_SHIFT) {
return getDescriptionForShiftKey(context, keyboard);
}
- if (code == Keyboard.CODE_ACTION_ENTER) {
+ if (code == Constants.CODE_ACTION_ENTER) {
return getDescriptionForActionKey(context, keyboard, key);
}
@@ -121,7 +124,7 @@ public final class KeyCodeDescriptionMapper {
}
// Just attempt to speak the description.
- if (key.mCode != Keyboard.CODE_UNSPECIFIED) {
+ if (key.mCode != Constants.CODE_UNSPECIFIED) {
return getDescriptionForKeyCode(context, keyboard, key, shouldObscure);
}
diff --git a/java/src/com/android/inputmethod/annotations/ExternallyReferenced.java b/java/src/com/android/inputmethod/annotations/ExternallyReferenced.java
new file mode 100644
index 000000000..ea5f12ce2
--- /dev/null
+++ b/java/src/com/android/inputmethod/annotations/ExternallyReferenced.java
@@ -0,0 +1,24 @@
+/*
+ * 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.annotations;
+
+/**
+ * Denotes that the class, method or field should not be eliminated by ProGuard,
+ * because it is externally referenced. (See proguard.flags)
+ */
+public @interface ExternallyReferenced {
+}
diff --git a/java/src/com/android/inputmethod/annotations/UsedForTesting.java b/java/src/com/android/inputmethod/annotations/UsedForTesting.java
new file mode 100644
index 000000000..2ada091e4
--- /dev/null
+++ b/java/src/com/android/inputmethod/annotations/UsedForTesting.java
@@ -0,0 +1,24 @@
+/*
+ * 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.annotations;
+
+/**
+ * Denotes that the class, method or field should not be eliminated by ProGuard,
+ * so that unit tests can access it. (See proguard.flags)
+ */
+public @interface UsedForTesting {
+}
diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
index ab7bd4914..8bd1e5208 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
@@ -19,61 +19,21 @@ package com.android.inputmethod.compat;
import android.content.Context;
import android.os.IBinder;
import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.InputMethodSubtype;
-
-import com.android.inputmethod.latin.ImfUtils;
import java.lang.reflect.Method;
-// TODO: Override this class with the concrete implementation if we need to take care of the
-// performance.
public final class InputMethodManagerCompatWrapper {
- private static final String TAG = InputMethodManagerCompatWrapper.class.getSimpleName();
private static final Method METHOD_switchToNextInputMethod = CompatUtils.getMethod(
InputMethodManager.class, "switchToNextInputMethod", IBinder.class, Boolean.TYPE);
- private static final InputMethodManagerCompatWrapper sInstance =
- new InputMethodManagerCompatWrapper();
-
- private InputMethodManager mImm;
-
- private InputMethodManagerCompatWrapper() {
- // This wrapper class is not publicly instantiable.
- }
-
- public static InputMethodManagerCompatWrapper getInstance() {
- if (sInstance.mImm == null) {
- throw new RuntimeException(TAG + ".getInstance() is called before initialization");
- }
- return sInstance;
- }
-
- public static void init(Context context) {
- sInstance.mImm = ImfUtils.getInputMethodManager(context);
- }
-
- public InputMethodSubtype getCurrentInputMethodSubtype() {
- return mImm.getCurrentInputMethodSubtype();
- }
-
- public InputMethodSubtype getLastInputMethodSubtype() {
- return mImm.getLastInputMethodSubtype();
- }
+ public final InputMethodManager mImm;
- public boolean switchToLastInputMethod(IBinder token) {
- return mImm.switchToLastInputMethod(token);
+ public InputMethodManagerCompatWrapper(final Context context) {
+ mImm = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);
}
- public boolean switchToNextInputMethod(IBinder token, boolean onlyCurrentIme) {
+ public boolean switchToNextInputMethod(final IBinder token, final boolean onlyCurrentIme) {
return (Boolean)CompatUtils.invoke(mImm, false, METHOD_switchToNextInputMethod, token,
onlyCurrentIme);
}
-
- public void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) {
- mImm.setInputMethodAndSubtype(token, id, subtype);
- }
-
- public void showInputMethodPicker() {
- mImm.showInputMethodPicker();
- }
}
diff --git a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
index 159f43650..c1609ea28 100644
--- a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
+++ b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
@@ -83,14 +83,13 @@ public final class SuggestionSpanUtils {
}
public static CharSequence getTextWithAutoCorrectionIndicatorUnderline(
- Context context, CharSequence text) {
+ final Context context, final String text) {
if (TextUtils.isEmpty(text) || CONSTRUCTOR_SuggestionSpan == null
|| OBJ_FLAG_AUTO_CORRECTION == null || OBJ_SUGGESTIONS_MAX_SIZE == null
|| OBJ_FLAG_MISSPELLED == null || OBJ_FLAG_EASY_CORRECT == null) {
return text;
}
- final Spannable spannable = text instanceof Spannable
- ? (Spannable) text : new SpannableString(text);
+ final Spannable spannable = new SpannableString(text);
final Object[] args =
{ context, null, new String[] {}, (int)OBJ_FLAG_AUTO_CORRECTION,
(Class<?>) SuggestionSpanPickedNotificationReceiver.class };
@@ -104,28 +103,24 @@ public final class SuggestionSpanUtils {
return spannable;
}
- public static CharSequence getTextWithSuggestionSpan(Context context,
- CharSequence pickedWord, SuggestedWords suggestedWords, boolean dictionaryAvailable) {
+ public static CharSequence getTextWithSuggestionSpan(final Context context,
+ final String pickedWord, final SuggestedWords suggestedWords,
+ final boolean dictionaryAvailable) {
if (!dictionaryAvailable || TextUtils.isEmpty(pickedWord)
|| CONSTRUCTOR_SuggestionSpan == null
- || suggestedWords == null || suggestedWords.size() == 0
- || suggestedWords.mIsPrediction || suggestedWords.mIsPunctuationSuggestions
+ || suggestedWords.isEmpty() || suggestedWords.mIsPrediction
+ || suggestedWords.mIsPunctuationSuggestions
|| OBJ_SUGGESTIONS_MAX_SIZE == null) {
return pickedWord;
}
- final Spannable spannable;
- if (pickedWord instanceof Spannable) {
- spannable = (Spannable) pickedWord;
- } else {
- spannable = new SpannableString(pickedWord);
- }
+ final Spannable spannable = new SpannableString(pickedWord);
final ArrayList<String> suggestionsList = CollectionUtils.newArrayList();
for (int i = 0; i < suggestedWords.size(); ++i) {
if (suggestionsList.size() >= OBJ_SUGGESTIONS_MAX_SIZE) {
break;
}
- final CharSequence word = suggestedWords.getWord(i);
+ final String word = suggestedWords.getWord(i);
if (!TextUtils.equals(pickedWord, word)) {
suggestionsList.add(word.toString());
}
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 30812e8c3..7346a9c38 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -16,11 +16,11 @@
package com.android.inputmethod.keyboard;
-import static com.android.inputmethod.keyboard.Keyboard.CODE_OUTPUT_TEXT;
-import static com.android.inputmethod.keyboard.Keyboard.CODE_SHIFT;
-import static com.android.inputmethod.keyboard.Keyboard.CODE_SWITCH_ALPHA_SYMBOL;
-import static com.android.inputmethod.keyboard.Keyboard.CODE_UNSPECIFIED;
import static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.ICON_UNDEFINED;
+import static com.android.inputmethod.latin.Constants.CODE_OUTPUT_TEXT;
+import static com.android.inputmethod.latin.Constants.CODE_SHIFT;
+import static com.android.inputmethod.latin.Constants.CODE_SWITCH_ALPHA_SYMBOL;
+import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -39,6 +39,7 @@ import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.keyboard.internal.KeyboardParams;
import com.android.inputmethod.keyboard.internal.KeyboardRow;
import com.android.inputmethod.keyboard.internal.MoreKeySpec;
+import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.ResourceUtils;
import com.android.inputmethod.latin.StringUtils;
@@ -453,7 +454,7 @@ public class Key implements Comparable<Key> {
label = "/" + mLabel;
}
return String.format("%s%s %d,%d %dx%d %s/%s/%s",
- Keyboard.printableCode(mCode), label, mX, mY, mWidth, mHeight, mHintLabel,
+ Constants.printableCode(mCode), label, mX, mY, mWidth, mHeight, mHintLabel,
KeyboardIconsSet.getIconName(mIconId), backgroundName(mBackgroundType));
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
index aa683c1d7..0a91284d0 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
@@ -118,7 +118,7 @@ public class KeyDetector {
}
public static String printableCode(Key key) {
- return key != null ? Keyboard.printableCode(key.mCode) : "none";
+ return key != null ? Constants.printableCode(key.mCode) : "none";
}
public static String printableCodes(int[] codes) {
@@ -127,7 +127,7 @@ public class KeyDetector {
for (final int code : codes) {
if (code == Constants.NOT_A_CODE) break;
if (addDelimiter) sb.append(", ");
- sb.append(Keyboard.printableCode(code));
+ sb.append(Constants.printableCode(code));
addDelimiter = true;
}
return "[" + sb + "]";
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index b7c7f415d..a1b1f5dad 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -16,15 +16,13 @@
package com.android.inputmethod.keyboard;
-import android.util.Log;
import android.util.SparseArray;
import com.android.inputmethod.keyboard.internal.KeyVisualAttributes;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.keyboard.internal.KeyboardParams;
import com.android.inputmethod.latin.CollectionUtils;
-
-
+import com.android.inputmethod.latin.Constants;
/**
* Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
@@ -45,46 +43,6 @@ import com.android.inputmethod.latin.CollectionUtils;
* </pre>
*/
public class Keyboard {
- private static final String TAG = Keyboard.class.getSimpleName();
-
- /** Some common keys code. Must be positive.
- * These should be aligned with values/keycodes.xml
- */
- public static final int CODE_ENTER = '\n';
- public static final int CODE_TAB = '\t';
- public static final int CODE_SPACE = ' ';
- public static final int CODE_PERIOD = '.';
- public static final int CODE_DASH = '-';
- public static final int CODE_SINGLE_QUOTE = '\'';
- public static final int CODE_DOUBLE_QUOTE = '"';
- public static final int CODE_QUESTION_MARK = '?';
- public static final int CODE_EXCLAMATION_MARK = '!';
- // TODO: Check how this should work for right-to-left languages. It seems to stand
- // that for rtl languages, a closing parenthesis is a left parenthesis. Is this
- // managed by the font? Or is it a different char?
- public static final int CODE_CLOSING_PARENTHESIS = ')';
- public static final int CODE_CLOSING_SQUARE_BRACKET = ']';
- public static final int CODE_CLOSING_CURLY_BRACKET = '}';
- public static final int CODE_CLOSING_ANGLE_BRACKET = '>';
-
- /** Special keys code. Must be negative.
- * These should be aligned with KeyboardCodesSet.ID_TO_NAME[],
- * KeyboardCodesSet.DEFAULT[] and KeyboardCodesSet.RTL[]
- */
- public static final int CODE_SHIFT = -1;
- public static final int CODE_SWITCH_ALPHA_SYMBOL = -2;
- public static final int CODE_OUTPUT_TEXT = -3;
- public static final int CODE_DELETE = -4;
- public static final int CODE_SETTINGS = -5;
- public static final int CODE_SHORTCUT = -6;
- public static final int CODE_ACTION_ENTER = -7;
- public static final int CODE_ACTION_NEXT = -8;
- public static final int CODE_ACTION_PREVIOUS = -9;
- public static final int CODE_LANGUAGE_SWITCH = -10;
- public static final int CODE_RESEARCH = -11;
- // Code value representing the code is not specified.
- public static final int CODE_UNSPECIFIED = -12;
-
public final KeyboardId mId;
public final int mThemeId;
@@ -163,7 +121,7 @@ public class Keyboard {
}
public Key getKey(final int code) {
- if (code == CODE_UNSPECIFIED) {
+ if (code == Constants.CODE_UNSPECIFIED) {
return null;
}
synchronized (mKeyCache) {
@@ -197,10 +155,6 @@ public class Keyboard {
return false;
}
- public static boolean isLetterCode(final int code) {
- return code >= CODE_SPACE;
- }
-
@Override
public String toString() {
return mId.toString();
@@ -219,27 +173,4 @@ public class Keyboard {
final int adjustedY = Math.max(0, Math.min(y, mOccupiedHeight - 1));
return mProximityInfo.getNearestKeys(adjustedX, adjustedY);
}
-
- public static String printableCode(final int code) {
- switch (code) {
- case CODE_SHIFT: return "shift";
- case CODE_SWITCH_ALPHA_SYMBOL: return "symbol";
- case CODE_OUTPUT_TEXT: return "text";
- case CODE_DELETE: return "delete";
- case CODE_SETTINGS: return "settings";
- case CODE_SHORTCUT: return "shortcut";
- case CODE_ACTION_ENTER: return "actionEnter";
- case CODE_ACTION_NEXT: return "actionNext";
- case CODE_ACTION_PREVIOUS: return "actionPrevious";
- case CODE_LANGUAGE_SWITCH: return "languageSwitch";
- case CODE_UNSPECIFIED: return "unspec";
- case CODE_TAB: return "tab";
- case CODE_ENTER: return "enter";
- default:
- if (code <= 0) Log.w(TAG, "Unknown non-positive key code=" + code);
- if (code < CODE_SPACE) return String.format("'\\u%02x'", code);
- if (code < 0x100) return String.format("'%c'", code);
- return String.format("'\\u%04x'", code);
- }
- }
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
index 5c8f78f5e..14da9ebe6 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
@@ -56,11 +56,11 @@ public interface KeyboardActionListener {
public void onCodeInput(int primaryCode, int x, int y);
/**
- * Sends a sequence of characters to the listener.
+ * Sends a string of characters to the listener.
*
- * @param text the sequence of characters to be displayed.
+ * @param text the string of characters to be registered.
*/
- public void onTextInput(CharSequence text);
+ public void onTextInput(String text);
/**
* Called when user started batch input.
@@ -80,6 +80,8 @@ public interface KeyboardActionListener {
*/
public void onEndBatchInput(InputPointers batchPointers);
+ public void onCancelBatchInput();
+
/**
* Called when user released a finger outside any key.
*/
@@ -99,7 +101,7 @@ public interface KeyboardActionListener {
@Override
public void onCodeInput(int primaryCode, int x, int y) {}
@Override
- public void onTextInput(CharSequence text) {}
+ public void onTextInput(String text) {}
@Override
public void onStartBatchInput() {}
@Override
@@ -107,18 +109,12 @@ public interface KeyboardActionListener {
@Override
public void onEndBatchInput(InputPointers batchPointers) {}
@Override
+ public void onCancelBatchInput() {}
+ @Override
public void onCancelInput() {}
@Override
public boolean onCustomRequest(int requestCode) {
return false;
}
-
- // TODO: Remove this method when the vertical correction is removed.
- public static boolean isInvalidCoordinate(int coordinate) {
- // Detect {@link Constants#NOT_A_COORDINATE},
- // {@link Constants#SUGGESTION_STRIP_COORDINATE}, and
- // {@link Constants#SPELL_CHECKER_COORDINATE}.
- return coordinate < 0;
- }
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index 5e8a8f6bb..b41361515 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -71,34 +71,39 @@ public final class KeyboardId {
private final EditorInfo mEditorInfo;
public final boolean mClobberSettingsKey;
public final boolean mShortcutKeyEnabled;
- public final boolean mHasShortcutKey;
+ public final boolean mShortcutKeyOnSymbols;
public final boolean mLanguageSwitchKeyEnabled;
public final String mCustomActionLabel;
+ public final boolean mHasShortcutKey;
private final int mHashCode;
- public KeyboardId(int elementId, InputMethodSubtype subtype, int deviceFormFactor,
- int orientation, int width, int mode, EditorInfo editorInfo, boolean clobberSettingsKey,
- boolean shortcutKeyEnabled, boolean hasShortcutKey, boolean languageSwitchKeyEnabled) {
- mSubtype = subtype;
- mLocale = SubtypeLocale.getSubtypeLocale(subtype);
- mDeviceFormFactor = deviceFormFactor;
- mOrientation = orientation;
- mWidth = width;
- mMode = mode;
+ public KeyboardId(final int elementId, final KeyboardLayoutSet.Params params) {
+ mSubtype = params.mSubtype;
+ mLocale = SubtypeLocale.getSubtypeLocale(mSubtype);
+ mDeviceFormFactor = params.mDeviceFormFactor;
+ mOrientation = params.mOrientation;
+ mWidth = params.mWidth;
+ mMode = params.mMode;
mElementId = elementId;
- mEditorInfo = editorInfo;
- mClobberSettingsKey = clobberSettingsKey;
- mShortcutKeyEnabled = shortcutKeyEnabled;
- mHasShortcutKey = hasShortcutKey;
- mLanguageSwitchKeyEnabled = languageSwitchKeyEnabled;
- mCustomActionLabel = (editorInfo.actionLabel != null)
- ? editorInfo.actionLabel.toString() : null;
+ mEditorInfo = params.mEditorInfo;
+ mClobberSettingsKey = params.mNoSettingsKey;
+ mShortcutKeyEnabled = params.mVoiceKeyEnabled;
+ mShortcutKeyOnSymbols = mShortcutKeyEnabled && !params.mVoiceKeyOnMain;
+ mLanguageSwitchKeyEnabled = params.mLanguageSwitchKeyEnabled;
+ mCustomActionLabel = (mEditorInfo.actionLabel != null)
+ ? mEditorInfo.actionLabel.toString() : null;
+ final boolean alphabetMayHaveShortcutKey = isAlphabetKeyboard(elementId)
+ && !mShortcutKeyOnSymbols;
+ final boolean symbolsMayHaveShortcutKey = (elementId == KeyboardId.ELEMENT_SYMBOLS)
+ && mShortcutKeyOnSymbols;
+ mHasShortcutKey = mShortcutKeyEnabled
+ && (alphabetMayHaveShortcutKey || symbolsMayHaveShortcutKey);
mHashCode = computeHashCode(this);
}
- private static int computeHashCode(KeyboardId id) {
+ private static int computeHashCode(final KeyboardId id) {
return Arrays.hashCode(new Object[] {
id.mDeviceFormFactor,
id.mOrientation,
@@ -108,7 +113,7 @@ public final class KeyboardId {
id.passwordInput(),
id.mClobberSettingsKey,
id.mShortcutKeyEnabled,
- id.mHasShortcutKey,
+ id.mShortcutKeyOnSymbols,
id.mLanguageSwitchKeyEnabled,
id.isMultiLine(),
id.imeAction(),
@@ -119,7 +124,7 @@ public final class KeyboardId {
});
}
- private boolean equals(KeyboardId other) {
+ private boolean equals(final KeyboardId other) {
if (other == this)
return true;
return other.mDeviceFormFactor == mDeviceFormFactor
@@ -130,7 +135,7 @@ public final class KeyboardId {
&& other.passwordInput() == passwordInput()
&& other.mClobberSettingsKey == mClobberSettingsKey
&& other.mShortcutKeyEnabled == mShortcutKeyEnabled
- && other.mHasShortcutKey == mHasShortcutKey
+ && other.mShortcutKeyOnSymbols == mShortcutKeyOnSymbols
&& other.mLanguageSwitchKeyEnabled == mLanguageSwitchKeyEnabled
&& other.isMultiLine() == isMultiLine()
&& other.imeAction() == imeAction()
@@ -140,8 +145,12 @@ public final class KeyboardId {
&& other.mSubtype.equals(mSubtype);
}
+ private static boolean isAlphabetKeyboard(final int elementId) {
+ return elementId < ELEMENT_SYMBOLS;
+ }
+
public boolean isAlphabetKeyboard() {
- return mElementId < ELEMENT_SYMBOLS;
+ return isAlphabetKeyboard(mElementId);
}
public boolean navigateNext() {
@@ -181,7 +190,7 @@ public final class KeyboardId {
}
@Override
- public boolean equals(Object other) {
+ public boolean equals(final Object other) {
return other instanceof KeyboardId && equals((KeyboardId) other);
}
@@ -192,7 +201,7 @@ public final class KeyboardId {
@Override
public String toString() {
- return String.format("[%s %s:%s %s-%s:%d %s %s %s%s%s%s%s%s%s%s]",
+ return String.format("[%s %s:%s %s-%s:%d %s %s %s%s%s%s%s%s%s%s%s]",
elementIdToName(mElementId),
mLocale,
mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET),
@@ -204,13 +213,14 @@ public final class KeyboardId {
(mClobberSettingsKey ? " clobberSettingsKey" : ""),
(passwordInput() ? " passwordInput" : ""),
(mShortcutKeyEnabled ? " shortcutKeyEnabled" : ""),
+ (mShortcutKeyOnSymbols ? " shortcutKeyOnSymbols" : ""),
(mHasShortcutKey ? " hasShortcutKey" : ""),
(mLanguageSwitchKeyEnabled ? " languageSwitchKeyEnabled" : ""),
(isMultiLine() ? "isMultiLine" : "")
);
}
- public static boolean equivalentEditorInfoForKeyboard(EditorInfo a, EditorInfo b) {
+ public static boolean equivalentEditorInfoForKeyboard(final EditorInfo a, final EditorInfo b) {
if (a == null && b == null) return true;
if (a == null || b == null) return false;
return a.inputType == b.inputType
@@ -218,7 +228,7 @@ public final class KeyboardId {
&& TextUtils.equals(a.privateImeOptions, b.privateImeOptions);
}
- public static String elementIdToName(int elementId) {
+ public static String elementIdToName(final int elementId) {
switch (elementId) {
case ELEMENT_ALPHABET: return "alphabet";
case ELEMENT_ALPHABET_MANUAL_SHIFTED: return "alphabetManualShifted";
@@ -234,8 +244,8 @@ public final class KeyboardId {
}
}
- public static String deviceFormFactor(int devoceFormFactor) {
- switch (devoceFormFactor) {
+ public static String deviceFormFactor(final int deviceFormFactor) {
+ switch (deviceFormFactor) {
case FORM_FACTOR_PHONE: return "phone";
case FORM_FACTOR_TABLET7: return "tablet7";
case FORM_FACTOR_TABLET10: return "tablet10";
@@ -243,7 +253,7 @@ public final class KeyboardId {
}
}
- public static String modeName(int mode) {
+ public static String modeName(final int mode) {
switch (mode) {
case MODE_TEXT: return "text";
case MODE_URL: return "url";
@@ -258,7 +268,7 @@ public final class KeyboardId {
}
}
- public static String actionName(int actionId) {
+ public static String actionName(final int actionId) {
return (actionId == IME_ACTION_CUSTOM_LABEL) ? "actionCustomLabel"
: EditorInfoCompatUtils.imeActionName(actionId);
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index c7813ab02..295047530 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -34,6 +34,7 @@ import android.util.Xml;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodSubtype;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.compat.EditorInfoCompatUtils;
import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
import com.android.inputmethod.keyboard.internal.KeyboardParams;
@@ -77,6 +78,7 @@ public final class KeyboardLayoutSet {
CollectionUtils.newHashMap();
private static final KeysCache sKeysCache = new KeysCache();
+ @SuppressWarnings("serial")
public static final class KeyboardLayoutSetException extends RuntimeException {
public final KeyboardId mKeyboardId;
@@ -92,7 +94,7 @@ public final class KeyboardLayoutSet {
public ElementParams() {}
}
- private static final class Params {
+ public static final class Params {
String mKeyboardLayoutSetName;
int mMode;
EditorInfo mEditorInfo;
@@ -108,7 +110,6 @@ public final class KeyboardLayoutSet {
// Sparse array of KeyboardLayoutSet element parameters indexed by element's id.
final SparseArray<ElementParams> mKeyboardLayoutSetElementIdToParamsMap =
CollectionUtils.newSparseArray();
- public Params() {}
}
public static void clearKeyboardCache() {
@@ -148,7 +149,11 @@ public final class KeyboardLayoutSet {
elementParams = mParams.mKeyboardLayoutSetElementIdToParamsMap.get(
KeyboardId.ELEMENT_ALPHABET);
}
- final KeyboardId id = getKeyboardId(keyboardLayoutSetElementId);
+ // Note: The keyboard for each shift state, and mode are represented as an elementName
+ // attribute in a keyboard_layout_set XML file. Also each keyboard layout XML resource is
+ // specified as an elementKeyboard attribute in the file.
+ // The KeyboardId is an internal key for a Keyboard object.
+ final KeyboardId id = new KeyboardId(keyboardLayoutSetElementId, mParams);
try {
return getKeyboard(elementParams, id);
} catch (RuntimeException e) {
@@ -186,23 +191,6 @@ public final class KeyboardLayoutSet {
return keyboard;
}
- // Note: The keyboard for each locale, shift state, and mode are represented as
- // KeyboardLayoutSet element id that is a key in keyboard_set.xml. Also that file specifies
- // which XML layout should be used for each keyboard. The KeyboardId is an internal key for
- // Keyboard object.
- private KeyboardId getKeyboardId(final int keyboardLayoutSetElementId) {
- final Params params = mParams;
- final boolean isSymbols = (keyboardLayoutSetElementId == KeyboardId.ELEMENT_SYMBOLS
- || keyboardLayoutSetElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED);
- final boolean noLanguage = SubtypeLocale.isNoLanguage(params.mSubtype);
- final boolean voiceKeyEnabled = params.mVoiceKeyEnabled && !noLanguage;
- final boolean hasShortcutKey = voiceKeyEnabled && (isSymbols != params.mVoiceKeyOnMain);
- return new KeyboardId(keyboardLayoutSetElementId, params.mSubtype, params.mDeviceFormFactor,
- params.mOrientation, params.mWidth, params.mMode, params.mEditorInfo,
- params.mNoSettingsKey, voiceKeyEnabled, hasShortcutKey,
- params.mLanguageSwitchKeyEnabled);
- }
-
public static final class Builder {
private final Context mContext;
private final String mPackageName;
@@ -266,7 +254,7 @@ public final class KeyboardLayoutSet {
return this;
}
- // For test only
+ @UsedForTesting
public void disableTouchPositionCorrectionDataForTest() {
mParams.mDisableTouchPositionCorrectionDataForTest = true;
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index de8097b55..c1c105e8d 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -29,12 +29,12 @@ import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
import com.android.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException;
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
import com.android.inputmethod.keyboard.internal.KeyboardState;
-import com.android.inputmethod.latin.DebugSettings;
-import com.android.inputmethod.latin.ImfUtils;
+import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
import com.android.inputmethod.latin.InputView;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodManager;
import com.android.inputmethod.latin.SettingsValues;
import com.android.inputmethod.latin.SubtypeSwitcher;
import com.android.inputmethod.latin.WordComposer;
@@ -65,9 +65,9 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
new KeyboardTheme(5, R.style.KeyboardTheme_IceCreamSandwich),
};
+ private AudioAndHapticFeedbackManager mFeedbackManager;
private SubtypeSwitcher mSubtypeSwitcher;
private SharedPreferences mPrefs;
- private boolean mForceNonDistinctMultitouch;
private InputView mCurrentInputView;
private MainKeyboardView mKeyboardView;
@@ -102,12 +102,11 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
private void initInternal(LatinIME latinIme, SharedPreferences prefs) {
mLatinIME = latinIme;
mResources = latinIme.getResources();
+ mFeedbackManager = new AudioAndHapticFeedbackManager(latinIme);
mPrefs = prefs;
mSubtypeSwitcher = SubtypeSwitcher.getInstance();
mState = new KeyboardState(this);
setContextThemeWrapper(latinIme, getKeyboardTheme(latinIme, prefs));
- mForceNonDistinctMultitouch = prefs.getBoolean(
- DebugSettings.FORCE_NON_DISTINCT_MULTITOUCH_KEY, false);
}
private static KeyboardTheme getKeyboardTheme(Context context, SharedPreferences prefs) {
@@ -126,7 +125,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
}
private void setContextThemeWrapper(Context context, KeyboardTheme keyboardTheme) {
- if (mKeyboardTheme.mThemeId != keyboardTheme.mThemeId) {
+ if (mThemeContext == null || mKeyboardTheme.mThemeId != keyboardTheme.mThemeId) {
mKeyboardTheme = keyboardTheme;
mThemeContext = new ContextThemeWrapper(context, keyboardTheme.mStyleId);
KeyboardLayoutSet.clearKeyboardCache();
@@ -143,10 +142,11 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
builder.setOptions(
settingsValues.isVoiceKeyEnabled(editorInfo),
settingsValues.isVoiceKeyOnMain(),
- settingsValues.isLanguageSwitchKeyEnabled(mThemeContext));
+ settingsValues.isLanguageSwitchKeyEnabled());
mKeyboardLayoutSet = builder.build();
try {
mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols));
+ mFeedbackManager.onSettingsChanged(settingsValues);
} catch (KeyboardLayoutSetException e) {
Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause());
LatinImeLogger.logOnException(e.mKeyboardId.toString(), e.getCause());
@@ -154,6 +154,10 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
}
}
+ public void onRingerModeChanged() {
+ mFeedbackManager.onRingerModeChanged();
+ }
+
public void saveKeyboardState() {
if (getKeyboard() != null) {
mState.onSaveKeyboardState();
@@ -183,7 +187,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
final boolean needsToDisplayLanguage = mSubtypeSwitcher.needsToDisplayLanguage(
keyboard.mId.mLocale);
keyboardView.startDisplayLanguageOnSpacebar(subtypeChanged, needsToDisplayLanguage,
- ImfUtils.hasMultipleEnabledIMEsOrSubtypes(mLatinIME, true));
+ RichInputMethodManager.getInstance().hasMultipleEnabledIMEsOrSubtypes(true));
}
public Keyboard getKeyboard() {
@@ -208,7 +212,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
public void onPressKey(int code) {
if (isVibrateAndSoundFeedbackRequired()) {
- mLatinIME.hapticAndAudioFeedback(code);
+ mFeedbackManager.hapticAndAudioFeedback(code, mKeyboardView);
}
mState.onPressKey(code, isSinglePointer(), mLatinIME.getCurrentAutoCapsState());
}
@@ -320,7 +324,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
// Implements {@link KeyboardState.SwitchActions}.
@Override
public void hapticAndAudioFeedback(int code) {
- mLatinIME.hapticAndAudioFeedback(code);
+ mFeedbackManager.hapticAndAudioFeedback(code, mKeyboardView);
}
public void onLongPressTimeout(int code) {
@@ -339,10 +343,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
return mKeyboardView != null && mKeyboardView.getPointerCount() == 1;
}
- public boolean hasDistinctMultitouch() {
- return mKeyboardView != null && mKeyboardView.hasDistinctMultitouch();
- }
-
/**
* Updates state machine to figure out when to automatically switch back to the previous mode.
*/
@@ -369,9 +369,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
// TODO: Should use LAYER_TYPE_SOFTWARE when hardware acceleration is off?
}
mKeyboardView.setKeyboardActionListener(mLatinIME);
- if (mForceNonDistinctMultitouch) {
- mKeyboardView.setDistinctMultitouch(false);
- }
// This always needs to be set since the accessibility state can
// potentially change without the input view being re-created.
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 472f74b12..61d38745e 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -45,6 +45,7 @@ import com.android.inputmethod.keyboard.internal.KeyVisualAttributes;
import com.android.inputmethod.keyboard.internal.PreviewPlacerView;
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.CoordinateUtils;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
@@ -101,7 +102,8 @@ import java.util.HashSet;
* @attr ref R.styleable#Keyboard_Key_keyShiftedLetterHintActivatedColor
* @attr ref R.styleable#Keyboard_Key_keyPreviewTextColor
*/
-public class KeyboardView extends View implements PointerTracker.DrawingProxy {
+public class KeyboardView extends View implements PointerTracker.DrawingProxy,
+ MoreKeysPanel.Controller {
private static final String TAG = KeyboardView.class.getSimpleName();
// XML attributes
@@ -134,7 +136,11 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// Preview placer view
private final PreviewPlacerView mPreviewPlacerView;
- private final int[] mCoordinates = new int[2];
+ private final int[] mOriginCoords = CoordinateUtils.newInstance();
+
+ // More keys panel (used by both more keys keyboard and more suggestions view)
+ // TODO: Consider extending to support multiple more keys panels
+ protected MoreKeysPanel mMoreKeysPanel;
// Key preview
private static final int PREVIEW_ALPHA = 240;
@@ -832,10 +838,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// In transient state.
return;
}
- final int[] viewOrigin = new int[2];
- getLocationInWindow(viewOrigin);
+ getLocationInWindow(mOriginCoords);
final DisplayMetrics dm = getResources().getDisplayMetrics();
- if (viewOrigin[1] < dm.heightPixels / 4) {
+ if (CoordinateUtils.y(mOriginCoords) < dm.heightPixels / 4) {
// In transient state.
return;
}
@@ -850,10 +855,21 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
Log.w(TAG, "Cannot find android.R.id.content view to add PreviewPlacerView");
} else {
windowContentView.addView(mPreviewPlacerView);
- mPreviewPlacerView.setKeyboardViewGeometry(viewOrigin[0], viewOrigin[1], width, height);
+ mPreviewPlacerView.setKeyboardViewGeometry(mOriginCoords, width, height);
}
}
+ @Override
+ public void showSlidingKeyInputPreview(final PointerTracker tracker) {
+ locatePreviewPlacerView();
+ mPreviewPlacerView.showSlidingKeyInputPreview(tracker);
+ }
+
+ @Override
+ public void dismissSlidingKeyInputPreview() {
+ mPreviewPlacerView.dismissSlidingKeyInputPreview();
+ }
+
public void showGestureFloatingPreviewText(final String gestureFloatingPreviewText) {
locatePreviewPlacerView();
mPreviewPlacerView.setGestureFloatingPreviewText(gestureFloatingPreviewText);
@@ -935,12 +951,13 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// The distance between the top edge of the parent key and the bottom of the visible part
// of the key preview background.
previewParams.mPreviewVisibleOffset = mPreviewOffset - previewText.getPaddingBottom();
- getLocationInWindow(mCoordinates);
+ getLocationInWindow(mOriginCoords);
// The key preview is horizontally aligned with the center of the visible part of the
// parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and
// the left/right background is used if such background is specified.
final int statePosition;
- int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2 + mCoordinates[0];
+ int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2
+ + CoordinateUtils.x(mOriginCoords);
if (previewX < 0) {
previewX = 0;
statePosition = STATE_LEFT;
@@ -952,7 +969,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
// The key preview is placed vertically above the top edge of the parent key with an
// arbitrary offset.
- final int previewY = key.mY - previewHeight + mPreviewOffset + mCoordinates[1];
+ final int previewY = key.mY - previewHeight + mPreviewOffset
+ + CoordinateUtils.y(mOriginCoords);
if (background != null) {
final int hasMoreKeys = (key.mMoreKeys != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL;
@@ -995,13 +1013,38 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
public void closing() {
dismissAllKeyPreviews();
cancelAllMessages();
-
+ onCancelMoreKeysPanel();
mInvalidateAllKeys = true;
requestLayout();
}
@Override
- public boolean dismissMoreKeysPanel() {
+ public void onShowMoreKeysPanel(final MoreKeysPanel panel) {
+ if (isShowingMoreKeysPanel()) {
+ onDismissMoreKeysPanel();
+ }
+ mMoreKeysPanel = panel;
+ mPreviewPlacerView.addView(mMoreKeysPanel.getContainerView());
+ }
+
+ public boolean isShowingMoreKeysPanel() {
+ return (mMoreKeysPanel != null);
+ }
+
+ @Override
+ public void onCancelMoreKeysPanel() {
+ if (isShowingMoreKeysPanel()) {
+ mMoreKeysPanel.dismissMoreKeysPanel();
+ }
+ }
+
+ @Override
+ public boolean onDismissMoreKeysPanel() {
+ if (isShowingMoreKeysPanel()) {
+ mPreviewPlacerView.removeView(mMoreKeysPanel.getContainerView());
+ mMoreKeysPanel = null;
+ return true;
+ }
return false;
}
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 3e6f92c2a..584d2fe46 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -19,6 +19,7 @@ package com.android.inputmethod.keyboard;
import android.animation.AnimatorInflater;
import android.animation.ObjectAnimator;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -28,7 +29,8 @@ import android.graphics.Paint.Align;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Message;
-import android.text.TextUtils;
+import android.os.SystemClock;
+import android.preference.PreferenceManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
@@ -37,15 +39,17 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodSubtype;
-import android.widget.PopupWindow;
import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
+import com.android.inputmethod.annotations.ExternallyReferenced;
import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
import com.android.inputmethod.keyboard.internal.KeyDrawParams;
-import com.android.inputmethod.keyboard.internal.SuddenJumpingTouchEventHandler;
+import com.android.inputmethod.keyboard.internal.TouchScreenRegulator;
import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.CoordinateUtils;
+import com.android.inputmethod.latin.DebugSettings;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
@@ -95,7 +99,7 @@ import java.util.WeakHashMap;
* @attr ref R.styleable#MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration
*/
public final class MainKeyboardView extends KeyboardView implements PointerTracker.KeyEventHandler,
- SuddenJumpingTouchEventHandler.ProcessMotionEvent {
+ TouchScreenRegulator.ProcessMotionEvent {
private static final String TAG = MainKeyboardView.class.getSimpleName();
// TODO: Kill process when the usability study mode was changed.
@@ -131,17 +135,14 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private int mAltCodeKeyWhileTypingAnimAlpha = Constants.Color.ALPHA_OPAQUE;
// More keys keyboard
- private PopupWindow mMoreKeysWindow;
- private MoreKeysPanel mMoreKeysPanel;
- private int mMoreKeysPanelPointerTrackerId;
private final WeakHashMap<Key, MoreKeysPanel> mMoreKeysPanelCache =
new WeakHashMap<Key, MoreKeysPanel>();
private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint;
- private final SuddenJumpingTouchEventHandler mTouchScreenRegulator;
+ private final TouchScreenRegulator mTouchScreenRegulator;
protected KeyDetector mKeyDetector;
- private boolean mHasDistinctMultitouch;
+ private final boolean mHasDistinctMultitouch;
private int mOldPointerCount = 1;
private Key mOldKey;
@@ -153,12 +154,14 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private static final int MSG_REPEAT_KEY = 1;
private static final int MSG_LONGPRESS_KEY = 2;
private static final int MSG_DOUBLE_TAP = 3;
+ private static final int MSG_UPDATE_BATCH_INPUT = 4;
private final int mKeyRepeatStartTimeout;
private final int mKeyRepeatInterval;
private final int mLongPressKeyTimeout;
private final int mLongPressShiftKeyTimeout;
private final int mIgnoreAltCodeKeyTimeout;
+ private final int mGestureRecognitionUpdateTime;
public KeyTimerHandler(final MainKeyboardView outerInstance,
final TypedArray mainKeyboardViewAttr) {
@@ -174,6 +177,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
R.styleable.MainKeyboardView_longPressShiftKeyTimeout, 0);
mIgnoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt(
R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0);
+ mGestureRecognitionUpdateTime = mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_gestureRecognitionUpdateTime, 0);
}
@Override
@@ -198,12 +203,18 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
KeyboardSwitcher.getInstance().onLongPressTimeout(msg.arg1);
}
break;
+ case MSG_UPDATE_BATCH_INPUT:
+ tracker.updateBatchInputByTimer(SystemClock.uptimeMillis());
+ startUpdateBatchInputTimer(tracker);
+ break;
}
}
private void startKeyRepeatTimer(final PointerTracker tracker, final long delay) {
final Key key = tracker.getKey();
- if (key == null) return;
+ if (key == null) {
+ return;
+ }
sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, key.mCode, 0, tracker), delay);
}
@@ -226,7 +237,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
cancelLongPressTimer();
final int delay;
switch (code) {
- case Keyboard.CODE_SHIFT:
+ case Constants.CODE_SHIFT:
delay = mLongPressShiftKeyTimeout;
break;
default:
@@ -247,7 +258,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
final Key key = tracker.getKey();
final int delay;
switch (key.mCode) {
- case Keyboard.CODE_SHIFT:
+ case Constants.CODE_SHIFT:
delay = mLongPressShiftKeyTimeout;
break;
default:
@@ -304,7 +315,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
// When user hits the space or the enter key, just cancel the while-typing timer.
final int typedCode = typedKey.mCode;
- if (typedCode == Keyboard.CODE_SPACE || typedCode == Keyboard.CODE_ENTER) {
+ if (typedCode == Constants.CODE_SPACE || typedCode == Constants.CODE_ENTER) {
startWhileTypingFadeinAnimation(keyboardView);
return;
}
@@ -344,8 +355,24 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
cancelLongPressTimer();
}
+ @Override
+ public void startUpdateBatchInputTimer(final PointerTracker tracker) {
+ if (mGestureRecognitionUpdateTime <= 0) {
+ return;
+ }
+ removeMessages(MSG_UPDATE_BATCH_INPUT, tracker);
+ sendMessageDelayed(obtainMessage(MSG_UPDATE_BATCH_INPUT, tracker),
+ mGestureRecognitionUpdateTime);
+ }
+
+ @Override
+ public void cancelAllUpdateBatchInputTimers() {
+ removeMessages(MSG_UPDATE_BATCH_INPUT);
+ }
+
public void cancelAllMessages() {
cancelKeyTimers();
+ cancelAllUpdateBatchInputTimers();
}
}
@@ -356,15 +383,19 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
public MainKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
- mTouchScreenRegulator = new SuddenJumpingTouchEventHandler(getContext(), this);
+ mTouchScreenRegulator = new TouchScreenRegulator(context, this);
- mHasDistinctMultitouch = context.getPackageManager()
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ final boolean forceNonDistinctMultitouch = prefs.getBoolean(
+ DebugSettings.FORCE_NON_DISTINCT_MULTITOUCH_KEY, false);
+ final boolean hasDistinctMultitouch = context.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT);
+ mHasDistinctMultitouch = hasDistinctMultitouch && !forceNonDistinctMultitouch;
final Resources res = getResources();
final boolean needsPhantomSuddenMoveEventHack = Boolean.parseBoolean(
ResourceUtils.getDeviceOverrideValue(res,
R.array.phantom_sudden_move_event_device_list, "false"));
- PointerTracker.init(mHasDistinctMultitouch, needsPhantomSuddenMoveEventHack);
+ PointerTracker.init(needsPhantomSuddenMoveEventHack);
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.MainKeyboardView, defStyle, R.style.MainKeyboardView);
@@ -408,7 +439,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
}
private ObjectAnimator loadObjectAnimator(final int resId, final Object target) {
- if (resId == 0) return null;
+ if (resId == 0) {
+ return null;
+ }
final ObjectAnimator animator = (ObjectAnimator)AnimatorInflater.loadAnimator(
getContext(), resId);
if (animator != null) {
@@ -417,20 +450,23 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
return animator;
}
- // Getter/setter methods for {@link ObjectAnimator}.
+ @ExternallyReferenced
public int getLanguageOnSpacebarAnimAlpha() {
return mLanguageOnSpacebarAnimAlpha;
}
+ @ExternallyReferenced
public void setLanguageOnSpacebarAnimAlpha(final int alpha) {
mLanguageOnSpacebarAnimAlpha = alpha;
invalidateKey(mSpaceKey);
}
+ @ExternallyReferenced
public int getAltCodeKeyWhileTypingAnimAlpha() {
return mAltCodeKeyWhileTypingAnimAlpha;
}
+ @ExternallyReferenced
public void setAltCodeKeyWhileTypingAnimAlpha(final int alpha) {
mAltCodeKeyWhileTypingAnimAlpha = alpha;
updateAltCodeKeyWhileTyping();
@@ -480,10 +516,10 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
mKeyDetector.setKeyboard(
keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection);
PointerTracker.setKeyDetector(mKeyDetector);
- mTouchScreenRegulator.setKeyboard(keyboard);
+ mTouchScreenRegulator.setKeyboardGeometry(keyboard.mOccupiedWidth);
mMoreKeysPanelCache.clear();
- mSpaceKey = keyboard.getKey(Keyboard.CODE_SPACE);
+ mSpaceKey = keyboard.getKey(Constants.CODE_SPACE);
mSpaceIcon = (mSpaceKey != null)
? mSpaceKey.getIcon(keyboard.mIconsSet, Constants.Color.ALPHA_OPAQUE) : null;
final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
@@ -506,18 +542,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
PointerTracker.setGestureHandlingEnabledByUser(gestureHandlingEnabledByUser);
}
- /**
- * Returns whether the device has distinct multi-touch panel.
- * @return true if the device has distinct multi-touch panel.
- */
- public boolean hasDistinctMultitouch() {
- return mHasDistinctMultitouch;
- }
-
- public void setDistinctMultitouch(final boolean hasDistinctMultitouch) {
- mHasDistinctMultitouch = hasDistinctMultitouch;
- }
-
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
@@ -553,21 +577,25 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
}
// Check if we are already displaying popup panel.
- if (mMoreKeysPanel != null)
+ if (mMoreKeysPanel != null) {
return false;
- if (parentKey == null)
+ }
+ if (parentKey == null) {
return false;
+ }
return onLongPress(parentKey, tracker);
}
// This default implementation returns a more keys panel.
protected MoreKeysPanel onCreateMoreKeysPanel(final Key parentKey) {
- if (parentKey.mMoreKeys == null)
+ if (parentKey.mMoreKeys == null) {
return null;
+ }
final View container = LayoutInflater.from(getContext()).inflate(mMoreKeysLayout, null);
- if (container == null)
+ if (container == null) {
throw new NullPointerException();
+ }
final MoreKeysKeyboardView moreKeysKeyboardView =
(MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view);
@@ -600,7 +628,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
KeyboardSwitcher.getInstance().hapticAndAudioFeedback(primaryCode);
return true;
}
- if (primaryCode == Keyboard.CODE_SPACE || primaryCode == Keyboard.CODE_LANGUAGE_SWITCH) {
+ if (primaryCode == Constants.CODE_SPACE || primaryCode == Constants.CODE_LANGUAGE_SWITCH) {
// Long pressing the space key invokes IME switcher dialog.
if (invokeCustomRequest(LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) {
tracker.onLongPressed();
@@ -628,24 +656,20 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
MoreKeysPanel moreKeysPanel = mMoreKeysPanelCache.get(parentKey);
if (moreKeysPanel == null) {
moreKeysPanel = onCreateMoreKeysPanel(parentKey);
- if (moreKeysPanel == null)
+ if (moreKeysPanel == null) {
return false;
+ }
mMoreKeysPanelCache.put(parentKey, moreKeysPanel);
}
- if (mMoreKeysWindow == null) {
- mMoreKeysWindow = new PopupWindow(getContext());
- mMoreKeysWindow.setBackgroundDrawable(null);
- mMoreKeysWindow.setAnimationStyle(R.style.MoreKeysKeyboardAnimation);
- }
- mMoreKeysPanel = moreKeysPanel;
- mMoreKeysPanelPointerTrackerId = tracker.mPointerId;
+ final int[] lastCoords = CoordinateUtils.newInstance();
+ tracker.getLastCoordinates(lastCoords);
final boolean keyPreviewEnabled = isKeyPreviewPopupEnabled() && !parentKey.noKeyPreview();
// The more keys keyboard is usually horizontally aligned with the center of the parent key.
// If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more
// keys keyboard is placed at the touch point of the parent key.
final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint && !keyPreviewEnabled)
- ? tracker.getLastX()
+ ? CoordinateUtils.x(lastCoords)
: parentKey.mX + parentKey.mWidth / 2;
// The more keys keyboard is usually vertically aligned with the top edge of the parent key
// (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically
@@ -653,21 +677,19 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
// {@code mPreviewVisibleOffset} has been set appropriately in
// {@link KeyboardView#showKeyPreview(PointerTracker)}.
final int pointY = parentKey.mY + mKeyPreviewDrawParams.mPreviewVisibleOffset;
- moreKeysPanel.showMoreKeysPanel(
- this, this, pointX, pointY, mMoreKeysWindow, mKeyboardActionListener);
- final int translatedX = moreKeysPanel.translateX(tracker.getLastX());
- final int translatedY = moreKeysPanel.translateY(tracker.getLastY());
+ moreKeysPanel.showMoreKeysPanel(this, this, pointX, pointY, mKeyboardActionListener);
+ final int translatedX = moreKeysPanel.translateX(CoordinateUtils.x(lastCoords));
+ final int translatedY = moreKeysPanel.translateY(CoordinateUtils.y(lastCoords));
tracker.onShowMoreKeysPanel(translatedX, translatedY, moreKeysPanel);
- dimEntireKeyboard(true);
+ dimEntireKeyboard(true /* dimmed */);
return true;
}
public boolean isInSlidingKeyInput() {
if (mMoreKeysPanel != null) {
return true;
- } else {
- return PointerTracker.isAnyInSlidingKeyInput();
}
+ return PointerTracker.isAnyInSlidingKeyInput();
}
public int getPointerCount() {
@@ -708,47 +730,18 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
final long eventTime = me.getEventTime();
final int index = me.getActionIndex();
final int id = me.getPointerId(index);
- final int x, y;
- if (mMoreKeysPanel != null && id == mMoreKeysPanelPointerTrackerId) {
- x = mMoreKeysPanel.translateX((int)me.getX(index));
- y = mMoreKeysPanel.translateY((int)me.getY(index));
- } else {
- x = (int)me.getX(index);
- y = (int)me.getY(index);
- }
- if (ENABLE_USABILITY_STUDY_LOG) {
- final String eventTag;
- switch (action) {
- case MotionEvent.ACTION_UP:
- eventTag = "[Up]";
- break;
- case MotionEvent.ACTION_DOWN:
- eventTag = "[Down]";
- break;
- case MotionEvent.ACTION_POINTER_UP:
- eventTag = "[PointerUp]";
- break;
- case MotionEvent.ACTION_POINTER_DOWN:
- eventTag = "[PointerDown]";
- break;
- case MotionEvent.ACTION_MOVE: // Skip this as being logged below
- eventTag = "";
- break;
- default:
- eventTag = "[Action" + action + "]";
- break;
- }
- if (!TextUtils.isEmpty(eventTag)) {
- final float size = me.getSize(index);
- final float pressure = me.getPressure(index);
- UsabilityStudyLogUtils.getInstance().write(
- eventTag + eventTime + "," + id + "," + x + "," + y + ","
- + size + "," + pressure);
- }
+ final int x = (int)me.getX(index);
+ final int y = (int)me.getY(index);
+
+ // TODO: This might be moved to the tracker.processMotionEvent() call below.
+ if (ENABLE_USABILITY_STUDY_LOG && action != MotionEvent.ACTION_MOVE) {
+ writeUsabilityStudyLog(me, action, eventTime, index, id, x, y);
}
+ // TODO: This should be moved to the tracker.processMotionEvent() call below.
+ // Currently the same "move" event is being logged twice.
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.mainKeyboardView_processMotionEvent(me, action, eventTime, index, id,
- x, y);
+ ResearchLogger.mainKeyboardView_processMotionEvent(
+ me, action, eventTime, index, id, x, y);
}
if (mKeyTimerHandler.isInKeyRepeat()) {
@@ -774,16 +767,18 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
final Key newKey = tracker.getKeyOn(x, y);
if (mOldKey != newKey) {
tracker.onDownEvent(x, y, eventTime, this);
- if (action == MotionEvent.ACTION_UP)
+ if (action == MotionEvent.ACTION_UP) {
tracker.onUpEvent(x, y, eventTime);
+ }
}
} else if (pointerCount == 2 && oldPointerCount == 1) {
// Single-touch to multi-touch transition.
// Send an up event for the last pointer.
- final int lastX = tracker.getLastX();
- final int lastY = tracker.getLastY();
- mOldKey = tracker.getKeyOn(lastX, lastY);
- tracker.onUpEvent(lastX, lastY, eventTime);
+ final int[] lastCoords = CoordinateUtils.newInstance();
+ mOldKey = tracker.getKeyOn(
+ CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords));
+ tracker.onUpEvent(
+ CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords), eventTime);
} else if (pointerCount == 1 && oldPointerCount == 1) {
tracker.processMotionEvent(action, x, y, eventTime, this);
} else {
@@ -798,29 +793,15 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
final int pointerId = me.getPointerId(i);
final PointerTracker tracker = PointerTracker.getPointerTracker(
pointerId, this);
- final int px, py;
- final MotionEvent motionEvent;
- if (mMoreKeysPanel != null
- && tracker.mPointerId == mMoreKeysPanelPointerTrackerId) {
- px = mMoreKeysPanel.translateX((int)me.getX(i));
- py = mMoreKeysPanel.translateY((int)me.getY(i));
- motionEvent = null;
- } else {
- px = (int)me.getX(i);
- py = (int)me.getY(i);
- motionEvent = me;
- }
- tracker.onMoveEvent(px, py, eventTime, motionEvent);
+ final int px = (int)me.getX(i);
+ final int py = (int)me.getY(i);
+ tracker.onMoveEvent(px, py, eventTime, me);
if (ENABLE_USABILITY_STUDY_LOG) {
- final float pointerSize = me.getSize(i);
- final float pointerPressure = me.getPressure(i);
- UsabilityStudyLogUtils.getInstance().write("[Move]" + eventTime + ","
- + pointerId + "," + px + "," + py + ","
- + pointerSize + "," + pointerPressure);
+ writeUsabilityStudyLog(me, action, eventTime, i, pointerId, px, py);
}
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.mainKeyboardView_processMotionEvent(me, action, eventTime,
- i, pointerId, px, py);
+ ResearchLogger.mainKeyboardView_processMotionEvent(
+ me, action, eventTime, i, pointerId, px, py);
}
}
} else {
@@ -831,23 +812,52 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
return true;
}
+ private static void writeUsabilityStudyLog(final MotionEvent me, final int action,
+ final long eventTime, final int index, final int id, final int x, final int y) {
+ final String eventTag;
+ switch (action) {
+ case MotionEvent.ACTION_UP:
+ eventTag = "[Up]";
+ break;
+ case MotionEvent.ACTION_DOWN:
+ eventTag = "[Down]";
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ eventTag = "[PointerUp]";
+ break;
+ case MotionEvent.ACTION_POINTER_DOWN:
+ eventTag = "[PointerDown]";
+ break;
+ case MotionEvent.ACTION_MOVE:
+ eventTag = "[Move]";
+ break;
+ default:
+ eventTag = "[Action" + action + "]";
+ break;
+ }
+ final float size = me.getSize(index);
+ final float pressure = me.getPressure(index);
+ UsabilityStudyLogUtils.getInstance().write(
+ eventTag + eventTime + "," + id + "," + x + "," + y + "," + size + "," + pressure);
+ }
+
@Override
public void closing() {
super.closing();
- dismissMoreKeysPanel();
+ onCancelMoreKeysPanel();
mMoreKeysPanelCache.clear();
}
@Override
- public boolean dismissMoreKeysPanel() {
- if (mMoreKeysWindow != null && mMoreKeysWindow.isShowing()) {
- mMoreKeysWindow.dismiss();
- mMoreKeysPanel = null;
- mMoreKeysPanelPointerTrackerId = -1;
- dimEntireKeyboard(false);
- return true;
- }
- return false;
+ public void onCancelMoreKeysPanel() {
+ super.onCancelMoreKeysPanel();
+ PointerTracker.dismissAllMoreKeysPanels();
+ }
+
+ @Override
+ public boolean onDismissMoreKeysPanel() {
+ dimEntireKeyboard(false /* dimmed */);
+ return super.onDismissMoreKeysPanel();
}
/**
@@ -870,16 +880,22 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
public void updateShortcutKey(final boolean available) {
final Keyboard keyboard = getKeyboard();
- if (keyboard == null) return;
- final Key shortcutKey = keyboard.getKey(Keyboard.CODE_SHORTCUT);
- if (shortcutKey == null) return;
+ if (keyboard == null) {
+ return;
+ }
+ final Key shortcutKey = keyboard.getKey(Constants.CODE_SHORTCUT);
+ if (shortcutKey == null) {
+ return;
+ }
shortcutKey.setEnabled(available);
invalidateKey(shortcutKey);
}
private void updateAltCodeKeyWhileTyping() {
final Keyboard keyboard = getKeyboard();
- if (keyboard == null) return;
+ if (keyboard == null) {
+ return;
+ }
for (final Key key : keyboard.mAltCodeKeysWhileTyping) {
invalidateKey(key);
}
@@ -909,7 +925,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
}
public void updateAutoCorrectionState(final boolean isAutoCorrection) {
- if (!mAutoCorrectionSpacebarLedEnabled) return;
+ if (!mAutoCorrectionSpacebarLedEnabled) {
+ return;
+ }
mAutoCorrectionSpacebarLedOn = isAutoCorrection;
invalidateKey(mSpaceKey);
}
@@ -920,13 +938,13 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
if (key.altCodeWhileTyping() && key.isEnabled()) {
params.mAnimAlpha = mAltCodeKeyWhileTypingAnimAlpha;
}
- if (key.mCode == Keyboard.CODE_SPACE) {
+ if (key.mCode == Constants.CODE_SPACE) {
drawSpacebar(key, canvas, paint);
// Whether space key needs to show the "..." popup hint for special purposes
if (key.isLongPressEnabled() && mHasMultipleEnabledIMEsOrSubtypes) {
drawKeyPopupHint(key, canvas, paint, params);
}
- } else if (key.mCode == Keyboard.CODE_LANGUAGE_SWITCH) {
+ } else if (key.mCode == Constants.CODE_LANGUAGE_SWITCH) {
super.onDrawKeyTopVisuals(key, canvas, paint, params);
drawKeyPopupHint(key, canvas, paint, params);
} else {
@@ -937,10 +955,14 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private boolean fitsTextIntoWidth(final int width, final String text, final Paint paint) {
paint.setTextScaleX(1.0f);
final float textWidth = getLabelWidth(text, paint);
- if (textWidth < width) return true;
+ if (textWidth < width) {
+ return true;
+ }
final float scaleX = width / textWidth;
- if (scaleX < MINIMUM_XSCALE_OF_LANGUAGE_NAME) return false;
+ if (scaleX < MINIMUM_XSCALE_OF_LANGUAGE_NAME) {
+ return false;
+ }
paint.setTextScaleX(scaleX);
return getLabelWidth(text, paint) < width;
@@ -950,19 +972,19 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private String layoutLanguageOnSpacebar(final Paint paint, final InputMethodSubtype subtype,
final int width) {
// Choose appropriate language name to fit into the width.
- String text = getFullDisplayName(subtype, getResources());
- if (fitsTextIntoWidth(width, text, paint)) {
- return text;
+ final String fullText = getFullDisplayName(subtype, getResources());
+ if (fitsTextIntoWidth(width, fullText, paint)) {
+ return fullText;
}
- text = getMiddleDisplayName(subtype);
- if (fitsTextIntoWidth(width, text, paint)) {
- return text;
+ final String middleText = getMiddleDisplayName(subtype);
+ if (fitsTextIntoWidth(width, middleText, paint)) {
+ return middleText;
}
- text = getShortDisplayName(subtype);
- if (fitsTextIntoWidth(width, text, paint)) {
- return text;
+ final String shortText = getShortDisplayName(subtype);
+ if (fitsTextIntoWidth(width, shortText, paint)) {
+ return shortText;
}
return "";
@@ -1009,18 +1031,19 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
// InputMethodSubtype's display name for spacebar text in its locale.
// isAdditionalSubtype (T=true, F=false)
- // locale layout | Short Middle Full
- // ------ ------ - ---- --------- ----------------------
- // en_US qwerty F En English English (US) exception
- // en_GB qwerty F En English English (UK) exception
- // fr azerty F Fr Français Français
- // fr_CA qwerty F Fr Français Français (Canada)
- // de qwertz F De Deutsch Deutsch
- // zz qwerty F QWERTY QWERTY
- // fr qwertz T Fr Français Français (QWERTZ)
- // de qwerty T De Deutsch Deutsch (QWERTY)
- // en_US azerty T En English English (US) (AZERTY)
- // zz azerty T AZERTY AZERTY
+ // locale layout | Short Middle Full
+ // ------ ------- - ---- --------- ----------------------
+ // en_US qwerty F En English English (US) exception
+ // en_GB qwerty F En English English (UK) exception
+ // es_US spanish F Es Español Español (EE.UU.) exception
+ // fr azerty F Fr Français Français
+ // fr_CA qwerty F Fr Français Français (Canada)
+ // de qwertz F De Deutsch Deutsch
+ // zz qwerty F QWERTY QWERTY
+ // fr qwertz T Fr Français Français (QWERTZ)
+ // de qwerty T De Deutsch Deutsch (QWERTY)
+ // en_US azerty T En English English (US) (AZERTY)
+ // zz azerty T AZERTY AZERTY
// Get InputMethodSubtype's full display name in its locale.
static String getFullDisplayName(final InputMethodSubtype subtype, final Resources res) {
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
index d7d4be40b..3826a39a4 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
@@ -20,6 +20,7 @@ import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.view.View;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.keyboard.internal.KeyboardParams;
@@ -39,7 +40,7 @@ public final class MoreKeysKeyboard extends Keyboard {
return mDefaultKeyCoordX;
}
- /* package for test */
+ @UsedForTesting
static class MoreKeysKeyboardParams extends KeyboardParams {
public boolean mIsFixedOrder;
/* package */int mTopRowAdjustment;
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
index a50617693..8a5b7dad5 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
@@ -19,83 +19,35 @@ package com.android.inputmethod.keyboard;
import android.content.Context;
import android.content.res.Resources;
import android.util.AttributeSet;
-import android.view.Gravity;
+import android.view.MotionEvent;
import android.view.View;
-import android.widget.PopupWindow;
-import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
-import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.InputPointers;
+import com.android.inputmethod.latin.CoordinateUtils;
import com.android.inputmethod.latin.R;
/**
* A view that renders a virtual {@link MoreKeysKeyboard}. It handles rendering of keys and
* detecting key presses and touch movements.
*/
-public final class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel {
- private final int[] mCoordinates = new int[2];
+public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel {
+ private final int[] mCoordinates = CoordinateUtils.newInstance();
private final KeyDetector mKeyDetector;
-
private Controller mController;
- private KeyboardActionListener mListener;
+ protected KeyboardActionListener mListener;
private int mOriginX;
private int mOriginY;
+ private Key mCurrentKey;
- private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy.Adapter();
-
- private final KeyboardActionListener mMoreKeysKeyboardListener =
- new KeyboardActionListener.Adapter() {
- @Override
- public void onCodeInput(int primaryCode, int x, int y) {
- // Because a more keys keyboard doesn't need proximity characters correction, we don't
- // send touch event coordinates.
- mListener.onCodeInput(
- primaryCode, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
- }
-
- @Override
- public void onTextInput(CharSequence text) {
- mListener.onTextInput(text);
- }
-
- @Override
- public void onStartBatchInput() {
- mListener.onStartBatchInput();
- }
-
- @Override
- public void onUpdateBatchInput(InputPointers batchPointers) {
- mListener.onUpdateBatchInput(batchPointers);
- }
-
- @Override
- public void onEndBatchInput(InputPointers batchPointers) {
- mListener.onEndBatchInput(batchPointers);
- }
-
- @Override
- public void onCancelInput() {
- mListener.onCancelInput();
- }
-
- @Override
- public void onPressKey(int primaryCode) {
- mListener.onPressKey(primaryCode);
- }
-
- @Override
- public void onReleaseKey(int primaryCode, boolean withSliding) {
- mListener.onReleaseKey(primaryCode, withSliding);
- }
- };
+ private int mActivePointerId;
- public MoreKeysKeyboardView(Context context, AttributeSet attrs) {
+ public MoreKeysKeyboardView(final Context context, final AttributeSet attrs) {
this(context, attrs, R.attr.moreKeysKeyboardViewStyle);
}
- public MoreKeysKeyboardView(Context context, AttributeSet attrs, int defStyle) {
+ public MoreKeysKeyboardView(final Context context, final AttributeSet attrs,
+ final int defStyle) {
super(context, attrs, defStyle);
final Resources res = context.getResources();
@@ -105,7 +57,7 @@ public final class MoreKeysKeyboardView extends KeyboardView implements MoreKeys
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final Keyboard keyboard = getKeyboard();
if (keyboard != null) {
final int width = keyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight();
@@ -117,80 +69,169 @@ public final class MoreKeysKeyboardView extends KeyboardView implements MoreKeys
}
@Override
- public void setKeyboard(Keyboard keyboard) {
+ public void setKeyboard(final Keyboard keyboard) {
super.setKeyboard(keyboard);
mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
-getPaddingTop() + mVerticalCorrection);
}
@Override
- public KeyDetector getKeyDetector() {
- return mKeyDetector;
+ public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) {
+ // More keys keyboard needs no pop-up key preview displayed, so we pass always false with a
+ // delay of 0. The delay does not matter actually since the popup is not shown anyway.
+ super.setKeyPreviewPopupEnabled(false, 0);
}
@Override
- public KeyboardActionListener getKeyboardActionListener() {
- return mMoreKeysKeyboardListener;
+ public void showMoreKeysPanel(final View parentView, final Controller controller,
+ final int pointX, final int pointY, final KeyboardActionListener listener) {
+ mController = controller;
+ mListener = listener;
+ final View container = getContainerView();
+ // The coordinates of panel's left-top corner in parentView's coordinate system.
+ final int x = pointX - getDefaultCoordX() - container.getPaddingLeft();
+ final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom();
+
+ parentView.getLocationInWindow(mCoordinates);
+ // Ensure the horizontal position of the panel does not extend past the screen edges.
+ final int maxX = parentView.getMeasuredWidth() - container.getMeasuredWidth();
+ final int panelX = Math.max(0, Math.min(maxX, x)) + CoordinateUtils.x(mCoordinates);
+ final int panelY = y + CoordinateUtils.y(mCoordinates);
+ container.setX(panelX);
+ container.setY(panelY);
+
+ mOriginX = x + container.getPaddingLeft();
+ mOriginY = y + container.getPaddingTop();
+ controller.onShowMoreKeysPanel(this);
}
- @Override
- public DrawingProxy getDrawingProxy() {
- return this;
+ /**
+ * Returns the default x coordinate for showing this panel.
+ */
+ protected int getDefaultCoordX() {
+ return ((MoreKeysKeyboard)getKeyboard()).getDefaultCoordX();
}
@Override
- public TimerProxy getTimerProxy() {
- return EMPTY_TIMER_PROXY;
+ public void onDownEvent(final int x, final int y, final int pointerId, final long eventTime) {
+ mActivePointerId = pointerId;
+ onMoveKeyInternal(x, y, pointerId);
}
@Override
- public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) {
- // More keys keyboard needs no pop-up key preview displayed, so we pass always false with a
- // delay of 0. The delay does not matter actually since the popup is not shown anyway.
- super.setKeyPreviewPopupEnabled(false, 0);
+ public void onMoveEvent(int x, int y, final int pointerId, long eventTime) {
+ if (mActivePointerId != pointerId) {
+ return;
+ }
+ final boolean hasOldKey = (mCurrentKey != null);
+ onMoveKeyInternal(x, y, pointerId);
+ if (hasOldKey && mCurrentKey == null) {
+ // If the pointer has moved too far away from any target then cancel the panel.
+ mController.onCancelMoreKeysPanel();
+ }
}
@Override
- public void showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY,
- PopupWindow window, KeyboardActionListener listener) {
- mController = controller;
- mListener = listener;
- final View container = (View)getParent();
- final MoreKeysKeyboard pane = (MoreKeysKeyboard)getKeyboard();
- final int defaultCoordX = pane.getDefaultCoordX();
- // The coordinates of panel's left-top corner in parentView's coordinate system.
- final int x = pointX - defaultCoordX - container.getPaddingLeft();
- final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom();
+ public void onUpEvent(final int x, final int y, final int pointerId, final long eventTime) {
+ if (mCurrentKey != null && mActivePointerId == pointerId) {
+ updateReleaseKeyGraphics(mCurrentKey);
+ onCodeInput(mCurrentKey.mCode, x, y);
+ mCurrentKey = null;
+ }
+ }
- window.setContentView(container);
- window.setWidth(container.getMeasuredWidth());
- window.setHeight(container.getMeasuredHeight());
- parentView.getLocationInWindow(mCoordinates);
- window.showAtLocation(parentView, Gravity.NO_GRAVITY,
- x + mCoordinates[0], y + mCoordinates[1]);
+ /**
+ * Performs the specific action for this panel when the user presses a key on the panel.
+ */
+ protected void onCodeInput(final int code, final int x, final int y) {
+ if (code == Constants.CODE_OUTPUT_TEXT) {
+ mListener.onTextInput(mCurrentKey.getOutputText());
+ } else if (code != Constants.CODE_UNSPECIFIED) {
+ mListener.onCodeInput(code, x, y);
+ }
+ }
- mOriginX = x + container.getPaddingLeft();
- mOriginY = y + container.getPaddingTop();
+ private void onMoveKeyInternal(int x, int y, int pointerId) {
+ if (mActivePointerId != pointerId) {
+ // Ignore old pointers when newer pointer is active.
+ return;
+ }
+ final Key oldKey = mCurrentKey;
+ final Key newKey = mKeyDetector.detectHitKey(x, y);
+ if (newKey != oldKey) {
+ mCurrentKey = newKey;
+ invalidateKey(mCurrentKey);
+ if (oldKey != null) {
+ updateReleaseKeyGraphics(oldKey);
+ }
+ if (newKey != null) {
+ updatePressKeyGraphics(newKey);
+ }
+ }
}
- private boolean mIsDismissing;
+ private void updateReleaseKeyGraphics(final Key key) {
+ key.onReleased();
+ invalidateKey(key);
+ }
+
+ private void updatePressKeyGraphics(final Key key) {
+ key.onPressed();
+ invalidateKey(key);
+ }
@Override
public boolean dismissMoreKeysPanel() {
- if (mIsDismissing || mController == null) return false;
- mIsDismissing = true;
- final boolean dismissed = mController.dismissMoreKeysPanel();
- mIsDismissing = false;
- return dismissed;
+ if (mController == null) return false;
+ return mController.onDismissMoreKeysPanel();
}
@Override
- public int translateX(int x) {
+ public int translateX(final int x) {
return x - mOriginX;
}
@Override
- public int translateY(int y) {
+ public int translateY(final int y) {
return y - mOriginY;
}
+
+ @Override
+ public boolean onTouchEvent(final MotionEvent me) {
+ final int action = me.getActionMasked();
+ final long eventTime = me.getEventTime();
+ final int index = me.getActionIndex();
+ final int x = (int)me.getX(index);
+ final int y = (int)me.getY(index);
+ final int pointerId = me.getPointerId(index);
+ processMotionEvent(action, x, y, pointerId, eventTime);
+ return true;
+ }
+
+ public void processMotionEvent(final int action, final int x, final int y,
+ final int pointerId, final long eventTime) {
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_POINTER_DOWN:
+ onDownEvent(x, y, pointerId, eventTime);
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_POINTER_UP:
+ onUpEvent(x, y, pointerId, eventTime);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ onMoveEvent(x, y, pointerId, eventTime);
+ break;
+ }
+ }
+
+ @Override
+ public View getContainerView() {
+ return (View)getParent();
+ }
+
+ @Override
+ public boolean isShowingInParent() {
+ return (getContainerView().getParent() != null);
+ }
}
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java
index f9a196d24..9c677e5c8 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java
@@ -17,25 +17,77 @@
package com.android.inputmethod.keyboard;
import android.view.View;
-import android.widget.PopupWindow;
-public interface MoreKeysPanel extends PointerTracker.KeyEventHandler {
+public interface MoreKeysPanel {
public interface Controller {
- public boolean dismissMoreKeysPanel();
+ /**
+ * Add the {@link MoreKeysPanel} to the target view.
+ * @param panel
+ */
+ public void onShowMoreKeysPanel(final MoreKeysPanel panel);
+
+ /**
+ * Remove the current {@link MoreKeysPanel} from the target view.
+ */
+ public boolean onDismissMoreKeysPanel();
+
+ /**
+ * Instructs the parent to cancel the panel (e.g., when entering a different input mode).
+ */
+ public void onCancelMoreKeysPanel();
}
/**
- * Show more keys panel.
+ * Initializes the layout and event handling of this {@link MoreKeysPanel} and calls the
+ * controller's onShowMoreKeysPanel to add the panel's container view.
+ *
+ * @param parentView the parent view of this {@link MoreKeysPanel}
+ * @param controller the controller that can dismiss this {@link MoreKeysPanel}
+ * @param pointX x coordinate of this {@link MoreKeysPanel}
+ * @param pointY y coordinate of this {@link MoreKeysPanel}
+ * @param listener the listener that will receive keyboard action from this
+ * {@link MoreKeysPanel}.
+ */
+ // TODO: Currently the MoreKeysPanel is inside a container view that is added to the parent.
+ // Consider the simpler approach of placing the MoreKeysPanel itself into the parent view.
+ public void showMoreKeysPanel(View parentView, Controller controller, int pointX,
+ int pointY, KeyboardActionListener listener);
+
+ /**
+ * Dismisses the more keys panel and calls the controller's onDismissMoreKeysPanel to remove
+ * the panel's container view.
+ */
+ public boolean dismissMoreKeysPanel();
+
+ /**
+ * Process a move event on the more keys panel.
+ *
+ * @param x translated x coordinate of the touch point
+ * @param y translated y coordinate of the touch point
+ * @param pointerId pointer id touch point
+ * @param eventTime timestamp of touch point
+ */
+ public void onMoveEvent(final int x, final int y, final int pointerId, final long eventTime);
+
+ /**
+ * Process a down event on the more keys panel.
+ *
+ * @param x translated x coordinate of the touch point
+ * @param y translated y coordinate of the touch point
+ * @param pointerId pointer id touch point
+ * @param eventTime timestamp of touch point
+ */
+ public void onDownEvent(final int x, final int y, final int pointerId, final long eventTime);
+
+ /**
+ * Process an up event on the more keys panel.
*
- * @param parentView the parent view of this more keys panel
- * @param controller the controller that can dismiss this more keys panel
- * @param pointX x coordinate of this more keys panel
- * @param pointY y coordinate of this more keys panel
- * @param window PopupWindow to be used to show this more keys panel
- * @param listener the listener that will receive keyboard action from this more keys panel.
+ * @param x translated x coordinate of the touch point
+ * @param y translated y coordinate of the touch point
+ * @param pointerId pointer id touch point
+ * @param eventTime timestamp of touch point
*/
- public void showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY,
- PopupWindow window, KeyboardActionListener listener);
+ public void onUpEvent(final int x, final int y, final int pointerId, final long eventTime);
/**
* Translate X-coordinate of touch event to the local X-coordinate of this
@@ -54,4 +106,14 @@ public interface MoreKeysPanel extends PointerTracker.KeyEventHandler {
* @return the local Y-coordinate to this {@link MoreKeysPanel}
*/
public int translateY(int y);
+
+ /**
+ * Return the view containing the more keys panel.
+ */
+ public View getContainerView();
+
+ /**
+ * Return whether the panel is currently being shown.
+ */
+ public boolean isShowingInParent();
}
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index d0f7cb276..0f55607a0 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -27,6 +27,8 @@ import com.android.inputmethod.keyboard.internal.GestureStroke.GestureStrokePara
import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints;
import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.CoordinateUtils;
import com.android.inputmethod.latin.InputPointers;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
@@ -75,10 +77,12 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
public TimerProxy getTimerProxy();
}
- public interface DrawingProxy extends MoreKeysPanel.Controller {
+ public interface DrawingProxy {
public void invalidateKey(Key key);
public void showKeyPreview(PointerTracker tracker);
public void dismissKeyPreview(PointerTracker tracker);
+ public void showSlidingKeyInputPreview(PointerTracker tracker);
+ public void dismissSlidingKeyInputPreview();
public void showGesturePreviewTrail(PointerTracker tracker, boolean isOldestTracker);
}
@@ -93,6 +97,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
public void cancelDoubleTapTimer();
public boolean isInDoubleTapTimeout();
public void cancelKeyTimers();
+ public void startUpdateBatchInputTimer(PointerTracker tracker);
+ public void cancelAllUpdateBatchInputTimers();
public static class Adapter implements TimerProxy {
@Override
@@ -115,6 +121,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
public boolean isInDoubleTapTimeout() { return false; }
@Override
public void cancelKeyTimers() {}
+ @Override
+ public void startUpdateBatchInputTimer(PointerTracker tracker) {}
+ @Override
+ public void cancelAllUpdateBatchInputTimers() {}
}
}
@@ -156,7 +166,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
private static final boolean sNeedsProximateBogusDownMoveUpEventHack = true;
private static final ArrayList<PointerTracker> sTrackers = CollectionUtils.newArrayList();
- private static PointerTrackerQueue sPointerTrackerQueue;
+ private static final PointerTrackerQueue sPointerTrackerQueue = new PointerTrackerQueue();
public final int mPointerId;
@@ -289,6 +299,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// The position and time at which first down event occurred.
private long mDownTime;
+ private int[] mDownCoordinates = CoordinateUtils.newInstance();
private long mUpTime;
// The current key where this pointer is.
@@ -304,11 +315,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// true if keyboard layout has been changed.
private boolean mKeyboardLayoutHasBeenChanged;
- // true if event is already translated to a key action.
- private boolean mKeyAlreadyProcessed;
+ // true if this pointer is no longer tracking touch event.
+ private boolean mIsTrackingCanceled;
- // true if this pointer has been long-pressed and is showing a more keys panel.
- private boolean mIsShowingMoreKeysPanel;
+ // the more keys panel currently being shown. equals null if no panel is active.
+ private MoreKeysPanel mMoreKeysPanel;
// true if this pointer is in a sliding key input.
boolean mIsInSlidingKeyInput;
@@ -325,13 +336,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
private final GestureStrokeWithPreviewPoints mGestureStrokeWithPreviewPoints;
- public static void init(boolean hasDistinctMultitouch,
- boolean needsPhantomSuddenMoveEventHack) {
- if (hasDistinctMultitouch) {
- sPointerTrackerQueue = new PointerTrackerQueue();
- } else {
- sPointerTrackerQueue = null;
- }
+ public static void init(final boolean needsPhantomSuddenMoveEventHack) {
sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack;
sParams = PointerTrackerParams.DEFAULT;
sGestureStrokeParams = GestureStrokeParams.DEFAULT;
@@ -375,7 +380,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
public static boolean isAnyInSlidingKeyInput() {
- return sPointerTrackerQueue != null ? sPointerTrackerQueue.isAnyInSlidingKeyInput() : false;
+ return sPointerTrackerQueue.isAnyInSlidingKeyInput();
}
public static void setKeyboardActionListener(final KeyboardActionListener listener) {
@@ -407,6 +412,17 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
}
+ public static void dismissAllMoreKeysPanels() {
+ final int trackersSize = sTrackers.size();
+ for (int i = 0; i < trackersSize; ++i) {
+ final PointerTracker tracker = sTrackers.get(i);
+ if (tracker.isShowingMoreKeysPanel()) {
+ tracker.mMoreKeysPanel.dismissMoreKeysPanel();
+ tracker.mMoreKeysPanel = null;
+ }
+ }
+ }
+
private PointerTracker(final int id, final KeyEventHandler handler) {
if (handler == null) {
throw new NullPointerException();
@@ -453,8 +469,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState();
final int code = altersCode ? key.getAltCode() : primaryCode;
if (DEBUG_LISTENER) {
- final String output = code == Keyboard.CODE_OUTPUT_TEXT
- ? key.getOutputText() : Keyboard.printableCode(code);
+ final String output = code == Constants.CODE_OUTPUT_TEXT
+ ? key.getOutputText() : Constants.printableCode(code);
Log.d(TAG, String.format("[%d] onCodeInput: %4d %4d %s%s%s", mPointerId, x, y,
output, ignoreModifierKey ? " ignoreModifier" : "",
altersCode ? " altersCode" : "", key.isEnabled() ? "" : " disabled"));
@@ -469,9 +485,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state.
if (key.isEnabled() || altersCode) {
sTimeRecorder.onCodeInput(code, eventTime);
- if (code == Keyboard.CODE_OUTPUT_TEXT) {
+ if (code == Constants.CODE_OUTPUT_TEXT) {
mListener.onTextInput(key.getOutputText());
- } else if (code != Keyboard.CODE_UNSPECIFIED) {
+ } else if (code != Constants.CODE_UNSPECIFIED) {
mListener.onCodeInput(code, x, y);
}
}
@@ -487,7 +503,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
final boolean ignoreModifierKey = mIsInSlidingKeyInputFromModifier && key.isModifier();
if (DEBUG_LISTENER) {
Log.d(TAG, String.format("[%d] onRelease : %s%s%s%s", mPointerId,
- Keyboard.printableCode(primaryCode),
+ Constants.printableCode(primaryCode),
withSliding ? " sliding" : "", ignoreModifierKey ? " ignoreModifier" : "",
key.isEnabled() ? "": " disabled"));
}
@@ -522,7 +538,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
mKeyboard = keyDetector.getKeyboard();
final int keyWidth = mKeyboard.mMostCommonKeyWidth;
final int keyHeight = mKeyboard.mMostCommonKeyHeight;
- mGestureStrokeWithPreviewPoints.setKeyboardGeometry(keyWidth);
+ mGestureStrokeWithPreviewPoints.setKeyboardGeometry(keyWidth, mKeyboard.mOccupiedHeight);
final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY);
if (newKey != mCurrentKey) {
if (mDrawingProxy != null) {
@@ -539,6 +555,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
return mIsInSlidingKeyInput;
}
+ public boolean isInSlidingKeyInputFromModifier() {
+ return mIsInSlidingKeyInputFromModifier;
+ }
+
public Key getKey() {
return mCurrentKey;
}
@@ -641,20 +661,21 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
return mGestureStrokeWithPreviewPoints;
}
- public int getLastX() {
- return mLastX;
- }
-
- public int getLastY() {
- return mLastY;
+ public void getLastCoordinates(final int[] outCoords) {
+ CoordinateUtils.set(outCoords, mLastX, mLastY);
}
public long getDownTime() {
return mDownTime;
}
+ public void getDownCoordinates(final int[] outCoords) {
+ CoordinateUtils.copy(outCoords, mDownCoordinates);
+ }
+
private Key onDownKey(final int x, final int y, final long eventTime) {
mDownTime = eventTime;
+ CoordinateUtils.set(mDownCoordinates, x, y);
mBogusMoveEventDetector.onDownKey();
return onMoveToNewKey(onMoveKeyInternal(x, y), x, y);
}
@@ -682,7 +703,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
private static int getActivePointerTrackerCount() {
- return (sPointerTrackerQueue == null) ? 1 : sPointerTrackerQueue.size();
+ return sPointerTrackerQueue.size();
+ }
+
+ private static boolean isOldestTrackerInQueue(final PointerTracker tracker) {
+ return sPointerTrackerQueue.getOldestElement() == tracker;
}
private void mayStartBatchInput(final Key key) {
@@ -701,48 +726,76 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
sLastRecognitionPointSize = 0;
sLastRecognitionTime = 0;
mListener.onStartBatchInput();
+ dismissAllMoreKeysPanels();
}
- final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this;
- mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker);
+ mTimerProxy.cancelLongPressTimer();
+ mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this));
+ }
+
+ public void updateBatchInputByTimer(final long eventTime) {
+ final int gestureTime = (int)(eventTime - sGestureFirstDownTime);
+ mGestureStrokeWithPreviewPoints.duplicateLastPointWith(gestureTime);
+ updateBatchInput(eventTime);
}
private void mayUpdateBatchInput(final long eventTime, final Key key) {
if (key != null) {
- synchronized (sAggregratedPointers) {
- final GestureStroke stroke = mGestureStrokeWithPreviewPoints;
- stroke.appendIncrementalBatchPoints(sAggregratedPointers);
- final int size = sAggregratedPointers.getPointerSize();
- if (size > sLastRecognitionPointSize
- && stroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) {
- sLastRecognitionPointSize = size;
- sLastRecognitionTime = eventTime;
- if (DEBUG_LISTENER) {
- Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d",
- mPointerId, size));
- }
- mListener.onUpdateBatchInput(sAggregratedPointers);
+ updateBatchInput(eventTime);
+ }
+ if (mIsTrackingCanceled) {
+ return;
+ }
+ mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this));
+ }
+
+ private void updateBatchInput(final long eventTime) {
+ synchronized (sAggregratedPointers) {
+ final GestureStroke stroke = mGestureStrokeWithPreviewPoints;
+ stroke.appendIncrementalBatchPoints(sAggregratedPointers);
+ final int size = sAggregratedPointers.getPointerSize();
+ if (size > sLastRecognitionPointSize
+ && stroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) {
+ sLastRecognitionPointSize = size;
+ sLastRecognitionTime = eventTime;
+ if (DEBUG_LISTENER) {
+ Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d", mPointerId,
+ size));
}
+ mTimerProxy.startUpdateBatchInputTimer(this);
+ mListener.onUpdateBatchInput(sAggregratedPointers);
}
}
- final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this;
- mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker);
}
private void mayEndBatchInput(final long eventTime) {
synchronized (sAggregratedPointers) {
mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers);
if (getActivePointerTrackerCount() == 1) {
- if (DEBUG_LISTENER) {
- Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d",
- mPointerId, sAggregratedPointers.getPointerSize()));
- }
sInGesture = false;
sTimeRecorder.onEndBatchInput(eventTime);
- mListener.onEndBatchInput(sAggregratedPointers);
+ mTimerProxy.cancelAllUpdateBatchInputTimers();
+ if (!mIsTrackingCanceled) {
+ if (DEBUG_LISTENER) {
+ Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d",
+ mPointerId, sAggregratedPointers.getPointerSize()));
+ }
+ mListener.onEndBatchInput(sAggregratedPointers);
+ }
}
}
- final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this;
- mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker);
+ if (mIsTrackingCanceled) {
+ return;
+ }
+ mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this));
+ }
+
+ private void cancelBatchInput() {
+ sPointerTrackerQueue.cancelAllPointerTracker();
+ sInGesture = false;
+ if (DEBUG_LISTENER) {
+ Log.d(TAG, String.format("[%d] onCancelBatchInput", mPointerId));
+ }
+ mListener.onCancelBatchInput();
}
public void processMotionEvent(final int action, final int x, final int y, final long eventTime,
@@ -770,7 +823,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (DEBUG_EVENT) {
printTouchEvent("onDownEvent:", x, y, eventTime);
}
-
mDrawingProxy = handler.getDrawingProxy();
mTimerProxy = handler.getTimerProxy();
setKeyboardActionListener(handler.getKeyboardActionListener());
@@ -787,29 +839,26 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.pointerTracker_onDownEvent(deltaT, distance * distance);
}
- mKeyAlreadyProcessed = true;
+ cancelTracking();
return;
}
}
final Key key = getKeyOn(x, y);
mBogusMoveEventDetector.onActualDownEvent(x, y);
- final PointerTrackerQueue queue = sPointerTrackerQueue;
- if (queue != null) {
- if (key != null && key.isModifier()) {
- // Before processing a down event of modifier key, all pointers already being
- // tracked should be released.
- queue.releaseAllPointers(eventTime);
- }
- queue.add(this);
+ if (key != null && key.isModifier()) {
+ // Before processing a down event of modifier key, all pointers already being
+ // tracked should be released.
+ sPointerTrackerQueue.releaseAllPointers(eventTime);
}
+ sPointerTrackerQueue.add(this);
onDownEventInternal(x, y, eventTime);
if (!sShouldHandleGesture) {
return;
}
- // A gesture should start only from the letter key.
+ // A gesture should start only from a non-modifier key.
mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard()
- && !mIsShowingMoreKeysPanel && key != null && Keyboard.isLetterCode(key.mCode);
+ && key != null && !key.isModifier();
if (mIsDetectingGesture) {
if (getActivePointerTrackerCount() == 1) {
sGestureFirstDownTime = eventTime;
@@ -819,6 +868,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
}
+ private boolean isShowingMoreKeysPanel() {
+ return (mMoreKeysPanel != null);
+ }
+
private void onDownEventInternal(final int x, final int y, final long eventTime) {
Key key = onDownKey(x, y, eventTime);
// Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding
@@ -827,7 +880,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|| (key != null && key.isModifier())
|| mKeyDetector.alwaysAllowsSlidingInput();
mKeyboardLayoutHasBeenChanged = false;
- mKeyAlreadyProcessed = false;
+ mIsTrackingCanceled = false;
resetSlidingKeyInput();
if (key != null) {
// This onPress call may have changed keyboard layout. Those cases are detected at
@@ -853,13 +906,24 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
private void resetSlidingKeyInput() {
mIsInSlidingKeyInput = false;
mIsInSlidingKeyInputFromModifier = false;
+ mDrawingProxy.dismissSlidingKeyInputPreview();
}
private void onGestureMoveEvent(final int x, final int y, final long eventTime,
final boolean isMajorEvent, final Key key) {
final int gestureTime = (int)(eventTime - sGestureFirstDownTime);
if (mIsDetectingGesture) {
- mGestureStrokeWithPreviewPoints.addPoint(x, y, gestureTime, isMajorEvent);
+ final boolean onValidArea = mGestureStrokeWithPreviewPoints.addPointOnKeyboard(
+ x, y, gestureTime, isMajorEvent);
+ if (!onValidArea) {
+ cancelBatchInput();
+ return;
+ }
+ // If the MoreKeysPanel is showing then do not attempt to enter gesture mode. However,
+ // the gestured touch points are still being recorded in case the panel is dismissed.
+ if (isShowingMoreKeysPanel()) {
+ return;
+ }
mayStartBatchInput(key);
if (sInGesture) {
mayUpdateBatchInput(eventTime, key);
@@ -871,10 +935,16 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (DEBUG_MOVE_EVENT) {
printTouchEvent("onMoveEvent:", x, y, eventTime);
}
- if (mKeyAlreadyProcessed) {
+ if (mIsTrackingCanceled) {
return;
}
+ if (isShowingMoreKeysPanel()) {
+ final int translatedX = mMoreKeysPanel.translateX(x);
+ final int translatedY = mMoreKeysPanel.translateY(y);
+ mMoreKeysPanel.onMoveEvent(translatedX, translatedY, mPointerId, eventTime);
+ }
+
if (sShouldHandleGesture && me != null) {
// Add historical points to gesture path.
final int pointerIndex = me.findPointerIndex(mPointerId);
@@ -888,141 +958,160 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
}
+ if (isShowingMoreKeysPanel()) {
+ // Do not handle sliding keys (or show key pop-ups) when the MoreKeysPanel is visible.
+ return;
+ }
onMoveEventInternal(x, y, eventTime);
}
+ private void processSlidingKeyInput(final Key newKey, final int x, final int y,
+ final long eventTime) {
+ // This onPress call may have changed keyboard layout. Those cases are detected
+ // at {@link #setKeyboard}. In those cases, we should update key according
+ // to the new keyboard layout.
+ Key key = newKey;
+ if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) {
+ key = onMoveKey(x, y);
+ }
+ onMoveToNewKey(key, x, y);
+ startLongPressTimer(key);
+ setPressedKeyGraphics(key, eventTime);
+ }
+
+ private void processPhantomSuddenMoveHack(final Key key, final int x, final int y,
+ final long eventTime, final Key oldKey, final int lastX, final int lastY) {
+ if (DEBUG_MODE) {
+ Log.w(TAG, String.format("[%d] onMoveEvent:"
+ + " phantom sudden move event (distance=%d) is translated to "
+ + "up[%d,%d,%s]/down[%d,%d,%s] events", mPointerId,
+ getDistance(x, y, lastX, lastY),
+ lastX, lastY, Constants.printableCode(oldKey.mCode),
+ x, y, Constants.printableCode(key.mCode)));
+ }
+ // TODO: This should be moved to outside of this nested if-clause?
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY);
+ }
+ onUpEventInternal(x, y, eventTime);
+ onDownEventInternal(x, y, eventTime);
+ }
+
+ private void processProximateBogusDownMoveUpEventHack(final Key key, final int x, final int y,
+ final long eventTime, final Key oldKey, final int lastX, final int lastY) {
+ if (DEBUG_MODE) {
+ final float keyDiagonal = (float)Math.hypot(
+ mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight);
+ final float radiusRatio =
+ mBogusMoveEventDetector.getDistanceFromDownEvent(x, y)
+ / keyDiagonal;
+ Log.w(TAG, String.format("[%d] onMoveEvent:"
+ + " bogus down-move-up event (raidus=%.2f key diagonal) is "
+ + " translated to up[%d,%d,%s]/down[%d,%d,%s] events",
+ mPointerId, radiusRatio,
+ lastX, lastY, Constants.printableCode(oldKey.mCode),
+ x, y, Constants.printableCode(key.mCode)));
+ }
+ onUpEventInternal(x, y, eventTime);
+ onDownEventInternal(x, y, eventTime);
+ }
+
+ private void processSildeOutFromOldKey(final Key oldKey) {
+ setReleasedKeyGraphics(oldKey);
+ callListenerOnRelease(oldKey, oldKey.mCode, true);
+ startSlidingKeyInput(oldKey);
+ mTimerProxy.cancelKeyTimers();
+ }
+
+ private void slideFromOldKeyToNewKey(final Key key, final int x, final int y,
+ final long eventTime, final Key oldKey, final int lastX, final int lastY) {
+ // The pointer has been slid in to the new key from the previous key, we must call
+ // onRelease() first to notify that the previous key has been released, then call
+ // onPress() to notify that the new key is being pressed.
+ processSildeOutFromOldKey(oldKey);
+ startRepeatKey(key);
+ if (mIsAllowedSlidingKeyInput) {
+ processSlidingKeyInput(key, x, y, eventTime);
+ }
+ // HACK: On some devices, quick successive touches may be reported as a sudden move by
+ // touch panel firmware. This hack detects such cases and translates the move event to
+ // successive up and down events.
+ // TODO: Should find a way to balance gesture detection and this hack.
+ else if (sNeedsPhantomSuddenMoveEventHack
+ && getDistance(x, y, lastX, lastY) >= mPhantonSuddenMoveThreshold) {
+ processPhantomSuddenMoveHack(key, x, y, eventTime, oldKey, lastX, lastY);
+ }
+ // HACK: On some devices, quick successive proximate touches may be reported as a bogus
+ // down-move-up event by touch panel firmware. This hack detects such cases and breaks
+ // these events into separate up and down events.
+ else if (sNeedsProximateBogusDownMoveUpEventHack && sTimeRecorder.isInFastTyping(eventTime)
+ && mBogusMoveEventDetector.isCloseToActualDownEvent(x, y)) {
+ processProximateBogusDownMoveUpEventHack(key, x, y, eventTime, oldKey, lastX, lastY);
+ }
+ // 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.
+ else if (getActivePointerTrackerCount() > 1
+ && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) {
+ if (DEBUG_MODE) {
+ Log.w(TAG, String.format("[%d] onMoveEvent:"
+ + " detected sliding finger while multi touching", mPointerId));
+ }
+ onUpEvent(x, y, eventTime);
+ cancelTracking();
+ setReleasedKeyGraphics(oldKey);
+ } else {
+ if (!mIsDetectingGesture) {
+ cancelTracking();
+ }
+ setReleasedKeyGraphics(oldKey);
+ }
+ }
+
+ private void slideOutFromOldKey(final Key oldKey, final int x, final int y) {
+ // The pointer has been slid out from the previous key, we must call onRelease() to
+ // notify that the previous key has been released.
+ processSildeOutFromOldKey(oldKey);
+ if (mIsAllowedSlidingKeyInput) {
+ onMoveToNewKey(null, x, y);
+ } else {
+ if (!mIsDetectingGesture) {
+ cancelTracking();
+ }
+ }
+ }
+
private void onMoveEventInternal(final int x, final int y, final long eventTime) {
final int lastX = mLastX;
final int lastY = mLastY;
final Key oldKey = mCurrentKey;
- Key key = onMoveKey(x, y);
+ final Key newKey = onMoveKey(x, y);
if (sShouldHandleGesture) {
// Register move event on gesture tracker.
- onGestureMoveEvent(x, y, eventTime, true /* isMajorEvent */, key);
+ onGestureMoveEvent(x, y, eventTime, true /* isMajorEvent */, newKey);
if (sInGesture) {
- mTimerProxy.cancelLongPressTimer();
mCurrentKey = null;
setReleasedKeyGraphics(oldKey);
return;
}
}
- if (key != null) {
- if (oldKey == null) {
+ if (newKey != null) {
+ if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) {
+ slideFromOldKeyToNewKey(newKey, x, y, eventTime, oldKey, lastX, lastY);
+ } else if (oldKey == null) {
// The pointer has been slid in to the new key, but the finger was not on any keys.
// In this case, we must call onPress() to notify that the new key is being pressed.
- // This onPress call may have changed keyboard layout. Those cases are detected at
- // {@link #setKeyboard}. In those cases, we should update key according to the
- // new keyboard layout.
- if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) {
- key = onMoveKey(x, y);
- }
- onMoveToNewKey(key, x, y);
- startLongPressTimer(key);
- setPressedKeyGraphics(key, eventTime);
- } else if (isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, key)) {
- // The pointer has been slid in to the new key from the previous key, we must call
- // onRelease() first to notify that the previous key has been released, then call
- // onPress() to notify that the new key is being pressed.
- setReleasedKeyGraphics(oldKey);
- callListenerOnRelease(oldKey, oldKey.mCode, true);
- startSlidingKeyInput(oldKey);
- mTimerProxy.cancelKeyTimers();
- startRepeatKey(key);
- if (mIsAllowedSlidingKeyInput) {
- // This onPress call may have changed keyboard layout. Those cases are detected
- // at {@link #setKeyboard}. In those cases, we should update key according
- // to the new keyboard layout.
- if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) {
- key = onMoveKey(x, y);
- }
- onMoveToNewKey(key, x, y);
- startLongPressTimer(key);
- setPressedKeyGraphics(key, eventTime);
- } else {
- // HACK: On some devices, quick successive touches may be reported as a sudden
- // move by touch panel firmware. This hack detects such cases and translates the
- // move event to successive up and down events.
- // TODO: Should find a way to balance gesture detection and this hack.
- if (sNeedsPhantomSuddenMoveEventHack
- && getDistance(x, y, lastX, lastY) >= mPhantonSuddenMoveThreshold) {
- if (DEBUG_MODE) {
- Log.w(TAG, String.format("[%d] onMoveEvent:"
- + " phantom sudden move event (distance=%d) is translated to "
- + "up[%d,%d,%s]/down[%d,%d,%s] events", mPointerId,
- getDistance(x, y, lastX, lastY),
- lastX, lastY, Keyboard.printableCode(oldKey.mCode),
- x, y, Keyboard.printableCode(key.mCode)));
- }
- // TODO: This should be moved to outside of this nested if-clause?
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY);
- }
- onUpEventInternal(eventTime);
- onDownEventInternal(x, y, eventTime);
- }
- // HACK: On some devices, quick successive proximate touches may be reported as
- // a bogus down-move-up event by touch panel firmware. This hack detects such
- // cases and breaks these events into separate up and down events.
- else if (sNeedsProximateBogusDownMoveUpEventHack
- && sTimeRecorder.isInFastTyping(eventTime)
- && mBogusMoveEventDetector.isCloseToActualDownEvent(x, y)) {
- if (DEBUG_MODE) {
- final float keyDiagonal = (float)Math.hypot(
- mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight);
- final float radiusRatio =
- mBogusMoveEventDetector.getDistanceFromDownEvent(x, y)
- / keyDiagonal;
- Log.w(TAG, String.format("[%d] onMoveEvent:"
- + " bogus down-move-up event (raidus=%.2f key diagonal) is "
- + " translated to up[%d,%d,%s]/down[%d,%d,%s] events",
- mPointerId, radiusRatio,
- lastX, lastY, Keyboard.printableCode(oldKey.mCode),
- x, y, Keyboard.printableCode(key.mCode)));
- }
- onUpEventInternal(eventTime);
- 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 (getActivePointerTrackerCount() > 1 && sPointerTrackerQueue != null
- && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) {
- if (DEBUG_MODE) {
- Log.w(TAG, String.format("[%d] onMoveEvent:"
- + " detected sliding finger while multi touching",
- mPointerId));
- }
- onUpEvent(x, y, eventTime);
- mKeyAlreadyProcessed = true;
- }
- if (!mIsDetectingGesture) {
- mKeyAlreadyProcessed = true;
- }
- setReleasedKeyGraphics(oldKey);
- }
- }
+ processSlidingKeyInput(newKey, x, y, eventTime);
}
- } else {
- if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, key)) {
- // The pointer has been slid out from the previous key, we must call onRelease() to
- // notify that the previous key has been released.
- setReleasedKeyGraphics(oldKey);
- callListenerOnRelease(oldKey, oldKey.mCode, true);
- startSlidingKeyInput(oldKey);
- mTimerProxy.cancelLongPressTimer();
- if (mIsAllowedSlidingKeyInput) {
- onMoveToNewKey(key, x, y);
- } else {
- if (!mIsDetectingGesture) {
- mKeyAlreadyProcessed = true;
- }
- }
+ } else { // newKey == null
+ if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) {
+ slideOutFromOldKey(oldKey, x, y);
}
}
+ mDrawingProxy.showSlidingKeyInputPreview(this);
}
public void onUpEvent(final int x, final int y, final long eventTime) {
@@ -1030,22 +1119,17 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
printTouchEvent("onUpEvent :", x, y, eventTime);
}
- final PointerTrackerQueue queue = sPointerTrackerQueue;
- if (queue != null) {
- if (!sInGesture) {
- if (mCurrentKey != null && mCurrentKey.isModifier()) {
- // Before processing an up event of modifier key, all pointers already being
- // tracked should be released.
- queue.releaseAllPointersExcept(this, eventTime);
- } else {
- queue.releaseAllPointersOlderThan(this, eventTime);
- }
+ if (!sInGesture) {
+ if (mCurrentKey != null && mCurrentKey.isModifier()) {
+ // Before processing an up event of modifier key, all pointers already being
+ // tracked should be released.
+ sPointerTrackerQueue.releaseAllPointersExcept(this, eventTime);
+ } else {
+ sPointerTrackerQueue.releaseAllPointersOlderThan(this, eventTime);
}
}
- onUpEventInternal(eventTime);
- if (queue != null) {
- queue.remove(this);
- }
+ onUpEventInternal(x, y, eventTime);
+ sPointerTrackerQueue.remove(this);
}
// Let this pointer tracker know that one of newer-than-this pointer trackers got an up event.
@@ -1054,13 +1138,16 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
@Override
public void onPhantomUpEvent(final long eventTime) {
if (DEBUG_EVENT) {
- printTouchEvent("onPhntEvent:", getLastX(), getLastY(), eventTime);
+ printTouchEvent("onPhntEvent:", mLastX, mLastY, eventTime);
}
- onUpEventInternal(eventTime);
- mKeyAlreadyProcessed = true;
+ if (isShowingMoreKeysPanel()) {
+ return;
+ }
+ onUpEventInternal(mLastX, mLastY, eventTime);
+ cancelTracking();
}
- private void onUpEventInternal(final long eventTime) {
+ private void onUpEventInternal(final int x, final int y, final long eventTime) {
mTimerProxy.cancelKeyTimers();
resetSlidingKeyInput();
mIsDetectingGesture = false;
@@ -1068,9 +1155,16 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
mCurrentKey = null;
// Release the last pressed key.
setReleasedKeyGraphics(currentKey);
- if (mIsShowingMoreKeysPanel) {
- mDrawingProxy.dismissMoreKeysPanel();
- mIsShowingMoreKeysPanel = false;
+
+ if (isShowingMoreKeysPanel()) {
+ if (!mIsTrackingCanceled) {
+ final int translatedX = mMoreKeysPanel.translateX(x);
+ final int translatedY = mMoreKeysPanel.translateY(y);
+ mMoreKeysPanel.onUpEvent(translatedX, translatedY, mPointerId, eventTime);
+ }
+ mMoreKeysPanel.dismissMoreKeysPanel();
+ mMoreKeysPanel = null;
+ return;
}
if (sInGesture) {
@@ -1081,7 +1175,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
return;
}
- if (mKeyAlreadyProcessed) {
+ if (mIsTrackingCanceled) {
return;
}
if (currentKey != null && !currentKey.isRepeatable()) {
@@ -1089,19 +1183,24 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
}
- public void onShowMoreKeysPanel(final int x, final int y, final KeyEventHandler handler) {
- onLongPressed();
- mIsShowingMoreKeysPanel = true;
- onDownEvent(x, y, SystemClock.uptimeMillis(), handler);
+ public void onShowMoreKeysPanel(final int translatedX, final int translatedY,
+ final MoreKeysPanel panel) {
+ setReleasedKeyGraphics(mCurrentKey);
+ final long eventTime = SystemClock.uptimeMillis();
+ mMoreKeysPanel = panel;
+ mMoreKeysPanel.onDownEvent(translatedX, translatedY, mPointerId, eventTime);
+ }
+
+ @Override
+ public void cancelTracking() {
+ mIsTrackingCanceled = true;
}
public void onLongPressed() {
- mKeyAlreadyProcessed = true;
+ resetSlidingKeyInput();
+ cancelTracking();
setReleasedKeyGraphics(mCurrentKey);
- final PointerTrackerQueue queue = sPointerTrackerQueue;
- if (queue != null) {
- queue.remove(this);
- }
+ sPointerTrackerQueue.remove(this);
}
public void onCancelEvent(final int x, final int y, final long eventTime) {
@@ -1109,11 +1208,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
printTouchEvent("onCancelEvt:", x, y, eventTime);
}
- final PointerTrackerQueue queue = sPointerTrackerQueue;
- if (queue != null) {
- queue.releaseAllPointersExcept(this, eventTime);
- queue.remove(this);
+ if (sInGesture) {
+ cancelBatchInput();
}
+ sPointerTrackerQueue.cancelAllPointerTracker();
+ sPointerTrackerQueue.releaseAllPointers(eventTime);
onCancelEventInternal();
}
@@ -1121,9 +1220,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
mTimerProxy.cancelKeyTimers();
setReleasedKeyGraphics(mCurrentKey);
resetSlidingKeyInput();
- if (mIsShowingMoreKeysPanel) {
- mDrawingProxy.dismissMoreKeysPanel();
- mIsShowingMoreKeysPanel = false;
+ if (isShowingMoreKeysPanel()) {
+ mMoreKeysPanel.dismissMoreKeysPanel();
+ mMoreKeysPanel = null;
}
}
@@ -1149,38 +1248,38 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
final Key curKey = mCurrentKey;
if (newKey == curKey) {
return false;
- } else if (curKey != null) {
- final int keyHysteresisDistanceSquared = mKeyDetector.getKeyHysteresisDistanceSquared(
- mIsInSlidingKeyInputFromModifier);
- final int distanceFromKeyEdgeSquared = curKey.squaredDistanceToEdge(x, y);
- if (distanceFromKeyEdgeSquared >= keyHysteresisDistanceSquared) {
- if (DEBUG_MODE) {
- final float distanceToEdgeRatio = (float)Math.sqrt(distanceFromKeyEdgeSquared)
- / mKeyboard.mMostCommonKeyWidth;
- Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:"
- +" %.2f key width from key edge",
- mPointerId, distanceToEdgeRatio));
- }
- return true;
+ }
+ if (curKey == null /* && newKey != null */) {
+ return true;
+ }
+ // Here curKey points to the different key from newKey.
+ final int keyHysteresisDistanceSquared = mKeyDetector.getKeyHysteresisDistanceSquared(
+ mIsInSlidingKeyInputFromModifier);
+ final int distanceFromKeyEdgeSquared = curKey.squaredDistanceToEdge(x, y);
+ if (distanceFromKeyEdgeSquared >= keyHysteresisDistanceSquared) {
+ if (DEBUG_MODE) {
+ final float distanceToEdgeRatio = (float)Math.sqrt(distanceFromKeyEdgeSquared)
+ / mKeyboard.mMostCommonKeyWidth;
+ Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:"
+ +" %.2f key width from key edge", mPointerId, distanceToEdgeRatio));
}
- if (sNeedsProximateBogusDownMoveUpEventHack && !mIsAllowedSlidingKeyInput
- && sTimeRecorder.isInFastTyping(eventTime)
- && mBogusMoveEventDetector.hasTraveledLongDistance(x, y)) {
- if (DEBUG_MODE) {
- final float keyDiagonal = (float)Math.hypot(
- mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight);
- final float lengthFromDownRatio =
- mBogusMoveEventDetector.mAccumulatedDistanceFromDownKey / keyDiagonal;
- Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:"
- + " %.2f key diagonal from virtual down point",
- mPointerId, lengthFromDownRatio));
- }
- return true;
+ return true;
+ }
+ if (sNeedsProximateBogusDownMoveUpEventHack && !mIsAllowedSlidingKeyInput
+ && sTimeRecorder.isInFastTyping(eventTime)
+ && mBogusMoveEventDetector.hasTraveledLongDistance(x, y)) {
+ if (DEBUG_MODE) {
+ final float keyDiagonal = (float)Math.hypot(
+ mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight);
+ final float lengthFromDownRatio =
+ mBogusMoveEventDetector.mAccumulatedDistanceFromDownKey / keyDiagonal;
+ Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:"
+ + " %.2f key diagonal from virtual down point",
+ mPointerId, lengthFromDownRatio));
}
- return false;
- } else { // curKey == null && newKey != null
return true;
}
+ return false;
}
private void startLongPressTimer(final Key key) {
@@ -1205,6 +1304,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
final Key key = mKeyDetector.detectHitKey(x, y);
final String code = KeyDetector.printableCode(key);
Log.d(TAG, String.format("[%d]%s%s %4d %4d %5d %s", mPointerId,
- (mKeyAlreadyProcessed ? "-" : " "), title, x, y, eventTime, code));
+ (mIsTrackingCanceled ? "-" : " "), title, x, y, eventTime, code));
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index 06a9e9252..b5ba98d85 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.keyboard;
import android.graphics.Rect;
import android.text.TextUtils;
+import android.util.Log;
import com.android.inputmethod.keyboard.internal.TouchPositionCorrection;
import com.android.inputmethod.latin.Constants;
@@ -26,11 +27,14 @@ import com.android.inputmethod.latin.JniUtils;
import java.util.Arrays;
public final class ProximityInfo {
+ private static final String TAG = ProximityInfo.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
/** MAX_PROXIMITY_CHARS_SIZE must be the same as MAX_PROXIMITY_CHARS_SIZE_INTERNAL
* in defines.h */
public static final int MAX_PROXIMITY_CHARS_SIZE = 16;
/** Number of key widths from current touch point to search for nearest keys. */
- private static float SEARCH_DISTANCE = 1.2f;
+ private static final float SEARCH_DISTANCE = 1.2f;
private static final Key[] EMPTY_KEY_ARRAY = new Key[0];
private static final float DEFAULT_TOUCH_POSITION_CORRECTION_RADIUS = 0.15f;
@@ -95,6 +99,7 @@ public final class ProximityInfo {
JniUtils.loadNativeLibrary();
}
+ // TODO: Stop passing proximityCharsArray
private native long setProximityInfoNative(
String locale, int maxProximityCharsSize, int displayWidth,
int displayHeight, int gridWidth, int gridHeight,
@@ -105,22 +110,56 @@ public final class ProximityInfo {
private native void releaseProximityInfoNative(long nativeProximityInfo);
- private final long createNativeProximityInfo(
- final TouchPositionCorrection touchPositionCorrection) {
+ private static boolean needsProximityInfo(final Key key) {
+ // Don't include special keys into ProximityInfo.
+ return key.mCode >= Constants.CODE_SPACE;
+ }
+
+ private static int getProximityInfoKeysCount(final Key[] keys) {
+ int count = 0;
+ for (final Key key : keys) {
+ if (needsProximityInfo(key)) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private long createNativeProximityInfo(final TouchPositionCorrection touchPositionCorrection) {
final Key[][] gridNeighborKeys = mGridNeighbors;
- final int keyboardWidth = mKeyboardMinWidth;
- final int keyboardHeight = mKeyboardHeight;
- final Key[] keys = mKeys;
final int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE];
Arrays.fill(proximityCharsArray, Constants.NOT_A_CODE);
for (int i = 0; i < mGridSize; ++i) {
final int proximityCharsLength = gridNeighborKeys[i].length;
+ int infoIndex = i * MAX_PROXIMITY_CHARS_SIZE;
for (int j = 0; j < proximityCharsLength; ++j) {
- proximityCharsArray[i * MAX_PROXIMITY_CHARS_SIZE + j] =
- gridNeighborKeys[i][j].mCode;
+ final Key neighborKey = gridNeighborKeys[i][j];
+ // Excluding from proximityCharsArray
+ if (!needsProximityInfo(neighborKey)) {
+ continue;
+ }
+ proximityCharsArray[infoIndex] = neighborKey.mCode;
+ infoIndex++;
}
}
- final int keyCount = keys.length;
+ if (DEBUG) {
+ final StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < mGridSize; i++) {
+ sb.setLength(0);
+ for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE; j++) {
+ final int code = proximityCharsArray[i * MAX_PROXIMITY_CHARS_SIZE + j];
+ if (code == Constants.NOT_A_CODE) {
+ break;
+ }
+ if (sb.length() > 0) sb.append(" ");
+ sb.append(Constants.printableCode(code));
+ }
+ Log.d(TAG, "proxmityChars["+i+"]: " + sb);
+ }
+ }
+
+ final Key[] keys = mKeys;
+ final int keyCount = getProximityInfoKeysCount(keys);
final int[] keyXCoordinates = new int[keyCount];
final int[] keyYCoordinates = new int[keyCount];
final int[] keyWidths = new int[keyCount];
@@ -130,46 +169,73 @@ public final class ProximityInfo {
final float[] sweetSpotCenterYs;
final float[] sweetSpotRadii;
- for (int i = 0; i < keyCount; ++i) {
- final Key key = keys[i];
- keyXCoordinates[i] = key.mX;
- keyYCoordinates[i] = key.mY;
- keyWidths[i] = key.mWidth;
- keyHeights[i] = key.mHeight;
- keyCharCodes[i] = key.mCode;
+ for (int infoIndex = 0, keyIndex = 0; keyIndex < keys.length; keyIndex++) {
+ final Key key = keys[keyIndex];
+ // Excluding from key coordinate arrays
+ if (!needsProximityInfo(key)) {
+ continue;
+ }
+ keyXCoordinates[infoIndex] = key.mX;
+ keyYCoordinates[infoIndex] = key.mY;
+ keyWidths[infoIndex] = key.mWidth;
+ keyHeights[infoIndex] = key.mHeight;
+ keyCharCodes[infoIndex] = key.mCode;
+ infoIndex++;
}
if (touchPositionCorrection != null && touchPositionCorrection.isValid()) {
+ if (DEBUG) {
+ Log.d(TAG, "touchPositionCorrection: ON");
+ }
sweetSpotCenterXs = new float[keyCount];
sweetSpotCenterYs = new float[keyCount];
sweetSpotRadii = new float[keyCount];
+ final int rows = touchPositionCorrection.getRows();
final float defaultRadius = DEFAULT_TOUCH_POSITION_CORRECTION_RADIUS
* (float)Math.hypot(mMostCommonKeyWidth, mMostCommonKeyHeight);
- for (int i = 0; i < keyCount; i++) {
- final Key key = keys[i];
+ for (int infoIndex = 0, keyIndex = 0; keyIndex < keys.length; keyIndex++) {
+ final Key key = keys[keyIndex];
+ // Excluding from touch position correction arrays
+ if (!needsProximityInfo(key)) {
+ continue;
+ }
final Rect hitBox = key.mHitBox;
- sweetSpotCenterXs[i] = hitBox.exactCenterX();
- sweetSpotCenterYs[i] = hitBox.exactCenterY();
- sweetSpotRadii[i] = defaultRadius;
+ sweetSpotCenterXs[infoIndex] = hitBox.exactCenterX();
+ sweetSpotCenterYs[infoIndex] = hitBox.exactCenterY();
+ sweetSpotRadii[infoIndex] = defaultRadius;
final int row = hitBox.top / mMostCommonKeyHeight;
- if (row < touchPositionCorrection.getRows()) {
+ if (row < rows) {
final int hitBoxWidth = hitBox.width();
final int hitBoxHeight = hitBox.height();
final float hitBoxDiagonal = (float)Math.hypot(hitBoxWidth, hitBoxHeight);
- sweetSpotCenterXs[i] += touchPositionCorrection.getX(row) * hitBoxWidth;
- sweetSpotCenterYs[i] += touchPositionCorrection.getY(row) * hitBoxHeight;
- sweetSpotRadii[i] = touchPositionCorrection.getRadius(row) * hitBoxDiagonal;
+ sweetSpotCenterXs[infoIndex] +=
+ touchPositionCorrection.getX(row) * hitBoxWidth;
+ sweetSpotCenterYs[infoIndex] +=
+ touchPositionCorrection.getY(row) * hitBoxHeight;
+ sweetSpotRadii[infoIndex] =
+ touchPositionCorrection.getRadius(row) * hitBoxDiagonal;
}
+ if (DEBUG) {
+ Log.d(TAG, String.format(
+ " [%2d] row=%d x/y/r=%7.2f/%7.2f/%5.2f %s code=%s", infoIndex, row,
+ sweetSpotCenterXs[infoIndex], sweetSpotCenterYs[infoIndex],
+ sweetSpotRadii[infoIndex], (row < rows ? "correct" : "default"),
+ Constants.printableCode(key.mCode)));
+ }
+ infoIndex++;
}
} else {
sweetSpotCenterXs = sweetSpotCenterYs = sweetSpotRadii = null;
+ if (DEBUG) {
+ Log.d(TAG, "touchPositionCorrection: OFF");
+ }
}
+ // TODO: Stop passing proximityCharsArray
return setProximityInfoNative(mLocaleStr, MAX_PROXIMITY_CHARS_SIZE,
- keyboardWidth, keyboardHeight, mGridWidth, mGridHeight, mMostCommonKeyWidth,
- proximityCharsArray,
- keyCount, keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes,
- sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
+ mKeyboardMinWidth, mKeyboardHeight, mGridWidth, mGridHeight, mMostCommonKeyWidth,
+ proximityCharsArray, keyCount, keyXCoordinates, keyYCoordinates, keyWidths,
+ keyHeights, keyCharCodes, sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
}
public long getNativeProximityInfo() {
@@ -221,7 +287,7 @@ public final class ProximityInfo {
return;
}
int index = 0;
- if (primaryKeyCode > Keyboard.CODE_SPACE) {
+ if (primaryKeyCode > Constants.CODE_SPACE) {
dest[index++] = primaryKeyCode;
}
final Key[] nearestKeys = getNearestKeys(x, y);
@@ -230,7 +296,7 @@ public final class ProximityInfo {
break;
}
final int code = key.mCode;
- if (code <= Keyboard.CODE_SPACE) {
+ if (code <= Constants.CODE_SPACE) {
break;
}
dest[index++] = code;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
index 699aaeaef..3a57f673a 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
@@ -19,7 +19,6 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.os.SystemClock;
import com.android.inputmethod.latin.Constants;
@@ -118,98 +117,7 @@ final class GesturePreviewTrail {
/ params.mTrailLingerDuration, 0.0f);
}
- static final class WorkingSet {
- // Input
- // Previous point (P1) coordinates and trail radius.
- public float p1x, p1y;
- public float r1;
- // Current point (P2) coordinates and trail radius.
- public float p2x, p2y;
- public float r2;
-
- // Output
- // Closing point of arc at P1.
- public float p1ax, p1ay;
- // Opening point of arc at P1.
- public float p1bx, p1by;
- // Opening point of arc at P2.
- public float p2ax, p2ay;
- // Closing point of arc at P2.
- public float p2bx, p2by;
- // Start angle of the trail arcs.
- public float aa;
- // Sweep angle of the trail arc at P1.
- public float a1;
- public RectF arc1 = new RectF();
- // Sweep angle of the trail arc at P2.
- public float a2;
- public RectF arc2 = new RectF();
- }
-
- private static final float RIGHT_ANGLE = (float)(Math.PI / 2.0d);
- private static final float RADIAN_TO_DEGREE = (float)(180.0d / Math.PI);
-
- private static boolean calculatePathPoints(final WorkingSet w) {
- final float dx = w.p2x - w.p1x;
- final float dy = w.p2y - w.p1y;
- // Distance of the points.
- final double l = Math.hypot(dx, dy);
- if (Double.compare(0.0d, l) == 0) {
- return false;
- }
- // Angle of the line p1-p2
- final float a = (float)Math.atan2(dy, dx);
- // Difference of trail cap radius.
- final float dr = w.r2 - w.r1;
- // Variation of angle at trail cap.
- final float ar = (float)Math.asin(dr / l);
- // The start angle of trail cap arc at P1.
- final float aa = a - (RIGHT_ANGLE + ar);
- // The end angle of trail cap arc at P2.
- final float ab = a + (RIGHT_ANGLE + ar);
- final float cosa = (float)Math.cos(aa);
- final float sina = (float)Math.sin(aa);
- final float cosb = (float)Math.cos(ab);
- final float sinb = (float)Math.sin(ab);
- w.p1ax = w.p1x + w.r1 * cosa;
- w.p1ay = w.p1y + w.r1 * sina;
- w.p1bx = w.p1x + w.r1 * cosb;
- w.p1by = w.p1y + w.r1 * sinb;
- w.p2ax = w.p2x + w.r2 * cosa;
- w.p2ay = w.p2y + w.r2 * sina;
- w.p2bx = w.p2x + w.r2 * cosb;
- w.p2by = w.p2y + w.r2 * sinb;
- w.aa = aa * RADIAN_TO_DEGREE;
- final float ar2degree = ar * 2.0f * RADIAN_TO_DEGREE;
- w.a1 = -180.0f + ar2degree;
- w.a2 = 180.0f + ar2degree;
- w.arc1.set(w.p1x, w.p1y, w.p1x, w.p1y);
- w.arc1.inset(-w.r1, -w.r1);
- w.arc2.set(w.p2x, w.p2y, w.p2x, w.p2y);
- w.arc2.inset(-w.r2, -w.r2);
- return true;
- }
-
- private static void createPath(final Path path, final WorkingSet w) {
- path.rewind();
- // Trail cap at P1.
- path.moveTo(w.p1x, w.p1y);
- path.arcTo(w.arc1, w.aa, w.a1);
- // Trail cap at P2.
- path.moveTo(w.p2x, w.p2y);
- path.arcTo(w.arc2, w.aa, w.a2);
- // Two trapezoids connecting P1 and P2.
- path.moveTo(w.p1ax, w.p1ay);
- path.lineTo(w.p1x, w.p1y);
- path.lineTo(w.p1bx, w.p1by);
- path.lineTo(w.p2bx, w.p2by);
- path.lineTo(w.p2x, w.p2y);
- path.lineTo(w.p2ax, w.p2ay);
- path.close();
- }
-
- private final WorkingSet mWorkingSet = new WorkingSet();
- private final Path mPath = new Path();
+ private final RoundedLine mRoundedLine = new RoundedLine();
/**
* Draw gesture preview trail
@@ -243,36 +151,35 @@ final class GesturePreviewTrail {
if (startIndex < trailSize) {
paint.setColor(params.mTrailColor);
paint.setStyle(Paint.Style.FILL);
- final Path path = mPath;
- final WorkingSet w = mWorkingSet;
- w.p1x = getXCoordValue(xCoords[startIndex]);
- w.p1y = yCoords[startIndex];
+ final RoundedLine line = mRoundedLine;
+ int p1x = getXCoordValue(xCoords[startIndex]);
+ int p1y = yCoords[startIndex];
int lastTime = sinceDown - eventTimes[startIndex];
float maxWidth = getWidth(lastTime, params);
- w.r1 = maxWidth / 2.0f;
+ float r1 = maxWidth / 2.0f;
// Initialize bounds rectangle.
- outBoundsRect.set((int)w.p1x, (int)w.p1y, (int)w.p1x, (int)w.p1y);
- for (int i = startIndex + 1; i < trailSize - 1; i++) {
+ outBoundsRect.set(p1x, p1y, p1x, p1y);
+ for (int i = startIndex + 1; i < trailSize; i++) {
final int elapsedTime = sinceDown - eventTimes[i];
- w.p2x = getXCoordValue(xCoords[i]);
- w.p2y = yCoords[i];
+ final int p2x = getXCoordValue(xCoords[i]);
+ final int p2y = yCoords[i];
+ final float width = getWidth(elapsedTime, params);
+ final float r2 = width / 2.0f;
// Draw trail line only when the current point isn't a down point.
if (!isDownEventXCoord(xCoords[i])) {
final int alpha = getAlpha(elapsedTime, params);
paint.setAlpha(alpha);
- final float width = getWidth(elapsedTime, params);
- w.r2 = width / 2.0f;
- if (calculatePathPoints(w)) {
- createPath(path, w);
+ final Path path = line.makePath(p1x, p1y, r1, p2x, p2y, r2);
+ if (path != null) {
canvas.drawPath(path, paint);
- outBoundsRect.union((int)w.p2x, (int)w.p2y);
+ outBoundsRect.union(p2x, p2y);
}
// Take union for the bounds.
maxWidth = Math.max(maxWidth, width);
}
- w.p1x = w.p2x;
- w.p1y = w.p2y;
- w.r1 = w.r2;
+ p1x = p2x;
+ p1y = p2y;
+ r1 = r2;
lastTime = elapsedTime;
}
// Take care of trail line width.
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
index f8244dd5b..a43e94a75 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
@@ -27,6 +27,10 @@ public class GestureStroke {
private static final boolean DEBUG = false;
private static final boolean DEBUG_SPEED = false;
+ // The height of extra area above the keyboard to draw gesture trails.
+ // Proportional to the keyboard height.
+ public static final float EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO = 0.25f;
+
public static final int DEFAULT_CAPACITY = 128;
private final int mPointerId;
@@ -37,6 +41,8 @@ public class GestureStroke {
private final GestureStrokeParams mParams;
private int mKeyWidth; // pixel
+ private int mMinYCoordinate; // pixel
+ private int mMaxYCoordinate; // pixel
// Static threshold for starting gesture detection
private int mDetectFastMoveSpeedThreshold; // pixel /sec
private int mDetectFastMoveTime;
@@ -135,8 +141,10 @@ public class GestureStroke {
mParams = params;
}
- public void setKeyboardGeometry(final int keyWidth) {
+ public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) {
mKeyWidth = keyWidth;
+ mMinYCoordinate = -(int)(keyboardHeight * EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO);
+ mMaxYCoordinate = keyboardHeight - 1;
// TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key?
mDetectFastMoveSpeedThreshold = (int)(keyWidth * mParams.mDetectFastMoveSpeedThreshold);
mGestureDynamicDistanceThresholdFrom =
@@ -167,7 +175,7 @@ public class GestureStroke {
elapsedTimeAfterTyping, mAfterFastTyping ? " afterFastTyping" : ""));
}
final int elapsedTimeFromFirstDown = (int)(downTime - gestureFirstDownTime);
- addPoint(x, y, elapsedTimeFromFirstDown, true /* isMajorEvent */);
+ addPointOnKeyboard(x, y, elapsedTimeFromFirstDown, true /* isMajorEvent */);
}
private int getGestureDynamicDistanceThreshold(final int deltaTime) {
@@ -220,6 +228,17 @@ public class GestureStroke {
return isStartOfAGesture;
}
+ public void duplicateLastPointWith(final int time) {
+ final int lastIndex = mEventTimes.getLength() - 1;
+ if (lastIndex >= 0) {
+ final int x = mXCoordinates.get(lastIndex);
+ final int y = mYCoordinates.get(lastIndex);
+ // TODO: Have appendMajorPoint()
+ appendPoint(x, y, time);
+ updateIncrementalRecognitionSize(x, y, time);
+ }
+ }
+
protected void reset() {
mIncrementalRecognitionSize = 0;
mLastIncrementalBatchSize = 0;
@@ -277,7 +296,17 @@ public class GestureStroke {
return dist;
}
- public void addPoint(final int x, final int y, final int time, final boolean isMajorEvent) {
+ /**
+ * Add a touch event as a gesture point. Returns true if the touch event is on the valid
+ * gesture area.
+ * @param x the x-coordinate of the touch event
+ * @param y the y-coordinate of the touch event
+ * @param time the elapsed time in millisecond from the first gesture down
+ * @param isMajorEvent false if this is a historical move event
+ * @return true if the touch event is on the valid gesture area
+ */
+ public boolean addPointOnKeyboard(final int x, final int y, final int time,
+ final boolean isMajorEvent) {
final int size = mEventTimes.getLength();
if (size <= 0) {
// Down event
@@ -293,6 +322,7 @@ public class GestureStroke {
updateIncrementalRecognitionSize(x, y, time);
updateMajorEvent(x, y, time);
}
+ return y >= mMinYCoordinate && y < mMaxYCoordinate;
}
private void updateIncrementalRecognitionSize(final int x, final int y, final int time) {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
index 8192c9076..7ab7e9aad 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
@@ -56,8 +56,8 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke {
}
@Override
- public void setKeyboardGeometry(final int keyWidth) {
- super.setKeyboardGeometry(keyWidth);
+ public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) {
+ super.setKeyboardGeometry(keyWidth, keyboardHeight);
final float sampleLength = keyWidth * MIN_PREVIEW_SAMPLE_LENGTH_RATIO_TO_KEY_WIDTH;
mMinPreviewSampleLengthSquare = (int)(sampleLength * sampleLength);
}
@@ -69,8 +69,9 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke {
}
@Override
- public void addPoint(final int x, final int y, final int time, final boolean isMajorEvent) {
- super.addPoint(x, y, time, isMajorEvent);
+ public boolean addPointOnKeyboard(final int x, final int y, final int time,
+ final boolean isMajorEvent) {
+ final boolean onValidArea = super.addPointOnKeyboard(x, y, time, isMajorEvent);
if (isMajorEvent || needsSampling(x, y)) {
mPreviewEventTimes.add(time);
mPreviewXCoordinates.add(x);
@@ -78,6 +79,7 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke {
mLastX = x;
mLastY = y;
}
+ return onValidArea;
}
public void appendPreviewStroke(final ResizableIntArray eventTimes,
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
index 2caa5eb02..9f6e2f37e 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
@@ -16,12 +16,13 @@
package com.android.inputmethod.keyboard.internal;
-import static com.android.inputmethod.keyboard.Keyboard.CODE_UNSPECIFIED;
+import static com.android.inputmethod.latin.Constants.CODE_OUTPUT_TEXT;
+import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED;
import android.text.TextUtils;
-import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.StringUtils;
@@ -172,7 +173,7 @@ public final class KeySpecParser {
if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) {
throw new KeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec);
}
- return parseCode(moreKeySpec.substring(end + 1), codesSet, Keyboard.CODE_UNSPECIFIED);
+ return parseCode(moreKeySpec.substring(end + 1), codesSet, CODE_UNSPECIFIED);
}
final String outputText = getOutputTextInternal(moreKeySpec);
if (outputText != null) {
@@ -181,14 +182,14 @@ public final class KeySpecParser {
if (StringUtils.codePointCount(outputText) == 1) {
return outputText.codePointAt(0);
}
- return Keyboard.CODE_OUTPUT_TEXT;
+ return CODE_OUTPUT_TEXT;
}
final String label = getLabel(moreKeySpec);
// Code is automatically generated for one letter label.
if (StringUtils.codePointCount(label) == 1) {
return label.codePointAt(0);
}
- return Keyboard.CODE_OUTPUT_TEXT;
+ return CODE_OUTPUT_TEXT;
}
public static int parseCode(final String text, final KeyboardCodesSet codesSet,
@@ -468,7 +469,7 @@ public final class KeySpecParser {
public static int toUpperCaseOfCodeForLocale(final int code, final boolean needsToUpperCase,
final Locale locale) {
- if (!Keyboard.isLetterCode(code) || !needsToUpperCase) return code;
+ if (!Constants.isLetterCode(code) || !needsToUpperCase) return code;
final String text = new String(new int[] { code } , 0, 1);
final String casedText = KeySpecParser.toUpperCaseOfStringForLocale(
text, needsToUpperCase, locale);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
index b314a3795..da418f41a 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
@@ -27,6 +27,7 @@ import android.util.TypedValue;
import android.util.Xml;
import android.view.InflateException;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId;
@@ -177,7 +178,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
return this;
}
- // For test only
+ @UsedForTesting
public void disableTouchPositionCorrectionDataForTest() {
mParams.mTouchPositionCorrection.setEnabled(false);
}
@@ -621,6 +622,8 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
R.styleable.Keyboard_Case_clobberSettingsKey, id.mClobberSettingsKey);
final boolean shortcutKeyEnabledMatched = matchBoolean(a,
R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled);
+ final boolean shortcutKeyOnSymbolsMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_shortcutKeyOnSymbols, id.mShortcutKeyOnSymbols);
final boolean hasShortcutKeyMatched = matchBoolean(a,
R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey);
final boolean languageSwitchKeyEnabledMatched = matchBoolean(a,
@@ -639,12 +642,12 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
final boolean selected = keyboardLayoutSetElementMatched && modeMatched
&& navigateNextMatched && navigatePreviousMatched && passwordInputMatched
&& clobberSettingsKeyMatched && shortcutKeyEnabledMatched
- && hasShortcutKeyMatched && languageSwitchKeyEnabledMatched
- && isMultiLineMatched && imeActionMatched && localeCodeMatched
- && languageCodeMatched && countryCodeMatched;
+ && shortcutKeyOnSymbolsMatched && hasShortcutKeyMatched
+ && languageSwitchKeyEnabledMatched && isMultiLineMatched && imeActionMatched
+ && localeCodeMatched && languageCodeMatched && countryCodeMatched;
if (DEBUG) {
- startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE,
+ startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE,
textAttr(a.getString(
R.styleable.Keyboard_Case_keyboardLayoutSetElement),
"keyboardLayoutSetElement"),
@@ -661,6 +664,8 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
"passwordInput"),
booleanAttr(a, R.styleable.Keyboard_Case_shortcutKeyEnabled,
"shortcutKeyEnabled"),
+ booleanAttr(a, R.styleable.Keyboard_Case_shortcutKeyOnSymbols,
+ "shortcutKeyOnSymbols"),
booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey,
"hasShortcutKey"),
booleanAttr(a, R.styleable.Keyboard_Case_languageSwitchKeyEnabled,
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
index 840d7133d..428e31ccd 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
@@ -16,8 +16,8 @@
package com.android.inputmethod.keyboard.internal;
-import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.Constants;
import java.util.HashMap;
@@ -74,21 +74,21 @@ public final class KeyboardCodesSet {
private static final int CODE_RIGHT_CURLY_BRACKET = '}';
private static final int[] DEFAULT = {
- Keyboard.CODE_TAB,
- Keyboard.CODE_ENTER,
- Keyboard.CODE_SPACE,
- Keyboard.CODE_SHIFT,
- Keyboard.CODE_SWITCH_ALPHA_SYMBOL,
- Keyboard.CODE_OUTPUT_TEXT,
- Keyboard.CODE_DELETE,
- Keyboard.CODE_SETTINGS,
- Keyboard.CODE_SHORTCUT,
- Keyboard.CODE_ACTION_ENTER,
- Keyboard.CODE_ACTION_NEXT,
- Keyboard.CODE_ACTION_PREVIOUS,
- Keyboard.CODE_LANGUAGE_SWITCH,
- Keyboard.CODE_RESEARCH,
- Keyboard.CODE_UNSPECIFIED,
+ Constants.CODE_TAB,
+ Constants.CODE_ENTER,
+ Constants.CODE_SPACE,
+ Constants.CODE_SHIFT,
+ Constants.CODE_SWITCH_ALPHA_SYMBOL,
+ Constants.CODE_OUTPUT_TEXT,
+ Constants.CODE_DELETE,
+ Constants.CODE_SETTINGS,
+ Constants.CODE_SHORTCUT,
+ Constants.CODE_ACTION_ENTER,
+ Constants.CODE_ACTION_NEXT,
+ Constants.CODE_ACTION_PREVIOUS,
+ Constants.CODE_LANGUAGE_SWITCH,
+ Constants.CODE_RESEARCH,
+ Constants.CODE_UNSPECIFIED,
CODE_LEFT_PARENTHESIS,
CODE_RIGHT_PARENTHESIS,
CODE_LESS_THAN_SIGN,
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
index e6fe50e02..642e1a18c 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
@@ -19,9 +19,9 @@ package com.android.inputmethod.keyboard.internal;
import android.util.SparseIntArray;
import com.android.inputmethod.keyboard.Key;
-import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.Constants;
import java.util.ArrayList;
import java.util.TreeSet;
@@ -89,7 +89,7 @@ public class KeyboardParams {
mKeys.add(key);
updateHistogram(key);
}
- if (key.mCode == Keyboard.CODE_SHIFT) {
+ if (key.mCode == Constants.CODE_SHIFT) {
mShiftKeys.add(key);
}
if (key.altCodeWhileTyping()) {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index 631e647e8..25a1c6a00 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -19,7 +19,6 @@ package com.android.inputmethod.keyboard.internal;
import android.text.TextUtils;
import android.util.Log;
-import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.latin.Constants;
/**
@@ -316,12 +315,12 @@ public final class KeyboardState {
public void onPressKey(int code, boolean isSinglePointer, int autoCaps) {
if (DEBUG_EVENT) {
- Log.d(TAG, "onPressKey: code=" + Keyboard.printableCode(code)
+ Log.d(TAG, "onPressKey: code=" + Constants.printableCode(code)
+ " single=" + isSinglePointer + " autoCaps=" + autoCaps + " " + this);
}
- if (code == Keyboard.CODE_SHIFT) {
+ if (code == Constants.CODE_SHIFT) {
onPressShift();
- } else if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
+ } else if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) {
onPressSymbol();
} else {
mSwitchActions.cancelDoubleTapTimer();
@@ -349,12 +348,12 @@ public final class KeyboardState {
public void onReleaseKey(int code, boolean withSliding) {
if (DEBUG_EVENT) {
- Log.d(TAG, "onReleaseKey: code=" + Keyboard.printableCode(code)
+ Log.d(TAG, "onReleaseKey: code=" + Constants.printableCode(code)
+ " sliding=" + withSliding + " " + this);
}
- if (code == Keyboard.CODE_SHIFT) {
+ if (code == Constants.CODE_SHIFT) {
onReleaseShift(withSliding);
- } else if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
+ } else if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) {
onReleaseSymbol(withSliding);
}
}
@@ -381,9 +380,9 @@ public final class KeyboardState {
public void onLongPressTimeout(int code) {
if (DEBUG_EVENT) {
- Log.d(TAG, "onLongPressTimeout: code=" + Keyboard.printableCode(code) + " " + this);
+ Log.d(TAG, "onLongPressTimeout: code=" + Constants.printableCode(code) + " " + this);
}
- if (mIsAlphabetMode && code == Keyboard.CODE_SHIFT) {
+ if (mIsAlphabetMode && code == Constants.CODE_SHIFT) {
mLongPressShiftLockFired = true;
mSwitchActions.hapticAndAudioFeedback(code);
}
@@ -459,7 +458,7 @@ public final class KeyboardState {
setShifted(MANUAL_SHIFT);
mShiftKeyState.onPress();
}
- mSwitchActions.startLongPressTimer(Keyboard.CODE_SHIFT);
+ mSwitchActions.startLongPressTimer(Constants.CODE_SHIFT);
}
} else {
// In symbol mode, just toggle symbol and symbol more keyboard.
@@ -544,7 +543,7 @@ public final class KeyboardState {
}
private static boolean isSpaceCharacter(int c) {
- return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER;
+ return c == Constants.CODE_SPACE || c == Constants.CODE_ENTER;
}
private boolean isLayoutSwitchBackCharacter(int c) {
@@ -555,14 +554,14 @@ public final class KeyboardState {
public void onCodeInput(int code, boolean isSinglePointer, int autoCaps) {
if (DEBUG_EVENT) {
- Log.d(TAG, "onCodeInput: code=" + Keyboard.printableCode(code)
+ Log.d(TAG, "onCodeInput: code=" + Constants.printableCode(code)
+ " single=" + isSinglePointer
+ " autoCaps=" + autoCaps + " " + this);
}
switch (mSwitchState) {
case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL:
- if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
+ if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) {
// Detected only the mode change key has been pressed, and then released.
if (mIsAlphabetMode) {
mSwitchState = SWITCH_STATE_ALPHA;
@@ -578,7 +577,7 @@ public final class KeyboardState {
}
break;
case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE:
- if (code == Keyboard.CODE_SHIFT) {
+ if (code == Constants.CODE_SHIFT) {
// Detected only the shift key has been pressed on symbol layout, and then released.
mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
} else if (isSinglePointer) {
@@ -589,8 +588,8 @@ public final class KeyboardState {
}
break;
case SWITCH_STATE_SYMBOL_BEGIN:
- if (!isSpaceCharacter(code) && (Keyboard.isLetterCode(code)
- || code == Keyboard.CODE_OUTPUT_TEXT)) {
+ if (!isSpaceCharacter(code) && (Constants.isLetterCode(code)
+ || code == Constants.CODE_OUTPUT_TEXT)) {
mSwitchState = SWITCH_STATE_SYMBOL;
}
// Switch back to alpha keyboard mode immediately if user types one of the switch back
@@ -611,7 +610,7 @@ public final class KeyboardState {
}
// If the code is a letter, update keyboard shift state.
- if (Keyboard.isLetterCode(code)) {
+ if (Constants.isLetterCode(code)) {
updateAlphabetShiftState(autoCaps);
}
}
@@ -639,7 +638,7 @@ public final class KeyboardState {
@Override
public String toString() {
return "[keyboard=" + (mIsAlphabetMode ? mAlphabetShiftState.toString()
- : (mIsSymbolShifted ? "SYMBOLS_SHIFTED" : "SYMBOLS"))
+ : (mIsSymbolShifted ? "SYMBOLS_SHIFTED" : "SYMBOLS"))
+ " shift=" + mShiftKeyState
+ " symbol=" + mSymbolKeyState
+ " switch=" + switchStateToString(mSwitchState) + "]";
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index 3bb272f8c..6fefb809b 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -19,6 +19,7 @@ package com.android.inputmethod.keyboard.internal;
import android.content.Context;
import android.content.res.Resources;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.R;
@@ -64,7 +65,7 @@ public final class KeyboardTextsSet {
loadStringResourcesInternal(context, RESOURCE_NAMES, R.string.english_ime_name);
}
- /* package for test */
+ @UsedForTesting
void loadStringResourcesInternal(Context context, final String[] resourceNames,
int referenceId) {
final Resources res = context.getResources();
@@ -96,9 +97,6 @@ public final class KeyboardTextsSet {
"label_done_key",
"label_previous_key",
// Other labels.
- "label_to_alpha_key",
- "label_to_symbol_key",
- "label_to_symbol_with_microphone_key",
"label_pause_key",
"label_wait_key",
};
@@ -146,13 +144,13 @@ public final class KeyboardTextsSet {
/* 39 */ "keylabel_for_south_slavic_row3_8",
/* 40 */ "more_keys_for_cyrillic_ie",
/* 41 */ "more_keys_for_cyrillic_i",
- /* 42 */ "more_keys_for_single_quote",
- /* 43 */ "more_keys_for_double_quote",
- /* 44 */ "more_keys_for_tablet_double_quote",
- /* 45 */ "more_keys_for_currency_dollar",
- /* 46 */ "more_keys_for_currency_euro",
- /* 47 */ "more_keys_for_currency_pound",
- /* 48 */ "more_keys_for_currency_general",
+ /* 42 */ "label_to_alpha_key",
+ /* 43 */ "more_keys_for_single_quote",
+ /* 44 */ "more_keys_for_double_quote",
+ /* 45 */ "more_keys_for_tablet_double_quote",
+ /* 46 */ "more_keys_for_currency_dollar",
+ /* 47 */ "keylabel_for_currency_generic",
+ /* 48 */ "more_keys_for_currency_generic",
/* 49 */ "more_keys_for_punctuation",
/* 50 */ "more_keys_for_star",
/* 51 */ "more_keys_for_bullet",
@@ -173,66 +171,68 @@ public final class KeyboardTextsSet {
/* 66 */ "keylabel_for_symbols_8",
/* 67 */ "keylabel_for_symbols_9",
/* 68 */ "keylabel_for_symbols_0",
- /* 69 */ "additional_more_keys_for_symbols_1",
- /* 70 */ "additional_more_keys_for_symbols_2",
- /* 71 */ "additional_more_keys_for_symbols_3",
- /* 72 */ "additional_more_keys_for_symbols_4",
- /* 73 */ "additional_more_keys_for_symbols_5",
- /* 74 */ "additional_more_keys_for_symbols_6",
- /* 75 */ "additional_more_keys_for_symbols_7",
- /* 76 */ "additional_more_keys_for_symbols_8",
- /* 77 */ "additional_more_keys_for_symbols_9",
- /* 78 */ "additional_more_keys_for_symbols_0",
- /* 79 */ "more_keys_for_symbols_1",
- /* 80 */ "more_keys_for_symbols_2",
- /* 81 */ "more_keys_for_symbols_3",
- /* 82 */ "more_keys_for_symbols_4",
- /* 83 */ "more_keys_for_symbols_5",
- /* 84 */ "more_keys_for_symbols_6",
- /* 85 */ "more_keys_for_symbols_7",
- /* 86 */ "more_keys_for_symbols_8",
- /* 87 */ "more_keys_for_symbols_9",
- /* 88 */ "more_keys_for_symbols_0",
- /* 89 */ "keylabel_for_comma",
- /* 90 */ "more_keys_for_comma",
- /* 91 */ "keylabel_for_symbols_question",
- /* 92 */ "keylabel_for_symbols_semicolon",
- /* 93 */ "keylabel_for_symbols_percent",
- /* 94 */ "more_keys_for_symbols_exclamation",
- /* 95 */ "more_keys_for_symbols_question",
- /* 96 */ "more_keys_for_symbols_semicolon",
- /* 97 */ "more_keys_for_symbols_percent",
- /* 98 */ "keylabel_for_tablet_comma",
- /* 99 */ "keyhintlabel_for_tablet_comma",
- /* 100 */ "more_keys_for_tablet_comma",
- /* 101 */ "keyhintlabel_for_tablet_period",
- /* 102 */ "more_keys_for_tablet_period",
- /* 103 */ "keylabel_for_apostrophe",
- /* 104 */ "keyhintlabel_for_apostrophe",
- /* 105 */ "more_keys_for_apostrophe",
- /* 106 */ "more_keys_for_q",
- /* 107 */ "more_keys_for_x",
- /* 108 */ "keylabel_for_q",
- /* 109 */ "keylabel_for_w",
- /* 110 */ "keylabel_for_y",
- /* 111 */ "keylabel_for_x",
- /* 112 */ "keylabel_for_spanish_row2_10",
- /* 113 */ "more_keys_for_am_pm",
- /* 114 */ "settings_as_more_key",
- /* 115 */ "shortcut_as_more_key",
- /* 116 */ "action_next_as_more_key",
- /* 117 */ "action_previous_as_more_key",
- /* 118 */ "label_to_more_symbol_key",
- /* 119 */ "label_to_more_symbol_for_tablet_key",
- /* 120 */ "label_tab_key",
- /* 121 */ "label_to_phone_numeric_key",
- /* 122 */ "label_to_phone_symbols_key",
- /* 123 */ "label_time_am",
- /* 124 */ "label_time_pm",
- /* 125 */ "label_to_symbol_key_pcqwerty",
- /* 126 */ "keylabel_for_popular_domain",
- /* 127 */ "more_keys_for_popular_domain",
- /* 128 */ "more_keys_for_smiley",
+ /* 69 */ "label_to_symbol_key",
+ /* 70 */ "label_to_symbol_with_microphone_key",
+ /* 71 */ "additional_more_keys_for_symbols_1",
+ /* 72 */ "additional_more_keys_for_symbols_2",
+ /* 73 */ "additional_more_keys_for_symbols_3",
+ /* 74 */ "additional_more_keys_for_symbols_4",
+ /* 75 */ "additional_more_keys_for_symbols_5",
+ /* 76 */ "additional_more_keys_for_symbols_6",
+ /* 77 */ "additional_more_keys_for_symbols_7",
+ /* 78 */ "additional_more_keys_for_symbols_8",
+ /* 79 */ "additional_more_keys_for_symbols_9",
+ /* 80 */ "additional_more_keys_for_symbols_0",
+ /* 81 */ "more_keys_for_symbols_1",
+ /* 82 */ "more_keys_for_symbols_2",
+ /* 83 */ "more_keys_for_symbols_3",
+ /* 84 */ "more_keys_for_symbols_4",
+ /* 85 */ "more_keys_for_symbols_5",
+ /* 86 */ "more_keys_for_symbols_6",
+ /* 87 */ "more_keys_for_symbols_7",
+ /* 88 */ "more_keys_for_symbols_8",
+ /* 89 */ "more_keys_for_symbols_9",
+ /* 90 */ "more_keys_for_symbols_0",
+ /* 91 */ "keylabel_for_comma",
+ /* 92 */ "more_keys_for_comma",
+ /* 93 */ "keylabel_for_symbols_question",
+ /* 94 */ "keylabel_for_symbols_semicolon",
+ /* 95 */ "keylabel_for_symbols_percent",
+ /* 96 */ "more_keys_for_symbols_exclamation",
+ /* 97 */ "more_keys_for_symbols_question",
+ /* 98 */ "more_keys_for_symbols_semicolon",
+ /* 99 */ "more_keys_for_symbols_percent",
+ /* 100 */ "keylabel_for_tablet_comma",
+ /* 101 */ "keyhintlabel_for_tablet_comma",
+ /* 102 */ "more_keys_for_tablet_comma",
+ /* 103 */ "keyhintlabel_for_tablet_period",
+ /* 104 */ "more_keys_for_tablet_period",
+ /* 105 */ "keylabel_for_apostrophe",
+ /* 106 */ "keyhintlabel_for_apostrophe",
+ /* 107 */ "more_keys_for_apostrophe",
+ /* 108 */ "more_keys_for_q",
+ /* 109 */ "more_keys_for_x",
+ /* 110 */ "keylabel_for_q",
+ /* 111 */ "keylabel_for_w",
+ /* 112 */ "keylabel_for_y",
+ /* 113 */ "keylabel_for_x",
+ /* 114 */ "keylabel_for_spanish_row2_10",
+ /* 115 */ "more_keys_for_am_pm",
+ /* 116 */ "settings_as_more_key",
+ /* 117 */ "shortcut_as_more_key",
+ /* 118 */ "action_next_as_more_key",
+ /* 119 */ "action_previous_as_more_key",
+ /* 120 */ "label_to_more_symbol_key",
+ /* 121 */ "label_to_more_symbol_for_tablet_key",
+ /* 122 */ "label_tab_key",
+ /* 123 */ "label_to_phone_numeric_key",
+ /* 124 */ "label_to_phone_symbols_key",
+ /* 125 */ "label_time_am",
+ /* 126 */ "label_time_pm",
+ /* 127 */ "label_to_symbol_key_pcqwerty",
+ /* 128 */ "keylabel_for_popular_domain",
+ /* 129 */ "more_keys_for_popular_domain",
+ /* 130 */ "more_keys_for_smiley",
};
private static final String EMPTY = "";
@@ -245,22 +245,23 @@ public final class KeyboardTextsSet {
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY,
/* ~41 */
- /* 42 */ "!fixedColumnOrder!4,\u2018,\u2019,\u201A,\u201B",
+ // Label for "switch to alphabetic" key.
+ /* 42 */ "ABC",
+ /* 43 */ "!fixedColumnOrder!4,\u2018,\u2019,\u201A,\u201B",
// TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
// <string name="more_keys_for_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;</string>
- /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB,\u00BB",
+ /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB,\u00BB",
// TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
// <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
- /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B",
+ /* 45 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B",
// U+00A2: "¢" CENT SIGN
// U+00A3: "£" POUND SIGN
// U+20AC: "€" EURO SIGN
// U+00A5: "¥" YEN SIGN
// U+20B1: "₱" PESO SIGN
- /* 45 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
- /* 46 */ "\u00A2,\u00A3,$,\u00A5,\u20B1",
- /* 47 */ "\u00A2,$,\u20AC,\u00A5,\u20B1",
- /* 48 */ "\u00A2,$,\u20AC,\u00A3,\u00A5,\u20B1",
+ /* 46 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
+ /* 47 */ "$",
+ /* 48 */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1",
/* 49 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\\,,?,@,&,\\%,+,;,/,(,)",
// U+2020: "†" DAGGER
// U+2021: "‡" DOUBLE DAGGER
@@ -307,89 +308,94 @@ public final class KeyboardTextsSet {
/* 66 */ "8",
/* 67 */ "9",
/* 68 */ "0",
- /* 69~ */
+ // Label for "switch to symbols" key.
+ /* 69 */ "?123",
+ // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
+ // part because it'll be appended by the code.
+ /* 70 */ "123",
+ /* 71~ */
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
- /* ~78 */
+ /* ~80 */
// U+00B9: "¹" SUPERSCRIPT ONE
// U+00BD: "½" VULGAR FRACTION ONE HALF
// U+2153: "⅓" VULGAR FRACTION ONE THIRD
// U+00BC: "¼" VULGAR FRACTION ONE QUARTER
// U+215B: "⅛" VULGAR FRACTION ONE EIGHTH
- /* 79 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B",
+ /* 81 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B",
// U+00B2: "²" SUPERSCRIPT TWO
// U+2154: "⅔" VULGAR FRACTION TWO THIRDS
- /* 80 */ "\u00B2,\u2154",
+ /* 82 */ "\u00B2,\u2154",
// U+00B3: "³" SUPERSCRIPT THREE
// U+00BE: "¾" VULGAR FRACTION THREE QUARTERS
// U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS
- /* 81 */ "\u00B3,\u00BE,\u215C",
+ /* 83 */ "\u00B3,\u00BE,\u215C",
// U+2074: "⁴" SUPERSCRIPT FOUR
- /* 82 */ "\u2074",
+ /* 84 */ "\u2074",
// U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS
- /* 83 */ "\u215D",
- /* 84 */ EMPTY,
- // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS
- /* 85 */ "\u215E",
+ /* 85 */ "\u215D",
/* 86 */ EMPTY,
- /* 87 */ EMPTY,
+ // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS
+ /* 87 */ "\u215E",
+ /* 88 */ EMPTY,
+ /* 89 */ EMPTY,
// U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N
// U+2205: "∅" EMPTY SET
- /* 88 */ "\u207F,\u2205",
- /* 89 */ ",",
- /* 90 */ EMPTY,
- /* 91 */ "?",
- /* 92 */ ";",
- /* 93 */ "%",
+ /* 90 */ "\u207F,\u2205",
+ /* 91 */ ",",
+ /* 92 */ EMPTY,
+ /* 93 */ "?",
+ /* 94 */ ";",
+ /* 95 */ "%",
// U+00A1: "¡" INVERTED EXCLAMATION MARK
- /* 94 */ "\u00A1",
+ /* 96 */ "\u00A1",
// U+00BF: "¿" INVERTED QUESTION MARK
- /* 95 */ "\u00BF",
- /* 96 */ EMPTY,
+ /* 97 */ "\u00BF",
+ /* 98 */ EMPTY,
// U+2030: "‰" PER MILLE SIGN
- /* 97 */ "\u2030",
- /* 98 */ ",",
- /* 99 */ "!",
- /* 100 */ "!",
- /* 101 */ "?",
- /* 102 */ "?",
- /* 103 */ "\'",
- /* 104 */ "\"",
- /* 105 */ "\"",
- /* 106 */ EMPTY,
- /* 107 */ EMPTY,
- /* 108 */ "q",
- /* 109 */ "w",
- /* 110 */ "y",
- /* 111 */ "x",
+ /* 99 */ "\u2030",
+ /* 100 */ ",",
+ /* 101 */ "!",
+ /* 102 */ "!",
+ /* 103 */ "?",
+ /* 104 */ "?",
+ /* 105 */ "\'",
+ /* 106 */ "\"",
+ /* 107 */ "\"",
+ /* 108 */ EMPTY,
+ /* 109 */ EMPTY,
+ /* 110 */ "q",
+ /* 111 */ "w",
+ /* 112 */ "y",
+ /* 113 */ "x",
// U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
- /* 112 */ "\u00F1",
- /* 113 */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm",
- /* 114 */ "!icon/settings_key|!code/key_settings",
- /* 115 */ "!icon/shortcut_key|!code/key_shortcut",
- /* 116 */ "!hasLabels!,!text/label_next_key|!code/key_action_next",
- /* 117 */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous",
+ /* 114 */ "\u00F1",
+ /* 115 */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm",
+ /* 116 */ "!icon/settings_key|!code/key_settings",
+ /* 117 */ "!icon/shortcut_key|!code/key_shortcut",
+ /* 118 */ "!hasLabels!,!text/label_next_key|!code/key_action_next",
+ /* 119 */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous",
// Label for "switch to more symbol" modifier key. Must be short to fit on key!
- /* 118 */ "= \\ <",
+ /* 120 */ "= \\ <",
// Label for "switch to more symbol" modifier key on tablets. Must be short to fit on key!
- /* 119 */ "~ \\ {",
+ /* 121 */ "~ \\ {",
// Label for "Tab" key. Must be short to fit on key!
- /* 120 */ "Tab",
+ /* 122 */ "Tab",
// Label for "switch to phone numeric" key. Must be short to fit on key!
- /* 121 */ "123",
+ /* 123 */ "123",
// Label for "switch to phone symbols" key. Must be short to fit on key!
// U+FF0A: "*" FULLWIDTH ASTERISK
// U+FF03: "#" FULLWIDTH NUMBER SIGN
- /* 122 */ "\uFF0A\uFF03",
+ /* 124 */ "\uFF0A\uFF03",
// Key label for "ante meridiem"
- /* 123 */ "AM",
+ /* 125 */ "AM",
// Key label for "post meridiem"
- /* 124 */ "PM",
+ /* 126 */ "PM",
// Label for "switch to symbols" key on PC QWERTY layout
- /* 125 */ "Sym",
- /* 126 */ ".com",
+ /* 127 */ "Sym",
+ /* 128 */ ".com",
// popular web domains for the locale - most popular, displayed on the keyboard
- /* 127 */ "!hasLabels!,.net,.org,.gov,.edu",
- /* 128 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ",
+ /* 129 */ "!hasLabels!,.net,.org,.gov,.edu",
+ /* 130 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ",
};
/* Language af: Afrikaans */
@@ -450,17 +456,30 @@ public final class KeyboardTextsSet {
/* 0~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null, null, null,
- /* ~42 */
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~41 */
+ // Label for "switch to alphabetic" key.
+ // U+0623: "ا" ARABIC LETTER ALEF
+ // U+200C: ZERO WIDTH NON-JOINER
+ // U+0628: "ب" ARABIC LETTER BEH
+ // U+062C: "پ" ARABIC LETTER PEH
+ /* 42 */ "\u0623\u200C\u0628\u200C\u062C",
+ /* 43 */ null,
// TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
// <string name="more_keys_for_double_quote">&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB;|&#x00AB;</string>
- /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB",
+ /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB",
// TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
// <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB|&#x00AB;;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
- /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B",
- /* 45~ */
- null, null, null, null,
- /* ~48 */
+ /* 45 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B",
+ // U+00A2: "¢" CENT SIGN
+ // U+00A3: "£" POUND SIGN
+ // U+20AC: "€" EURO SIGN
+ // U+00A5: "¥" YEN SIGN
+ // U+20B1: "₱" PESO SIGN
+ // U+FDFC: "﷼" RIAL SIGN
+ /* 46 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1,\uFDFC",
+ /* 47 */ null,
+ /* 48 */ null,
// U+061F: "؟" ARABIC QUESTION MARK
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
@@ -531,42 +550,48 @@ public final class KeyboardTextsSet {
/* 67 */ "\u0669",
// U+0660: "٠" ARABIC-INDIC DIGIT ZERO
/* 68 */ "\u0660",
- /* 69 */ "1",
- /* 70 */ "2",
- /* 71 */ "3",
- /* 72 */ "4",
- /* 73 */ "5",
- /* 74 */ "6",
- /* 75 */ "7",
- /* 76 */ "8",
- /* 77 */ "9",
+ // Label for "switch to symbols" key.
+ // U+061F: "؟" ARABIC QUESTION MARK
+ /* 69 */ "\u0663\u0662\u0661\u061F",
+ // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
+ // part because it'll be appended by the code.
+ /* 70 */ "\u0663\u0662\u0661",
+ /* 71 */ "1",
+ /* 72 */ "2",
+ /* 73 */ "3",
+ /* 74 */ "4",
+ /* 75 */ "5",
+ /* 76 */ "6",
+ /* 77 */ "7",
+ /* 78 */ "8",
+ /* 79 */ "9",
// U+066B: "٫" ARABIC DECIMAL SEPARATOR
// U+066C: "٬" ARABIC THOUSANDS SEPARATOR
- /* 78 */ "0,\u066B,\u066C",
- /* 79~ */
+ /* 80 */ "0,\u066B,\u066C",
+ /* 81~ */
null, null, null, null, null, null, null, null, null, null,
- /* ~88 */
+ /* ~90 */
// U+060C: "،" ARABIC COMMA
- /* 89 */ "\u060C",
- /* 90 */ "\\,",
- /* 91 */ "\u061F",
- /* 92 */ "\u061B",
+ /* 91 */ "\u060C",
+ /* 92 */ "\\,",
+ /* 93 */ "\u061F",
+ /* 94 */ "\u061B",
// U+066A: "٪" ARABIC PERCENT SIGN
- /* 93 */ "\u066A",
- /* 94 */ null,
- /* 95 */ "?",
- /* 96 */ ";",
+ /* 95 */ "\u066A",
+ /* 96 */ null,
+ /* 97 */ "?",
+ /* 98 */ ";",
// U+2030: "‰" PER MILLE SIGN
- /* 97 */ "\\%,\u2030",
- /* 98~ */
+ /* 99 */ "\\%,\u2030",
+ /* 100~ */
null, null, null, null, null,
- /* ~102 */
+ /* ~104 */
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
// U+061F: "؟" ARABIC QUESTION MARK
- /* 103 */ "\u060C",
- /* 104 */ "\u061F",
- /* 105 */ "\u061F,\u061B,!,:,-,/,\',\"",
+ /* 105 */ "\u060C",
+ /* 106 */ "\u061F",
+ /* 107 */ "\u061F,\u061B,!,:,-,/,\',\"",
};
/* Language be: Belarusian */
@@ -595,6 +620,26 @@ public final class KeyboardTextsSet {
/* ~39 */
// U+0451: "ё" CYRILLIC SMALL LETTER IO
/* 40 */ "\u0451",
+ /* 41 */ null,
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* 42 */ "\u0410\u0411\u0412",
+ };
+
+ /* Language bg: Bulgarian */
+ private static final String[] LANGUAGE_bg = {
+ /* 0~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~41 */
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* 42 */ "\u0410\u0411\u0412",
};
/* Language ca: Catalan */
@@ -830,6 +875,20 @@ public final class KeyboardTextsSet {
/* 6 */ "\u00F1,\u0144",
};
+ /* Language el: Greek */
+ private static final String[] LANGUAGE_el = {
+ /* 0~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~41 */
+ // Label for "switch to alphabetic" key.
+ // U+0391: "Α" GREEK CAPITAL LETTER ALPHA
+ // U+0392: "Β" GREEK CAPITAL LETTER BETA
+ // U+0393: "Γ" GREEK CAPITAL LETTER GAMMA
+ /* 42 */ "\u0391\u0392\u0393",
+ };
+
/* Language en: English */
private static final String[] LANGUAGE_en = {
// U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
@@ -998,20 +1057,20 @@ public final class KeyboardTextsSet {
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null,
- /* ~105 */
- /* 106 */ "q",
- /* 107 */ "x",
+ null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~107 */
+ /* 108 */ "q",
+ /* 109 */ "x",
// U+015D: "ŝ" LATIN SMALL LETTER S WITH CIRCUMFLEX
- /* 108 */ "\u015D",
+ /* 110 */ "\u015D",
// U+011D: "ĝ" LATIN SMALL LETTER G WITH CIRCUMFLEX
- /* 109 */ "\u011D",
+ /* 111 */ "\u011D",
// U+016D: "ŭ" LATIN SMALL LETTER U WITH BREVE
- /* 110 */ "\u016D",
+ /* 112 */ "\u016D",
// U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX
- /* 111 */ "\u0109",
+ /* 113 */ "\u0109",
// U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX
- /* 112 */ "\u0135",
+ /* 114 */ "\u0135",
};
/* Language es: Spanish */
@@ -1078,13 +1137,16 @@ public final class KeyboardTextsSet {
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null,
- /* ~99 */
+ null, null, null, null, null, null, null,
+ /* ~101 */
// U+00A1: "¡" INVERTED EXCLAMATION MARK
- /* 100 */ "!,\u00A1",
- /* 101 */ null,
+ /* 102 */ "!,\u00A1",
+ /* 103 */ null,
// U+00BF: "¿" INVERTED QUESTION MARK
- /* 102 */ "?,\u00BF",
+ /* 104 */ "?,\u00BF",
+ /* 105 */ "\"",
+ /* 106 */ "\'",
+ /* 107 */ "\'",
};
/* Language et: Estonian */
@@ -1192,17 +1254,31 @@ public final class KeyboardTextsSet {
/* 0~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null, null, null,
- /* ~42 */
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~41 */
+ // Label for "switch to alphabetic" key.
+ // U+0627: "ا" ARABIC LETTER ALEF
+ // U+200C: ZERO WIDTH NON-JOINER
+ // U+0628: "ب" ARABIC LETTER BEH
+ // U+067E: "پ" ARABIC LETTER PEH
+ /* 42 */ "\u0627\u200C\u0628\u200C\u067E",
+ /* 43 */ null,
// TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
// <string name="more_keys_for_double_quote">&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB;|&#x00AB;</string>
- /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\",\'",
+ /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\",\'",
// TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
// <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB|&#x00AB;;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
- /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B",
- /* 45~ */
- null, null, null, null,
- /* ~48 */
+ /* 45 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B",
+ /* 46 */ null,
+ // U+FDFC: "﷼" RIAL SIGN
+ // U+060B: "؋" AFGHANI SIGN
+ // U+00A2: "¢" CENT SIGN
+ // U+00A3: "£" POUND SIGN
+ // U+20AC: "€" EURO SIGN
+ // U+00A5: "¥" YEN SIGN
+ // U+20B1: "₱" PESO SIGN
+ /* 47 */ "\uFDFC",
+ /* 48 */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1,\u060B",
// U+061F: "؟" ARABIC QUESTION MARK
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
@@ -1273,46 +1349,52 @@ public final class KeyboardTextsSet {
/* 67 */ "\u06F9",
// U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO
/* 68 */ "\u06F0",
- /* 69 */ "1",
- /* 70 */ "2",
- /* 71 */ "3",
- /* 72 */ "4",
- /* 73 */ "5",
- /* 74 */ "6",
- /* 75 */ "7",
- /* 76 */ "8",
- /* 77 */ "9",
+ // Label for "switch to symbols" key.
+ // U+061F: "؟" ARABIC QUESTION MARK
+ /* 69 */ "\u06F3\u06F2\u06F1\u061F",
+ // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
+ // part because it'll be appended by the code.
+ /* 70 */ "\u06F3\u06F2\u06F1",
+ /* 71 */ "1",
+ /* 72 */ "2",
+ /* 73 */ "3",
+ /* 74 */ "4",
+ /* 75 */ "5",
+ /* 76 */ "6",
+ /* 77 */ "7",
+ /* 78 */ "8",
+ /* 79 */ "9",
// U+066B: "٫" ARABIC DECIMAL SEPARATOR
// U+066C: "٬" ARABIC THOUSANDS SEPARATOR
- /* 78 */ "0,\u066B,\u066C",
- /* 79~ */
+ /* 80 */ "0,\u066B,\u066C",
+ /* 81~ */
null, null, null, null, null, null, null, null, null, null,
- /* ~88 */
+ /* ~90 */
// U+060C: "،" ARABIC COMMA
- /* 89 */ "\u060C",
- /* 90 */ "\\,",
- /* 91 */ "\u061F",
- /* 92 */ "\u061B",
+ /* 91 */ "\u060C",
+ /* 92 */ "\\,",
+ /* 93 */ "\u061F",
+ /* 94 */ "\u061B",
// U+066A: "٪" ARABIC PERCENT SIGN
- /* 93 */ "\u066A",
- /* 94 */ null,
- /* 95 */ "?",
- /* 96 */ ";",
+ /* 95 */ "\u066A",
+ /* 96 */ null,
+ /* 97 */ "?",
+ /* 98 */ ";",
// U+2030: "‰" PER MILLE SIGN
- /* 97 */ "\\%,\u2030",
+ /* 99 */ "\\%,\u2030",
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
// U+061F: "؟" ARABIC QUESTION MARK
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
- /* 98 */ "\u060C",
- /* 99 */ "!",
- /* 100 */ "!,\\,",
- /* 101 */ "\u061F",
- /* 102 */ "\u061F,?",
- /* 103 */ "\u060C",
- /* 104 */ "\u061F",
- /* 105 */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\u00AB|\u00BB,\u00BB|\u00AB",
+ /* 100 */ "\u060C",
+ /* 101 */ "!",
+ /* 102 */ "!,\\,",
+ /* 103 */ "\u061F",
+ /* 104 */ "\u061F,?",
+ /* 105 */ "\u060C",
+ /* 106 */ "\u061F",
+ /* 107 */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\u00AB|\u00BB,\u00BB|\u00AB",
};
/* Language fi: Finnish */
@@ -1420,8 +1502,20 @@ public final class KeyboardTextsSet {
/* 0~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~41 */
+ // Label for "switch to alphabetic" key.
+ // U+0915: "क" DEVANAGARI LETTER KA
+ // U+0916: "ख" DEVANAGARI LETTER KHA
+ // U+0917: "ग" DEVANAGARI LETTER GA
+ /* 42 */ "\u0915\u0916\u0917",
+ /* 43~ */
+ null, null, null, null,
+ /* ~46 */
+ // U+20B9: "₹" INDIAN RUPEE SIGN
+ /* 47 */ "\u20B9",
+ /* 48~ */
+ null, null, null, null, null, null, null, null, null, null, null,
/* ~58 */
// U+0967: "१" DEVANAGARI DIGIT ONE
/* 59 */ "\u0967",
@@ -1443,16 +1537,21 @@ public final class KeyboardTextsSet {
/* 67 */ "\u096F",
// U+0966: "०" DEVANAGARI DIGIT ZERO
/* 68 */ "\u0966",
- /* 69 */ "1",
- /* 70 */ "2",
- /* 71 */ "3",
- /* 72 */ "4",
- /* 73 */ "5",
- /* 74 */ "6",
- /* 75 */ "7",
- /* 76 */ "8",
- /* 77 */ "9",
- /* 78 */ "0",
+ // Label for "switch to symbols" key.
+ /* 69 */ "?\u0967\u0968\u0969",
+ // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
+ // part because it'll be appended by the code.
+ /* 70 */ "\u0967\u0968\u0969",
+ /* 71 */ "1",
+ /* 72 */ "2",
+ /* 73 */ "3",
+ /* 74 */ "4",
+ /* 75 */ "5",
+ /* 76 */ "6",
+ /* 77 */ "7",
+ /* 78 */ "8",
+ /* 79 */ "9",
+ /* 80 */ "0",
};
/* Language hr: Croatian */
@@ -1640,17 +1739,25 @@ public final class KeyboardTextsSet {
/* 0~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null, null, null,
- /* ~42 */
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~41 */
+ // Label for "switch to alphabetic" key.
+ // U+05D0: "א" HEBREW LETTER ALEF
+ // U+05D1: "ב" HEBREW LETTER BET
+ // U+05D2: "ג" HEBREW LETTER GIMEL
+ /* 42 */ "\u05D0\u05D1\u05D2",
+ /* 43 */ null,
// TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
// <string name="more_keys_for_double_quote">&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB;|&#x00AB;</string>
- /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB",
+ /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB",
// TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
// <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB|&#x00AB;;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
- /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B",
- /* 45~ */
- null, null, null, null, null,
- /* ~49 */
+ /* 45 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B",
+ /* 46 */ null,
+ // U+20AA: "₪" NEW SHEQEL SIGN
+ /* 47 */ "\u20AA",
+ /* 48 */ null,
+ /* 49 */ null,
// U+2605: "★" BLACK STAR
/* 50 */ "\u2605",
/* 51 */ null,
@@ -1680,6 +1787,20 @@ public final class KeyboardTextsSet {
/* 56 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
};
+ /* Language ka: Georgian */
+ private static final String[] LANGUAGE_ka = {
+ /* 0~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~41 */
+ // Label for "switch to alphabetic" key.
+ // U+10D0: "ა" GEORGIAN LETTER AN
+ // U+10D1: "ბ" GEORGIAN LETTER BAN
+ // U+10D2: "გ" GEORGIAN LETTER GAN
+ /* 42 */ "\u10D0\u10D1\u10D2",
+ };
+
/* Language ky: Kirghiz */
private static final String[] LANGUAGE_ky = {
/* 0~ */
@@ -1711,6 +1832,12 @@ public final class KeyboardTextsSet {
/* ~39 */
// U+0451: "ё" CYRILLIC SMALL LETTER IO
/* 40 */ "\u0451",
+ /* 41 */ null,
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* 42 */ "\u0410\u0411\u0412",
};
/* Language lt: Lithuanian */
@@ -1911,7 +2038,12 @@ public final class KeyboardTextsSet {
/* 40 */ "\u0450",
// U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE
/* 41 */ "\u045D",
- /* 42 */ null,
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* 42 */ "\u0410\u0411\u0412",
+ /* 43 */ null,
// U+2018: "‘" LEFT SINGLE QUOTATION MARK
// U+2019: "’" RIGHT SINGLE QUOTATION MARK
// U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
@@ -1922,10 +2054,29 @@ public final class KeyboardTextsSet {
// U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
// TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
// <string name="more_keys_for_double_quote">!fixedColumnOrder!6,&#x201E;,&#x201C;,&#x201D;,&#x201F;,&#x00AB;,&#x00BB;</string>
- /* 43 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB",
+ /* 44 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB",
// TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
// <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
- /* 44 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B",
+ /* 45 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B",
+ };
+
+ /* Language mn: Mongolian */
+ private static final String[] LANGUAGE_mn = {
+ /* 0~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~41 */
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* 42 */ "\u0410\u0411\u0412",
+ /* 43~ */
+ null, null, null, null,
+ /* ~46 */
+ // U+20AE: "₮" TUGRIK SIGN
+ /* 47 */ "\u20AE",
};
/* Language nb: Norwegian Bokmål */
@@ -2205,6 +2356,12 @@ public final class KeyboardTextsSet {
/* ~39 */
// U+0451: "ё" CYRILLIC SMALL LETTER IO
/* 40 */ "\u0451",
+ /* 41 */ null,
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* 42 */ "\u0410\u0411\u0412",
};
/* Language sk: Slovak */
@@ -2354,8 +2511,13 @@ public final class KeyboardTextsSet {
/* 40 */ "\u0450",
// U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE
/* 41 */ "\u045D",
- /* 42 */ null,
// END: More keys definitions for Serbian (Cyrillic)
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* 42 */ "\u0410\u0411\u0412",
+ /* 43 */ null,
// U+2018: "‘" LEFT SINGLE QUOTATION MARK
// U+2019: "’" RIGHT SINGLE QUOTATION MARK
// U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
@@ -2366,10 +2528,10 @@ public final class KeyboardTextsSet {
// U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
// TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
// <string name="more_keys_for_double_quote">!fixedColumnOrder!6,&#x201E;,&#x201C;,&#x201D;,&#x201F;,&#x00AB;,&#x00BB;</string>
- /* 43 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB",
+ /* 44 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB",
// TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
// <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
- /* 44 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B",
+ /* 45 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B",
};
/* Language sv: Swedish */
@@ -2465,6 +2627,25 @@ public final class KeyboardTextsSet {
/* 15 */ "g\'",
};
+ /* Language th: Thai */
+ private static final String[] LANGUAGE_th = {
+ /* 0~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~41 */
+ // Label for "switch to alphabetic" key.
+ // U+0E01: "ก" THAI CHARACTER KO KAI
+ // U+0E02: "ข" THAI CHARACTER KHO KHAI
+ // U+0E04: "ค" THAI CHARACTER KHO KHWAI
+ /* 42 */ "\u0E01\u0E02\u0E04",
+ /* 43~ */
+ null, null, null, null,
+ /* ~46 */
+ // U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT
+ /* 47 */ "\u0E3F",
+ };
+
/* Language tl: Tagalog */
private static final String[] LANGUAGE_tl = {
// U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
@@ -2589,6 +2770,19 @@ public final class KeyboardTextsSet {
/* 34 */ null,
// U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
/* 35 */ "\u044A",
+ /* 36~ */
+ null, null, null, null, null, null,
+ /* ~41 */
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* 42 */ "\u0410\u0411\u0412",
+ /* 43~ */
+ null, null, null, null,
+ /* ~46 */
+ // U+20B4: "₴" HRYVNIA SIGN
+ /* 47 */ "\u20B4",
};
/* Language vi: Vietnamese */
@@ -2670,6 +2864,13 @@ public final class KeyboardTextsSet {
/* 8 */ "\u1EF3,\u00FD,\u1EF7,\u1EF9,\u1EF5",
// U+0111: "đ" LATIN SMALL LETTER D WITH STROKE
/* 9 */ "\u0111",
+ /* 10~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null,
+ /* ~46 */
+ // U+20AB: "₫" DONG SIGN
+ /* 47 */ "\u20AB",
};
/* Language zu: Zulu */
@@ -2847,10 +3048,12 @@ public final class KeyboardTextsSet {
"af", LANGUAGE_af, /* Afrikaans */
"ar", LANGUAGE_ar, /* Arabic */
"be", LANGUAGE_be, /* Belarusian */
+ "bg", LANGUAGE_bg, /* Bulgarian */
"ca", LANGUAGE_ca, /* Catalan */
"cs", LANGUAGE_cs, /* Czech */
"da", LANGUAGE_da, /* Danish */
"de", LANGUAGE_de, /* German */
+ "el", LANGUAGE_el, /* Greek */
"en", LANGUAGE_en, /* English */
"eo", LANGUAGE_eo, /* Esperanto */
"es", LANGUAGE_es, /* Spanish */
@@ -2864,10 +3067,12 @@ public final class KeyboardTextsSet {
"is", LANGUAGE_is, /* Icelandic */
"it", LANGUAGE_it, /* Italian */
"iw", LANGUAGE_iw, /* Hebrew */
+ "ka", LANGUAGE_ka, /* Georgian */
"ky", LANGUAGE_ky, /* Kirghiz */
"lt", LANGUAGE_lt, /* Lithuanian */
"lv", LANGUAGE_lv, /* Latvian */
"mk", LANGUAGE_mk, /* Macedonian */
+ "mn", LANGUAGE_mn, /* Mongolian */
"nb", LANGUAGE_nb, /* Norwegian Bokmål */
"nl", LANGUAGE_nl, /* Dutch */
"pl", LANGUAGE_pl, /* Polish */
@@ -2880,6 +3085,7 @@ public final class KeyboardTextsSet {
"sr", LANGUAGE_sr, /* Serbian */
"sv", LANGUAGE_sv, /* Swedish */
"sw", LANGUAGE_sw, /* Swahili */
+ "th", LANGUAGE_th, /* Thai */
"tl", LANGUAGE_tl, /* Tagalog */
"tr", LANGUAGE_tr, /* Turkish */
"uk", LANGUAGE_uk, /* Ukrainian */
diff --git a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java
index 550391b49..ca16163d4 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java
@@ -18,7 +18,7 @@ package com.android.inputmethod.keyboard.internal;
import android.text.TextUtils;
-import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.StringUtils;
import java.util.Locale;
@@ -35,10 +35,10 @@ public final class MoreKeySpec {
KeySpecParser.getLabel(moreKeySpec), needsToUpperCase, locale);
final int code = KeySpecParser.toUpperCaseOfCodeForLocale(
KeySpecParser.getCode(moreKeySpec, codesSet), needsToUpperCase, locale);
- if (code == Keyboard.CODE_UNSPECIFIED) {
+ if (code == Constants.CODE_UNSPECIFIED) {
// Some letter, for example German Eszett (U+00DF: "ß"), has multiple characters
// upper case representation ("SS").
- mCode = Keyboard.CODE_OUTPUT_TEXT;
+ mCode = Constants.CODE_OUTPUT_TEXT;
mOutputText = mLabel;
} else {
mCode = code;
@@ -75,8 +75,8 @@ public final class MoreKeySpec {
public String toString() {
final String label = (mIconId == KeyboardIconsSet.ICON_UNDEFINED ? mLabel
: KeySpecParser.PREFIX_ICON + KeyboardIconsSet.getIconName(mIconId));
- final String output = (mCode == Keyboard.CODE_OUTPUT_TEXT ? mOutputText
- : Keyboard.printableCode(mCode));
+ final String output = (mCode == Constants.CODE_OUTPUT_TEXT ? mOutputText
+ : Constants.printableCode(mCode));
if (StringUtils.codePointCount(label) == 1 && label.codePointAt(0) == mCode) {
return output;
} else {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
index a52f202aa..00fc885e8 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
@@ -30,6 +30,7 @@ public final class PointerTrackerQueue {
public boolean isModifier();
public boolean isInSlidingKeyInput();
public void onPhantomUpEvent(long eventTime);
+ public void cancelTracking();
}
private static final int INITIAL_CAPACITY = 10;
@@ -182,6 +183,15 @@ public final class PointerTrackerQueue {
return false;
}
+ public synchronized void cancelAllPointerTracker() {
+ final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
+ final int arraySize = mArraySize;
+ for (int index = 0; index < arraySize; index++) {
+ final Element element = expandableArray.get(index);
+ element.cancelTracking();
+ }
+ }
+
@Override
public synchronized String toString() {
final StringBuilder sb = new StringBuilder();
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
index 776ac0204..bc734b08d 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
@@ -36,14 +36,11 @@ import android.widget.RelativeLayout;
import com.android.inputmethod.keyboard.PointerTracker;
import com.android.inputmethod.keyboard.internal.GesturePreviewTrail.Params;
import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.CoordinateUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
public final class PreviewPlacerView extends RelativeLayout {
- // The height of extra area above the keyboard to draw gesture trails.
- // Proportional to the keyboard height.
- private static final float EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO = 0.25f;
-
private final int mGestureFloatingPreviewTextColor;
private final int mGestureFloatingPreviewTextOffset;
private final int mGestureFloatingPreviewColor;
@@ -51,8 +48,7 @@ public final class PreviewPlacerView extends RelativeLayout {
private final float mGestureFloatingPreviewVerticalPadding;
private final float mGestureFloatingPreviewRoundRadius;
- private int mKeyboardViewOriginX;
- private int mKeyboardViewOriginY;
+ private final int[] mKeyboardViewOrigin = CoordinateUtils.newInstance();
private final SparseArray<GesturePreviewTrail> mGesturePreviewTrails =
CollectionUtils.newSparseArray();
@@ -72,11 +68,14 @@ public final class PreviewPlacerView extends RelativeLayout {
private final int mGestureFloatingPreviewTextHeight;
// {@link RectF} is needed for {@link Canvas#drawRoundRect(RectF, float, float, Paint)}.
private final RectF mGestureFloatingPreviewRectangle = new RectF();
- private int mLastPointerX;
- private int mLastPointerY;
+ private final int[] mLastPointerCoords = CoordinateUtils.newInstance();
private static final char[] TEXT_HEIGHT_REFERENCE_CHAR = { 'M' };
private boolean mDrawsGestureFloatingPreviewText;
+ private boolean mShowSlidingKeyInputPreview;
+ private final int[] mRubberBandFrom = CoordinateUtils.newInstance();
+ private final int[] mRubberBandTo = CoordinateUtils.newInstance();
+
private final DrawingHandler mDrawingHandler;
private static final class DrawingHandler extends StaticInnerHandlerWrapper<PreviewPlacerView> {
@@ -172,10 +171,9 @@ public final class PreviewPlacerView extends RelativeLayout {
setLayerType(LAYER_TYPE_HARDWARE, layerPaint);
}
- public void setKeyboardViewGeometry(final int x, final int y, final int w, final int h) {
- mKeyboardViewOriginX = x;
- mKeyboardViewOriginY = y;
- mOffscreenOffsetY = (int)(h * EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO);
+ public void setKeyboardViewGeometry(final int[] originCoords, final int w, final int h) {
+ CoordinateUtils.copy(mKeyboardViewOrigin, originCoords);
+ mOffscreenOffsetY = (int)(h * GestureStroke.EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO);
mOffscreenWidth = w;
mOffscreenHeight = mOffscreenOffsetY + h;
}
@@ -190,8 +188,7 @@ public final class PreviewPlacerView extends RelativeLayout {
final boolean needsToUpdateLastPointer =
isOldestTracker && mDrawsGestureFloatingPreviewText;
if (needsToUpdateLastPointer) {
- mLastPointerX = tracker.getLastX();
- mLastPointerY = tracker.getLastY();
+ tracker.getLastCoordinates(mLastPointerCoords);
}
if (mDrawsGesturePreviewTrail) {
@@ -212,6 +209,21 @@ public final class PreviewPlacerView extends RelativeLayout {
}
}
+ public void showSlidingKeyInputPreview(final PointerTracker tracker) {
+ if (!tracker.isInSlidingKeyInputFromModifier()) {
+ mShowSlidingKeyInputPreview = false;
+ return;
+ }
+ tracker.getDownCoordinates(mRubberBandFrom);
+ tracker.getLastCoordinates(mRubberBandTo);
+ mShowSlidingKeyInputPreview = true;
+ invalidate();
+ }
+
+ public void dismissSlidingKeyInputPreview() {
+ mShowSlidingKeyInputPreview = false;
+ }
+
@Override
protected void onDetachedFromWindow() {
freeOffscreenBuffer();
@@ -238,6 +250,8 @@ public final class PreviewPlacerView extends RelativeLayout {
@Override
public void onDraw(final Canvas canvas) {
super.onDraw(canvas);
+ final int originX = CoordinateUtils.x(mKeyboardViewOrigin);
+ final int originY = CoordinateUtils.y(mKeyboardViewOrigin);
if (mDrawsGesturePreviewTrail) {
mayAllocateOffscreenBuffer();
// Draw gesture trails to offscreen buffer.
@@ -245,11 +259,11 @@ public final class PreviewPlacerView extends RelativeLayout {
mOffscreenCanvas, mGesturePaint, mOffscreenDirtyRect);
// Transfer offscreen buffer to screen.
if (!mOffscreenDirtyRect.isEmpty()) {
- final int offsetY = mKeyboardViewOriginY - mOffscreenOffsetY;
- canvas.translate(mKeyboardViewOriginX, offsetY);
+ final int offsetY = originY - mOffscreenOffsetY;
+ canvas.translate(originX, offsetY);
canvas.drawBitmap(mOffscreenBuffer, mOffscreenDirtyRect, mOffscreenDirtyRect,
mGesturePaint);
- canvas.translate(-mKeyboardViewOriginX, -offsetY);
+ canvas.translate(-originX, -offsetY);
// Note: Defer clearing the dirty rectangle here because we will get cleared
// rectangle on the canvas.
}
@@ -258,9 +272,14 @@ public final class PreviewPlacerView extends RelativeLayout {
}
}
if (mDrawsGestureFloatingPreviewText) {
- canvas.translate(mKeyboardViewOriginX, mKeyboardViewOriginY);
+ canvas.translate(originX, originY);
drawGestureFloatingPreviewText(canvas, mGestureFloatingPreviewText);
- canvas.translate(-mKeyboardViewOriginX, -mKeyboardViewOriginY);
+ canvas.translate(-originX, -originY);
+ }
+ if (mShowSlidingKeyInputPreview) {
+ canvas.translate(originX, originY);
+ drawSlidingKeyInputPreview(canvas);
+ canvas.translate(-originX, -originY);
}
}
@@ -321,8 +340,6 @@ public final class PreviewPlacerView extends RelativeLayout {
final Paint paint = mTextPaint;
final RectF rectangle = mGestureFloatingPreviewRectangle;
- // TODO: Figure out how we should deal with the floating preview text with multiple moving
- // fingers.
// Paint the round rectangle background.
final int textHeight = mGestureFloatingPreviewTextHeight;
@@ -332,9 +349,11 @@ public final class PreviewPlacerView extends RelativeLayout {
final float rectWidth = textWidth + hPad * 2.0f;
final float rectHeight = textHeight + vPad * 2.0f;
final int canvasWidth = canvas.getWidth();
- final float rectX = Math.min(Math.max(mLastPointerX - rectWidth / 2.0f, 0.0f),
+ final float rectX = Math.min(
+ Math.max(CoordinateUtils.x(mLastPointerCoords) - rectWidth / 2.0f, 0.0f),
canvasWidth - rectWidth);
- final float rectY = mLastPointerY - mGestureFloatingPreviewTextOffset - rectHeight;
+ final float rectY = CoordinateUtils.y(mLastPointerCoords)
+ - mGestureFloatingPreviewTextOffset - rectHeight;
rectangle.set(rectX, rectY, rectX + rectWidth, rectY + rectHeight);
final float round = mGestureFloatingPreviewRoundRadius;
paint.setColor(mGestureFloatingPreviewColor);
@@ -345,4 +364,8 @@ public final class PreviewPlacerView extends RelativeLayout {
final float textY = rectY + vPad + textHeight;
canvas.drawText(gestureFloatingPreviewText, textX, textY, paint);
}
+
+ private void drawSlidingKeyInputPreview(final Canvas canvas) {
+ // TODO: Implement rubber band preview
+ }
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/RoundedLine.java b/java/src/com/android/inputmethod/keyboard/internal/RoundedLine.java
new file mode 100644
index 000000000..1f5252077
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/RoundedLine.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import android.graphics.Path;
+import android.graphics.RectF;
+
+public final class RoundedLine {
+ private final RectF mArc1 = new RectF();
+ private final RectF mArc2 = new RectF();
+ private final Path mPath = new Path();
+
+ private static final double RADIAN_TO_DEGREE = 180.0d / Math.PI;
+ private static final double RIGHT_ANGLE = Math.PI / 2.0d;
+
+ /**
+ * Make a rounded line path
+ *
+ * @param p1x the x-coordinate of the start point.
+ * @param p1y the y-coordinate of the start point.
+ * @param r1 the radius at the start point
+ * @param p2x the x-coordinate of the end point.
+ * @param p2y the y-coordinate of the end point.
+ * @param r2 the radius at the end point
+ * @return the path of rounded line
+ */
+ public Path makePath(final float p1x, final float p1y, final float r1,
+ final float p2x, final float p2y, final float r2) {
+ final double dx = p2x - p1x;
+ final double dy = p2y - p1y;
+ // Distance of the points.
+ final double l = Math.hypot(dx, dy);
+ if (Double.compare(0.0d, l) == 0) {
+ return null;
+ }
+ // Angle of the line p1-p2
+ final double a = Math.atan2(dy, dx);
+ // Difference of trail cap radius.
+ final double dr = r2 - r1;
+ // Variation of angle at trail cap.
+ final double ar = Math.asin(dr / l);
+ // The start angle of trail cap arc at P1.
+ final double aa = a - (RIGHT_ANGLE + ar);
+ // The end angle of trail cap arc at P2.
+ final double ab = a + (RIGHT_ANGLE + ar);
+ final float cosa = (float)Math.cos(aa);
+ final float sina = (float)Math.sin(aa);
+ final float cosb = (float)Math.cos(ab);
+ final float sinb = (float)Math.sin(ab);
+ // Closing point of arc at P1.
+ final float p1ax = p1x + r1 * cosa;
+ final float p1ay = p1y + r1 * sina;
+ // Opening point of arc at P1.
+ final float p1bx = p1x + r1 * cosb;
+ final float p1by = p1y + r1 * sinb;
+ // Opening point of arc at P2.
+ final float p2ax = p2x + r2 * cosa;
+ final float p2ay = p2y + r2 * sina;
+ // Closing point of arc at P2.
+ final float p2bx = p2x + r2 * cosb;
+ final float p2by = p2y + r2 * sinb;
+ // Start angle of the trail arcs.
+ final float angle = (float)(aa * RADIAN_TO_DEGREE);
+ final float ar2degree = (float)(ar * 2.0d * RADIAN_TO_DEGREE);
+ // Sweep angle of the trail arc at P1.
+ final float a1 = -180.0f + ar2degree;
+ // Sweep angle of the trail arc at P2.
+ final float a2 = 180.0f + ar2degree;
+ mArc1.set(p1x, p1y, p1x, p1y);
+ mArc1.inset(-r1, -r1);
+ mArc2.set(p2x, p2y, p2x, p2y);
+ mArc2.inset(-r2, -r2);
+
+ mPath.rewind();
+ // Trail cap at P1.
+ mPath.moveTo(p1x, p1y);
+ mPath.arcTo(mArc1, angle, a1);
+ // Trail cap at P2.
+ mPath.moveTo(p2x, p2y);
+ mPath.arcTo(mArc2, angle, a2);
+ // Two trapezoids connecting P1 and P2.
+ mPath.moveTo(p1ax, p1ay);
+ mPath.lineTo(p1x, p1y);
+ mPath.lineTo(p1bx, p1by);
+ mPath.lineTo(p2bx, p2by);
+ mPath.lineTo(p2x, p2y);
+ mPath.lineTo(p2ax, p2ay);
+ mPath.close();
+ return mPath;
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/TouchPositionCorrection.java b/java/src/com/android/inputmethod/keyboard/internal/TouchPositionCorrection.java
index d8950a713..d7a2b6f39 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/TouchPositionCorrection.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/TouchPositionCorrection.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.keyboard.internal;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.LatinImeLogger;
public final class TouchPositionCorrection {
@@ -66,7 +67,7 @@ public final class TouchPositionCorrection {
}
}
- // For test only
+ @UsedForTesting
public void setEnabled(final boolean enabled) {
mEnabled = enabled;
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/SuddenJumpingTouchEventHandler.java b/java/src/com/android/inputmethod/keyboard/internal/TouchScreenRegulator.java
index c53428fe5..c795d5322 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/SuddenJumpingTouchEventHandler.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/TouchScreenRegulator.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
-import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.MainKeyboardView;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
@@ -28,8 +27,8 @@ import com.android.inputmethod.latin.ResourceUtils;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.research.ResearchLogger;
-public final class SuddenJumpingTouchEventHandler {
- private static final String TAG = SuddenJumpingTouchEventHandler.class.getSimpleName();
+public final class TouchScreenRegulator {
+ private static final String TAG = TouchScreenRegulator.class.getSimpleName();
private static boolean DEBUG_MODE = LatinImeLogger.sDBG;
public interface ProcessMotionEvent {
@@ -50,17 +49,18 @@ public final class SuddenJumpingTouchEventHandler {
private int mJumpThresholdSquare = Integer.MAX_VALUE;
private int mLastX;
private int mLastY;
+ // One-seventh of the keyboard width seems like a reasonable threshold
+ private static final float JUMP_THRESHOLD_RATIO_TO_KEYBOARD_WIDTH = 1.0f / 7.0f;
- public SuddenJumpingTouchEventHandler(Context context, ProcessMotionEvent view) {
+ public TouchScreenRegulator(final Context context, final ProcessMotionEvent view) {
mView = view;
mNeedsSuddenJumpingHack = Boolean.parseBoolean(ResourceUtils.getDeviceOverrideValue(
context.getResources(), R.array.sudden_jumping_touch_event_device_list, "false"));
}
- public void setKeyboard(Keyboard newKeyboard) {
- // One-seventh of the keyboard width seems like a reasonable threshold
- final int jumpThreshold = newKeyboard.mOccupiedWidth / 7;
- mJumpThresholdSquare = jumpThreshold * jumpThreshold;
+ public void setKeyboardGeometry(final int keyboardWidth) {
+ final float jumpThreshold = keyboardWidth * JUMP_THRESHOLD_RATIO_TO_KEYBOARD_WIDTH;
+ mJumpThresholdSquare = (int)(jumpThreshold * jumpThreshold);
}
/**
@@ -74,7 +74,7 @@ public final class SuddenJumpingTouchEventHandler {
* @return true if the event was consumed, so that it doesn't continue to be handled by
* {@link MainKeyboardView}.
*/
- private boolean handleSuddenJumping(MotionEvent me) {
+ private boolean handleSuddenJumping(final MotionEvent me) {
if (!mNeedsSuddenJumpingHack)
return false;
final int action = me.getAction();
@@ -140,7 +140,7 @@ public final class SuddenJumpingTouchEventHandler {
return result;
}
- public boolean onTouchEvent(MotionEvent me) {
+ public boolean onTouchEvent(final MotionEvent me) {
// If there was a sudden jump, return without processing the actual motion event.
if (handleSuddenJumping(me)) {
if (DEBUG_MODE)
diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
index 939451899..08f08d24e 100644
--- a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
+++ b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
@@ -50,6 +50,7 @@ import java.util.ArrayList;
import java.util.TreeSet;
public final class AdditionalSubtypeSettings extends PreferenceFragment {
+ private RichInputMethodManager mRichImm;
private SharedPreferences mPrefs;
private SubtypeLocaleAdapter mSubtypeLocaleAdapter;
private KeyboardLayoutSetAdapter mKeyboardLayoutSetAdapter;
@@ -63,6 +64,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment {
private static final String KEY_IS_SUBTYPE_ENABLER_NOTIFICATION_DIALOG_OPEN =
"is_subtype_enabler_notification_dialog_open";
private static final String KEY_SUBTYPE_FOR_SUBTYPE_ENABLER = "subtype_for_subtype_enabler";
+
static final class SubtypeLocaleItem extends Pair<String, String>
implements Comparable<SubtypeLocaleItem> {
public SubtypeLocaleItem(final String localeString, final String displayName) {
@@ -93,7 +95,8 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment {
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
final TreeSet<SubtypeLocaleItem> items = CollectionUtils.newTreeSet();
- final InputMethodInfo imi = ImfUtils.getInputMethodInfoOfThisIme(context);
+ final InputMethodInfo imi = RichInputMethodManager.getInstance()
+ .getInputMethodInfoOfThisIme();
final int count = imi.getSubtypeCount();
for (int i = 0; i < count; i++) {
final InputMethodSubtype subtype = imi.getSubtypeAt(i);
@@ -383,10 +386,11 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment {
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mPrefs = getPreferenceManager().getSharedPreferences();
+ RichInputMethodManager.init(getActivity(), mPrefs);
+ mRichImm = RichInputMethodManager.getInstance();
addPreferencesFromResource(R.xml.additional_subtype_settings);
setHasOptionsMenu(true);
-
- mPrefs = getPreferenceManager().getSharedPreferences();
}
@Override
@@ -439,7 +443,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment {
mIsAddingNewSubtype = false;
final PreferenceGroup group = getPreferenceScreen();
group.removePreference(subtypePref);
- ImfUtils.setAdditionalInputMethodSubtypes(getActivity(), getSubtypes());
+ mRichImm.setAdditionalInputMethodSubtypes(getSubtypes());
}
@Override
@@ -449,7 +453,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment {
return;
}
if (findDuplicatedSubtype(subtype) == null) {
- ImfUtils.setAdditionalInputMethodSubtypes(getActivity(), getSubtypes());
+ mRichImm.setAdditionalInputMethodSubtypes(getSubtypes());
return;
}
@@ -466,7 +470,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment {
mIsAddingNewSubtype = false;
final InputMethodSubtype subtype = subtypePref.getSubtype();
if (findDuplicatedSubtype(subtype) == null) {
- ImfUtils.setAdditionalInputMethodSubtypes(getActivity(), getSubtypes());
+ mRichImm.setAdditionalInputMethodSubtypes(getSubtypes());
mSubtypePreferenceKeyForSubtypeEnabler = subtypePref.getKey();
mSubtypeEnablerNotificationDialog = createDialog(subtypePref);
mSubtypeEnablerNotificationDialog.show();
@@ -501,8 +505,8 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment {
private InputMethodSubtype findDuplicatedSubtype(final InputMethodSubtype subtype) {
final String localeString = subtype.getLocale();
final String keyboardLayoutSetName = SubtypeLocale.getKeyboardLayoutSetName(subtype);
- return ImfUtils.findSubtypeByLocaleAndKeyboardLayoutSet(
- getActivity(), localeString, keyboardLayoutSetName);
+ return mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ localeString, keyboardLayoutSetName);
}
private AlertDialog createDialog(
@@ -515,7 +519,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment {
@Override
public void onClick(DialogInterface dialog, int which) {
final Intent intent = CompatUtils.getInputLanguageSelectionIntent(
- ImfUtils.getInputMethodIdOfThisIme(getActivity()),
+ mRichImm.getInputMethodIdOfThisIme(),
Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -573,7 +577,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment {
} finally {
editor.apply();
}
- ImfUtils.setAdditionalInputMethodSubtypes(getActivity(), subtypes);
+ mRichImm.setAdditionalInputMethodSubtypes(subtypes);
}
@Override
diff --git a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java
index 59ef5e09f..024726391 100644
--- a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java
+++ b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java
@@ -21,7 +21,6 @@ import android.media.AudioManager;
import android.view.HapticFeedbackConstants;
import android.view.View;
-import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.latin.VibratorUtils;
/**
@@ -31,17 +30,15 @@ import com.android.inputmethod.latin.VibratorUtils;
* complexity of settings and the like.
*/
public final class AudioAndHapticFeedbackManager {
- final private SettingsValues mSettingsValues;
- final private AudioManager mAudioManager;
- final private VibratorUtils mVibratorUtils;
+ private final AudioManager mAudioManager;
+ private final VibratorUtils mVibratorUtils;
+
+ private SettingsValues mSettingsValues;
private boolean mSoundOn;
- public AudioAndHapticFeedbackManager(final LatinIME latinIme,
- final SettingsValues settingsValues) {
- mSettingsValues = settingsValues;
+ public AudioAndHapticFeedbackManager(final LatinIME latinIme) {
mVibratorUtils = VibratorUtils.getInstance(latinIme);
mAudioManager = (AudioManager) latinIme.getSystemService(Context.AUDIO_SERVICE);
- mSoundOn = reevaluateIfSoundIsOn();
}
public void hapticAndAudioFeedback(final int primaryCode,
@@ -51,7 +48,7 @@ public final class AudioAndHapticFeedbackManager {
}
private boolean reevaluateIfSoundIsOn() {
- if (!mSettingsValues.mSoundOn || mAudioManager == null) {
+ if (mSettingsValues == null || !mSettingsValues.mSoundOn || mAudioManager == null) {
return false;
} else {
return mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL;
@@ -64,13 +61,13 @@ public final class AudioAndHapticFeedbackManager {
if (mSoundOn) {
final int sound;
switch (primaryCode) {
- case Keyboard.CODE_DELETE:
+ case Constants.CODE_DELETE:
sound = AudioManager.FX_KEYPRESS_DELETE;
break;
- case Keyboard.CODE_ENTER:
+ case Constants.CODE_ENTER:
sound = AudioManager.FX_KEYPRESS_RETURN;
break;
- case Keyboard.CODE_SPACE:
+ case Constants.CODE_SPACE:
sound = AudioManager.FX_KEYPRESS_SPACEBAR;
break;
default:
@@ -81,8 +78,7 @@ public final class AudioAndHapticFeedbackManager {
}
}
- // TODO: make this private when LatinIME does not call it any more
- public void vibrate(final View viewToPerformHapticFeedbackOn) {
+ private void vibrate(final View viewToPerformHapticFeedbackOn) {
if (!mSettingsValues.mVibrateOn) {
return;
}
@@ -98,6 +94,11 @@ public final class AudioAndHapticFeedbackManager {
}
}
+ public void onSettingsChanged(final SettingsValues settingsValues) {
+ mSettingsValues = settingsValues;
+ mSoundOn = reevaluateIfSoundIsOn();
+ }
+
public void onRingerModeChanged() {
mSoundOn = reevaluateIfSoundIsOn();
}
diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java
index 84fad158f..fa35922b0 100644
--- a/java/src/com/android/inputmethod/latin/AutoCorrection.java
+++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java
@@ -33,11 +33,11 @@ public final class AutoCorrection {
}
public static boolean isValidWord(final ConcurrentHashMap<String, Dictionary> dictionaries,
- CharSequence word, boolean ignoreCase) {
+ final String word, final boolean ignoreCase) {
if (TextUtils.isEmpty(word)) {
return false;
}
- final CharSequence lowerCasedWord = word.toString().toLowerCase();
+ final String lowerCasedWord = word.toLowerCase();
for (final String key : dictionaries.keySet()) {
final Dictionary dictionary = dictionaries.get(key);
// It's unclear how realistically 'dictionary' can be null, but the monkey is somehow
@@ -57,7 +57,7 @@ public final class AutoCorrection {
}
public static int getMaxFrequency(final ConcurrentHashMap<String, Dictionary> dictionaries,
- CharSequence word) {
+ final String word) {
if (TextUtils.isEmpty(word)) {
return Dictionary.NOT_A_PROBABILITY;
}
@@ -76,12 +76,13 @@ public final class AutoCorrection {
// Returns true if this is in any of the dictionaries.
public static boolean isInTheDictionary(
final ConcurrentHashMap<String, Dictionary> dictionaries,
- final CharSequence word, final boolean ignoreCase) {
+ final String word, final boolean ignoreCase) {
return isValidWord(dictionaries, word, ignoreCase);
}
- public static boolean suggestionExceedsAutoCorrectionThreshold(SuggestedWordInfo suggestion,
- CharSequence consideredWord, float autoCorrectionThreshold) {
+ public static boolean suggestionExceedsAutoCorrectionThreshold(
+ final SuggestedWordInfo suggestion, final String consideredWord,
+ final float autoCorrectionThreshold) {
if (null != suggestion) {
// Shortlist a whitelisted word
if (suggestion.mKind == SuggestedWordInfo.KIND_WHITELIST) return true;
@@ -89,8 +90,7 @@ public final class AutoCorrection {
// TODO: when the normalized score of the first suggestion is nearly equals to
// the normalized score of the second suggestion, behave less aggressive.
final float normalizedScore = BinaryDictionary.calcNormalizedScore(
- consideredWord.toString(), suggestion.mWord.toString(),
- autoCorrectionSuggestionScore);
+ consideredWord, suggestion.mWord, autoCorrectionSuggestionScore);
if (DBG) {
Log.d(TAG, "Normalized " + consideredWord + "," + suggestion + ","
+ autoCorrectionSuggestionScore + ", " + normalizedScore
@@ -100,8 +100,7 @@ public final class AutoCorrection {
if (DBG) {
Log.d(TAG, "Auto corrected by S-threshold.");
}
- return !shouldBlockAutoCorrectionBySafetyNet(consideredWord.toString(),
- suggestion.mWord);
+ return !shouldBlockAutoCorrectionBySafetyNet(consideredWord, suggestion.mWord);
}
}
return false;
@@ -110,7 +109,7 @@ public final class AutoCorrection {
// TODO: Resolve the inconsistencies between the native auto correction algorithms and
// this safety net
public static boolean shouldBlockAutoCorrectionBySafetyNet(final String typedWord,
- final CharSequence suggestion) {
+ final String suggestion) {
// Safety net for auto correction.
// Actually if we hit this safety net, it's a bug.
// If user selected aggressive auto correction mode, there is no need to use the safety
@@ -123,7 +122,7 @@ public final class AutoCorrection {
}
final int maxEditDistanceOfNativeDictionary =
(typedWordLength < 5 ? 2 : typedWordLength / 2) + 1;
- final int distance = BinaryDictionary.editDistance(typedWord, suggestion.toString());
+ final int distance = BinaryDictionary.editDistance(typedWord, suggestion);
if (DBG) {
Log.d(TAG, "Autocorrected edit distance = " + distance
+ ", " + maxEditDistanceOfNativeDictionary);
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 7184f1d8a..6048a3308 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -31,7 +31,7 @@ import java.util.Locale;
* Implements a static, compacted, binary dictionary of standard words.
*/
public final class BinaryDictionary extends Dictionary {
-
+ private static final String TAG = BinaryDictionary.class.getSimpleName();
public static final String DICTIONARY_PACK_AUTHORITY =
"com.android.inputmethod.latin.dictionarypack";
@@ -45,17 +45,13 @@ public final class BinaryDictionary extends Dictionary {
public static final int MAX_WORDS = 18;
public static final int MAX_SPACES = 16;
- private static final String TAG = BinaryDictionary.class.getSimpleName();
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;
-
private long mNativeDict;
private final Locale mLocale;
private final int[] mInputCodePoints = new int[MAX_WORD_LENGTH];
- // TODO: The below should be int[] mOutputCodePoints
- private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_RESULTS];
+ private final int[] mOutputCodePoints = new int[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];
@@ -67,7 +63,7 @@ public final class BinaryDictionary extends Dictionary {
// TODO: There should be a way to remove used DicTraverseSession objects from
// {@code mDicTraverseSessions}.
- private DicTraverseSession getTraverseSession(int traverseSessionId) {
+ private DicTraverseSession getTraverseSession(final int traverseSessionId) {
synchronized(mDicTraverseSessions) {
DicTraverseSession traverseSession = mDicTraverseSessions.get(traverseSessionId);
if (traverseSession == null) {
@@ -84,7 +80,6 @@ public final class BinaryDictionary extends Dictionary {
/**
* Constructor for the binary dictionary. This is supposed to be called from the
* dictionary factory.
- * All implementations should pass null into flagArray, except for testing purposes.
* @param context the context to access the environment from.
* @param filename the name of the file to read through native code.
* @param offset the offset of the dictionary data within the file.
@@ -92,9 +87,9 @@ public final class BinaryDictionary extends Dictionary {
* @param useFullEditDistance whether to use the full edit distance in suggestions
* @param dictType the dictionary type, as a human-readable string
*/
- public BinaryDictionary(final Context context,
- final String filename, final long offset, final long length,
- final boolean useFullEditDistance, final Locale locale, final String dictType) {
+ public BinaryDictionary(final Context context, final String filename, final long offset,
+ final long length, final boolean useFullEditDistance, final Locale locale,
+ final String dictType) {
super(dictType);
mLocale = locale;
mUseFullEditDistance = useFullEditDistance;
@@ -106,40 +101,40 @@ public final class BinaryDictionary extends Dictionary {
}
private native long openNative(String sourceDir, long dictOffset, long dictSize,
- int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength, int maxWords,
- int maxPredictions);
+ int maxWordLength, int maxWords, int maxPredictions);
private native void closeNative(long dict);
private native int getFrequencyNative(long dict, int[] word);
private native boolean isValidBigramNative(long dict, int[] word1, int[] word2);
private native int getSuggestionsNative(long dict, long proximityInfo, long traverseSession,
int[] xCoordinates, int[] yCoordinates, int[] times, int[] pointerIds,
int[] inputCodePoints, int codesSize, int commitPoint, boolean isGesture,
- int[] prevWordCodePointArray, boolean useFullEditDistance, char[] outputChars,
+ int[] prevWordCodePointArray, boolean useFullEditDistance, int[] outputCodePoints,
int[] outputScores, int[] outputIndices, int[] outputTypes);
- private static native float calcNormalizedScoreNative(char[] before, char[] after, int score);
- private static native int editDistanceNative(char[] before, char[] after);
+ private static native float calcNormalizedScoreNative(int[] before, int[] after, int score);
+ private static native int editDistanceNative(int[] before, int[] after);
// TODO: Move native dict into session
- 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, MAX_PREDICTIONS);
+ private final void loadDictionary(final String path, final long startOffset,
+ final long length) {
+ mNativeDict = openNative(path, startOffset, length, MAX_WORD_LENGTH, MAX_WORDS,
+ MAX_PREDICTIONS);
}
@Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
- final CharSequence prevWord, final ProximityInfo proximityInfo) {
+ final String prevWord, final ProximityInfo proximityInfo) {
return getSuggestionsWithSessionId(composer, prevWord, proximityInfo, 0);
}
@Override
public ArrayList<SuggestedWordInfo> getSuggestionsWithSessionId(final WordComposer composer,
- final CharSequence prevWord, final ProximityInfo proximityInfo, int sessionId) {
+ final String prevWord, final ProximityInfo proximityInfo, int sessionId) {
if (!isValidDictionary()) return null;
Arrays.fill(mInputCodePoints, Constants.NOT_A_CODE);
// TODO: toLowerCase in the native code
final int[] prevWordCodePointArray = (null == prevWord)
- ? null : StringUtils.toCodePointArray(prevWord.toString());
+ ? null : StringUtils.toCodePointArray(prevWord);
final int composerSize = composer.size();
final boolean isGesture = composer.isBatchMode();
@@ -157,7 +152,8 @@ public final class BinaryDictionary extends Dictionary {
proximityInfo.getNativeProximityInfo(), getTraverseSession(sessionId).getSession(),
ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(),
mInputCodePoints, codesSize, 0 /* commitPoint */, isGesture, prevWordCodePointArray,
- mUseFullEditDistance, mOutputChars, mOutputScores, mSpaceIndices, mOutputTypes);
+ mUseFullEditDistance, mOutputCodePoints, mOutputScores, mSpaceIndices,
+ mOutputTypes);
final int count = Math.min(tmpCount, MAX_PREDICTIONS);
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
@@ -165,53 +161,56 @@ public final class BinaryDictionary extends Dictionary {
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) {
+ while (len < MAX_WORD_LENGTH && mOutputCodePoints[start + len] != 0) {
++len;
}
if (len > 0) {
final int score = SuggestedWordInfo.KIND_WHITELIST == mOutputTypes[j]
? SuggestedWordInfo.MAX_SCORE : mOutputScores[j];
- suggestions.add(new SuggestedWordInfo(
- new String(mOutputChars, start, len), score, mOutputTypes[j], mDictType));
+ suggestions.add(new SuggestedWordInfo(new String(mOutputCodePoints, start, len),
+ score, mOutputTypes[j], mDictType));
}
}
return suggestions;
}
- /* package for test */ boolean isValidDictionary() {
+ public boolean isValidDictionary() {
return mNativeDict != 0;
}
- public static float calcNormalizedScore(String before, String after, int score) {
- return calcNormalizedScoreNative(before.toCharArray(), after.toCharArray(), score);
+ public static float calcNormalizedScore(final String before, final String after,
+ final int score) {
+ return calcNormalizedScoreNative(StringUtils.toCodePointArray(before),
+ StringUtils.toCodePointArray(after), score);
}
- public static int editDistance(String before, String after) {
+ public static int editDistance(final String before, final String after) {
if (before == null || after == null) {
throw new IllegalArgumentException();
}
- return editDistanceNative(before.toCharArray(), after.toCharArray());
+ return editDistanceNative(StringUtils.toCodePointArray(before),
+ StringUtils.toCodePointArray(after));
}
@Override
- public boolean isValidWord(CharSequence word) {
+ public boolean isValidWord(final String word) {
return getFrequency(word) >= 0;
}
@Override
- public int getFrequency(CharSequence word) {
+ public int getFrequency(final String word) {
if (word == null) return -1;
- int[] codePoints = StringUtils.toCodePointArray(word.toString());
+ int[] codePoints = StringUtils.toCodePointArray(word);
return getFrequencyNative(mNativeDict, codePoints);
}
// TODO: Add a batch process version (isValidBigramMultiple?) to avoid excessive numbers of jni
// calls when checking for changes in an entire dictionary.
- public boolean isValidBigram(CharSequence word1, CharSequence word2) {
+ public boolean isValidBigram(final String word1, final String word2) {
if (TextUtils.isEmpty(word1) || TextUtils.isEmpty(word2)) return false;
- int[] chars1 = StringUtils.toCodePointArray(word1.toString());
- int[] chars2 = StringUtils.toCodePointArray(word2.toString());
- return isValidBigramNative(mNativeDict, chars1, chars2);
+ final int[] codePoints1 = StringUtils.toCodePointArray(word1);
+ final int[] codePoints2 = StringUtils.toCodePointArray(word2);
+ return isValidBigramNative(mNativeDict, codePoints1, codePoints2);
}
@Override
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
index 9a3f88f52..5eab292fc 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
@@ -149,7 +149,13 @@ public final class BinaryDictionaryFileDumper {
final Uri.Builder wordListUriBuilder = getProviderUriBuilder(id);
final String finalFileName = BinaryDictionaryGetter.getCacheFileName(id, locale, context);
- final String tempFileName = BinaryDictionaryGetter.getTempFileName(id, context);
+ String tempFileName;
+ try {
+ tempFileName = BinaryDictionaryGetter.getTempFileName(id, context);
+ } catch (IOException e) {
+ Log.e(TAG, "Can't open the temporary file", e);
+ return null;
+ }
for (int mode = MODE_MIN; mode <= MODE_MAX; ++mode) {
InputStream originalSourceStream = null;
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index c747dc673..83dabbede 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin;
+import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.latin.makedict.BinaryDictInputOutput;
import com.android.inputmethod.latin.makedict.FormatSpec;
@@ -165,14 +166,9 @@ final class BinaryDictionaryGetter {
/**
* Generates a unique temporary file name in the app cache directory.
- *
- * This is unique as long as it doesn't get called twice in the same millisecond by the same
- * thread, which should be more than enough for our purposes.
*/
- public static String getTempFileName(String id, Context context) {
- final String fileName = replaceFileNameDangerousCharacters(id);
- return context.getCacheDir() + File.separator + fileName + "."
- + Thread.currentThread().getId() + "." + System.currentTimeMillis();
+ public static String getTempFileName(String id, Context context) throws IOException {
+ return File.createTempFile(replaceFileNameDangerousCharacters(id), null).getAbsolutePath();
}
/**
@@ -427,8 +423,11 @@ final class BinaryDictionaryGetter {
// cacheWordListsFromContentProvider returns the list of files it copied to local
// storage, but we don't really care about what was copied NOW: what we want is the
// list of everything we ever cached, so we ignore the return value.
- BinaryDictionaryFileDumper.cacheWordListsFromContentProvider(locale, context,
- hasDefaultWordList);
+ // TODO: The experimental version is not supported by the Dictionary Pack Service yet
+ if (!ProductionFlag.IS_EXPERIMENTAL) {
+ BinaryDictionaryFileDumper.cacheWordListsFromContentProvider(locale, context,
+ hasDefaultWordList);
+ }
final File[] cachedWordLists = getCachedWordLists(locale.toString(), context);
final String mainDictId = getMainDictId(locale);
final DictPackSettings dictPackSettings = new DictPackSettings(context);
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index 57e12a64f..ba932e590 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -136,11 +136,81 @@ public final class Constants {
public static final int NOT_A_CODE = -1;
- // See {@link KeyboardActionListener.Adapter#isInvalidCoordinate(int)}.
public static final int NOT_A_COORDINATE = -1;
public static final int SUGGESTION_STRIP_COORDINATE = -2;
public static final int SPELL_CHECKER_COORDINATE = -3;
+ public static boolean isValidCoordinate(final int coordinate) {
+ // Detect {@link NOT_A_COORDINATE}, {@link SUGGESTION_STRIP_COORDINATE},
+ // and {@link SPELL_CHECKER_COORDINATE}.
+ return coordinate >= 0;
+ }
+
+ /**
+ * Some common keys code. Must be positive.
+ */
+ public static final int CODE_ENTER = '\n';
+ public static final int CODE_TAB = '\t';
+ public static final int CODE_SPACE = ' ';
+ public static final int CODE_PERIOD = '.';
+ public static final int CODE_DASH = '-';
+ public static final int CODE_SINGLE_QUOTE = '\'';
+ public static final int CODE_DOUBLE_QUOTE = '"';
+ public static final int CODE_QUESTION_MARK = '?';
+ public static final int CODE_EXCLAMATION_MARK = '!';
+ // TODO: Check how this should work for right-to-left languages. It seems to stand
+ // that for rtl languages, a closing parenthesis is a left parenthesis. Is this
+ // managed by the font? Or is it a different char?
+ public static final int CODE_CLOSING_PARENTHESIS = ')';
+ public static final int CODE_CLOSING_SQUARE_BRACKET = ']';
+ public static final int CODE_CLOSING_CURLY_BRACKET = '}';
+ public static final int CODE_CLOSING_ANGLE_BRACKET = '>';
+
+ /**
+ * Special keys code. Must be negative.
+ * These should be aligned with KeyboardCodesSet.ID_TO_NAME[],
+ * KeyboardCodesSet.DEFAULT[] and KeyboardCodesSet.RTL[]
+ */
+ public static final int CODE_SHIFT = -1;
+ public static final int CODE_SWITCH_ALPHA_SYMBOL = -2;
+ public static final int CODE_OUTPUT_TEXT = -3;
+ public static final int CODE_DELETE = -4;
+ public static final int CODE_SETTINGS = -5;
+ public static final int CODE_SHORTCUT = -6;
+ public static final int CODE_ACTION_ENTER = -7;
+ public static final int CODE_ACTION_NEXT = -8;
+ public static final int CODE_ACTION_PREVIOUS = -9;
+ public static final int CODE_LANGUAGE_SWITCH = -10;
+ public static final int CODE_RESEARCH = -11;
+ // Code value representing the code is not specified.
+ public static final int CODE_UNSPECIFIED = -12;
+
+ public static boolean isLetterCode(final int code) {
+ return code >= CODE_SPACE;
+ }
+
+ public static String printableCode(final int code) {
+ switch (code) {
+ case CODE_SHIFT: return "shift";
+ case CODE_SWITCH_ALPHA_SYMBOL: return "symbol";
+ case CODE_OUTPUT_TEXT: return "text";
+ case CODE_DELETE: return "delete";
+ case CODE_SETTINGS: return "settings";
+ case CODE_SHORTCUT: return "shortcut";
+ case CODE_ACTION_ENTER: return "actionEnter";
+ case CODE_ACTION_NEXT: return "actionNext";
+ case CODE_ACTION_PREVIOUS: return "actionPrevious";
+ case CODE_LANGUAGE_SWITCH: return "languageSwitch";
+ case CODE_UNSPECIFIED: return "unspec";
+ case CODE_TAB: return "tab";
+ case CODE_ENTER: return "enter";
+ default:
+ if (code < CODE_SPACE) return String.format("'\\u%02x'", code);
+ if (code < 0x100) return String.format("'%c'", code);
+ return String.format("'\\u%04x'", code);
+ }
+ }
+
private Constants() {
// This utility class is not publicly instantiable.
}
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index 5edc4314f..d1b32a2f3 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -24,8 +24,6 @@ import android.provider.ContactsContract.Contacts;
import android.text.TextUtils;
import android.util.Log;
-import com.android.inputmethod.keyboard.Keyboard;
-
import java.util.Locale;
public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
@@ -62,7 +60,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
*/
private final boolean mUseFirstLastBigrams;
- public ContactsBinaryDictionary(final Context context, Locale locale) {
+ public ContactsBinaryDictionary(final Context context, final Locale locale) {
super(context, getFilenameWithLocale(NAME, locale.toString()), Dictionary.TYPE_CONTACTS);
mLocale = locale;
mUseFirstLastBigrams = useFirstLastBigramsForLocale(locale);
@@ -120,7 +118,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
}
}
- private boolean useFirstLastBigramsForLocale(Locale locale) {
+ private boolean useFirstLastBigramsForLocale(final Locale locale) {
// TODO: Add firstname/lastname bigram rules for other languages.
if (locale != null && locale.getLanguage().equals(Locale.ENGLISH.getLanguage())) {
return true;
@@ -128,7 +126,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
return false;
}
- private void addWords(Cursor cursor) {
+ private void addWords(final Cursor cursor) {
clearFusionDictionary();
int count = 0;
while (!cursor.isAfterLast() && count < MAX_CONTACT_COUNT) {
@@ -160,7 +158,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
* Adds the words in a name (e.g., firstname/lastname) to the binary dictionary along with their
* bigrams depending on locale.
*/
- private void addName(String name) {
+ private void addName(final String name) {
int len = StringUtils.codePointCount(name);
String prevWord = null;
// TODO: Better tokenization for non-Latin writing systems
@@ -188,12 +186,13 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
/**
* Returns the index of the last letter in the word, starting from position startIndex.
*/
- private static int getWordEndPosition(String string, int len, int startIndex) {
+ private static int getWordEndPosition(final String string, final int len,
+ final int startIndex) {
int end;
int cp = 0;
for (end = startIndex + 1; end < len; end += Character.charCount(cp)) {
cp = string.codePointAt(end);
- if (!(cp == Keyboard.CODE_DASH || cp == Keyboard.CODE_SINGLE_QUOTE
+ if (!(cp == Constants.CODE_DASH || cp == Constants.CODE_SINGLE_QUOTE
|| Character.isLetter(cp))) {
break;
}
@@ -249,7 +248,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
return false;
}
- private static boolean isValidName(String name) {
+ private static boolean isValidName(final String name) {
if (name != null && -1 == name.indexOf('@')) {
return true;
}
@@ -259,7 +258,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
/**
* Checks if the words in a name are in the current binary dictionary.
*/
- private boolean isNameInDictionary(String name) {
+ private boolean isNameInDictionary(final String name) {
int len = StringUtils.codePointCount(name);
String prevWord = null;
for (int i = 0; i < len; i++) {
diff --git a/java/src/com/android/inputmethod/latin/CoordinateUtils.java b/java/src/com/android/inputmethod/latin/CoordinateUtils.java
new file mode 100644
index 000000000..af270e1e4
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/CoordinateUtils.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin;
+
+public final class CoordinateUtils {
+ private static final int INDEX_X = 0;
+ private static final int INDEX_Y = 1;
+ private static final int ARRAY_SIZE = INDEX_Y + 1;
+
+ private CoordinateUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ public static int[] newInstance() {
+ return new int[ARRAY_SIZE];
+ }
+
+ public static int x(final int[] coords) {
+ return coords[INDEX_X];
+ }
+
+ public static int y(final int[] coords) {
+ return coords[INDEX_Y];
+ }
+
+ public static void set(final int[] coords, final int x, final int y) {
+ coords[INDEX_X] = x;
+ coords[INDEX_Y] = y;
+ }
+
+ public static void copy(final int[] destination, final int[] source) {
+ destination[INDEX_X] = source[INDEX_X];
+ destination[INDEX_Y] = source[INDEX_Y];
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/DebugSettings.java b/java/src/com/android/inputmethod/latin/DebugSettings.java
index 3af3cab2c..f8aeb4e9f 100644
--- a/java/src/com/android/inputmethod/latin/DebugSettings.java
+++ b/java/src/com/android/inputmethod/latin/DebugSettings.java
@@ -37,9 +37,12 @@ public final class DebugSettings extends PreferenceFragment
private static final String DEBUG_MODE_KEY = "debug_mode";
public static final String FORCE_NON_DISTINCT_MULTITOUCH_KEY = "force_non_distinct_multitouch";
public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
+ private static final String PREF_STATISTICS_LOGGING_KEY = "enable_logging";
+ private static final boolean SHOW_STATISTICS_LOGGING = false;
private boolean mServiceNeedsRestart = false;
private CheckBoxPreference mDebugMode;
+ private CheckBoxPreference mStatisticsLoggingPref;
@Override
public void onCreate(Bundle icicle) {
@@ -55,6 +58,13 @@ public final class DebugSettings extends PreferenceFragment
ResearchLogger.DEFAULT_USABILITY_STUDY_MODE));
checkbox.setSummary(R.string.settings_warning_researcher_mode);
}
+ final Preference statisticsLoggingPref = findPreference(PREF_STATISTICS_LOGGING_KEY);
+ if (statisticsLoggingPref instanceof CheckBoxPreference) {
+ mStatisticsLoggingPref = (CheckBoxPreference) statisticsLoggingPref;
+ if (!SHOW_STATISTICS_LOGGING) {
+ getPreferenceScreen().removePreference(statisticsLoggingPref);
+ }
+ }
mServiceNeedsRestart = false;
mDebugMode = (CheckBoxPreference) findPreference(DEBUG_MODE_KEY);
@@ -72,6 +82,14 @@ public final class DebugSettings extends PreferenceFragment
if (key.equals(DEBUG_MODE_KEY)) {
if (mDebugMode != null) {
mDebugMode.setChecked(prefs.getBoolean(DEBUG_MODE_KEY, false));
+ final boolean checked = mDebugMode.isChecked();
+ if (mStatisticsLoggingPref != null) {
+ if (checked) {
+ getPreferenceScreen().addPreference(mStatisticsLoggingPref);
+ } else {
+ getPreferenceScreen().removePreference(mStatisticsLoggingPref);
+ }
+ }
updateDebugMode();
mServiceNeedsRestart = true;
}
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 88d0c09dd..a218509f3 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -26,11 +26,6 @@ import java.util.ArrayList;
* strokes.
*/
public abstract class Dictionary {
- /**
- * The weight to give to a word if it's length is the same as the number of typed characters.
- */
- protected static final int FULL_WORD_SCORE_MULTIPLIER = 2;
-
public static final int NOT_A_PROBABILITY = -1;
public static final String TYPE_USER_TYPED = "user_typed";
@@ -59,12 +54,12 @@ public abstract class Dictionary {
// TODO: pass more context than just the previous word, to enable better suggestions (n-gram
// and more)
abstract public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
- final CharSequence prevWord, final ProximityInfo proximityInfo);
+ final String prevWord, final ProximityInfo proximityInfo);
// The default implementation of this method ignores sessionId.
// Subclasses that want to use sessionId need to override this method.
public ArrayList<SuggestedWordInfo> getSuggestionsWithSessionId(final WordComposer composer,
- final CharSequence prevWord, final ProximityInfo proximityInfo, int sessionId) {
+ final String prevWord, final ProximityInfo proximityInfo, final int sessionId) {
return getSuggestions(composer, prevWord, proximityInfo);
}
@@ -73,9 +68,9 @@ public abstract class Dictionary {
* @param word the word to search for. The search should be case-insensitive.
* @return true if the word exists, false otherwise
*/
- abstract public boolean isValidWord(CharSequence word);
+ abstract public boolean isValidWord(final String word);
- public int getFrequency(CharSequence word) {
+ public int getFrequency(final String word) {
return NOT_A_PROBABILITY;
}
@@ -87,7 +82,7 @@ public abstract class Dictionary {
* @param typedWord the word to compare with
* @return true if they are the same, false otherwise.
*/
- protected boolean same(final char[] word, final int length, final CharSequence typedWord) {
+ protected boolean same(final char[] word, final int length, final String typedWord) {
if (typedWord.length() != length) {
return false;
}
diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
index d3b120989..7f78ac8a2 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
@@ -56,7 +56,7 @@ public final class DictionaryCollection extends Dictionary {
@Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
- final CharSequence prevWord, final ProximityInfo proximityInfo) {
+ final String prevWord, final ProximityInfo proximityInfo) {
final CopyOnWriteArrayList<Dictionary> dictionaries = mDictionaries;
if (dictionaries.isEmpty()) return null;
// To avoid creating unnecessary objects, we get the list out of the first
@@ -74,14 +74,14 @@ public final class DictionaryCollection extends Dictionary {
}
@Override
- public boolean isValidWord(CharSequence word) {
+ public boolean isValidWord(final String word) {
for (int i = mDictionaries.size() - 1; i >= 0; --i)
if (mDictionaries.get(i).isValidWord(word)) return true;
return false;
}
@Override
- public int getFrequency(CharSequence word) {
+ public int getFrequency(final String word) {
int maxFreq = -1;
for (int i = mDictionaries.size() - 1; i >= 0; --i) {
final int tempFreq = mDictionaries.get(i).getFrequency(word);
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index b93c17f11..159867ade 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -198,7 +198,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
@Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
- final CharSequence prevWord, final ProximityInfo proximityInfo) {
+ final String prevWord, final ProximityInfo proximityInfo) {
asyncReloadDictionaryIfRequired();
if (mLocalDictionaryController.tryLock()) {
try {
@@ -213,12 +213,12 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
}
@Override
- public boolean isValidWord(final CharSequence word) {
+ public boolean isValidWord(final String word) {
asyncReloadDictionaryIfRequired();
return isValidWordInner(word);
}
- protected boolean isValidWordInner(final CharSequence word) {
+ protected boolean isValidWordInner(final String word) {
if (mLocalDictionaryController.tryLock()) {
try {
return isValidWordLocked(word);
@@ -229,17 +229,17 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
return false;
}
- protected boolean isValidWordLocked(final CharSequence word) {
+ protected boolean isValidWordLocked(final String word) {
if (mBinaryDictionary == null) return false;
return mBinaryDictionary.isValidWord(word);
}
- protected boolean isValidBigram(final CharSequence word1, final CharSequence word2) {
+ protected boolean isValidBigram(final String word1, final String word2) {
if (mBinaryDictionary == null) return false;
return mBinaryDictionary.isValidBigram(word1, word2);
}
- protected boolean isValidBigramInner(final CharSequence word1, final CharSequence word2) {
+ protected boolean isValidBigramInner(final String word1, final String word2) {
if (mLocalDictionaryController.tryLock()) {
try {
return isValidBigramLocked(word1, word2);
@@ -250,7 +250,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
return false;
}
- protected boolean isValidBigramLocked(final CharSequence word1, final CharSequence word2) {
+ protected boolean isValidBigramLocked(final String word1, final String word2) {
if (mBinaryDictionary == null) return false;
return mBinaryDictionary.isValidBigram(word1, word2);
}
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index 8cdc2a0af..fa0d5497b 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -19,7 +19,6 @@ package com.android.inputmethod.latin;
import android.content.Context;
import android.text.TextUtils;
-import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.UserHistoryForgettingCurveUtils.ForgettingCurveParams;
@@ -32,6 +31,10 @@ import java.util.LinkedList;
* be searched for suggestions and valid words.
*/
public class ExpandableDictionary extends Dictionary {
+ /**
+ * The weight to give to a word if it's length is the same as the number of typed characters.
+ */
+ private static final int FULL_WORD_SCORE_MULTIPLIER = 2;
// Bigram frequency is a fixed point number with 1 meaning 1.2 and 255 meaning 1.8.
protected static final int BIGRAM_MAX_FREQUENCY = 255;
@@ -69,7 +72,7 @@ public class ExpandableDictionary extends Dictionary {
mData = new Node[INCREMENT];
}
- void add(Node n) {
+ void add(final Node n) {
if (mLength + 1 > mData.length) {
Node[] tempData = new Node[mLength + INCREMENT];
if (mLength > 0) {
@@ -172,7 +175,7 @@ public class ExpandableDictionary extends Dictionary {
}
}
- public void setRequiresReload(boolean reload) {
+ public void setRequiresReload(final boolean reload) {
synchronized (mUpdatingLock) {
mRequiresReload = reload;
}
@@ -202,8 +205,8 @@ public class ExpandableDictionary extends Dictionary {
addWordRec(mRoots, word, 0, shortcutTarget, frequency, null);
}
- private void addWordRec(NodeArray children, final String word, final int depth,
- final String shortcutTarget, final int frequency, Node parentNode) {
+ private void addWordRec(final NodeArray children, final String word, final int depth,
+ final String shortcutTarget, final int frequency, final Node parentNode) {
final int wordLength = word.length();
if (wordLength <= depth) return;
final char c = word.charAt(depth);
@@ -248,7 +251,7 @@ public class ExpandableDictionary extends Dictionary {
@Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
- final CharSequence prevWord, final ProximityInfo proximityInfo) {
+ final String prevWord, final ProximityInfo proximityInfo) {
if (reloadDictionaryIfRequired()) return null;
if (composer.size() > 1) {
if (composer.size() >= BinaryDictionary.MAX_WORD_LENGTH) {
@@ -267,8 +270,7 @@ public class ExpandableDictionary extends Dictionary {
// This reloads the dictionary if required, and returns whether it's currently updating its
// contents or not.
- // @VisibleForTesting
- boolean reloadDictionaryIfRequired() {
+ private boolean reloadDictionaryIfRequired() {
synchronized (mUpdatingLock) {
// If we need to update, start off a background task
if (mRequiresReload) startDictionaryLoadingTaskLocked();
@@ -277,7 +279,7 @@ public class ExpandableDictionary extends Dictionary {
}
protected ArrayList<SuggestedWordInfo> getWordsInner(final WordComposer codes,
- final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) {
+ final String prevWordForBigrams, final ProximityInfo proximityInfo) {
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
mInputLength = codes.size();
if (mCodes.length < mInputLength) mCodes = new int[mInputLength][];
@@ -305,7 +307,7 @@ public class ExpandableDictionary extends Dictionary {
}
@Override
- public synchronized boolean isValidWord(CharSequence word) {
+ public synchronized boolean isValidWord(final String word) {
synchronized (mUpdatingLock) {
// If we need to update, start off a background task
if (mRequiresReload) startDictionaryLoadingTaskLocked();
@@ -320,7 +322,7 @@ public class ExpandableDictionary extends Dictionary {
return (node == null) ? false : !node.mShortcutOnly;
}
- protected boolean removeBigram(String word1, String word2) {
+ protected boolean removeBigram(final String word1, final String word2) {
// Refer to addOrSetBigram() about word1.toLowerCase()
final Node firstWord = searchWord(mRoots, word1.toLowerCase(), 0, null);
final Node secondWord = searchWord(mRoots, word2, 0, null);
@@ -345,13 +347,13 @@ public class ExpandableDictionary extends Dictionary {
/**
* Returns the word's frequency or -1 if not found
*/
- protected int getWordFrequency(CharSequence word) {
+ protected int getWordFrequency(final String word) {
// Case-sensitive search
final Node node = searchNode(mRoots, word, 0, word.length());
return (node == null) ? -1 : node.mFrequency;
}
- protected NextWord getBigramWord(String word1, String word2) {
+ protected NextWord getBigramWord(final String word1, final String word2) {
// Refer to addOrSetBigram() about word1.toLowerCase()
final Node firstWord = searchWord(mRoots, word1.toLowerCase(), 0, null);
final Node secondWord = searchWord(mRoots, word2, 0, null);
@@ -368,7 +370,8 @@ public class ExpandableDictionary extends Dictionary {
return null;
}
- private static int computeSkippedWordFinalFreq(int freq, int snr, int inputLength) {
+ private static int computeSkippedWordFinalFreq(final int freq, final int snr,
+ final int inputLength) {
// The computation itself makes sense for >= 2, but the == 2 case returns 0
// anyway so we may as well test against 3 instead and return the constant
if (inputLength >= 3) {
@@ -431,9 +434,9 @@ public class ExpandableDictionary extends Dictionary {
* @param suggestions the list in which to add suggestions
*/
// TODO: Share this routine with the native code for BinaryDictionary
- protected void getWordsRec(NodeArray roots, final WordComposer codes, final char[] word,
- final int depth, final boolean completion, int snr, int inputIndex, int skipPos,
- final ArrayList<SuggestedWordInfo> suggestions) {
+ protected void getWordsRec(final NodeArray roots, final WordComposer codes, final char[] word,
+ final int depth, final boolean completion, final int snr, final int inputIndex,
+ final int skipPos, final ArrayList<SuggestedWordInfo> suggestions) {
final int count = roots.mLength;
final int codeSize = mInputLength;
// Optimization: Prune out words that are too long compared to how much was typed.
@@ -472,8 +475,8 @@ public class ExpandableDictionary extends Dictionary {
getWordsRec(children, codes, word, depth + 1, true, snr, inputIndex,
skipPos, suggestions);
}
- } else if ((c == Keyboard.CODE_SINGLE_QUOTE
- && currentChars[0] != Keyboard.CODE_SINGLE_QUOTE) || depth == skipPos) {
+ } else if ((c == Constants.CODE_SINGLE_QUOTE
+ && currentChars[0] != Constants.CODE_SINGLE_QUOTE) || depth == skipPos) {
// Skip the ' and continue deeper
word[depth] = c;
if (children != null) {
@@ -524,11 +527,13 @@ public class ExpandableDictionary extends Dictionary {
}
}
- public int setBigramAndGetFrequency(String word1, String word2, int frequency) {
+ public int setBigramAndGetFrequency(final String word1, final String word2,
+ final int frequency) {
return setBigramAndGetFrequency(word1, word2, frequency, null /* unused */);
}
- public int setBigramAndGetFrequency(String word1, String word2, ForgettingCurveParams fcp) {
+ public int setBigramAndGetFrequency(final String word1, final String word2,
+ final ForgettingCurveParams fcp) {
return setBigramAndGetFrequency(word1, word2, 0 /* unused */, fcp);
}
@@ -540,8 +545,8 @@ public class ExpandableDictionary extends Dictionary {
* @param fcp an instance of ForgettingCurveParams to use for decay policy
* @return returns the final bigram frequency
*/
- private int setBigramAndGetFrequency(
- String word1, String word2, int frequency, ForgettingCurveParams fcp) {
+ private int setBigramAndGetFrequency(final String word1, final String word2,
+ final int frequency, final ForgettingCurveParams fcp) {
// We don't want results to be different according to case of the looked up left hand side
// word. We do want however to return the correct case for the right hand side.
// So we want to squash the case of the left hand side, and preserve that of the right
@@ -572,7 +577,8 @@ public class ExpandableDictionary extends Dictionary {
* Searches for the word and add the word if it does not exist.
* @return Returns the terminal node of the word we are searching for.
*/
- private Node searchWord(NodeArray children, String word, int depth, Node parentNode) {
+ private Node searchWord(final NodeArray children, final String word, final int depth,
+ final Node parentNode) {
final int wordLength = word.length();
final char c = word.charAt(depth);
// Does children have the current character?
@@ -602,36 +608,17 @@ public class ExpandableDictionary extends Dictionary {
return searchWord(childNode.mChildren, word, depth + 1, childNode);
}
- private void runBigramReverseLookUp(final CharSequence previousWord,
+ private void runBigramReverseLookUp(final String previousWord,
final ArrayList<SuggestedWordInfo> suggestions) {
// Search for the lowercase version of the word only, because that's where bigrams
// store their sons.
- Node prevWord = searchNode(mRoots, previousWord.toString().toLowerCase(), 0,
+ final Node prevWord = searchNode(mRoots, previousWord.toLowerCase(), 0,
previousWord.length());
if (prevWord != null && prevWord.mNGrams != null) {
reverseLookUp(prevWord.mNGrams, suggestions);
}
}
- /**
- * Used for testing purposes and in the spell checker
- * This function will wait for loading from database to be done
- */
- void waitForDictionaryLoading() {
- while (mUpdatingDictionary) {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- //
- }
- }
- }
-
- protected final void blockingReloadDictionaryIfRequired() {
- reloadDictionaryIfRequired();
- waitForDictionaryLoading();
- }
-
// Local to reverseLookUp, but do not allocate each time.
private final char[] mLookedUpString = new char[BinaryDictionary.MAX_WORD_LENGTH];
@@ -641,7 +628,7 @@ public class ExpandableDictionary extends Dictionary {
* @param terminalNodes list of terminal nodes we want to add
* @param suggestions the suggestion collection to add the word to
*/
- private void reverseLookUp(LinkedList<NextWord> terminalNodes,
+ private void reverseLookUp(final LinkedList<NextWord> terminalNodes,
final ArrayList<SuggestedWordInfo> suggestions) {
Node node;
int freq;
@@ -714,7 +701,7 @@ public class ExpandableDictionary extends Dictionary {
}
}
- private static char toLowerCase(char c) {
+ private static char toLowerCase(final char c) {
char baseChar = c;
if (c < BASE_CHARS.length) {
baseChar = BASE_CHARS[c];
diff --git a/java/src/com/android/inputmethod/latin/ImfUtils.java b/java/src/com/android/inputmethod/latin/ImfUtils.java
deleted file mode 100644
index 2674e4575..000000000
--- a/java/src/com/android/inputmethod/latin/ImfUtils.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.latin;
-
-import static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE;
-
-import android.content.Context;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.InputMethodSubtype;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Utility class for Input Method Framework
- */
-public final class ImfUtils {
- private ImfUtils() {
- // This utility class is not publicly instantiable.
- }
-
- private static InputMethodManager sInputMethodManager;
-
- public static InputMethodManager getInputMethodManager(Context context) {
- if (sInputMethodManager == null) {
- sInputMethodManager = (InputMethodManager)context.getSystemService(
- Context.INPUT_METHOD_SERVICE);
- }
- return sInputMethodManager;
- }
-
- private static InputMethodInfo sInputMethodInfoOfThisIme;
-
- public static InputMethodInfo getInputMethodInfoOfThisIme(Context context) {
- if (sInputMethodInfoOfThisIme == null) {
- final InputMethodManager imm = getInputMethodManager(context);
- final String packageName = context.getPackageName();
- for (final InputMethodInfo imi : imm.getInputMethodList()) {
- if (imi.getPackageName().equals(packageName))
- return imi;
- }
- throw new RuntimeException("Can not find input method id for " + packageName);
- }
- return sInputMethodInfoOfThisIme;
- }
-
- public static String getInputMethodIdOfThisIme(Context context) {
- return getInputMethodInfoOfThisIme(context).getId();
- }
-
- public static boolean checkIfSubtypeBelongsToThisImeAndEnabled(Context context,
- InputMethodSubtype ims) {
- final InputMethodInfo myImi = getInputMethodInfoOfThisIme(context);
- final InputMethodManager imm = getInputMethodManager(context);
- // TODO: Cache all subtypes of this IME for optimization
- final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(myImi, true);
- for (final InputMethodSubtype subtype : subtypes) {
- if (subtype.equals(ims)) {
- return true;
- }
- }
- return false;
- }
-
- public static boolean checkIfSubtypeBelongsToThisIme(Context context,
- InputMethodSubtype ims) {
- final InputMethodInfo myImi = getInputMethodInfoOfThisIme(context);
- final int count = myImi.getSubtypeCount();
- for (int i = 0; i < count; i++) {
- final InputMethodSubtype subtype = myImi.getSubtypeAt(i);
- if (subtype.equals(ims)) {
- return true;
- }
- }
- return false;
- }
-
- public static InputMethodSubtype getCurrentInputMethodSubtype(Context context,
- InputMethodSubtype defaultSubtype) {
- final InputMethodManager imm = getInputMethodManager(context);
- final InputMethodSubtype currentSubtype = imm.getCurrentInputMethodSubtype();
- return (currentSubtype != null) ? currentSubtype : defaultSubtype;
- }
-
- public static boolean hasMultipleEnabledIMEsOrSubtypes(Context context,
- final boolean shouldIncludeAuxiliarySubtypes) {
- final InputMethodManager imm = getInputMethodManager(context);
- final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList();
- return hasMultipleEnabledSubtypes(context, shouldIncludeAuxiliarySubtypes, enabledImis);
- }
-
- public static boolean hasMultipleEnabledSubtypesInThisIme(Context context,
- final boolean shouldIncludeAuxiliarySubtypes) {
- final InputMethodInfo myImi = getInputMethodInfoOfThisIme(context);
- final List<InputMethodInfo> imiList = Collections.singletonList(myImi);
- return hasMultipleEnabledSubtypes(context, shouldIncludeAuxiliarySubtypes, imiList);
- }
-
- private static boolean hasMultipleEnabledSubtypes(Context context,
- final boolean shouldIncludeAuxiliarySubtypes, List<InputMethodInfo> imiList) {
- final InputMethodManager imm = getInputMethodManager(context);
-
- // Number of the filtered IMEs
- int filteredImisCount = 0;
-
- for (InputMethodInfo imi : imiList) {
- // We can return true immediately after we find two or more filtered IMEs.
- if (filteredImisCount > 1) return true;
- final List<InputMethodSubtype> subtypes =
- imm.getEnabledInputMethodSubtypeList(imi, true);
- // IMEs that have no subtypes should be counted.
- if (subtypes.isEmpty()) {
- ++filteredImisCount;
- continue;
- }
-
- int auxCount = 0;
- for (InputMethodSubtype subtype : subtypes) {
- if (subtype.isAuxiliary()) {
- ++auxCount;
- }
- }
- final int nonAuxCount = subtypes.size() - auxCount;
-
- // IMEs that have one or more non-auxiliary subtypes should be counted.
- // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
- // subtypes should be counted as well.
- if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
- ++filteredImisCount;
- continue;
- }
- }
-
- if (filteredImisCount > 1) {
- return true;
- }
- final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(null, true);
- int keyboardCount = 0;
- // imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's
- // both explicitly and implicitly enabled input method subtype.
- // (The current IME should be LatinIME.)
- for (InputMethodSubtype subtype : subtypes) {
- if (KEYBOARD_MODE.equals(subtype.getMode())) {
- ++keyboardCount;
- }
- }
- return keyboardCount > 1;
- }
-
- public static InputMethodSubtype findSubtypeByLocaleAndKeyboardLayoutSet(
- Context context, String localeString, String keyboardLayoutSetName) {
- final InputMethodInfo imi = getInputMethodInfoOfThisIme(context);
- final int count = imi.getSubtypeCount();
- for (int i = 0; i < count; i++) {
- final InputMethodSubtype subtype = imi.getSubtypeAt(i);
- final String layoutName = SubtypeLocale.getKeyboardLayoutSetName(subtype);
- if (localeString.equals(subtype.getLocale())
- && keyboardLayoutSetName.equals(layoutName)) {
- return subtype;
- }
- }
- return null;
- }
-
- public static void setAdditionalInputMethodSubtypes(Context context,
- InputMethodSubtype[] subtypes) {
- final InputMethodManager imm = getInputMethodManager(context);
- final String imiId = getInputMethodIdOfThisIme(context);
- imm.setAdditionalInputMethodSubtypes(imiId, subtypes);
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java
index 422fc72d3..1c5bff383 100644
--- a/java/src/com/android/inputmethod/latin/InputAttributes.java
+++ b/java/src/com/android/inputmethod/latin/InputAttributes.java
@@ -117,36 +117,56 @@ public final class InputAttributes {
if (inputClass == InputType.TYPE_CLASS_DATETIME)
Log.i(TAG, " TYPE_CLASS_DATETIME");
Log.i(TAG, "Variation:");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS))
- Log.i(TAG, " TYPE_TEXT_VARIATION_EMAIL_ADDRESS");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT))
- Log.i(TAG, " TYPE_TEXT_VARIATION_EMAIL_SUBJECT");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_FILTER))
- Log.i(TAG, " TYPE_TEXT_VARIATION_FILTER");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE))
- Log.i(TAG, " TYPE_TEXT_VARIATION_LONG_MESSAGE");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_NORMAL))
- Log.i(TAG, " TYPE_TEXT_VARIATION_NORMAL");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_PASSWORD))
- Log.i(TAG, " TYPE_TEXT_VARIATION_PASSWORD");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_PERSON_NAME))
- Log.i(TAG, " TYPE_TEXT_VARIATION_PERSON_NAME");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_PHONETIC))
- Log.i(TAG, " TYPE_TEXT_VARIATION_PHONETIC");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS))
- Log.i(TAG, " TYPE_TEXT_VARIATION_POSTAL_ADDRESS");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE))
- Log.i(TAG, " TYPE_TEXT_VARIATION_SHORT_MESSAGE");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_URI))
- Log.i(TAG, " TYPE_TEXT_VARIATION_URI");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD))
- Log.i(TAG, " TYPE_TEXT_VARIATION_VISIBLE_PASSWORD");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT))
- Log.i(TAG, " TYPE_TEXT_VARIATION_WEB_EDIT_TEXT");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS))
- Log.i(TAG, " TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS");
- if (0 != (inputType & InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD))
- Log.i(TAG, " TYPE_TEXT_VARIATION_WEB_PASSWORD");
+ switch (InputType.TYPE_MASK_VARIATION & inputType) {
+ case InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_EMAIL_ADDRESS");
+ break;
+ case InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_EMAIL_SUBJECT");
+ break;
+ case InputType.TYPE_TEXT_VARIATION_FILTER:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_FILTER");
+ break;
+ case InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_LONG_MESSAGE");
+ break;
+ case InputType.TYPE_TEXT_VARIATION_NORMAL:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_NORMAL");
+ break;
+ case InputType.TYPE_TEXT_VARIATION_PASSWORD:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_PASSWORD");
+ break;
+ case InputType.TYPE_TEXT_VARIATION_PERSON_NAME:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_PERSON_NAME");
+ break;
+ case InputType.TYPE_TEXT_VARIATION_PHONETIC:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_PHONETIC");
+ break;
+ case InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_POSTAL_ADDRESS");
+ break;
+ case InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_SHORT_MESSAGE");
+ break;
+ case InputType.TYPE_TEXT_VARIATION_URI:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_URI");
+ break;
+ case InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_VISIBLE_PASSWORD");
+ break;
+ case InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_WEB_EDIT_TEXT");
+ break;
+ case InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS");
+ break;
+ case InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD:
+ Log.i(TAG, " TYPE_TEXT_VARIATION_WEB_PASSWORD");
+ break;
+ default:
+ Log.i(TAG, " Unknown variation");
+ break;
+ }
Log.i(TAG, "Flags:");
if (0 != (inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS))
Log.i(TAG, " TYPE_TEXT_FLAG_NO_SUGGESTIONS");
diff --git a/java/src/com/android/inputmethod/latin/InputPointers.java b/java/src/com/android/inputmethod/latin/InputPointers.java
index 6b48aabb3..7dffd96dd 100644
--- a/java/src/com/android/inputmethod/latin/InputPointers.java
+++ b/java/src/com/android/inputmethod/latin/InputPointers.java
@@ -16,6 +16,8 @@
package com.android.inputmethod.latin;
+import com.android.inputmethod.annotations.UsedForTesting;
+
// TODO: This class is not thread-safe.
public final class InputPointers {
private final int mDefaultCapacity;
@@ -39,7 +41,8 @@ public final class InputPointers {
mTimes.add(index, time);
}
- public void addPointer(int x, int y, int pointerId, int time) {
+ @UsedForTesting
+ void addPointer(int x, int y, int pointerId, int time) {
mXCoordinates.add(x);
mYCoordinates.add(y);
mPointerIds.add(pointerId);
@@ -66,7 +69,8 @@ public final class InputPointers {
* @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) {
+ @UsedForTesting
+ void append(InputPointers src, int startPos, int length) {
if (length == 0) {
return;
}
diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java
index 94cdc9b85..44ef01204 100644
--- a/java/src/com/android/inputmethod/latin/LastComposedWord.java
+++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java
@@ -44,7 +44,7 @@ public final class LastComposedWord {
public final String mTypedWord;
public final String mCommittedWord;
public final String mSeparatorString;
- public final CharSequence mPrevWord;
+ public final String mPrevWord;
public final InputPointers mInputPointers = new InputPointers(BinaryDictionary.MAX_WORD_LENGTH);
private boolean mActive;
@@ -56,7 +56,7 @@ public final class LastComposedWord {
// immutable. Do not fiddle with their contents after you passed them to this constructor.
public LastComposedWord(final int[] primaryKeyCodes, final InputPointers inputPointers,
final String typedWord, final String committedWord,
- final String separatorString, final CharSequence prevWord) {
+ final String separatorString, final String prevWord) {
mPrimaryKeyCodes = primaryKeyCodes;
if (inputPointers != null) {
mInputPointers.copy(inputPointers);
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index e2a76a456..6a198000a 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -60,8 +60,8 @@ import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.compat.CompatUtils;
-import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
import com.android.inputmethod.compat.InputMethodServiceCompatUtils;
import com.android.inputmethod.compat.SuggestionSpanUtils;
import com.android.inputmethod.keyboard.KeyDetector;
@@ -132,14 +132,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private View mKeyPreviewBackingView;
private View mSuggestionsContainer;
private SuggestionStripView mSuggestionStripView;
- /* package for tests */ Suggest mSuggest;
+ @UsedForTesting Suggest mSuggest;
private CompletionInfo[] mApplicationSpecifiedCompletions;
private ApplicationInfo mTargetApplicationInfo;
- private InputMethodManagerCompatWrapper mImm;
+ private RichInputMethodManager mRichImm;
private Resources mResources;
private SharedPreferences mPrefs;
- /* package for tests */ final KeyboardSwitcher mKeyboardSwitcher;
+ @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher;
private final SubtypeSwitcher mSubtypeSwitcher;
private final SubtypeState mSubtypeState = new SubtypeState();
@@ -165,17 +165,17 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private int mDeleteCount;
private long mLastKeyTime;
- private AudioAndHapticFeedbackManager mFeedbackManager;
-
// Member variables for remembering the current device orientation.
private int mDisplayOrientation;
// Object for reacting to adding/removing a dictionary pack.
+ // TODO: The experimental version is not supported by the Dictionary Pack Service yet.
private BroadcastReceiver mDictionaryPackInstallReceiver =
- new DictionaryPackInstallBroadcastReceiver(this);
+ ProductionFlag.IS_EXPERIMENTAL
+ ? null : new DictionaryPackInstallBroadcastReceiver(this);
// Keeps track of most recently inserted text (multi-character key) for reverting
- private CharSequence mEnteredText;
+ private String mEnteredText;
private boolean mIsAutoCorrectionIndicatorOn;
@@ -195,8 +195,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private int mDelayUpdateSuggestions;
private int mDelayUpdateShiftState;
- private long mDoubleSpacesTurnIntoPeriodTimeout;
- private long mDoubleSpaceTimerStart;
+ private long mDoubleSpacePeriodTimeout;
+ private long mDoubleSpacePeriodTimerStart;
public UIHandler(final LatinIME outerInstance) {
super(outerInstance);
@@ -208,8 +208,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
res.getInteger(R.integer.config_delay_update_suggestions);
mDelayUpdateShiftState =
res.getInteger(R.integer.config_delay_update_shift_state);
- mDoubleSpacesTurnIntoPeriodTimeout = res.getInteger(
- R.integer.config_double_spaces_turn_into_period_timeout);
+ mDoubleSpacePeriodTimeout =
+ res.getInteger(R.integer.config_double_space_period_timeout);
}
@Override
@@ -260,17 +260,17 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
.sendToTarget();
}
- public void startDoubleSpacesTimer() {
- mDoubleSpaceTimerStart = SystemClock.uptimeMillis();
+ public void startDoubleSpacePeriodTimer() {
+ mDoubleSpacePeriodTimerStart = SystemClock.uptimeMillis();
}
- public void cancelDoubleSpacesTimer() {
- mDoubleSpaceTimerStart = 0;
+ public void cancelDoubleSpacePeriodTimer() {
+ mDoubleSpacePeriodTimerStart = 0;
}
- public boolean isAcceptingDoubleSpaces() {
- return SystemClock.uptimeMillis() - mDoubleSpaceTimerStart
- < mDoubleSpacesTurnIntoPeriodTimeout;
+ public boolean isAcceptingDoubleSpacePeriod() {
+ return SystemClock.uptimeMillis() - mDoubleSpacePeriodTimerStart
+ < mDoubleSpacePeriodTimeout;
}
// Working variables for the following methods.
@@ -375,9 +375,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mCurrentSubtypeUsed = true;
}
- public void switchSubtype(final IBinder token, final InputMethodManagerCompatWrapper imm,
- final Context context) {
- final InputMethodSubtype currentSubtype = imm.getCurrentInputMethodSubtype();
+ public void switchSubtype(final IBinder token, final RichInputMethodManager richImm) {
+ final InputMethodSubtype currentSubtype = richImm.getInputMethodManager()
+ .getCurrentInputMethodSubtype();
final InputMethodSubtype lastActiveSubtype = mLastActiveSubtype;
final boolean currentSubtypeUsed = mCurrentSubtypeUsed;
if (currentSubtypeUsed) {
@@ -385,13 +385,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mCurrentSubtypeUsed = false;
}
if (currentSubtypeUsed
- && ImfUtils.checkIfSubtypeBelongsToThisImeAndEnabled(context, lastActiveSubtype)
+ && richImm.checkIfSubtypeBelongsToThisImeAndEnabled(lastActiveSubtype)
&& !currentSubtype.equals(lastActiveSubtype)) {
- final String id = ImfUtils.getInputMethodIdOfThisIme(context);
- imm.setInputMethodAndSubtype(token, id, lastActiveSubtype);
+ richImm.setInputMethodAndSubtype(token, lastActiveSubtype);
return;
}
- imm.switchToNextInputMethod(token, true /* onlyCurrentIme */);
+ richImm.switchToNextInputMethod(token, true /* onlyCurrentIme */);
}
}
@@ -406,33 +405,28 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
@Override
public void onCreate() {
- final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- mPrefs = prefs;
- LatinImeLogger.init(this, prefs);
+ mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ mResources = getResources();
+
+ LatinImeLogger.init(this, mPrefs);
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.getInstance().init(this, prefs);
+ ResearchLogger.getInstance().init(this, mPrefs);
}
- InputMethodManagerCompatWrapper.init(this);
+ RichInputMethodManager.init(this, mPrefs);
+ mRichImm = RichInputMethodManager.getInstance();
SubtypeSwitcher.init(this);
- KeyboardSwitcher.init(this, prefs);
+ KeyboardSwitcher.init(this, mPrefs);
AccessibilityUtils.init(this);
super.onCreate();
- mImm = InputMethodManagerCompatWrapper.getInstance();
mHandler.onCreate();
DEBUG = LatinImeLogger.sDBG;
- final Resources res = getResources();
- mResources = res;
-
loadSettings();
-
- ImfUtils.setAdditionalInputMethodSubtypes(this, mCurrentSettings.getAdditionalSubtypes());
-
initSuggest();
- mDisplayOrientation = res.getConfiguration().orientation;
+ mDisplayOrientation = mResources.getConfiguration().orientation;
// Register to receive ringer mode change and network state change.
// Also receive installation and removal of a dictionary pack.
@@ -441,20 +435,23 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
registerReceiver(mReceiver, filter);
- final IntentFilter packageFilter = new IntentFilter();
- packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- packageFilter.addDataScheme(SCHEME_PACKAGE);
- registerReceiver(mDictionaryPackInstallReceiver, packageFilter);
+ // TODO: The experimental version is not supported by the Dictionary Pack Service yet.
+ if (!ProductionFlag.IS_EXPERIMENTAL) {
+ final IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageFilter.addDataScheme(SCHEME_PACKAGE);
+ registerReceiver(mDictionaryPackInstallReceiver, packageFilter);
- final IntentFilter newDictFilter = new IntentFilter();
- newDictFilter.addAction(
- DictionaryPackInstallBroadcastReceiver.NEW_DICTIONARY_INTENT_ACTION);
- registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
+ final IntentFilter newDictFilter = new IntentFilter();
+ newDictFilter.addAction(
+ DictionaryPackInstallBroadcastReceiver.NEW_DICTIONARY_INTENT_ACTION);
+ registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
+ }
}
// Has to be package-visible for unit tests
- /* package for test */
+ @UsedForTesting
void loadSettings() {
// Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged()
// is not guaranteed. It may even be called at the same time on a different thread.
@@ -468,7 +465,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
};
mCurrentSettings = job.runInLocale(mResources, mSubtypeSwitcher.getCurrentSubtypeLocale());
- mFeedbackManager = new AudioAndHapticFeedbackManager(this, mCurrentSettings);
resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
}
@@ -571,7 +567,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mSuggest = null;
}
unregisterReceiver(mReceiver);
- unregisterReceiver(mDictionaryPackInstallReceiver);
+ // TODO: The experimental version is not supported by the Dictionary Pack Service yet.
+ if (!ProductionFlag.IS_EXPERIMENTAL) {
+ unregisterReceiver(mDictionaryPackInstallReceiver);
+ }
LatinImeLogger.commit();
LatinImeLogger.onDestroy();
super.onDestroy();
@@ -580,7 +579,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
@Override
public void onConfigurationChanged(final Configuration conf) {
// System locale has been changed. Needs to reload keyboard.
- if (mSubtypeSwitcher.onConfigurationChanged(conf, this)) {
+ if (mSubtypeSwitcher.onConfigurationChanged(conf)) {
loadKeyboard();
}
// If orientation changed while predicting, commit the change
@@ -720,8 +719,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
.updateParametersOnStartInputViewAndReturnIfCurrentSubtypeEnabled();
if (!currentSubtypeEnabled) {
// Current subtype is disabled. Needs to update subtype and keyboard.
- final InputMethodSubtype newSubtype = ImfUtils.getCurrentInputMethodSubtype(
- this, mSubtypeSwitcher.getNoLanguageSubtype());
+ final InputMethodSubtype newSubtype = mRichImm.getCurrentInputMethodSubtype(
+ mSubtypeSwitcher.getNoLanguageSubtype());
mSubtypeSwitcher.updateSubtype(newSubtype);
loadKeyboard();
}
@@ -773,7 +772,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mLastSelectionEnd = editorInfo.initialSelEnd;
mHandler.cancelUpdateSuggestionStrip();
- mHandler.cancelDoubleSpacesTimer();
+ mHandler.cancelDoubleSpacePeriodTimer();
mainKeyboardView.setMainDictionaryAvailability(mIsMainDictionaryAvailable);
mainKeyboardView.setKeyPreviewPopupEnabled(mCurrentSettings.mKeyPreviewPopupOn,
@@ -840,6 +839,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
// Remove pending messages related to update suggestions
mHandler.cancelUpdateSuggestionStrip();
+ resetComposingState(true /* alsoResetLastComposedWord */);
}
@Override
@@ -1080,12 +1080,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
final int suggestionsHeight = (mSuggestionsContainer.getVisibility() == View.GONE) ? 0
: mSuggestionsContainer.getHeight();
final int extraHeight = extractHeight + backingHeight + suggestionsHeight;
- int touchY = extraHeight;
+ int visibleTopY = extraHeight;
// Need to set touchable region only if input view is being shown
if (mainKeyboardView.isShown()) {
if (mSuggestionsContainer.getVisibility() == View.VISIBLE) {
- touchY -= suggestionsHeight;
+ visibleTopY -= suggestionsHeight;
}
+ final int touchY = mainKeyboardView.isShowingMoreKeysPanel() ? 0 : visibleTopY;
final int touchWidth = mainKeyboardView.getWidth();
final int touchHeight = mainKeyboardView.getHeight() + extraHeight
// Extend touchable region below the keyboard.
@@ -1093,15 +1094,15 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION;
outInsets.touchableRegion.set(0, touchY, touchWidth, touchHeight);
}
- outInsets.contentTopInsets = touchY;
- outInsets.visibleTopInsets = touchY;
+ outInsets.contentTopInsets = visibleTopY;
+ outInsets.visibleTopInsets = visibleTopY;
}
@Override
public boolean onEvaluateFullscreenMode() {
// Reread resource value here, because this method is called by framework anytime as needed.
final boolean isFullscreenModeAllowed =
- mCurrentSettings.isFullscreenModeAllowed(getResources());
+ SettingsValues.isFullscreenModeAllowed(getResources());
if (super.onEvaluateFullscreenMode() && isFullscreenModeAllowed) {
// TODO: Remove this hack. Actually we should not really assume NO_EXTRACT_UI
// implies NO_FULLSCREEN. However, the framework mistakenly does. i.e. NO_EXTRACT_UI
@@ -1144,7 +1145,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private void commitTyped(final String separatorString) {
if (!mWordComposer.isComposingWord()) return;
- final CharSequence typedWord = mWordComposer.getTypedWord();
+ final String typedWord = mWordComposer.getTypedWord();
if (typedWord.length() > 0) {
commitChosenWord(typedWord, LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD,
separatorString);
@@ -1181,7 +1182,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
CharSequence lastTwo = mConnection.getTextBeforeCursor(2, 0);
// It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called.
if (lastTwo != null && lastTwo.length() == 2
- && lastTwo.charAt(0) == Keyboard.CODE_SPACE) {
+ && lastTwo.charAt(0) == Constants.CODE_SPACE) {
mConnection.deleteSurroundingText(2, 0);
mConnection.commitText(lastTwo.charAt(1) + " ", 1);
if (ProductionFlag.IS_EXPERIMENTAL) {
@@ -1191,15 +1192,16 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
}
- private boolean maybeDoubleSpace() {
+ private boolean maybeDoubleSpacePeriod() {
if (!mCurrentSettings.mCorrectionEnabled) return false;
- if (!mHandler.isAcceptingDoubleSpaces()) return false;
+ if (!mCurrentSettings.mUseDoubleSpacePeriod) return false;
+ if (!mHandler.isAcceptingDoubleSpacePeriod()) return false;
final CharSequence lastThree = mConnection.getTextBeforeCursor(3, 0);
if (lastThree != null && lastThree.length() == 3
- && canBeFollowedByPeriod(lastThree.charAt(0))
- && lastThree.charAt(1) == Keyboard.CODE_SPACE
- && lastThree.charAt(2) == Keyboard.CODE_SPACE) {
- mHandler.cancelDoubleSpacesTimer();
+ && canBeFollowedByDoubleSpacePeriod(lastThree.charAt(0))
+ && lastThree.charAt(1) == Constants.CODE_SPACE
+ && lastThree.charAt(2) == Constants.CODE_SPACE) {
+ mHandler.cancelDoubleSpacePeriodTimer();
mConnection.deleteSurroundingText(2, 0);
mConnection.commitText(". ", 1);
mKeyboardSwitcher.updateShiftState();
@@ -1208,16 +1210,16 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
return false;
}
- private static boolean canBeFollowedByPeriod(final int codePoint) {
+ private static boolean canBeFollowedByDoubleSpacePeriod(final int codePoint) {
// TODO: Check again whether there really ain't a better way to check this.
// TODO: This should probably be language-dependant...
return Character.isLetterOrDigit(codePoint)
- || codePoint == Keyboard.CODE_SINGLE_QUOTE
- || codePoint == Keyboard.CODE_DOUBLE_QUOTE
- || codePoint == Keyboard.CODE_CLOSING_PARENTHESIS
- || codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET
- || codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET
- || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET;
+ || codePoint == Constants.CODE_SINGLE_QUOTE
+ || codePoint == Constants.CODE_DOUBLE_QUOTE
+ || codePoint == Constants.CODE_CLOSING_PARENTHESIS
+ || codePoint == Constants.CODE_CLOSING_SQUARE_BRACKET
+ || codePoint == Constants.CODE_CLOSING_CURLY_BRACKET
+ || codePoint == Constants.CODE_CLOSING_ANGLE_BRACKET;
}
// Callback for the {@link SuggestionStripView}, to call when the "add to dictionary" hint is
@@ -1267,9 +1269,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
if (isShowingOptionDialog()) return false;
switch (requestCode) {
case CODE_SHOW_INPUT_METHOD_PICKER:
- if (ImfUtils.hasMultipleEnabledIMEsOrSubtypes(
- this, true /* include aux subtypes */)) {
- mImm.showInputMethodPicker();
+ if (mRichImm.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
+ mRichImm.getInputMethodManager().showInputMethodPicker();
return true;
}
return false;
@@ -1293,10 +1294,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private void handleLanguageSwitchKey() {
final IBinder token = getWindow().getWindow().getAttributes().token;
if (mCurrentSettings.mIncludesOtherImesInLanguageSwitchList) {
- mImm.switchToNextInputMethod(token, false /* onlyCurrentIme */);
+ mRichImm.switchToNextInputMethod(token, false /* onlyCurrentIme */);
return;
}
- mSubtypeState.switchSubtype(token, mImm, this);
+ mSubtypeState.switchSubtype(token, mRichImm);
}
private void sendDownUpKeyEventForBackwardCompatibility(final int code) {
@@ -1322,7 +1323,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// 16 is android.os.Build.VERSION_CODES.JELLY_BEAN but we can't write it because
// we want to be able to compile against the Ice Cream Sandwich SDK.
- if (Keyboard.CODE_ENTER == code && mTargetApplicationInfo != null
+ if (Constants.CODE_ENTER == code && mTargetApplicationInfo != null
&& mTargetApplicationInfo.targetSdkVersion < 16) {
// Backward compatibility mode. Before Jelly bean, the keyboard would simulate
// a hardware keyboard event on pressing enter or delete. This is bad for many
@@ -1339,7 +1340,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
@Override
public void onCodeInput(final int primaryCode, final int x, final int y) {
final long when = SystemClock.uptimeMillis();
- if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
+ if (primaryCode != Constants.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
mDeleteCount = 0;
}
mLastKeyTime = when;
@@ -1353,43 +1354,43 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
final int spaceState = mSpaceState;
if (!mWordComposer.isComposingWord()) mIsAutoCorrectionIndicatorOn = false;
- // TODO: Consolidate the double space timer, mLastKeyTime, and the space state.
- if (primaryCode != Keyboard.CODE_SPACE) {
- mHandler.cancelDoubleSpacesTimer();
+ // TODO: Consolidate the double-space period timer, mLastKeyTime, and the space state.
+ if (primaryCode != Constants.CODE_SPACE) {
+ mHandler.cancelDoubleSpacePeriodTimer();
}
boolean didAutoCorrect = false;
switch (primaryCode) {
- case Keyboard.CODE_DELETE:
+ case Constants.CODE_DELETE:
mSpaceState = SPACE_STATE_NONE;
handleBackspace(spaceState);
mDeleteCount++;
mExpectingUpdateSelection = true;
LatinImeLogger.logOnDelete(x, y);
break;
- case Keyboard.CODE_SHIFT:
- case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
+ case Constants.CODE_SHIFT:
+ case Constants.CODE_SWITCH_ALPHA_SYMBOL:
// Shift and symbol key is handled in onPressKey() and onReleaseKey().
break;
- case Keyboard.CODE_SETTINGS:
+ case Constants.CODE_SETTINGS:
onSettingsKeyPressed();
break;
- case Keyboard.CODE_SHORTCUT:
+ case Constants.CODE_SHORTCUT:
mSubtypeSwitcher.switchToShortcutIME(this);
break;
- case Keyboard.CODE_ACTION_ENTER:
+ case Constants.CODE_ACTION_ENTER:
performEditorAction(getActionId(switcher.getKeyboard()));
break;
- case Keyboard.CODE_ACTION_NEXT:
+ case Constants.CODE_ACTION_NEXT:
performEditorAction(EditorInfo.IME_ACTION_NEXT);
break;
- case Keyboard.CODE_ACTION_PREVIOUS:
+ case Constants.CODE_ACTION_PREVIOUS:
performEditorAction(EditorInfo.IME_ACTION_PREVIOUS);
break;
- case Keyboard.CODE_LANGUAGE_SWITCH:
+ case Constants.CODE_LANGUAGE_SWITCH:
handleLanguageSwitchKey();
break;
- case Keyboard.CODE_RESEARCH:
+ case Constants.CODE_RESEARCH:
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.getInstance().onResearchKeySelected(this);
}
@@ -1424,10 +1425,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
switcher.onCodeInput(primaryCode);
// Reset after any single keystroke, except shift and symbol-shift
- if (!didAutoCorrect && primaryCode != Keyboard.CODE_SHIFT
- && primaryCode != Keyboard.CODE_SWITCH_ALPHA_SYMBOL)
+ if (!didAutoCorrect && primaryCode != Constants.CODE_SHIFT
+ && primaryCode != Constants.CODE_SWITCH_ALPHA_SYMBOL)
mLastComposedWord.deactivate();
- if (Keyboard.CODE_DELETE != primaryCode) {
+ if (Constants.CODE_DELETE != primaryCode) {
mEnteredText = null;
}
mConnection.endBatchEdit();
@@ -1438,7 +1439,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// Called from PointerTracker through the KeyboardActionListener interface
@Override
- public void onTextInput(final CharSequence rawText) {
+ public void onTextInput(final String rawText) {
mConnection.beginBatchEdit();
if (mWordComposer.isComposingWord()) {
commitCurrentAutoCorrection(rawText.toString());
@@ -1446,7 +1447,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
resetComposingState(true /* alsoResetLastComposedWord */);
}
mHandler.postUpdateSuggestionStrip();
- final CharSequence text = specificTldProcessingOnTextInput(rawText);
+ final String text = specificTldProcessingOnTextInput(rawText);
if (SPACE_STATE_PHANTOM == mSpaceState) {
promotePhantomSpace();
}
@@ -1455,7 +1456,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// Space state must be updated before calling updateShiftState
mSpaceState = SPACE_STATE_NONE;
mKeyboardSwitcher.updateShiftState();
- mKeyboardSwitcher.onCodeInput(Keyboard.CODE_OUTPUT_TEXT);
+ mKeyboardSwitcher.onCodeInput(Constants.CODE_OUTPUT_TEXT);
mEnteredText = text;
}
@@ -1503,7 +1504,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private static final class BatchInputUpdater implements Handler.Callback {
private final Handler mHandler;
private LatinIME mLatinIme;
- private boolean mInBatchInput; // synchornized using "this".
+ private boolean mInBatchInput; // synchronized using "this".
private BatchInputUpdater() {
final HandlerThread handlerThread = new HandlerThread(
@@ -1535,6 +1536,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// Run in the UI thread.
public synchronized void onStartBatchInput() {
+ mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
mInBatchInput = true;
}
@@ -1542,7 +1544,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private synchronized void updateBatchInput(final InputPointers batchPointers,
final LatinIME latinIme) {
if (!mInBatchInput) {
- // Batch input has ended while the message was being delivered.
+ // Batch input has ended or canceled while the message was being delivered.
return;
}
final SuggestedWords suggestedWords = getSuggestedWordsGestureLocked(
@@ -1562,6 +1564,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
.sendToTarget();
}
+ public synchronized void onCancelBatchInput(final LatinIME latinIme) {
+ mInBatchInput = false;
+ latinIme.mHandler.showGesturePreviewAndSuggestionStrip(
+ SuggestedWords.EMPTY, true /* dismissGestureFloatingPreviewText */);
+ }
+
// Run in the UI thread.
public synchronized SuggestedWords onEndBatchInput(final InputPointers batchPointers,
final LatinIME latinIme) {
@@ -1584,13 +1592,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private void showGesturePreviewAndSuggestionStrip(final SuggestedWords suggestedWords,
final boolean dismissGestureFloatingPreviewText) {
- final String batchInputText = (suggestedWords.size() > 0)
- ? suggestedWords.getWord(0) : null;
- final KeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
- mainKeyboardView.showGestureFloatingPreviewText(batchInputText);
showSuggestionStrip(suggestedWords, null);
+ final KeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
if (dismissGestureFloatingPreviewText) {
mainKeyboardView.dismissGestureFloatingPreviewText();
+ } else {
+ final String batchInputText = suggestedWords.isEmpty()
+ ? null : suggestedWords.getWord(0);
+ mainKeyboardView.showGestureFloatingPreviewText(batchInputText);
}
}
@@ -1603,8 +1612,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
public void onEndBatchInput(final InputPointers batchPointers) {
final SuggestedWords suggestedWords = BatchInputUpdater.getInstance().onEndBatchInput(
batchPointers, this);
- final String batchInputText = (suggestedWords.size() > 0)
- ? suggestedWords.getWord(0) : null;
+ final String batchInputText = suggestedWords.isEmpty()
+ ? null : suggestedWords.getWord(0);
if (TextUtils.isEmpty(batchInputText)) {
return;
}
@@ -1621,8 +1630,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mKeyboardSwitcher.updateShiftState();
}
- private CharSequence specificTldProcessingOnTextInput(final CharSequence text) {
- if (text.length() <= 1 || text.charAt(0) != Keyboard.CODE_PERIOD
+ private String specificTldProcessingOnTextInput(final String text) {
+ if (text.length() <= 1 || text.charAt(0) != Constants.CODE_PERIOD
|| !Character.isLetter(text.charAt(1))) {
// Not a tld: do nothing.
return text;
@@ -1633,8 +1642,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// TODO: use getCodePointBeforeCursor instead to improve performance and simplify the code
final CharSequence lastOne = mConnection.getTextBeforeCursor(1, 0);
if (lastOne != null && lastOne.length() == 1
- && lastOne.charAt(0) == Keyboard.CODE_PERIOD) {
- return text.subSequence(1, text.length());
+ && lastOne.charAt(0) == Constants.CODE_PERIOD) {
+ return text.substring(1);
} else {
return text;
}
@@ -1647,6 +1656,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mKeyboardSwitcher.onCancelInput();
}
+ @Override
+ public void onCancelBatchInput() {
+ BatchInputUpdater.getInstance().onCancelBatchInput(this);
+ }
+
private void handleBackspace(final int spaceState) {
// In many cases, we may have to put the keyboard in auto-shift state again. However
// we want to wait a few milliseconds before doing it to avoid the keyboard flashing
@@ -1656,8 +1670,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
if (mWordComposer.isComposingWord()) {
final int length = mWordComposer.size();
if (length > 0) {
- // Immediately after a batch input.
- if (SPACE_STATE_PHANTOM == spaceState) {
+ if (mWordComposer.isBatchMode()) {
mWordComposer.reset();
} else {
mWordComposer.deleteLast();
@@ -1688,7 +1701,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
return;
}
if (SPACE_STATE_DOUBLE == spaceState) {
- mHandler.cancelDoubleSpacesTimer();
+ mHandler.cancelDoubleSpacePeriodTimer();
if (mConnection.revertDoubleSpace()) {
// No need to reset mSpaceState, it has already be done (that's why we
// receive it as a parameter)
@@ -1738,7 +1751,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private boolean maybeStripSpace(final int code,
final int spaceState, final boolean isFromSuggestionStrip) {
- if (Keyboard.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) {
+ if (Constants.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) {
mConnection.removeTrailingSpace();
return false;
} else if ((SPACE_STATE_WEAK == spaceState
@@ -1781,7 +1794,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// the character is a single quote. The idea here is, single quote is not a
// separator and it should be treated as a normal character, except in the first
// position where it should not start composing a word.
- isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != primaryCode);
+ isComposingWord = (Constants.CODE_SINGLE_QUOTE != primaryCode);
// Here we don't need to reset the last composed word. It will be reset
// when we commit this one, if we ever do; if on the other hand we backspace
// it entirely and resume suggestions on the previous word, we'd like to still
@@ -1790,15 +1803,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
if (isComposingWord) {
final int keyX, keyY;
- if (KeyboardActionListener.Adapter.isInvalidCoordinate(x)
- || KeyboardActionListener.Adapter.isInvalidCoordinate(y)) {
- keyX = x;
- keyY = y;
- } else {
+ if (Constants.isValidCoordinate(x) && Constants.isValidCoordinate(y)) {
final KeyDetector keyDetector =
mKeyboardSwitcher.getMainKeyboardView().getKeyDetector();
keyX = keyDetector.getTouchX(x);
keyY = keyDetector.getTouchY(y);
+ } else {
+ keyX = x;
+ keyY = y;
}
mWordComposer.add(primaryCode, keyX, keyY);
// If it's the first letter, make note of auto-caps state
@@ -1849,16 +1861,16 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
sendKeyCodePoint(primaryCode);
- if (Keyboard.CODE_SPACE == primaryCode) {
+ if (Constants.CODE_SPACE == primaryCode) {
if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) {
- if (maybeDoubleSpace()) {
+ if (maybeDoubleSpacePeriod()) {
mSpaceState = SPACE_STATE_DOUBLE;
} else if (!isShowingPunctuationList()) {
mSpaceState = SPACE_STATE_WEAK;
}
}
- mHandler.startDoubleSpacesTimer();
+ mHandler.startDoubleSpacePeriodTimer();
if (!mConnection.isCursorTouchingWord(mCurrentSettings)) {
mHandler.postUpdateSuggestionStrip();
}
@@ -1894,7 +1906,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
return didAutoCorrect;
}
- private CharSequence getTextWithUnderline(final CharSequence text) {
+ private CharSequence getTextWithUnderline(final String text) {
return mIsAutoCorrectionIndicatorOn
? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(this, text)
: text;
@@ -1911,7 +1923,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// TODO: make this private
// Outside LatinIME, only used by the test suite.
- /* package for tests */
+ @UsedForTesting
boolean isShowingPunctuationList() {
if (mSuggestionStripView == null) return false;
return mCurrentSettings.mSuggestPuncList == mSuggestionStripView.getSuggestions();
@@ -1981,7 +1993,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private SuggestedWords getSuggestedWords(final int sessionId) {
final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
- if (keyboard == null) {
+ if (keyboard == null || mSuggest == null) {
return SuggestedWords.EMPTY;
}
final String typedWord = mWordComposer.getTypedWord();
@@ -1989,7 +2001,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// 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 =
+ final String prevWord =
mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators,
mWordComposer.isComposingWord() ? 2 : 1);
final SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer,
@@ -1998,7 +2010,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
return maybeRetrieveOlderSuggestions(typedWord, suggestedWords);
}
- private SuggestedWords maybeRetrieveOlderSuggestions(final CharSequence typedWord,
+ private SuggestedWords maybeRetrieveOlderSuggestions(final String typedWord,
final SuggestedWords suggestedWords) {
// TODO: consolidate this into getSuggestedWords
// We update the suggestion strip only when we have some suggestions to show, i.e. when
@@ -2028,21 +2040,16 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
}
- private void showSuggestionStrip(final SuggestedWords suggestedWords,
- final CharSequence typedWord) {
- if (null == suggestedWords || suggestedWords.size() <= 0) {
+ private void showSuggestionStrip(final SuggestedWords suggestedWords, final String typedWord) {
+ if (suggestedWords.isEmpty()) {
clearSuggestionStrip();
return;
}
- final CharSequence autoCorrection;
- if (suggestedWords.size() > 0) {
- if (suggestedWords.mWillAutoCorrect) {
- autoCorrection = suggestedWords.getWord(1);
- } else {
- autoCorrection = typedWord;
- }
+ final String autoCorrection;
+ if (suggestedWords.mWillAutoCorrect) {
+ autoCorrection = suggestedWords.getWord(1);
} else {
- autoCorrection = null;
+ autoCorrection = typedWord;
}
mWordComposer.setAutoCorrection(autoCorrection);
final boolean isAutoCorrection = suggestedWords.willAutoCorrect();
@@ -2056,9 +2063,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
if (mHandler.hasPendingUpdateSuggestions()) {
updateSuggestionStrip();
}
- final CharSequence typedAutoCorrection = mWordComposer.getAutoCorrectionOrNull();
+ final String typedAutoCorrection = mWordComposer.getAutoCorrectionOrNull();
final String typedWord = mWordComposer.getTypedWord();
- final CharSequence autoCorrection = (typedAutoCorrection != null)
+ final String autoCorrection = (typedAutoCorrection != null)
? typedAutoCorrection : typedWord;
if (autoCorrection != null) {
if (TextUtils.isEmpty(typedWord)) {
@@ -2089,7 +2096,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// Called from {@link SuggestionStripView} through the {@link SuggestionStripView#Listener}
// interface
@Override
- public void pickSuggestionManually(final int index, final CharSequence suggestion) {
+ public void pickSuggestionManually(final int index, final String suggestion) {
final SuggestedWords suggestedWords = mSuggestionStripView.getSuggestions();
// If this is a punctuation picked from the suggestion strip, pass it to onCodeInput
if (suggestion.length() == 1 && isShowingPunctuationList()) {
@@ -2159,7 +2166,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
&& !AutoCorrection.isValidWord(mSuggest.getUnigramDictionaries(), suggestion, true);
if (ProductionFlag.IS_INTERNAL) {
- Stats.onSeparator((char)Keyboard.CODE_SPACE,
+ Stats.onSeparator((char)Constants.CODE_SPACE,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
}
if (showingAddToDictionaryHint && mIsUserDictionaryAvailable) {
@@ -2174,13 +2181,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
/**
* Commits the chosen word to the text field and saves it for later retrieval.
*/
- private void commitChosenWord(final CharSequence chosenWord, final int commitType,
+ private void commitChosenWord(final String chosenWord, final int commitType,
final String separatorString) {
final SuggestedWords suggestedWords = mSuggestionStripView.getSuggestions();
mConnection.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan(
this, chosenWord, suggestedWords, mIsMainDictionaryAvailable), 1);
// Add the word to the user history dictionary
- final CharSequence prevWord = addToUserHistoryDictionary(chosenWord);
+ final String prevWord = addToUserHistoryDictionary(chosenWord);
// TODO: figure out here if this is an auto-correct or if the best word is actually
// what user typed. Note: currently this is done much later in
// LastComposedWord#didCommitTypedWord by string equality of the remembered
@@ -2199,7 +2206,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
setSuggestionStripShown(isSuggestionsStripVisible());
}
- private CharSequence addToUserHistoryDictionary(final CharSequence suggestion) {
+ private String addToUserHistoryDictionary(final String suggestion) {
if (TextUtils.isEmpty(suggestion)) return null;
if (mSuggest == null) return null;
@@ -2214,19 +2221,18 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
= mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, 2);
final String secondWord;
if (mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps()) {
- secondWord = suggestion.toString().toLowerCase(
- mSubtypeSwitcher.getCurrentSubtypeLocale());
+ secondWord = suggestion.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale());
} else {
- secondWord = suggestion.toString();
+ secondWord = suggestion;
}
// We demote unrecognized words (frequency < 0, below) by specifying them as "invalid".
// We don't add words with 0-frequency (assuming they would be profanity etc.).
final int maxFreq = AutoCorrection.getMaxFrequency(
mSuggest.getUnigramDictionaries(), suggestion);
if (maxFreq == 0) return null;
- userHistoryDictionary.addToUserHistory(null == prevWord ? null : prevWord.toString(),
- secondWord, maxFreq > 0);
- return prevWord;
+ final String prevWordString = (null == prevWord) ? null : prevWord.toString();
+ userHistoryDictionary.addToUserHistory(prevWordString, secondWord, maxFreq > 0);
+ return prevWordString;
}
return null;
}
@@ -2251,9 +2257,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
private void revertCommit() {
- final CharSequence previousWord = mLastComposedWord.mPrevWord;
+ final String previousWord = mLastComposedWord.mPrevWord;
final String originallyTypedWord = mLastComposedWord.mTypedWord;
- final CharSequence committedWord = mLastComposedWord.mCommittedWord;
+ final String committedWord = mLastComposedWord.mCommittedWord;
final int cancelLength = committedWord.length();
final int separatorLength = LastComposedWord.getSeparatorLength(
mLastComposedWord.mSeparatorString);
@@ -2263,9 +2269,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
if (mWordComposer.isComposingWord()) {
throw new RuntimeException("revertCommit, but we are composing a word");
}
- final String wordBeforeCursor =
+ final CharSequence wordBeforeCursor =
mConnection.getTextBeforeCursor(deleteLength, 0)
- .subSequence(0, cancelLength).toString();
+ .subSequence(0, cancelLength);
if (!TextUtils.equals(committedWord, wordBeforeCursor)) {
throw new RuntimeException("revertCommit check failed: we thought we were "
+ "reverting \"" + committedWord
@@ -2295,7 +2301,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// This essentially inserts a space, and that's it.
public void promotePhantomSpace() {
if (mCurrentSettings.shouldInsertSpacesAutomatically()) {
- sendKeyCodePoint(Keyboard.CODE_SPACE);
+ sendKeyCodePoint(Constants.CODE_SPACE);
}
}
@@ -2306,7 +2312,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// TODO: Make this private
// Outside LatinIME, only used by the {@link InputTestsBase} test suite.
- /* package for test */
+ @UsedForTesting
void loadKeyboard() {
// When the device locale is changed in SetupWizard etc., this method may get called via
// onConfigurationChanged before SoftInputWindow is shown.
@@ -2322,13 +2328,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mHandler.postUpdateSuggestionStrip();
}
- // TODO: Remove this method from {@link LatinIME} and move {@link FeedbackManager} to
- // {@link KeyboardSwitcher}. Called from KeyboardSwitcher
- public void hapticAndAudioFeedback(final int primaryCode) {
- mFeedbackManager.hapticAndAudioFeedback(
- primaryCode, mKeyboardSwitcher.getMainKeyboardView());
- }
-
// Callback called by PointerTracker through the KeyboardActionListener. This is called when a
// key is depressed; release matching call is onReleaseKey below.
@Override
@@ -2345,16 +2344,16 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// If accessibility is on, ensure the user receives keyboard state updates.
if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
switch (primaryCode) {
- case Keyboard.CODE_SHIFT:
+ case Constants.CODE_SHIFT:
AccessibleKeyboardViewProxy.getInstance().notifyShiftState();
break;
- case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
+ case Constants.CODE_SWITCH_ALPHA_SYMBOL:
AccessibleKeyboardViewProxy.getInstance().notifySymbolsState();
break;
}
}
- if (Keyboard.CODE_DELETE == primaryCode) {
+ if (Constants.CODE_DELETE == primaryCode) {
// This is a stopgap solution to avoid leaving a high surrogate alone in a text view.
// In the future, we need to deprecate deteleSurroundingText() and have a surrogate
// pair-friendly way of deleting characters in InputConnection.
@@ -2374,7 +2373,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
mSubtypeSwitcher.onNetworkStateChanged(intent);
} else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
- mFeedbackManager.onRingerModeChanged();
+ mKeyboardSwitcher.onRingerModeChanged();
}
}
};
@@ -2411,7 +2410,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
getString(R.string.language_selection_title),
getString(R.string.english_ime_settings),
};
- final Context context = this;
final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface di, int position) {
@@ -2419,7 +2417,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
switch (position) {
case 0:
Intent intent = CompatUtils.getInputLanguageSelectionIntent(
- ImfUtils.getInputMethodIdOfThisIme(context),
+ mRichImm.getInputMethodIdOfThisIme(),
Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 3b732278b..d1d920698 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -26,7 +26,6 @@ import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
-import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.research.ResearchLogger;
@@ -66,12 +65,6 @@ public final class RichInputConnection {
* This contains the currently composing text, as LatinIME thinks the TextView is seeing it.
*/
private StringBuilder mComposingText = new StringBuilder();
- /**
- * This is a one-character string containing the character after the cursor. Since LatinIME
- * never touches it directly, it's never modified by any means other than re-reading from the
- * TextView when the cursor position is changed by the user.
- */
- private CharSequence mCharAfterTheCursor = "";
// A hint on how many characters to cache from the TextView. A good value of this is given by
// how many characters we need to be able to almost always find the caps mode.
private static final int DEFAULT_TEXT_CACHE_SIZE = 100;
@@ -147,7 +140,6 @@ public final class RichInputConnection {
mCommittedTextBeforeComposingText.setLength(0);
final CharSequence textBeforeCursor = getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE, 0);
if (null != textBeforeCursor) mCommittedTextBeforeComposingText.append(textBeforeCursor);
- mCharAfterTheCursor = getTextAfterCursor(1, 0);
if (null != mIC) {
mIC.finishComposingText();
if (ProductionFlag.IS_EXPERIMENTAL) {
@@ -417,7 +409,8 @@ public final class RichInputConnection {
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
}
- public CharSequence getNthPreviousWord(final String sentenceSeperators, final int n) {
+ @SuppressWarnings("unused")
+ public String getNthPreviousWord(final String sentenceSeperators, final int n) {
mIC = mParent.getCurrentInputConnection();
if (null == mIC) return null;
final CharSequence prev = mIC.getTextBeforeCursor(LOOKBACK_CHARACTER_NUM, 0);
@@ -485,19 +478,22 @@ public final class RichInputConnection {
// (n = 2) "abc|" -> null
// (n = 2) "abc |" -> null
// (n = 2) "abc. def|" -> null
- public static CharSequence getNthPreviousWord(final CharSequence prev,
+ public static String getNthPreviousWord(final CharSequence prev,
final String sentenceSeperators, final int n) {
if (prev == null) return null;
- String[] w = spaceRegex.split(prev);
+ final String[] w = spaceRegex.split(prev);
// If we can't find n words, or we found an empty word, return null.
- if (w.length < n || w[w.length - n].length() <= 0) return null;
+ if (w.length < n) return null;
+ final String nthPrevWord = w[w.length - n];
+ final int length = nthPrevWord.length();
+ if (length <= 0) return null;
// If ends in a separator, return null
- char lastChar = w[w.length - n].charAt(w[w.length - n].length() - 1);
+ final char lastChar = nthPrevWord.charAt(length - 1);
if (sentenceSeperators.contains(String.valueOf(lastChar))) return null;
- return w[w.length - n];
+ return nthPrevWord;
}
/**
@@ -530,19 +526,20 @@ public final class RichInputConnection {
* be included in the returned range
* @return a range containing the text surrounding the cursor
*/
- public Range getWordRangeAtCursor(String sep, int additionalPrecedingWordsCount) {
+ public Range getWordRangeAtCursor(final String sep, final int additionalPrecedingWordsCount) {
mIC = mParent.getCurrentInputConnection();
if (mIC == null || sep == null) {
return null;
}
- CharSequence before = mIC.getTextBeforeCursor(1000, 0);
- CharSequence after = mIC.getTextAfterCursor(1000, 0);
+ final CharSequence before = mIC.getTextBeforeCursor(1000, 0);
+ final CharSequence after = mIC.getTextAfterCursor(1000, 0);
if (before == null || after == null) {
return null;
}
// Going backward, alternate skipping non-separators and separators until enough words
// have been read.
+ int count = additionalPrecedingWordsCount;
int start = before.length();
boolean isStoppingAtWhitespace = true; // toggles to indicate what to stop at
while (true) { // see comments below for why this is guaranteed to halt
@@ -559,7 +556,7 @@ public final class RichInputConnection {
// isStoppingAtWhitespace is true every other time through the loop,
// so additionalPrecedingWordsCount is guaranteed to become < 0, which
// guarantees outer loop termination
- if (isStoppingAtWhitespace && (--additionalPrecedingWordsCount < 0)) {
+ if (isStoppingAtWhitespace && (--count < 0)) {
break; // outer loop
}
isStoppingAtWhitespace = !isStoppingAtWhitespace;
@@ -577,7 +574,7 @@ public final class RichInputConnection {
}
}
- int cursor = getCursorPosition();
+ final int cursor = getCursorPosition();
if (start >= 0 && cursor + end <= after.length() + before.length()) {
String word = before.toString().substring(start, before.length())
+ after.toString().substring(0, end);
@@ -588,8 +585,8 @@ public final class RichInputConnection {
}
public boolean isCursorTouchingWord(final SettingsValues settingsValues) {
- CharSequence before = getTextBeforeCursor(1, 0);
- CharSequence after = getTextAfterCursor(1, 0);
+ final CharSequence before = getTextBeforeCursor(1, 0);
+ final CharSequence after = getTextAfterCursor(1, 0);
if (!TextUtils.isEmpty(before) && !settingsValues.isWordSeparator(before.charAt(0))
&& !settingsValues.isSymbolExcludedFromWordSeparators(before.charAt(0))) {
return true;
@@ -605,7 +602,7 @@ public final class RichInputConnection {
if (DEBUG_BATCH_NESTING) checkBatchEdit();
final CharSequence lastOne = getTextBeforeCursor(1, 0);
if (lastOne != null && lastOne.length() == 1
- && lastOne.charAt(0) == Keyboard.CODE_SPACE) {
+ && lastOne.charAt(0) == Constants.CODE_SPACE) {
deleteSurroundingText(1, 0);
}
}
@@ -631,7 +628,7 @@ public final class RichInputConnection {
CharSequence word = getWordAtCursor(settings.mWordSeparators);
// We don't suggest on leading single quotes, so we have to remove them from the word if
// it starts with single quotes.
- while (!TextUtils.isEmpty(word) && Keyboard.CODE_SINGLE_QUOTE == word.charAt(0)) {
+ while (!TextUtils.isEmpty(word) && Constants.CODE_SINGLE_QUOTE == word.charAt(0)) {
word = word.subSequence(1, word.length());
}
if (TextUtils.isEmpty(word)) return null;
@@ -683,7 +680,7 @@ public final class RichInputConnection {
// NOTE: This does not work with surrogate pairs. Hopefully when the keyboard is able to
// enter surrogate pairs this code will have been removed.
if (TextUtils.isEmpty(textBeforeCursor)
- || (Keyboard.CODE_SPACE != textBeforeCursor.charAt(1))) {
+ || (Constants.CODE_SPACE != textBeforeCursor.charAt(1))) {
// We may only come here if the application is changing the text while we are typing.
// This is quite a broken case, but not logically impossible, so we shouldn't crash,
// but some debugging log may be in order.
diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
new file mode 100644
index 000000000..af0d61cc7
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
@@ -0,0 +1,248 @@
+/*
+ * 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 static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.IBinder;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Enrichment class for InputMethodManager to simplify interaction and add functionality.
+ */
+public final class RichInputMethodManager {
+ private static final String TAG = RichInputMethodManager.class.getSimpleName();
+
+ private RichInputMethodManager() {
+ // This utility class is not publicly instantiable.
+ }
+
+ private static final RichInputMethodManager sInstance = new RichInputMethodManager();
+
+ private InputMethodManagerCompatWrapper mImmWrapper;
+ private InputMethodInfo mInputMethodInfoOfThisIme;
+
+ public static RichInputMethodManager getInstance() {
+ sInstance.checkInitialized();
+ return sInstance;
+ }
+
+ public static void init(final Context context, final SharedPreferences prefs) {
+ sInstance.initInternal(context, prefs);
+ }
+
+ private boolean isInitialized() {
+ return mImmWrapper != null;
+ }
+
+ private void checkInitialized() {
+ if (!isInitialized()) {
+ throw new RuntimeException(TAG + " is used before initialization");
+ }
+ }
+
+ private void initInternal(final Context context, final SharedPreferences prefs) {
+ if (isInitialized()) {
+ return;
+ }
+ mImmWrapper = new InputMethodManagerCompatWrapper(context);
+ mInputMethodInfoOfThisIme = getInputMethodInfoOfThisIme(context);
+
+ // Initialize additional subtypes.
+ SubtypeLocale.init(context);
+ final String prefAdditionalSubtypes = SettingsValues.getPrefAdditionalSubtypes(
+ prefs, context.getResources());
+ final InputMethodSubtype[] additionalSubtypes =
+ AdditionalSubtype.createAdditionalSubtypesArray(prefAdditionalSubtypes);
+ setAdditionalInputMethodSubtypes(additionalSubtypes);
+ }
+
+ public InputMethodManager getInputMethodManager() {
+ checkInitialized();
+ return mImmWrapper.mImm;
+ }
+
+ private InputMethodInfo getInputMethodInfoOfThisIme(final Context context) {
+ final String packageName = context.getPackageName();
+ for (final InputMethodInfo imi : mImmWrapper.mImm.getInputMethodList()) {
+ if (imi.getPackageName().equals(packageName)) {
+ return imi;
+ }
+ }
+ throw new RuntimeException("Input method id for " + packageName + " not found.");
+ }
+
+ public boolean switchToNextInputMethod(final IBinder token, final boolean onlyCurrentIme) {
+ final boolean result = mImmWrapper.switchToNextInputMethod(token, onlyCurrentIme);
+ if (!result) {
+ mImmWrapper.mImm.switchToLastInputMethod(token);
+ return false;
+ }
+ return true;
+ }
+
+ public InputMethodInfo getInputMethodInfoOfThisIme() {
+ return mInputMethodInfoOfThisIme;
+ }
+
+ public String getInputMethodIdOfThisIme() {
+ return mInputMethodInfoOfThisIme.getId();
+ }
+
+ public boolean checkIfSubtypeBelongsToThisImeAndEnabled(final InputMethodSubtype subtype) {
+ return checkIfSubtypeBelongsToImeAndEnabled(mInputMethodInfoOfThisIme, subtype);
+ }
+
+ public boolean checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(
+ final InputMethodSubtype subtype) {
+ final boolean subtypeEnabled = checkIfSubtypeBelongsToThisImeAndEnabled(subtype);
+ final boolean subtypeExplicitlyEnabled = checkIfSubtypeBelongsToList(
+ subtype, mImmWrapper.mImm.getEnabledInputMethodSubtypeList(
+ mInputMethodInfoOfThisIme, false /* allowsImplicitlySelectedSubtypes */));
+ return subtypeEnabled && !subtypeExplicitlyEnabled;
+ }
+
+ public boolean checkIfSubtypeBelongsToImeAndEnabled(final InputMethodInfo imi,
+ final InputMethodSubtype subtype) {
+ return checkIfSubtypeBelongsToList(
+ subtype, mImmWrapper.mImm.getEnabledInputMethodSubtypeList(
+ imi, true /* allowsImplicitlySelectedSubtypes */));
+ }
+
+ private static boolean checkIfSubtypeBelongsToList(final InputMethodSubtype subtype,
+ final List<InputMethodSubtype> subtypes) {
+ for (final InputMethodSubtype ims : subtypes) {
+ if (ims.equals(subtype)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean checkIfSubtypeBelongsToThisIme(final InputMethodSubtype subtype) {
+ final InputMethodInfo myImi = mInputMethodInfoOfThisIme;
+ final int count = myImi.getSubtypeCount();
+ for (int i = 0; i < count; i++) {
+ final InputMethodSubtype ims = myImi.getSubtypeAt(i);
+ if (ims.equals(subtype)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public InputMethodSubtype getCurrentInputMethodSubtype(
+ final InputMethodSubtype defaultSubtype) {
+ final InputMethodSubtype currentSubtype = mImmWrapper.mImm.getCurrentInputMethodSubtype();
+ return (currentSubtype != null) ? currentSubtype : defaultSubtype;
+ }
+
+ public boolean hasMultipleEnabledIMEsOrSubtypes(final boolean shouldIncludeAuxiliarySubtypes) {
+ final List<InputMethodInfo> enabledImis = mImmWrapper.mImm.getEnabledInputMethodList();
+ return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, enabledImis);
+ }
+
+ public boolean hasMultipleEnabledSubtypesInThisIme(
+ final boolean shouldIncludeAuxiliarySubtypes) {
+ final List<InputMethodInfo> imiList = Collections.singletonList(mInputMethodInfoOfThisIme);
+ return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList);
+ }
+
+ private boolean hasMultipleEnabledSubtypes(final boolean shouldIncludeAuxiliarySubtypes,
+ final List<InputMethodInfo> imiList) {
+ // Number of the filtered IMEs
+ int filteredImisCount = 0;
+
+ for (InputMethodInfo imi : imiList) {
+ // We can return true immediately after we find two or more filtered IMEs.
+ if (filteredImisCount > 1) return true;
+ final List<InputMethodSubtype> subtypes =
+ mImmWrapper.mImm.getEnabledInputMethodSubtypeList(imi, true);
+ // IMEs that have no subtypes should be counted.
+ if (subtypes.isEmpty()) {
+ ++filteredImisCount;
+ continue;
+ }
+
+ int auxCount = 0;
+ for (InputMethodSubtype subtype : subtypes) {
+ if (subtype.isAuxiliary()) {
+ ++auxCount;
+ }
+ }
+ final int nonAuxCount = subtypes.size() - auxCount;
+
+ // IMEs that have one or more non-auxiliary subtypes should be counted.
+ // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
+ // subtypes should be counted as well.
+ if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
+ ++filteredImisCount;
+ continue;
+ }
+ }
+
+ if (filteredImisCount > 1) {
+ return true;
+ }
+ final List<InputMethodSubtype> subtypes =
+ mImmWrapper.mImm.getEnabledInputMethodSubtypeList(null, true);
+ int keyboardCount = 0;
+ // imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's
+ // both explicitly and implicitly enabled input method subtype.
+ // (The current IME should be LatinIME.)
+ for (InputMethodSubtype subtype : subtypes) {
+ if (KEYBOARD_MODE.equals(subtype.getMode())) {
+ ++keyboardCount;
+ }
+ }
+ return keyboardCount > 1;
+ }
+
+ public InputMethodSubtype findSubtypeByLocaleAndKeyboardLayoutSet(final String localeString,
+ final String keyboardLayoutSetName) {
+ final InputMethodInfo myImi = mInputMethodInfoOfThisIme;
+ final int count = myImi.getSubtypeCount();
+ for (int i = 0; i < count; i++) {
+ final InputMethodSubtype subtype = myImi.getSubtypeAt(i);
+ final String layoutName = SubtypeLocale.getKeyboardLayoutSetName(subtype);
+ if (localeString.equals(subtype.getLocale())
+ && keyboardLayoutSetName.equals(layoutName)) {
+ return subtype;
+ }
+ }
+ return null;
+ }
+
+ public void setInputMethodAndSubtype(final IBinder token, final InputMethodSubtype subtype) {
+ mImmWrapper.mImm.setInputMethodAndSubtype(
+ token, mInputMethodInfoOfThisIme.getId(), subtype);
+ }
+
+ public void setAdditionalInputMethodSubtypes(final InputMethodSubtype[] subtypes) {
+ mImmWrapper.mImm.setAdditionalInputMethodSubtypes(
+ mInputMethodInfoOfThisIme.getId(), subtypes);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index 348928df8..7a73cade3 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -60,6 +60,8 @@ public final class Settings extends InputMethodSettingsFragment
"last_user_dictionary_write_time";
public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings";
public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict";
+ public static final String PREF_KEY_USE_DOUBLE_SPACE_PERIOD =
+ "pref_key_use_double_space_period";
public static final String PREF_SHOW_LANGUAGE_SWITCH_KEY =
"pref_show_language_switch_key";
public static final String PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST =
@@ -203,7 +205,8 @@ public final class Settings extends InputMethodSettingsFragment
final Intent intent = dictionaryLink.getIntent();
final int number = context.getPackageManager().queryIntentActivities(intent, 0).size();
- if (0 >= number) {
+ // TODO: The experimental version is not supported by the Dictionary Pack Service yet
+ if (ProductionFlag.IS_EXPERIMENTAL || 0 >= number) {
textCorrectionGroup.removePreference(dictionaryLink);
}
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 2f49fe92e..a23876722 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -22,7 +22,6 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.Log;
import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.keyboard.internal.KeySpecParser;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
@@ -76,13 +75,13 @@ public final class SettingsValues {
@SuppressWarnings("unused") // TODO: Use this
private final String mKeyPreviewPopupDismissDelayRawValue;
public final boolean mUseContactsDict;
+ public final boolean mUseDoubleSpacePeriod;
// Use bigrams to predict the next word when there is no input for it yet
public final boolean mBigramPredictionEnabled;
@SuppressWarnings("unused") // TODO: Use this
private final int mVibrationDurationSettingsRawValue;
@SuppressWarnings("unused") // TODO: Use this
private final float mKeypressSoundVolumeRawValue;
- private final InputMethodSubtype[] mAdditionalSubtypes;
public final boolean mGestureInputEnabled;
public final boolean mGesturePreviewTrailEnabled;
public final boolean mGestureFloatingPreviewTextEnabled;
@@ -156,6 +155,7 @@ public final class SettingsValues {
Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
Integer.toString(res.getInteger(R.integer.config_key_preview_linger_timeout)));
mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true);
+ mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true);
mAutoCorrectEnabled = isAutoCorrectEnabled(res, mAutoCorrectionThresholdRawValue);
mBigramPredictionEnabled = isBigramPredictionEnabled(prefs, res);
mVibrationDurationSettingsRawValue =
@@ -170,8 +170,6 @@ public final class SettingsValues {
mAutoCorrectionThresholdRawValue);
mVoiceKeyEnabled = mVoiceMode != null && !mVoiceMode.equals(voiceModeOff);
mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain);
- mAdditionalSubtypes = AdditionalSubtype.createAdditionalSubtypesArray(
- getPrefAdditionalSubtypes(prefs, res));
final boolean gestureInputEnabledByBuildConfig = res.getBoolean(
R.bool.config_gesture_input_enabled_by_build_config);
mGestureInputEnabled = gestureInputEnabledByBuildConfig
@@ -359,16 +357,15 @@ public final class SettingsValues {
return prefs.getBoolean(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, true);
}
- public boolean isLanguageSwitchKeyEnabled(final Context context) {
+ public boolean isLanguageSwitchKeyEnabled() {
if (!mShowsLanguageSwitchKey) {
return false;
}
+ final RichInputMethodManager imm = RichInputMethodManager.getInstance();
if (mIncludesOtherImesInLanguageSwitchList) {
- return ImfUtils.hasMultipleEnabledIMEsOrSubtypes(
- context, /* include aux subtypes */false);
+ return imm.hasMultipleEnabledIMEsOrSubtypes(false /* include aux subtypes */);
} else {
- return ImfUtils.hasMultipleEnabledSubtypesInThisIme(
- context, /* include aux subtypes */false);
+ return imm.hasMultipleEnabledSubtypesInThisIme(false /* include aux subtypes */);
}
}
@@ -376,10 +373,6 @@ public final class SettingsValues {
return res.getBoolean(R.bool.config_use_fullscreen_mode);
}
- public InputMethodSubtype[] getAdditionalSubtypes() {
- return mAdditionalSubtypes;
- }
-
public static String getPrefAdditionalSubtypes(final SharedPreferences prefs,
final Resources res) {
final String predefinedPrefSubtypes = AdditionalSubtype.createPrefSubtypes(
diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java
index df7709892..043043cef 100644
--- a/java/src/com/android/inputmethod/latin/StringUtils.java
+++ b/java/src/com/android/inputmethod/latin/StringUtils.java
@@ -16,10 +16,9 @@
package com.android.inputmethod.latin;
+import android.text.InputType;
import android.text.TextUtils;
-import com.android.inputmethod.keyboard.Keyboard; // For character constants
-
import java.util.ArrayList;
import java.util.Locale;
@@ -28,30 +27,30 @@ public final class StringUtils {
// This utility class is not publicly instantiable.
}
- public static int codePointCount(String text) {
+ public static int codePointCount(final String text) {
if (TextUtils.isEmpty(text)) return 0;
return text.codePointCount(0, text.length());
}
- public static boolean containsInArray(String key, String[] array) {
+ public static boolean containsInArray(final String key, final String[] array) {
for (final String element : array) {
if (key.equals(element)) return true;
}
return false;
}
- public static boolean containsInCsv(String key, String csv) {
+ public static boolean containsInCsv(final String key, final String csv) {
if (TextUtils.isEmpty(csv)) return false;
return containsInArray(key, csv.split(","));
}
- public static String appendToCsvIfNotExists(String key, String csv) {
+ public static String appendToCsvIfNotExists(final String key, final String csv) {
if (TextUtils.isEmpty(csv)) return key;
if (containsInCsv(key, csv)) return csv;
return csv + "," + key;
}
- public static String removeFromCsvIfExists(String key, String csv) {
+ public static String removeFromCsvIfExists(final String key, final String csv) {
if (TextUtils.isEmpty(csv)) return "";
final String[] elements = csv.split(",");
if (!containsInArray(key, elements)) return csv;
@@ -63,82 +62,20 @@ public final class StringUtils {
}
/**
- * Returns true if a and b are equal ignoring the case of the character.
- * @param a first character to check
- * @param b second character to check
- * @return {@code true} if a and b are equal, {@code false} otherwise.
- */
- public static boolean equalsIgnoreCase(char a, char b) {
- // Some language, such as Turkish, need testing both cases.
- return a == b
- || Character.toLowerCase(a) == Character.toLowerCase(b)
- || Character.toUpperCase(a) == Character.toUpperCase(b);
- }
-
- /**
- * Returns true if a and b are equal ignoring the case of the characters, including if they are
- * both null.
- * @param a first CharSequence to check
- * @param b second CharSequence to check
- * @return {@code true} if a and b are equal, {@code false} otherwise.
- */
- public static boolean equalsIgnoreCase(CharSequence a, CharSequence b) {
- if (a == b)
- return true; // including both a and b are null.
- if (a == null || b == null)
- return false;
- final int length = a.length();
- if (length != b.length())
- return false;
- for (int i = 0; i < length; i++) {
- if (!equalsIgnoreCase(a.charAt(i), b.charAt(i)))
- return false;
- }
- return true;
- }
-
- /**
- * Returns true if a and b are equal ignoring the case of the characters, including if a is null
- * and b is zero length.
- * @param a CharSequence to check
- * @param b character array to check
- * @param offset start offset of array b
- * @param length length of characters in array b
- * @return {@code true} if a and b are equal, {@code false} otherwise.
- * @throws IndexOutOfBoundsException
- * if {@code offset < 0 || length < 0 || offset + length > data.length}.
- * @throws NullPointerException if {@code b == null}.
- */
- public static boolean equalsIgnoreCase(CharSequence a, char[] b, int offset, int length) {
- if (offset < 0 || length < 0 || length > b.length - offset)
- throw new IndexOutOfBoundsException("array.length=" + b.length + " offset=" + offset
- + " length=" + length);
- if (a == null)
- return length == 0; // including a is null and b is zero length.
- if (a.length() != length)
- return false;
- for (int i = 0; i < length; i++) {
- if (!equalsIgnoreCase(a.charAt(i), b[offset + i]))
- return false;
- }
- return true;
- }
-
- /**
* Remove duplicates from an array of strings.
*
* This method will always keep the first occurrence of all strings at their position
* in the array, removing the subsequent ones.
*/
- public static void removeDupes(final ArrayList<CharSequence> suggestions) {
+ public static void removeDupes(final ArrayList<String> suggestions) {
if (suggestions.size() < 2) return;
int i = 1;
// Don't cache suggestions.size(), since we may be removing items
while (i < suggestions.size()) {
- final CharSequence cur = suggestions.get(i);
+ final String cur = suggestions.get(i);
// Compare each suggestion with each previous suggestion
for (int j = 0; j < i; j++) {
- CharSequence previous = suggestions.get(j);
+ final String previous = suggestions.get(j);
if (TextUtils.equals(cur, previous)) {
suggestions.remove(i);
i--;
@@ -149,7 +86,7 @@ public final class StringUtils {
}
}
- public static String toTitleCase(String s, Locale locale) {
+ public static String toTitleCase(final String s, final Locale locale) {
if (s.length() <= 1) {
// TODO: is this really correct? Shouldn't this be s.toUpperCase()?
return s;
@@ -165,21 +102,19 @@ public final class StringUtils {
return s.toUpperCase(locale).charAt(0) + s.substring(1);
}
+ private static final int[] EMPTY_CODEPOINTS = {};
+
public static int[] toCodePointArray(final String string) {
- final char[] characters = string.toCharArray();
- final int length = characters.length;
- final int[] codePoints = new int[Character.codePointCount(characters, 0, length)];
+ final int length = string.length();
if (length <= 0) {
- return new int[0];
+ return EMPTY_CODEPOINTS;
}
- int codePoint = Character.codePointAt(characters, 0);
- int dsti = 0;
- for (int srci = Character.charCount(codePoint);
- srci < length; srci += Character.charCount(codePoint), ++dsti) {
- codePoints[dsti] = codePoint;
- codePoint = Character.codePointAt(characters, srci);
+ final int[] codePoints = new int[string.codePointCount(0, length)];
+ int destIndex = 0;
+ for (int index = 0; index < length; index = string.offsetByCodePoints(index, 1)) {
+ codePoints[destIndex] = string.codePointAt(index);
+ destIndex++;
}
- codePoints[dsti] = codePoint;
return codePoints;
}
@@ -237,7 +172,7 @@ public final class StringUtils {
} else {
for (i = cs.length(); i > 0; i--) {
final char c = cs.charAt(i - 1);
- if (c != Keyboard.CODE_DOUBLE_QUOTE && c != Keyboard.CODE_SINGLE_QUOTE
+ if (c != Constants.CODE_DOUBLE_QUOTE && c != Constants.CODE_SINGLE_QUOTE
&& Character.getType(c) != Character.START_PUNCTUATION) {
break;
}
@@ -253,11 +188,11 @@ public final class StringUtils {
// if the first char that's not a space or tab is a start of line (as in \n, start of text,
// or some other similar characters).
int j = i;
- char prevChar = Keyboard.CODE_SPACE;
+ char prevChar = Constants.CODE_SPACE;
if (hasSpaceBefore) --j;
while (j > 0) {
prevChar = cs.charAt(j - 1);
- if (!Character.isSpaceChar(prevChar) && prevChar != Keyboard.CODE_TAB) break;
+ if (!Character.isSpaceChar(prevChar) && prevChar != Constants.CODE_TAB) break;
j--;
}
if (j <= 0 || Character.isWhitespace(prevChar)) {
@@ -296,7 +231,7 @@ public final class StringUtils {
// variants of English, the final period is placed within double quotes and maybe
// other closing punctuation signs. This is generally not true in other languages.
final char c = cs.charAt(j - 1);
- if (c != Keyboard.CODE_DOUBLE_QUOTE && c != Keyboard.CODE_SINGLE_QUOTE
+ if (c != Constants.CODE_DOUBLE_QUOTE && c != Constants.CODE_SINGLE_QUOTE
&& Character.getType(c) != Character.END_PUNCTUATION) {
break;
}
@@ -310,10 +245,10 @@ public final class StringUtils {
// end of a sentence. If we have a question mark or an exclamation mark, it's the end of
// a sentence. If it's neither, the only remaining case is the period so we get the opposite
// case out of the way.
- if (c == Keyboard.CODE_QUESTION_MARK || c == Keyboard.CODE_EXCLAMATION_MARK) {
+ if (c == Constants.CODE_QUESTION_MARK || c == Constants.CODE_EXCLAMATION_MARK) {
return (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_SENTENCES) & reqModes;
}
- if (c != Keyboard.CODE_PERIOD || j <= 0) {
+ if (c != Constants.CODE_PERIOD || j <= 0) {
return (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_WORDS) & reqModes;
}
@@ -363,7 +298,7 @@ public final class StringUtils {
case WORD:
if (Character.isLetter(c)) {
state = WORD;
- } else if (c == Keyboard.CODE_PERIOD) {
+ } else if (c == Constants.CODE_PERIOD) {
state = PERIOD;
} else {
return caps;
@@ -379,7 +314,7 @@ public final class StringUtils {
case LETTER:
if (Character.isLetter(c)) {
state = LETTER;
- } else if (c == Keyboard.CODE_PERIOD) {
+ } else if (c == Constants.CODE_PERIOD) {
state = PERIOD;
} else {
return noCaps;
diff --git a/java/src/com/android/inputmethod/latin/SubtypeLocale.java b/java/src/com/android/inputmethod/latin/SubtypeLocale.java
index 579f96bb4..5d8c0b17d 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeLocale.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeLocale.java
@@ -151,18 +151,19 @@ public final class SubtypeLocale {
// InputMethodSubtype's display name in its locale.
// isAdditionalSubtype (T=true, F=false)
- // locale layout | display name
- // ------ ------ - ----------------------
- // en_US qwerty F English (US) exception
- // en_GB qwerty F English (UK) exception
- // fr azerty F Français
- // fr_CA qwerty F Français (Canada)
- // de qwertz F Deutsch
- // zz qwerty F No language (QWERTY) in system locale
- // fr qwertz T Français (QWERTZ)
- // de qwerty T Deutsch (QWERTY)
- // en_US azerty T English (US) (AZERTY)
- // zz azerty T No language (AZERTY) in system locale
+ // locale layout | display name
+ // ------ ------- - ----------------------
+ // en_US qwerty F English (US) exception
+ // en_GB qwerty F English (UK) exception
+ // es_US spanish F Español (EE.UU.) exception
+ // fr azerty F Français
+ // fr_CA qwerty F Français (Canada)
+ // de qwertz F Deutsch
+ // zz qwerty F No language (QWERTY) in system locale
+ // fr qwertz T Français (QWERTZ)
+ // de qwerty T Deutsch (QWERTY)
+ // en_US azerty T English (US) (AZERTY)
+ // zz azerty T No language (AZERTY) in system locale
public static String getSubtypeDisplayName(final InputMethodSubtype subtype, Resources res) {
final String replacementString = (Build.VERSION.SDK_INT >= /* JELLY_BEAN */ 15
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index 8e51a372b..8f2e27549 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -43,7 +43,7 @@ public final class SubtypeSwitcher {
private static final String TAG = SubtypeSwitcher.class.getSimpleName();
private static final SubtypeSwitcher sInstance = new SubtypeSwitcher();
- private /* final */ InputMethodManager mImm;
+ private /* final */ RichInputMethodManager mRichImm;
private /* final */ Resources mResources;
private /* final */ ConnectivityManager mConnectivityManager;
@@ -84,7 +84,7 @@ public final class SubtypeSwitcher {
public static void init(final Context context) {
SubtypeLocale.init(context);
sInstance.initialize(context);
- sInstance.updateAllParameters(context);
+ sInstance.updateAllParameters();
}
private SubtypeSwitcher() {
@@ -93,13 +93,13 @@ public final class SubtypeSwitcher {
private void initialize(final Context service) {
mResources = service.getResources();
- mImm = ImfUtils.getInputMethodManager(service);
+ mRichImm = RichInputMethodManager.getInstance();
mConnectivityManager = (ConnectivityManager) service.getSystemService(
Context.CONNECTIVITY_SERVICE);
mCurrentSystemLocale = mResources.getConfiguration().locale;
- mNoLanguageSubtype = ImfUtils.findSubtypeByLocaleAndKeyboardLayoutSet(
- service, SubtypeLocale.NO_LANGUAGE, SubtypeLocale.QWERTY);
- mCurrentSubtype = ImfUtils.getCurrentInputMethodSubtype(service, mNoLanguageSubtype);
+ mNoLanguageSubtype = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ SubtypeLocale.NO_LANGUAGE, SubtypeLocale.QWERTY);
+ mCurrentSubtype = mRichImm.getCurrentInputMethodSubtype(mNoLanguageSubtype);
if (mNoLanguageSubtype == null) {
throw new RuntimeException("Can't find no lanugage with QWERTY subtype");
}
@@ -110,9 +110,9 @@ public final class SubtypeSwitcher {
// Update all parameters stored in SubtypeSwitcher.
// Only configuration changed event is allowed to call this because this is heavy.
- private void updateAllParameters(final Context context) {
+ private void updateAllParameters() {
mCurrentSystemLocale = mResources.getConfiguration().locale;
- updateSubtype(ImfUtils.getCurrentInputMethodSubtype(context, mNoLanguageSubtype));
+ updateSubtype(mRichImm.getCurrentInputMethodSubtype(mNoLanguageSubtype));
updateParametersOnStartInputViewAndReturnIfCurrentSubtypeEnabled();
}
@@ -137,7 +137,7 @@ public final class SubtypeSwitcher {
*/
private boolean updateEnabledSubtypesAndReturnIfEnabled(final InputMethodSubtype subtype) {
final List<InputMethodSubtype> enabledSubtypesOfThisIme =
- mImm.getEnabledInputMethodSubtypeList(null, true);
+ mRichImm.getInputMethodManager().getEnabledInputMethodSubtypeList(null, true);
mNeedsToDisplayLanguage.updateEnabledSubtypeCount(enabledSubtypesOfThisIme.size());
for (final InputMethodSubtype ims : enabledSubtypesOfThisIme) {
@@ -162,7 +162,7 @@ public final class SubtypeSwitcher {
}
// TODO: Update an icon for shortcut IME
final Map<InputMethodInfo, List<InputMethodSubtype>> shortcuts =
- mImm.getShortcutInputMethodsAndSubtypes();
+ mRichImm.getInputMethodManager().getShortcutInputMethodsAndSubtypes();
mShortcutInputMethodInfo = null;
mShortcutSubtype = null;
for (final InputMethodInfo imi : shortcuts.keySet()) {
@@ -193,8 +193,13 @@ public final class SubtypeSwitcher {
}
final Locale newLocale = SubtypeLocale.getSubtypeLocale(newSubtype);
+ final boolean sameLocale = mCurrentSystemLocale.equals(newLocale);
+ final boolean sameLanguage = mCurrentSystemLocale.getLanguage().equals(
+ newLocale.getLanguage());
+ final boolean implicitlyEnabled =
+ mRichImm.checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype);
mNeedsToDisplayLanguage.updateIsSystemLanguageSameAsInputLanguage(
- mCurrentSystemLocale.equals(newLocale));
+ sameLocale || (sameLanguage && implicitlyEnabled));
if (newSubtype.equals(mCurrentSubtype)) return;
@@ -221,7 +226,7 @@ public final class SubtypeSwitcher {
if (token == null) {
return;
}
- final InputMethodManager imm = mImm;
+ final InputMethodManager imm = mRichImm.getInputMethodManager();
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
@@ -238,14 +243,8 @@ public final class SubtypeSwitcher {
if (mShortcutSubtype == null) {
return true;
}
- final boolean allowsImplicitlySelectedSubtypes = true;
- for (final InputMethodSubtype enabledSubtype : mImm.getEnabledInputMethodSubtypeList(
- mShortcutInputMethodInfo, allowsImplicitlySelectedSubtypes)) {
- if (enabledSubtype.equals(mShortcutSubtype)) {
- return true;
- }
- }
- return false;
+ return mRichImm.checkIfSubtypeBelongsToImeAndEnabled(
+ mShortcutInputMethodInfo, mShortcutSubtype);
}
public boolean isShortcutImeReady() {
@@ -285,12 +284,12 @@ public final class SubtypeSwitcher {
return SubtypeLocale.getSubtypeLocale(mCurrentSubtype);
}
- public boolean onConfigurationChanged(final Configuration conf, final Context context) {
+ public boolean onConfigurationChanged(final Configuration conf) {
final Locale systemLocale = conf.locale;
final boolean systemLocaleChanged = !systemLocale.equals(mCurrentSystemLocale);
// If system configuration was changed, update all parameters.
if (systemLocaleChanged) {
- updateAllParameters(context);
+ updateAllParameters();
}
return systemLocaleChanged;
}
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index f0e3b4ebd..3dc2ba95b 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -19,7 +19,7 @@ package com.android.inputmethod.latin;
import android.content.Context;
import android.text.TextUtils;
-import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
@@ -38,7 +38,7 @@ public final class Suggest {
public static final String TAG = Suggest.class.getSimpleName();
// Session id for
- // {@link #getSuggestedWords(WordComposer,CharSequence,ProximityInfo,boolean,int)}.
+ // {@link #getSuggestedWords(WordComposer,String,ProximityInfo,boolean,int)}.
public static final int SESSION_TYPING = 0;
public static final int SESSION_GESTURE = 1;
@@ -71,7 +71,8 @@ public final class Suggest {
mLocale = locale;
}
- /* package for test */ Suggest(final Context context, final File dictionary,
+ @UsedForTesting
+ Suggest(final Context context, final File dictionary,
final long startOffset, final long length, final Locale locale) {
final Dictionary mainDict = DictionaryFactory.createDictionaryForTest(context, dictionary,
startOffset, length /* useFullEditDistance */, false, locale);
@@ -138,7 +139,7 @@ public final class Suggest {
* Sets an optional user dictionary resource to be loaded. The user dictionary is consulted
* before the main dictionary, if set. This refers to the system-managed user dictionary.
*/
- public void setUserDictionary(UserBinaryDictionary userDictionary) {
+ public void setUserDictionary(final UserBinaryDictionary userDictionary) {
addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_USER, userDictionary);
}
@@ -147,12 +148,12 @@ public final class Suggest {
* the contacts dictionary by passing null to this method. In this case no contacts dictionary
* won't be used.
*/
- public void setContactsDictionary(ContactsBinaryDictionary contactsDictionary) {
+ public void setContactsDictionary(final ContactsBinaryDictionary contactsDictionary) {
mContactsDict = contactsDictionary;
addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_CONTACTS, contactsDictionary);
}
- public void setUserHistoryDictionary(UserHistoryDictionary userHistoryDictionary) {
+ public void setUserHistoryDictionary(final UserHistoryDictionary userHistoryDictionary) {
addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_USER_HISTORY, userHistoryDictionary);
}
@@ -160,9 +161,9 @@ public final class Suggest {
mAutoCorrectionThreshold = threshold;
}
- public SuggestedWords getSuggestedWords(
- final WordComposer wordComposer, CharSequence prevWordForBigram,
- final ProximityInfo proximityInfo, final boolean isCorrectionEnabled, int sessionId) {
+ public SuggestedWords getSuggestedWords(final WordComposer wordComposer,
+ final String prevWordForBigram, final ProximityInfo proximityInfo,
+ final boolean isCorrectionEnabled, final int sessionId) {
LatinImeLogger.onStartSuggestion(prevWordForBigram);
if (wordComposer.isBatchMode()) {
return getSuggestedWordsForBatchInput(
@@ -174,9 +175,9 @@ public final class Suggest {
}
// Retrieves suggestions for the typing input.
- private SuggestedWords getSuggestedWordsForTypingInput(
- final WordComposer wordComposer, CharSequence prevWordForBigram,
- final ProximityInfo proximityInfo, final boolean isCorrectionEnabled) {
+ private SuggestedWords getSuggestedWordsForTypingInput(final WordComposer wordComposer,
+ final String prevWordForBigram, final ProximityInfo proximityInfo,
+ final boolean isCorrectionEnabled) {
final int trailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount();
final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator,
MAX_SUGGESTIONS);
@@ -203,7 +204,7 @@ public final class Suggest {
wordComposerForLookup, prevWordForBigram, proximityInfo));
}
- final CharSequence whitelistedWord;
+ final String whitelistedWord;
if (suggestionsSet.isEmpty()) {
whitelistedWord = null;
} else if (SuggestedWordInfo.KIND_WHITELIST != suggestionsSet.first().mKind) {
@@ -287,9 +288,9 @@ public final class Suggest {
}
// Retrieves suggestions for the batch input.
- private SuggestedWords getSuggestedWordsForBatchInput(
- final WordComposer wordComposer, CharSequence prevWordForBigram,
- final ProximityInfo proximityInfo, int sessionId) {
+ private SuggestedWords getSuggestedWordsForBatchInput(final WordComposer wordComposer,
+ final String prevWordForBigram, final ProximityInfo proximityInfo,
+ final int sessionId) {
final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator,
MAX_SUGGESTIONS);
@@ -307,7 +308,7 @@ public final class Suggest {
}
for (SuggestedWordInfo wordInfo : suggestionsSet) {
- LatinImeLogger.onAddSuggestedWord(wordInfo.mWord.toString(), wordInfo.mSourceDict);
+ LatinImeLogger.onAddSuggestedWord(wordInfo.mWord, wordInfo.mSourceDict);
}
final ArrayList<SuggestedWordInfo> suggestionsContainer =
@@ -372,7 +373,7 @@ public final class Suggest {
if (o1.mScore < o2.mScore) return 1;
if (o1.mCodePointCount < o2.mCodePointCount) return -1;
if (o1.mCodePointCount > o2.mCodePointCount) return 1;
- return o1.mWord.toString().compareTo(o2.mWord.toString());
+ return o1.mWord.compareTo(o2.mWord);
}
}
private static final SuggestedWordInfoComparator sSuggestedWordInfoComparator =
@@ -383,16 +384,17 @@ public final class Suggest {
final boolean isFirstCharCapitalized, final int trailingSingleQuotesCount) {
final StringBuilder sb = new StringBuilder(wordInfo.mWord.length());
if (isAllUpperCase) {
- sb.append(wordInfo.mWord.toString().toUpperCase(locale));
+ sb.append(wordInfo.mWord.toUpperCase(locale));
} else if (isFirstCharCapitalized) {
- sb.append(StringUtils.toTitleCase(wordInfo.mWord.toString(), locale));
+ sb.append(StringUtils.toTitleCase(wordInfo.mWord, locale));
} else {
sb.append(wordInfo.mWord);
}
for (int i = trailingSingleQuotesCount - 1; i >= 0; --i) {
- sb.appendCodePoint(Keyboard.CODE_SINGLE_QUOTE);
+ sb.appendCodePoint(Constants.CODE_SINGLE_QUOTE);
}
- return new SuggestedWordInfo(sb, wordInfo.mScore, wordInfo.mKind, wordInfo.mSourceDict);
+ return new SuggestedWordInfo(sb.toString(), wordInfo.mScore, wordInfo.mKind,
+ wordInfo.mSourceDict);
}
public void close() {
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 52e292a86..572f2906e 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -53,6 +53,10 @@ public final class SuggestedWords {
mIsPrediction = isPrediction;
}
+ public boolean isEmpty() {
+ return mSuggestedWordInfoList.isEmpty();
+ }
+
public int size() {
return mSuggestedWordInfoList.size();
}
@@ -86,11 +90,14 @@ public final class SuggestedWords {
public static ArrayList<SuggestedWordInfo> getFromApplicationSpecifiedCompletions(
final CompletionInfo[] infos) {
final ArrayList<SuggestedWordInfo> result = CollectionUtils.newArrayList();
- for (CompletionInfo info : infos) {
- if (null != info && info.getText() != null) {
- result.add(new SuggestedWordInfo(info.getText(), SuggestedWordInfo.MAX_SCORE,
- SuggestedWordInfo.KIND_APP_DEFINED, Dictionary.TYPE_APPLICATION_DEFINED));
- }
+ for (final CompletionInfo info : infos) {
+ if (info == null) continue;
+ final CharSequence text = info.getText();
+ if (null == text) continue;
+ final SuggestedWordInfo suggestedWordInfo = new SuggestedWordInfo(text.toString(),
+ SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_APP_DEFINED,
+ Dictionary.TYPE_APPLICATION_DEFINED);
+ result.add(suggestedWordInfo);
}
return result;
}
@@ -98,7 +105,7 @@ public final class SuggestedWords {
// Should get rid of the first one (what the user typed previously) from suggestions
// and replace it with what the user currently typed.
public static ArrayList<SuggestedWordInfo> getTypedWordAndPreviousSuggestions(
- final CharSequence typedWord, final SuggestedWords previousSuggestions) {
+ final String typedWord, final SuggestedWords previousSuggestions) {
final ArrayList<SuggestedWordInfo> suggestionsList = CollectionUtils.newArrayList();
final HashSet<String> alreadySeen = CollectionUtils.newHashSet();
suggestionsList.add(new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE,
@@ -107,7 +114,7 @@ public final class SuggestedWords {
final int previousSize = previousSuggestions.size();
for (int pos = 1; pos < previousSize; pos++) {
final SuggestedWordInfo prevWordInfo = previousSuggestions.getWordInfo(pos);
- final String prevWord = prevWordInfo.mWord.toString();
+ final String prevWord = prevWordInfo.mWord;
// Filter out duplicate suggestion.
if (!alreadySeen.contains(prevWord)) {
suggestionsList.add(prevWordInfo);
@@ -135,9 +142,9 @@ public final class SuggestedWords {
public final String mSourceDict;
private String mDebugString = "";
- public SuggestedWordInfo(final CharSequence word, final int score, final int kind,
+ public SuggestedWordInfo(final String word, final int score, final int kind,
final String sourceDict) {
- mWord = word.toString();
+ mWord = word;
mScore = score;
mKind = kind;
mSourceDict = sourceDict;
@@ -145,7 +152,7 @@ public final class SuggestedWords {
}
- public void setDebugString(String str) {
+ public void setDebugString(final String str) {
if (null == str) throw new NullPointerException("Debug info is null");
mDebugString = str;
}
@@ -167,7 +174,7 @@ public final class SuggestedWords {
if (TextUtils.isEmpty(mDebugString)) {
return mWord;
} else {
- return mWord + " (" + mDebugString.toString() + ")";
+ return mWord + " (" + mDebugString + ")";
}
}
diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java
index 8f21b7b4a..ec4dc1436 100644
--- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java
@@ -33,13 +33,13 @@ public final class SynchronouslyLoadedContactsBinaryDictionary extends ContactsB
@Override
public synchronized ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer codes,
- final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) {
+ final String prevWordForBigrams, final ProximityInfo proximityInfo) {
syncReloadDictionaryIfRequired();
return super.getSuggestions(codes, prevWordForBigrams, proximityInfo);
}
@Override
- public synchronized boolean isValidWord(CharSequence word) {
+ public synchronized boolean isValidWord(final String word) {
syncReloadDictionaryIfRequired();
return isValidWordInner(word);
}
diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java
index 612f54d73..4bdaf2039 100644
--- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java
@@ -36,13 +36,13 @@ public final class SynchronouslyLoadedUserBinaryDictionary extends UserBinaryDic
@Override
public synchronized ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer codes,
- final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) {
+ final String prevWordForBigrams, final ProximityInfo proximityInfo) {
syncReloadDictionaryIfRequired();
return super.getSuggestions(codes, prevWordForBigrams, proximityInfo);
}
@Override
- public synchronized boolean isValidWord(CharSequence word) {
+ public synchronized boolean isValidWord(final String word) {
syncReloadDictionaryIfRequired();
return isValidWordInner(word);
}
diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
index 8570746b1..ddae5ac48 100644
--- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
@@ -232,7 +232,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
mContext.startActivity(intent);
}
- private void addWords(Cursor cursor) {
+ private void addWords(final Cursor cursor) {
// 16 is JellyBean, but we want this to compile against ICS.
final boolean hasShortcutColumn = android.os.Build.VERSION.SDK_INT >= 16;
clearFusionDictionary();
diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java b/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java
index e39011145..100e377f6 100644
--- a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java
+++ b/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.latin;
import android.util.Log;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.makedict.BinaryDictIOUtils;
import com.android.inputmethod.latin.makedict.BinaryDictInputOutput;
import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface;
@@ -62,7 +63,7 @@ public final class UserHistoryDictIOUtils {
@Override
public int readUnsignedByte() {
- return ((int)mBuffer[mPosition++]) & 0xFF;
+ return mBuffer[mPosition++] & 0xFF;
}
@Override
@@ -129,7 +130,8 @@ public final class UserHistoryDictIOUtils {
/**
* Constructs a new FusionDictionary from BigramDictionaryInterface.
*/
- /* packages for test */ static FusionDictionary constructFusionDictionary(
+ @UsedForTesting
+ static FusionDictionary constructFusionDictionary(
final BigramDictionaryInterface dict, final UserHistoryDictionaryBigramList bigrams) {
final FusionDictionary fusionDict = new FusionDictionary(new Node(),
new FusionDictionary.DictionaryOptions(new HashMap<String, String>(), false,
@@ -193,7 +195,8 @@ public final class UserHistoryDictIOUtils {
/**
* Adds all unigrams and bigrams in maps to OnAddWordListener.
*/
- /* package for test */ static void addWordsFromWordMap(final Map<Integer, String> unigrams,
+ @UsedForTesting
+ static void addWordsFromWordMap(final Map<Integer, String> unigrams,
final Map<Integer, Integer> frequencies,
final Map<Integer, ArrayList<PendingAttribute>> bigrams, final OnAddWordListener to) {
for (Map.Entry<Integer, String> entry : unigrams.entrySet()) {
diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
index 3615fa1fb..f30a60af2 100644
--- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
@@ -21,6 +21,7 @@ import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.util.Log;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.UserHistoryDictIOUtils.BigramDictionaryInterface;
@@ -75,7 +76,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
private final SharedPreferences mPrefs;
// Should always be false except when we use this class for test
- /* package for test */ boolean isTest = false;
+ @UsedForTesting boolean isTest = false;
private static final ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>>
sLangDictCache = CollectionUtils.newConcurrentHashMap();
@@ -122,7 +123,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
@Override
protected ArrayList<SuggestedWordInfo> getWordsInner(final WordComposer composer,
- final CharSequence prevWord, final ProximityInfo proximityInfo) {
+ final String prevWord, final ProximityInfo proximityInfo) {
// Inhibit suggestions (not predictions) for user history for now. Removing this method
// is enough to use it through the standard ExpandableDictionary way.
return null;
@@ -132,7 +133,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
* Return whether the passed charsequence is in the dictionary.
*/
@Override
- public synchronized boolean isValidWord(final CharSequence word) {
+ public synchronized boolean isValidWord(final String word) {
// TODO: figure out what is the correct thing to do here.
return false;
}
@@ -145,7 +146,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
* context, as in beginning of a sentence for example.
* The second word may not be null (a NullPointerException would be thrown).
*/
- public int addToUserHistory(final String word1, String word2, boolean isValid) {
+ public int addToUserHistory(final String word1, final String word2, final boolean isValid) {
if (word2.length() >= BinaryDictionary.MAX_WORD_LENGTH ||
(word1 != null && word1.length() >= BinaryDictionary.MAX_WORD_LENGTH)) {
return -1;
@@ -175,7 +176,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
return -1;
}
- public boolean cancelAddingUserHistory(String word1, String word2) {
+ public boolean cancelAddingUserHistory(final String word1, final String word2) {
if (mBigramListLock.tryLock()) {
try {
if (mBigramList.removeBigram(word1, word2)) {
@@ -226,7 +227,8 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
final ExpandableDictionary dictionary = this;
final OnAddWordListener listener = new OnAddWordListener() {
@Override
- public void setUnigram(String word, String shortcutTarget, int frequency) {
+ public void setUnigram(final String word, final String shortcutTarget,
+ final int frequency) {
profTotal++;
if (DBG_SAVE_RESTORE) {
Log.d(TAG, "load unigram: " + word + "," + frequency);
@@ -236,7 +238,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
}
@Override
- public void setBigram(String word1, String word2, int frequency) {
+ public void setBigram(final String word1, final String word2, final int frequency) {
if (word1.length() < BinaryDictionary.MAX_WORD_LENGTH
&& word2.length() < BinaryDictionary.MAX_WORD_LENGTH) {
profTotal++;
@@ -250,7 +252,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
mBigramList.addBigram(word1, word2, (byte)frequency);
}
};
-
+
// Load the dictionary from binary file
FileInputStream inStream = null;
try {
@@ -292,8 +294,9 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
private final SharedPreferences mPrefs;
private final Context mContext;
- public UpdateBinaryTask(UserHistoryDictionaryBigramList pendingWrites, String locale,
- UserHistoryDictionary dict, SharedPreferences prefs, Context context) {
+ public UpdateBinaryTask(final UserHistoryDictionaryBigramList pendingWrites,
+ final String locale, final UserHistoryDictionary dict,
+ final SharedPreferences prefs, final Context context) {
mBigramList = pendingWrites;
mLocale = locale;
mUserHistoryDictionary = dict;
@@ -303,7 +306,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
}
@Override
- protected Void doInBackground(Void... v) {
+ protected Void doInBackground(final Void... v) {
if (mUserHistoryDictionary.isTest) {
// If isTest == true, wait until the lock is released.
mUserHistoryDictionary.mBigramListLock.lock();
@@ -360,7 +363,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
}
@Override
- public int getFrequency(String word1, String word2) {
+ public int getFrequency(final String word1, final String word2) {
final int freq;
if (word1 == null) { // unigram
freq = FREQUENCY_FOR_TYPED;
@@ -373,10 +376,10 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
final byte fc = fcp.getFc();
final boolean isValid = fcp.isValid();
if (prevFc > 0 && prevFc == fc) {
- freq = ((int)fc) & 0xFF;
+ freq = fc & 0xFF;
} else if (UserHistoryForgettingCurveUtils.
needsToSave(fc, isValid, mAddLevel0Bigrams)) {
- freq = ((int)fc) & 0xFF;
+ freq = fc & 0xFF;
} else {
// Delete this entry
freq = -1;
@@ -390,6 +393,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
}
}
+ @UsedForTesting
void forceAddWordForTest(final String word1, final String word2, final boolean isValid) {
mBigramListLock.lock();
try {
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index 876bc8e79..3eac6a237 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -41,6 +41,7 @@ import java.io.PrintWriter;
import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.Locale;
public final class Utils {
private Utils() {
@@ -193,7 +194,7 @@ public final class Utils {
private UsabilityStudyLogUtils() {
mDate = new Date();
- mDateFormat = new SimpleDateFormat("yyyyMMdd-HHmmss.SSSZ");
+ mDateFormat = new SimpleDateFormat("yyyyMMdd-HHmmss.SSSZ", Locale.US);
HandlerThread handlerThread = new HandlerThread("UsabilityStudyLogUtils logging task",
Process.THREAD_PRIORITY_BACKGROUND);
@@ -255,7 +256,7 @@ public final class Utils {
final long currentTime = System.currentTimeMillis();
mDate.setTime(currentTime);
- final String printString = String.format("%s\t%d\t%s\n",
+ final String printString = String.format(Locale.US, "%s\t%d\t%s\n",
mDateFormat.format(mDate), currentTime, log);
if (LatinImeLogger.sDBG) {
Log.d(USABILITY_TAG, "Write: " + log);
@@ -297,7 +298,7 @@ public final class Utils {
final Date date = new Date();
date.setTime(System.currentTimeMillis());
final String currentDateTimeString =
- new SimpleDateFormat("yyyyMMdd-HHmmssZ").format(date);
+ new SimpleDateFormat("yyyyMMdd-HHmmssZ", Locale.US).format(date);
if (mFile == null) {
Log.w(USABILITY_TAG, "No internal log file found.");
return;
@@ -313,11 +314,15 @@ public final class Utils {
+ "/research-" + currentDateTimeString + ".log";
final File destFile = new File(destPath);
try {
- final FileChannel src = (new FileInputStream(mFile)).getChannel();
- final FileChannel dest = (new FileOutputStream(destFile)).getChannel();
+ final FileInputStream srcStream = new FileInputStream(mFile);
+ final FileOutputStream destStream = new FileOutputStream(destFile);
+ final FileChannel src = srcStream.getChannel();
+ final FileChannel dest = destStream.getChannel();
src.transferTo(0, src.size(), dest);
src.close();
+ srcStream.close();
dest.close();
+ destStream.close();
} catch (FileNotFoundException e1) {
Log.w(USABILITY_TAG, e1);
return;
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index da0071adc..daff442f3 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -38,7 +38,7 @@ public final class WordComposer {
private int[] mPrimaryKeyCodes;
private final InputPointers mInputPointers = new InputPointers(N);
private final StringBuilder mTypedWord;
- private CharSequence mAutoCorrection;
+ private String mAutoCorrection;
private boolean mIsResumed;
private boolean mIsBatchMode;
@@ -64,7 +64,7 @@ public final class WordComposer {
refreshSize();
}
- public WordComposer(WordComposer source) {
+ public WordComposer(final WordComposer source) {
mPrimaryKeyCodes = Arrays.copyOf(source.mPrimaryKeyCodes, source.mPrimaryKeyCodes.length);
mTypedWord = new StringBuilder(source.mTypedWord);
mInputPointers.copy(source.mInputPointers);
@@ -121,7 +121,8 @@ public final class WordComposer {
return mInputPointers;
}
- private static boolean isFirstCharCapitalized(int index, int codePoint, boolean previous) {
+ private static boolean isFirstCharCapitalized(final int index, final int codePoint,
+ final boolean previous) {
if (index == 0) return Character.isUpperCase(codePoint);
return previous && !Character.isUpperCase(codePoint);
}
@@ -129,12 +130,12 @@ public final class WordComposer {
/**
* Add a new keystroke, with the pressed key's code point with the touch point coordinates.
*/
- public void add(int primaryCode, int keyX, int keyY) {
+ public void add(final int primaryCode, final int keyX, final int keyY) {
final int newIndex = size();
mTypedWord.appendCodePoint(primaryCode);
refreshSize();
if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) {
- mPrimaryKeyCodes[newIndex] = primaryCode >= Keyboard.CODE_SPACE
+ mPrimaryKeyCodes[newIndex] = primaryCode >= Constants.CODE_SPACE
? Character.toLowerCase(primaryCode) : primaryCode;
// In the batch input mode, the {@code mInputPointers} holds batch input points and
// shouldn't be overridden by the "typed key" coordinates
@@ -148,7 +149,7 @@ public final class WordComposer {
newIndex, primaryCode, mIsFirstCharCapitalized);
if (Character.isUpperCase(primaryCode)) mCapsCount++;
if (Character.isDigit(primaryCode)) mDigitsCount++;
- if (Keyboard.CODE_SINGLE_QUOTE == primaryCode) {
+ if (Constants.CODE_SINGLE_QUOTE == primaryCode) {
++mTrailingSingleQuotesCount;
} else {
mTrailingSingleQuotesCount = 0;
@@ -156,12 +157,12 @@ public final class WordComposer {
mAutoCorrection = null;
}
- public void setBatchInputPointers(InputPointers batchPointers) {
+ public void setBatchInputPointers(final InputPointers batchPointers) {
mInputPointers.set(batchPointers);
mIsBatchMode = true;
}
- public void setBatchInputWord(CharSequence word) {
+ public void setBatchInputWord(final String word) {
reset();
mIsBatchMode = true;
final int length = word.length();
@@ -235,7 +236,7 @@ public final class WordComposer {
int i = mTypedWord.length();
while (i > 0) {
i = mTypedWord.offsetByCodePoints(i, -1);
- if (Keyboard.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break;
+ if (Constants.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break;
++mTrailingSingleQuotesCount;
}
}
@@ -321,14 +322,14 @@ public final class WordComposer {
/**
* Sets the auto-correction for this word.
*/
- public void setAutoCorrection(final CharSequence correction) {
+ public void setAutoCorrection(final String correction) {
mAutoCorrection = correction;
}
/**
* @return the auto-correction for this word, or null if none.
*/
- public CharSequence getAutoCorrectionOrNull() {
+ public String getAutoCorrectionOrNull() {
return mAutoCorrection;
}
@@ -341,7 +342,7 @@ public final class WordComposer {
// `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above.
public LastComposedWord commitWord(final int type, final String committedWord,
- final String separatorString, final CharSequence prevWord) {
+ final String separatorString, final String prevWord) {
// Note: currently, we come here whenever we commit a word. If it's a MANUAL_PICK
// or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate
// the last composed word to ensure this does not happen.
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
index 7b0231a6b..ee0e9cd7e 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
@@ -16,19 +16,32 @@
package com.android.inputmethod.latin.makedict;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.CharEncoding;
import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface;
import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup;
+import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
import java.io.IOException;
+import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
public final class BinaryDictIOUtils {
private static final boolean DBG = false;
+ private static final int MSB24 = 0x800000;
+ private static final int SINT24_MAX = 0x7FFFFF;
+ private static final int MAX_JUMPS = 10000;
+
+ private BinaryDictIOUtils() {
+ // This utility class is not publicly instantiable.
+ }
private static final class Position {
public static final int NOT_READ_GROUPCOUNT = -1;
@@ -90,7 +103,9 @@ public final class BinaryDictIOUtils {
final boolean isMovedGroup = BinaryDictInputOutput.isMovedGroup(info.mFlags,
formatOptions);
- if (!isMovedGroup
+ final boolean isDeletedGroup = BinaryDictInputOutput.isDeletedGroup(info.mFlags,
+ formatOptions);
+ if (!isMovedGroup && !isDeletedGroup
&& info.mFrequency != FusionDictionary.CharGroup.NOT_A_TERMINAL) {// found word
words.put(info.mOriginalAddress, new String(pushedChars, 0, index));
frequencies.put(info.mOriginalAddress, info.mFrequency);
@@ -153,6 +168,7 @@ public final class BinaryDictIOUtils {
* @throws IOException
* @throws UnsupportedFormatException
*/
+ @UsedForTesting
public static int getTerminalPosition(final FusionDictionaryBufferInterface buffer,
final String word) throws IOException, UnsupportedFormatException {
if (word == null) return FormatSpec.NOT_VALID_WORD;
@@ -165,19 +181,19 @@ public final class BinaryDictIOUtils {
if (wordPos >= wordLen) return FormatSpec.NOT_VALID_WORD;
do {
- int groupOffset = buffer.position() - header.mHeaderSize;
final int charGroupCount = BinaryDictInputOutput.readCharGroupCount(buffer);
- groupOffset += BinaryDictInputOutput.getGroupCountSize(charGroupCount);
-
boolean foundNextCharGroup = false;
for (int i = 0; i < charGroupCount; ++i) {
final int charGroupPos = buffer.position();
final CharGroupInfo currentInfo = BinaryDictInputOutput.readCharGroup(buffer,
buffer.position(), header.mFormatOptions);
- if (BinaryDictInputOutput.isMovedGroup(currentInfo.mFlags,
- header.mFormatOptions)) {
- continue;
- }
+ final boolean isMovedGroup =
+ BinaryDictInputOutput.isMovedGroup(currentInfo.mFlags,
+ header.mFormatOptions);
+ final boolean isDeletedGroup =
+ BinaryDictInputOutput.isDeletedGroup(currentInfo.mFlags,
+ header.mFormatOptions);
+ if (isMovedGroup) continue;
boolean same = true;
for (int p = 0, j = word.offsetByCodePoints(0, wordPos);
p < currentInfo.mCharacters.length;
@@ -192,7 +208,8 @@ public final class BinaryDictIOUtils {
if (same) {
// found the group matches the word.
if (wordPos + currentInfo.mCharacters.length == wordLen) {
- if (currentInfo.mFrequency == CharGroup.NOT_A_TERMINAL) {
+ if (currentInfo.mFrequency == CharGroup.NOT_A_TERMINAL
+ || isDeletedGroup) {
return FormatSpec.NOT_VALID_WORD;
} else {
return charGroupPos;
@@ -206,7 +223,6 @@ public final class BinaryDictIOUtils {
buffer.position(currentInfo.mChildrenAddress);
break;
}
- groupOffset = currentInfo.mEndAddress;
}
// If we found the next char group, it is under the file pointer.
@@ -228,6 +244,10 @@ public final class BinaryDictIOUtils {
return FormatSpec.NOT_VALID_WORD;
}
+ private static int markAsDeleted(final int flags) {
+ return (flags & (~FormatSpec.MASK_GROUP_ADDRESS_TYPE)) | FormatSpec.FLAG_IS_DELETED;
+ }
+
/**
* Delete the word from the binary file.
*
@@ -236,6 +256,7 @@ public final class BinaryDictIOUtils {
* @throws IOException
* @throws UnsupportedFormatException
*/
+ @UsedForTesting
public static void deleteWord(final FusionDictionaryBufferInterface buffer,
final String word) throws IOException, UnsupportedFormatException {
buffer.position(0);
@@ -245,21 +266,58 @@ public final class BinaryDictIOUtils {
buffer.position(wordPosition);
final int flags = buffer.readUnsignedByte();
- final int newFlags = flags ^ FormatSpec.FLAG_IS_TERMINAL;
buffer.position(wordPosition);
- buffer.put((byte)newFlags);
+ buffer.put((byte)markAsDeleted(flags));
}
- private static void putSInt24(final FusionDictionaryBufferInterface buffer,
+ /**
+ * @return the size written, in bytes. Always 3 bytes.
+ */
+ private static int writeSInt24ToBuffer(final FusionDictionaryBufferInterface buffer,
final int value) {
final int absValue = Math.abs(value);
buffer.put((byte)(((value < 0 ? 0x80 : 0) | (absValue >> 16)) & 0xFF));
buffer.put((byte)((absValue >> 8) & 0xFF));
buffer.put((byte)(absValue & 0xFF));
+ return 3;
+ }
+
+ /**
+ * @return the size written, in bytes. Always 3 bytes.
+ */
+ private static int writeSInt24ToStream(final OutputStream destination, final int value)
+ throws IOException {
+ final int absValue = Math.abs(value);
+ destination.write((byte)(((value < 0 ? 0x80 : 0) | (absValue >> 16)) & 0xFF));
+ destination.write((byte)((absValue >> 8) & 0xFF));
+ destination.write((byte)(absValue & 0xFF));
+ return 3;
}
/**
- * Update a parent address in a CharGroup that is addressed by groupOriginAddress.
+ * @return the size written, in bytes. 1, 2, or 3 bytes.
+ */
+ private static int writeVariableAddress(final OutputStream destination, final int value)
+ throws IOException {
+ switch (BinaryDictInputOutput.getByteSize(value)) {
+ case 1:
+ destination.write((byte)value);
+ break;
+ case 2:
+ destination.write((byte)(0xFF & (value >> 8)));
+ destination.write((byte)(0xFF & value));
+ break;
+ case 3:
+ destination.write((byte)(0xFF & (value >> 16)));
+ destination.write((byte)(0xFF & (value >> 8)));
+ destination.write((byte)(0xFF & value));
+ break;
+ }
+ return BinaryDictInputOutput.getByteSize(value);
+ }
+
+ /**
+ * Update a parent address in a CharGroup that is referred to by groupOriginAddress.
*
* @param buffer the buffer to write.
* @param groupOriginAddress the address of the group.
@@ -275,8 +333,648 @@ public final class BinaryDictIOUtils {
throw new RuntimeException("this file format does not support parent addresses");
}
final int flags = buffer.readUnsignedByte();
+ if (BinaryDictInputOutput.isMovedGroup(flags, formatOptions)) {
+ // if the group is moved, the parent address is stored in the destination group.
+ // We are guaranteed to process the destination group later, so there is no need to
+ // update anything here.
+ buffer.position(originalPosition);
+ return;
+ }
+ if (DBG) {
+ MakedictLog.d("update parent address flags=" + flags + ", " + groupOriginAddress);
+ }
final int parentOffset = newParentAddress - groupOriginAddress;
- putSInt24(buffer, parentOffset);
+ writeSInt24ToBuffer(buffer, parentOffset);
+ buffer.position(originalPosition);
+ }
+
+ private static void skipCharGroup(final FusionDictionaryBufferInterface buffer,
+ final FormatOptions formatOptions) {
+ final int flags = buffer.readUnsignedByte();
+ BinaryDictInputOutput.readParentAddress(buffer, formatOptions);
+ skipString(buffer, (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS) != 0);
+ BinaryDictInputOutput.readChildrenAddress(buffer, flags, formatOptions);
+ if ((flags & FormatSpec.FLAG_IS_TERMINAL) != 0) buffer.readUnsignedByte();
+ if ((flags & FormatSpec.FLAG_HAS_SHORTCUT_TARGETS) != 0) {
+ final int shortcutsSize = buffer.readUnsignedShort();
+ buffer.position(buffer.position() + shortcutsSize
+ - FormatSpec.GROUP_SHORTCUT_LIST_SIZE_SIZE);
+ }
+ if ((flags & FormatSpec.FLAG_HAS_BIGRAMS) != 0) {
+ int bigramCount = 0;
+ while (bigramCount++ < FormatSpec.MAX_BIGRAMS_IN_A_GROUP) {
+ final int bigramFlags = buffer.readUnsignedByte();
+ switch (bigramFlags & FormatSpec.MASK_ATTRIBUTE_ADDRESS_TYPE) {
+ case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
+ buffer.readUnsignedByte();
+ break;
+ case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
+ buffer.readUnsignedShort();
+ break;
+ case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
+ buffer.readUnsignedInt24();
+ break;
+ }
+ if ((bigramFlags & FormatSpec.FLAG_ATTRIBUTE_HAS_NEXT) == 0) break;
+ }
+ if (bigramCount >= FormatSpec.MAX_BIGRAMS_IN_A_GROUP) {
+ throw new RuntimeException("Too many bigrams in a group.");
+ }
+ }
+ }
+
+ /**
+ * Update parent addresses in a Node that is referred to by nodeOriginAddress.
+ *
+ * @param buffer the buffer to be modified.
+ * @param nodeOriginAddress the address of a modified Node.
+ * @param newParentAddress the address to be written.
+ * @param formatOptions file format options.
+ */
+ public static void updateParentAddresses(final FusionDictionaryBufferInterface buffer,
+ final int nodeOriginAddress, final int newParentAddress,
+ final FormatOptions formatOptions) {
+ final int originalPosition = buffer.position();
+ buffer.position(nodeOriginAddress);
+ do {
+ final int count = BinaryDictInputOutput.readCharGroupCount(buffer);
+ for (int i = 0; i < count; ++i) {
+ updateParentAddress(buffer, buffer.position(), newParentAddress, formatOptions);
+ skipCharGroup(buffer, formatOptions);
+ }
+ final int forwardLinkAddress = buffer.readUnsignedInt24();
+ buffer.position(forwardLinkAddress);
+ } while (formatOptions.mSupportsDynamicUpdate
+ && buffer.position() != FormatSpec.NO_FORWARD_LINK_ADDRESS);
+ buffer.position(originalPosition);
+ }
+
+ private static void skipString(final FusionDictionaryBufferInterface buffer,
+ final boolean hasMultipleChars) {
+ if (hasMultipleChars) {
+ int character = CharEncoding.readChar(buffer);
+ while (character != FormatSpec.INVALID_CHARACTER) {
+ character = CharEncoding.readChar(buffer);
+ }
+ } else {
+ CharEncoding.readChar(buffer);
+ }
+ }
+
+ /**
+ * Write a string to a stream.
+ *
+ * @param destination the stream to write.
+ * @param word the string to be written.
+ * @return the size written, in bytes.
+ * @throws IOException
+ */
+ private static int writeString(final OutputStream destination, final String word)
+ throws IOException {
+ int size = 0;
+ final int length = word.length();
+ for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
+ final int codePoint = word.codePointAt(i);
+ if (CharEncoding.getCharSize(codePoint) == 1) {
+ destination.write((byte)codePoint);
+ size++;
+ } else {
+ destination.write((byte)(0xFF & (codePoint >> 16)));
+ destination.write((byte)(0xFF & (codePoint >> 8)));
+ destination.write((byte)(0xFF & codePoint));
+ size += 3;
+ }
+ }
+ destination.write((byte)FormatSpec.GROUP_CHARACTERS_TERMINATOR);
+ size += FormatSpec.GROUP_TERMINATOR_SIZE;
+ return size;
+ }
+
+ /**
+ * Update a children address in a CharGroup that is addressed by groupOriginAddress.
+ *
+ * @param buffer the buffer to write.
+ * @param groupOriginAddress the address of the group.
+ * @param newChildrenAddress the absolute address of the child.
+ * @param formatOptions file format options.
+ */
+ public static void updateChildrenAddress(final FusionDictionaryBufferInterface buffer,
+ final int groupOriginAddress, final int newChildrenAddress,
+ final FormatOptions formatOptions) {
+ final int originalPosition = buffer.position();
+ buffer.position(groupOriginAddress);
+ final int flags = buffer.readUnsignedByte();
+ final int parentAddress = BinaryDictInputOutput.readParentAddress(buffer, formatOptions);
+ skipString(buffer, (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS) != 0);
+ if ((flags & FormatSpec.FLAG_IS_TERMINAL) != 0) buffer.readUnsignedByte();
+ final int childrenOffset = newChildrenAddress == FormatSpec.NO_CHILDREN_ADDRESS
+ ? FormatSpec.NO_CHILDREN_ADDRESS : newChildrenAddress - buffer.position();
+ writeSInt24ToBuffer(buffer, childrenOffset);
buffer.position(originalPosition);
}
+
+ /**
+ * Write a char group to an output stream.
+ * A char group is an in-memory representation of a node in trie.
+ * A char group info is an on-disk representation of a node.
+ *
+ * @param destination the stream to write.
+ * @param info the char group info to be written.
+ * @return the size written, in bytes.
+ */
+ public static int writeCharGroup(final OutputStream destination, final CharGroupInfo info)
+ throws IOException {
+ int size = FormatSpec.GROUP_FLAGS_SIZE;
+ destination.write((byte)info.mFlags);
+ final int parentOffset = info.mParentAddress == FormatSpec.NO_PARENT_ADDRESS ?
+ FormatSpec.NO_PARENT_ADDRESS : info.mParentAddress - info.mOriginalAddress;
+ size += writeSInt24ToStream(destination, parentOffset);
+
+ for (int i = 0; i < info.mCharacters.length; ++i) {
+ if (CharEncoding.getCharSize(info.mCharacters[i]) == 1) {
+ destination.write((byte)info.mCharacters[i]);
+ size++;
+ } else {
+ size += writeSInt24ToStream(destination, info.mCharacters[i]);
+ }
+ }
+ if (info.mCharacters.length > 1) {
+ destination.write((byte)FormatSpec.GROUP_CHARACTERS_TERMINATOR);
+ size++;
+ }
+
+ if ((info.mFlags & FormatSpec.FLAG_IS_TERMINAL) != 0) {
+ destination.write((byte)info.mFrequency);
+ size++;
+ }
+
+ if (DBG) {
+ MakedictLog.d("writeCharGroup origin=" + info.mOriginalAddress + ", size=" + size
+ + ", child=" + info.mChildrenAddress + ", characters ="
+ + new String(info.mCharacters, 0, info.mCharacters.length));
+ }
+ final int childrenOffset = info.mChildrenAddress == FormatSpec.NO_CHILDREN_ADDRESS ?
+ 0 : info.mChildrenAddress - (info.mOriginalAddress + size);
+ writeSInt24ToStream(destination, childrenOffset);
+ size += FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE;
+
+ if (info.mShortcutTargets != null && info.mShortcutTargets.size() > 0) {
+ final int shortcutListSize =
+ BinaryDictInputOutput.getShortcutListSize(info.mShortcutTargets);
+ destination.write((byte)(shortcutListSize >> 8));
+ destination.write((byte)(shortcutListSize & 0xFF));
+ size += 2;
+ final Iterator<WeightedString> shortcutIterator = info.mShortcutTargets.iterator();
+ while (shortcutIterator.hasNext()) {
+ final WeightedString target = shortcutIterator.next();
+ destination.write((byte)BinaryDictInputOutput.makeShortcutFlags(
+ shortcutIterator.hasNext(), target.mFrequency));
+ size++;
+ size += writeString(destination, target.mWord);
+ }
+ }
+
+ if (info.mBigrams != null) {
+ // TODO: Consolidate this code with the code that computes the size of the bigram list
+ // in BinaryDictionaryInputOutput#computeActualNodeSize
+ for (int i = 0; i < info.mBigrams.size(); ++i) {
+
+ final int bigramFrequency = info.mBigrams.get(i).mFrequency;
+ int bigramFlags = (i < info.mBigrams.size() - 1)
+ ? FormatSpec.FLAG_ATTRIBUTE_HAS_NEXT : 0;
+ size++;
+ final int bigramOffset = info.mBigrams.get(i).mAddress - (info.mOriginalAddress
+ + size);
+ bigramFlags |= (bigramOffset < 0) ? FormatSpec.FLAG_ATTRIBUTE_OFFSET_NEGATIVE : 0;
+ switch (BinaryDictInputOutput.getByteSize(bigramOffset)) {
+ case 1:
+ bigramFlags |= FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE;
+ break;
+ case 2:
+ bigramFlags |= FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES;
+ break;
+ case 3:
+ bigramFlags |= FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES;
+ break;
+ }
+ bigramFlags |= bigramFrequency & FormatSpec.FLAG_ATTRIBUTE_FREQUENCY;
+ destination.write((byte)bigramFlags);
+ size += writeVariableAddress(destination, Math.abs(bigramOffset));
+ }
+ }
+ return size;
+ }
+
+ @SuppressWarnings("unused")
+ private static void updateForwardLink(final FusionDictionaryBufferInterface buffer,
+ final int nodeOriginAddress, final int newNodeAddress,
+ final FormatOptions formatOptions) {
+ buffer.position(nodeOriginAddress);
+ int jumpCount = 0;
+ while (jumpCount++ < MAX_JUMPS) {
+ final int count = BinaryDictInputOutput.readCharGroupCount(buffer);
+ for (int i = 0; i < count; ++i) skipCharGroup(buffer, formatOptions);
+ final int forwardLinkAddress = buffer.readUnsignedInt24();
+ if (forwardLinkAddress == FormatSpec.NO_FORWARD_LINK_ADDRESS) {
+ buffer.position(buffer.position() - FormatSpec.FORWARD_LINK_ADDRESS_SIZE);
+ writeSInt24ToBuffer(buffer, newNodeAddress);
+ return;
+ }
+ buffer.position(forwardLinkAddress);
+ }
+ if (DBG && jumpCount >= MAX_JUMPS) {
+ throw new RuntimeException("too many jumps, probably a bug.");
+ }
+ }
+
+ /**
+ * Helper method to move a char group to the tail of the file.
+ */
+ private static int moveCharGroup(final OutputStream destination,
+ final FusionDictionaryBufferInterface buffer, final CharGroupInfo info,
+ final int nodeOriginAddress, final int oldGroupAddress,
+ final FormatOptions formatOptions) throws IOException {
+ updateParentAddress(buffer, oldGroupAddress, buffer.limit() + 1, formatOptions);
+ buffer.position(oldGroupAddress);
+ final int currentFlags = buffer.readUnsignedByte();
+ buffer.position(oldGroupAddress);
+ buffer.put((byte)(FormatSpec.FLAG_IS_MOVED | (currentFlags
+ & (~FormatSpec.MASK_MOVE_AND_DELETE_FLAG))));
+ int size = FormatSpec.GROUP_FLAGS_SIZE;
+ updateForwardLink(buffer, nodeOriginAddress, buffer.limit(), formatOptions);
+ size += writeNode(destination, new CharGroupInfo[] { info });
+ return size;
+ }
+
+ /**
+ * Compute the size of the char group.
+ */
+ private static int computeGroupSize(final CharGroupInfo info,
+ final FormatOptions formatOptions) {
+ int size = FormatSpec.GROUP_FLAGS_SIZE + FormatSpec.PARENT_ADDRESS_SIZE
+ + BinaryDictInputOutput.getGroupCharactersSize(info.mCharacters)
+ + BinaryDictInputOutput.getChildrenAddressSize(info.mFlags, formatOptions);
+ if ((info.mFlags & FormatSpec.FLAG_IS_TERMINAL) != 0) {
+ size += FormatSpec.GROUP_FREQUENCY_SIZE;
+ }
+ if (info.mShortcutTargets != null && !info.mShortcutTargets.isEmpty()) {
+ size += BinaryDictInputOutput.getShortcutListSize(info.mShortcutTargets);
+ }
+ if (info.mBigrams != null) {
+ for (final PendingAttribute attr : info.mBigrams) {
+ size += FormatSpec.GROUP_FLAGS_SIZE;
+ size += BinaryDictInputOutput.getByteSize(attr.mAddress);
+ }
+ }
+ return size;
+ }
+
+ /**
+ * Write a node to the stream.
+ *
+ * @param destination the stream to write.
+ * @param infos groups to be written.
+ * @return the size written, in bytes.
+ * @throws IOException
+ */
+ private static int writeNode(final OutputStream destination, final CharGroupInfo[] infos)
+ throws IOException {
+ int size = BinaryDictInputOutput.getGroupCountSize(infos.length);
+ switch (BinaryDictInputOutput.getGroupCountSize(infos.length)) {
+ case 1:
+ destination.write((byte)infos.length);
+ break;
+ case 2:
+ destination.write((byte)(infos.length >> 8));
+ destination.write((byte)(infos.length & 0xFF));
+ break;
+ default:
+ throw new RuntimeException("Invalid group count size.");
+ }
+ for (final CharGroupInfo info : infos) size += writeCharGroup(destination, info);
+ writeSInt24ToStream(destination, FormatSpec.NO_FORWARD_LINK_ADDRESS);
+ return size + FormatSpec.FORWARD_LINK_ADDRESS_SIZE;
+ }
+
+ /**
+ * Move a group that is referred to by oldGroupOrigin to the tail of the file.
+ * And set the children address to the byte after the group.
+ *
+ * @param nodeOrigin the address of the tail of the file.
+ * @param characters
+ * @param length
+ * @param flags
+ * @param frequency
+ * @param parentAddress
+ * @param shortcutTargets
+ * @param bigrams
+ * @param destination the stream representing the tail of the file.
+ * @param buffer the buffer representing the (constant-size) body of the file.
+ * @param oldNodeOrigin
+ * @param oldGroupOrigin
+ * @param formatOptions
+ * @return the size written, in bytes.
+ * @throws IOException
+ */
+ private static int moveGroup(final int nodeOrigin, final int[] characters, final int length,
+ final int flags, final int frequency, final int parentAddress,
+ final ArrayList<WeightedString> shortcutTargets,
+ final ArrayList<PendingAttribute> bigrams, final OutputStream destination,
+ final FusionDictionaryBufferInterface buffer, final int oldNodeOrigin,
+ final int oldGroupOrigin, final FormatOptions formatOptions) throws IOException {
+ int size = 0;
+ final int newGroupOrigin = nodeOrigin + 1;
+ final int[] writtenCharacters = Arrays.copyOfRange(characters, 0, length);
+ final CharGroupInfo tmpInfo = new CharGroupInfo(newGroupOrigin, -1 /* endAddress */,
+ flags, writtenCharacters, frequency, parentAddress, FormatSpec.NO_CHILDREN_ADDRESS,
+ shortcutTargets, bigrams);
+ size = computeGroupSize(tmpInfo, formatOptions);
+ final CharGroupInfo newInfo = new CharGroupInfo(newGroupOrigin, newGroupOrigin + size,
+ flags, writtenCharacters, frequency, parentAddress,
+ nodeOrigin + 1 + size + FormatSpec.FORWARD_LINK_ADDRESS_SIZE, shortcutTargets,
+ bigrams);
+ moveCharGroup(destination, buffer, newInfo, oldNodeOrigin, oldGroupOrigin, formatOptions);
+ return 1 + size + FormatSpec.FORWARD_LINK_ADDRESS_SIZE;
+ }
+
+ /**
+ * Insert a word into a binary dictionary.
+ *
+ * @param buffer
+ * @param destination
+ * @param word
+ * @param frequency
+ * @param bigramStrings
+ * @param shortcuts
+ * @throws IOException
+ * @throws UnsupportedFormatException
+ */
+ // TODO: Support batch insertion.
+ // TODO: Remove @UsedForTesting once UserHistoryDictionary is implemented by BinaryDictionary.
+ @UsedForTesting
+ public static void insertWord(final FusionDictionaryBufferInterface buffer,
+ final OutputStream destination, final String word, final int frequency,
+ final ArrayList<WeightedString> bigramStrings,
+ final ArrayList<WeightedString> shortcuts, final boolean isNotAWord,
+ final boolean isBlackListEntry)
+ throws IOException, UnsupportedFormatException {
+ final ArrayList<PendingAttribute> bigrams = new ArrayList<PendingAttribute>();
+ if (bigramStrings != null) {
+ for (final WeightedString bigram : bigramStrings) {
+ int position = getTerminalPosition(buffer, bigram.mWord);
+ if (position == FormatSpec.NOT_VALID_WORD) {
+ // TODO: figure out what is the correct thing to do here.
+ } else {
+ bigrams.add(new PendingAttribute(bigram.mFrequency, position));
+ }
+ }
+ }
+
+ final boolean isTerminal = true;
+ final boolean hasBigrams = !bigrams.isEmpty();
+ final boolean hasShortcuts = shortcuts != null && !shortcuts.isEmpty();
+
+ // find the insert position of the word.
+ if (buffer.position() != 0) buffer.position(0);
+ final FileHeader header = BinaryDictInputOutput.readHeader(buffer);
+
+ int wordPos = 0, address = buffer.position(), nodeOriginAddress = buffer.position();
+ final int[] codePoints = FusionDictionary.getCodePoints(word);
+ final int wordLen = codePoints.length;
+
+ for (int depth = 0; depth < Constants.Dictionary.MAX_WORD_LENGTH; ++depth) {
+ if (wordPos >= wordLen) break;
+ nodeOriginAddress = buffer.position();
+ int nodeParentAddress = -1;
+ final int charGroupCount = BinaryDictInputOutput.readCharGroupCount(buffer);
+ boolean foundNextGroup = false;
+
+ for (int i = 0; i < charGroupCount; ++i) {
+ address = buffer.position();
+ final CharGroupInfo currentInfo = BinaryDictInputOutput.readCharGroup(buffer,
+ buffer.position(), header.mFormatOptions);
+ final boolean isMovedGroup = BinaryDictInputOutput.isMovedGroup(currentInfo.mFlags,
+ header.mFormatOptions);
+ if (isMovedGroup) continue;
+ nodeParentAddress = (currentInfo.mParentAddress == FormatSpec.NO_PARENT_ADDRESS)
+ ? FormatSpec.NO_PARENT_ADDRESS : currentInfo.mParentAddress + address;
+ boolean matched = true;
+ for (int p = 0; p < currentInfo.mCharacters.length; ++p) {
+ if (wordPos + p >= wordLen) {
+ /*
+ * splitting
+ * before
+ * abcd - ef
+ *
+ * insert "abc"
+ *
+ * after
+ * abc - d - ef
+ */
+ final int newNodeAddress = buffer.limit();
+ final int flags = BinaryDictInputOutput.makeCharGroupFlags(p > 1,
+ isTerminal, 0, hasShortcuts, hasBigrams, false /* isNotAWord */,
+ false /* isBlackListEntry */, header.mFormatOptions);
+ int written = moveGroup(newNodeAddress, currentInfo.mCharacters, p, flags,
+ frequency, nodeParentAddress, shortcuts, bigrams, destination,
+ buffer, nodeOriginAddress, address, header.mFormatOptions);
+
+ final int[] characters2 = Arrays.copyOfRange(currentInfo.mCharacters, p,
+ currentInfo.mCharacters.length);
+ if (currentInfo.mChildrenAddress != FormatSpec.NO_CHILDREN_ADDRESS) {
+ updateParentAddresses(buffer, currentInfo.mChildrenAddress,
+ newNodeAddress + written + 1, header.mFormatOptions);
+ }
+ final CharGroupInfo newInfo2 = new CharGroupInfo(
+ newNodeAddress + written + 1, -1 /* endAddress */,
+ currentInfo.mFlags, characters2, currentInfo.mFrequency,
+ newNodeAddress + 1, currentInfo.mChildrenAddress,
+ currentInfo.mShortcutTargets, currentInfo.mBigrams);
+ writeNode(destination, new CharGroupInfo[] { newInfo2 });
+ return;
+ } else if (codePoints[wordPos + p] != currentInfo.mCharacters[p]) {
+ if (p > 0) {
+ /*
+ * splitting
+ * before
+ * ab - cd
+ *
+ * insert "ac"
+ *
+ * after
+ * a - b - cd
+ * |
+ * - c
+ */
+
+ final int newNodeAddress = buffer.limit();
+ final int childrenAddress = currentInfo.mChildrenAddress;
+
+ // move prefix
+ final int prefixFlags = BinaryDictInputOutput.makeCharGroupFlags(p > 1,
+ false /* isTerminal */, 0 /* childrenAddressSize*/,
+ false /* hasShortcut */, false /* hasBigrams */,
+ false /* isNotAWord */, false /* isBlackListEntry */,
+ header.mFormatOptions);
+ int written = moveGroup(newNodeAddress, currentInfo.mCharacters, p,
+ prefixFlags, -1 /* frequency */, nodeParentAddress, null, null,
+ destination, buffer, nodeOriginAddress, address,
+ header.mFormatOptions);
+
+ final int[] suffixCharacters = Arrays.copyOfRange(
+ currentInfo.mCharacters, p, currentInfo.mCharacters.length);
+ if (currentInfo.mChildrenAddress != FormatSpec.NO_CHILDREN_ADDRESS) {
+ updateParentAddresses(buffer, currentInfo.mChildrenAddress,
+ newNodeAddress + written + 1, header.mFormatOptions);
+ }
+ final int suffixFlags = BinaryDictInputOutput.makeCharGroupFlags(
+ suffixCharacters.length > 1,
+ (currentInfo.mFlags & FormatSpec.FLAG_IS_TERMINAL) != 0,
+ 0 /* childrenAddressSize */,
+ (currentInfo.mFlags & FormatSpec.FLAG_HAS_SHORTCUT_TARGETS)
+ != 0,
+ (currentInfo.mFlags & FormatSpec.FLAG_HAS_BIGRAMS) != 0,
+ isNotAWord, isBlackListEntry, header.mFormatOptions);
+ final CharGroupInfo suffixInfo = new CharGroupInfo(
+ newNodeAddress + written + 1, -1 /* endAddress */, suffixFlags,
+ suffixCharacters, currentInfo.mFrequency, newNodeAddress + 1,
+ currentInfo.mChildrenAddress, currentInfo.mShortcutTargets,
+ currentInfo.mBigrams);
+ written += computeGroupSize(suffixInfo, header.mFormatOptions) + 1;
+
+ final int[] newCharacters = Arrays.copyOfRange(codePoints, wordPos + p,
+ codePoints.length);
+ final int flags = BinaryDictInputOutput.makeCharGroupFlags(
+ newCharacters.length > 1, isTerminal,
+ 0 /* childrenAddressSize */, hasShortcuts, hasBigrams,
+ isNotAWord, isBlackListEntry, header.mFormatOptions);
+ final CharGroupInfo newInfo = new CharGroupInfo(
+ newNodeAddress + written, -1 /* endAddress */, flags,
+ newCharacters, frequency, newNodeAddress + 1,
+ FormatSpec.NO_CHILDREN_ADDRESS, shortcuts, bigrams);
+ writeNode(destination, new CharGroupInfo[] { suffixInfo, newInfo });
+ return;
+ }
+ matched = false;
+ break;
+ }
+ }
+
+ if (matched) {
+ if (wordPos + currentInfo.mCharacters.length == wordLen) {
+ // the word exists in the dictionary.
+ // only update group.
+ final int newNodeAddress = buffer.limit();
+ final boolean hasMultipleChars = currentInfo.mCharacters.length > 1;
+ final int flags = BinaryDictInputOutput.makeCharGroupFlags(hasMultipleChars,
+ isTerminal, 0 /* childrenAddressSize */, hasShortcuts, hasBigrams,
+ isNotAWord, isBlackListEntry, header.mFormatOptions);
+ final CharGroupInfo newInfo = new CharGroupInfo(newNodeAddress + 1,
+ -1 /* endAddress */, flags, currentInfo.mCharacters, frequency,
+ nodeParentAddress, currentInfo.mChildrenAddress, shortcuts,
+ bigrams);
+ moveCharGroup(destination, buffer, newInfo, nodeOriginAddress, address,
+ header.mFormatOptions);
+ return;
+ }
+ wordPos += currentInfo.mCharacters.length;
+ if (currentInfo.mChildrenAddress == FormatSpec.NO_CHILDREN_ADDRESS) {
+ /*
+ * found the prefix of the word.
+ * make new node and link to the node from this group.
+ *
+ * before
+ * ab - cd
+ *
+ * insert "abcde"
+ *
+ * after
+ * ab - cd - e
+ */
+ final int newNodeAddress = buffer.limit();
+ updateChildrenAddress(buffer, address, newNodeAddress,
+ header.mFormatOptions);
+ final int newGroupAddress = newNodeAddress + 1;
+ final boolean hasMultipleChars = (wordLen - wordPos) > 1;
+ final int flags = BinaryDictInputOutput.makeCharGroupFlags(hasMultipleChars,
+ isTerminal, 0 /* childrenAddressSize */, hasShortcuts, hasBigrams,
+ isNotAWord, isBlackListEntry, header.mFormatOptions);
+ final int[] characters = Arrays.copyOfRange(codePoints, wordPos, wordLen);
+ final CharGroupInfo newInfo = new CharGroupInfo(newGroupAddress, -1, flags,
+ characters, frequency, address, FormatSpec.NO_CHILDREN_ADDRESS,
+ shortcuts, bigrams);
+ writeNode(destination, new CharGroupInfo[] { newInfo });
+ return;
+ }
+ buffer.position(currentInfo.mChildrenAddress);
+ foundNextGroup = true;
+ break;
+ }
+ }
+
+ if (foundNextGroup) continue;
+
+ // reached the end of the array.
+ final int linkAddressPosition = buffer.position();
+ int nextLink = buffer.readUnsignedInt24();
+ if ((nextLink & MSB24) != 0) {
+ nextLink = -(nextLink & SINT24_MAX);
+ }
+ if (nextLink == FormatSpec.NO_FORWARD_LINK_ADDRESS) {
+ /*
+ * expand this node.
+ *
+ * before
+ * ab - cd
+ *
+ * insert "abef"
+ *
+ * after
+ * ab - cd
+ * |
+ * - ef
+ */
+
+ // change the forward link address.
+ final int newNodeAddress = buffer.limit();
+ buffer.position(linkAddressPosition);
+ writeSInt24ToBuffer(buffer, newNodeAddress);
+
+ final int[] characters = Arrays.copyOfRange(codePoints, wordPos, wordLen);
+ final int flags = BinaryDictInputOutput.makeCharGroupFlags(characters.length > 1,
+ isTerminal, 0 /* childrenAddressSize */, hasShortcuts, hasBigrams,
+ isNotAWord, isBlackListEntry, header.mFormatOptions);
+ final CharGroupInfo newInfo = new CharGroupInfo(newNodeAddress + 1,
+ -1 /* endAddress */, flags, characters, frequency, nodeParentAddress,
+ FormatSpec.NO_CHILDREN_ADDRESS, shortcuts, bigrams);
+ writeNode(destination, new CharGroupInfo[]{ newInfo });
+ return;
+ } else {
+ depth--;
+ buffer.position(nextLink);
+ }
+ }
+ }
+
+ /**
+ * Find a word from the buffer.
+ *
+ * @param buffer the buffer representing the body of the dictionary file.
+ * @param word the word searched
+ * @return the found group
+ * @throws IOException
+ * @throws UnsupportedFormatException
+ */
+ @UsedForTesting
+ public static CharGroupInfo findWordFromBuffer(final FusionDictionaryBufferInterface buffer,
+ final String word) throws IOException, UnsupportedFormatException {
+ int position = getTerminalPosition(buffer, word);
+ if (position != FormatSpec.NOT_VALID_WORD) {
+ buffer.position(0);
+ final FileHeader header = BinaryDictInputOutput.readHeader(buffer);
+ buffer.position(position);
+ return BinaryDictInputOutput.readCharGroup(buffer, position, header.mFormatOptions);
+ }
+ return null;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
index b431a4da9..f1a7e97e8 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin.makedict;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup;
@@ -76,12 +77,12 @@ public final class BinaryDictInputOutput {
@Override
public int readUnsignedByte() {
- return ((int)mBuffer.get()) & 0xFF;
+ return mBuffer.get() & 0xFF;
}
@Override
public int readUnsignedShort() {
- return ((int)mBuffer.getShort()) & 0xFFFF;
+ return mBuffer.getShort() & 0xFFFF;
}
@Override
@@ -124,8 +125,7 @@ public final class BinaryDictInputOutput {
/**
* A class grouping utility function for our specific character encoding.
*/
- private static final class CharEncoding {
-
+ static final class CharEncoding {
private static final int MINIMAL_ONE_BYTE_CHARACTER_VALUE = 0x20;
private static final int MAXIMAL_ONE_BYTE_CHARACTER_VALUE = 0xFF;
@@ -154,7 +154,7 @@ public final class BinaryDictInputOutput {
* @param character the character code.
* @return the size in binary encoded-form, either 1 or 3 bytes.
*/
- private static int getCharSize(final int character) {
+ static int getCharSize(final int character) {
// See char encoding in FusionDictionary.java
if (fitsOnOneByte(character)) return 1;
if (FormatSpec.INVALID_CHARACTER == character) return 1;
@@ -263,7 +263,7 @@ public final class BinaryDictInputOutput {
* @param buffer the buffer, positioned over an encoded character.
* @return the character code.
*/
- private static int readChar(final FusionDictionaryBufferInterface buffer) {
+ static int readChar(final FusionDictionaryBufferInterface buffer) {
int character = buffer.readUnsignedByte();
if (!fitsOnOneByte(character)) {
if (FormatSpec.GROUP_CHARACTERS_TERMINATOR == character) {
@@ -277,6 +277,21 @@ public final class BinaryDictInputOutput {
}
/**
+ * Compute the binary size of the character array.
+ *
+ * If only one character, this is the size of this character. If many, it's the sum of their
+ * sizes + 1 byte for the terminator.
+ *
+ * @param characters the character array
+ * @return the size of the char array, including the terminator if any
+ */
+ static int getGroupCharactersSize(final int[] characters) {
+ int size = CharEncoding.getCharArraySize(characters);
+ if (characters.length > 1) size += FormatSpec.GROUP_TERMINATOR_SIZE;
+ return size;
+ }
+
+ /**
* Compute the binary size of the character array in a group
*
* If only one character, this is the size of this character. If many, it's the sum of their
@@ -286,9 +301,7 @@ public final class BinaryDictInputOutput {
* @return the size of the char array, including the terminator if any
*/
private static int getGroupCharactersSize(final CharGroup group) {
- int size = CharEncoding.getCharArraySize(group.mChars);
- if (group.hasSeveralChars()) size += FormatSpec.GROUP_TERMINATOR_SIZE;
- return size;
+ return getGroupCharactersSize(group.mChars);
}
/**
@@ -338,7 +351,7 @@ public final class BinaryDictInputOutput {
* This is known in advance and does not change according to position in the file
* like address lists do.
*/
- private static int getShortcutListSize(final ArrayList<WeightedString> shortcutList) {
+ static int getShortcutListSize(final ArrayList<WeightedString> shortcutList) {
if (null == shortcutList) return 0;
int size = FormatSpec.GROUP_SHORTCUT_LIST_SIZE_SIZE;
for (final WeightedString shortcut : shortcutList) {
@@ -399,7 +412,16 @@ public final class BinaryDictInputOutput {
* Helper method to check whether the group is moved.
*/
public static boolean isMovedGroup(final int flags, final FormatOptions options) {
- return options.mSupportsDynamicUpdate && ((flags & FormatSpec.FLAG_IS_MOVED) == 1);
+ return options.mSupportsDynamicUpdate
+ && ((flags & FormatSpec.MASK_GROUP_ADDRESS_TYPE) == FormatSpec.FLAG_IS_MOVED);
+ }
+
+ /**
+ * Helper method to check whether the group is deleted.
+ */
+ public static boolean isDeletedGroup(final int flags, final FormatOptions formatOptions) {
+ return formatOptions.mSupportsDynamicUpdate
+ && ((flags & FormatSpec.MASK_GROUP_ADDRESS_TYPE) == FormatSpec.FLAG_IS_DELETED);
}
/**
@@ -439,7 +461,7 @@ public final class BinaryDictInputOutput {
* @param address the address
* @return the byte size.
*/
- private static int getByteSize(final int address) {
+ static int getByteSize(final int address) {
assert(address <= UINT24_MAX);
if (!hasChildrenAddress(address)) {
return 0;
@@ -452,11 +474,8 @@ public final class BinaryDictInputOutput {
}
}
- private static final int SINT8_MAX = 0x7F;
- private static final int SINT16_MAX = 0x7FFF;
private static final int SINT24_MAX = 0x7FFFFF;
private static final int MSB8 = 0x80;
- private static final int MSB16 = 0x8000;
private static final int MSB24 = 0x800000;
// End utility methods.
@@ -721,53 +740,60 @@ public final class BinaryDictInputOutput {
return 3;
}
- private static byte makeCharGroupFlags(final CharGroup group, final int groupAddress,
- final int childrenOffset, final FormatOptions formatOptions) {
+ /**
+ * Makes the flag value for a char group.
+ *
+ * @param hasMultipleChars whether the group has multiple chars.
+ * @param isTerminal whether the group is terminal.
+ * @param childrenAddressSize the size of a children address.
+ * @param hasShortcuts whether the group has shortcuts.
+ * @param hasBigrams whether the group has bigrams.
+ * @param isNotAWord whether the group is not a word.
+ * @param isBlackListEntry whether the group is a blacklist entry.
+ * @param formatOptions file format options.
+ * @return the flags
+ */
+ static int makeCharGroupFlags(final boolean hasMultipleChars, final boolean isTerminal,
+ final int childrenAddressSize, final boolean hasShortcuts, final boolean hasBigrams,
+ final boolean isNotAWord, final boolean isBlackListEntry,
+ final FormatOptions formatOptions) {
byte flags = 0;
- if (group.mChars.length > 1) flags |= FormatSpec.FLAG_HAS_MULTIPLE_CHARS;
- if (group.mFrequency >= 0) {
- flags |= FormatSpec.FLAG_IS_TERMINAL;
- }
- if (null != group.mChildren) {
- final int byteSize = formatOptions.mSupportsDynamicUpdate
- ? FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE : getByteSize(childrenOffset);
- switch (byteSize) {
- case 1:
- flags |= FormatSpec.FLAG_GROUP_ADDRESS_TYPE_ONEBYTE;
- break;
- case 2:
- flags |= FormatSpec.FLAG_GROUP_ADDRESS_TYPE_TWOBYTES;
- break;
- case 3:
- flags |= FormatSpec.FLAG_GROUP_ADDRESS_TYPE_THREEBYTES;
- break;
- default:
- throw new RuntimeException("Node with a strange address");
- }
- } else if (formatOptions.mSupportsDynamicUpdate) {
- flags |= FormatSpec.FLAG_GROUP_ADDRESS_TYPE_THREEBYTES;
- }
- if (null != group.mShortcutTargets) {
- if (DBG && 0 == group.mShortcutTargets.size()) {
- throw new RuntimeException("0-sized shortcut list must be null");
- }
- flags |= FormatSpec.FLAG_HAS_SHORTCUT_TARGETS;
- }
- if (null != group.mBigrams) {
- if (DBG && 0 == group.mBigrams.size()) {
- throw new RuntimeException("0-sized bigram list must be null");
+ if (hasMultipleChars) flags |= FormatSpec.FLAG_HAS_MULTIPLE_CHARS;
+ if (isTerminal) flags |= FormatSpec.FLAG_IS_TERMINAL;
+ if (formatOptions.mSupportsDynamicUpdate) {
+ flags |= FormatSpec.FLAG_IS_NOT_MOVED;
+ } else if (true) {
+ switch (childrenAddressSize) {
+ case 1:
+ flags |= FormatSpec.FLAG_GROUP_ADDRESS_TYPE_ONEBYTE;
+ break;
+ case 2:
+ flags |= FormatSpec.FLAG_GROUP_ADDRESS_TYPE_TWOBYTES;
+ break;
+ case 3:
+ flags |= FormatSpec.FLAG_GROUP_ADDRESS_TYPE_THREEBYTES;
+ break;
+ case 0:
+ flags |= FormatSpec.FLAG_GROUP_ADDRESS_TYPE_NOADDRESS;
+ break;
+ default:
+ throw new RuntimeException("Node with a strange address");
}
- flags |= FormatSpec.FLAG_HAS_BIGRAMS;
- }
- if (group.mIsNotAWord) {
- flags |= FormatSpec.FLAG_IS_NOT_A_WORD;
- }
- if (group.mIsBlacklistEntry) {
- flags |= FormatSpec.FLAG_IS_BLACKLISTED;
}
+ if (hasShortcuts) flags |= FormatSpec.FLAG_HAS_SHORTCUT_TARGETS;
+ if (hasBigrams) flags |= FormatSpec.FLAG_HAS_BIGRAMS;
+ if (isNotAWord) flags |= FormatSpec.FLAG_IS_NOT_A_WORD;
+ if (isBlackListEntry) flags |= FormatSpec.FLAG_IS_BLACKLISTED;
return flags;
}
+ private static byte makeCharGroupFlags(final CharGroup group, final int groupAddress,
+ final int childrenOffset, final FormatOptions formatOptions) {
+ return (byte) makeCharGroupFlags(group.mChars.length > 1, group.mFrequency >= 0,
+ getByteSize(childrenOffset), group.mShortcutTargets != null, group.mBigrams != null,
+ group.mIsNotAWord, group.mIsBlacklistEntry, formatOptions);
+ }
+
/**
* Makes the flag value for a bigram.
*
@@ -859,7 +885,7 @@ public final class BinaryDictInputOutput {
* @param frequency the frequency of the attribute, 0..15
* @return the flags
*/
- private static final int makeShortcutFlags(final boolean more, final int frequency) {
+ static final int makeShortcutFlags(final boolean more, final int frequency) {
return (more ? FormatSpec.FLAG_ATTRIBUTE_HAS_NEXT : 0)
+ (frequency & FormatSpec.FLAG_ATTRIBUTE_FREQUENCY);
}
@@ -895,8 +921,10 @@ public final class BinaryDictInputOutput {
* @param formatOptions file format options.
* @return the address of the END of the node.
*/
+ @SuppressWarnings("unused")
private static int writePlacedNode(final FusionDictionary dict, byte[] buffer,
final Node node, final FormatOptions formatOptions) {
+ // TODO: Make the code in common with BinaryDictIOUtils#writeCharGroup
int index = node.mCachedAddress;
final int groupCount = node.mData.size();
@@ -1178,7 +1206,7 @@ public final class BinaryDictInputOutput {
// Input methods: Read a binary dictionary to memory.
// readDictionaryBinary is the public entry point for them.
- private static int getChildrenAddressSize(final int optionFlags,
+ static int getChildrenAddressSize(final int optionFlags,
final FormatOptions formatOptions) {
if (formatOptions.mSupportsDynamicUpdate) return FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE;
switch (optionFlags & FormatSpec.MASK_GROUP_ADDRESS_TYPE) {
@@ -1194,7 +1222,7 @@ public final class BinaryDictInputOutput {
}
}
- private static int readChildrenAddress(final FusionDictionaryBufferInterface buffer,
+ static int readChildrenAddress(final FusionDictionaryBufferInterface buffer,
final int optionFlags, final FormatOptions options) {
if (options.mSupportsDynamicUpdate) {
final int address = buffer.readUnsignedInt24();
@@ -1219,7 +1247,7 @@ public final class BinaryDictInputOutput {
}
}
- private static int readParentAddress(final FusionDictionaryBufferInterface buffer,
+ static int readParentAddress(final FusionDictionaryBufferInterface buffer,
final FormatOptions formatOptions) {
if (supportsDynamicUpdate(formatOptions)) {
final int parentAddress = buffer.readUnsignedInt24();
@@ -1290,7 +1318,8 @@ public final class BinaryDictInputOutput {
ArrayList<PendingAttribute> bigrams = null;
if (0 != (flags & FormatSpec.FLAG_HAS_BIGRAMS)) {
bigrams = new ArrayList<PendingAttribute>();
- while (true) {
+ int bigramCount = 0;
+ while (bigramCount++ < FormatSpec.MAX_BIGRAMS_IN_A_GROUP) {
final int bigramFlags = buffer.readUnsignedByte();
++addressPointer;
final int sign = 0 == (bigramFlags & FormatSpec.FLAG_ATTRIBUTE_OFFSET_NEGATIVE)
@@ -1318,6 +1347,9 @@ public final class BinaryDictInputOutput {
bigramAddress));
if (0 == (bigramFlags & FormatSpec.FLAG_ATTRIBUTE_HAS_NEXT)) break;
}
+ if (bigramCount >= FormatSpec.MAX_BIGRAMS_IN_A_GROUP) {
+ MakedictLog.d("too many bigrams in a group.");
+ }
}
return new CharGroupInfo(originalGroupAddress, addressPointer, flags, characters, frequency,
parentAddress, childrenAddress, shortcutTargets, bigrams);
@@ -1340,7 +1372,8 @@ public final class BinaryDictInputOutput {
// of this method. Since it performs direct, unbuffered random access to the file and
// may be called hundreds of thousands of times, the resulting performance is not
// reasonable without some kind of cache. Thus:
- private static TreeMap<Integer, String> wordCache = new TreeMap<Integer, String>();
+ private static TreeMap<Integer, WeightedString> wordCache =
+ new TreeMap<Integer, WeightedString>();
/**
* Finds, as a string, the word at the address passed as an argument.
*
@@ -1348,15 +1381,15 @@ public final class BinaryDictInputOutput {
* @param headerSize the size of the header.
* @param address the address to seek.
* @param formatOptions file format options.
- * @return the word, as a string.
+ * @return the word with its frequency, as a weighted string.
*/
- /* packages for tests */ static String getWordAtAddress(
+ /* package for tests */ static WeightedString getWordAtAddress(
final FusionDictionaryBufferInterface buffer, final int headerSize, final int address,
final FormatOptions formatOptions) {
- final String cachedString = wordCache.get(address);
+ final WeightedString cachedString = wordCache.get(address);
if (null != cachedString) return cachedString;
- final String result;
+ final WeightedString result;
final int originalPointer = buffer.position();
buffer.position(address);
@@ -1372,14 +1405,16 @@ public final class BinaryDictInputOutput {
return result;
}
+ // TODO: static!? This will behave erratically when used in multi-threaded code.
+ // We need to fix this
private static int[] sGetWordBuffer = new int[FormatSpec.MAX_WORD_LENGTH];
- private static String getWordAtAddressWithParentAddress(
+ @SuppressWarnings("unused")
+ private static WeightedString getWordAtAddressWithParentAddress(
final FusionDictionaryBufferInterface buffer, final int headerSize, final int address,
final FormatOptions options) {
- final StringBuilder builder = new StringBuilder();
-
int currentAddress = address;
int index = FormatSpec.MAX_WORD_LENGTH - 1;
+ int frequency = Integer.MIN_VALUE;
// the length of the path from the root to the leaf is limited by MAX_WORD_LENGTH
for (int count = 0; count < FormatSpec.MAX_WORD_LENGTH; ++count) {
CharGroupInfo currentInfo;
@@ -1394,6 +1429,7 @@ public final class BinaryDictInputOutput {
MakedictLog.d("Too many jumps - probably a bug");
}
} while (isMovedGroup(currentInfo.mFlags, options));
+ if (Integer.MIN_VALUE == frequency) frequency = currentInfo.mFrequency;
for (int i = 0; i < currentInfo.mCharacters.length; ++i) {
sGetWordBuffer[index--] =
currentInfo.mCharacters[currentInfo.mCharacters.length - i - 1];
@@ -1402,17 +1438,19 @@ public final class BinaryDictInputOutput {
currentAddress = currentInfo.mParentAddress + currentInfo.mOriginalAddress;
}
- return new String(sGetWordBuffer, index + 1, FormatSpec.MAX_WORD_LENGTH - index - 1);
+ return new WeightedString(
+ new String(sGetWordBuffer, index + 1, FormatSpec.MAX_WORD_LENGTH - index - 1),
+ frequency);
}
- private static String getWordAtAddressWithoutParentAddress(
+ private static WeightedString getWordAtAddressWithoutParentAddress(
final FusionDictionaryBufferInterface buffer, final int headerSize, final int address,
final FormatOptions options) {
buffer.position(headerSize);
final int count = readCharGroupCount(buffer);
int groupOffset = getGroupCountSize(count);
final StringBuilder builder = new StringBuilder();
- String result = null;
+ WeightedString result = null;
CharGroupInfo last = null;
for (int i = count - 1; i >= 0; --i) {
@@ -1420,7 +1458,7 @@ public final class BinaryDictInputOutput {
groupOffset = info.mEndAddress;
if (info.mOriginalAddress == address) {
builder.append(new String(info.mCharacters, 0, info.mCharacters.length));
- result = builder.toString();
+ result = new WeightedString(builder.toString(), info.mFrequency);
break; // and return
}
if (hasChildrenAddress(info.mChildrenAddress)) {
@@ -1481,9 +1519,11 @@ public final class BinaryDictInputOutput {
if (null != info.mBigrams) {
bigrams = new ArrayList<WeightedString>();
for (PendingAttribute bigram : info.mBigrams) {
- final String word = getWordAtAddress(
+ final WeightedString word = getWordAtAddress(
buffer, headerSize, bigram.mAddress, options);
- bigrams.add(new WeightedString(word, bigram.mFrequency));
+ final int reconstructedFrequency =
+ reconstructBigramFrequency(word.mFrequency, bigram.mFrequency);
+ bigrams.add(new WeightedString(word.mWord, reconstructedFrequency));
}
}
if (hasChildrenAddress(info.mChildrenAddress)) {
@@ -1618,6 +1658,7 @@ public final class BinaryDictInputOutput {
* @param dict an optional dictionary to add words to, or null.
* @return the created (or merged) dictionary.
*/
+ @UsedForTesting
public static FusionDictionary readDictionaryBinary(
final FusionDictionaryBufferInterface buffer, final FusionDictionary dict)
throws IOException, UnsupportedFormatException {
@@ -1655,17 +1696,24 @@ public final class BinaryDictInputOutput {
}
/**
+ * Helper method to pass a file name instead of a File object to isBinaryDictionary.
+ */
+ public static boolean isBinaryDictionary(final String filename) {
+ final File file = new File(filename);
+ return isBinaryDictionary(file);
+ }
+
+ /**
* Basic test to find out whether the file is a binary dictionary or not.
*
* Concretely this only tests the magic number.
*
- * @param filename The name of the file to test.
+ * @param file The file to test.
* @return true if it's a binary dictionary, false otherwise
*/
- public static boolean isBinaryDictionary(final String filename) {
+ public static boolean isBinaryDictionary(final File file) {
FileInputStream inStream = null;
try {
- final File file = new File(filename);
inStream = new FileInputStream(file);
final ByteBuffer buffer = inStream.getChannel().map(
FileChannel.MapMode.READ_ONLY, 0, file.length());
@@ -1700,8 +1748,7 @@ public final class BinaryDictInputOutput {
final int bigramFrequency) {
final float stepSize = (FormatSpec.MAX_TERMINAL_FREQUENCY - unigramFrequency)
/ (1.5f + FormatSpec.MAX_BIGRAM_FREQUENCY);
- final float resultFreqFloat = (float)unigramFrequency
- + stepSize * (bigramFrequency + 1.0f);
+ final float resultFreqFloat = unigramFrequency + stepSize * (bigramFrequency + 1.0f);
return (int)resultFreqFloat;
}
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
index b3fbb9fb5..705f66414 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
@@ -59,9 +59,11 @@ public final class FormatSpec {
* l | 10 = 2 bytes : FLAG_GROUP_ADDRESS_TYPE_TWOBYTES
* a | 11 = 3 bytes : FLAG_GROUP_ADDRESS_TYPE_THREEBYTES
* g | ELSE
- * s | is moved ? 2 bits, 11 = no
- * | 01 = yes
+ * s | is moved ? 2 bits, 11 = no : FLAG_IS_NOT_MOVED
+ * | This must be the same as FLAG_GROUP_ADDRESS_TYPE_THREEBYTES
+ * | 01 = yes : FLAG_IS_MOVED
* | the new address is stored in the same place as the parent address
+ * | is deleted? 10 = yes : FLAG_IS_DELETED
* | has several chars ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_MULTIPLE_CHARS
* | has a terminal ? 1 bit, 1 = yes, 0 = no : FLAG_IS_TERMINAL
* | has shortcut targets ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_SHORTCUT_TARGETS
@@ -170,6 +172,7 @@ public final class FormatSpec {
static final int PARENT_ADDRESS_SIZE = 3;
static final int FORWARD_LINK_ADDRESS_SIZE = 3;
+ // These flags are used only in the static dictionary.
static final int MASK_GROUP_ADDRESS_TYPE = 0xC0;
static final int FLAG_GROUP_ADDRESS_TYPE_NOADDRESS = 0x00;
static final int FLAG_GROUP_ADDRESS_TYPE_ONEBYTE = 0x40;
@@ -183,7 +186,13 @@ public final class FormatSpec {
static final int FLAG_HAS_BIGRAMS = 0x04;
static final int FLAG_IS_NOT_A_WORD = 0x02;
static final int FLAG_IS_BLACKLISTED = 0x01;
- static final int FLAG_IS_MOVED = 0x40;
+
+ // These flags are used only in the dynamic dictionary.
+ static final int MASK_MOVE_AND_DELETE_FLAG = 0xC0;
+ static final int FIXED_BIT_OF_DYNAMIC_UPDATE_MOVE = 0x40;
+ static final int FLAG_IS_MOVED = 0x00 | FIXED_BIT_OF_DYNAMIC_UPDATE_MOVE;
+ static final int FLAG_IS_NOT_MOVED = 0x80 | FIXED_BIT_OF_DYNAMIC_UPDATE_MOVE;
+ static final int FLAG_IS_DELETED = 0x80;
static final int FLAG_ATTRIBUTE_HAS_NEXT = 0x80;
static final int FLAG_ATTRIBUTE_OFFSET_NEGATIVE = 0x40;
@@ -210,10 +219,13 @@ public final class FormatSpec {
static final int MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT = 0x7F; // 127
static final int MAX_CHARGROUPS_IN_A_NODE = 0x7FFF; // 32767
+ static final int MAX_BIGRAMS_IN_A_GROUP = 10000;
static final int MAX_TERMINAL_FREQUENCY = 255;
static final int MAX_BIGRAM_FREQUENCY = 15;
+ public static final int SHORTCUT_WHITELIST_FREQUENCY = 15;
+
// This option needs to be the same numeric value as the one in binary_format.h.
static final int NOT_VALID_WORD = -99;
static final int SIGNED_CHILDREN_ADDRESS_SIZE = 3;
diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
index 3193ef457..ee647abed 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
@@ -21,6 +21,7 @@ import com.android.inputmethod.latin.Constants;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
@@ -141,6 +142,33 @@ public final class FusionDictionary implements Iterable<Word> {
return NOT_A_TERMINAL != mFrequency;
}
+ public int getFrequency() {
+ return mFrequency;
+ }
+
+ public boolean getIsNotAWord() {
+ return mIsNotAWord;
+ }
+
+ public boolean getIsBlacklistEntry() {
+ return mIsBlacklistEntry;
+ }
+
+ public ArrayList<WeightedString> getShortcutTargets() {
+ // We don't want write permission to escape outside the package, so we return a copy
+ if (null == mShortcutTargets) return null;
+ final ArrayList<WeightedString> copyOfShortcutTargets =
+ new ArrayList<WeightedString>(mShortcutTargets);
+ return copyOfShortcutTargets;
+ }
+
+ public ArrayList<WeightedString> getBigrams() {
+ // We don't want write permission to escape outside the package, so we return a copy
+ if (null == mBigrams) return null;
+ final ArrayList<WeightedString> copyOfBigrams = new ArrayList<WeightedString>(mBigrams);
+ return copyOfBigrams;
+ }
+
public boolean hasSeveralChars() {
assert(mChars.length > 0);
return 1 < mChars.length;
@@ -249,8 +277,6 @@ public final class FusionDictionary implements Iterable<Word> {
/**
* Options global to the dictionary.
- *
- * There are no options at the moment, so this class is empty.
*/
public static final class DictionaryOptions {
public final boolean mGermanUmlautProcessing;
@@ -262,6 +288,43 @@ public final class FusionDictionary implements Iterable<Word> {
mGermanUmlautProcessing = germanUmlautProcessing;
mFrenchLigatureProcessing = frenchLigatureProcessing;
}
+ @Override
+ public String toString() { // Convenience method
+ return toString(0, false);
+ }
+ public String toString(final int indentCount, final boolean plumbing) {
+ final StringBuilder indent = new StringBuilder();
+ if (plumbing) {
+ indent.append("H:");
+ } else {
+ for (int i = 0; i < indentCount; ++i) {
+ indent.append(" ");
+ }
+ }
+ final StringBuilder s = new StringBuilder();
+ for (final String optionKey : mAttributes.keySet()) {
+ s.append(indent);
+ s.append(optionKey);
+ s.append(" = ");
+ if ("date".equals(optionKey) && !plumbing) {
+ // Date needs a number of milliseconds, but the dictionary contains seconds
+ s.append(new Date(
+ 1000 * Long.parseLong(mAttributes.get(optionKey))).toString());
+ } else {
+ s.append(mAttributes.get(optionKey));
+ }
+ s.append("\n");
+ }
+ if (mGermanUmlautProcessing) {
+ s.append(indent);
+ s.append("Needs German umlaut processing\n");
+ }
+ if (mFrenchLigatureProcessing) {
+ s.append(indent);
+ s.append("Needs French ligature processing\n");
+ }
+ return s.toString();
+ }
}
public final DictionaryOptions mOptions;
@@ -279,7 +342,7 @@ public final class FusionDictionary implements Iterable<Word> {
/**
* Helper method to convert a String to an int array.
*/
- static private int[] getCodePoints(final String word) {
+ static int[] getCodePoints(final String word) {
// TODO: this is a copy-paste of the contents of StringUtils.toCodePointArray,
// which is not visible from the makedict package. Factor this code.
final char[] characters = word.toCharArray();
@@ -358,6 +421,10 @@ public final class FusionDictionary implements Iterable<Word> {
if (charGroup2 == null) {
add(getCodePoints(word2), 0, null, false /* isNotAWord */,
false /* isBlacklistEntry */);
+ // The chargroup for the first word may have moved by the above insertion,
+ // if word1 and word2 share a common stem that happens not to have been
+ // a cutting point until now. In this case, we need to refresh charGroup.
+ charGroup = findWordInTree(mRoot, word1);
}
charGroup.addBigram(word2, frequency);
} else {
@@ -550,6 +617,7 @@ public final class FusionDictionary implements Iterable<Word> {
/**
* Helper method to find a word in a given branch.
*/
+ @SuppressWarnings("unused")
public static CharGroup findWordInTree(Node node, final String s) {
int index = 0;
final StringBuilder checker = DBG ? new StringBuilder() : null;
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 5a11ae534..89d6c9010 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -212,7 +212,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
}
}
- private final ArrayList<CharSequence> mSuggestions;
+ private final ArrayList<String> mSuggestions;
private final int[] mScores;
private final String mOriginalText;
private final float mSuggestionThreshold;
@@ -294,6 +294,8 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
final String[] gatheredSuggestions;
final boolean hasRecommendedSuggestions;
if (0 == mLength) {
+ // TODO: the comment below describes what is intended, but in the practice
+ // mBestSuggestion is only ever set to null so it doesn't work. Fix this.
// Either we found no suggestions, or we found some BUT the max length was 0.
// If we found some mBestSuggestion will not be null. If it is null, then
// we found none, regardless of the max length.
@@ -335,7 +337,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
gatheredSuggestions = mSuggestions.toArray(EMPTY_STRING_ARRAY);
final int bestScore = mScores[mLength - 1];
- final CharSequence bestSuggestion = mSuggestions.get(0);
+ final String bestSuggestion = mSuggestions.get(0);
final float normalizedScore =
BinaryDictionary.calcNormalizedScore(
mOriginalText, bestSuggestion.toString(), bestScore);
@@ -438,15 +440,23 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
if (!Character.isUpperCase(text.codePointAt(0))) return CAPITALIZE_NONE;
final int len = text.length();
int capsCount = 1;
+ int letterCount = 1;
for (int i = 1; i < len; i = text.offsetByCodePoints(i, 1)) {
- if (1 != capsCount && i != capsCount) break;
- if (Character.isUpperCase(text.codePointAt(i))) ++capsCount;
+ if (1 != capsCount && letterCount != capsCount) break;
+ final int codePoint = text.codePointAt(i);
+ if (Character.isUpperCase(codePoint)) {
+ ++capsCount;
+ ++letterCount;
+ } else if (Character.isLetter(codePoint)) {
+ // We need to discount non-letters since they may not be upper-case, but may
+ // still be part of a word (e.g. single quote or dash, as in "IT'S" or "FULL-TIME")
+ ++letterCount;
+ }
}
- // We know the first char is upper case. So we want to test if either everything
- // else is lower case, or if everything else is upper case. If the string is
- // exactly one char long, then we will arrive here with capsCount 1, and this is
- // correct, too.
+ // We know the first char is upper case. So we want to test if either every letter other
+ // than the first is lower case, or if they are all upper case. If the string is exactly
+ // one char long, then we will arrive here with letterCount 1, and this is correct, too.
if (1 == capsCount) return CAPITALIZE_FIRST;
- return (len == capsCount ? CAPITALIZE_ALL : CAPITALIZE_NONE);
+ return (letterCount == capsCount ? CAPITALIZE_ALL : CAPITALIZE_NONE);
}
}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index 53ed4d3c3..470943be1 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -28,9 +28,11 @@ import android.view.textservice.TextInfo;
import com.android.inputmethod.compat.SuggestionsInfoCompatUtils;
import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.Dictionary;
import com.android.inputmethod.latin.LocaleUtils;
-import com.android.inputmethod.latin.WordComposer;
+import com.android.inputmethod.latin.StringUtils;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.WordComposer;
import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService.SuggestionsGatherer;
import java.util.ArrayList;
@@ -188,6 +190,35 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
return (letterCount * 4 < length * 3);
}
+ /**
+ * Helper method to test valid capitalizations of a word.
+ *
+ * If the "text" is lower-case, we test only the exact string.
+ * If the "Text" is capitalized, we test the exact string "Text" and the lower-cased
+ * version of it "text".
+ * If the "TEXT" is fully upper case, we test the exact string "TEXT", the lower-cased
+ * version of it "text" and the capitalized version of it "Text".
+ */
+ private boolean isInDictForAnyCapitalization(final Dictionary dict, final String text,
+ final int capitalizeType) {
+ // If the word is in there as is, then it's in the dictionary. If not, we'll test lower
+ // case versions, but only if the word is not already all-lower case or mixed case.
+ if (dict.isValidWord(text)) return true;
+ if (AndroidSpellCheckerService.CAPITALIZE_NONE == capitalizeType) return false;
+
+ // If we come here, we have a capitalized word (either First- or All-).
+ // Downcase the word and look it up again. If the word is only capitalized, we
+ // tested all possibilities, so if it's still negative we can return false.
+ final String lowerCaseText = text.toLowerCase(mLocale);
+ if (dict.isValidWord(lowerCaseText)) return true;
+ if (AndroidSpellCheckerService.CAPITALIZE_FIRST == capitalizeType) return false;
+
+ // If the lower case version is not in the dictionary, it's still possible
+ // that we have an all-caps version of a word that needs to be capitalized
+ // according to the dictionary. E.g. "GERMANS" only exists in the dictionary as "Germans".
+ return dict.isValidWord(StringUtils.toTitleCase(lowerCaseText, mLocale));
+ }
+
// Note : this must be reentrant
/**
* Gets a list of suggestions for a specific string. This returns a list of possible
@@ -268,17 +299,11 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
dictInfo.mDictionary.getSuggestions(composer, prevWord,
dictInfo.mProximityInfo);
for (final SuggestedWordInfo suggestion : suggestions) {
- final String suggestionStr = suggestion.mWord.toString();
+ final String suggestionStr = suggestion.mWord;
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));
- }
+ isInDict = isInDictForAnyCapitalization(dictInfo.mDictionary, text, capitalizeType);
} finally {
if (null != dictInfo) {
if (!mDictionaryPool.offer(dictInfo)) {
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
index 1fb2bbb6a..eae5d2e60 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
@@ -51,11 +51,11 @@ public final class DictionaryPool extends LinkedBlockingQueue<DictAndProximity>
new Dictionary(Dictionary.TYPE_MAIN) {
@Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
- final CharSequence prevWord, final ProximityInfo proximityInfo) {
+ final String prevWord, final ProximityInfo proximityInfo) {
return noSuggestions;
}
@Override
- public boolean isValidWord(CharSequence word) {
+ public boolean isValidWord(final String word) {
// This is never called. However if for some strange reason it ever gets
// called, returning true is less destructive (it will not underline the
// word in red).
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
index 11bb97031..6c0d79c2b 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin.spellcheck;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.Constants;
@@ -23,7 +24,7 @@ import com.android.inputmethod.latin.Constants;
import java.util.TreeMap;
public final class SpellCheckerProximityInfo {
- /* public for test */
+ @UsedForTesting
final public static int NUL = Constants.NOT_A_CODE;
// This must be the same as MAX_PROXIMITY_CHARS_SIZE else it will not work inside
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index 4e9fd1968..35d5a0067 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -22,7 +22,6 @@ import android.graphics.drawable.Drawable;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
-import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.keyboard.internal.KeyboardParams;
@@ -66,7 +65,7 @@ public final class MoreSuggestions extends Keyboard {
int pos = fromPos, rowStartPos = fromPos;
final int size = Math.min(suggestions.size(), SuggestionStripView.MAX_SUGGESTIONS);
while (pos < size) {
- final String word = suggestions.getWord(pos).toString();
+ final String word = suggestions.getWord(pos);
// TODO: Should take care of text x-scaling.
mWidths[pos] = (int)view.getLabelWidth(word, paint) + padding;
final int numColumn = pos - rowStartPos + 1;
@@ -176,11 +175,11 @@ public final class MoreSuggestions extends Keyboard {
}
public Builder layout(final SuggestedWords suggestions, final int fromPos,
- final int maxWidth, final int minWidth, final int maxRow) {
- final Keyboard keyboard = KeyboardSwitcher.getInstance().getKeyboard();
+ final int maxWidth, final int minWidth, final int maxRow,
+ final Keyboard parentKeyboard) {
final int xmlId = R.xml.kbd_suggestions_pane_template;
- load(xmlId, keyboard.mId);
- mParams.mVerticalGap = mParams.mTopPadding = keyboard.mVerticalGap / 2;
+ load(xmlId, parentKeyboard.mId);
+ mParams.mVerticalGap = mParams.mTopPadding = parentKeyboard.mVerticalGap / 2;
mPaneView.updateKeyboardGeometry(mParams.mDefaultRowHeight);
final int count = mParams.layout(suggestions, fromPos, maxWidth, minWidth, maxRow,
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
index 03a2e73d1..26a304ef8 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
@@ -17,84 +17,35 @@
package com.android.inputmethod.latin.suggestions;
import android.content.Context;
-import android.content.res.Resources;
import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.PopupWindow;
-import com.android.inputmethod.keyboard.KeyDetector;
import com.android.inputmethod.keyboard.Keyboard;
-import com.android.inputmethod.keyboard.KeyboardActionListener;
-import com.android.inputmethod.keyboard.KeyboardView;
-import com.android.inputmethod.keyboard.MoreKeysDetector;
-import com.android.inputmethod.keyboard.MoreKeysPanel;
-import com.android.inputmethod.keyboard.PointerTracker;
-import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
-import com.android.inputmethod.keyboard.PointerTracker.KeyEventHandler;
-import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
+import com.android.inputmethod.keyboard.MoreKeysKeyboardView;
import com.android.inputmethod.latin.R;
/**
* A view that renders a virtual {@link MoreSuggestions}. It handles rendering of keys and detecting
* key presses and touch movements.
*/
-public final class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel {
- private final int[] mCoordinates = new int[2];
+public final class MoreSuggestionsView extends MoreKeysKeyboardView {
- final KeyDetector mModalPanelKeyDetector;
- private final KeyDetector mSlidingPanelKeyDetector;
-
- private Controller mController;
- KeyboardActionListener mListener;
- private int mOriginX;
- private int mOriginY;
-
- static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy.Adapter();
-
- final KeyboardActionListener mSuggestionsPaneListener =
- new KeyboardActionListener.Adapter() {
- @Override
- public void onPressKey(int primaryCode) {
- mListener.onPressKey(primaryCode);
- }
-
- @Override
- public void onReleaseKey(int primaryCode, boolean withSliding) {
- mListener.onReleaseKey(primaryCode, withSliding);
- }
-
- @Override
- public void onCodeInput(int primaryCode, int x, int y) {
- final int index = primaryCode - MoreSuggestions.SUGGESTION_CODE_BASE;
- if (index >= 0 && index < SuggestionStripView.MAX_SUGGESTIONS) {
- mListener.onCustomRequest(index);
- }
- }
-
- @Override
- public void onCancelInput() {
- mListener.onCancelInput();
- }
- };
-
- public MoreSuggestionsView(Context context, AttributeSet attrs) {
+ public MoreSuggestionsView(final Context context, final AttributeSet attrs) {
this(context, attrs, R.attr.moreSuggestionsViewStyle);
}
- public MoreSuggestionsView(Context context, AttributeSet attrs, int defStyle) {
+ public MoreSuggestionsView(final Context context, final AttributeSet attrs,
+ final int defStyle) {
super(context, attrs, defStyle);
+ }
- final Resources res = context.getResources();
- mModalPanelKeyDetector = new KeyDetector(/* keyHysteresisDistance */ 0);
- mSlidingPanelKeyDetector = new MoreKeysDetector(
- res.getDimension(R.dimen.more_suggestions_slide_allowance));
- setKeyPreviewPopupEnabled(false, 0);
+ @Override
+ protected int getDefaultCoordX() {
+ final MoreSuggestions pane = (MoreSuggestions)getKeyboard();
+ return pane.mOccupiedWidth / 2;
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final Keyboard keyboard = getKeyboard();
if (keyboard != null) {
final int width = keyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight();
@@ -110,116 +61,15 @@ public final class MoreSuggestionsView extends KeyboardView implements MoreKeysP
}
@Override
- public void setKeyboard(Keyboard keyboard) {
- super.setKeyboard(keyboard);
- mModalPanelKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), -getPaddingTop());
- mSlidingPanelKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
- -getPaddingTop() + mVerticalCorrection);
- }
-
- @Override
- public KeyDetector getKeyDetector() {
- return mSlidingPanelKeyDetector;
- }
-
- @Override
- public KeyboardActionListener getKeyboardActionListener() {
- return mSuggestionsPaneListener;
- }
-
- @Override
- public DrawingProxy getDrawingProxy() {
- return this;
- }
-
- @Override
- public TimerProxy getTimerProxy() {
- return EMPTY_TIMER_PROXY;
- }
-
- @Override
- public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) {
- // Suggestions pane needs no pop-up key preview displayed, so we pass always false with a
- // delay of 0. The delay does not matter actually since the popup is not shown anyway.
- super.setKeyPreviewPopupEnabled(false, 0);
- }
-
- @Override
- public void showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY,
- PopupWindow window, KeyboardActionListener listener) {
- mController = controller;
- mListener = listener;
- final View container = (View)getParent();
- final MoreSuggestions pane = (MoreSuggestions)getKeyboard();
- final int defaultCoordX = pane.mOccupiedWidth / 2;
- // The coordinates of panel's left-top corner in parentView's coordinate system.
- final int x = pointX - defaultCoordX - container.getPaddingLeft();
- final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom();
-
- window.setContentView(container);
- window.setWidth(container.getMeasuredWidth());
- window.setHeight(container.getMeasuredHeight());
- parentView.getLocationInWindow(mCoordinates);
- window.showAtLocation(parentView, Gravity.NO_GRAVITY,
- x + mCoordinates[0], y + mCoordinates[1]);
-
- mOriginX = x + container.getPaddingLeft();
- mOriginY = y + container.getPaddingTop();
- }
-
- private boolean mIsDismissing;
-
- @Override
- public boolean dismissMoreKeysPanel() {
- if (mIsDismissing || mController == null) return false;
- mIsDismissing = true;
- final boolean dismissed = mController.dismissMoreKeysPanel();
- mIsDismissing = false;
- return dismissed;
- }
-
- @Override
- public int translateX(int x) {
- return x - mOriginX;
- }
-
- @Override
- public int translateY(int y) {
- return y - mOriginY;
- }
-
- private final KeyEventHandler mModalPanelKeyEventHandler = new KeyEventHandler() {
- @Override
- public KeyDetector getKeyDetector() {
- return mModalPanelKeyDetector;
+ public void onCodeInput(final int primaryCode, final int x, final int y) {
+ final int index = primaryCode - MoreSuggestions.SUGGESTION_CODE_BASE;
+ if (index >= 0 && index < SuggestionStripView.MAX_SUGGESTIONS) {
+ mListener.onCustomRequest(index);
}
-
- @Override
- public KeyboardActionListener getKeyboardActionListener() {
- return mSuggestionsPaneListener;
- }
-
- @Override
- public DrawingProxy getDrawingProxy() {
- return MoreSuggestionsView.this;
- }
-
- @Override
- public TimerProxy getTimerProxy() {
- return EMPTY_TIMER_PROXY;
- }
- };
+ }
@Override
- public boolean onTouchEvent(MotionEvent me) {
- final int action = me.getAction();
- final long eventTime = me.getEventTime();
- final int index = me.getActionIndex();
- final int id = me.getPointerId(index);
- final PointerTracker tracker = PointerTracker.getPointerTracker(id, this);
- final int x = (int)me.getX(index);
- final int y = (int)me.getY(index);
- tracker.processMotionEvent(action, x, y, eventTime, mModalPanelKeyEventHandler);
- return true;
+ public boolean isShowingInParent() {
+ return (getContainerView().getParent() != null);
}
}
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index a1c95ad8a..14bb95b3c 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -27,9 +27,7 @@ import android.graphics.Paint.Align;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Message;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
@@ -48,21 +46,21 @@ import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.LinearLayout;
-import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardActionListener;
+import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.keyboard.MoreKeysPanel;
-import com.android.inputmethod.keyboard.PointerTracker;
import com.android.inputmethod.keyboard.ViewLayoutUtils;
import com.android.inputmethod.latin.AutoCorrection;
import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.ResourceUtils;
-import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.Utils;
import com.android.inputmethod.latin.define.ProductionFlag;
@@ -74,7 +72,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
OnLongClickListener {
public interface Listener {
public void addWordToUserDictionary(String word);
- public void pickSuggestionManually(int index, CharSequence word);
+ public void pickSuggestionManually(int index, String word);
}
// The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}.
@@ -83,54 +81,22 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
static final boolean DBG = LatinImeLogger.sDBG;
private final ViewGroup mSuggestionsStrip;
- private KeyboardView mKeyboardView;
+ KeyboardView mKeyboardView;
private final View mMoreSuggestionsContainer;
private final MoreSuggestionsView mMoreSuggestionsView;
private final MoreSuggestions.Builder mMoreSuggestionsBuilder;
- private final PopupWindow mMoreSuggestionsWindow;
private final ArrayList<TextView> mWords = CollectionUtils.newArrayList();
private final ArrayList<TextView> mInfos = CollectionUtils.newArrayList();
private final ArrayList<View> mDividers = CollectionUtils.newArrayList();
- private final PopupWindow mPreviewPopup;
- private final TextView mPreviewText;
-
- private Listener mListener;
- private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
+ Listener mListener;
+ SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
private final SuggestionStripViewParams mParams;
private static final float MIN_TEXT_XSCALE = 0.70f;
- private final UiHandler mHandler = new UiHandler(this);
-
- private static final class UiHandler extends StaticInnerHandlerWrapper<SuggestionStripView> {
- private static final int MSG_HIDE_PREVIEW = 0;
-
- public UiHandler(SuggestionStripView outerInstance) {
- super(outerInstance);
- }
-
- @Override
- public void dispatchMessage(Message msg) {
- final SuggestionStripView suggestionStripView = getOuterInstance();
- switch (msg.what) {
- case MSG_HIDE_PREVIEW:
- suggestionStripView.hidePreview();
- break;
- }
- }
-
- public void cancelHidePreview() {
- removeMessages(MSG_HIDE_PREVIEW);
- }
-
- public void cancelAllMessages() {
- cancelHidePreview();
- }
- }
-
private static final class SuggestionStripViewParams {
private static final int DEFAULT_SUGGESTIONS_COUNT_IN_STRIP = 3;
private static final float DEFAULT_CENTER_SUGGESTION_PERCENTILE = 0.40f;
@@ -177,8 +143,9 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
private final TextView mLeftwardsArrowView;
private final TextView mHintToSaveView;
- public SuggestionStripViewParams(Context context, AttributeSet attrs, int defStyle,
- ArrayList<TextView> words, ArrayList<View> dividers, ArrayList<TextView> infos) {
+ public SuggestionStripViewParams(final Context context, final AttributeSet attrs,
+ final int defStyle, final ArrayList<TextView> words, final ArrayList<View> dividers,
+ final ArrayList<TextView> infos) {
mWords = words;
mDividers = dividers;
mInfos = infos;
@@ -250,7 +217,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return mMaxMoreSuggestionsRow * mMoreSuggestionsRowHeight + mMoreSuggestionsBottomGap;
}
- public int setMoreSuggestionsHeight(int remainingHeight) {
+ public int setMoreSuggestionsHeight(final int remainingHeight) {
final int currentHeight = getMoreSuggestionsHeight();
if (currentHeight <= remainingHeight) {
return currentHeight;
@@ -262,7 +229,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return newHeight;
}
- private static Drawable getMoreSuggestionsHint(Resources res, float textSize, int color) {
+ private static Drawable getMoreSuggestionsHint(final Resources res, final float textSize,
+ final int color) {
final Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setTextAlign(Align.CENTER);
@@ -279,8 +247,9 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return new BitmapDrawable(res, buffer);
}
- private CharSequence getStyledSuggestionWord(SuggestedWords suggestedWords, int pos) {
- final CharSequence word = suggestedWords.getWord(pos);
+ private CharSequence getStyledSuggestionWord(final SuggestedWords suggestedWords,
+ final int pos) {
+ final String word = suggestedWords.getWord(pos);
final boolean isAutoCorrect = pos == 1 && suggestedWords.willAutoCorrect();
final boolean isTypedWordValid = pos == 0 && suggestedWords.mTypedWordValid;
if (!isAutoCorrect && !isTypedWordValid)
@@ -299,7 +268,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return spannedWord;
}
- private int getWordPosition(int index, SuggestedWords suggestedWords) {
+ private int getWordPosition(final int index, final SuggestedWords suggestedWords) {
// TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more
// suggestions.
final int centerPos = suggestedWords.willAutoCorrect() ? 1 : 0;
@@ -312,7 +281,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
}
}
- private int getSuggestionTextColor(int index, SuggestedWords suggestedWords, int pos) {
+ private int getSuggestionTextColor(final int index, final SuggestedWords suggestedWords,
+ final int pos) {
// TODO: Need to revisit this logic with bigram suggestions
final boolean isSuggested = (pos != 0);
@@ -331,7 +301,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
// is in slot 1.
if (index == mCenterSuggestionIndex
&& AutoCorrection.shouldBlockAutoCorrectionBySafetyNet(
- suggestedWords.getWord(1).toString(), suggestedWords.getWord(0))) {
+ suggestedWords.getWord(1), suggestedWords.getWord(0))) {
return 0xFFFF0000;
}
}
@@ -355,8 +325,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
params.gravity = Gravity.CENTER;
}
- public void layout(SuggestedWords suggestedWords, ViewGroup stripView, ViewGroup placer,
- int stripWidth) {
+ public void layout(final SuggestedWords suggestedWords, final ViewGroup stripView,
+ final ViewGroup placer, final int stripWidth) {
if (suggestedWords.mIsPunctuationSuggestions) {
layoutPunctuationSuggestions(suggestedWords, stripView);
return;
@@ -402,7 +372,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
x += word.getMeasuredWidth();
if (DBG && pos < suggestedWords.size()) {
- final CharSequence debugInfo = Utils.getDebugInfo(suggestedWords, pos);
+ final String debugInfo = Utils.getDebugInfo(suggestedWords, pos);
if (debugInfo != null) {
final TextView info = mInfos.get(pos);
info.setText(debugInfo);
@@ -418,14 +388,14 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
}
}
- private int getSuggestionWidth(int index, int maxWidth) {
+ private int getSuggestionWidth(final int index, final int maxWidth) {
final int paddings = mPadding * mSuggestionsCountInStrip;
final int dividers = mDividerWidth * (mSuggestionsCountInStrip - 1);
final int availableWidth = maxWidth - paddings - dividers;
return (int)(availableWidth * getSuggestionWeight(index));
}
- private float getSuggestionWeight(int index) {
+ private float getSuggestionWeight(final int index) {
if (index == mCenterSuggestionIndex) {
return mCenterSuggestionWeight;
} else {
@@ -434,7 +404,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
}
}
- private void setupTexts(SuggestedWords suggestedWords, int countInStrip) {
+ private void setupTexts(final SuggestedWords suggestedWords, final int countInStrip) {
mTexts.clear();
final int count = Math.min(suggestedWords.size(), countInStrip);
for (int pos = 0; pos < count; pos++) {
@@ -447,8 +417,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
}
}
- private void layoutPunctuationSuggestions(SuggestedWords suggestedWords,
- ViewGroup stripView) {
+ private void layoutPunctuationSuggestions(final SuggestedWords suggestedWords,
+ final ViewGroup stripView) {
final int countInStrip = Math.min(suggestedWords.size(), PUNCTUATIONS_IN_STRIP);
for (int index = 0; index < countInStrip; index++) {
if (index != 0) {
@@ -459,7 +429,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
final TextView word = mWords.get(index);
word.setEnabled(true);
word.setTextColor(mColorAutoCorrect);
- final CharSequence text = suggestedWords.getWord(index);
+ final String text = suggestedWords.getWord(index);
word.setText(text);
word.setTextScaleX(1.0f);
word.setCompoundDrawables(null, null, null, null);
@@ -469,8 +439,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
mMoreSuggestionsAvailable = false;
}
- public void layoutAddToDictionaryHint(CharSequence word, ViewGroup stripView,
- int stripWidth, CharSequence hintText, OnClickListener listener) {
+ public void layoutAddToDictionaryHint(final String word, final ViewGroup stripView,
+ final int stripWidth, final CharSequence hintText, final OnClickListener listener) {
final int width = stripWidth - mDividerWidth - mPadding * 2;
final TextView wordView = mWordToSaveView;
@@ -511,11 +481,11 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return (CharSequence)mWordToSaveView.getTag();
}
- public boolean isAddToDictionaryShowing(View v) {
+ public boolean isAddToDictionaryShowing(final View v) {
return v == mWordToSaveView || v == mHintToSaveView || v == mLeftwardsArrowView;
}
- private static void setLayoutWeight(View v, float weight, int height) {
+ private static void setLayoutWeight(final View v, final float weight, final int height) {
final ViewGroup.LayoutParams lp = v.getLayoutParams();
if (lp instanceof LinearLayout.LayoutParams) {
final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp;
@@ -525,7 +495,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
}
}
- private static float getTextScaleX(CharSequence text, int maxWidth, TextPaint paint) {
+ private static float getTextScaleX(final CharSequence text, final int maxWidth,
+ final TextPaint paint) {
paint.setTextScaleX(1.0f);
final int width = getTextWidth(text, paint);
if (width <= maxWidth) {
@@ -534,8 +505,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return maxWidth / (float)width;
}
- private static CharSequence getEllipsizedText(CharSequence text, int maxWidth,
- TextPaint paint) {
+ private static CharSequence getEllipsizedText(final CharSequence text, final int maxWidth,
+ final TextPaint paint) {
if (text == null) return null;
paint.setTextScaleX(1.0f);
final int width = getTextWidth(text, paint);
@@ -556,7 +527,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return ellipsized;
}
- private static int getTextWidth(CharSequence text, TextPaint paint) {
+ private static int getTextWidth(final CharSequence text, final TextPaint paint) {
if (TextUtils.isEmpty(text)) return 0;
final Typeface savedTypeface = paint.getTypeface();
paint.setTypeface(getTextTypeface(text));
@@ -571,7 +542,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return width;
}
- private static Typeface getTextTypeface(CharSequence text) {
+ private static Typeface getTextTypeface(final CharSequence text) {
if (!(text instanceof SpannableString))
return Typeface.DEFAULT;
@@ -593,23 +564,17 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
* @param context
* @param attrs
*/
- public SuggestionStripView(Context context, AttributeSet attrs) {
+ public SuggestionStripView(final Context context, final AttributeSet attrs) {
this(context, attrs, R.attr.suggestionStripViewStyle);
}
- public SuggestionStripView(Context context, AttributeSet attrs, int defStyle) {
+ public SuggestionStripView(final Context context, final AttributeSet attrs,
+ final int defStyle) {
super(context, attrs, defStyle);
final LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.suggestions_strip, this);
- mPreviewPopup = new PopupWindow(context);
- mPreviewText = (TextView) inflater.inflate(R.layout.suggestion_preview, null);
- mPreviewPopup.setWindowLayoutMode(
- ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- mPreviewPopup.setContentView(mPreviewText);
- mPreviewPopup.setBackgroundDrawable(null);
-
mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip);
for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) {
final TextView word = (TextView)inflater.inflate(R.layout.suggestion_word, null);
@@ -632,21 +597,6 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
.findViewById(R.id.more_suggestions_view);
mMoreSuggestionsBuilder = new MoreSuggestions.Builder(mMoreSuggestionsView);
- final PopupWindow moreWindow = new PopupWindow(context);
- moreWindow.setWindowLayoutMode(
- ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- moreWindow.setBackgroundDrawable(new ColorDrawable(android.R.color.transparent));
- moreWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
- moreWindow.setFocusable(true);
- moreWindow.setOutsideTouchable(true);
- moreWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
- @Override
- public void onDismiss() {
- mKeyboardView.dimEntireKeyboard(false);
- }
- });
- mMoreSuggestionsWindow = moreWindow;
-
final Resources res = context.getResources();
mMoreSuggestionsModalTolerance = res.getDimensionPixelOffset(
R.dimen.more_suggestions_modal_tolerance);
@@ -658,15 +608,12 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
* A connection back to the input method.
* @param listener
*/
- public void setListener(Listener listener, View inputView) {
+ public void setListener(final Listener listener, final View inputView) {
mListener = listener;
mKeyboardView = (KeyboardView)inputView.findViewById(R.id.keyboard_view);
}
- public void setSuggestions(SuggestedWords suggestedWords) {
- if (suggestedWords == null)
- return;
-
+ public void setSuggestions(final SuggestedWords suggestedWords) {
clear();
mSuggestedWords = suggestedWords;
mParams.layout(mSuggestedWords, mSuggestionsStrip, this, getWidth());
@@ -675,7 +622,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
}
}
- public int setMoreSuggestionsHeight(int remainingHeight) {
+ public int setMoreSuggestionsHeight(final int remainingHeight) {
return mParams.setMoreSuggestionsHeight(remainingHeight);
}
@@ -684,7 +631,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
&& mParams.isAddToDictionaryShowing(mSuggestionsStrip.getChildAt(0));
}
- public void showAddToDictionaryHint(CharSequence word, CharSequence hintText) {
+ public void showAddToDictionaryHint(final String word, final CharSequence hintText) {
clear();
mParams.layoutAddToDictionaryHint(word, mSuggestionsStrip, getWidth(), hintText, this);
}
@@ -708,16 +655,12 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
dismissMoreSuggestions();
}
- private void hidePreview() {
- mPreviewPopup.dismiss();
- }
-
private final KeyboardActionListener mMoreSuggestionsListener =
new KeyboardActionListener.Adapter() {
@Override
- public boolean onCustomRequest(int requestCode) {
+ public boolean onCustomRequest(final int requestCode) {
final int index = requestCode;
- final CharSequence word = mSuggestedWords.getWord(index);
+ final String word = mSuggestedWords.getWord(index);
mListener.pickSuggestionManually(index, word);
dismissMoreSuggestions();
return true;
@@ -732,55 +675,64 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
private final MoreKeysPanel.Controller mMoreSuggestionsController =
new MoreKeysPanel.Controller() {
@Override
- public boolean dismissMoreKeysPanel() {
- return dismissMoreSuggestions();
+ public boolean onDismissMoreKeysPanel() {
+ mKeyboardView.dimEntireKeyboard(false /* dimmed */);
+ return mKeyboardView.onDismissMoreKeysPanel();
}
- };
- private boolean dismissMoreSuggestions() {
- if (mMoreSuggestionsWindow.isShowing()) {
- mMoreSuggestionsWindow.dismiss();
- return true;
+ @Override
+ public void onShowMoreKeysPanel(MoreKeysPanel panel) {
+ mKeyboardView.onShowMoreKeysPanel(panel);
}
- return false;
+
+ @Override
+ public void onCancelMoreKeysPanel() {
+ dismissMoreSuggestions();
+ }
+ };
+
+ boolean dismissMoreSuggestions() {
+ return mMoreSuggestionsView.dismissMoreKeysPanel();
}
@Override
- public boolean onLongClick(View view) {
+ public boolean onLongClick(final View view) {
+ KeyboardSwitcher.getInstance().hapticAndAudioFeedback(Constants.NOT_A_CODE);
return showMoreSuggestions();
}
- private boolean showMoreSuggestions() {
+ boolean showMoreSuggestions() {
+ final Keyboard parentKeyboard = KeyboardSwitcher.getInstance().getKeyboard();
+ if (parentKeyboard == null) {
+ return false;
+ }
final SuggestionStripViewParams params = mParams;
- if (params.mMoreSuggestionsAvailable) {
- final int stripWidth = getWidth();
- final View container = mMoreSuggestionsContainer;
- final int maxWidth = stripWidth - container.getPaddingLeft()
- - container.getPaddingRight();
- final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder;
- builder.layout(mSuggestedWords, params.mSuggestionsCountInStrip, maxWidth,
- (int)(maxWidth * params.mMinMoreSuggestionsWidth),
- params.getMaxMoreSuggestionsRow());
- mMoreSuggestionsView.setKeyboard(builder.build());
- container.measure(
- ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-
- final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
- final int pointX = stripWidth / 2;
- final int pointY = -params.mMoreSuggestionsBottomGap;
- moreKeysPanel.showMoreKeysPanel(
- this, mMoreSuggestionsController, pointX, pointY,
- mMoreSuggestionsWindow, mMoreSuggestionsListener);
- mMoreSuggestionsMode = MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING;
- mOriginX = mLastX;
- mOriginY = mLastY;
- mKeyboardView.dimEntireKeyboard(true);
- for (int i = 0; i < params.mSuggestionsCountInStrip; i++) {
- mWords.get(i).setPressed(false);
- }
- return true;
+ if (!params.mMoreSuggestionsAvailable) {
+ return false;
}
- return false;
+ final int stripWidth = getWidth();
+ final View container = mMoreSuggestionsContainer;
+ final int maxWidth = stripWidth - container.getPaddingLeft() - container.getPaddingRight();
+ final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder;
+ builder.layout(mSuggestedWords, params.mSuggestionsCountInStrip, maxWidth,
+ (int)(maxWidth * params.mMinMoreSuggestionsWidth),
+ params.getMaxMoreSuggestionsRow(), parentKeyboard);
+ mMoreSuggestionsView.setKeyboard(builder.build());
+ container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+
+ final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
+ final int pointX = stripWidth / 2;
+ final int pointY = -params.mMoreSuggestionsBottomGap;
+ moreKeysPanel.showMoreKeysPanel(this, mMoreSuggestionsController, pointX, pointY,
+ mMoreSuggestionsListener);
+ mMoreSuggestionsMode = MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING;
+ mOriginX = mLastX;
+ mOriginY = mLastY;
+ mKeyboardView.dimEntireKeyboard(true /* dimmed */);
+ for (int i = 0; i < params.mSuggestionsCountInStrip; i++) {
+ mWords.get(i).setPressed(false);
+ }
+ return true;
}
// Working variables for onLongClick and dispatchTouchEvent.
@@ -807,8 +759,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
};
@Override
- public boolean dispatchTouchEvent(MotionEvent me) {
- if (!mMoreSuggestionsWindow.isShowing()
+ public boolean dispatchTouchEvent(final MotionEvent me) {
+ if (!mMoreSuggestionsView.isShowingInParent()
|| mMoreSuggestionsMode == MORE_SUGGESTIONS_IN_MODAL_MODE) {
mLastX = (int)me.getX();
mLastY = (int)me.getY();
@@ -823,7 +775,6 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
final long eventTime = me.getEventTime();
final int index = me.getActionIndex();
final int id = me.getPointerId(index);
- final PointerTracker tracker = PointerTracker.getPointerTracker(id, moreKeysPanel);
final int x = (int)me.getX(index);
final int y = (int)me.getY(index);
final int translatedX = moreKeysPanel.translateX(x);
@@ -835,7 +786,6 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
// Decided to be in the sliding input mode only when the touch point has been moved
// upward.
mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_SLIDING_MODE;
- tracker.onShowMoreKeysPanel(translatedX, translatedY, moreKeysPanel);
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
// Decided to be in the modal input mode
mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE;
@@ -844,12 +794,12 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
}
// MORE_SUGGESTIONS_IN_SLIDING_MODE
- tracker.processMotionEvent(action, translatedX, translatedY, eventTime, moreKeysPanel);
+ mMoreSuggestionsView.processMotionEvent(action, translatedX, translatedY, id, eventTime);
return true;
}
@Override
- public void onClick(View view) {
+ public void onClick(final View view) {
if (mParams.isAddToDictionaryShowing(view)) {
mListener.addWordToUserDictionary(mParams.getAddToDictionaryWord().toString());
clear();
@@ -863,15 +813,13 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
if (index >= mSuggestedWords.size())
return;
- final CharSequence word = mSuggestedWords.getWord(index);
+ final String word = mSuggestedWords.getWord(index);
mListener.pickSuggestionManually(index, word);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- mHandler.cancelAllMessages();
- hidePreview();
dismissMoreSuggestions();
}
}
diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java
index d8b3a29ff..0aec80a40 100644
--- a/java/src/com/android/inputmethod/research/LogUnit.java
+++ b/java/src/com/android/inputmethod/research/LogUnit.java
@@ -18,7 +18,7 @@ package com.android.inputmethod.research;
import com.android.inputmethod.latin.CollectionUtils;
-import java.util.ArrayList;
+import java.util.List;
/**
* A group of log statements related to each other.
@@ -35,16 +35,39 @@ import java.util.ArrayList;
* been published recently, or whether the LogUnit contains numbers, etc.
*/
/* package */ class LogUnit {
- private final ArrayList<String[]> mKeysList = CollectionUtils.newArrayList();
- private final ArrayList<Object[]> mValuesList = CollectionUtils.newArrayList();
- private final ArrayList<Boolean> mIsPotentiallyPrivate = CollectionUtils.newArrayList();
+ private final List<String[]> mKeysList;
+ private final List<Object[]> mValuesList;
+ // Assume that mTimeList is sorted in increasing order. Do not insert null values into
+ // mTimeList.
+ private final List<Long> mTimeList;
+ private final List<Boolean> mIsPotentiallyPrivate;
private String mWord;
- private boolean mContainsDigit;
+ private boolean mMayContainDigit;
+ public LogUnit() {
+ mKeysList = CollectionUtils.newArrayList();
+ mValuesList = CollectionUtils.newArrayList();
+ mTimeList = CollectionUtils.newArrayList();
+ mIsPotentiallyPrivate = CollectionUtils.newArrayList();
+ }
+
+ private LogUnit(final List<String[]> keysList, final List<Object[]> valuesList,
+ final List<Long> timeList, final List<Boolean> isPotentiallyPrivate) {
+ mKeysList = keysList;
+ mValuesList = valuesList;
+ mTimeList = timeList;
+ mIsPotentiallyPrivate = isPotentiallyPrivate;
+ }
+
+ /**
+ * Adds a new log statement. The time parameter in successive calls to this method must be
+ * monotonically increasing, or splitByTime() will not work.
+ */
public void addLogStatement(final String[] keys, final Object[] values,
- final Boolean isPotentiallyPrivate) {
+ final long time, final boolean isPotentiallyPrivate) {
mKeysList.add(keys);
mValuesList.add(values);
+ mTimeList.add(time);
mIsPotentiallyPrivate.add(isPotentiallyPrivate);
}
@@ -52,7 +75,7 @@ import java.util.ArrayList;
final int size = mKeysList.size();
for (int i = 0; i < size; i++) {
if (!mIsPotentiallyPrivate.get(i) || isIncludingPrivateData) {
- researchLog.outputEvent(mKeysList.get(i), mValuesList.get(i));
+ researchLog.outputEvent(mKeysList.get(i), mValuesList.get(i), mTimeList.get(i));
}
}
}
@@ -69,15 +92,37 @@ import java.util.ArrayList;
return mWord != null;
}
- public void setContainsDigit() {
- mContainsDigit = true;
+ public void setMayContainDigit() {
+ mMayContainDigit = true;
}
- public boolean hasDigit() {
- return mContainsDigit;
+ public boolean mayContainDigit() {
+ return mMayContainDigit;
}
public boolean isEmpty() {
return mKeysList.isEmpty();
}
+
+ /**
+ * Split this logUnit, with all events before maxTime staying in the current logUnit, and all
+ * events after maxTime going into a new LogUnit that is returned.
+ */
+ public LogUnit splitByTime(final long maxTime) {
+ // Assume that mTimeList is in sorted order.
+ final int length = mTimeList.size();
+ for (int index = 0; index < length; index++) {
+ if (mTimeList.get(index) >= maxTime) {
+ final LogUnit newLogUnit = new LogUnit(
+ mKeysList.subList(index, length),
+ mValuesList.subList(index, length),
+ mTimeList.subList(index, length),
+ mIsPotentiallyPrivate.subList(index, length));
+ newLogUnit.mWord = null;
+ newLogUnit.mMayContainDigit = mMayContainDigit;
+ return newLogUnit;
+ }
+ }
+ return new LogUnit();
+ }
}
diff --git a/java/src/com/android/inputmethod/research/MainLogBuffer.java b/java/src/com/android/inputmethod/research/MainLogBuffer.java
index 745768d35..f665e5906 100644
--- a/java/src/com/android/inputmethod/research/MainLogBuffer.java
+++ b/java/src/com/android/inputmethod/research/MainLogBuffer.java
@@ -16,16 +16,22 @@
package com.android.inputmethod.research;
+import android.util.Log;
+
import com.android.inputmethod.latin.Dictionary;
import com.android.inputmethod.latin.Suggest;
import java.util.Random;
public class MainLogBuffer extends LogBuffer {
+ private static final String TAG = MainLogBuffer.class.getSimpleName();
+ // For privacy reasons, be sure to set to "false" for production code.
+ private static final boolean DEBUG = false;
+
// The size of the n-grams logged. E.g. N_GRAM_SIZE = 2 means to sample bigrams.
private static final int N_GRAM_SIZE = 2;
// The number of words between n-grams to omit from the log.
- private static final int DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES = 18;
+ private static final int DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES = DEBUG ? 2 : 18;
private final ResearchLog mResearchLog;
private Suggest mSuggest;
@@ -61,6 +67,9 @@ public class MainLogBuffer extends LogBuffer {
mWordsUntilSafeToSample--;
}
}
+ if (DEBUG) {
+ Log.d(TAG, "shiftedIn " + (newLogUnit.hasWord() ? newLogUnit.getWord() : ""));
+ }
}
public void resetWordCounter() {
@@ -104,7 +113,7 @@ public class MainLogBuffer extends LogBuffer {
final String word = logUnit.getWord();
if (word == null) {
// Digits outside words are a privacy threat.
- if (logUnit.hasDigit()) {
+ if (logUnit.mayContainDigit()) {
return false;
}
} else {
diff --git a/java/src/com/android/inputmethod/research/ResearchLog.java b/java/src/com/android/inputmethod/research/ResearchLog.java
index 70c38e909..96dac55ac 100644
--- a/java/src/com/android/inputmethod/research/ResearchLog.java
+++ b/java/src/com/android/inputmethod/research/ResearchLog.java
@@ -207,7 +207,7 @@ public class ResearchLog {
private static final String UPTIME_KEY = "_ut";
private static final String EVENT_TYPE_KEY = "_ty";
- void outputEvent(final String[] keys, final Object[] values) {
+ void outputEvent(final String[] keys, final Object[] values, final long time) {
// Not thread safe.
if (keys.length == 0) {
return;
@@ -225,7 +225,7 @@ public class ResearchLog {
}
mJsonWriter.beginObject();
mJsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis());
- mJsonWriter.name(UPTIME_KEY).value(SystemClock.uptimeMillis());
+ mJsonWriter.name(UPTIME_KEY).value(time);
mJsonWriter.name(EVENT_TYPE_KEY).value(keys[0]);
final int length = values.length;
for (int i = 0; i < length; i++) {
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index 763fd6e00..2657da285 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -57,9 +57,9 @@ import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.keyboard.MainKeyboardView;
-import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.Dictionary;
+import com.android.inputmethod.latin.InputTypeUtils;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.RichInputConnection;
@@ -143,7 +143,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private final Statistics mStatistics;
private Intent mUploadIntent;
- private PendingIntent mUploadPendingIntent;
private LogUnit mCurrentLogUnit = new LogUnit();
@@ -188,7 +187,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mInputMethodService = ims;
mPrefs = prefs;
mUploadIntent = new Intent(mInputMethodService, UploaderService.class);
- mUploadPendingIntent = PendingIntent.getService(mInputMethodService, 0, mUploadIntent, 0);
if (ProductionFlag.IS_EXPERIMENTAL) {
scheduleUploadingService(mInputMethodService);
@@ -379,7 +377,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
Log.d(TAG, "stop called");
}
logStatistics();
- commitCurrentLogUnit();
+ commitCurrentLogUnit(SystemClock.uptimeMillis());
if (mMainLogBuffer != null) {
publishLogBuffer(mMainLogBuffer, mMainResearchLog, false /* isIncludingPrivateData */);
@@ -427,21 +425,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
private long mResumeTime = 0L;
- private void suspendLoggingUntil(long time) {
- mIsLoggingSuspended = true;
- mResumeTime = time;
- requestIndicatorRedraw();
- }
-
- private void resumeLogging() {
- mResumeTime = 0L;
- updateSuspendedState();
- requestIndicatorRedraw();
- if (isAllowedToLog()) {
- restart();
- }
- }
-
private void updateSuspendedState() {
final long time = System.currentTimeMillis();
if (time > mResumeTime) {
@@ -547,7 +530,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
return;
}
if (includeHistory) {
- commitCurrentLogUnit();
+ commitCurrentLogUnit(SystemClock.uptimeMillis());
} else {
mFeedbackLogBuffer.clear();
}
@@ -556,7 +539,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
feedbackContents
};
feedbackLogUnit.addLogStatement(EVENTKEYS_FEEDBACK, values,
- false /* isPotentiallyPrivate */);
+ SystemClock.uptimeMillis(), false /* isPotentiallyPrivate */);
mFeedbackLogBuffer.shiftIn(feedbackLogUnit);
publishLogBuffer(mFeedbackLogBuffer, mFeedbackLog, true /* isIncludingPrivateData */);
mFeedbackLog.close(new Runnable() {
@@ -658,12 +641,13 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values) {
assert values.length + 1 == keys.length;
if (isAllowedToLog()) {
- mCurrentLogUnit.addLogStatement(keys, values, true /* isPotentiallyPrivate */);
+ final long time = SystemClock.uptimeMillis();
+ mCurrentLogUnit.addLogStatement(keys, values, time, true /* isPotentiallyPrivate */);
}
}
private void setCurrentLogUnitContainsDigitFlag() {
- mCurrentLogUnit.setContainsDigit();
+ mCurrentLogUnit.setMayContainDigit();
}
/**
@@ -681,15 +665,18 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private synchronized void enqueueEvent(final String[] keys, final Object[] values) {
assert values.length + 1 == keys.length;
if (isAllowedToLog()) {
- mCurrentLogUnit.addLogStatement(keys, values, false /* isPotentiallyPrivate */);
+ final long time = SystemClock.uptimeMillis();
+ mCurrentLogUnit.addLogStatement(keys, values, time, false /* isPotentiallyPrivate */);
}
}
- /* package for test */ void commitCurrentLogUnit() {
+ /* package for test */ void commitCurrentLogUnit(final long maxTime) {
if (DEBUG) {
- Log.d(TAG, "commitCurrentLogUnit");
+ Log.d(TAG, "commitCurrentLogUnit" + (mCurrentLogUnit.hasWord() ?
+ ": " + mCurrentLogUnit.getWord() : ""));
}
if (!mCurrentLogUnit.isEmpty()) {
+ final LogUnit newLogUnit = mCurrentLogUnit.splitByTime(maxTime);
if (mMainLogBuffer != null) {
mMainLogBuffer.shiftIn(mCurrentLogUnit);
if (mMainLogBuffer.isSafeToLog() && mMainResearchLog != null) {
@@ -701,37 +688,54 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
if (mFeedbackLogBuffer != null) {
mFeedbackLogBuffer.shiftIn(mCurrentLogUnit);
}
- mCurrentLogUnit = new LogUnit();
+ mCurrentLogUnit = newLogUnit;
Log.d(TAG, "commitCurrentLogUnit");
}
}
+ private static final String[] EVENTKEYS_LOG_SEGMENT_START = {
+ "logSegmentStart", "isIncludingPrivateData"
+ };
+ private static final String[] EVENTKEYS_LOG_SEGMENT_END = {
+ "logSegmentEnd"
+ };
/* package for test */ void publishLogBuffer(final LogBuffer logBuffer,
final ResearchLog researchLog, final boolean isIncludingPrivateData) {
+ final LogUnit openingLogUnit = new LogUnit();
+ final Object[] values = {
+ isIncludingPrivateData
+ };
+ openingLogUnit.addLogStatement(EVENTKEYS_LOG_SEGMENT_START, values,
+ SystemClock.uptimeMillis(), false /* isPotentiallyPrivate */);
+ researchLog.publish(openingLogUnit, true /* isIncludingPrivateData */);
LogUnit logUnit;
while ((logUnit = logBuffer.shiftOut()) != null) {
researchLog.publish(logUnit, isIncludingPrivateData);
}
+ final LogUnit closingLogUnit = new LogUnit();
+ closingLogUnit.addLogStatement(EVENTKEYS_LOG_SEGMENT_END, EVENTKEYS_NULLVALUES,
+ SystemClock.uptimeMillis(), false /* isPotentiallyPrivate */);
+ researchLog.publish(closingLogUnit, true /* isIncludingPrivateData */);
}
- private boolean hasOnlyLetters(final String word) {
+ private boolean hasLetters(final String word) {
final int length = word.length();
for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
final int codePoint = word.codePointAt(i);
- if (!Character.isLetter(codePoint)) {
- return false;
+ if (Character.isLetter(codePoint)) {
+ return true;
}
}
- return true;
+ return false;
}
- private void onWordComplete(final String word) {
+ private void onWordComplete(final String word, final long maxTime) {
Log.d(TAG, "onWordComplete: " + word);
- if (word != null && word.length() > 0 && hasOnlyLetters(word)) {
+ if (word != null && word.length() > 0 && hasLetters(word)) {
mCurrentLogUnit.setWord(word);
mStatistics.recordWordEntered();
}
- commitCurrentLogUnit();
+ commitCurrentLogUnit(maxTime);
}
private static int scrubDigitFromCodePoint(int codePoint) {
@@ -791,8 +795,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static void latinIME_onStartInputViewInternal(final EditorInfo editorInfo,
final SharedPreferences prefs) {
final ResearchLogger researchLogger = getInstance();
- researchLogger.start();
if (editorInfo != null) {
+ final boolean isPassword = InputTypeUtils.isPasswordInputType(editorInfo.inputType)
+ || InputTypeUtils.isVisiblePasswordInputType(editorInfo.inputType);
+ getInstance().setIsPasswordView(isPassword);
+ researchLogger.start();
final Context context = researchLogger.mInputMethodService;
try {
final PackageInfo packageInfo;
@@ -818,10 +825,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
stop();
}
- private static final String[] EVENTKEYS_USER_FEEDBACK = {
- "UserFeedback", "FeedbackContents"
- };
-
private static final String[] EVENTKEYS_PREFS_CHANGED = {
"PrefsChanged", "prefs"
};
@@ -870,7 +873,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final long time = SystemClock.uptimeMillis();
final ResearchLogger researchLogger = getInstance();
final Object[] values = {
- Keyboard.printableCode(scrubDigitFromCodePoint(code)), x, y
+ Constants.printableCode(scrubDigitFromCodePoint(code)), x, y
};
researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_ONCODEINPUT, values);
if (Character.isDigit(code)) {
@@ -903,18 +906,20 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static void latinIME_onWindowHidden(final int savedSelectionStart,
final int savedSelectionEnd, final InputConnection ic) {
if (ic != null) {
- // Capture the TextView contents. This will trigger onUpdateSelection(), so we
- // set sLatinIMEExpectingUpdateSelection so that when onUpdateSelection() is called,
- // it can tell that it was generated by the logging code, and not by the user, and
- // therefore keep user-visible state as is.
- ic.beginBatchEdit();
- ic.performContextMenuAction(android.R.id.selectAll);
- CharSequence charSequence = ic.getSelectedText(0);
- ic.setSelection(savedSelectionStart, savedSelectionEnd);
- ic.endBatchEdit();
- sLatinIMEExpectingUpdateSelection = true;
final Object[] values = new Object[2];
if (OUTPUT_ENTIRE_BUFFER) {
+ // Capture the TextView contents. This will trigger onUpdateSelection(), so we
+ // set sLatinIMEExpectingUpdateSelection so that when onUpdateSelection() is called,
+ // it can tell that it was generated by the logging code, and not by the user, and
+ // therefore keep user-visible state as is.
+ ic.beginBatchEdit();
+ ic.performContextMenuAction(android.R.id.selectAll);
+ CharSequence charSequence = ic.getSelectedText(0);
+ if (savedSelectionStart != -1 && savedSelectionEnd != -1) {
+ ic.setSelection(savedSelectionStart, savedSelectionEnd);
+ }
+ ic.endBatchEdit();
+ sLatinIMEExpectingUpdateSelection = true;
if (TextUtils.isEmpty(charSequence)) {
values[0] = false;
values[1] = "";
@@ -941,7 +946,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
final ResearchLogger researchLogger = getInstance();
researchLogger.enqueueEvent(EVENTKEYS_LATINIME_ONWINDOWHIDDEN, values);
- researchLogger.commitCurrentLogUnit();
+ researchLogger.commitCurrentLogUnit(SystemClock.uptimeMillis());
getInstance().stop();
}
}
@@ -1006,7 +1011,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
};
public static void latinIME_sendKeyCodePoint(final int code) {
final Object[] values = {
- Keyboard.printableCode(scrubDigitFromCodePoint(code))
+ Constants.printableCode(scrubDigitFromCodePoint(code))
};
final ResearchLogger researchLogger = getInstance();
researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_SENDKEYCODEPOINT, values);
@@ -1059,7 +1064,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
keyboard.mOccupiedHeight,
keyboard.mKeys
};
- getInstance().setIsPasswordView(isPasswordView);
getInstance().enqueueEvent(EVENTKEYS_MAINKEYBOARDVIEW_SETKEYBOARD, values);
}
}
@@ -1092,7 +1096,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
if (key != null) {
String outputText = key.getOutputText();
final Object[] values = {
- Keyboard.printableCode(scrubDigitFromCodePoint(code)), outputText == null ? null
+ Constants.printableCode(scrubDigitFromCodePoint(code)), outputText == null ? null
: scrubDigitsFromString(outputText.toString()),
x, y, ignoreModifierKey, altersCode, key.isEnabled()
};
@@ -1109,7 +1113,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final boolean withSliding, final boolean ignoreModifierKey) {
if (key != null) {
final Object[] values = {
- Keyboard.printableCode(scrubDigitFromCodePoint(primaryCode)), withSliding,
+ Constants.printableCode(scrubDigitFromCodePoint(primaryCode)), withSliding,
ignoreModifierKey, key.isEnabled()
};
getInstance().enqueuePotentiallyPrivateEvent(
@@ -1188,7 +1192,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final ResearchLogger researchLogger = getInstance();
researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_RICHINPUTCONNECTION_COMMITTEXT,
values);
- researchLogger.onWordComplete(scrubbedWord);
+ // TODO: Replace Long.MAX_VALUE with timestamp of last data to include
+ researchLogger.onWordComplete(scrubbedWord, Long.MAX_VALUE);
}
private static final String[] EVENTKEYS_RICHINPUTCONNECTION_DELETESURROUNDINGTEXT = {
diff --git a/java/src/com/android/inputmethod/research/Statistics.java b/java/src/com/android/inputmethod/research/Statistics.java
index eab465aa2..2065ab15e 100644
--- a/java/src/com/android/inputmethod/research/Statistics.java
+++ b/java/src/com/android/inputmethod/research/Statistics.java
@@ -16,9 +16,14 @@
package com.android.inputmethod.research;
-import com.android.inputmethod.keyboard.Keyboard;
+import android.util.Log;
+
+import com.android.inputmethod.latin.Constants;
public class Statistics {
+ private static final String TAG = Statistics.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
// Number of characters entered during a typing session
int mCharCount;
// Number of letter characters entered during a typing session
@@ -103,8 +108,11 @@ public class Statistics {
}
public void recordChar(int codePoint, long time) {
+ if (DEBUG) {
+ Log.d(TAG, "recordChar() called");
+ }
final long delta = time - mLastTapTime;
- if (codePoint == Keyboard.CODE_DELETE) {
+ if (codePoint == Constants.CODE_DELETE) {
mDeleteKeyCount++;
if (delta < MIN_DELETION_INTERMISSION) {
if (mIsLastKeyDeleteKey) {