aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/res/drawable-hdpi/unbundled_check_01.pngbin0 -> 1358 bytes
-rw-r--r--java/res/drawable-hdpi/unbundled_check_02.pngbin0 -> 1451 bytes
-rw-r--r--java/res/drawable-hdpi/unbundled_earth_01.pngbin0 -> 2373 bytes
-rw-r--r--java/res/drawable-hdpi/unbundled_earth_02.pngbin0 -> 2680 bytes
-rw-r--r--java/res/drawable-hdpi/unbundled_key_01.pngbin0 -> 1554 bytes
-rw-r--r--java/res/drawable-hdpi/unbundled_key_02.pngbin0 -> 1569 bytes
-rw-r--r--java/res/drawable-hdpi/unbundled_select_01.pngbin0 -> 1636 bytes
-rw-r--r--java/res/drawable-hdpi/unbundled_select_02.pngbin0 -> 2098 bytes
-rw-r--r--java/res/drawable/ic_setup_step1.xml30
-rw-r--r--java/res/drawable/ic_setup_step2.xml30
-rw-r--r--java/res/drawable/ic_setup_step3.xml30
-rw-r--r--java/res/drawable/ic_setup_step3_finish.xml30
-rw-r--r--java/res/drawable/setup_step_action_background.xml30
-rw-r--r--java/res/drawable/setup_step_action_color.xml30
-rw-r--r--java/res/layout/setup_step.xml2
-rw-r--r--java/res/values/attrs.xml4
-rw-r--r--java/res/values/config.xml3
-rw-r--r--java/res/values/dimens.xml3
-rw-r--r--java/res/values/setup-styles.xml4
-rw-r--r--java/res/values/strings.xml37
-rw-r--r--java/res/values/styles.xml4
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java6
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java10
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java37
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java49
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java20
-rw-r--r--java/src/com/android/inputmethod/latin/Constants.java2
-rw-r--r--java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java2
-rw-r--r--java/src/com/android/inputmethod/latin/InputTypeUtils.java1
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java36
-rw-r--r--java/src/com/android/inputmethod/latin/RecapitalizeStatus.java68
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java12
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsFragment.java9
-rw-r--r--java/src/com/android/inputmethod/latin/StringUtils.java65
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeSwitcher.java10
-rw-r--r--java/src/com/android/inputmethod/latin/setup/SetupActivity.java13
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java8
-rw-r--r--java/src/com/android/inputmethod/research/FeedbackFragment.java39
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLog.java16
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogDirectory.java14
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java15
-rw-r--r--java/src/com/android/inputmethod/research/UploaderService.java25
-rw-r--r--native/jni/src/binary_format.h12
-rw-r--r--native/jni/src/char_utils.cpp190
-rw-r--r--native/jni/src/char_utils.h3
-rw-r--r--native/jni/src/defines.h5
-rw-r--r--native/jni/src/digraph_utils.cpp4
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node.h5
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node_state_scoring.h17
-rw-r--r--native/jni/src/suggest/core/policy/weighting.cpp30
-rw-r--r--native/jni/src/suggest/core/policy/weighting.h6
-rw-r--r--native/jni/src/suggest/core/session/dic_traverse_session.cpp2
-rw-r--r--native/jni/src/suggest/core/session/dic_traverse_session.h13
-rw-r--r--native/jni/src/suggest/core/suggest.cpp24
-rw-r--r--native/jni/src/suggest/core/suggest.h15
-rw-r--r--native/jni/src/suggest/policyimpl/typing/scoring_params.cpp6
-rw-r--r--native/jni/src/suggest/policyimpl/typing/typing_traversal.cpp4
-rw-r--r--native/jni/src/suggest/policyimpl/typing/typing_traversal.h8
-rw-r--r--native/jni/src/suggest/policyimpl/typing/typing_weighting.h24
-rw-r--r--tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java5
-rw-r--r--tests/src/com/android/inputmethod/latin/RecapitalizeStatusTests.java42
-rw-r--r--tests/src/com/android/inputmethod/latin/RichInputConnectionTests.java5
-rw-r--r--tests/src/com/android/inputmethod/latin/StringUtilsTests.java22
63 files changed, 839 insertions, 297 deletions
diff --git a/java/res/drawable-hdpi/unbundled_check_01.png b/java/res/drawable-hdpi/unbundled_check_01.png
new file mode 100644
index 000000000..8234399d5
--- /dev/null
+++ b/java/res/drawable-hdpi/unbundled_check_01.png
Binary files differ
diff --git a/java/res/drawable-hdpi/unbundled_check_02.png b/java/res/drawable-hdpi/unbundled_check_02.png
new file mode 100644
index 000000000..6ccd07b55
--- /dev/null
+++ b/java/res/drawable-hdpi/unbundled_check_02.png
Binary files differ
diff --git a/java/res/drawable-hdpi/unbundled_earth_01.png b/java/res/drawable-hdpi/unbundled_earth_01.png
new file mode 100644
index 000000000..3d22f3bfc
--- /dev/null
+++ b/java/res/drawable-hdpi/unbundled_earth_01.png
Binary files differ
diff --git a/java/res/drawable-hdpi/unbundled_earth_02.png b/java/res/drawable-hdpi/unbundled_earth_02.png
new file mode 100644
index 000000000..1998aea56
--- /dev/null
+++ b/java/res/drawable-hdpi/unbundled_earth_02.png
Binary files differ
diff --git a/java/res/drawable-hdpi/unbundled_key_01.png b/java/res/drawable-hdpi/unbundled_key_01.png
new file mode 100644
index 000000000..84591ecb7
--- /dev/null
+++ b/java/res/drawable-hdpi/unbundled_key_01.png
Binary files differ
diff --git a/java/res/drawable-hdpi/unbundled_key_02.png b/java/res/drawable-hdpi/unbundled_key_02.png
new file mode 100644
index 000000000..f366e524c
--- /dev/null
+++ b/java/res/drawable-hdpi/unbundled_key_02.png
Binary files differ
diff --git a/java/res/drawable-hdpi/unbundled_select_01.png b/java/res/drawable-hdpi/unbundled_select_01.png
new file mode 100644
index 000000000..3887fe491
--- /dev/null
+++ b/java/res/drawable-hdpi/unbundled_select_01.png
Binary files differ
diff --git a/java/res/drawable-hdpi/unbundled_select_02.png b/java/res/drawable-hdpi/unbundled_select_02.png
new file mode 100644
index 000000000..6a99b6b09
--- /dev/null
+++ b/java/res/drawable-hdpi/unbundled_select_02.png
Binary files differ
diff --git a/java/res/drawable/ic_setup_step1.xml b/java/res/drawable/ic_setup_step1.xml
new file mode 100644
index 000000000..e26afb3ca
--- /dev/null
+++ b/java/res/drawable/ic_setup_step1.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of 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.
+*/
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="true"
+ android:drawable="@drawable/unbundled_key_01" />
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/unbundled_key_01" />
+ <item
+ android:drawable="@drawable/unbundled_key_02" />
+</selector>
diff --git a/java/res/drawable/ic_setup_step2.xml b/java/res/drawable/ic_setup_step2.xml
new file mode 100644
index 000000000..46db29306
--- /dev/null
+++ b/java/res/drawable/ic_setup_step2.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of 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.
+*/
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="true"
+ android:drawable="@drawable/unbundled_select_01" />
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/unbundled_select_01" />
+ <item
+ android:drawable="@drawable/unbundled_select_02" />
+</selector>
diff --git a/java/res/drawable/ic_setup_step3.xml b/java/res/drawable/ic_setup_step3.xml
new file mode 100644
index 000000000..4ff9fd933
--- /dev/null
+++ b/java/res/drawable/ic_setup_step3.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of 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.
+*/
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="true"
+ android:drawable="@drawable/unbundled_earth_01" />
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/unbundled_earth_01" />
+ <item
+ android:drawable="@drawable/unbundled_earth_02" />
+</selector>
diff --git a/java/res/drawable/ic_setup_step3_finish.xml b/java/res/drawable/ic_setup_step3_finish.xml
new file mode 100644
index 000000000..8ac8a86d1
--- /dev/null
+++ b/java/res/drawable/ic_setup_step3_finish.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of 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.
+*/
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="true"
+ android:drawable="@drawable/unbundled_check_01" />
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/unbundled_check_01" />
+ <item
+ android:drawable="@drawable/unbundled_check_02" />
+</selector>
diff --git a/java/res/drawable/setup_step_action_background.xml b/java/res/drawable/setup_step_action_background.xml
new file mode 100644
index 000000000..25738e3a4
--- /dev/null
+++ b/java/res/drawable/setup_step_action_background.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of 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.
+*/
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="true"
+ android:drawable="@color/setup_text_action" />
+ <item
+ android:state_pressed="true"
+ android:drawable="@color/setup_text_action" />
+ <item
+ android:drawable="@color/setup_step_background" />
+</selector>
diff --git a/java/res/drawable/setup_step_action_color.xml b/java/res/drawable/setup_step_action_color.xml
new file mode 100644
index 000000000..c53e026d5
--- /dev/null
+++ b/java/res/drawable/setup_step_action_color.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of 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.
+*/
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="true"
+ android:color="@color/setup_step_background" />
+ <item
+ android:state_pressed="true"
+ android:color="@color/setup_step_background" />
+ <item
+ android:color="@color/setup_text_action" />
+</selector>
diff --git a/java/res/layout/setup_step.xml b/java/res/layout/setup_step.xml
index 26d7fe799..c15d07bad 100644
--- a/java/res/layout/setup_step.xml
+++ b/java/res/layout/setup_step.xml
@@ -42,7 +42,7 @@
<View
android:layout_width="match_parent"
android:layout_height="2dp" />
- <TextView
+ <Button
android:id="@+id/setup_step_action_label"
style="@style/setupStepActionLabelStyle"
android:gravity="center_vertical"
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 3a7b39e3a..a71e7cc11 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -85,6 +85,8 @@
<attr name="slidingKeyInputEnable" format="boolean" />
<attr name="slidingKeyInputPreviewColor" format="color" />
<attr name="slidingKeyInputPreviewWidth" format="dimension" />
+ <attr name="slidingKeyInputPreviewBodyRatio" format="integer" />
+ <attr name="slidingKeyInputPreviewShadowRatio" format="integer" />
<!-- Key repeat start timeout -->
<attr name="keyRepeatStartTimeout" format="integer" />
<!-- Key repeat interval in millisecond. -->
@@ -115,6 +117,8 @@
<attr name="gesturePreviewTrailColor" format="color" />
<attr name="gesturePreviewTrailStartWidth" format="dimension" />
<attr name="gesturePreviewTrailEndWidth" format="dimension" />
+ <attr name="gesturePreviewTrailBodyRatio" format="integer" />
+ <attr name="gesturePreviewTrailShadowRatio" format="integer" />
<!-- Delay after gesture input and gesture floating preview text dismissing in millisecond -->
<attr name="gestureFloatingPreviewTextLingerTimeout" format="integer" />
<!-- Attributes for GestureFloatingPreviewText -->
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index a90ba8014..d4fff620c 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -58,6 +58,9 @@
<bool name="config_sliding_key_input_enabled">true</bool>
<!-- Sliding key input preview parameters -->
<dimen name="config_sliding_key_input_preview_width">8.0dp</dimen>
+ <!-- Percentages of sliding key input preview body and shadow, in proportion to the width. -->
+ <integer name="config_sliding_key_input_preview_body_ratio">80</integer>
+ <integer name="config_sliding_key_input_preview_shadow_ratio">50</integer>
<integer name="config_key_repeat_start_timeout">400</integer>
<integer name="config_key_repeat_interval">50</integer>
<integer name="config_default_longpress_key_timeout">300</integer> <!-- milliseconds -->
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index dd42acf3c..db33ad812 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -103,6 +103,9 @@
<!-- Gesture preview trail parameters -->
<dimen name="gesture_preview_trail_start_width">10.0dp</dimen>
<dimen name="gesture_preview_trail_end_width">2.5dp</dimen>
+ <!-- Percentages of gesture preview taril body and shadow, in proportion to the trail width. -->
+ <integer name="gesture_preview_trail_body_ratio">80</integer>
+ <integer name="gesture_preview_trail_shadow_ratio">50</integer>
<!-- Gesture floating preview text parameters -->
<dimen name="gesture_floating_preview_text_size">24dp</dimen>
<dimen name="gesture_floating_preview_text_offset">73dp</dimen>
diff --git a/java/res/values/setup-styles.xml b/java/res/values/setup-styles.xml
index cfc689a78..420adcbb7 100644
--- a/java/res/values/setup-styles.xml
+++ b/java/res/values/setup-styles.xml
@@ -38,8 +38,8 @@
<item name="android:textSize">14sp</item>
</style>
<style name="setupStepActionLabelStyle">
- <item name="android:background">@color/setup_step_background</item>
- <item name="android:textColor">@color/setup_text_action</item>
+ <item name="android:background">@drawable/setup_step_action_background</item>
+ <item name="android:textColor">@drawable/setup_step_action_color</item>
<item name="android:textSize">18sp</item>
</style>
</resources>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index dbadfabb8..3d283de23 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -442,31 +442,40 @@
<!-- Title of the button to revert to the default value of the device in the settings dialog [CHAR LIMIT=15] -->
<string name="button_default">Default</string>
- <!-- TODO: Remove translatable="false" once wordings are finalized. -->
+ <!-- Title of the setup wizard welcome screen. [CHAR LIMT=40] -->
+ <string name="setup_welcome_title">"Welcome to <xliff:g id="application_name">%s</xliff:g>"</string>
+ <!-- Additional title of the setup wizard welcome screen, just below the setup_welcome_title. [CHAR_LIMIT=64] -->
+ <string name="setup_welcome_additional_description">with Gesture Typing</string>
+ <!-- The label of the button that starts the setup wizard. [CHAR_LIMIT=64] -->
+ <string name="setup_start_action">Get started</string>
<!-- Title of the setup wizard. [CHAR LIMT=40] -->
- <string name="setup_title" translatable="false">"Installing <xliff:g id="application_name">%s</xliff:g>"</string>
+ <string name="setup_steps_title">"Setting up <xliff:g id="application_name">%s</xliff:g>"</string>
<!-- Ordinal number of the 1st step in the setup wizard. [CHAR LIMIT=5] -->
<string name="setup_step1_bullet" translatable="false">1</string>
<!-- Title of the 1st step in the setup wizard. [CHAR LIMIT=64] -->
- <string name="setup_step1_title" translatable="false">"Enable <xliff:g id="application_name">%s</xliff:g> in settings."</string>
+ <string name="setup_step1_title">"Enable <xliff:g id="application_name">%s</xliff:g>"</string>
<!-- Detailed instruction of the 1st step in the setup wizard. [CHAR LIMIT=80] -->
- <string name="setup_step1_instruction" translatable="false">"For security, please check \"<xliff:g id="application_name">%s</xliff:g>\""</string>
+ <string name="setup_step1_instruction">"Please check \"<xliff:g id="application_name">%s</xliff:g>\" in your Language &amp; input settings. This will authorize it to run on your device."</string>
+ <!-- Title of the Language & input settings. This should be aligned with msgid="5292716747264442359" -->
+ <string name="setup_step1_action">Language &amp; input</string>
<!-- Ordinal number of the 2nd step in the setup wizard. [CHAR LIMIT=5] -->
<string name="setup_step2_bullet" translatable="false">2</string>
<!-- Title of the 2nd step in the setup wizard. [CHAR LIMIT=64] -->
- <string name="setup_step2_title" translatable="false">"Switch to <xliff:g id="application_name">%s</xliff:g>."</string>
+ <string name="setup_step2_title">"Switch to <xliff:g id="application_name">%s</xliff:g>"</string>
<!-- Detailed instruction of the 2nd step in the setup wizard. [CHAR LIMIT=80] -->
- <string name="setup_step2_instruction" translatable="false">"Now that you've enabled <xliff:g id="application_name">%s</xliff:g>, you can switch to it."</string>
+ <string name="setup_step2_instruction">"Now that it's enabled, select \"<xliff:g id="application_name">%s</xliff:g>\", one more time to activate it."</string>
+ <!-- Title of the Input method picker. This should be aligned with msgid="4653387336791222978" -->
+ <string name="setup_step2_action">Choose input method</string>
<!-- Ordinal number of the 3rd step in the setup wizard. [CHAR LIMIT=5] -->
<string name="setup_step3_bullet" translatable="false">3</string>
<!-- Title of the 3rd step in the setup wizard. [CHAR LIMIT=64] -->
- <string name="setup_step3_title" translatable="false">"Congratulations, you're all set!"</string>
+ <string name="setup_step3_title">"Congratulations, you're all set!"</string>
<!-- Detailed instruction of the 3rd step in the setup wizard. [CHAR LIMIT=80] -->
- <string name="setup_step3_instruction" translatable="false">Configure additional languages</string>
- <!-- Title of the Language & input settings. This should be aligned with msgid="5292716747264442359" -->
- <string name="language_settings">Language &amp; input</string>
- <!-- Title of the Input method picker. This should be aligned with msgid="4653387336791222978" -->
- <string name="select_input_method">Choose input method</string>
+ <string name="setup_step3_instruction">Now you can type in all your favorite apps with <xliff:g id="application_name">%s</xliff:g>.</string>
+ <!-- The label of the button that triggers the screen for configuaring additional languages of the keyboard. [CHAR_LIMIT=64] -->
+ <string name="setup_step3_action">Configure additional languages</string>
+ <!-- The label of the button that finishes the setup wizard. [CHAR_LIMIT=64] -->
+ <string name="setup_finish_action">Finished</string>
<!-- Option to show setup wizard icon. [CHAR LIMIT=30]-->
<string name="show_setup_wizard_icon" translatable="false">Show setup wizard icon</string>
@@ -498,9 +507,9 @@
<!-- Message about some dictionary indicating the file is installed, but the dictionary is disabled -->
<string name="dictionary_disabled">Installed, disabled</string>
- <!-- Message to display in the dictionaries setting screen when some error prevented us to list installed dictionaries [CHAR LIMIT=50] -->
+ <!-- Message to display in the dictionaries setting screen when some error prevented us to list installed dictionaries [CHAR LIMIT=20] -->
<string name="cannot_connect_to_dict_service">Problem connecting to dictionary service</string>
- <!-- Message to display in the dictionaries setting screen when we found that no dictionaries are available [CHAR LIMIT=50]-->
+ <!-- Message to display in the dictionaries setting screen when we found that no dictionaries are available [CHAR LIMIT=20]-->
<string name="no_dictionaries_available">No dictionaries available</string>
<!-- Title of the options to press to refresh the list (as in, check for updates now) [CHAR_LIMIT=50] -->
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index fb59c745f..436e080f7 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -70,6 +70,8 @@
<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>
+ <item name="gesturePreviewTrailBodyRatio">@integer/gesture_preview_trail_body_ratio</item>
+ <item name="gesturePreviewTrailShadowRatio">@integer/gesture_preview_trail_shadow_ratio</item>
<!-- Common attributes of MainKeyboardView -->
<item name="keyHysteresisDistance">@dimen/config_key_hysteresis_distance</item>
<item name="keyHysteresisDistanceForSlidingModifier">@dimen/config_key_hysteresis_distance_for_sliding_modifier</item>
@@ -78,6 +80,8 @@
<item name="slidingKeyInputEnable">@bool/config_sliding_key_input_enabled</item>
<item name="slidingKeyInputPreviewColor">@color/highlight_translucent_color_default</item>
<item name="slidingKeyInputPreviewWidth">@dimen/config_sliding_key_input_preview_width</item>
+ <item name="slidingKeyInputPreviewBodyRatio">@integer/config_sliding_key_input_preview_body_ratio</item>
+ <item name="slidingKeyInputPreviewShadowRatio">@integer/config_sliding_key_input_preview_shadow_ratio</item>
<item name="keyRepeatStartTimeout">@integer/config_key_repeat_start_timeout</item>
<item name="keyRepeatInterval">@integer/config_key_repeat_interval</item>
<item name="longPressShiftLockTimeout">@integer/config_longpress_shift_lock_timeout</item>
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index d15f14f88..4e41b77ce 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -207,7 +207,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
* Update keyboard shift state triggered by connected EditText status change.
*/
public void updateShiftState() {
- mState.onUpdateShiftState(mLatinIME.getCurrentAutoCapsState());
+ mState.onUpdateShiftState(mLatinIME.getCurrentAutoCapsState(),
+ mLatinIME.getCurrentRecapitalizeState());
}
// TODO: Remove this method. Come up with a more comprehensive way to reset the keyboard layout
@@ -276,7 +277,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
// Implements {@link KeyboardState.SwitchActions}.
@Override
public void requestUpdatingShiftState() {
- mState.onUpdateShiftState(mLatinIME.getCurrentAutoCapsState());
+ mState.onUpdateShiftState(mLatinIME.getCurrentAutoCapsState(),
+ mLatinIME.getCurrentRecapitalizeState());
}
// Implements {@link KeyboardState.SwitchActions}.
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index ba78d014a..d74644d9e 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -1189,10 +1189,12 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
if (ENABLE_USABILITY_STUDY_LOG) {
writeUsabilityStudyLog(me, action, eventTime, i, pointerId, px, py);
}
- if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- ResearchLogger.mainKeyboardView_processMotionEvent(
- me, action, eventTime, i, pointerId, px, py);
- }
+ // TODO: This seems to be no longer necessary, and confusing because it leads to
+ // duplicate MotionEvents being recorded.
+ // if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
+ // ResearchLogger.mainKeyboardView_processMotionEvent(
+ // me, action, eventTime, i, pointerId, px, py);
+ // }
}
} else {
final PointerTracker tracker = PointerTracker.getPointerTracker(id, this);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
index f682b518f..7fd1bedcb 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
@@ -51,6 +51,9 @@ final class GesturePreviewTrail {
public final int mTrailColor;
public final float mTrailStartWidth;
public final float mTrailEndWidth;
+ public final float mTrailBodyRatio;
+ public boolean mTrailShadowEnabled;
+ public final float mTrailShadowRatio;
public final int mFadeoutStartDelay;
public final int mFadeoutDuration;
public final int mUpdateInterval;
@@ -64,6 +67,14 @@ final class GesturePreviewTrail {
R.styleable.MainKeyboardView_gesturePreviewTrailStartWidth, 0.0f);
mTrailEndWidth = mainKeyboardViewAttr.getDimension(
R.styleable.MainKeyboardView_gesturePreviewTrailEndWidth, 0.0f);
+ final int PERCENTAGE_INT = 100;
+ mTrailBodyRatio = (float)mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_gesturePreviewTrailBodyRatio, PERCENTAGE_INT)
+ / (float)PERCENTAGE_INT;
+ final int trailShadowRatioInt = mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_gesturePreviewTrailShadowRatio, 0);
+ mTrailShadowEnabled = (trailShadowRatioInt > 0);
+ mTrailShadowRatio = (float)trailShadowRatioInt / (float)PERCENTAGE_INT;
mFadeoutStartDelay = mainKeyboardViewAttr.getInt(
R.styleable.MainKeyboardView_gesturePreviewTrailFadeoutStartDelay, 0);
mFadeoutDuration = mainKeyboardViewAttr.getInt(
@@ -97,7 +108,7 @@ final class GesturePreviewTrail {
}
private void addStrokeLocked(final GestureStrokeWithPreviewPoints stroke, final long downTime) {
- final int trailSize = mEventTimes.getLength();
+ final int trailSize = mEventTimes.getLength();
stroke.appendPreviewStroke(mEventTimes, mXCoordinates, mYCoordinates);
if (mEventTimes.getLength() == trailSize) {
return;
@@ -219,14 +230,22 @@ final class GesturePreviewTrail {
final float r2 = getWidth(elapsedTime, params) / 2.0f;
// Draw trail line only when the current point isn't a down point.
if (!isDownEventXCoord(xCoords[i])) {
- final Path path = roundedLine.makePath(p1x, p1y, r1, p2x, p2y, r2);
+ final float body1 = r1 * params.mTrailBodyRatio;
+ final float body2 = r2 * params.mTrailBodyRatio;
+ final Path path = roundedLine.makePath(p1x, p1y, body1, p2x, p2y, body2);
if (path != null) {
+ roundedLine.getBounds(mRoundedLineBounds);
+ if (params.mTrailShadowEnabled) {
+ final float shadow2 = r2 * params.mTrailShadowRatio;
+ paint.setShadowLayer(shadow2, 0.0f, 0.0f, params.mTrailColor);
+ final int shadowInset = -(int)Math.ceil(shadow2);
+ mRoundedLineBounds.inset(shadowInset, shadowInset);
+ }
+ // Take union for the bounds.
+ outBoundsRect.union(mRoundedLineBounds);
final int alpha = getAlpha(elapsedTime, params);
paint.setAlpha(alpha);
canvas.drawPath(path, paint);
- // Take union for the bounds.
- roundedLine.getBounds(mRoundedLineBounds);
- outBoundsRect.union(mRoundedLineBounds);
}
}
p1x = p2x;
@@ -242,14 +261,14 @@ final class GesturePreviewTrail {
System.arraycopy(eventTimes, startIndex, eventTimes, 0, newSize);
System.arraycopy(xCoords, startIndex, xCoords, 0, newSize);
System.arraycopy(yCoords, startIndex, yCoords, 0, newSize);
- // The start index of the last segment of the stroke
- // {@link mLastInterpolatedDrawIndex} should also be updated because all array
- // elements have just been shifted for compaction.
- mLastInterpolatedDrawIndex = Math.max(mLastInterpolatedDrawIndex - startIndex, 0);
}
mEventTimes.setLength(newSize);
mXCoordinates.setLength(newSize);
mYCoordinates.setLength(newSize);
+ // The start index of the last segment of the stroke
+ // {@link mLastInterpolatedDrawIndex} should also be updated because all array
+ // elements have just been shifted for compaction or been zeroed.
+ mLastInterpolatedDrawIndex = Math.max(mLastInterpolatedDrawIndex - startIndex, 0);
}
return newSize > 0;
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index 95d9ccb58..b1d499702 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -20,6 +20,7 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.RecapitalizeStatus;
/**
* Keyboard state machine.
@@ -29,7 +30,7 @@ import com.android.inputmethod.latin.Constants;
* The input events are {@link #onLoadKeyboard()}, {@link #onSaveKeyboardState()},
* {@link #onPressKey(int, boolean, int)}, {@link #onReleaseKey(int, boolean)},
* {@link #onCodeInput(int, boolean, int)}, {@link #onCancelInput(boolean)},
- * {@link #onUpdateShiftState(int)}, {@link #onLongPressTimeout(int)}.
+ * {@link #onUpdateShiftState(int, int)}, {@link #onLongPressTimeout(int)}.
*
* The actions are {@link SwitchActions}'s methods.
*/
@@ -48,7 +49,7 @@ public final class KeyboardState {
public void setSymbolsShiftedKeyboard();
/**
- * Request to call back {@link KeyboardState#onUpdateShiftState(int)}.
+ * Request to call back {@link KeyboardState#onUpdateShiftState(int, int)}.
*/
public void requestUpdatingShiftState();
@@ -80,6 +81,7 @@ public final class KeyboardState {
private boolean mIsSymbolShifted;
private boolean mPrevMainKeyboardWasShiftLocked;
private boolean mPrevSymbolsKeyboardWasShifted;
+ private int mRecapitalizeMode;
// For handling long press.
private boolean mLongPressShiftLockFired;
@@ -110,6 +112,7 @@ public final class KeyboardState {
public KeyboardState(final SwitchActions switchActions) {
mSwitchActions = switchActions;
+ mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE;
}
public void onLoadKeyboard() {
@@ -283,6 +286,7 @@ public final class KeyboardState {
mSwitchActions.setAlphabetKeyboard();
mIsAlphabetMode = true;
mIsSymbolShifted = false;
+ mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE;
mSwitchState = SWITCH_STATE_ALPHA;
mSwitchActions.requestUpdatingShiftState();
}
@@ -386,11 +390,13 @@ public final class KeyboardState {
}
}
- public void onUpdateShiftState(final int autoCaps) {
+ public void onUpdateShiftState(final int autoCaps, final int recapitalizeMode) {
if (DEBUG_EVENT) {
- Log.d(TAG, "onUpdateShiftState: autoCaps=" + autoCaps + " " + this);
+ Log.d(TAG, "onUpdateShiftState: autoCaps=" + autoCaps + ", recapitalizeMode="
+ + recapitalizeMode + " " + this);
}
- updateAlphabetShiftState(autoCaps);
+ mRecapitalizeMode = recapitalizeMode;
+ updateAlphabetShiftState(autoCaps, recapitalizeMode);
}
// TODO: Remove this method. Come up with a more comprehensive way to reset the keyboard layout
@@ -402,8 +408,28 @@ public final class KeyboardState {
resetKeyboardStateToAlphabet();
}
- private void updateAlphabetShiftState(final int autoCaps) {
+ private void updateShiftStateForRecapitalize(final int recapitalizeMode) {
+ switch (recapitalizeMode) {
+ case RecapitalizeStatus.CAPS_MODE_ALL_UPPER:
+ setShifted(SHIFT_LOCK_SHIFTED);
+ break;
+ case RecapitalizeStatus.CAPS_MODE_FIRST_WORD_UPPER:
+ setShifted(AUTOMATIC_SHIFT);
+ break;
+ case RecapitalizeStatus.CAPS_MODE_ALL_LOWER:
+ case RecapitalizeStatus.CAPS_MODE_ORIGINAL_MIXED_CASE:
+ default:
+ setShifted(UNSHIFT);
+ }
+ }
+
+ private void updateAlphabetShiftState(final int autoCaps, final int recapitalizeMode) {
if (!mIsAlphabetMode) return;
+ if (RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE != recapitalizeMode) {
+ // We are recapitalizing. Match the keyboard to the current recapitalize state.
+ updateShiftStateForRecapitalize(recapitalizeMode);
+ return;
+ }
if (!mShiftKeyState.isReleasing()) {
// Ignore update shift state event while the shift key is being pressed (including
// chording).
@@ -421,6 +447,9 @@ public final class KeyboardState {
private void onPressShift() {
mLongPressShiftLockFired = false;
+ // If we are recapitalizing, we don't do any of the normal processing, including
+ // importantly the double tap timer.
+ if (RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE != mRecapitalizeMode) return;
if (mIsAlphabetMode) {
mIsInDoubleTapShiftKey = mSwitchActions.isInDoubleTapTimeout();
if (!mIsInDoubleTapShiftKey) {
@@ -467,7 +496,11 @@ public final class KeyboardState {
}
private void onReleaseShift(final boolean withSliding) {
- if (mIsAlphabetMode) {
+ if (RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE != mRecapitalizeMode) {
+ // We are recapitalizing. We should match the keyboard state to the recapitalize
+ // state in priority.
+ updateShiftStateForRecapitalize(mRecapitalizeMode);
+ } else if (mIsAlphabetMode) {
final boolean isShiftLocked = mAlphabetShiftState.isShiftLocked();
mIsInAlphabetUnshiftedFromShifted = false;
if (mIsInDoubleTapShiftKey) {
@@ -597,7 +630,7 @@ public final class KeyboardState {
// If the code is a letter, update keyboard shift state.
if (Constants.isLetterCode(code)) {
- updateAlphabetShiftState(autoCaps);
+ updateAlphabetShiftState(autoCaps, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE);
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java b/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java
index 37f4e3582..33dbbafa3 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java
@@ -30,7 +30,7 @@ import com.android.inputmethod.latin.R;
* Draw rubber band preview graphics during sliding key input.
*/
public final class SlidingKeyInputPreview extends AbstractDrawingPreview {
- private final int mPreviewWidth;
+ private final float mPreviewBodyRadius;
private boolean mShowSlidingKeyInputPreview;
private final int[] mPreviewFrom = CoordinateUtils.newInstance();
@@ -44,8 +44,20 @@ public final class SlidingKeyInputPreview extends AbstractDrawingPreview {
super(drawingView);
final int previewColor = mainKeyboardViewAttr.getColor(
R.styleable.MainKeyboardView_slidingKeyInputPreviewColor, 0);
- mPreviewWidth = mainKeyboardViewAttr.getDimensionPixelSize(
- R.styleable.MainKeyboardView_slidingKeyInputPreviewWidth, 0);
+ final float previewRadius = mainKeyboardViewAttr.getDimension(
+ R.styleable.MainKeyboardView_slidingKeyInputPreviewWidth, 0) / 2.0f;
+ final int PERCENTAGE_INT = 100;
+ final float previewBodyRatio = (float)mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_slidingKeyInputPreviewBodyRatio, PERCENTAGE_INT)
+ / (float)PERCENTAGE_INT;
+ mPreviewBodyRadius = previewRadius * previewBodyRatio;
+ final int previewShadowRatioInt = mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_slidingKeyInputPreviewShadowRatio, 0);
+ if (previewShadowRatioInt > 0) {
+ final float previewShadowRatio = (float)previewShadowRatioInt / (float)PERCENTAGE_INT;
+ final float shadowRadius = previewRadius * previewShadowRatio;
+ mPaint.setShadowLayer(shadowRadius, 0.0f, 0.0f, previewColor);
+ }
mPaint.setColor(previewColor);
}
@@ -65,7 +77,7 @@ public final class SlidingKeyInputPreview extends AbstractDrawingPreview {
}
// TODO: Finalize the rubber band preview implementation.
- final int radius = mPreviewWidth / 2;
+ final float radius = mPreviewBodyRadius;
final Path path = mRoundedLine.makePath(
CoordinateUtils.x(mPreviewFrom), CoordinateUtils.y(mPreviewFrom), radius,
CoordinateUtils.x(mPreviewTo), CoordinateUtils.y(mPreviewTo), radius);
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index 50e50233e..86bb25562 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -160,6 +160,8 @@ public final class Constants {
public static final int CODE_DOUBLE_QUOTE = '"';
public static final int CODE_QUESTION_MARK = '?';
public static final int CODE_EXCLAMATION_MARK = '!';
+ public static final int CODE_SLASH = '/';
+ public static final int CODE_COMMERCIAL_AT = '@';
// 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?
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index 22d189987..75c2cf2c8 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -252,7 +252,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
}
private static boolean isValidName(final String name) {
- if (name != null && -1 == name.indexOf('@')) {
+ if (name != null && -1 == name.indexOf(Constants.CODE_COMMERCIAL_AT)) {
return true;
}
return false;
diff --git a/java/src/com/android/inputmethod/latin/InputTypeUtils.java b/java/src/com/android/inputmethod/latin/InputTypeUtils.java
index ecb20144b..46194f6e4 100644
--- a/java/src/com/android/inputmethod/latin/InputTypeUtils.java
+++ b/java/src/com/android/inputmethod/latin/InputTypeUtils.java
@@ -33,7 +33,6 @@ public final class InputTypeUtils implements InputType {
private static final int[] SUPPRESSING_AUTO_SPACES_FIELD_VARIATION = {
InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS,
InputType.TYPE_TEXT_VARIATION_PASSWORD,
- InputType.TYPE_TEXT_VARIATION_URI,
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD,
InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD };
public static final int IME_ACTION_CUSTOM_LABEL = EditorInfo.IME_MASK_ACTION + 1;
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index bf4c22d23..0e1c4dc31 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -161,7 +161,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mPositionalInfoForUserDictPendingAddition = null;
private final WordComposer mWordComposer = new WordComposer();
private final RichInputConnection mConnection = new RichInputConnection(this);
- private RecapitalizeStatus mRecapitalizeStatus = null;
+ private final RecapitalizeStatus mRecapitalizeStatus = new RecapitalizeStatus();
// Keep track of the last selection range to decide if we need to show word alternatives
private static final int NOT_A_CURSOR_POSITION = -1;
@@ -742,6 +742,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
resetComposingState(true /* alsoResetLastComposedWord */);
mDeleteCount = 0;
mSpaceState = SPACE_STATE_NONE;
+ mRecapitalizeStatus.deactivate();
mCurrentlyPressedHardwareKeys.clear();
if (mSuggestionStripView != null) {
@@ -925,7 +926,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// We moved the cursor. If we are touching a word, we need to resume suggestion.
mHandler.postResumeSuggestions();
// Reset the last recapitalization.
- mRecapitalizeStatus = null;
+ mRecapitalizeStatus.deactivate();
mKeyboardSwitcher.updateShiftState();
}
mExpectingUpdateSelection = false;
@@ -995,8 +996,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
}
if (!mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) return;
- mApplicationSpecifiedCompletions =
- CompletionInfoUtils.removeNulls(applicationSpecifiedCompletions);
if (applicationSpecifiedCompletions == null) {
clearSuggestionStrip();
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
@@ -1004,6 +1003,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
return;
}
+ mApplicationSpecifiedCompletions =
+ CompletionInfoUtils.removeNulls(applicationSpecifiedCompletions);
final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords =
SuggestedWords.getFromApplicationSpecifiedCompletions(
@@ -1179,6 +1180,15 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
SPACE_STATE_PHANTOM == mSpaceState);
}
+ public int getCurrentRecapitalizeState() {
+ if (!mRecapitalizeStatus.isActive()
+ || !mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) {
+ // Not recapitalizing at the moment
+ return RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE;
+ }
+ return mRecapitalizeStatus.getCurrentMode();
+ }
+
// Factor in auto-caps and manual caps and compute the current caps mode.
private int getActualCapsMode() {
final int keyboardShiftMode = mKeyboardSwitcher.getKeyboardShiftMode();
@@ -1391,7 +1401,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
case Constants.CODE_SHIFT:
// Note: calling back to the keyboard on Shift key is handled in onPressKey()
// and onReleaseKey().
- handleRecapitalize();
+ final Keyboard currentKeyboard = switcher.getKeyboard();
+ if (null != currentKeyboard && currentKeyboard.mId.isAlphabetKeyboard()) {
+ // TODO: Instead of checking for alphabetic keyboard here, separate keycodes for
+ // alphabetic shift and shift while in symbol layout.
+ handleRecapitalize();
+ }
break;
case Constants.CODE_SWITCH_ALPHA_SYMBOL:
// Note: calling back to the keyboard on symbol key is handled in onPressKey()
@@ -1953,10 +1968,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private void handleRecapitalize() {
if (mLastSelectionStart == mLastSelectionEnd) return; // No selection
// If we have a recapitalize in progress, use it; otherwise, create a new one.
- if (null == mRecapitalizeStatus
+ if (!mRecapitalizeStatus.isActive()
|| !mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) {
- mRecapitalizeStatus =
- new RecapitalizeStatus(mLastSelectionStart, mLastSelectionEnd,
+ mRecapitalizeStatus.initialize(mLastSelectionStart, mLastSelectionEnd,
mConnection.getSelectedText(0 /* flags, 0 for no styles */).toString(),
mSettings.getCurrentLocale(), mSettings.getWordSeparators());
// We trim leading and trailing whitespace.
@@ -1979,6 +1993,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mLastSelectionStart = mRecapitalizeStatus.getNewCursorStart();
mLastSelectionEnd = mRecapitalizeStatus.getNewCursorEnd();
mConnection.setSelection(mLastSelectionStart, mLastSelectionEnd);
+ // Match the keyboard to the new state.
+ mKeyboardSwitcher.updateShiftState();
}
// Returns true if we did an autocorrection, false otherwise.
@@ -2413,6 +2429,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) return;
final Range range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(),
0 /* additionalPrecedingWordsCount */);
+ if (null == range) return; // Happens if we don't have an input connection at all
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
final String typedWord = range.mWord.toString();
if (range.mWord instanceof SpannableString) {
@@ -2542,7 +2559,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// This essentially inserts a space, and that's it.
public void promotePhantomSpace() {
- if (mSettings.getCurrent().shouldInsertSpacesAutomatically()) {
+ if (mSettings.getCurrent().shouldInsertSpacesAutomatically()
+ && !mConnection.textBeforeCursorLooksLikeURL()) {
sendKeyCodePoint(Constants.CODE_SPACE);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_promotePhantomSpace();
diff --git a/java/src/com/android/inputmethod/latin/RecapitalizeStatus.java b/java/src/com/android/inputmethod/latin/RecapitalizeStatus.java
index 9edd3a160..8a704ab42 100644
--- a/java/src/com/android/inputmethod/latin/RecapitalizeStatus.java
+++ b/java/src/com/android/inputmethod/latin/RecapitalizeStatus.java
@@ -24,6 +24,7 @@ import java.util.Locale;
* The status of the current recapitalize process.
*/
public class RecapitalizeStatus {
+ public static final int NOT_A_RECAPITALIZE_MODE = -1;
public static final int CAPS_MODE_ORIGINAL_MIXED_CASE = 0;
public static final int CAPS_MODE_ALL_LOWER = 1;
public static final int CAPS_MODE_FIRST_WORD_UPPER = 2;
@@ -37,6 +38,7 @@ public class RecapitalizeStatus {
CAPS_MODE_FIRST_WORD_UPPER,
CAPS_MODE_ALL_UPPER
};
+
private static final int getStringMode(final String string, final String separators) {
if (StringUtils.isIdenticalAfterUpcase(string)) {
return CAPS_MODE_ALL_UPPER;
@@ -50,24 +52,29 @@ public class RecapitalizeStatus {
}
/**
- * We store the location of the cursor and the string that was there before the undoable
+ * We store the location of the cursor and the string that was there before the recapitalize
* action was done, and the location of the cursor and the string that was there after.
*/
private int mCursorStartBefore;
- private int mCursorEndBefore;
private String mStringBefore;
private int mCursorStartAfter;
private int mCursorEndAfter;
private int mRotationStyleCurrentIndex;
- private final boolean mSkipOriginalMixedCaseMode;
- private final Locale mLocale;
- private final String mSeparators;
+ private boolean mSkipOriginalMixedCaseMode;
+ private Locale mLocale;
+ private String mSeparators;
private String mStringAfter;
+ private boolean mIsActive;
+
+ public RecapitalizeStatus() {
+ // By default, initialize with dummy values that won't match any real recapitalize.
+ initialize(-1, -1, "", Locale.getDefault(), "");
+ deactivate();
+ }
- public RecapitalizeStatus(final int cursorStart, final int cursorEnd, final String string,
+ public void initialize(final int cursorStart, final int cursorEnd, final String string,
final Locale locale, final String separators) {
mCursorStartBefore = cursorStart;
- mCursorEndBefore = cursorEnd;
mStringBefore = string;
mCursorStartAfter = cursorStart;
mCursorEndAfter = cursorEnd;
@@ -89,6 +96,15 @@ public class RecapitalizeStatus {
mRotationStyleCurrentIndex = currentMode;
mSkipOriginalMixedCaseMode = true;
}
+ mIsActive = true;
+ }
+
+ public void deactivate() {
+ mIsActive = false;
+ }
+
+ public boolean isActive() {
+ return mIsActive;
}
public boolean isSetAt(final int cursorStart, final int cursorEnd) {
@@ -110,23 +126,23 @@ public class RecapitalizeStatus {
}
++count;
switch (ROTATION_STYLE[mRotationStyleCurrentIndex]) {
- case CAPS_MODE_ORIGINAL_MIXED_CASE:
- mStringAfter = mStringBefore;
- break;
- case CAPS_MODE_ALL_LOWER:
- mStringAfter = mStringBefore.toLowerCase(mLocale);
- break;
- case CAPS_MODE_FIRST_WORD_UPPER:
- mStringAfter = StringUtils.capitalizeEachWord(mStringBefore, mSeparators,
- mLocale);
- break;
- case CAPS_MODE_ALL_UPPER:
- mStringAfter = mStringBefore.toUpperCase(mLocale);
- break;
- default:
- mStringAfter = mStringBefore;
+ case CAPS_MODE_ORIGINAL_MIXED_CASE:
+ mStringAfter = mStringBefore;
+ break;
+ case CAPS_MODE_ALL_LOWER:
+ mStringAfter = mStringBefore.toLowerCase(mLocale);
+ break;
+ case CAPS_MODE_FIRST_WORD_UPPER:
+ mStringAfter = StringUtils.capitalizeEachWord(mStringBefore, mSeparators,
+ mLocale);
+ break;
+ case CAPS_MODE_ALL_UPPER:
+ mStringAfter = mStringBefore.toUpperCase(mLocale);
+ break;
+ default:
+ mStringAfter = mStringBefore;
}
- } while (mStringAfter.equals(oldResult) && count < 5);
+ } while (mStringAfter.equals(oldResult) && count < ROTATION_STYLE.length + 1);
mCursorEndAfter = mCursorStartAfter + mStringAfter.length();
}
@@ -148,7 +164,7 @@ public class RecapitalizeStatus {
if (!Character.isWhitespace(codePoint)) break;
}
if (0 != nonWhitespaceStart || len != nonWhitespaceEnd) {
- mCursorEndBefore = mCursorEndAfter = mCursorStartBefore + nonWhitespaceEnd;
+ mCursorEndAfter = mCursorStartBefore + nonWhitespaceEnd;
mCursorStartBefore = mCursorStartAfter = mCursorStartBefore + nonWhitespaceStart;
mStringAfter = mStringBefore =
mStringBefore.substring(nonWhitespaceStart, nonWhitespaceEnd);
@@ -166,4 +182,8 @@ public class RecapitalizeStatus {
public int getNewCursorEnd() {
return mCursorEndAfter;
}
+
+ public int getCurrentMode() {
+ return ROTATION_STYLE[mRotationStyleCurrentIndex];
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index e17846618..8ed7ab264 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -19,7 +19,6 @@ package com.android.inputmethod.latin;
import android.inputmethodservice.InputMethodService;
import android.text.SpannableString;
import android.text.TextUtils;
-import android.text.style.SuggestionSpan;
import android.util.Log;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
@@ -721,4 +720,15 @@ public final class RichInputConnection {
// position and the expected position, then it must be a belated update.
return (newSelStart - oldSelStart) * (mCurrentCursorPosition - newSelStart) >= 0;
}
+
+ /**
+ * Looks at the text just before the cursor to find out if it looks like a URL.
+ *
+ * The weakest point here is, if we don't have enough text bufferized, we may fail to realize
+ * we are in URL situation, but other places in this class have the same limitation and it
+ * does not matter too much in the practice.
+ */
+ public boolean textBeforeCursorLooksLikeURL() {
+ return StringUtils.lastPartLooksLikeURL(mCommittedTextBeforeComposingText);
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java
index a96c997c8..79036c276 100644
--- a/java/src/com/android/inputmethod/latin/SettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java
@@ -77,10 +77,13 @@ public final class SettingsFragment extends InputMethodSettingsFragment
final Resources res = getResources();
final Context context = getActivity();
- // When we are called from the Settings application but we are not already running, the
- // {@link SubtypeLocale} class may not have been initialized. It is safe to call
- // {@link SubtypeLocale#init(Context)} multiple times.
+ // When we are called from the Settings application but we are not already running, some
+ // singleton and utility classes may not have been initialized. We have to call
+ // initialization method of these classes here. See {@link LatinIME#onCreate()}.
+ SubtypeSwitcher.init(context);
SubtypeLocale.init(context);
+ AudioAndHapticFeedbackManager.init(context);
+
mVoicePreference = (ListPreference) findPreference(Settings.PREF_VOICE_MODE);
mShowCorrectionSuggestionsPreference =
(ListPreference) findPreference(Settings.PREF_SHOW_SUGGESTIONS_SETTING);
diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java
index 7f1e7c619..d5ee58a63 100644
--- a/java/src/com/android/inputmethod/latin/StringUtils.java
+++ b/java/src/com/android/inputmethod/latin/StringUtils.java
@@ -282,4 +282,69 @@ public final class StringUtils {
}
return builder.toString();
}
+
+ /**
+ * Approximates whether the text before the cursor looks like a URL.
+ *
+ * This is not foolproof, but it should work well in the practice.
+ * Essentially it walks backward from the cursor until it finds something that's not a letter,
+ * digit, or common URL symbol like underscore. If it hasn't found a period yet, then it
+ * does not look like a URL.
+ * If the text:
+ * - starts with www and contains a period
+ * - starts with a slash preceded by either a slash, whitespace, or start-of-string
+ * Then it looks like a URL and we return true. Otherwise, we return false.
+ *
+ * Note: this method is called quite often, and should be fast.
+ *
+ * TODO: This will return that "abc./def" and ".abc/def" look like URLs to keep down the
+ * code complexity, but ideally it should not. It's acceptable for now.
+ */
+ public static boolean lastPartLooksLikeURL(final CharSequence text) {
+ int i = text.length();
+ if (0 == i) return false;
+ int wCount = 0;
+ int slashCount = 0;
+ boolean hasSlash = false;
+ boolean hasPeriod = false;
+ int codePoint = 0;
+ while (i > 0) {
+ codePoint = Character.codePointBefore(text, i);
+ if (codePoint < Constants.CODE_PERIOD || codePoint > 'z') {
+ // Handwavy heuristic to see if that's a URL character. Anything between period
+ // and z. This includes all lower- and upper-case ascii letters, period,
+ // underscore, arrobase, question mark, equal sign. It excludes spaces, exclamation
+ // marks, double quotes...
+ // Anything that's not a URL-like character causes us to break from here and
+ // evaluate normally.
+ break;
+ }
+ if (Constants.CODE_PERIOD == codePoint) {
+ hasPeriod = true;
+ }
+ if (Constants.CODE_SLASH == codePoint) {
+ hasSlash = true;
+ if (2 == ++slashCount) {
+ return true;
+ }
+ } else {
+ slashCount = 0;
+ }
+ if ('w' == codePoint) {
+ ++wCount;
+ } else {
+ wCount = 0;
+ }
+ i = Character.offsetByCodePoints(text, i, -1);
+ }
+ // End of the text run.
+ // If it starts with www and includes a period, then it looks like a URL.
+ if (wCount >= 3 && hasPeriod) return true;
+ // If it starts with a slash, and the code point before is whitespace, it looks like an URL.
+ if (1 == slashCount && (0 == i || Character.isWhitespace(codePoint))) return true;
+ // If it has both a period and a slash, it looks like an URL.
+ if (hasPeriod && hasSlash) return true;
+ // Otherwise, it doesn't look like an URL.
+ return false;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index 2f9e34ff1..bef8a3cf1 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -80,6 +80,7 @@ public final class SubtypeSwitcher {
public static void init(final Context context) {
SubtypeLocale.init(context);
+ RichInputMethodManager.init(context);
sInstance.initialize(context);
}
@@ -87,10 +88,13 @@ public final class SubtypeSwitcher {
// Intentional empty constructor for singleton.
}
- private void initialize(final Context service) {
- mResources = service.getResources();
+ private void initialize(final Context context) {
+ if (mResources != null) {
+ return;
+ }
+ mResources = context.getResources();
mRichImm = RichInputMethodManager.getInstance();
- mConnectivityManager = (ConnectivityManager) service.getSystemService(
+ mConnectivityManager = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
mNoLanguageSubtype = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
SubtypeLocale.NO_LANGUAGE, SubtypeLocale.QWERTY);
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
index 15d0bac37..099169aa9 100644
--- a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
+++ b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
@@ -20,7 +20,6 @@ import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
-import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Message;
@@ -113,13 +112,13 @@ public final class SetupActivity extends Activity {
// the SDK version.
final TextView titleView = (TextView)findViewById(R.id.setup_title);
final int appName = getApplicationInfo().labelRes;
- titleView.setText(getString(R.string.setup_title, getString(appName)));
+ titleView.setText(getString(R.string.setup_steps_title, getString(appName)));
mStepIndicatorView = (SetupStepIndicatorView)findViewById(R.id.setup_step_indicator);
final SetupStep step1 = new SetupStep(findViewById(R.id.setup_step1),
appName, R.string.setup_step1_title, R.string.setup_step1_instruction,
- R.drawable.ic_settings_language, R.string.language_settings);
+ R.drawable.ic_setup_step1, R.string.setup_step1_action);
step1.setAction(new Runnable() {
@Override
public void run() {
@@ -131,7 +130,7 @@ public final class SetupActivity extends Activity {
final SetupStep step2 = new SetupStep(findViewById(R.id.setup_step2),
appName, R.string.setup_step2_title, R.string.setup_step2_instruction,
- 0 /* actionIcon */, R.string.select_input_method);
+ R.drawable.ic_setup_step2, R.string.setup_step2_action);
step2.setAction(new Runnable() {
@Override
public void run() {
@@ -143,8 +142,8 @@ public final class SetupActivity extends Activity {
mSetupSteps.addStep(STEP_2, step2);
final SetupStep step3 = new SetupStep(findViewById(R.id.setup_step3),
- appName, R.string.setup_step3_title, 0 /* instruction */,
- R.drawable.sym_keyboard_language_switch, R.string.setup_step3_instruction);
+ appName, R.string.setup_step3_title, R.string.setup_step3_instruction,
+ R.drawable.ic_setup_step3, R.string.setup_step3_action);
step3.setAction(new Runnable() {
@Override
public void run() {
@@ -314,9 +313,7 @@ public final class SetupActivity extends Activity {
final int paddingEnd = ViewCompatUtils.getPaddingEnd(mActionLabel);
ViewCompatUtils.setPaddingRelative(mActionLabel, paddingEnd, 0, paddingEnd, 0);
} else {
- final int overrideColor = res.getColor(R.color.setup_text_action);
final Drawable icon = res.getDrawable(actionIcon);
- icon.setColorFilter(overrideColor, PorterDuff.Mode.MULTIPLY);
icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
TextViewCompatUtils.setCompoundDrawablesRelative(
mActionLabel, icon, null, null, null);
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index 96b2c818d..da8657201 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -189,10 +189,12 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
int letterCount = 0;
for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) {
final int codePoint = text.codePointAt(i);
- // Any word containing a '@' is probably an e-mail address
- // Any word containing a '/' is probably either an ad-hoc combination of two
+ // Any word containing a COMMERCIAL_AT is probably an e-mail address
+ // Any word containing a SLASH is probably either an ad-hoc combination of two
// words or a URI - in either case we don't want to spell check that
- if ('@' == codePoint || '/' == codePoint) return true;
+ if (Constants.CODE_COMMERCIAL_AT == codePoint || Constants.CODE_SLASH == codePoint) {
+ return true;
+ }
if (isLetterCheckableByLanguage(codePoint, script)) ++letterCount;
}
// Guestimate heuristic: perform spell checking if at least 3/4 of the characters
diff --git a/java/src/com/android/inputmethod/research/FeedbackFragment.java b/java/src/com/android/inputmethod/research/FeedbackFragment.java
index 39f9c87a0..a0738292e 100644
--- a/java/src/com/android/inputmethod/research/FeedbackFragment.java
+++ b/java/src/com/android/inputmethod/research/FeedbackFragment.java
@@ -65,12 +65,10 @@ public class FeedbackFragment extends Fragment implements OnClickListener {
mCancelButton.setOnClickListener(this);
if (savedInstanceState != null) {
- Log.d(TAG, "restoring from savedInstanceState");
restoreState(savedInstanceState);
} else {
final Bundle bundle = getActivity().getIntent().getExtras();
if (bundle != null) {
- Log.d(TAG, "restoring from getArguments()");
restoreState(bundle);
}
}
@@ -81,10 +79,7 @@ public class FeedbackFragment extends Fragment implements OnClickListener {
public void onClick(final View view) {
final ResearchLogger researchLogger = ResearchLogger.getInstance();
if (view == mIncludingUserRecordingCheckBox) {
- if (hasUserRecording()) {
- // Remove the recording
- setHasUserRecording(false);
- } else {
+ if (mIncludingUserRecordingCheckBox.isChecked()) {
final Bundle bundle = new Bundle();
onSaveInstanceState(bundle);
@@ -103,9 +98,9 @@ public class FeedbackFragment extends Fragment implements OnClickListener {
R.string.research_feedback_empty_feedback_error_message,
Toast.LENGTH_LONG).show();
} else {
- final boolean isIncludingAccountName = isIncludingAccountName();
- researchLogger.sendFeedback(feedbackContents,
- false /* isIncludingHistory */, isIncludingAccountName, hasUserRecording());
+ final boolean isIncludingAccountName = mIncludingAccountNameCheckBox.isChecked();
+ researchLogger.sendFeedback(feedbackContents, false /* isIncludingHistory */,
+ isIncludingAccountName, mIncludingUserRecordingCheckBox.isChecked());
getActivity().finish();
researchLogger.setFeedbackDialogBundle(null);
researchLogger.onLeavingSendFeedbackDialog();
@@ -125,29 +120,13 @@ public class FeedbackFragment extends Fragment implements OnClickListener {
final String savedFeedbackString = mEditText.getText().toString();
bundle.putString(KEY_FEEDBACK_STRING, savedFeedbackString);
- bundle.putBoolean(KEY_INCLUDE_ACCOUNT_NAME, isIncludingAccountName());
- bundle.putBoolean(KEY_HAS_USER_RECORDING, hasUserRecording());
+ bundle.putBoolean(KEY_INCLUDE_ACCOUNT_NAME, mIncludingAccountNameCheckBox.isChecked());
+ bundle.putBoolean(KEY_HAS_USER_RECORDING, mIncludingUserRecordingCheckBox.isChecked());
}
- public void restoreState(final Bundle bundle) {
+ private void restoreState(final Bundle bundle) {
mEditText.setText(bundle.getString(KEY_FEEDBACK_STRING));
- setIsIncludingAccountName(bundle.getBoolean(KEY_INCLUDE_ACCOUNT_NAME));
- setHasUserRecording(bundle.getBoolean(KEY_HAS_USER_RECORDING));
- }
-
- private boolean hasUserRecording() {
- return mIncludingUserRecordingCheckBox.isChecked();
- }
-
- private void setHasUserRecording(final boolean hasRecording) {
- mIncludingUserRecordingCheckBox.setChecked(hasRecording);
- }
-
- private boolean isIncludingAccountName() {
- return mIncludingAccountNameCheckBox.isChecked();
- }
-
- private void setIsIncludingAccountName(final boolean isIncludingAccountName) {
- mIncludingAccountNameCheckBox.setChecked(isIncludingAccountName);
+ mIncludingAccountNameCheckBox.setChecked(bundle.getBoolean(KEY_INCLUDE_ACCOUNT_NAME));
+ mIncludingUserRecordingCheckBox.setChecked(bundle.getBoolean(KEY_HAS_USER_RECORDING));
}
}
diff --git a/java/src/com/android/inputmethod/research/ResearchLog.java b/java/src/com/android/inputmethod/research/ResearchLog.java
index 35a491f2c..18bf7ba54 100644
--- a/java/src/com/android/inputmethod/research/ResearchLog.java
+++ b/java/src/com/android/inputmethod/research/ResearchLog.java
@@ -108,10 +108,14 @@ public class ResearchLog {
@Override
public Object call() throws Exception {
try {
- if (mHasWrittenData) {
- mJsonWriter.endArray();
- mHasWrittenData = false;
+ // TODO: This is necessary to avoid an exception. Better would be to not even
+ // open the JsonWriter if the file is not even opened unless there is valid data
+ // to write.
+ if (!mHasWrittenData) {
+ mJsonWriter.beginArray();
}
+ mJsonWriter.endArray();
+ mHasWrittenData = false;
mJsonWriter.flush();
mJsonWriter.close();
if (DEBUG) {
@@ -159,6 +163,12 @@ public class ResearchLog {
public Object call() throws Exception {
try {
if (mHasWrittenData) {
+ // TODO: This is necessary to avoid an exception. Better would be to not
+ // even open the JsonWriter if the file is not even opened unless there is
+ // valid data to write.
+ if (!mHasWrittenData) {
+ mJsonWriter.beginArray();
+ }
mJsonWriter.endArray();
mJsonWriter.close();
mHasWrittenData = false;
diff --git a/java/src/com/android/inputmethod/research/ResearchLogDirectory.java b/java/src/com/android/inputmethod/research/ResearchLogDirectory.java
index 291dea5d0..d156068d6 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogDirectory.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogDirectory.java
@@ -97,15 +97,17 @@ public class ResearchLogDirectory {
}
}
- public File getLogFilePath(final long time) {
- return new File(mFilesDir, getUniqueFilename(LOG_FILENAME_PREFIX, time));
+ public File getLogFilePath(final long time, final long nanoTime) {
+ return new File(mFilesDir, getUniqueFilename(LOG_FILENAME_PREFIX, time, nanoTime));
}
- public File getUserRecordingFilePath(final long time) {
- return new File(mFilesDir, getUniqueFilename(USER_RECORDING_FILENAME_PREFIX, time));
+ public File getUserRecordingFilePath(final long time, final long nanoTime) {
+ return new File(mFilesDir, getUniqueFilename(USER_RECORDING_FILENAME_PREFIX, time,
+ nanoTime));
}
- private static String getUniqueFilename(final String prefix, final long time) {
- return prefix + "-" + time + FILENAME_SUFFIX;
+ private static String getUniqueFilename(final String prefix, final long time,
+ final long nanoTime) {
+ return prefix + "-" + time + "-" + nanoTime + FILENAME_SUFFIX;
}
}
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index 7a23ddb05..cd18e3de6 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -389,7 +389,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
if (mMainLogBuffer == null) {
mMainResearchLog = new ResearchLog(mResearchLogDirectory.getLogFilePath(
- System.currentTimeMillis()), mLatinIME);
+ System.currentTimeMillis(), System.nanoTime()), mLatinIME);
final int numWordsToIgnore = new Random().nextInt(NUMBER_OF_WORDS_BETWEEN_SAMPLES + 1);
mMainLogBuffer = new MainLogBuffer(NUMBER_OF_WORDS_BETWEEN_SAMPLES, numWordsToIgnore,
mSuggest) {
@@ -420,7 +420,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private void resetFeedbackLogging() {
mFeedbackLog = new ResearchLog(mResearchLogDirectory.getLogFilePath(
- System.currentTimeMillis()), mLatinIME);
+ System.currentTimeMillis(), System.nanoTime()), mLatinIME);
mFeedbackLogBuffer = new FixedLogBuffer(FEEDBACK_WORD_BUFFER_SIZE);
}
@@ -545,7 +545,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mUserRecordingLog.blockingAbort(RESEARCHLOG_ABORT_TIMEOUT_IN_MS);
}
mUserRecordingFile = mResearchLogDirectory.getUserRecordingFilePath(
- System.currentTimeMillis());
+ System.currentTimeMillis(), System.nanoTime());
mUserRecordingLog = new ResearchLog(mUserRecordingFile, mLatinIME);
mUserRecordingLogBuffer = new LogBuffer();
resetRecordingTimer();
@@ -813,7 +813,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
// enabled. The dot is actually a zero-width, zero-height rectangle, placed at the
// lower-right corner of the canvas, painted with a non-zero border width.
paint.setStrokeWidth(3);
- canvas.drawRect(width, height, width, height, paint);
+ canvas.drawRect(width - 1, height - 1, width, height, paint);
}
paint.setColor(savedColor);
paint.setStyle(savedStyle);
@@ -894,7 +894,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
// Check that expected word matches.
if (oldLogUnit != null) {
final String oldLogUnitWord = oldLogUnit.getWord();
- if (!oldLogUnitWord.equals(expectedWord)) {
+ if (oldLogUnitWord != null && !oldLogUnitWord.equals(expectedWord)) {
return;
}
}
@@ -1107,7 +1107,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
packageInfo = mLatinIME.getPackageManager().getPackageInfo(mLatinIME.getPackageName(),
0);
final String versionName = packageInfo.versionName;
- return !(developerBuildRegex.matcher(versionName).find());
+ return developerBuildRegex.matcher(versionName).find();
} catch (final NameNotFoundException e) {
Log.e(TAG, "Could not determine package name", e);
return false;
@@ -1826,6 +1826,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static void latinIME_onEndBatchInput(final CharSequence enteredText,
final int enteredWordPos, final SuggestedWords suggestedWords) {
final ResearchLogger researchLogger = getInstance();
+ if (!TextUtils.isEmpty(enteredText) && hasLetters(enteredText.toString())) {
+ researchLogger.mCurrentLogUnit.setWord(enteredText.toString());
+ }
researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_ONENDBATCHINPUT, enteredText,
enteredWordPos);
researchLogger.mCurrentLogUnit.initializeSuggestions(suggestedWords);
diff --git a/java/src/com/android/inputmethod/research/UploaderService.java b/java/src/com/android/inputmethod/research/UploaderService.java
index 6a9717b7c..d2db34927 100644
--- a/java/src/com/android/inputmethod/research/UploaderService.java
+++ b/java/src/com/android/inputmethod/research/UploaderService.java
@@ -22,6 +22,7 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.os.SystemClock;
import com.android.inputmethod.latin.define.ProductionFlag;
@@ -79,28 +80,14 @@ public final class UploaderService extends IntentService {
*/
public static void cancelAndRescheduleUploadingService(final Context context,
final boolean needsRescheduling) {
- final PendingIntent pendingIntent = getPendingIntentForService(context);
+ final Intent intent = new Intent(context, UploaderService.class);
+ final PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
final AlarmManager alarmManager = (AlarmManager) context.getSystemService(
Context.ALARM_SERVICE);
- cancelAnyScheduledServiceAlarm(alarmManager, pendingIntent);
+ alarmManager.cancel(pendingIntent);
if (needsRescheduling) {
- scheduleServiceAlarm(alarmManager, pendingIntent);
+ alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()
+ + UploaderService.RUN_INTERVAL, pendingIntent);
}
}
-
- private static PendingIntent getPendingIntentForService(final Context context) {
- final Intent intent = new Intent(context, UploaderService.class);
- return PendingIntent.getService(context, 0, intent, 0);
- }
-
- private static void cancelAnyScheduledServiceAlarm(final AlarmManager alarmManager,
- final PendingIntent pendingIntent) {
- alarmManager.cancel(pendingIntent);
- }
-
- private static void scheduleServiceAlarm(final AlarmManager alarmManager,
- final PendingIntent pendingIntent) {
- alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, UploaderService.RUN_INTERVAL,
- pendingIntent);
- }
}
diff --git a/native/jni/src/binary_format.h b/native/jni/src/binary_format.h
index 1c4061fd8..2d2e19501 100644
--- a/native/jni/src/binary_format.h
+++ b/native/jni/src/binary_format.h
@@ -92,6 +92,7 @@ class BinaryFormat {
const int unigramProbability, const int bigramProbability);
static int getProbability(const int position, const std::map<int, int> *bigramMap,
const uint8_t *bigramFilter, const int unigramProbability);
+ static float getMultiWordCostMultiplier(const uint8_t *const dict);
// Flags for special processing
// Those *must* match the flags in makedict (BinaryDictInputOutput#*_PROCESSING_FLAG) or
@@ -241,6 +242,17 @@ AK_FORCE_INLINE int BinaryFormat::getGroupCountAndForwardPointer(const uint8_t *
return ((msb & 0x7F) << 8) | dict[(*pos)++];
}
+inline float BinaryFormat::getMultiWordCostMultiplier(const uint8_t *const dict) {
+ const int headerValue = readHeaderValueInt(dict, "MULTIPLE_WORDS_DEMOTION_RATE");
+ if (headerValue == S_INT_MIN) {
+ return 1.0f;
+ }
+ if (headerValue <= 0) {
+ return static_cast<float>(MAX_VALUE_FOR_WEIGHTING);
+ }
+ return 100.0f / static_cast<float>(headerValue);
+}
+
inline uint8_t BinaryFormat::getFlagsAndForwardPointer(const uint8_t *const dict, int *pos) {
return dict[(*pos)++];
}
diff --git a/native/jni/src/char_utils.cpp b/native/jni/src/char_utils.cpp
index 8d917ea74..e219beb62 100644
--- a/native/jni/src/char_utils.cpp
+++ b/native/jni/src/char_utils.cpp
@@ -45,18 +45,16 @@ struct LatinCapitalSmallPair {
extern "C" int main() {
for (unsigned short c = 0; c < 0xFFFF; c++) {
- const unsigned short baseC = c < NELEMS(BASE_CHARS) ? BASE_CHARS[c] : c;
- if (baseC <= 0x7F) continue;
- const unsigned short icu4cLowerBaseC = u_tolower(baseC);
- const unsigned short myLowerBaseC = latin_tolower(baseC);
- if (baseC != icu4cLowerBaseC) {
+ if (c <= 0x7F) continue;
+ const unsigned short icu4cLowerC = u_tolower(c);
+ const unsigned short myLowerC = latin_tolower(c);
+ if (c != icu4cLowerC) {
#ifdef CONFIRMING_CHAR_UTILS
- if (icu4cLowerBaseC != myLowerBaseC) {
- fprintf(stderr, "icu4cLowerBaseC != myLowerBaseC, 0x%04X, 0x%04X\n",
- icu4cLowerBaseC, myLowerBaseC);
+ if (icu4cLowerC != myLowerC) {
+ fprintf(stderr, "icu4cLowerC != myLowerC, 0x%04X, 0x%04X\n", icu4cLowerC, myLowerC);
}
#else // CONFIRMING_CHAR_UTILS
- printf("0x%04X, 0x%04X\n", baseC, icu4cLowerBaseC);
+ printf("0x%04X, 0x%04X\n", c, icu4cLowerC);
#endif // CONFIRMING_CHAR_UTILS
}
}
@@ -77,14 +75,99 @@ extern "C" int main() {
* $
*/
static const struct LatinCapitalSmallPair SORTED_CHAR_MAP[] = {
+ { 0x00C0, 0x00E0 }, // LATIN CAPITAL LETTER A WITH GRAVE
+ { 0x00C1, 0x00E1 }, // LATIN CAPITAL LETTER A WITH ACUTE
+ { 0x00C2, 0x00E2 }, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ { 0x00C3, 0x00E3 }, // LATIN CAPITAL LETTER A WITH TILDE
+ { 0x00C4, 0x00E4 }, // LATIN CAPITAL LETTER A WITH DIAERESIS
+ { 0x00C5, 0x00E5 }, // LATIN CAPITAL LETTER A WITH RING ABOVE
{ 0x00C6, 0x00E6 }, // LATIN CAPITAL LETTER AE
+ { 0x00C7, 0x00E7 }, // LATIN CAPITAL LETTER C WITH CEDILLA
+ { 0x00C8, 0x00E8 }, // LATIN CAPITAL LETTER E WITH GRAVE
+ { 0x00C9, 0x00E9 }, // LATIN CAPITAL LETTER E WITH ACUTE
+ { 0x00CA, 0x00EA }, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ { 0x00CB, 0x00EB }, // LATIN CAPITAL LETTER E WITH DIAERESIS
+ { 0x00CC, 0x00EC }, // LATIN CAPITAL LETTER I WITH GRAVE
+ { 0x00CD, 0x00ED }, // LATIN CAPITAL LETTER I WITH ACUTE
+ { 0x00CE, 0x00EE }, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ { 0x00CF, 0x00EF }, // LATIN CAPITAL LETTER I WITH DIAERESIS
{ 0x00D0, 0x00F0 }, // LATIN CAPITAL LETTER ETH
+ { 0x00D1, 0x00F1 }, // LATIN CAPITAL LETTER N WITH TILDE
+ { 0x00D2, 0x00F2 }, // LATIN CAPITAL LETTER O WITH GRAVE
+ { 0x00D3, 0x00F3 }, // LATIN CAPITAL LETTER O WITH ACUTE
+ { 0x00D4, 0x00F4 }, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ { 0x00D5, 0x00F5 }, // LATIN CAPITAL LETTER O WITH TILDE
+ { 0x00D6, 0x00F6 }, // LATIN CAPITAL LETTER O WITH DIAERESIS
+ { 0x00D8, 0x00F8 }, // LATIN CAPITAL LETTER O WITH STROKE
+ { 0x00D9, 0x00F9 }, // LATIN CAPITAL LETTER U WITH GRAVE
+ { 0x00DA, 0x00FA }, // LATIN CAPITAL LETTER U WITH ACUTE
+ { 0x00DB, 0x00FB }, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ { 0x00DC, 0x00FC }, // LATIN CAPITAL LETTER U WITH DIAERESIS
+ { 0x00DD, 0x00FD }, // LATIN CAPITAL LETTER Y WITH ACUTE
{ 0x00DE, 0x00FE }, // LATIN CAPITAL LETTER THORN
+ { 0x0100, 0x0101 }, // LATIN CAPITAL LETTER A WITH MACRON
+ { 0x0102, 0x0103 }, // LATIN CAPITAL LETTER A WITH BREVE
+ { 0x0104, 0x0105 }, // LATIN CAPITAL LETTER A WITH OGONEK
+ { 0x0106, 0x0107 }, // LATIN CAPITAL LETTER C WITH ACUTE
+ { 0x0108, 0x0109 }, // LATIN CAPITAL LETTER C WITH CIRCUMFLEX
+ { 0x010A, 0x010B }, // LATIN CAPITAL LETTER C WITH DOT ABOVE
+ { 0x010C, 0x010D }, // LATIN CAPITAL LETTER C WITH CARON
+ { 0x010E, 0x010F }, // LATIN CAPITAL LETTER D WITH CARON
{ 0x0110, 0x0111 }, // LATIN CAPITAL LETTER D WITH STROKE
+ { 0x0112, 0x0113 }, // LATIN CAPITAL LETTER E WITH MACRON
+ { 0x0114, 0x0115 }, // LATIN CAPITAL LETTER E WITH BREVE
+ { 0x0116, 0x0117 }, // LATIN CAPITAL LETTER E WITH DOT ABOVE
+ { 0x0118, 0x0119 }, // LATIN CAPITAL LETTER E WITH OGONEK
+ { 0x011A, 0x011B }, // LATIN CAPITAL LETTER E WITH CARON
+ { 0x011C, 0x011D }, // LATIN CAPITAL LETTER G WITH CIRCUMFLEX
+ { 0x011E, 0x011F }, // LATIN CAPITAL LETTER G WITH BREVE
+ { 0x0120, 0x0121 }, // LATIN CAPITAL LETTER G WITH DOT ABOVE
+ { 0x0122, 0x0123 }, // LATIN CAPITAL LETTER G WITH CEDILLA
+ { 0x0124, 0x0125 }, // LATIN CAPITAL LETTER H WITH CIRCUMFLEX
{ 0x0126, 0x0127 }, // LATIN CAPITAL LETTER H WITH STROKE
+ { 0x0128, 0x0129 }, // LATIN CAPITAL LETTER I WITH TILDE
+ { 0x012A, 0x012B }, // LATIN CAPITAL LETTER I WITH MACRON
+ { 0x012C, 0x012D }, // LATIN CAPITAL LETTER I WITH BREVE
+ { 0x012E, 0x012F }, // LATIN CAPITAL LETTER I WITH OGONEK
+ { 0x0130, 0x0069 }, // LATIN CAPITAL LETTER I WITH DOT ABOVE
+ { 0x0132, 0x0133 }, // LATIN CAPITAL LIGATURE IJ
+ { 0x0134, 0x0135 }, // LATIN CAPITAL LETTER J WITH CIRCUMFLEX
+ { 0x0136, 0x0137 }, // LATIN CAPITAL LETTER K WITH CEDILLA
+ { 0x0139, 0x013A }, // LATIN CAPITAL LETTER L WITH ACUTE
+ { 0x013B, 0x013C }, // LATIN CAPITAL LETTER L WITH CEDILLA
+ { 0x013D, 0x013E }, // LATIN CAPITAL LETTER L WITH CARON
+ { 0x013F, 0x0140 }, // LATIN CAPITAL LETTER L WITH MIDDLE DOT
+ { 0x0141, 0x0142 }, // LATIN CAPITAL LETTER L WITH STROKE
+ { 0x0143, 0x0144 }, // LATIN CAPITAL LETTER N WITH ACUTE
+ { 0x0145, 0x0146 }, // LATIN CAPITAL LETTER N WITH CEDILLA
+ { 0x0147, 0x0148 }, // LATIN CAPITAL LETTER N WITH CARON
{ 0x014A, 0x014B }, // LATIN CAPITAL LETTER ENG
+ { 0x014C, 0x014D }, // LATIN CAPITAL LETTER O WITH MACRON
+ { 0x014E, 0x014F }, // LATIN CAPITAL LETTER O WITH BREVE
+ { 0x0150, 0x0151 }, // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
{ 0x0152, 0x0153 }, // LATIN CAPITAL LIGATURE OE
+ { 0x0154, 0x0155 }, // LATIN CAPITAL LETTER R WITH ACUTE
+ { 0x0156, 0x0157 }, // LATIN CAPITAL LETTER R WITH CEDILLA
+ { 0x0158, 0x0159 }, // LATIN CAPITAL LETTER R WITH CARON
+ { 0x015A, 0x015B }, // LATIN CAPITAL LETTER S WITH ACUTE
+ { 0x015C, 0x015D }, // LATIN CAPITAL LETTER S WITH CIRCUMFLEX
+ { 0x015E, 0x015F }, // LATIN CAPITAL LETTER S WITH CEDILLA
+ { 0x0160, 0x0161 }, // LATIN CAPITAL LETTER S WITH CARON
+ { 0x0162, 0x0163 }, // LATIN CAPITAL LETTER T WITH CEDILLA
+ { 0x0164, 0x0165 }, // LATIN CAPITAL LETTER T WITH CARON
{ 0x0166, 0x0167 }, // LATIN CAPITAL LETTER T WITH STROKE
+ { 0x0168, 0x0169 }, // LATIN CAPITAL LETTER U WITH TILDE
+ { 0x016A, 0x016B }, // LATIN CAPITAL LETTER U WITH MACRON
+ { 0x016C, 0x016D }, // LATIN CAPITAL LETTER U WITH BREVE
+ { 0x016E, 0x016F }, // LATIN CAPITAL LETTER U WITH RING ABOVE
+ { 0x0170, 0x0171 }, // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+ { 0x0172, 0x0173 }, // LATIN CAPITAL LETTER U WITH OGONEK
+ { 0x0174, 0x0175 }, // LATIN CAPITAL LETTER W WITH CIRCUMFLEX
+ { 0x0176, 0x0177 }, // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
+ { 0x0178, 0x00FF }, // LATIN CAPITAL LETTER Y WITH DIAERESIS
+ { 0x0179, 0x017A }, // LATIN CAPITAL LETTER Z WITH ACUTE
+ { 0x017B, 0x017C }, // LATIN CAPITAL LETTER Z WITH DOT ABOVE
+ { 0x017D, 0x017E }, // LATIN CAPITAL LETTER Z WITH CARON
{ 0x0181, 0x0253 }, // LATIN CAPITAL LETTER B WITH HOOK
{ 0x0182, 0x0183 }, // LATIN CAPITAL LETTER B WITH TOPBAR
{ 0x0184, 0x0185 }, // LATIN CAPITAL LETTER TONE SIX
@@ -105,6 +188,7 @@ static const struct LatinCapitalSmallPair SORTED_CHAR_MAP[] = {
{ 0x019C, 0x026F }, // LATIN CAPITAL LETTER TURNED M
{ 0x019D, 0x0272 }, // LATIN CAPITAL LETTER N WITH LEFT HOOK
{ 0x019F, 0x0275 }, // LATIN CAPITAL LETTER O WITH MIDDLE TILDE
+ { 0x01A0, 0x01A1 }, // LATIN CAPITAL LETTER O WITH HORN
{ 0x01A2, 0x01A3 }, // LATIN CAPITAL LETTER OI
{ 0x01A4, 0x01A5 }, // LATIN CAPITAL LETTER P WITH HOOK
{ 0x01A6, 0x0280 }, // LATIN LETTER YR
@@ -112,6 +196,7 @@ static const struct LatinCapitalSmallPair SORTED_CHAR_MAP[] = {
{ 0x01A9, 0x0283 }, // LATIN CAPITAL LETTER ESH
{ 0x01AC, 0x01AD }, // LATIN CAPITAL LETTER T WITH HOOK
{ 0x01AE, 0x0288 }, // LATIN CAPITAL LETTER T WITH RETROFLEX HOOK
+ { 0x01AF, 0x01B0 }, // LATIN CAPITAL LETTER U WITH HORN
{ 0x01B1, 0x028A }, // LATIN CAPITAL LETTER UPSILON
{ 0x01B2, 0x028B }, // LATIN CAPITAL LETTER V WITH HOOK
{ 0x01B3, 0x01B4 }, // LATIN CAPITAL LETTER Y WITH HOOK
@@ -119,13 +204,64 @@ static const struct LatinCapitalSmallPair SORTED_CHAR_MAP[] = {
{ 0x01B7, 0x0292 }, // LATIN CAPITAL LETTER EZH
{ 0x01B8, 0x01B9 }, // LATIN CAPITAL LETTER EZH REVERSED
{ 0x01BC, 0x01BD }, // LATIN CAPITAL LETTER TONE FIVE
+ { 0x01C4, 0x01C6 }, // LATIN CAPITAL LETTER DZ WITH CARON
+ { 0x01C5, 0x01C6 }, // LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
+ { 0x01C7, 0x01C9 }, // LATIN CAPITAL LETTER LJ
+ { 0x01C8, 0x01C9 }, // LATIN CAPITAL LETTER L WITH SMALL LETTER J
+ { 0x01CA, 0x01CC }, // LATIN CAPITAL LETTER NJ
+ { 0x01CB, 0x01CC }, // LATIN CAPITAL LETTER N WITH SMALL LETTER J
+ { 0x01CD, 0x01CE }, // LATIN CAPITAL LETTER A WITH CARON
+ { 0x01CF, 0x01D0 }, // LATIN CAPITAL LETTER I WITH CARON
+ { 0x01D1, 0x01D2 }, // LATIN CAPITAL LETTER O WITH CARON
+ { 0x01D3, 0x01D4 }, // LATIN CAPITAL LETTER U WITH CARON
+ { 0x01D5, 0x01D6 }, // LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON
+ { 0x01D7, 0x01D8 }, // LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE
+ { 0x01D9, 0x01DA }, // LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON
+ { 0x01DB, 0x01DC }, // LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE
+ { 0x01DE, 0x01DF }, // LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON
+ { 0x01E0, 0x01E1 }, // LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON
+ { 0x01E2, 0x01E3 }, // LATIN CAPITAL LETTER AE WITH MACRON
{ 0x01E4, 0x01E5 }, // LATIN CAPITAL LETTER G WITH STROKE
+ { 0x01E6, 0x01E7 }, // LATIN CAPITAL LETTER G WITH CARON
+ { 0x01E8, 0x01E9 }, // LATIN CAPITAL LETTER K WITH CARON
+ { 0x01EA, 0x01EB }, // LATIN CAPITAL LETTER O WITH OGONEK
+ { 0x01EC, 0x01ED }, // LATIN CAPITAL LETTER O WITH OGONEK AND MACRON
+ { 0x01EE, 0x01EF }, // LATIN CAPITAL LETTER EZH WITH CARON
+ { 0x01F1, 0x01F3 }, // LATIN CAPITAL LETTER DZ
+ { 0x01F2, 0x01F3 }, // LATIN CAPITAL LETTER D WITH SMALL LETTER Z
+ { 0x01F4, 0x01F5 }, // LATIN CAPITAL LETTER G WITH ACUTE
{ 0x01F6, 0x0195 }, // LATIN CAPITAL LETTER HWAIR
{ 0x01F7, 0x01BF }, // LATIN CAPITAL LETTER WYNN
+ { 0x01F8, 0x01F9 }, // LATIN CAPITAL LETTER N WITH GRAVE
+ { 0x01FA, 0x01FB }, // LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
+ { 0x01FC, 0x01FD }, // LATIN CAPITAL LETTER AE WITH ACUTE
+ { 0x01FE, 0x01FF }, // LATIN CAPITAL LETTER O WITH STROKE AND ACUTE
+ { 0x0200, 0x0201 }, // LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
+ { 0x0202, 0x0203 }, // LATIN CAPITAL LETTER A WITH INVERTED BREVE
+ { 0x0204, 0x0205 }, // LATIN CAPITAL LETTER E WITH DOUBLE GRAVE
+ { 0x0206, 0x0207 }, // LATIN CAPITAL LETTER E WITH INVERTED BREVE
+ { 0x0208, 0x0209 }, // LATIN CAPITAL LETTER I WITH DOUBLE GRAVE
+ { 0x020A, 0x020B }, // LATIN CAPITAL LETTER I WITH INVERTED BREVE
+ { 0x020C, 0x020D }, // LATIN CAPITAL LETTER O WITH DOUBLE GRAVE
+ { 0x020E, 0x020F }, // LATIN CAPITAL LETTER O WITH INVERTED BREVE
+ { 0x0210, 0x0211 }, // LATIN CAPITAL LETTER R WITH DOUBLE GRAVE
+ { 0x0212, 0x0213 }, // LATIN CAPITAL LETTER R WITH INVERTED BREVE
+ { 0x0214, 0x0215 }, // LATIN CAPITAL LETTER U WITH DOUBLE GRAVE
+ { 0x0216, 0x0217 }, // LATIN CAPITAL LETTER U WITH INVERTED BREVE
+ { 0x0218, 0x0219 }, // LATIN CAPITAL LETTER S WITH COMMA BELOW
+ { 0x021A, 0x021B }, // LATIN CAPITAL LETTER T WITH COMMA BELOW
{ 0x021C, 0x021D }, // LATIN CAPITAL LETTER YOGH
+ { 0x021E, 0x021F }, // LATIN CAPITAL LETTER H WITH CARON
{ 0x0220, 0x019E }, // LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
{ 0x0222, 0x0223 }, // LATIN CAPITAL LETTER OU
{ 0x0224, 0x0225 }, // LATIN CAPITAL LETTER Z WITH HOOK
+ { 0x0226, 0x0227 }, // LATIN CAPITAL LETTER A WITH DOT ABOVE
+ { 0x0228, 0x0229 }, // LATIN CAPITAL LETTER E WITH CEDILLA
+ { 0x022A, 0x022B }, // LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON
+ { 0x022C, 0x022D }, // LATIN CAPITAL LETTER O WITH TILDE AND MACRON
+ { 0x022E, 0x022F }, // LATIN CAPITAL LETTER O WITH DOT ABOVE
+ { 0x0230, 0x0231 }, // LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON
+ { 0x0232, 0x0233 }, // LATIN CAPITAL LETTER Y WITH MACRON
{ 0x023A, 0x2C65 }, // LATIN CAPITAL LETTER A WITH STROKE
{ 0x023B, 0x023C }, // LATIN CAPITAL LETTER C WITH STROKE
{ 0x023D, 0x019A }, // LATIN CAPITAL LETTER L WITH BAR
@@ -142,6 +278,13 @@ static const struct LatinCapitalSmallPair SORTED_CHAR_MAP[] = {
{ 0x0370, 0x0371 }, // GREEK CAPITAL LETTER HETA
{ 0x0372, 0x0373 }, // GREEK CAPITAL LETTER ARCHAIC SAMPI
{ 0x0376, 0x0377 }, // GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA
+ { 0x0386, 0x03AC }, // GREEK CAPITAL LETTER ALPHA WITH TONOS
+ { 0x0388, 0x03AD }, // GREEK CAPITAL LETTER EPSILON WITH TONOS
+ { 0x0389, 0x03AE }, // GREEK CAPITAL LETTER ETA WITH TONOS
+ { 0x038A, 0x03AF }, // GREEK CAPITAL LETTER IOTA WITH TONOS
+ { 0x038C, 0x03CC }, // GREEK CAPITAL LETTER OMICRON WITH TONOS
+ { 0x038E, 0x03CD }, // GREEK CAPITAL LETTER UPSILON WITH TONOS
+ { 0x038F, 0x03CE }, // GREEK CAPITAL LETTER OMEGA WITH TONOS
{ 0x0391, 0x03B1 }, // GREEK CAPITAL LETTER ALPHA
{ 0x0392, 0x03B2 }, // GREEK CAPITAL LETTER BETA
{ 0x0393, 0x03B3 }, // GREEK CAPITAL LETTER GAMMA
@@ -166,6 +309,8 @@ static const struct LatinCapitalSmallPair SORTED_CHAR_MAP[] = {
{ 0x03A7, 0x03C7 }, // GREEK CAPITAL LETTER CHI
{ 0x03A8, 0x03C8 }, // GREEK CAPITAL LETTER PSI
{ 0x03A9, 0x03C9 }, // GREEK CAPITAL LETTER OMEGA
+ { 0x03AA, 0x03CA }, // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+ { 0x03AB, 0x03CB }, // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
{ 0x03CF, 0x03D7 }, // GREEK CAPITAL KAI SYMBOL
{ 0x03D8, 0x03D9 }, // GREEK LETTER ARCHAIC KOPPA
{ 0x03DA, 0x03DB }, // GREEK LETTER STIGMA
@@ -179,19 +324,28 @@ static const struct LatinCapitalSmallPair SORTED_CHAR_MAP[] = {
{ 0x03EA, 0x03EB }, // COPTIC CAPITAL LETTER GANGIA
{ 0x03EC, 0x03ED }, // COPTIC CAPITAL LETTER SHIMA
{ 0x03EE, 0x03EF }, // COPTIC CAPITAL LETTER DEI
+ { 0x03F4, 0x03B8 }, // GREEK CAPITAL THETA SYMBOL
{ 0x03F7, 0x03F8 }, // GREEK CAPITAL LETTER SHO
+ { 0x03F9, 0x03F2 }, // GREEK CAPITAL LUNATE SIGMA SYMBOL
{ 0x03FA, 0x03FB }, // GREEK CAPITAL LETTER SAN
{ 0x03FD, 0x037B }, // GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL
{ 0x03FE, 0x037C }, // GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL
{ 0x03FF, 0x037D }, // GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL
+ { 0x0400, 0x0450 }, // CYRILLIC CAPITAL LETTER IE WITH GRAVE
+ { 0x0401, 0x0451 }, // CYRILLIC CAPITAL LETTER IO
{ 0x0402, 0x0452 }, // CYRILLIC CAPITAL LETTER DJE
+ { 0x0403, 0x0453 }, // CYRILLIC CAPITAL LETTER GJE
{ 0x0404, 0x0454 }, // CYRILLIC CAPITAL LETTER UKRAINIAN IE
{ 0x0405, 0x0455 }, // CYRILLIC CAPITAL LETTER DZE
{ 0x0406, 0x0456 }, // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+ { 0x0407, 0x0457 }, // CYRILLIC CAPITAL LETTER YI
{ 0x0408, 0x0458 }, // CYRILLIC CAPITAL LETTER JE
{ 0x0409, 0x0459 }, // CYRILLIC CAPITAL LETTER LJE
{ 0x040A, 0x045A }, // CYRILLIC CAPITAL LETTER NJE
{ 0x040B, 0x045B }, // CYRILLIC CAPITAL LETTER TSHE
+ { 0x040C, 0x045C }, // CYRILLIC CAPITAL LETTER KJE
+ { 0x040D, 0x045D }, // CYRILLIC CAPITAL LETTER I WITH GRAVE
+ { 0x040E, 0x045E }, // CYRILLIC CAPITAL LETTER SHORT U
{ 0x040F, 0x045F }, // CYRILLIC CAPITAL LETTER DZHE
{ 0x0410, 0x0430 }, // CYRILLIC CAPITAL LETTER A
{ 0x0411, 0x0431 }, // CYRILLIC CAPITAL LETTER BE
@@ -236,6 +390,7 @@ static const struct LatinCapitalSmallPair SORTED_CHAR_MAP[] = {
{ 0x0470, 0x0471 }, // CYRILLIC CAPITAL LETTER PSI
{ 0x0472, 0x0473 }, // CYRILLIC CAPITAL LETTER FITA
{ 0x0474, 0x0475 }, // CYRILLIC CAPITAL LETTER IZHITSA
+ { 0x0476, 0x0477 }, // CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
{ 0x0478, 0x0479 }, // CYRILLIC CAPITAL LETTER UK
{ 0x047A, 0x047B }, // CYRILLIC CAPITAL LETTER ROUND OMEGA
{ 0x047C, 0x047D }, // CYRILLIC CAPITAL LETTER OMEGA WITH TITLO
@@ -269,17 +424,34 @@ static const struct LatinCapitalSmallPair SORTED_CHAR_MAP[] = {
{ 0x04BC, 0x04BD }, // CYRILLIC CAPITAL LETTER ABKHASIAN CHE
{ 0x04BE, 0x04BF }, // CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER
{ 0x04C0, 0x04CF }, // CYRILLIC LETTER PALOCHKA
+ { 0x04C1, 0x04C2 }, // CYRILLIC CAPITAL LETTER ZHE WITH BREVE
{ 0x04C3, 0x04C4 }, // CYRILLIC CAPITAL LETTER KA WITH HOOK
{ 0x04C5, 0x04C6 }, // CYRILLIC CAPITAL LETTER EL WITH TAIL
{ 0x04C7, 0x04C8 }, // CYRILLIC CAPITAL LETTER EN WITH HOOK
{ 0x04C9, 0x04CA }, // CYRILLIC CAPITAL LETTER EN WITH TAIL
{ 0x04CB, 0x04CC }, // CYRILLIC CAPITAL LETTER KHAKASSIAN CHE
{ 0x04CD, 0x04CE }, // CYRILLIC CAPITAL LETTER EM WITH TAIL
+ { 0x04D0, 0x04D1 }, // CYRILLIC CAPITAL LETTER A WITH BREVE
+ { 0x04D2, 0x04D3 }, // CYRILLIC CAPITAL LETTER A WITH DIAERESIS
{ 0x04D4, 0x04D5 }, // CYRILLIC CAPITAL LIGATURE A IE
+ { 0x04D6, 0x04D7 }, // CYRILLIC CAPITAL LETTER IE WITH BREVE
{ 0x04D8, 0x04D9 }, // CYRILLIC CAPITAL LETTER SCHWA
+ { 0x04DA, 0x04DB }, // CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS
+ { 0x04DC, 0x04DD }, // CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS
+ { 0x04DE, 0x04DF }, // CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS
{ 0x04E0, 0x04E1 }, // CYRILLIC CAPITAL LETTER ABKHASIAN DZE
+ { 0x04E2, 0x04E3 }, // CYRILLIC CAPITAL LETTER I WITH MACRON
+ { 0x04E4, 0x04E5 }, // CYRILLIC CAPITAL LETTER I WITH DIAERESIS
+ { 0x04E6, 0x04E7 }, // CYRILLIC CAPITAL LETTER O WITH DIAERESIS
{ 0x04E8, 0x04E9 }, // CYRILLIC CAPITAL LETTER BARRED O
+ { 0x04EA, 0x04EB }, // CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS
+ { 0x04EC, 0x04ED }, // CYRILLIC CAPITAL LETTER E WITH DIAERESIS
+ { 0x04EE, 0x04EF }, // CYRILLIC CAPITAL LETTER U WITH MACRON
+ { 0x04F0, 0x04F1 }, // CYRILLIC CAPITAL LETTER U WITH DIAERESIS
+ { 0x04F2, 0x04F3 }, // CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE
+ { 0x04F4, 0x04F5 }, // CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS
{ 0x04F6, 0x04F7 }, // CYRILLIC CAPITAL LETTER GHE WITH DESCENDER
+ { 0x04F8, 0x04F9 }, // CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS
{ 0x04FA, 0x04FB }, // CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK
{ 0x04FC, 0x04FD }, // CYRILLIC CAPITAL LETTER HA WITH HOOK
{ 0x04FE, 0x04FF }, // CYRILLIC CAPITAL LETTER HA WITH STROKE
diff --git a/native/jni/src/char_utils.h b/native/jni/src/char_utils.h
index 58d388dbf..b429f40b2 100644
--- a/native/jni/src/char_utils.h
+++ b/native/jni/src/char_utils.h
@@ -58,7 +58,8 @@ inline static int toBaseCodePoint(int c) {
AK_FORCE_INLINE static int toLowerCase(const int c) {
if (isAsciiUpper(c)) {
return toAsciiLower(c);
- } else if (isAscii(c)) {
+ }
+ if (isAscii(c)) {
return c;
}
return static_cast<int>(latin_tolower(static_cast<unsigned short>(c)));
diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h
index a7b023a75..6ef9f414b 100644
--- a/native/jni/src/defines.h
+++ b/native/jni/src/defines.h
@@ -424,10 +424,9 @@ typedef enum {
CT_OMISSION,
CT_INSERTION,
CT_TRANSPOSITION,
- CT_SPACE_SUBSTITUTION,
- CT_SPACE_OMISSION,
CT_COMPLETION,
CT_TERMINAL,
- CT_NEW_WORD,
+ CT_NEW_WORD_SPACE_OMITTION,
+ CT_NEW_WORD_SPACE_SUBSTITUTION,
} CorrectionType;
#endif // LATINIME_DEFINES_H
diff --git a/native/jni/src/digraph_utils.cpp b/native/jni/src/digraph_utils.cpp
index 6a1ab0271..083442669 100644
--- a/native/jni/src/digraph_utils.cpp
+++ b/native/jni/src/digraph_utils.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "char_utils.h"
#include "binary_format.h"
#include "defines.h"
#include "digraph_utils.h"
@@ -120,10 +121,11 @@ const DigraphUtils::DigraphType DigraphUtils::USED_DIGRAPH_TYPES[] =
/* static */ const DigraphUtils::digraph_t *DigraphUtils::getDigraphForDigraphTypeAndCodePoint(
const DigraphUtils::DigraphType digraphType, const int compositeGlyphCodePoint) {
const DigraphUtils::digraph_t *digraphs = 0;
+ const int compositeGlyphLowerCodePoint = toLowerCase(compositeGlyphCodePoint);
const int digraphsSize =
DigraphUtils::getAllDigraphsForDictionaryAndReturnSize(digraphType, &digraphs);
for (int i = 0; i < digraphsSize; i++) {
- if (digraphs[i].compositeGlyph == compositeGlyphCodePoint) {
+ if (digraphs[i].compositeGlyph == compositeGlyphLowerCodePoint) {
return &digraphs[i];
}
}
diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h
index 32faae52c..f8d2df452 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node.h
@@ -360,11 +360,6 @@ class DicNode {
return mDicNodeState.mDicNodeStateScoring.getCompoundDistance(languageWeight);
}
- // Note that "cost" means delta for "distance" that is weighted.
- float getTotalPrevWordsLanguageCost() const {
- return mDicNodeState.mDicNodeStateScoring.getTotalPrevWordsLanguageCost();
- }
-
// Used to commit input partially
int getPrevWordNodePos() const {
return mDicNodeState.mDicNodeStatePrevWord.getPrevWordNodePos();
diff --git a/native/jni/src/suggest/core/dicnode/dic_node_state_scoring.h b/native/jni/src/suggest/core/dicnode/dic_node_state_scoring.h
index 8902d3122..fd9d610e3 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node_state_scoring.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node_state_scoring.h
@@ -31,7 +31,7 @@ class DicNodeStateScoring {
mDigraphIndex(DigraphUtils::NOT_A_DIGRAPH_INDEX),
mEditCorrectionCount(0), mProximityCorrectionCount(0),
mNormalizedCompoundDistance(0.0f), mSpatialDistance(0.0f), mLanguageDistance(0.0f),
- mTotalPrevWordsLanguageCost(0.0f), mRawLength(0.0f) {
+ mRawLength(0.0f) {
}
virtual ~DicNodeStateScoring() {}
@@ -42,7 +42,6 @@ class DicNodeStateScoring {
mNormalizedCompoundDistance = 0.0f;
mSpatialDistance = 0.0f;
mLanguageDistance = 0.0f;
- mTotalPrevWordsLanguageCost = 0.0f;
mRawLength = 0.0f;
mDoubleLetterLevel = NOT_A_DOUBLE_LETTER;
mDigraphIndex = DigraphUtils::NOT_A_DIGRAPH_INDEX;
@@ -54,7 +53,6 @@ class DicNodeStateScoring {
mNormalizedCompoundDistance = scoring->mNormalizedCompoundDistance;
mSpatialDistance = scoring->mSpatialDistance;
mLanguageDistance = scoring->mLanguageDistance;
- mTotalPrevWordsLanguageCost = scoring->mTotalPrevWordsLanguageCost;
mRawLength = scoring->mRawLength;
mDoubleLetterLevel = scoring->mDoubleLetterLevel;
mDigraphIndex = scoring->mDigraphIndex;
@@ -70,9 +68,6 @@ class DicNodeStateScoring {
if (isProximityCorrection) {
++mProximityCorrectionCount;
}
- if (languageCost > 0.0f) {
- setTotalPrevWordsLanguageCost(mTotalPrevWordsLanguageCost + languageCost);
- }
}
void addRawLength(const float rawLength) {
@@ -148,10 +143,6 @@ class DicNodeStateScoring {
}
}
- float getTotalPrevWordsLanguageCost() const {
- return mTotalPrevWordsLanguageCost;
- }
-
private:
// Caution!!!
// Use a default copy constructor and an assign operator because shallow copies are ok
@@ -165,7 +156,6 @@ class DicNodeStateScoring {
float mNormalizedCompoundDistance;
float mSpatialDistance;
float mLanguageDistance;
- float mTotalPrevWordsLanguageCost;
float mRawLength;
AK_FORCE_INLINE void addDistance(float spatialDistance, float languageDistance,
@@ -179,11 +169,6 @@ class DicNodeStateScoring {
/ static_cast<float>(max(1, totalInputIndex));
}
}
-
- //TODO: remove
- AK_FORCE_INLINE void setTotalPrevWordsLanguageCost(float totalPrevWordsLanguageCost) {
- mTotalPrevWordsLanguageCost = totalPrevWordsLanguageCost;
- }
};
} // namespace latinime
#endif // LATINIME_DIC_NODE_STATE_SCORING_H
diff --git a/native/jni/src/suggest/core/policy/weighting.cpp b/native/jni/src/suggest/core/policy/weighting.cpp
index e62b70423..b9c0b8129 100644
--- a/native/jni/src/suggest/core/policy/weighting.cpp
+++ b/native/jni/src/suggest/core/policy/weighting.cpp
@@ -38,7 +38,7 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n
case CT_SUBSTITUTION:
PROF_SUBSTITUTION(node->mProfiler);
return;
- case CT_NEW_WORD:
+ case CT_NEW_WORD_SPACE_OMITTION:
PROF_NEW_WORD(node->mProfiler);
return;
case CT_MATCH:
@@ -50,7 +50,7 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n
case CT_TERMINAL:
PROF_TERMINAL(node->mProfiler);
return;
- case CT_SPACE_SUBSTITUTION:
+ case CT_NEW_WORD_SPACE_SUBSTITUTION:
PROF_SPACE_SUBSTITUTION(node->mProfiler);
return;
case CT_INSERTION:
@@ -107,16 +107,16 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n
case CT_SUBSTITUTION:
// only used for typing
return weighting->getSubstitutionCost();
- case CT_NEW_WORD:
- return weighting->getNewWordCost(dicNode);
+ case CT_NEW_WORD_SPACE_OMITTION:
+ return weighting->getNewWordCost(traverseSession, dicNode);
case CT_MATCH:
return weighting->getMatchedCost(traverseSession, dicNode, inputStateG);
case CT_COMPLETION:
return weighting->getCompletionCost(traverseSession, dicNode);
case CT_TERMINAL:
return weighting->getTerminalSpatialCost(traverseSession, dicNode);
- case CT_SPACE_SUBSTITUTION:
- return weighting->getSpaceSubstitutionCost();
+ case CT_NEW_WORD_SPACE_SUBSTITUTION:
+ return weighting->getSpaceSubstitutionCost(traverseSession, dicNode);
case CT_INSERTION:
return weighting->getInsertionCost(traverseSession, parentDicNode, dicNode);
case CT_TRANSPOSITION:
@@ -135,7 +135,7 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n
return 0.0f;
case CT_SUBSTITUTION:
return 0.0f;
- case CT_NEW_WORD:
+ case CT_NEW_WORD_SPACE_OMITTION:
return weighting->getNewWordBigramCost(traverseSession, parentDicNode, bigramCacheMap);
case CT_MATCH:
return 0.0f;
@@ -147,8 +147,8 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n
traverseSession->getOffsetDict(), dicNode, bigramCacheMap);
return weighting->getTerminalLanguageCost(traverseSession, dicNode, languageImprobability);
}
- case CT_SPACE_SUBSTITUTION:
- return 0.0f;
+ case CT_NEW_WORD_SPACE_SUBSTITUTION:
+ return weighting->getNewWordBigramCost(traverseSession, parentDicNode, bigramCacheMap);
case CT_INSERTION:
return 0.0f;
case CT_TRANSPOSITION:
@@ -168,7 +168,7 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n
case CT_SUBSTITUTION:
// Should return true?
return false;
- case CT_NEW_WORD:
+ case CT_NEW_WORD_SPACE_OMITTION:
return false;
case CT_MATCH:
return false;
@@ -176,7 +176,7 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n
return false;
case CT_TERMINAL:
return false;
- case CT_SPACE_SUBSTITUTION:
+ case CT_NEW_WORD_SPACE_SUBSTITUTION:
return false;
case CT_INSERTION:
return true;
@@ -197,7 +197,7 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n
return false;
case CT_SUBSTITUTION:
return false;
- case CT_NEW_WORD:
+ case CT_NEW_WORD_SPACE_OMITTION:
return false;
case CT_MATCH:
return weighting->isProximityDicNode(traverseSession, dicNode);
@@ -205,7 +205,7 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n
return false;
case CT_TERMINAL:
return false;
- case CT_SPACE_SUBSTITUTION:
+ case CT_NEW_WORD_SPACE_SUBSTITUTION:
return false;
case CT_INSERTION:
return false;
@@ -224,7 +224,7 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n
return 0;
case CT_SUBSTITUTION:
return 0;
- case CT_NEW_WORD:
+ case CT_NEW_WORD_SPACE_OMITTION:
return 0;
case CT_MATCH:
return 1;
@@ -232,7 +232,7 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n
return 0;
case CT_TERMINAL:
return 0;
- case CT_SPACE_SUBSTITUTION:
+ case CT_NEW_WORD_SPACE_SUBSTITUTION:
return 1;
case CT_INSERTION:
return 2;
diff --git a/native/jni/src/suggest/core/policy/weighting.h b/native/jni/src/suggest/core/policy/weighting.h
index b92dbe278..bce479c51 100644
--- a/native/jni/src/suggest/core/policy/weighting.h
+++ b/native/jni/src/suggest/core/policy/weighting.h
@@ -56,7 +56,8 @@ class Weighting {
const DicTraverseSession *const traverseSession,
const DicNode *const parentDicNode, const DicNode *const dicNode) const = 0;
- virtual float getNewWordCost(const DicNode *const dicNode) const = 0;
+ virtual float getNewWordCost(const DicTraverseSession *const traverseSession,
+ const DicNode *const dicNode) const = 0;
virtual float getNewWordBigramCost(
const DicTraverseSession *const traverseSession, const DicNode *const dicNode,
@@ -76,7 +77,8 @@ class Weighting {
virtual float getSubstitutionCost() const = 0;
- virtual float getSpaceSubstitutionCost() const = 0;
+ virtual float getSpaceSubstitutionCost(const DicTraverseSession *const traverseSession,
+ const DicNode *const dicNode) const = 0;
Weighting() {}
virtual ~Weighting() {}
diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.cpp b/native/jni/src/suggest/core/session/dic_traverse_session.cpp
index 5b783a2ba..3c44db21c 100644
--- a/native/jni/src/suggest/core/session/dic_traverse_session.cpp
+++ b/native/jni/src/suggest/core/session/dic_traverse_session.cpp
@@ -16,6 +16,7 @@
#include "suggest/core/session/dic_traverse_session.h"
+#include "binary_format.h"
#include "defines.h"
#include "dictionary.h"
#include "dic_traverse_wrapper.h"
@@ -63,6 +64,7 @@ static TraverseSessionFactoryRegisterer traverseSessionFactoryRegisterer;
void DicTraverseSession::init(const Dictionary *const dictionary, const int *prevWord,
int prevWordLength) {
mDictionary = dictionary;
+ mMultiWordCostMultiplier = BinaryFormat::getMultiWordCostMultiplier(mDictionary->getDict());
if (!prevWord) {
mPrevWordPos = NOT_VALID_WORD;
return;
diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.h b/native/jni/src/suggest/core/session/dic_traverse_session.h
index fe0527639..d9c2a51d0 100644
--- a/native/jni/src/suggest/core/session/dic_traverse_session.h
+++ b/native/jni/src/suggest/core/session/dic_traverse_session.h
@@ -36,7 +36,8 @@ class DicTraverseSession {
AK_FORCE_INLINE DicTraverseSession(JNIEnv *env, jstring localeStr)
: mPrevWordPos(NOT_VALID_WORD), mProximityInfo(0),
mDictionary(0), mDicNodesCache(), mBigramCacheMap(),
- mInputSize(0), mPartiallyCommited(false), mMaxPointerCount(1) {
+ mInputSize(0), mPartiallyCommited(false), mMaxPointerCount(1),
+ mMultiWordCostMultiplier(1.0f) {
// NOTE: mProximityInfoStates is an array of instances.
// No need to initialize it explicitly here.
}
@@ -52,6 +53,7 @@ class DicTraverseSession {
const int maxPointerCount);
void resetCache(const int nextActiveCacheSize, const int maxWords);
+ // TODO: Remove
const uint8_t *getOffsetDict() const;
int getDictFlags() const;
@@ -150,6 +152,10 @@ class DicTraverseSession {
return mProximityInfoStates[0].touchPositionCorrectionEnabled();
}
+ float getMultiWordCostMultiplier() const {
+ return mMultiWordCostMultiplier;
+ }
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(DicTraverseSession);
// threshold to start caching
@@ -170,6 +176,11 @@ class DicTraverseSession {
int mInputSize;
bool mPartiallyCommited;
int mMaxPointerCount;
+
+ /////////////////////////////////
+ // Configuration per dictionary
+ float mMultiWordCostMultiplier;
+
};
} // namespace latinime
#endif // LATINIME_DIC_TRAVERSE_SESSION_H
diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp
index 67d351fa1..9de2cd2e2 100644
--- a/native/jni/src/suggest/core/suggest.cpp
+++ b/native/jni/src/suggest/core/suggest.cpp
@@ -33,16 +33,9 @@
namespace latinime {
// Initialization of class constants.
-const int Suggest::LOOKAHEAD_DIC_NODES_CACHE_SIZE = 25;
const int Suggest::MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT = 16;
const int Suggest::MIN_CONTINUOUS_SUGGESTION_INPUT_SIZE = 2;
const float Suggest::AUTOCORRECT_CLASSIFICATION_THRESHOLD = 0.33f;
-const float Suggest::AUTOCORRECT_LANGUAGE_FEATURE_THRESHOLD = 0.6f;
-
-const bool Suggest::CORRECT_SPACE_OMISSION = true;
-const bool Suggest::CORRECT_TRANSPOSITION = true;
-const bool Suggest::CORRECT_INSERTION = true;
-const bool Suggest::CORRECT_OMISSION_G = true;
/**
* Returns a set of suggestions for the given input touch points. The commitPoint argument indicates
@@ -270,12 +263,8 @@ void Suggest::expandCurrentDicNodes(DicTraverseSession *traverseSession) const {
// latest touch point yet. These are needed to apply look-ahead correction operations
// that require special handling of the latest touch point. For example, with insertions
// (e.g., "thiis" -> "this") the latest touch point should not be consumed at all.
- if (CORRECT_TRANSPOSITION) {
- processDicNodeAsTransposition(traverseSession, &dicNode);
- }
- if (CORRECT_INSERTION) {
- processDicNodeAsInsertion(traverseSession, &dicNode);
- }
+ processDicNodeAsTransposition(traverseSession, &dicNode);
+ processDicNodeAsInsertion(traverseSession, &dicNode);
} else { // !isLookAheadCorrection
// Only consider typing error corrections if the normalized compound distance is
// below a spatial distance threshold.
@@ -531,13 +520,10 @@ void Suggest::createNextWordDicNode(DicTraverseSession *traverseSession, DicNode
DicNode newDicNode;
DicNodeUtils::initAsRootWithPreviousWord(traverseSession->getDicRootPos(),
traverseSession->getOffsetDict(), dicNode, &newDicNode);
- Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_NEW_WORD, traverseSession, dicNode,
+ const CorrectionType correctionType = spaceSubstitution ?
+ CT_NEW_WORD_SPACE_SUBSTITUTION : CT_NEW_WORD_SPACE_OMITTION;
+ Weighting::addCostAndForwardInputIndex(WEIGHTING, correctionType, traverseSession, dicNode,
&newDicNode, traverseSession->getBigramCacheMap());
- if (spaceSubstitution) {
- // Merge this with CT_NEW_WORD
- Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_SPACE_SUBSTITUTION,
- traverseSession, 0, &newDicNode, 0 /* bigramCacheMap */);
- }
traverseSession->getDicTraverseCache()->copyPushNextActive(&newDicNode);
}
} // namespace latinime
diff --git a/native/jni/src/suggest/core/suggest.h b/native/jni/src/suggest/core/suggest.h
index becd6c1de..875cbe4e0 100644
--- a/native/jni/src/suggest/core/suggest.h
+++ b/native/jni/src/suggest/core/suggest.h
@@ -76,31 +76,16 @@ class Suggest : public SuggestInterface {
void processDicNodeAsMatch(DicTraverseSession *traverseSession,
DicNode *childDicNode) const;
- // Dic nodes cache size for lookahead (autocompletion)
- static const int LOOKAHEAD_DIC_NODES_CACHE_SIZE;
- // Max characters to lookahead
- static const int MAX_LOOKAHEAD;
// Inputs longer than this will autocorrect if the suggestion is multi-word
static const int MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT;
static const int MIN_CONTINUOUS_SUGGESTION_INPUT_SIZE;
- // Base value for converting costs into scores (low so will not autocorrect without classifier)
- static const float BASE_OUTPUT_SCORE;
// Threshold for autocorrection classifier
static const float AUTOCORRECT_CLASSIFICATION_THRESHOLD;
- // Threshold for computing the language model feature for autocorrect classification
- static const float AUTOCORRECT_LANGUAGE_FEATURE_THRESHOLD;
-
- // Typing error correction settings
- static const bool CORRECT_SPACE_OMISSION;
- static const bool CORRECT_TRANSPOSITION;
- static const bool CORRECT_INSERTION;
const Traversal *const TRAVERSAL;
const Scoring *const SCORING;
const Weighting *const WEIGHTING;
-
- static const bool CORRECT_OMISSION_G;
};
} // namespace latinime
#endif // LATINIME_SUGGEST_IMPL_H
diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp
index 0fa684f01..11ccf1773 100644
--- a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp
+++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp
@@ -35,17 +35,17 @@ const float ScoringParams::INSERTION_COST = 0.670f;
const float ScoringParams::INSERTION_COST_SAME_CHAR = 0.526f;
const float ScoringParams::INSERTION_COST_FIRST_CHAR = 0.563f;
const float ScoringParams::TRANSPOSITION_COST = 0.494f;
-const float ScoringParams::SPACE_SUBSTITUTION_COST = 0.239f;
+const float ScoringParams::SPACE_SUBSTITUTION_COST = 0.289f;
const float ScoringParams::ADDITIONAL_PROXIMITY_COST = 0.380f;
const float ScoringParams::SUBSTITUTION_COST = 0.363f;
-const float ScoringParams::COST_NEW_WORD = 0.054f;
+const float ScoringParams::COST_NEW_WORD = 0.024f;
const float ScoringParams::COST_NEW_WORD_CAPITALIZED = 0.174f;
const float ScoringParams::DISTANCE_WEIGHT_LANGUAGE = 1.123f;
const float ScoringParams::COST_FIRST_LOOKAHEAD = 0.462f;
const float ScoringParams::COST_LOOKAHEAD = 0.092f;
const float ScoringParams::HAS_PROXIMITY_TERMINAL_COST = 0.126f;
const float ScoringParams::HAS_EDIT_CORRECTION_TERMINAL_COST = 0.056f;
-const float ScoringParams::HAS_MULTI_WORD_TERMINAL_COST = 0.136f;
+const float ScoringParams::HAS_MULTI_WORD_TERMINAL_COST = 0.536f;
const float ScoringParams::TYPING_BASE_OUTPUT_SCORE = 1.0f;
const float ScoringParams::TYPING_MAX_OUTPUT_SCORE_PER_INPUT = 0.1f;
const float ScoringParams::MAX_NORM_DISTANCE_FOR_EDIT = 0.1f;
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_traversal.cpp b/native/jni/src/suggest/policyimpl/typing/typing_traversal.cpp
index 66f8ba9fa..e7e40e34d 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_traversal.cpp
+++ b/native/jni/src/suggest/policyimpl/typing/typing_traversal.cpp
@@ -18,7 +18,7 @@
namespace latinime {
const bool TypingTraversal::CORRECT_OMISSION = true;
-const bool TypingTraversal::CORRECT_SPACE_SUBSTITUTION = true;
-const bool TypingTraversal::CORRECT_SPACE_OMISSION = true;
+const bool TypingTraversal::CORRECT_NEW_WORD_SPACE_SUBSTITUTION = true;
+const bool TypingTraversal::CORRECT_NEW_WORD_SPACE_OMISSION = true;
const TypingTraversal TypingTraversal::sInstance;
} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_traversal.h b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h
index f22029a2c..9f8347452 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_traversal.h
+++ b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h
@@ -66,7 +66,7 @@ class TypingTraversal : public Traversal {
AK_FORCE_INLINE bool isSpaceSubstitutionTerminal(
const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const {
- if (!CORRECT_SPACE_SUBSTITUTION) {
+ if (!CORRECT_NEW_WORD_SPACE_SUBSTITUTION) {
return false;
}
if (!canDoLookAheadCorrection(traverseSession, dicNode)) {
@@ -80,7 +80,7 @@ class TypingTraversal : public Traversal {
AK_FORCE_INLINE bool isSpaceOmissionTerminal(
const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const {
- if (!CORRECT_SPACE_OMISSION) {
+ if (!CORRECT_NEW_WORD_SPACE_OMISSION) {
return false;
}
const int inputSize = traverseSession->getInputSize();
@@ -173,8 +173,8 @@ class TypingTraversal : public Traversal {
private:
DISALLOW_COPY_AND_ASSIGN(TypingTraversal);
static const bool CORRECT_OMISSION;
- static const bool CORRECT_SPACE_SUBSTITUTION;
- static const bool CORRECT_SPACE_OMISSION;
+ static const bool CORRECT_NEW_WORD_SPACE_SUBSTITUTION;
+ static const bool CORRECT_NEW_WORD_SPACE_OMISSION;
static const TypingTraversal sInstance;
TypingTraversal() {}
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
index 2dcee343f..34d25ae1a 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
+++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
@@ -128,17 +128,19 @@ class TypingWeighting : public Weighting {
return cost + weightedDistance;
}
- float getNewWordCost(const DicNode *const dicNode) const {
+ float getNewWordCost(const DicTraverseSession *const traverseSession,
+ const DicNode *const dicNode) const {
const bool isCapitalized = dicNode->isCapitalized();
- return isCapitalized ?
+ const float cost = isCapitalized ?
ScoringParams::COST_NEW_WORD_CAPITALIZED : ScoringParams::COST_NEW_WORD;
+ return cost * traverseSession->getMultiWordCostMultiplier();
}
float getNewWordBigramCost(
const DicTraverseSession *const traverseSession, const DicNode *const dicNode,
hash_map_compat<int, int16_t> *const bigramCacheMap) const {
return DicNodeUtils::getBigramNodeImprobability(traverseSession->getOffsetDict(),
- dicNode, bigramCacheMap);
+ dicNode, bigramCacheMap) * ScoringParams::DISTANCE_WEIGHT_LANGUAGE;
}
float getCompletionCost(const DicTraverseSession *const traverseSession,
@@ -162,13 +164,8 @@ class TypingWeighting : public Weighting {
// because the input word shouldn't be treated as perfect
const bool isExactMatch = !hasEditCount && !hasMultipleWords
&& !hasProximityErrors && isSameLength;
-
- const float totalPrevWordsLanguageCost = dicNode->getTotalPrevWordsLanguageCost();
const float languageImprobability = isExactMatch ? 0.0f : dicNodeLanguageImprobability;
- const float languageWeight = ScoringParams::DISTANCE_WEIGHT_LANGUAGE;
- // TODO: Caveat: The following equation should be:
- // totalPrevWordsLanguageCost + (languageImprobability * languageWeight);
- return (totalPrevWordsLanguageCost + languageImprobability) * languageWeight;
+ return languageImprobability * ScoringParams::DISTANCE_WEIGHT_LANGUAGE;
}
AK_FORCE_INLINE bool needsToNormalizeCompoundDistance() const {
@@ -183,8 +180,13 @@ class TypingWeighting : public Weighting {
return ScoringParams::SUBSTITUTION_COST;
}
- AK_FORCE_INLINE float getSpaceSubstitutionCost() const {
- return ScoringParams::SPACE_SUBSTITUTION_COST;
+ AK_FORCE_INLINE float getSpaceSubstitutionCost(
+ const DicTraverseSession *const traverseSession,
+ const DicNode *const dicNode) const {
+ const bool isCapitalized = dicNode->isCapitalized();
+ const float cost = ScoringParams::SPACE_SUBSTITUTION_COST + (isCapitalized ?
+ ScoringParams::COST_NEW_WORD_CAPITALIZED : ScoringParams::COST_NEW_WORD);
+ return cost * traverseSession->getMultiWordCostMultiplier();
}
private:
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
index eb484084e..74506d26a 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
@@ -19,6 +19,7 @@ package com.android.inputmethod.keyboard.internal;
import android.text.TextUtils;
import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.RecapitalizeStatus;
public class MockKeyboardSwitcher implements KeyboardState.SwitchActions {
public interface MockConstants {
@@ -120,7 +121,7 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions {
@Override
public void requestUpdatingShiftState() {
- mState.onUpdateShiftState(mAutoCapsState);
+ mState.onUpdateShiftState(mAutoCapsState, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE);
}
@Override
@@ -162,7 +163,7 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions {
}
public void updateShiftState() {
- mState.onUpdateShiftState(mAutoCapsState);
+ mState.onUpdateShiftState(mAutoCapsState, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE);
}
public void loadKeyboard() {
diff --git a/tests/src/com/android/inputmethod/latin/RecapitalizeStatusTests.java b/tests/src/com/android/inputmethod/latin/RecapitalizeStatusTests.java
index 4dfae4c94..9d7203e5a 100644
--- a/tests/src/com/android/inputmethod/latin/RecapitalizeStatusTests.java
+++ b/tests/src/com/android/inputmethod/latin/RecapitalizeStatusTests.java
@@ -24,29 +24,26 @@ import java.util.Locale;
@SmallTest
public class RecapitalizeStatusTests extends AndroidTestCase {
public void testTrim() {
- RecapitalizeStatus status = new RecapitalizeStatus(30, 40, "abcdefghij",
- Locale.ENGLISH, " ");
+ final RecapitalizeStatus status = new RecapitalizeStatus();
+ status.initialize(30, 40, "abcdefghij", Locale.ENGLISH, " ");
status.trim();
assertEquals("abcdefghij", status.getRecapitalizedString());
assertEquals(30, status.getNewCursorStart());
assertEquals(40, status.getNewCursorEnd());
- status = new RecapitalizeStatus(30, 44, " abcdefghij",
- Locale.ENGLISH, " ");
+ status.initialize(30, 44, " abcdefghij", Locale.ENGLISH, " ");
status.trim();
assertEquals("abcdefghij", status.getRecapitalizedString());
assertEquals(34, status.getNewCursorStart());
assertEquals(44, status.getNewCursorEnd());
- status = new RecapitalizeStatus(30, 40, "abcdefgh ",
- Locale.ENGLISH, " ");
+ status.initialize(30, 40, "abcdefgh ", Locale.ENGLISH, " ");
status.trim();
assertEquals("abcdefgh", status.getRecapitalizedString());
assertEquals(30, status.getNewCursorStart());
assertEquals(38, status.getNewCursorEnd());
- status = new RecapitalizeStatus(30, 45, " abcdefghij ",
- Locale.ENGLISH, " ");
+ status.initialize(30, 45, " abcdefghij ", Locale.ENGLISH, " ");
status.trim();
assertEquals("abcdefghij", status.getRecapitalizedString());
assertEquals(33, status.getNewCursorStart());
@@ -54,8 +51,8 @@ public class RecapitalizeStatusTests extends AndroidTestCase {
}
public void testRotate() {
- RecapitalizeStatus status = new RecapitalizeStatus(29, 40, "abcd efghij",
- Locale.ENGLISH, " ");
+ final RecapitalizeStatus status = new RecapitalizeStatus();
+ status.initialize(29, 40, "abcd efghij", Locale.ENGLISH, " ");
status.rotate();
assertEquals("Abcd Efghij", status.getRecapitalizedString());
assertEquals(29, status.getNewCursorStart());
@@ -67,8 +64,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase {
status.rotate();
assertEquals("Abcd Efghij", status.getRecapitalizedString());
- status = new RecapitalizeStatus(29, 40, "Abcd Efghij",
- Locale.ENGLISH, " ");
+ status.initialize(29, 40, "Abcd Efghij", Locale.ENGLISH, " ");
status.rotate();
assertEquals("ABCD EFGHIJ", status.getRecapitalizedString());
assertEquals(29, status.getNewCursorStart());
@@ -80,8 +76,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase {
status.rotate();
assertEquals("ABCD EFGHIJ", status.getRecapitalizedString());
- status = new RecapitalizeStatus(29, 40, "ABCD EFGHIJ",
- Locale.ENGLISH, " ");
+ status.initialize(29, 40, "ABCD EFGHIJ", Locale.ENGLISH, " ");
status.rotate();
assertEquals("abcd efghij", status.getRecapitalizedString());
assertEquals(29, status.getNewCursorStart());
@@ -93,8 +88,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase {
status.rotate();
assertEquals("abcd efghij", status.getRecapitalizedString());
- status = new RecapitalizeStatus(29, 39, "AbCDefghij",
- Locale.ENGLISH, " ");
+ status.initialize(29, 39, "AbCDefghij", Locale.ENGLISH, " ");
status.rotate();
assertEquals("abcdefghij", status.getRecapitalizedString());
assertEquals(29, status.getNewCursorStart());
@@ -108,8 +102,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase {
status.rotate();
assertEquals("abcdefghij", status.getRecapitalizedString());
- status = new RecapitalizeStatus(29, 40, "Abcd efghij",
- Locale.ENGLISH, " ");
+ status.initialize(29, 40, "Abcd efghij", Locale.ENGLISH, " ");
status.rotate();
assertEquals("abcd efghij", status.getRecapitalizedString());
assertEquals(29, status.getNewCursorStart());
@@ -123,8 +116,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase {
status.rotate();
assertEquals("abcd efghij", status.getRecapitalizedString());
- status = new RecapitalizeStatus(30, 34, "grüß", Locale.GERMAN, " ");
- status.rotate();
+ status.initialize(30, 34, "grüß", Locale.GERMAN, " "); status.rotate();
assertEquals("Grüß", status.getRecapitalizedString());
assertEquals(30, status.getNewCursorStart());
assertEquals(34, status.getNewCursorEnd());
@@ -141,9 +133,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase {
assertEquals(30, status.getNewCursorStart());
assertEquals(34, status.getNewCursorEnd());
-
- status = new RecapitalizeStatus(30, 33, "œuf", Locale.FRENCH, " ");
- status.rotate();
+ status.initialize(30, 33, "œuf", Locale.FRENCH, " "); status.rotate();
assertEquals("Œuf", status.getRecapitalizedString());
assertEquals(30, status.getNewCursorStart());
assertEquals(33, status.getNewCursorEnd());
@@ -160,8 +150,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase {
assertEquals(30, status.getNewCursorStart());
assertEquals(33, status.getNewCursorEnd());
- status = new RecapitalizeStatus(30, 33, "œUf", Locale.FRENCH, " ");
- status.rotate();
+ status.initialize(30, 33, "œUf", Locale.FRENCH, " "); status.rotate();
assertEquals("œuf", status.getRecapitalizedString());
assertEquals(30, status.getNewCursorStart());
assertEquals(33, status.getNewCursorEnd());
@@ -182,8 +171,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase {
assertEquals(30, status.getNewCursorStart());
assertEquals(33, status.getNewCursorEnd());
- status = new RecapitalizeStatus(30, 35, "école", Locale.FRENCH, " ");
- status.rotate();
+ status.initialize(30, 35, "école", Locale.FRENCH, " "); status.rotate();
assertEquals("École", status.getRecapitalizedString());
assertEquals(30, status.getNewCursorStart());
assertEquals(35, status.getNewCursorEnd());
diff --git a/tests/src/com/android/inputmethod/latin/RichInputConnectionTests.java b/tests/src/com/android/inputmethod/latin/RichInputConnectionTests.java
index dc8837dab..aacd60f4d 100644
--- a/tests/src/com/android/inputmethod/latin/RichInputConnectionTests.java
+++ b/tests/src/com/android/inputmethod/latin/RichInputConnectionTests.java
@@ -85,6 +85,11 @@ public class RichInputConnectionTests extends AndroidTestCase {
public boolean endBatchEdit() {
return true;
}
+
+ @Override
+ public boolean finishComposingText() {
+ return true;
+ }
}
private class MockInputMethodService extends InputMethodService {
diff --git a/tests/src/com/android/inputmethod/latin/StringUtilsTests.java b/tests/src/com/android/inputmethod/latin/StringUtilsTests.java
index 98a50b730..1e3cc8ad4 100644
--- a/tests/src/com/android/inputmethod/latin/StringUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/StringUtilsTests.java
@@ -215,4 +215,26 @@ public class StringUtilsTests extends AndroidTestCase {
checkCapitalize("Lorem!Ipsum (dolor) Sit * Amet", "Lorem!Ipsum (Dolor) Sit * Amet",
" \n,.;!?*()&", Locale.ENGLISH);
}
+
+ public void testLooksLikeURL() {
+ assertTrue(StringUtils.lastPartLooksLikeURL("http://www.google."));
+ assertFalse(StringUtils.lastPartLooksLikeURL("word wo"));
+ assertTrue(StringUtils.lastPartLooksLikeURL("/etc/foo"));
+ assertFalse(StringUtils.lastPartLooksLikeURL("left/right"));
+ assertTrue(StringUtils.lastPartLooksLikeURL("www.goo"));
+ assertTrue(StringUtils.lastPartLooksLikeURL("www."));
+ assertFalse(StringUtils.lastPartLooksLikeURL("U.S.A"));
+ assertFalse(StringUtils.lastPartLooksLikeURL("U.S.A."));
+ assertTrue(StringUtils.lastPartLooksLikeURL("rtsp://foo."));
+ assertTrue(StringUtils.lastPartLooksLikeURL("://"));
+ assertFalse(StringUtils.lastPartLooksLikeURL("abc/"));
+ assertTrue(StringUtils.lastPartLooksLikeURL("abc.def/ghi"));
+ assertFalse(StringUtils.lastPartLooksLikeURL("abc.def"));
+ // TODO: ideally this would not look like a URL, but to keep down the complexity of the
+ // code for now True is acceptable.
+ assertTrue(StringUtils.lastPartLooksLikeURL("abc./def"));
+ // TODO: ideally this would not look like a URL, but to keep down the complexity of the
+ // code for now True is acceptable.
+ assertTrue(StringUtils.lastPartLooksLikeURL(".abc/def"));
+ }
}