Merge remote branch 'goog/master' into merge

Conflicts:
	java/src/com/android/inputmethod/latin/BinaryDictionary.java
	java/src/com/android/inputmethod/latin/SubtypeSwitcher.java

Change-Id: Ib2b4acc9dd570d5f37b6aa455e2f07b0a884944a
This commit is contained in:
satok 2011-01-14 13:45:21 +09:00
commit e5585c1854
101 changed files with 756 additions and 1545 deletions

View file

@ -13,7 +13,11 @@ LOCAL_JNI_SHARED_LIBRARIES := libjni_latinime
LOCAL_STATIC_JAVA_LIBRARIES := android-common LOCAL_STATIC_JAVA_LIBRARIES := android-common
#LOCAL_AAPT_FLAGS := -0 .dict # Do not compress dictionary files to mmap dict data runtime
LOCAL_AAPT_FLAGS := -0 .dict
# Include all the resources regardless of system supported locales
LOCAL_AAPT_INCLUDE_ALL_RESOURCES := true
LOCAL_SDK_VERSION := current LOCAL_SDK_VERSION := current

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -32,7 +32,7 @@
latin:keyBackground="@drawable/btn_keyboard_key_honeycomb" latin:keyBackground="@drawable/btn_keyboard_key_honeycomb"
latin:keyPreviewLayout="@layout/key_preview_honeycomb" latin:keyPreviewLayout="@layout/key_preview_honeycomb"
latin:popupLayout="@layout/keyboard_popup_honeycomb" latin:popupLayout="@layout/keyboard_popup_honeycomb"
latin:keyTextColorDisabled="#FF353535" latin:keyTextColorDisabled="#FF63666D"
latin:keyLetterStyle="bold" latin:keyLetterStyle="bold"
latin:shadowColor="#00000000" latin:shadowColor="#00000000"
latin:shadowRadius="0.0" latin:shadowRadius="0.0"

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- XL -->
<string name="sound_on_keypress" msgid="5115009797011251176">"Sonar al pulsar teclas"</string>
<!-- XL -->
<string name="auto_cap" msgid="6033382411344449470">"Uso de mayúsculas automático"</string>
<!-- XL -->
<string name="auto_correction" msgid="7961335093790493671">"Corrección automática"</string>
<!-- XL -->
<string name="auto_correction_summary" msgid="6260001790426244084">"La barra espaciadora o la puntuación insertan automáticamente la palabra resaltada."</string>
<!-- XL -->
<string name="bigram_suggestion" msgid="7146707435859263625">"Sugerencias de bigramas"</string>
<!-- XL -->
<string name="label_done_key" msgid="5392116476778838314">"Listo"</string>
<!-- XL -->
<string name="voice_warning_title" msgid="7559175513146431282">"Entrada de voz"</string>
<!-- XL -->
<string name="voice_warning_may_not_understand" msgid="5450473727606344027">"La entrada de voz utiliza el reconocimiento de voz de Google. "<a href="http://m.google.com/privacy">"Aplica la Política de privacidad de Google para celulares"</a>"."</string>
<!-- XL -->
<string name="voice_warning_how_to_turn_off" msgid="8461922898209345270">"Para desactivar la entrada por voz, ve a la configuración de métodos de entrada."</string>
<!-- XL -->
<string name="voice_hint_dialog_message" msgid="6099357096490592798">"Para utilizar entrada de voz, presiona el botón micrófono."</string>
<!-- XL -->
<string name="voice_input" msgid="6634874497844843576">"Entrada de voz"</string>
<!-- XL -->
<string name="prefs_enable_recorrection_summary" msgid="3119549956172710725">"Toca las palabras ingresadas que desees corregir, solo cuando las sugerencias estén visibles."</string>
<!-- XL -->
<string name="prefs_show_suggestions" msgid="1375526087676269770">"Mostrar sugerencias"</string>
<!-- XL -->
<string name="prefs_show_suggestions_summary" msgid="2564386479780335351">"Mostrar palabras sugeridas al escribir"</string>
<!-- XL -->
<string name="prefs_suggestion_visibility_show_name" msgid="8350173747634837929">"Mostrar siempre"</string>
<!-- XL -->
<string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="670278993111469619">"Mostrar en modo retrato"</string>
<!-- XL -->
<string name="prefs_suggestion_visibility_hide_name" msgid="2750493093338023345">"Ocultar siempre"</string>
<!-- XL -->
<string name="auto_correction_threshold_mode_off" msgid="4899978031827517261">"Apagado"</string>
<!-- XL -->
<string name="auto_correction_threshold_mode_modest" msgid="3316394123368070951">"Moderado"</string>
<!-- XL -->
<string name="auto_correction_threshold_mode_aggeressive" msgid="6091003457668724585">"Intenso"</string>
<!-- XL -->
<string name="label_to_alpha_key" msgid="3103719164112604010">"ABC"</string>
<!-- XL -->
<string name="voice_input_modes_main_keyboard" msgid="1403596961453846365">"En el teclado principal"</string>
<!-- XL -->
<string name="voice_input_modes_symbols_keyboard" msgid="5916050323076830126">"En el teclado de símbolos"</string>
<!-- XL -->
<string name="voice_input_modes_off" msgid="1577817314089496020">"Apagado"</string>
<!-- XL -->
<string name="voice_input_modes_summary_main_keyboard" msgid="5118121899312172508">"Micrófono en el teclado principal"</string>
<!-- XL -->
<string name="voice_input_modes_summary_symbols_keyboard" msgid="8181616553734217736">"Micrófono en el teclado de símbolos"</string>
<!-- XL -->
<string name="voice_input_modes_summary_off" msgid="3854831353403775554">"La entrada por voz está inhabilitada."</string>
<!-- XL -->
<string name="subtype_mode_cs_keyboard" msgid="1186679497674833204">"Teclado en checo"</string>
<!-- XL -->
<string name="subtype_mode_da_keyboard" msgid="1395637124037817510">"Teclado en danés"</string>
<!-- XL -->
<string name="subtype_mode_de_keyboard" msgid="1145552122692431122">"Teclado en alemán"</string>
<!-- XL -->
<string name="subtype_mode_en_GB_keyboard" msgid="5050923189634470413">"Teclado en inglés (Reino Unido)"</string>
<!-- XL -->
<string name="subtype_mode_en_US_keyboard" msgid="3435344903704397043">"Teclado en inglés (EE.UU.)"</string>
<!-- XL -->
<string name="subtype_mode_es_keyboard" msgid="1030419781157491328">"Teclado en español"</string>
<!-- XL -->
<string name="subtype_mode_es_US_keyboard" msgid="5792199241357098918">"Teclado en español (EE.UU.)"</string>
<!-- XL -->
<string name="subtype_mode_fr_keyboard" msgid="4855416218650524164">"Teclado en francés"</string>
<!-- XL -->
<string name="subtype_mode_fr_CA_keyboard" msgid="6458285776720480201">"Teclado en francés (Canadá)"</string>
<!-- XL -->
<string name="subtype_mode_fr_CH_keyboard" msgid="5966960427086795964">"Teclado en francés (Suiza)"</string>
<!-- XL -->
<string name="subtype_mode_it_keyboard" msgid="6927754583816493555">"Teclado en italiano"</string>
<!-- XL -->
<string name="subtype_mode_nb_keyboard" msgid="771634025467668613">"Teclado en noruego"</string>
<!-- XL -->
<string name="subtype_mode_nl_keyboard" msgid="3397048533451717478">"Teclado en holandés"</string>
<!-- XL -->
<string name="subtype_mode_ru_keyboard" msgid="3812694929448916712">"Teclado en ruso"</string>
<!-- XL -->
<string name="subtype_mode_sr_keyboard" msgid="7947963963114184275">"Teclado en serbio"</string>
<!-- XL -->
<string name="subtype_mode_sv_keyboard" msgid="3874083866564515371">"Teclado en sueco"</string>
<!-- XL -->
<string name="subtype_mode_cs_voice" msgid="8290007904951946296">"Voz en checo"</string>
<!-- XL -->
<string name="subtype_mode_de_voice" msgid="672328729666823853">"Voz en alemán"</string>
<!-- XL -->
<string name="subtype_mode_en_AU_voice" msgid="4170989257043892770">"Voz en inglés (Australia)"</string>
<!-- XL -->
<string name="subtype_mode_en_GB_voice" msgid="3134961988951205695">"Voz en inglés (Reino Unido)"</string>
<!-- XL -->
<string name="subtype_mode_en_IN_voice" msgid="5699787782487633128">"Voz en inglés (India)"</string>
<!-- XL -->
<string name="subtype_mode_en_NZ_voice" msgid="4121688717194804130">"Voz en inglés (Nueva Zelanda)"</string>
<!-- XL -->
<string name="subtype_mode_en_US_voice" msgid="8006563098744135975">"Voz en inglés (EE.UU.)"</string>
<!-- XL -->
<string name="subtype_mode_es_voice" msgid="1243071504878834350">"Voz en español"</string>
<!-- XL -->
<string name="subtype_mode_fr_voice" msgid="2048805677248981105">"Voz en francés"</string>
<!-- XL -->
<string name="subtype_mode_ja_voice" msgid="1855513591711108481">"Voz en japonés"</string>
<!-- XL -->
<string name="subtype_mode_ko_voice" msgid="3453153041889151316">"Voz en coreano"</string>
<!-- XL -->
<string name="subtype_mode_pl_voice" msgid="6730658974157645735">"Voz en polaco"</string>
<!-- XL -->
<string name="subtype_mode_pt_voice" msgid="4508062762756741654">"Voz en portugués"</string>
<!-- XL -->
<string name="subtype_mode_ru_voice" msgid="554299262138845594">"Voz en ruso"</string>
<!-- XL -->
<string name="subtype_mode_tr_voice" msgid="5242644971865917801">"Voz en turco"</string>
<!-- XL -->
<string name="subtype_mode_zh_CN_voice" msgid="4505329319557358473">"Voz en chino (China, simplificado)"</string>
<!-- XL -->
<string name="subtype_mode_zh_TW_voice" msgid="3976996097508134329">"Voz en chino (Taiwán, tradicional)"</string>
<!-- XL -->
<string name="prefs_usability_study_mode" msgid="8423000345880575687">"Modo estudio de usabilidad"</string>
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -25,8 +25,11 @@
<bool name="config_candidate_highlight_font_color_enabled">false</bool> <bool name="config_candidate_highlight_font_color_enabled">false</bool>
<bool name="config_swipe_down_dismiss_keyboard_enabled">false</bool> <bool name="config_swipe_down_dismiss_keyboard_enabled">false</bool>
<bool name="config_sliding_key_input_enabled">false</bool> <bool name="config_sliding_key_input_enabled">false</bool>
<bool name="config_digit_popup_characters_enabled">false</bool>
<!-- Whether or not Popup on key press is enabled by default --> <!-- Whether or not Popup on key press is enabled by default -->
<bool name="config_default_popup_preview">false</bool> <bool name="config_default_popup_preview">false</bool>
<string name="config_text_size_of_language_on_spacebar">medium</string> <!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. -->
<string name="config_default_keyboard_theme_id" translatable="false">5</string>
<string name="config_text_size_of_language_on_spacebar" translatable="false">medium</string>
<integer name="config_max_popup_keyboard_column">9</integer> <integer name="config_max_popup_keyboard_column">9</integer>
</resources> </resources>

View file

@ -30,6 +30,7 @@
<dimen name="keyboard_bottom_padding">0.0mm</dimen> <dimen name="keyboard_bottom_padding">0.0mm</dimen>
<!-- key_height x 1.0 --> <!-- key_height x 1.0 -->
<dimen name="key_preview_height">13.0mm</dimen> <dimen name="key_preview_height">13.0mm</dimen>
<dimen name="mini_keyboard_key_horizontal_padding">12dip</dimen>
<!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. --> <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. -->
<!-- popup_key_height x 1.2 --> <!-- popup_key_height x 1.2 -->
<dimen name="mini_keyboard_slide_allowance">15.6mm</dimen> <dimen name="mini_keyboard_slide_allowance">15.6mm</dimen>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for config_text_size_of_language_on_spacebar (2561849581542626045) -->
<skip />
<!-- no translation found for auto_correction_threshold_values:1 (162196081188429793) -->
<!-- no translation found for auto_correction_threshold_values:2 (861483375701275215) -->
</resources>

View file

@ -28,6 +28,7 @@
<bool name="config_candidate_highlight_font_color_enabled">true</bool> <bool name="config_candidate_highlight_font_color_enabled">true</bool>
<bool name="config_swipe_down_dismiss_keyboard_enabled">true</bool> <bool name="config_swipe_down_dismiss_keyboard_enabled">true</bool>
<bool name="config_sliding_key_input_enabled">true</bool> <bool name="config_sliding_key_input_enabled">true</bool>
<bool name="config_digit_popup_characters_enabled">true</bool>
<!-- Whether or not Popup on key press is enabled by default --> <!-- Whether or not Popup on key press is enabled by default -->
<bool name="config_default_popup_preview">true</bool> <bool name="config_default_popup_preview">true</bool>
<integer name="config_delay_before_preview">0</integer> <integer name="config_delay_before_preview">0</integer>
@ -44,11 +45,13 @@
<integer name="config_long_press_shift_key_timeout">1200</integer> <integer name="config_long_press_shift_key_timeout">1200</integer>
<integer name="config_touch_noise_threshold_millis">40</integer> <integer name="config_touch_noise_threshold_millis">40</integer>
<dimen name="config_touch_noise_threshold_distance">2.0mm</dimen> <dimen name="config_touch_noise_threshold_distance">2.0mm</dimen>
<string name="config_text_size_of_language_on_spacebar">small</string> <!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. -->
<string name="config_default_keyboard_theme_id" translatable="false">4</string>
<string name="config_text_size_of_language_on_spacebar" translatable="false">small</string>
<integer name="config_max_popup_keyboard_column">9</integer> <integer name="config_max_popup_keyboard_column">9</integer>
<!-- Whether or not auto-correction should be enabled by default --> <!-- Whether or not auto-correction should be enabled by default -->
<bool name="enable_autocorrect">true</bool> <bool name="enable_autocorrect">true</bool>
<string-array name="auto_correction_threshold_values"> <string-array name="auto_correction_threshold_values" translatable="false">
<!-- Off, When auto correction setting is Off, this value is not used. --> <!-- Off, When auto correction setting is Off, this value is not used. -->
<item></item> <item></item>
<!-- Modest : Suggestion whose normalized score is greater than this value <!-- Modest : Suggestion whose normalized score is greater than this value

View file

@ -30,6 +30,7 @@
<dimen name="keyboard_bottom_padding">0.06in</dimen> <dimen name="keyboard_bottom_padding">0.06in</dimen>
<!-- key_preview_text_size_large x 2 --> <!-- key_preview_text_size_large x 2 -->
<dimen name="key_preview_height">80sp</dimen> <dimen name="key_preview_height">80sp</dimen>
<dimen name="mini_keyboard_key_horizontal_padding">8dip</dimen>
<!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. --> <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. -->
<!-- popup_key_height x 1.2 --> <!-- popup_key_height x 1.2 -->
<dimen name="mini_keyboard_slide_allowance">0.390in</dimen> <dimen name="mini_keyboard_slide_allowance">0.390in</dimen>

View file

@ -212,39 +212,72 @@
<!-- Description for keyboard theme switcher --> <!-- Description for keyboard theme switcher -->
<string name="keyboard_layout">Keyboard Theme</string> <string name="keyboard_layout">Keyboard Theme</string>
<!-- Description for Czech keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_cs_keyboard">Czech Keyboard</string> <string name="subtype_mode_cs_keyboard">Czech Keyboard</string>
<!-- Description for Danish keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_da_keyboard">Danish Keyboard</string> <string name="subtype_mode_da_keyboard">Danish Keyboard</string>
<!-- Description for German keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_de_keyboard">German Keyboard</string> <string name="subtype_mode_de_keyboard">German Keyboard</string>
<!-- Description for English (United Kingdom) keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_en_GB_keyboard">English (UK) Keyboard</string> <string name="subtype_mode_en_GB_keyboard">English (UK) Keyboard</string>
<!-- Description for English (United States) keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_en_US_keyboard">English (US) Keyboard</string> <string name="subtype_mode_en_US_keyboard">English (US) Keyboard</string>
<!-- Description for Spanish keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_es_keyboard">Spanish Keyboard</string> <string name="subtype_mode_es_keyboard">Spanish Keyboard</string>
<!-- Description for Spanish (United States) keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_es_US_keyboard">Spanish (US) Keyboard</string> <string name="subtype_mode_es_US_keyboard">Spanish (US) Keyboard</string>
<!-- Description for French keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_fr_keyboard">French Keyboard</string> <string name="subtype_mode_fr_keyboard">French Keyboard</string>
<!-- Description for French (Canada) keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_fr_CA_keyboard">French (Canada) Keyboard</string> <string name="subtype_mode_fr_CA_keyboard">French (Canada) Keyboard</string>
<!-- Description for French (Switzerland) keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_fr_CH_keyboard">French (Switzerland) Keyboard</string> <string name="subtype_mode_fr_CH_keyboard">French (Switzerland) Keyboard</string>
<!-- Description for Italian keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_it_keyboard">Italian Keyboard</string> <string name="subtype_mode_it_keyboard">Italian Keyboard</string>
<!-- Description for Norwegian keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_nb_keyboard">Norwegian Keyboard</string> <string name="subtype_mode_nb_keyboard">Norwegian Keyboard</string>
<!-- Description for Dutch keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_nl_keyboard">Dutch Keyboard</string> <string name="subtype_mode_nl_keyboard">Dutch Keyboard</string>
<!-- Description for Russian keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_ru_keyboard">Russian Keyboard</string> <string name="subtype_mode_ru_keyboard">Russian Keyboard</string>
<!-- Description for Serbian keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_sr_keyboard">Serbian Keyboard</string> <string name="subtype_mode_sr_keyboard">Serbian Keyboard</string>
<!-- Description for Swedish keyboard subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_sv_keyboard">Swedish Keyboard</string> <string name="subtype_mode_sv_keyboard">Swedish Keyboard</string>
<!-- Description for Czech voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_cs_voice">Czech Voice</string> <string name="subtype_mode_cs_voice">Czech Voice</string>
<!-- Description for German voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_de_voice">German Voice</string> <string name="subtype_mode_de_voice">German Voice</string>
<!-- Description for English (Australia) voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_en_AU_voice">English (Australia) Voice</string> <string name="subtype_mode_en_AU_voice">English (Australia) Voice</string>
<!-- Description for English (United Kingdom) voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_en_GB_voice">English (UK) Voice</string> <string name="subtype_mode_en_GB_voice">English (UK) Voice</string>
<!-- Description for English (India) voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_en_IN_voice">English (India) Voice</string> <string name="subtype_mode_en_IN_voice">English (India) Voice</string>
<!-- Description for English (New Zealand) voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_en_NZ_voice">English (New Zealand) Voice</string> <string name="subtype_mode_en_NZ_voice">English (New Zealand) Voice</string>
<!-- Description for English (United States) voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_en_US_voice">English (US) Voice</string> <string name="subtype_mode_en_US_voice">English (US) Voice</string>
<!-- Description for Spanish voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_es_voice">Spanish Voice</string> <string name="subtype_mode_es_voice">Spanish Voice</string>
<!-- Description for French voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_fr_voice">French Voice</string> <string name="subtype_mode_fr_voice">French Voice</string>
<!-- Description for Japanese voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_ja_voice">Japanese Voice</string> <string name="subtype_mode_ja_voice">Japanese Voice</string>
<!-- Description for Korean voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_ko_voice">Korean Voice</string> <string name="subtype_mode_ko_voice">Korean Voice</string>
<!-- Description for Polish voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_pl_voice">Polish Voice</string> <string name="subtype_mode_pl_voice">Polish Voice</string>
<!-- Description for Portuguese voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_pt_voice">Portuguese Voice</string> <string name="subtype_mode_pt_voice">Portuguese Voice</string>
<!-- Description for Russian voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_ru_voice">Russian Voice</string> <string name="subtype_mode_ru_voice">Russian Voice</string>
<!-- Description for Turkish voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_tr_voice">Turkish Voice</string> <string name="subtype_mode_tr_voice">Turkish Voice</string>
<!-- Description for Chinese (China, Simplified) voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_zh_CN_voice">Chinese (China, Simplified) Voice</string> <string name="subtype_mode_zh_CN_voice">Chinese (China, Simplified) Voice</string>
<!-- Description for Chinese (Taiwan, Traditional) voice input subtype [CHAR LIMIT=35] -->
<string name="subtype_mode_zh_TW_voice">Chinese (Taiwan, Traditional) Voice</string> <string name="subtype_mode_zh_TW_voice">Chinese (Taiwan, Traditional) Voice</string>
<!-- Title of an option for usability study mode --> <!-- Title of an option for usability study mode -->

View file

@ -53,7 +53,6 @@
<key-style <key-style
latin:styleName="spaceKeyStyle" latin:styleName="spaceKeyStyle"
latin:code="@integer/key_space" latin:code="@integer/key_space"
latin:keyIcon="@drawable/sym_keyboard_space_holo"
latin:iconPreview="@drawable/sym_keyboard_feedback_space" /> latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
<key-style <key-style
latin:styleName="nonSpecialBackgroundSpaceKeyStyle" latin:styleName="nonSpecialBackgroundSpaceKeyStyle"

View file

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 2010, 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.
*/
-->
<dictionary>
<part name = "main" />
</dictionary>

View file

@ -32,7 +32,7 @@
android:persistent="true" android:persistent="true"
android:entryValues="@array/keyboard_layout_modes_values" android:entryValues="@array/keyboard_layout_modes_values"
android:entries="@array/keyboard_layout_modes" android:entries="@array/keyboard_layout_modes"
android:defaultValue="5" android:defaultValue="@string/config_default_keyboard_theme_id"
/> />
<CheckBoxPreference <CheckBoxPreference

View file

@ -27,6 +27,8 @@ import android.graphics.drawable.Drawable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Xml; import android.util.Xml;
import java.util.ArrayList;
/** /**
* Class for describing the position and characteristics of a single key in the keyboard. * Class for describing the position and characteristics of a single key in the keyboard.
*/ */
@ -133,15 +135,15 @@ public class Key {
}; };
/** /**
* Create an empty key with no attributes.
* This constructor is being used only for key in mini popup keyboard. * This constructor is being used only for key in mini popup keyboard.
*/ */
public Key(Resources res, Row row, CharSequence popupCharacter, int x, int y) { public Key(Resources res, Keyboard keyboard, CharSequence popupCharacter, int x, int y,
mKeyboard = row.getKeyboard(); int width, int edgeFlags) {
mHeight = row.mDefaultHeight - row.mVerticalGap; mKeyboard = keyboard;
mGap = row.mDefaultHorizontalGap; mHeight = keyboard.getRowHeight() - keyboard.getVerticalGap();
mWidth = row.mDefaultWidth - mGap; mGap = keyboard.getHorizontalGap();
mEdgeFlags = row.mRowEdgeFlags; mWidth = width - mGap;
mEdgeFlags = edgeFlags;
mHintIcon = null; mHintIcon = null;
mManualTemporaryUpperCaseHintIcon = null; mManualTemporaryUpperCaseHintIcon = null;
mManualTemporaryUpperCaseCode = Keyboard.CODE_DUMMY; mManualTemporaryUpperCaseCode = Keyboard.CODE_DUMMY;
@ -208,8 +210,13 @@ public class Key {
style = keyStyles.getEmptyKeyStyle(); style = keyStyles.getEmptyKeyStyle();
} }
mPopupCharacters = style.getTextArray(keyAttr, final CharSequence[] popupCharacters = style.getTextArray(keyAttr,
R.styleable.Keyboard_Key_popupCharacters); R.styleable.Keyboard_Key_popupCharacters);
if (res.getBoolean(R.bool.config_digit_popup_characters_enabled)) {
mPopupCharacters = popupCharacters;
} else {
mPopupCharacters = filterOutDigitPopupCharacters(popupCharacters);
}
mMaxPopupColumn = style.getInt(keyboardAttr, mMaxPopupColumn = style.getInt(keyboardAttr,
R.styleable.Keyboard_Key_maxPopupKeyboardColumn, R.styleable.Keyboard_Key_maxPopupKeyboardColumn,
mKeyboard.getMaxPopupKeyboardColumn()); mKeyboard.getMaxPopupKeyboardColumn());
@ -256,6 +263,36 @@ public class Key {
} }
} }
private static boolean isDigitPopupCharacter(CharSequence label) {
return label.length() == 1 && Character.isDigit(label.charAt(0));
}
private static CharSequence[] filterOutDigitPopupCharacters(CharSequence[] popupCharacters) {
if (popupCharacters == null || popupCharacters.length < 1)
return null;
if (popupCharacters.length == 1 && isDigitPopupCharacter(
PopupCharactersParser.getLabel(popupCharacters[0].toString())))
return null;
ArrayList<CharSequence> filtered = null;
for (int i = 0; i < popupCharacters.length; i++) {
final CharSequence popupSpec = popupCharacters[i];
if (isDigitPopupCharacter(PopupCharactersParser.getLabel(popupSpec.toString()))) {
if (filtered == null) {
filtered = new ArrayList<CharSequence>();
for (int j = 0; j < i; j++)
filtered.add(popupCharacters[j]);
}
} else if (filtered != null) {
filtered.add(popupSpec);
}
}
if (filtered == null)
return popupCharacters;
if (filtered.size() == 0)
return null;
return filtered.toArray(new CharSequence[filtered.size()]);
}
public Drawable getIcon() { public Drawable getIcon() {
return mIcon; return mIcon;
} }

View file

@ -79,8 +79,7 @@ public abstract class KeyDetector {
* *
* @return Allocates and returns an array that can hold all key indices returned by * @return Allocates and returns an array that can hold all key indices returned by
* {@link #getKeyIndexAndNearbyCodes} method. All elements in the returned array are * {@link #getKeyIndexAndNearbyCodes} method. All elements in the returned array are
* initialized by {@link com.android.inputmethod.latin.LatinKeyboardView.NOT_A_KEY} * initialized by {@link #NOT_A_KEY} value.
* value.
*/ */
public int[] newCodeArray() { public int[] newCodeArray() {
int[] codes = new int[getMaxNearbyKeys()]; int[] codes = new int[getMaxNearbyKeys()];

View file

@ -19,64 +19,56 @@ package com.android.inputmethod.keyboard;
public interface KeyboardActionListener { public interface KeyboardActionListener {
/** /**
* Called when the user presses a key. This is sent before the * Called when the user presses a key. This is sent before the {@link #onCodeInput} is called.
* {@link #onKey} is called. For keys that repeat, this is only * For keys that repeat, this is only called once.
* called once.
* *
* @param primaryCode * @param primaryCode the unicode of the key being pressed. If the touch is not on a valid key,
* the unicode of the key being pressed. If the touch is * the value will be zero.
* not on a valid key, the value will be zero.
*/ */
void onPress(int primaryCode); public void onPress(int primaryCode);
/** /**
* Called when the user releases a key. This is sent after the * Called when the user releases a key. This is sent after the {@link #onCodeInput} is called.
* {@link #onKey} is called. For keys that repeat, this is only * For keys that repeat, this is only called once.
* called once.
* *
* @param primaryCode * @param primaryCode the code of the key that was released
* the code of the key that was released
*/ */
void onRelease(int primaryCode); public void onRelease(int primaryCode);
/** /**
* Send a key code to the listener. * Send a key code to the listener.
* *
* @param primaryCode * @param primaryCode this is the code of the key that was pressed
* this is the code of the key that was pressed * @param keyCodes the codes for all the possible alternative keys with the primary code being
* @param keyCodes * the first. If the primary key code is a single character such as an alphabet or
* the codes for all the possible alternative keys with * number or symbol, the alternatives will include other characters that may be on
* the primary code being the first. If the primary key * the same key or adjacent keys. These codes are useful to correct for accidental
* code is a single character such as an alphabet or * presses of a key adjacent to the intended key.
* number or symbol, the alternatives will include other * @param x x-coordinate pixel of touched event. If {@link #onCodeInput} is not called by
* characters that may be on the same key or adjacent * {@link PointerTracker#onTouchEvent} or so, the value should be
* keys. These codes are useful to correct for * {@link #NOT_A_TOUCH_COORDINATE}.
* accidental presses of a key adjacent to the intended * @param y y-coordinate pixel of touched event. If {@link #onCodeInput} is not called by
* key. * {@link PointerTracker#onTouchEvent} or so, the value should be
* @param x * {@link #NOT_A_TOUCH_COORDINATE}.
* x-coordinate pixel of touched event. If onKey is not called by onTouchEvent,
* the value should be NOT_A_TOUCH_COORDINATE.
* @param y
* y-coordinate pixel of touched event. If onKey is not called by onTouchEvent,
* the value should be NOT_A_TOUCH_COORDINATE.
*/ */
void onCodeInput(int primaryCode, int[] keyCodes, int x, int y); public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y);
public static final int NOT_A_TOUCH_COORDINATE = -1;
/** /**
* Sends a sequence of characters to the listener. * Sends a sequence of characters to the listener.
* *
* @param text * @param text the sequence of characters to be displayed.
* the sequence of characters to be displayed.
*/ */
void onTextInput(CharSequence text); public void onTextInput(CharSequence text);
/** /**
* Called when user released a finger outside any key. * Called when user released a finger outside any key.
*/ */
void onCancelInput(); public void onCancelInput();
/** /**
* Called when the user quickly moves the finger from up to down. * Called when the user quickly moves the finger from up to down.
*/ */
void onSwipeDown(); public void onSwipeDown();
} }

View file

@ -39,16 +39,15 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
public static final boolean DEBUG_STATE = false; public static final boolean DEBUG_STATE = false;
// Changing DEFAULT_LAYOUT_ID also requires prefs_for_debug.xml to be matched with. private static String sConfigDefaultKeyboardThemeId;
public static final String DEFAULT_LAYOUT_ID = "5";
public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902"; public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902";
private static final int[] THEMES = new int [] { private static final int[] KEYBOARD_THEMES = {
R.layout.input_basic, R.layout.input_basic,
R.layout.input_basic_highcontrast, R.layout.input_basic_highcontrast,
R.layout.input_stone_normal, R.layout.input_stone_normal,
R.layout.input_stone_bold, R.layout.input_stone_bold,
R.layout.input_gingerbread, R.layout.input_gingerbread,
R.layout.input_honeycomb, // DEFAULT_LAYOUT_ID R.layout.input_honeycomb,
}; };
private SubtypeSwitcher mSubtypeSwitcher; private SubtypeSwitcher mSubtypeSwitcher;
@ -111,8 +110,15 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
sInstance.mPrefs = prefs; sInstance.mPrefs = prefs;
sInstance.mSubtypeSwitcher = SubtypeSwitcher.getInstance(); sInstance.mSubtypeSwitcher = SubtypeSwitcher.getInstance();
sInstance.mLayoutId = Integer.valueOf( try {
prefs.getString(PREF_KEYBOARD_LAYOUT, DEFAULT_LAYOUT_ID)); sConfigDefaultKeyboardThemeId = ims.getString(
R.string.config_default_keyboard_theme_id);
sInstance.mLayoutId = Integer.valueOf(
prefs.getString(PREF_KEYBOARD_LAYOUT, sConfigDefaultKeyboardThemeId));
} catch (NumberFormatException e) {
sConfigDefaultKeyboardThemeId = "0";
sInstance.mLayoutId = 0;
}
prefs.registerOnSharedPreferenceChangeListener(sInstance); prefs.registerOnSharedPreferenceChangeListener(sInstance);
} }
@ -499,6 +505,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mSymbolKeyState.onOtherKeyPressed(); mSymbolKeyState.onOtherKeyPressed();
} }
public void onCancelInput() {
// Snap back to the previous keyboard mode if the user cancels sliding input.
if (mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_MOMENTARY && getPointerCount() == 1)
changeKeyboardMode();
}
private void toggleShiftInSymbol() { private void toggleShiftInSymbol() {
if (isAlphabetMode()) if (isAlphabetMode())
return; return;
@ -557,11 +569,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
switch (mAutoModeSwitchState) { switch (mAutoModeSwitchState) {
case AUTO_MODE_SWITCH_STATE_MOMENTARY: case AUTO_MODE_SWITCH_STATE_MOMENTARY:
// Only distinct multi touch devices can be in this state. // Only distinct multi touch devices can be in this state.
// On non-distinct multi touch devices, mode change key is handled by {@link onKey}, // On non-distinct multi touch devices, mode change key is handled by
// not by {@link onPress} and {@link onRelease}. So, on such devices, // {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and
// {@link mAutoModeSwitchState} starts from {@link AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN}, // {@link LatinIME#onRelease}. So, on such devices, {@link #mAutoModeSwitchState} starts
// or {@link AUTO_MODE_SWITCH_STATE_ALPHA}, not from // from {@link #AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN}, or
// {@link AUTO_MODE_SWITCH_STATE_MOMENTARY}. // {@link #AUTO_MODE_SWITCH_STATE_ALPHA}, not from
// {@link #AUTO_MODE_SWITCH_STATE_MOMENTARY}.
if (key == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { if (key == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
// Detected only the mode change key has been pressed, and then released. // Detected only the mode change key has been pressed, and then released.
if (mIsSymbols) { if (mIsSymbols) {
@ -572,6 +585,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
} else if (getPointerCount() == 1) { } else if (getPointerCount() == 1) {
// Snap back to the previous keyboard mode if the user pressed the mode change key // Snap back to the previous keyboard mode if the user pressed the mode change key
// and slid to other key, then released the finger. // and slid to other key, then released the finger.
// If the user cancels the sliding input, snapping back to the previous keyboard
// mode is handled by {@link #onCancelInput}.
changeKeyboardMode(); changeKeyboardMode();
} else { } else {
// Chording input is being started. The keyboard mode will be snapped back to the // Chording input is being started. The keyboard mode will be snapped back to the
@ -609,8 +624,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
if (mInputView != null) { if (mInputView != null) {
mInputView.closing(); mInputView.closing();
} }
if (THEMES.length <= layoutId) { if (KEYBOARD_THEMES.length <= layoutId) {
layoutId = Integer.valueOf(DEFAULT_LAYOUT_ID); layoutId = Integer.valueOf(sConfigDefaultKeyboardThemeId);
} }
Utils.GCUtils.getInstance().reset(); Utils.GCUtils.getInstance().reset();
@ -618,7 +633,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
try { try {
mInputView = (LatinKeyboardView) mInputMethodService.getLayoutInflater( mInputView = (LatinKeyboardView) mInputMethodService.getLayoutInflater(
).inflate(THEMES[layoutId], null); ).inflate(KEYBOARD_THEMES[layoutId], null);
tryGC = false; tryGC = false;
} catch (OutOfMemoryError e) { } catch (OutOfMemoryError e) {
Log.w(TAG, "load keyboard failed: " + e); Log.w(TAG, "load keyboard failed: " + e);
@ -651,7 +666,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (PREF_KEYBOARD_LAYOUT.equals(key)) { if (PREF_KEYBOARD_LAYOUT.equals(key)) {
final int layoutId = Integer.valueOf( final int layoutId = Integer.valueOf(
sharedPreferences.getString(key, DEFAULT_LAYOUT_ID)); sharedPreferences.getString(key, sConfigDefaultKeyboardThemeId));
createInputViewInternal(layoutId, false); createInputViewInternal(layoutId, false);
postSetInputView(); postSetInputView();
} else if (Settings.PREF_SETTINGS_KEY.equals(key)) { } else if (Settings.PREF_SETTINGS_KEY.equals(key)) {

View file

@ -79,8 +79,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
public static final int COLOR_SCHEME_WHITE = 0; public static final int COLOR_SCHEME_WHITE = 0;
public static final int COLOR_SCHEME_BLACK = 1; public static final int COLOR_SCHEME_BLACK = 1;
public static final int NOT_A_TOUCH_COORDINATE = -1;
// Timing constants // Timing constants
private final int mKeyRepeatInterval; private final int mKeyRepeatInterval;
@ -550,7 +548,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
} }
/** /**
* When enabled, calls to {@link KeyboardActionListener#onKey} will include key * When enabled, calls to {@link KeyboardActionListener#onCodeInput} will include key
* codes for adjacent keys. When disabled, only the primary key code will be * codes for adjacent keys. When disabled, only the primary key code will be
* reported. * reported.
* @param enabled whether or not the proximity correction is enabled * @param enabled whether or not the proximity correction is enabled
@ -694,7 +692,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
// Draw key label // Draw key label
if (label != null) { if (label != null) {
// For characters, use large font. For labels like "Done", use small font. // For characters, use large font. For labels like "Done", use small font.
final int labelSize = getLabelSizeAndSetPaint(label, key, paint); final int labelSize = getLabelSizeAndSetPaint(label, key.mLabelOption, paint);
final int labelCharHeight = getLabelCharHeight(labelSize, paint); final int labelCharHeight = getLabelCharHeight(labelSize, paint);
// Vertical label text alignment. // Vertical label text alignment.
@ -830,13 +828,13 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
mDirtyRect.setEmpty(); mDirtyRect.setEmpty();
} }
private int getLabelSizeAndSetPaint(CharSequence label, Key key, Paint paint) { public int getLabelSizeAndSetPaint(CharSequence label, int keyLabelOption, Paint paint) {
// For characters, use large font. For labels like "Done", use small font. // For characters, use large font. For labels like "Done", use small font.
final int labelSize; final int labelSize;
final Typeface labelStyle; final Typeface labelStyle;
if (label.length() > 1) { if (label.length() > 1) {
labelSize = mLabelTextSize; labelSize = mLabelTextSize;
if ((key.mLabelOption & KEY_LABEL_OPTION_FONT_NORMAL) != 0) { if ((keyLabelOption & KEY_LABEL_OPTION_FONT_NORMAL) != 0) {
labelStyle = Typeface.DEFAULT; labelStyle = Typeface.DEFAULT;
} else { } else {
labelStyle = Typeface.DEFAULT_BOLD; labelStyle = Typeface.DEFAULT_BOLD;
@ -1106,6 +1104,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
@Override @Override
public void onCancelInput() { public void onCancelInput() {
mKeyboardActionListener.onCancelInput();
dismissPopupKeyboard(); dismissPopupKeyboard();
} }
@ -1127,7 +1126,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
// Remove gesture detector on mini-keyboard // Remove gesture detector on mini-keyboard
miniKeyboard.mGestureDetector = null; miniKeyboard.mGestureDetector = null;
Keyboard keyboard = new MiniKeyboardBuilder(getContext(), popupKeyboardResId, popupKey) Keyboard keyboard = new MiniKeyboardBuilder(this, popupKeyboardResId, popupKey)
.build(); .build();
miniKeyboard.setKeyboard(keyboard); miniKeyboard.setKeyboard(keyboard);
miniKeyboard.setPopupParent(this); miniKeyboard.setPopupParent(this);

View file

@ -48,7 +48,7 @@ public class LatinKeyboard extends Keyboard {
private final Drawable mButtonArrowLeftIcon; private final Drawable mButtonArrowLeftIcon;
private final Drawable mButtonArrowRightIcon; private final Drawable mButtonArrowRightIcon;
private final int mSpaceBarTextShadowColor; private final int mSpaceBarTextShadowColor;
private int mSpaceKeyIndex = -1; private final int[] mSpaceKeyIndexArray;
private int mSpaceDragStartX; private int mSpaceDragStartX;
private int mSpaceDragLastDiff; private int mSpaceDragLastDiff;
private final Context mContext; private final Context mContext;
@ -92,7 +92,8 @@ public class LatinKeyboard extends Keyboard {
mButtonArrowRightIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_right); mButtonArrowRightIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_right);
sSpacebarVerticalCorrection = res.getDimensionPixelOffset( sSpacebarVerticalCorrection = res.getDimensionPixelOffset(
R.dimen.spacebar_vertical_correction); R.dimen.spacebar_vertical_correction);
mSpaceKeyIndex = indexOf(CODE_SPACE); // The index of space key is available only after Keyboard constructor has finished.
mSpaceKeyIndexArray = new int[] { indexOf(CODE_SPACE) };
} }
/** /**
@ -173,7 +174,7 @@ public class LatinKeyboard extends Keyboard {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private Bitmap drawSpaceBar(int opacity, boolean isAutoCorrection) { private Bitmap drawSpaceBar(int opacity, boolean isAutoCorrection) {
final int width = mSpaceKey.mWidth; final int width = mSpaceKey.mWidth;
final int height = mSpaceIcon.getIntrinsicHeight(); final int height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : mSpaceKey.mHeight;
final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(buffer); final Canvas canvas = new Canvas(buffer);
final Resources res = mContext.getResources(); final Resources res = mContext.getResources();
@ -230,7 +231,7 @@ public class LatinKeyboard extends Keyboard {
int y = height - iconHeight; int y = height - iconHeight;
mSpaceAutoCorrectionIndicator.setBounds(x, y, x + iconWidth, y + iconHeight); mSpaceAutoCorrectionIndicator.setBounds(x, y, x + iconWidth, y + iconHeight);
mSpaceAutoCorrectionIndicator.draw(canvas); mSpaceAutoCorrectionIndicator.draw(canvas);
} else { } else if (mSpaceIcon != null) {
final int iconWidth = mSpaceIcon.getIntrinsicWidth(); final int iconWidth = mSpaceIcon.getIntrinsicWidth();
final int iconHeight = mSpaceIcon.getIntrinsicHeight(); final int iconHeight = mSpaceIcon.getIntrinsicHeight();
int x = (width - iconWidth) / 2; int x = (width - iconWidth) / 2;
@ -418,7 +419,7 @@ public class LatinKeyboard extends Keyboard {
@Override @Override
public int[] getNearestKeys(int x, int y) { public int[] getNearestKeys(int x, int y) {
if (mCurrentlyInSpace) { if (mCurrentlyInSpace) {
return new int[] { mSpaceKeyIndex }; return mSpaceKeyIndexArray;
} else { } else {
// Avoid dead pixels at edges of the keyboard // Avoid dead pixels at edges of the keyboard
return super.getNearestKeys(Math.max(0, Math.min(x, getMinWidth() - 1)), return super.getNearestKeys(Math.max(0, Math.min(x, getMinWidth() - 1)),

View file

@ -62,13 +62,18 @@ public class LatinKeyboardView extends KeyboardView {
} }
} }
public void setLatinKeyboard(LatinKeyboard k) { public void setLatinKeyboard(LatinKeyboard newKeyboard) {
super.setKeyboard(k); final LatinKeyboard oldKeyboard = getLatinKeyboard();
if (oldKeyboard != null) {
// Reset old keyboard state before switching to new keyboard.
oldKeyboard.keyReleased();
}
super.setKeyboard(newKeyboard);
// One-seventh of the keyboard width seems like a reasonable threshold // One-seventh of the keyboard width seems like a reasonable threshold
mJumpThresholdSquare = k.getMinWidth() / 7; mJumpThresholdSquare = newKeyboard.getMinWidth() / 7;
mJumpThresholdSquare *= mJumpThresholdSquare; mJumpThresholdSquare *= mJumpThresholdSquare;
// Assuming there are 4 rows, this is the coordinate of the last row // Assuming there are 4 rows, this is the coordinate of the last row
mLastRowY = (k.getHeight() * 3) / 4; mLastRowY = (newKeyboard.getHeight() * 3) / 4;
} }
public LatinKeyboard getLatinKeyboard() { public LatinKeyboard getLatinKeyboard() {
@ -95,8 +100,8 @@ public class LatinKeyboardView extends KeyboardView {
private boolean invokeOnKey(int primaryCode) { private boolean invokeOnKey(int primaryCode) {
getOnKeyboardActionListener().onCodeInput(primaryCode, null, getOnKeyboardActionListener().onCodeInput(primaryCode, null,
KeyboardView.NOT_A_TOUCH_COORDINATE, KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
KeyboardView.NOT_A_TOUCH_COORDINATE); KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
return true; return true;
} }

View file

@ -16,8 +16,12 @@
package com.android.inputmethod.keyboard; package com.android.inputmethod.keyboard;
import com.android.inputmethod.latin.R;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Paint;
import android.graphics.Rect;
import java.util.List; import java.util.List;
@ -25,45 +29,74 @@ public class MiniKeyboardBuilder {
private final Resources mRes; private final Resources mRes;
private final Keyboard mKeyboard; private final Keyboard mKeyboard;
private final CharSequence[] mPopupCharacters; private final CharSequence[] mPopupCharacters;
private final int mMiniKeyboardKeyHorizontalPadding;
private final int mKeyWidth;
private final int mMaxColumns; private final int mMaxColumns;
private final int mNumRows; private final int mNumRows;
private int mColPos; private int mColPos;
private int mRowPos; private int mRowPos;
private Row mRow;
private int mX; private int mX;
private int mY; private int mY;
public MiniKeyboardBuilder(Context context, int layoutTemplateResId, Key popupKey) { public MiniKeyboardBuilder(KeyboardView view, int layoutTemplateResId, Key popupKey) {
final Context context = view.getContext();
mRes = context.getResources(); mRes = context.getResources();
mKeyboard = new Keyboard(context, layoutTemplateResId, null); final Keyboard keyboard = new Keyboard(context, layoutTemplateResId, null);
mKeyboard = keyboard;
mPopupCharacters = popupKey.mPopupCharacters; mPopupCharacters = popupKey.mPopupCharacters;
final int numKeys = mPopupCharacters.length; mMiniKeyboardKeyHorizontalPadding = (int)mRes.getDimension(
R.dimen.mini_keyboard_key_horizontal_padding);
mKeyWidth = getMaxKeyWidth(view, mPopupCharacters, mKeyboard.getKeyWidth());
final int maxColumns = popupKey.mMaxPopupColumn; final int maxColumns = popupKey.mMaxPopupColumn;
mMaxColumns = maxColumns;
final int numKeys = mPopupCharacters.length;
int numRows = numKeys / maxColumns; int numRows = numKeys / maxColumns;
if (numKeys % maxColumns != 0) numRows++; if (numKeys % maxColumns != 0) numRows++;
mMaxColumns = maxColumns;
mNumRows = numRows; mNumRows = numRows;
// TODO: To determine key width we should pay attention to key label length. keyboard.setHeight((keyboard.getRowHeight() + keyboard.getVerticalGap()) * numRows
mRow = new Row(mKeyboard, getRowFlags()); - keyboard.getVerticalGap());
if (numRows > 1) { if (numRows > 1) {
mColPos = numKeys % maxColumns; mColPos = numKeys % maxColumns;
if (mColPos > 0) mColPos = maxColumns - mColPos; if (mColPos > 0) mColPos = maxColumns - mColPos;
// Centering top-row keys. // Centering top-row keys.
mX = mColPos * (mRow.mDefaultWidth + mRow.mDefaultHorizontalGap) / 2; mX = mColPos * (mKeyWidth + keyboard.getHorizontalGap()) / 2;
} }
mKeyboard.setMinWidth(0); mKeyboard.setMinWidth(0);
} }
private int getMaxKeyWidth(KeyboardView view, CharSequence[] popupCharacters, int minKeyWidth) {
Paint paint = null;
Rect bounds = null;
int maxWidth = 0;
for (CharSequence popupSpec : popupCharacters) {
final CharSequence label = PopupCharactersParser.getLabel(popupSpec.toString());
// If the label is single letter, minKeyWidth is enough to hold the label.
if (label.length() > 1) {
if (paint == null) {
paint = new Paint();
paint.setAntiAlias(true);
}
final int labelSize = view.getLabelSizeAndSetPaint(label, 0, paint);
paint.setTextSize(labelSize);
if (bounds == null) bounds = new Rect();
paint.getTextBounds(label.toString(), 0, label.length(), bounds);
if (maxWidth < bounds.width())
maxWidth = bounds.width();
}
}
return Math.max(minKeyWidth, maxWidth + mMiniKeyboardKeyHorizontalPadding);
}
public Keyboard build() { public Keyboard build() {
List<Key> keys = mKeyboard.getKeys(); final Keyboard keyboard = mKeyboard;
final List<Key> keys = keyboard.getKeys();
for (CharSequence label : mPopupCharacters) { for (CharSequence label : mPopupCharacters) {
refresh(); refresh();
final Key key = new Key(mRes, mRow, label, mX, mY); final Key key = new Key(mRes, keyboard, label, mX, mY, mKeyWidth, getRowFlags());
keys.add(key); keys.add(key);
advance(); advance();
} }
finish(); return keyboard;
return mKeyboard;
} }
private int getRowFlags() { private int getRowFlags() {
@ -76,29 +109,21 @@ public class MiniKeyboardBuilder {
private void refresh() { private void refresh() {
if (mColPos >= mMaxColumns) { if (mColPos >= mMaxColumns) {
final Row row = mRow; final Keyboard keyboard = mKeyboard;
// TODO: Allocate key position depending the precedence of popup characters. // TODO: Allocate key position depending the precedence of popup characters.
mX = 0; mX = 0;
mY += row.mDefaultHeight + row.mVerticalGap; mY += keyboard.getRowHeight() + keyboard.getVerticalGap();
mColPos = 0; mColPos = 0;
// TODO: To determine key width we should pay attention to key label length from
// bottom to up for rows.
mRow = new Row(mKeyboard, getRowFlags());
mRowPos++; mRowPos++;
} }
} }
private void advance() { private void advance() {
final Row row = mRow;
final Keyboard keyboard = mKeyboard; final Keyboard keyboard = mKeyboard;
// TODO: Allocate key position depending the precedence of popup characters. // TODO: Allocate key position depending the precedence of popup characters.
mX += row.mDefaultWidth + row.mDefaultHorizontalGap; mX += mKeyWidth + keyboard.getHorizontalGap();
if (mX > keyboard.getMinWidth()) if (mX > keyboard.getMinWidth())
keyboard.setMinWidth(mX); keyboard.setMinWidth(mX);
mColPos++; mColPos++;
} }
}
private void finish() {
mKeyboard.setHeight(mY + mRow.mDefaultHeight);
}
}

View file

@ -65,6 +65,9 @@ public class PointerTracker {
private final PointerTrackerKeyState mKeyState; private final PointerTrackerKeyState mKeyState;
// true if keyboard layout has been changed.
private boolean mKeyboardLayoutHasBeenChanged;
// true if event is already translated to a key action (long press or mini-keyboard) // true if event is already translated to a key action (long press or mini-keyboard)
private boolean mKeyAlreadyProcessed; private boolean mKeyAlreadyProcessed;
@ -122,10 +125,14 @@ public class PointerTracker {
mListener = listener; mListener = listener;
} }
private void callListenerOnPress(int primaryCode) { // Returns true if keyboard has been changed by this callback.
private boolean callListenerOnPressAndCheckKeyboardLayoutChange(int primaryCode) {
if (DEBUG_LISTENER) if (DEBUG_LISTENER)
Log.d(TAG, "onPress : " + keyCodePrintable(primaryCode)); Log.d(TAG, "onPress : " + keyCodePrintable(primaryCode));
mListener.onPress(primaryCode); mListener.onPress(primaryCode);
final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged;
mKeyboardLayoutHasBeenChanged = false;
return keyboardLayoutHasBeenChanged;
} }
private void callListenerOnCodeInput(int primaryCode, int[] keyCodes, int x, int y) { private void callListenerOnCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
@ -159,8 +166,8 @@ public class PointerTracker {
mKeyboard = keyboard; mKeyboard = keyboard;
mKeys = keys; mKeys = keys;
mKeyHysteresisDistanceSquared = (int)(keyHysteresisDistance * keyHysteresisDistance); mKeyHysteresisDistanceSquared = (int)(keyHysteresisDistance * keyHysteresisDistance);
// Update current key index because keyboard layout has been changed. // Mark that keyboard layout has been changed.
mKeyState.onSetKeyboard(); mKeyboardLayoutHasBeenChanged = true;
} }
public boolean isInSlidingKeyInput() { public boolean isInSlidingKeyInput() {
@ -296,14 +303,16 @@ public class PointerTracker {
// from modifier key, or 3) this pointer is on mini-keyboard. // from modifier key, or 3) this pointer is on mini-keyboard.
mIsAllowedSlidingKeyInput = mConfigSlidingKeyInputEnabled || isModifierInternal(keyIndex) mIsAllowedSlidingKeyInput = mConfigSlidingKeyInputEnabled || isModifierInternal(keyIndex)
|| mKeyDetector instanceof MiniKeyboardKeyDetector; || mKeyDetector instanceof MiniKeyboardKeyDetector;
mKeyboardLayoutHasBeenChanged = false;
mKeyAlreadyProcessed = false; mKeyAlreadyProcessed = false;
mIsRepeatableKey = false; mIsRepeatableKey = false;
mIsInSlidingKeyInput = false; mIsInSlidingKeyInput = false;
if (isValidKeyIndex(keyIndex)) { if (isValidKeyIndex(keyIndex)) {
callListenerOnPress(mKeys[keyIndex].mCode); // This onPress call may have changed keyboard layout. Those cases are detected at
// This onPress call may have changed keyboard layout and have updated mKeyIndex. // {@link #setKeyboard}. In those cases, we should update keyIndex according to the new
// If that's the case, mKeyIndex has been updated in setKeyboard(). // keyboard layout.
keyIndex = mKeyState.getKeyIndex(); if (callListenerOnPressAndCheckKeyboardLayoutChange(mKeys[keyIndex].mCode))
keyIndex = mKeyState.onDownKey(x, y, eventTime);
} }
if (isValidKeyIndex(keyIndex)) { if (isValidKeyIndex(keyIndex)) {
if (mKeys[keyIndex].mRepeatable) { if (mKeys[keyIndex].mRepeatable) {
@ -327,13 +336,17 @@ public class PointerTracker {
// TODO: down-to-up filter, if (eventTime-downTime) is less than threshold, just ignore // TODO: down-to-up filter, if (eventTime-downTime) is less than threshold, just ignore
// this move event. Otherwise fire {@link onDownEventInternal} and continue. // this move event. Otherwise fire {@link onDownEventInternal} and continue.
final int keyIndex = keyState.onMoveKey(x, y); int keyIndex = keyState.onMoveKey(x, y);
final Key oldKey = getKey(keyState.getKeyIndex()); final Key oldKey = getKey(keyState.getKeyIndex());
if (isValidKeyIndex(keyIndex)) { if (isValidKeyIndex(keyIndex)) {
if (oldKey == null) { if (oldKey == null) {
// The pointer has been slid in to the new key, but the finger was not on any keys. // The pointer has been slid in to the new key, but the finger was not on any keys.
// In this case, we must call onPress() to notify that the new key is being pressed. // In this case, we must call onPress() to notify that the new key is being pressed.
callListenerOnPress(getKey(keyIndex).mCode); // This onPress call may have changed keyboard layout. Those cases are detected at
// {@link #setKeyboard}. In those cases, we should update keyIndex according to the
// new keyboard layout.
if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex).mCode))
keyIndex = keyState.onMoveKey(x, y);
keyState.onMoveToNewKey(keyIndex, x, y); keyState.onMoveToNewKey(keyIndex, x, y);
startLongPressTimer(keyIndex); startLongPressTimer(keyIndex);
} else if (!isMinorMoveBounce(x, y, keyIndex)) { } else if (!isMinorMoveBounce(x, y, keyIndex)) {
@ -344,7 +357,11 @@ public class PointerTracker {
callListenerOnRelease(oldKey.mCode); callListenerOnRelease(oldKey.mCode);
mHandler.cancelLongPressTimers(); mHandler.cancelLongPressTimers();
if (mIsAllowedSlidingKeyInput) { if (mIsAllowedSlidingKeyInput) {
callListenerOnPress(getKey(keyIndex).mCode); // This onPress call may have changed keyboard layout. Those cases are detected
// at {@link #setKeyboard}. In those cases, we should update keyIndex according
// to the new keyboard layout.
if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex).mCode))
keyIndex = keyState.onMoveKey(x, y);
keyState.onMoveToNewKey(keyIndex, x, y); keyState.onMoveToNewKey(keyIndex, x, y);
startLongPressTimer(keyIndex); startLongPressTimer(keyIndex);
} else { } else {
@ -509,7 +526,7 @@ public class PointerTracker {
return; return;
} else if (mKeyboardSwitcher.isInMomentaryAutoModeSwitchState()) { } else if (mKeyboardSwitcher.isInMomentaryAutoModeSwitchState()) {
// We use longer timeout for sliding finger input started from the symbols mode key. // We use longer timeout for sliding finger input started from the symbols mode key.
mHandler.startLongPressTimer(mLongPressKeyTimeout * 2, keyIndex, this); mHandler.startLongPressTimer(mLongPressKeyTimeout * 3, keyIndex, this);
} else { } else {
mHandler.startLongPressTimer(mLongPressKeyTimeout, keyIndex, this); mHandler.startLongPressTimer(mLongPressKeyTimeout, keyIndex, this);
} }

View file

@ -106,8 +106,4 @@ package com.android.inputmethod.keyboard;
mUpTime = eventTime; mUpTime = eventTime;
return onMoveKeyInternal(x, y); return onMoveKeyInternal(x, y);
} }
public void onSetKeyboard() {
mKeyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(mKeyX, mKeyY, null);
}
} }

View file

@ -45,15 +45,6 @@ public class Row {
private final Keyboard mKeyboard; private final Keyboard mKeyboard;
public Row(Keyboard keyboard, int rowFlags) {
this.mKeyboard = keyboard;
mDefaultHeight = keyboard.getRowHeight();
mDefaultWidth = keyboard.getKeyWidth();
mDefaultHorizontalGap = keyboard.getHorizontalGap();
mVerticalGap = keyboard.getVerticalGap();
mRowEdgeFlags = rowFlags;
}
public Row(Resources res, Keyboard keyboard, XmlResourceParser parser) { public Row(Resources res, Keyboard keyboard, XmlResourceParser parser) {
this.mKeyboard = keyboard; this.mKeyboard = keyboard;
final int keyboardWidth = keyboard.getDisplayWidth(); final int keyboardWidth = keyboard.getDisplayWidth();

View file

@ -1,12 +1,12 @@
/* /*
* Copyright (C) 2008 The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * 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 * use this file except in compliance with the License. You may obtain a copy of
* the License at * the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@ -17,13 +17,9 @@
package com.android.inputmethod.latin; package com.android.inputmethod.latin;
import android.content.Context; import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.util.Log; import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.Channels;
import java.util.Arrays; import java.util.Arrays;
/** /**
@ -48,21 +44,18 @@ public class BinaryDictionary extends Dictionary {
private int mDicTypeId; private int mDicTypeId;
private int mNativeDict; private int mNativeDict;
private int mDictLength; private long mDictLength;
private final int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_ALTERNATIVES]; private final int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_ALTERNATIVES];
private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS]; private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS];
private final char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS]; private final char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS];
private final int[] mFrequencies = new int[MAX_WORDS]; private final int[] mFrequencies = new int[MAX_WORDS];
private final int[] mFrequencies_bigrams = new int[MAX_BIGRAMS]; private final int[] mFrequencies_bigrams = new int[MAX_BIGRAMS];
// Keep a reference to the native dict direct buffer in Java to avoid
// unexpected deallocation of the direct buffer.
private ByteBuffer mNativeDictDirectBuffer;
static { static {
try { try {
System.loadLibrary("jni_latinime2"); System.loadLibrary("jni_latinime2");
} catch (UnsatisfiedLinkError ule) { } catch (UnsatisfiedLinkError ule) {
Log.e("BinaryDictionary", "Could not load native library jni_latinime2"); Log.e(TAG, "Could not load native library jni_latinime");
} }
} }
@ -71,91 +64,46 @@ public class BinaryDictionary extends Dictionary {
* @param context application context for reading resources * @param context application context for reading resources
* @param resId the resource containing the raw binary dictionary * @param resId the resource containing the raw binary dictionary
*/ */
public BinaryDictionary(Context context, int[] resId, int dicTypeId) { public BinaryDictionary(Context context, int resId, int dicTypeId) {
if (resId != null && resId.length > 0 && resId[0] != 0) { if (resId != 0) {
loadDictionary(context, resId); loadDictionary(context, resId);
} }
mDicTypeId = dicTypeId; mDicTypeId = dicTypeId;
} }
/** private native int openNative(String sourceDir, long dictOffset, long dictSize,
* Create a dictionary from a byte buffer. This is used for testing. int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength,
* @param context application context for reading resources int maxWords, int maxAlternatives);
* @param byteBuffer a ByteBuffer containing the binary dictionary
*/
public BinaryDictionary(Context context, ByteBuffer byteBuffer, int dicTypeId) {
if (byteBuffer != null) {
if (byteBuffer.isDirect()) {
mNativeDictDirectBuffer = byteBuffer;
} else {
mNativeDictDirectBuffer = ByteBuffer.allocateDirect(byteBuffer.capacity());
byteBuffer.rewind();
mNativeDictDirectBuffer.put(byteBuffer);
}
mDictLength = byteBuffer.capacity();
mNativeDict = openNative(mNativeDictDirectBuffer,
TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER,
MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES);
}
mDicTypeId = dicTypeId;
}
private native int openNative(ByteBuffer bb, int typedLetterMultiplier,
int fullWordMultiplier, int maxWordLength, int maxWords, int maxAlternatives);
private native void closeNative(int dict); private native void closeNative(int dict);
private native boolean isValidWordNative(int nativeData, char[] word, int wordLength); private native boolean isValidWordNative(int nativeData, char[] word, int wordLength);
private native int getSuggestionsNative(int dict, int[] inputCodes, int codesSize, private native int getSuggestionsNative(int dict, int[] inputCodes, int codesSize,
char[] outputChars, int[] frequencies, char[] outputChars, int[] frequencies,
int[] nextLettersFrequencies, int nextLettersSize); int[] nextLettersFrequencies, int nextLettersSize);
private native int getBigramsNative(int dict, char[] prevWord, int prevWordLength, private native int getBigramsNative(int dict, char[] prevWord, int prevWordLength,
int[] inputCodes, int inputCodesLength, char[] outputChars, int[] frequencies, int[] inputCodes, int inputCodesLength, char[] outputChars, int[] frequencies,
int maxWordLength, int maxBigrams, int maxAlternatives); int maxWordLength, int maxBigrams, int maxAlternatives);
private final void loadDictionary(Context context, int[] resId) { private final void loadDictionary(Context context, int resId) {
InputStream[] is = null;
try { try {
// merging separated dictionary into one if dictionary is separated final AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId);
int total = 0; if (afd == null) {
is = new InputStream[resId.length]; Log.e(TAG, "Found the resource but it is compressed. resId=" + resId);
for (int i = 0; i < resId.length; i++) { return;
is[i] = context.getResources().openRawResource(resId[i]);
total += is[i].available();
}
mNativeDictDirectBuffer =
ByteBuffer.allocateDirect(total).order(ByteOrder.nativeOrder());
int got = 0;
for (int i = 0; i < resId.length; i++) {
got += Channels.newChannel(is[i]).read(mNativeDictDirectBuffer);
}
if (got != total) {
Log.e(TAG, "Read " + got + " bytes, expected " + total);
} else {
mNativeDict = openNative(mNativeDictDirectBuffer,
TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER,
MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES);
mDictLength = total;
}
} catch (IOException e) {
Log.w(TAG, "No available memory for binary dictionary");
} finally {
try {
if (is != null) {
for (int i = 0; i < is.length; i++) {
is[i].close();
}
}
} catch (IOException e) {
Log.w(TAG, "Failed to close input stream");
} }
mNativeDict = openNative(context.getApplicationInfo().sourceDir,
afd.getStartOffset(), afd.getLength(),
TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER,
MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES);
mDictLength = afd.getLength();
} catch (android.content.res.Resources.NotFoundException e) {
Log.e(TAG, "Could not find the resource. resId=" + resId);
return;
} }
} }
@Override @Override
public void getBigrams(final WordComposer codes, final CharSequence previousWord, public void getBigrams(final WordComposer codes, final CharSequence previousWord,
final WordCallback callback, int[] nextLettersFrequencies) { final WordCallback callback, int[] nextLettersFrequencies) {
char[] chars = previousWord.toString().toCharArray(); char[] chars = previousWord.toString().toCharArray();
Arrays.fill(mOutputChars_bigrams, (char) 0); Arrays.fill(mOutputChars_bigrams, (char) 0);
Arrays.fill(mFrequencies_bigrams, 0); Arrays.fill(mFrequencies_bigrams, 0);
@ -225,8 +173,8 @@ public class BinaryDictionary extends Dictionary {
return isValidWordNative(mNativeDict, chars, chars.length); return isValidWordNative(mNativeDict, chars, chars.length);
} }
public int getSize() { public long getSize() {
return mDictLength; // This value is initialized on the call to openNative() return mDictLength; // This value is initialized in loadDictionary()
} }
@Override @Override
@ -234,6 +182,7 @@ public class BinaryDictionary extends Dictionary {
if (mNativeDict != 0) { if (mNativeDict != 0) {
closeNative(mNativeDict); closeNative(mNativeDict);
mNativeDict = 0; mNativeDict = 0;
mDictLength = 0;
} }
} }

View file

@ -146,7 +146,7 @@ public class ExpandableDictionary extends Dictionary {
public Context getContext() { public Context getContext() {
return mContext; return mContext;
} }
public int getMaxWordLength() { public int getMaxWordLength() {
return MAX_WORD_LENGTH; return MAX_WORD_LENGTH;
} }
@ -158,6 +158,7 @@ public class ExpandableDictionary extends Dictionary {
private void addWordRec(NodeArray children, final String word, final int depth, private void addWordRec(NodeArray children, final String word, final int depth,
final int frequency, Node parentNode) { final int frequency, Node parentNode) {
final int wordLength = word.length(); final int wordLength = word.length();
if (wordLength <= depth) return;
final char c = word.charAt(depth); final char c = word.charAt(depth);
// Does children have the current character? // Does children have the current character?
final int childrenLength = children.mLength; final int childrenLength = children.mLength;

View file

@ -99,15 +99,15 @@ public class InputLanguageSelection extends PreferenceActivity {
} }
private boolean hasDictionary(Locale locale) { private boolean hasDictionary(Locale locale) {
Resources res = getResources(); final Resources res = getResources();
Configuration conf = res.getConfiguration(); final Configuration conf = res.getConfiguration();
Locale saveLocale = conf.locale; final Locale saveLocale = conf.locale;
boolean haveDictionary = false; boolean haveDictionary = false;
conf.locale = locale; conf.locale = locale;
res.updateConfiguration(conf, res.getDisplayMetrics()); res.updateConfiguration(conf, res.getDisplayMetrics());
int[] dictionaries = LatinIME.getDictionary(res); int mainDicResId = LatinIME.getMainDictionaryResourceId(res);
BinaryDictionary bd = new BinaryDictionary(this, dictionaries, Suggest.DIC_MAIN); BinaryDictionary bd = new BinaryDictionary(this, mainDicResId, Suggest.DIC_MAIN);
// Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of // Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of
// 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words. // 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words.

View file

@ -347,49 +347,19 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} }
/** /**
* Loads a dictionary or multiple separated dictionary * Returns a main dictionary resource id
* @return returns array of dictionary resource ids * @return main dictionary resource id
*/ */
public static int[] getDictionary(Resources res) { public static int getMainDictionaryResourceId(Resources res) {
final String MAIN_DIC_NAME = "main";
String packageName = LatinIME.class.getPackage().getName(); String packageName = LatinIME.class.getPackage().getName();
XmlResourceParser xrp = res.getXml(R.xml.dictionary); return res.getIdentifier(MAIN_DIC_NAME, "raw", packageName);
ArrayList<Integer> dictionaries = new ArrayList<Integer>();
try {
int current = xrp.getEventType();
while (current != XmlPullParser.END_DOCUMENT) {
if (current == XmlPullParser.START_TAG) {
String tag = xrp.getName();
if (tag != null) {
if (tag.equals("part")) {
String dictFileName = xrp.getAttributeValue(null, "name");
dictionaries.add(res.getIdentifier(dictFileName, "raw", packageName));
}
}
}
xrp.next();
current = xrp.getEventType();
}
} catch (XmlPullParserException e) {
Log.e(TAG, "Dictionary XML parsing failure");
} catch (IOException e) {
Log.e(TAG, "Dictionary XML IOException");
}
int count = dictionaries.size();
int[] dict = new int[count];
for (int i = 0; i < count; i++) {
dict[i] = dictionaries.get(i);
}
return dict;
} }
private void initSuggest() { private void initSuggest() {
updateAutoTextEnabled(); updateAutoTextEnabled();
String locale = mSubtypeSwitcher.getInputLocaleStr(); String locale = mSubtypeSwitcher.getInputLocaleStr();
Resources orig = getResources();
Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(new Locale(locale)); Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(new Locale(locale));
if (mSuggest != null) { if (mSuggest != null) {
mSuggest.close(); mSuggest.close();
@ -397,40 +367,35 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final SharedPreferences prefs = mPrefs; final SharedPreferences prefs = mPrefs;
mQuickFixes = prefs.getBoolean(Settings.PREF_QUICK_FIXES, true); mQuickFixes = prefs.getBoolean(Settings.PREF_QUICK_FIXES, true);
int[] dictionaries = getDictionary(orig); final Resources res = mResources;
mSuggest = new Suggest(this, dictionaries); int mainDicResId = getMainDictionaryResourceId(res);
mSuggest = new Suggest(this, mainDicResId);
loadAndSetAutoCorrectionThreshold(prefs); loadAndSetAutoCorrectionThreshold(prefs);
if (mUserDictionary != null) mUserDictionary.close();
mUserDictionary = new UserDictionary(this, locale); mUserDictionary = new UserDictionary(this, locale);
if (mContactsDictionary == null) { mSuggest.setUserDictionary(mUserDictionary);
mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
} mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
if (mAutoDictionary != null) { mSuggest.setContactsDictionary(mContactsDictionary);
mAutoDictionary.close();
}
mAutoDictionary = new AutoDictionary(this, this, locale, Suggest.DIC_AUTO); mAutoDictionary = new AutoDictionary(this, this, locale, Suggest.DIC_AUTO);
if (mUserBigramDictionary != null) { mSuggest.setAutoDictionary(mAutoDictionary);
mUserBigramDictionary.close();
}
mUserBigramDictionary = new UserBigramDictionary(this, this, locale, Suggest.DIC_USER); mUserBigramDictionary = new UserBigramDictionary(this, this, locale, Suggest.DIC_USER);
mSuggest.setUserBigramDictionary(mUserBigramDictionary); mSuggest.setUserBigramDictionary(mUserBigramDictionary);
mSuggest.setUserDictionary(mUserDictionary);
mSuggest.setContactsDictionary(mContactsDictionary);
mSuggest.setAutoDictionary(mAutoDictionary);
updateCorrectionMode(); updateCorrectionMode();
mWordSeparators = mResources.getString(R.string.word_separators); mWordSeparators = res.getString(R.string.word_separators);
mSentenceSeparators = mResources.getString(R.string.sentence_separators); mSentenceSeparators = res.getString(R.string.sentence_separators);
mSubtypeSwitcher.changeSystemLocale(savedLocale); mSubtypeSwitcher.changeSystemLocale(savedLocale);
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
if (mUserDictionary != null) { if (mSuggest != null) {
mUserDictionary.close(); mSuggest.close();
} mSuggest = null;
if (mContactsDictionary != null) {
mContactsDictionary.close();
} }
unregisterReceiver(mReceiver); unregisterReceiver(mReceiver);
mVoiceConnector.destroy(); mVoiceConnector.destroy();
@ -811,11 +776,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override @Override
public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) { public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
if (DEBUG) { if (DEBUG) {
Log.i("foo", "Received completions:"); Log.i(TAG, "Received completions:");
final int count = (applicationSpecifiedCompletions != null) final int count = (applicationSpecifiedCompletions != null)
? applicationSpecifiedCompletions.length : 0; ? applicationSpecifiedCompletions.length : 0;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
Log.i("foo", " #" + i + ": " + applicationSpecifiedCompletions[i]); Log.i(TAG, " #" + i + ": " + applicationSpecifiedCompletions[i]);
} }
} }
if (mApplicationSpecifiedCompletionOn) { if (mApplicationSpecifiedCompletionOn) {
@ -859,10 +824,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override @Override
public boolean onEvaluateFullscreenMode() { public boolean onEvaluateFullscreenMode() {
DisplayMetrics dm = getResources().getDisplayMetrics(); final Resources res = mResources;
DisplayMetrics dm = res.getDisplayMetrics();
float displayHeight = dm.heightPixels; float displayHeight = dm.heightPixels;
// If the display is more than X inches high, don't go to fullscreen mode // If the display is more than X inches high, don't go to fullscreen mode
float dimen = getResources().getDimension(R.dimen.max_height_for_fullscreen); float dimen = res.getDimension(R.dimen.max_height_for_fullscreen);
if (displayHeight > dimen) { if (displayHeight > dimen) {
return false; return false;
} else { } else {
@ -1048,8 +1014,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return mOptionsDialog != null && mOptionsDialog.isShowing(); return mOptionsDialog != null && mOptionsDialog.isShowing();
} }
// Implementation of KeyboardViewListener // Implementation of {@link KeyboardActionListener}.
@Override @Override
public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
long when = SystemClock.uptimeMillis(); long when = SystemClock.uptimeMillis();
@ -1132,7 +1097,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
ic.commitText(text, 1); ic.commitText(text, 1);
ic.endBatchEdit(); ic.endBatchEdit();
mKeyboardSwitcher.updateShiftState(); mKeyboardSwitcher.updateShiftState();
mKeyboardSwitcher.onKey(0); // dummy key code. mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY);
mJustReverted = false; mJustReverted = false;
mJustAddedAutoSpace = false; mJustAddedAutoSpace = false;
mEnteredText = text; mEnteredText = text;
@ -1141,6 +1106,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override @Override
public void onCancelInput() { public void onCancelInput() {
// User released a finger outside any key // User released a finger outside any key
mKeyboardSwitcher.onCancelInput();
} }
private void handleBackspace() { private void handleBackspace() {
@ -1486,7 +1452,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} }
private void showSuggestions(WordComposer word) { private void showSuggestions(WordComposer word) {
// long startTime = System.currentTimeMillis(); // TIME MEASUREMENT!
// TODO Maybe need better way of retrieving previous word // TODO Maybe need better way of retrieving previous word
CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(), CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
mWordSeparators); mWordSeparators);
@ -1498,9 +1463,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
boolean correctionAvailable = !mInputTypeNoAutoCorrect && !mJustReverted boolean correctionAvailable = !mInputTypeNoAutoCorrect && !mJustReverted
&& mSuggest.hasMinimalCorrection(); && mSuggest.hasMinimalCorrection();
CharSequence typedWord = word.getTypedWord(); final CharSequence typedWord = word.getTypedWord();
// If we're in basic correct // If we're in basic correct
boolean typedWordValid = mSuggest.isValidWord(typedWord) || final boolean typedWordValid = mSuggest.isValidWord(typedWord) ||
(preferCapitalization() (preferCapitalization()
&& mSuggest.isValidWord(typedWord.toString().toLowerCase())); && mSuggest.isValidWord(typedWord.toString().toLowerCase()));
if (mCorrectionMode == Suggest.CORRECTION_FULL if (mCorrectionMode == Suggest.CORRECTION_FULL
@ -1511,7 +1476,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
correctionAvailable &= !word.isMostlyCaps(); correctionAvailable &= !word.isMostlyCaps();
correctionAvailable &= !TextEntryState.isCorrecting(); correctionAvailable &= !TextEntryState.isCorrecting();
if (builder.size() > 1 || mCandidateView.isShowingAddToDictionaryHint()) { // Basically, we update the suggestion strip only when suggestion count > 1. However,
// there is an exception: We update the suggestion strip whenever typed word's length
// is 1, regardless of suggestion count. Actually, in most cases, suggestion count is 1
// when typed word's length is 1, but we do always need to clear the previous state when
// the user starts typing a word (i.e. typed word's length == 1).
if (typedWord.length() == 1 || builder.size() > 1
|| mCandidateView.isShowingAddToDictionaryHint()) {
builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion(correctionAvailable); builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion(correctionAvailable);
} else { } else {
final SuggestedWords previousSuggestions = mCandidateView.getSuggestions(); final SuggestedWords previousSuggestions = mCandidateView.getSuggestions();
@ -1588,8 +1559,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
LatinImeLogger.logOnManualSuggestion( LatinImeLogger.logOnManualSuggestion(
"", suggestion.toString(), index, suggestions.mWords); "", suggestion.toString(), index, suggestions.mWords);
final char primaryCode = suggestion.charAt(0); final char primaryCode = suggestion.charAt(0);
onCodeInput(primaryCode, new int[]{primaryCode}, KeyboardView.NOT_A_TOUCH_COORDINATE, onCodeInput(primaryCode, new int[] { primaryCode },
KeyboardView.NOT_A_TOUCH_COORDINATE); KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
if (ic != null) { if (ic != null) {
ic.endBatchEdit(); ic.endBatchEdit();
} }
@ -1841,7 +1813,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void sendSpace() { private void sendSpace() {
sendKeyChar((char)Keyboard.CODE_SPACE); sendKeyChar((char)Keyboard.CODE_SPACE);
mKeyboardSwitcher.updateShiftState(); mKeyboardSwitcher.updateShiftState();
//onKey(KEY_SPACE[0], KEY_SPACE);
} }
public boolean preferCapitalization() { public boolean preferCapitalization() {
@ -1879,7 +1850,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} else if (Settings.PREF_RECORRECTION_ENABLED.equals(key)) { } else if (Settings.PREF_RECORRECTION_ENABLED.equals(key)) {
mReCorrectionEnabled = sharedPreferences.getBoolean( mReCorrectionEnabled = sharedPreferences.getBoolean(
Settings.PREF_RECORRECTION_ENABLED, Settings.PREF_RECORRECTION_ENABLED,
getResources().getBoolean(R.bool.default_recorrection_enabled)); mResources.getBoolean(R.bool.default_recorrection_enabled));
} }
} }
@ -2011,11 +1982,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} }
private void updateSuggestionVisibility(SharedPreferences prefs) { private void updateSuggestionVisibility(SharedPreferences prefs) {
final Resources res = mResources;
final String suggestionVisiblityStr = prefs.getString( final String suggestionVisiblityStr = prefs.getString(
Settings.PREF_SHOW_SUGGESTIONS_SETTING, Settings.PREF_SHOW_SUGGESTIONS_SETTING,
mResources.getString(R.string.prefs_suggestion_visibility_default_value)); res.getString(R.string.prefs_suggestion_visibility_default_value));
for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) { for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
if (suggestionVisiblityStr.equals(mResources.getString(visibility))) { if (suggestionVisiblityStr.equals(res.getString(visibility))) {
mSuggestionVisibility = visibility; mSuggestionVisibility = visibility;
break; break;
} }

View file

@ -72,6 +72,6 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
public static void onSetKeyboard(Keyboard kb) { public static void onSetKeyboard(Keyboard kb) {
} }
public static void onPrintAllUsabilityStudtyLogs() { public static void onPrintAllUsabilityStudyLogs() {
} }
} }

View file

@ -42,6 +42,7 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
public class SubtypeSwitcher { public class SubtypeSwitcher {
// TODO: This should be configurable by resource
// This flag indicates if we support language switching by swipe on space bar. // This flag indicates if we support language switching by swipe on space bar.
// We may or may not draw the current language on space bar regardless of this flag. // We may or may not draw the current language on space bar regardless of this flag.
// @@@ // @@@
@ -105,6 +106,7 @@ public class SubtypeSwitcher {
mSystemLocale = null; mSystemLocale = null;
mInputLocale = null; mInputLocale = null;
mInputLocaleStr = null; mInputLocaleStr = null;
// Mode is initialized to KEYBOARD_MODE, in case that LatinIME can't obtain currentSubtype
mMode = KEYBOARD_MODE; mMode = KEYBOARD_MODE;
mAllEnabledSubtypesOfCurrentInputMethod = null; mAllEnabledSubtypesOfCurrentInputMethod = null;
// TODO: Voice input should be created here // TODO: Voice input should be created here

View file

@ -1,12 +1,12 @@
/* /*
* Copyright (C) 2008 The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * 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 * use this file except in compliance with the License. You may obtain a copy of
* the License at * the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@ -22,12 +22,11 @@ import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
/** /**
* This class loads a dictionary and provides a list of suggestions for a given sequence of * This class loads a dictionary and provides a list of suggestions for a given sequence of
* characters. This includes corrections and completions. * characters. This includes corrections and completions.
*/ */
public class Suggest implements Dictionary.WordCallback { public class Suggest implements Dictionary.WordCallback {
@ -103,16 +102,11 @@ public class Suggest implements Dictionary.WordCallback {
private int mCorrectionMode = CORRECTION_BASIC; private int mCorrectionMode = CORRECTION_BASIC;
public Suggest(Context context, int[] dictionaryResId) { public Suggest(Context context, int dictionaryResId) {
mMainDict = new BinaryDictionary(context, dictionaryResId, DIC_MAIN); mMainDict = new BinaryDictionary(context, dictionaryResId, DIC_MAIN);
initPool(); initPool();
} }
public Suggest(Context context, ByteBuffer byteBuffer) {
mMainDict = new BinaryDictionary(context, byteBuffer, DIC_MAIN);
initPool();
}
private void initPool() { private void initPool() {
for (int i = 0; i < mPrefMaxSuggestions; i++) { for (int i = 0; i < mPrefMaxSuggestions; i++) {
StringBuilder sb = new StringBuilder(getApproxMaxWordLength()); StringBuilder sb = new StringBuilder(getApproxMaxWordLength());
@ -154,7 +148,7 @@ public class Suggest implements Dictionary.WordCallback {
public void setContactsDictionary(Dictionary userDictionary) { public void setContactsDictionary(Dictionary userDictionary) {
mContactsDictionary = userDictionary; mContactsDictionary = userDictionary;
} }
public void setAutoDictionary(Dictionary autoDictionary) { public void setAutoDictionary(Dictionary autoDictionary) {
mAutoDictionary = autoDictionary; mAutoDictionary = autoDictionary;
} }
@ -232,7 +226,7 @@ public class Suggest implements Dictionary.WordCallback {
if (!TextUtils.isEmpty(prevWordForBigram)) { if (!TextUtils.isEmpty(prevWordForBigram)) {
CharSequence lowerPrevWord = prevWordForBigram.toString().toLowerCase(); CharSequence lowerPrevWord = prevWordForBigram.toString().toLowerCase();
if (mMainDict.isValidWord(lowerPrevWord)) { if (mMainDict != null && mMainDict.isValidWord(lowerPrevWord)) {
prevWordForBigram = lowerPrevWord; prevWordForBigram = lowerPrevWord;
} }
if (mUserBigramDictionary != null) { if (mUserBigramDictionary != null) {
@ -383,7 +377,7 @@ public class Suggest implements Dictionary.WordCallback {
return mHaveCorrection; return mHaveCorrection;
} }
private boolean compareCaseInsensitive(final String mLowerOriginalWord, private boolean compareCaseInsensitive(final String mLowerOriginalWord,
final char[] word, final int offset, final int length) { final char[] word, final int offset, final int length) {
final int originalLength = mLowerOriginalWord.length(); final int originalLength = mLowerOriginalWord.length();
if (originalLength == length && Character.isUpperCase(word[offset])) { if (originalLength == length && Character.isUpperCase(word[offset])) {
@ -456,7 +450,7 @@ public class Suggest implements Dictionary.WordCallback {
System.arraycopy(priorities, pos, priorities, pos + 1, prefMaxSuggestions - pos - 1); System.arraycopy(priorities, pos, priorities, pos + 1, prefMaxSuggestions - pos - 1);
priorities[pos] = freq; priorities[pos] = freq;
int poolSize = mStringPool.size(); int poolSize = mStringPool.size();
StringBuilder sb = poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1) StringBuilder sb = poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1)
: new StringBuilder(getApproxMaxWordLength()); : new StringBuilder(getApproxMaxWordLength());
sb.setLength(0); sb.setLength(0);
if (mIsAllUpperCase) { if (mIsAllUpperCase) {
@ -510,7 +504,7 @@ public class Suggest implements Dictionary.WordCallback {
|| (mAutoDictionary != null && mAutoDictionary.isValidWord(word)) || (mAutoDictionary != null && mAutoDictionary.isValidWord(word))
|| (mContactsDictionary != null && mContactsDictionary.isValidWord(word)); || (mContactsDictionary != null && mContactsDictionary.isValidWord(word));
} }
private void collectGarbage(ArrayList<CharSequence> suggestions, int prefMaxSuggestions) { private void collectGarbage(ArrayList<CharSequence> suggestions, int prefMaxSuggestions) {
int poolSize = mStringPool.size(); int poolSize = mStringPool.size();
int garbageSize = suggestions.size(); int garbageSize = suggestions.size();
@ -531,6 +525,23 @@ public class Suggest implements Dictionary.WordCallback {
public void close() { public void close() {
if (mMainDict != null) { if (mMainDict != null) {
mMainDict.close(); mMainDict.close();
mMainDict = null;
}
if (mUserDictionary != null) {
mUserDictionary.close();
mUserDictionary = null;
}
if (mUserBigramDictionary != null) {
mUserBigramDictionary.close();
mUserBigramDictionary = null;
}
if (mContactsDictionary != null) {
mContactsDictionary.close();
mContactsDictionary = null;
}
if (mAutoDictionary != null) {
mAutoDictionary.close();
mAutoDictionary = null;
} }
} }
} }

View file

@ -307,7 +307,7 @@ public class Utils {
break; break;
} }
UsabilityStudyLogUtils.getInstance().write(inputChar + "\t" + x + "\t" + y); UsabilityStudyLogUtils.getInstance().write(inputChar + "\t" + x + "\t" + y);
LatinImeLogger.onPrintAllUsabilityStudtyLogs(); LatinImeLogger.onPrintAllUsabilityStudyLogs();
} }
public void write(final String log) { public void write(final String log) {

View file

@ -12,11 +12,20 @@ LOCAL_SRC_FILES := \
#FLAG_DBG := true #FLAG_DBG := true
ifneq ($(FLAG_DBG), true) TARGETING_UNBUNDLED_FROYO := true
LOCAL_NDK_VERSION := 4
ifeq ($(TARGET_ARCH), x86)
TARGETING_UNBUNDLED_FROYO := false
endif endif
LOCAL_SDK_VERSION := 8 ifeq ($(FLAG_DBG), true)
TARGETING_UNBUNDLED_FROYO := false
endif
ifeq ($(TARGETING_UNBUNDLED_FROYO), true)
LOCAL_NDK_VERSION := 4
LOCAL_SDK_VERSION := 8
endif
LOCAL_PRELINK_MODULE := false LOCAL_PRELINK_MODULE := false
@ -25,7 +34,7 @@ LOCAL_MODULE := libjni_latinime2
LOCAL_MODULE_TAGS := optional LOCAL_MODULE_TAGS := optional
ifeq ($(FLAG_DBG), true) ifeq ($(FLAG_DBG), true)
$(warning "Making debug build.") $(warning Making debug version of native library)
LOCAL_CFLAGS += -DFLAG_DBG LOCAL_CFLAGS += -DFLAG_DBG
LOCAL_SHARED_LIBRARIES := libcutils libutils LOCAL_SHARED_LIBRARIES := libcutils libutils
endif endif

View file

@ -15,12 +15,24 @@
** limitations under the License. ** limitations under the License.
*/ */
#define LOG_TAG "LatinIME: jni"
#include "dictionary.h" #include "dictionary.h"
#include "jni.h" #include "jni.h"
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <stdio.h> #include <stdio.h>
#ifdef USE_MMAP_FOR_DICTIONARY
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#else // USE_MMAP_FOR_DICTIONARY
#include <stdlib.h>
#endif // USE_MMAP_FOR_DICTIONARY
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
using namespace latinime; using namespace latinime;
@ -37,24 +49,84 @@ static void throwException(JNIEnv *env, const char* ex, const char* fmt, int dat
} }
} }
static jint latinime_BinaryDictionary_open(JNIEnv *env, jobject object, jobject dictDirectBuffer, static jint latinime_BinaryDictionary_open(JNIEnv *env, jobject object,
jstring sourceDir, jlong dictOffset, jlong dictSize,
jint typedLetterMultiplier, jint fullWordMultiplier, jint maxWordLength, jint maxWords, jint typedLetterMultiplier, jint fullWordMultiplier, jint maxWordLength, jint maxWords,
jint maxAlternatives) { jint maxAlternatives) {
void *dict = env->GetDirectBufferAddress(dictDirectBuffer); PROF_OPEN;
if (dict == NULL) { PROF_START(66);
fprintf(stderr, "DICT: Dictionary buffer is null\n"); const char *sourceDirChars = env->GetStringUTFChars(sourceDir, NULL);
if (sourceDirChars == NULL) {
LOGE("DICT: Can't get sourceDir string");
return 0; return 0;
} }
Dictionary *dictionary = new Dictionary(dict, typedLetterMultiplier, fullWordMultiplier, int fd = 0;
maxWordLength, maxWords, maxAlternatives); void *dictBuf = NULL;
return (jint) dictionary; int adjust = 0;
#ifdef USE_MMAP_FOR_DICTIONARY
/* mmap version */
fd = open(sourceDirChars, O_RDONLY);
if (fd < 0) {
LOGE("DICT: Can't open sourceDir. sourceDirChars=%s errno=%d", sourceDirChars, errno);
return 0;
}
int pagesize = getpagesize();
adjust = dictOffset % pagesize;
int adjDictOffset = dictOffset - adjust;
int adjDictSize = dictSize + adjust;
dictBuf = mmap(NULL, sizeof(char) * adjDictSize, PROT_READ, MAP_PRIVATE, fd, adjDictOffset);
if (dictBuf == MAP_FAILED) {
LOGE("DICT: Can't mmap dictionary. errno=%d", errno);
return 0;
}
dictBuf = (void *)((char *)dictBuf + adjust);
#else // USE_MMAP_FOR_DICTIONARY
/* malloc version */
FILE *file = NULL;
file = fopen(sourceDirChars, "rb");
if (file == NULL) {
LOGE("DICT: Can't fopen sourceDir. sourceDirChars=%s errno=%d", sourceDirChars, errno);
return 0;
}
dictBuf = malloc(sizeof(char) * dictSize);
if (dictBuf == NULL) {
LOGE("DICT: Can't allocate memory region for dictionary. errno=%d", errno);
return 0;
}
int ret = fseek(file, (long)dictOffset, SEEK_SET);
if (ret != 0) {
LOGE("DICT: Failure in fseek. ret=%d errno=%d", ret, errno);
return 0;
}
ret = fread(dictBuf, sizeof(char) * dictSize, 1, file);
if (ret != 1) {
LOGE("DICT: Failure in fread. ret=%d errno=%d", ret, errno);
return 0;
}
ret = fclose(file);
if (ret != 0) {
LOGE("DICT: Failure in fclose. ret=%d errno=%d", ret, errno);
return 0;
}
#endif // USE_MMAP_FOR_DICTIONARY
env->ReleaseStringUTFChars(sourceDir, sourceDirChars);
if (!dictBuf) {
LOGE("DICT: dictBuf is null");
return 0;
}
Dictionary *dictionary = new Dictionary(dictBuf, dictSize, fd, adjust, typedLetterMultiplier,
fullWordMultiplier, maxWordLength, maxWords, maxAlternatives);
PROF_END(66);
PROF_CLOSE;
return (jint)dictionary;
} }
static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jint dict, static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jint dict,
jintArray inputArray, jint arraySize, jcharArray outputArray, jintArray frequencyArray, jintArray inputArray, jint arraySize, jcharArray outputArray, jintArray frequencyArray,
jintArray nextLettersArray, jint nextLettersSize) { jintArray nextLettersArray, jint nextLettersSize) {
Dictionary *dictionary = (Dictionary*) dict; Dictionary *dictionary = (Dictionary*)dict;
if (dictionary == NULL) return 0; if (!dictionary) return 0;
int *frequencies = env->GetIntArrayElements(frequencyArray, NULL); int *frequencies = env->GetIntArrayElements(frequencyArray, NULL);
int *inputCodes = env->GetIntArrayElements(inputArray, NULL); int *inputCodes = env->GetIntArrayElements(inputArray, NULL);
@ -79,8 +151,8 @@ static int latinime_BinaryDictionary_getBigrams(JNIEnv *env, jobject object, jin
jcharArray prevWordArray, jint prevWordLength, jintArray inputArray, jint inputArraySize, jcharArray prevWordArray, jint prevWordLength, jintArray inputArray, jint inputArraySize,
jcharArray outputArray, jintArray frequencyArray, jint maxWordLength, jint maxBigrams, jcharArray outputArray, jintArray frequencyArray, jint maxWordLength, jint maxBigrams,
jint maxAlternatives) { jint maxAlternatives) {
Dictionary *dictionary = (Dictionary*) dict; Dictionary *dictionary = (Dictionary*)dict;
if (dictionary == NULL) return 0; if (!dictionary) return 0;
jchar *prevWord = env->GetCharArrayElements(prevWordArray, NULL); jchar *prevWord = env->GetCharArrayElements(prevWordArray, NULL);
int *inputCodes = env->GetIntArrayElements(inputArray, NULL); int *inputCodes = env->GetIntArrayElements(inputArray, NULL);
@ -99,11 +171,10 @@ static int latinime_BinaryDictionary_getBigrams(JNIEnv *env, jobject object, jin
return count; return count;
} }
static jboolean latinime_BinaryDictionary_isValidWord(JNIEnv *env, jobject object, jint dict, static jboolean latinime_BinaryDictionary_isValidWord(JNIEnv *env, jobject object, jint dict,
jcharArray wordArray, jint wordLength) { jcharArray wordArray, jint wordLength) {
Dictionary *dictionary = (Dictionary*) dict; Dictionary *dictionary = (Dictionary*)dict;
if (dictionary == NULL) return (jboolean) false; if (!dictionary) return (jboolean) false;
jchar *word = env->GetCharArrayElements(wordArray, NULL); jchar *word = env->GetCharArrayElements(wordArray, NULL);
jboolean result = dictionary->isValidWord((unsigned short*) word, wordLength); jboolean result = dictionary->isValidWord((unsigned short*) word, wordLength);
@ -113,13 +184,30 @@ static jboolean latinime_BinaryDictionary_isValidWord(JNIEnv *env, jobject objec
} }
static void latinime_BinaryDictionary_close(JNIEnv *env, jobject object, jint dict) { static void latinime_BinaryDictionary_close(JNIEnv *env, jobject object, jint dict) {
delete (Dictionary*) dict; Dictionary *dictionary = (Dictionary*)dict;
if (!dictionary) return;
void *dictBuf = dictionary->getDict();
if (!dictBuf) return;
#ifdef USE_MMAP_FOR_DICTIONARY
int ret = munmap((void *)((char *)dictBuf - dictionary->getDictBufAdjust()),
dictionary->getDictSize() + dictionary->getDictBufAdjust());
if (ret != 0) {
LOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno);
}
ret = close(dictionary->getMmapFd());
if (ret != 0) {
LOGE("DICT: Failure in close. ret=%d errno=%d", ret, errno);
}
#else // USE_MMAP_FOR_DICTIONARY
free(dictBuf);
#endif // USE_MMAP_FOR_DICTIONARY
delete dictionary;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = { static JNINativeMethod gMethods[] = {
{"openNative", "(Ljava/nio/ByteBuffer;IIIII)I", (void*)latinime_BinaryDictionary_open}, {"openNative", "(Ljava/lang/String;JJIIIII)I", (void*)latinime_BinaryDictionary_open},
{"closeNative", "(I)V", (void*)latinime_BinaryDictionary_close}, {"closeNative", "(I)V", (void*)latinime_BinaryDictionary_close},
{"getSuggestionsNative", "(I[II[C[I[II)I", (void*)latinime_BinaryDictionary_getSuggestions}, {"getSuggestionsNative", "(I[II[C[I[II)I", (void*)latinime_BinaryDictionary_getSuggestions},
{"isValidWordNative", "(I[CI)Z", (void*)latinime_BinaryDictionary_isValidWord}, {"isValidWordNative", "(I[CI)Z", (void*)latinime_BinaryDictionary_isValidWord},
@ -132,11 +220,11 @@ static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMe
clazz = env->FindClass(className); clazz = env->FindClass(className);
if (clazz == NULL) { if (clazz == NULL) {
fprintf(stderr, "Native registration unable to find class '%s'\n", className); LOGE("Native registration unable to find class '%s'", className);
return JNI_FALSE; return JNI_FALSE;
} }
if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) { if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
fprintf(stderr, "RegisterNatives failed for '%s'\n", className); LOGE("RegisterNatives failed for '%s'", className);
return JNI_FALSE; return JNI_FALSE;
} }
@ -157,13 +245,13 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
jint result = -1; jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
fprintf(stderr, "ERROR: GetEnv failed\n"); LOGE("ERROR: GetEnv failed");
goto bail; goto bail;
} }
assert(env != NULL); assert(env != NULL);
if (!registerNatives(env)) { if (!registerNatives(env)) {
fprintf(stderr, "ERROR: BinaryDictionary native registration failed\n"); LOGE("ERROR: BinaryDictionary native registration failed");
goto bail; goto bail;
} }

View file

@ -31,7 +31,7 @@ BigramDictionary::BigramDictionary(const unsigned char *dict, int maxWordLength,
MAX_ALTERNATIVES(maxAlternatives), IS_LATEST_DICT_VERSION(isLatestDictVersion), MAX_ALTERNATIVES(maxAlternatives), IS_LATEST_DICT_VERSION(isLatestDictVersion),
HAS_BIGRAM(hasBigram), mParentDictionary(parentDictionary) { HAS_BIGRAM(hasBigram), mParentDictionary(parentDictionary) {
if (DEBUG_DICT) LOGI("BigramDictionary - constructor"); if (DEBUG_DICT) LOGI("BigramDictionary - constructor");
if (DEBUG_DICT) LOGI("Has Bigram : %d \n", hasBigram); if (DEBUG_DICT) LOGI("Has Bigram : %d", hasBigram);
} }
BigramDictionary::~BigramDictionary() { BigramDictionary::~BigramDictionary() {
@ -42,7 +42,7 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ
if (DEBUG_DICT) { if (DEBUG_DICT) {
char s[length + 1]; char s[length + 1];
for (int i = 0; i <= length; i++) s[i] = word[i]; for (int i = 0; i <= length; i++) s[i] = word[i];
LOGI("Bigram: Found word = %s, freq = %d : \n", s, frequency); LOGI("Bigram: Found word = %s, freq = %d :", s, frequency);
} }
// Find the right insertion point // Find the right insertion point
@ -54,7 +54,7 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ
} }
insertAt++; insertAt++;
} }
if (DEBUG_DICT) LOGI("Bigram: InsertAt -> %d maxBigrams: %d\n", insertAt, mMaxBigrams); if (DEBUG_DICT) LOGI("Bigram: InsertAt -> %d maxBigrams: %d", insertAt, mMaxBigrams);
if (insertAt < mMaxBigrams) { if (insertAt < mMaxBigrams) {
memmove((char*) mBigramFreq + (insertAt + 1) * sizeof(mBigramFreq[0]), memmove((char*) mBigramFreq + (insertAt + 1) * sizeof(mBigramFreq[0]),
(char*) mBigramFreq + insertAt * sizeof(mBigramFreq[0]), (char*) mBigramFreq + insertAt * sizeof(mBigramFreq[0]),
@ -68,7 +68,7 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ
*dest++ = *word++; *dest++ = *word++;
} }
*dest = 0; // NULL terminate *dest = 0; // NULL terminate
if (DEBUG_DICT) LOGI("Bigram: Added word at %d\n", insertAt); if (DEBUG_DICT) LOGI("Bigram: Added word at %d", insertAt);
return true; return true;
} }
return false; return false;
@ -107,7 +107,7 @@ int BigramDictionary::getBigrams(unsigned short *prevWord, int prevWordLength, i
if (HAS_BIGRAM && IS_LATEST_DICT_VERSION) { if (HAS_BIGRAM && IS_LATEST_DICT_VERSION) {
int pos = mParentDictionary->isValidWordRec( int pos = mParentDictionary->isValidWordRec(
DICTIONARY_HEADER_SIZE, prevWord, 0, prevWordLength); DICTIONARY_HEADER_SIZE, prevWord, 0, prevWordLength);
if (DEBUG_DICT) LOGI("Pos -> %d\n", pos); if (DEBUG_DICT) LOGI("Pos -> %d", pos);
if (pos < 0) { if (pos < 0) {
return 0; return 0;
} }
@ -151,7 +151,7 @@ void BigramDictionary::searchForTerminalNode(int addressLookingFor, int frequenc
} }
pos = followDownBranchAddress; // pos start at count pos = followDownBranchAddress; // pos start at count
int count = DICT[pos] & 0xFF; int count = DICT[pos] & 0xFF;
if (DEBUG_DICT) LOGI("count - %d\n",count); if (DEBUG_DICT) LOGI("count - %d",count);
pos++; pos++;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
// pos at data // pos at data

View file

@ -24,23 +24,88 @@
#define LOG_TAG "LatinIME: " #define LOG_TAG "LatinIME: "
#endif #endif
#define DEBUG_DICT true #define DEBUG_DICT true
#define DEBUG_DICT_FULL true #define DEBUG_DICT_FULL false
#define DEBUG_SHOW_FOUND_WORD DEBUG_DICT_FULL #define DEBUG_SHOW_FOUND_WORD DEBUG_DICT_FULL
#define DEBUG_NODE DEBUG_DICT_FULL #define DEBUG_NODE DEBUG_DICT_FULL
#define DEBUG_TRACE DEBUG_DICT_FULL #define DEBUG_TRACE DEBUG_DICT_FULL
// Profiler
#include <time.h>
#define PROF_BUF_SIZE 100
static double profile_buf[PROF_BUF_SIZE];
static double profile_old[PROF_BUF_SIZE];
static unsigned int profile_counter[PROF_BUF_SIZE];
#define PROF_RESET prof_reset()
#define PROF_COUNT(prof_buf_id) ++profile_counter[prof_buf_id]
#define PROF_OPEN do { PROF_RESET; PROF_START(PROF_BUF_SIZE - 1); } while(0)
#define PROF_START(prof_buf_id) do { \
PROF_COUNT(prof_buf_id); profile_old[prof_buf_id] = (clock()); } while(0)
#define PROF_CLOSE do { PROF_END(PROF_BUF_SIZE - 1); PROF_OUTALL; } while(0)
#define PROF_END(prof_buf_id) profile_buf[prof_buf_id] += ((clock()) - profile_old[prof_buf_id])
#define PROF_CLOCKOUT(prof_buf_id) \
LOGI("%s : clock is %f", __FUNCTION__, (clock() - profile_old[prof_buf_id]))
#define PROF_OUTALL do { LOGI("--- %s ---", __FUNCTION__); prof_out(); } while(0)
static void prof_reset(void) {
for (int i = 0; i < PROF_BUF_SIZE; ++i) {
profile_buf[i] = 0;
profile_old[i] = 0;
profile_counter[i] = 0;
}
}
static void prof_out(void) {
if (profile_counter[PROF_BUF_SIZE - 1] != 1) {
LOGI("Error: You must call PROF_OPEN before PROF_CLOSE.");
}
LOGI("Total time is %6.3f ms.",
profile_buf[PROF_BUF_SIZE - 1] * 1000 / (double)CLOCKS_PER_SEC);
double all = 0;
for (int i = 0; i < PROF_BUF_SIZE - 1; ++i) {
all += profile_buf[i];
}
if (all == 0) all = 1;
for (int i = 0; i < PROF_BUF_SIZE - 1; ++i) {
if (profile_buf[i] != 0) {
LOGI("(%d): Used %4.2f%%, %8.4f ms. Called %d times.",
i, (profile_buf[i] * 100 / all),
profile_buf[i] * 1000 / (double)CLOCKS_PER_SEC, profile_counter[i]);
}
}
}
#else // FLAG_DBG #else // FLAG_DBG
#define LOGE
#define LOGI #define LOGI
#define DEBUG_DICT false #define DEBUG_DICT false
#define DEBUG_DICT_FULL false #define DEBUG_DICT_FULL false
#define DEBUG_SHOW_FOUND_WORD false #define DEBUG_SHOW_FOUND_WORD false
#define DEBUG_NODE false #define DEBUG_NODE false
#define DEBUG_TRACE false #define DEBUG_TRACE false
#define PROF_BUF_SIZE 0
#define PROF_RESET
#define PROF_COUNT(prof_buf_id)
#define PROF_OPEN
#define PROF_START(prof_buf_id)
#define PROF_CLOSE
#define PROF_END(prof_buf_id)
#define PROF_CLOCK_OUT(prof_buf_id)
#define PROF_CLOCKOUT(prof_buf_id)
#define PROF_OUTALL
#endif // FLAG_DBG #endif // FLAG_DBG
#ifndef U_SHORT_MAX #ifndef U_SHORT_MAX
#define U_SHORT_MAX 1 << 16 #define U_SHORT_MAX 1 << 16
#endif #endif
// Define this to use mmap() for dictionary loading. Undefine to use malloc() instead of mmap().
// We measured and compared performance of both, and found mmap() is fairly good in terms of
// loading time, and acceptable even for several initial lookups which involve page faults.
#define USE_MMAP_FOR_DICTIONARY
// 22-bit address = ~4MB dictionary size limit, which on average would be about 200k-300k words // 22-bit address = ~4MB dictionary size limit, which on average would be about 200k-300k words
#define ADDRESS_MASK 0x3FFFFF #define ADDRESS_MASK 0x3FFFFF

View file

@ -23,21 +23,23 @@
namespace latinime { namespace latinime {
Dictionary::Dictionary(void *dict, int typedLetterMultiplier, int fullWordMultiplier, Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust,
int typedLetterMultiplier, int fullWordMultiplier,
int maxWordLength, int maxWords, int maxAlternatives) int maxWordLength, int maxWords, int maxAlternatives)
: DICT((unsigned char*) dict), : mDict((unsigned char*) dict), mDictSize(dictSize),
mMmapFd(mmapFd), mDictBufAdjust(dictBufAdjust),
// Checks whether it has the latest dictionary or the old dictionary // Checks whether it has the latest dictionary or the old dictionary
IS_LATEST_DICT_VERSION((((unsigned char*) dict)[0] & 0xFF) >= DICTIONARY_VERSION_MIN) { IS_LATEST_DICT_VERSION((((unsigned char*) dict)[0] & 0xFF) >= DICTIONARY_VERSION_MIN) {
if (DEBUG_DICT) { if (DEBUG_DICT) {
if (MAX_WORD_LENGTH_INTERNAL < maxWordLength) { if (MAX_WORD_LENGTH_INTERNAL < maxWordLength) {
LOGI("Max word length (%d) is greater than %d", LOGI("Max word length (%d) is greater than %d",
maxWordLength, MAX_WORD_LENGTH_INTERNAL); maxWordLength, MAX_WORD_LENGTH_INTERNAL);
LOGI("IN NATIVE SUGGEST Version: %d \n", (DICT[0] & 0xFF)); LOGI("IN NATIVE SUGGEST Version: %d", (mDict[0] & 0xFF));
} }
} }
mUnigramDictionary = new UnigramDictionary(DICT, typedLetterMultiplier, fullWordMultiplier, mUnigramDictionary = new UnigramDictionary(mDict, typedLetterMultiplier, fullWordMultiplier,
maxWordLength, maxWords, maxAlternatives, IS_LATEST_DICT_VERSION); maxWordLength, maxWords, maxAlternatives, IS_LATEST_DICT_VERSION);
mBigramDictionary = new BigramDictionary(DICT, maxWordLength, maxAlternatives, mBigramDictionary = new BigramDictionary(mDict, maxWordLength, maxAlternatives,
IS_LATEST_DICT_VERSION, hasBigram(), this); IS_LATEST_DICT_VERSION, hasBigram(), this);
} }
@ -47,7 +49,7 @@ Dictionary::~Dictionary() {
} }
bool Dictionary::hasBigram() { bool Dictionary::hasBigram() {
return ((DICT[1] & 0xFF) == 1); return ((mDict[1] & 0xFF) == 1);
} }
// TODO: use uint16_t instead of unsigned short // TODO: use uint16_t instead of unsigned short
@ -64,12 +66,12 @@ int Dictionary::isValidWordRec(int pos, unsigned short *word, int offset, int le
// returns address of bigram data of that word // returns address of bigram data of that word
// return -99 if not found // return -99 if not found
int count = Dictionary::getCount(DICT, &pos); int count = Dictionary::getCount(mDict, &pos);
unsigned short currentChar = (unsigned short) word[offset]; unsigned short currentChar = (unsigned short) word[offset];
for (int j = 0; j < count; j++) { for (int j = 0; j < count; j++) {
unsigned short c = Dictionary::getChar(DICT, &pos); unsigned short c = Dictionary::getChar(mDict, &pos);
int terminal = Dictionary::getTerminal(DICT, &pos); int terminal = Dictionary::getTerminal(mDict, &pos);
int childPos = Dictionary::getAddress(DICT, &pos); int childPos = Dictionary::getAddress(mDict, &pos);
if (c == currentChar) { if (c == currentChar) {
if (offset == length - 1) { if (offset == length - 1) {
if (terminal) { if (terminal) {
@ -85,7 +87,7 @@ int Dictionary::isValidWordRec(int pos, unsigned short *word, int offset, int le
} }
} }
if (terminal) { if (terminal) {
Dictionary::getFreq(DICT, IS_LATEST_DICT_VERSION, &pos); Dictionary::getFreq(mDict, IS_LATEST_DICT_VERSION, &pos);
} }
// There could be two instances of each alphabet - upper and lower case. So continue // There could be two instances of each alphabet - upper and lower case. So continue
// looking ... // looking ...

View file

@ -25,8 +25,8 @@ namespace latinime {
class Dictionary { class Dictionary {
public: public:
Dictionary(void *dict, int typedLetterMultipler, int fullWordMultiplier, int maxWordLength, Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, int typedLetterMultipler,
int maxWords, int maxAlternatives); int fullWordMultiplier, int maxWordLength, int maxWords, int maxAlternatives);
int getSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies, int getSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies,
int *nextLetters, int nextLettersSize) { int *nextLetters, int nextLettersSize) {
return mUnigramDictionary->getSuggestions(codes, codesSize, outWords, frequencies, return mUnigramDictionary->getSuggestions(codes, codesSize, outWords, frequencies,
@ -42,8 +42,10 @@ public:
} }
bool isValidWord(unsigned short *word, int length); bool isValidWord(unsigned short *word, int length);
int isValidWordRec(int pos, unsigned short *word, int offset, int length); int isValidWordRec(int pos, unsigned short *word, int offset, int length);
void setAsset(void *asset) { mAsset = asset; } void *getDict() { return (void *)mDict; }
void *getAsset() { return mAsset; } int getDictSize() { return mDictSize; }
int getMmapFd() { return mMmapFd; }
int getDictBufAdjust() { return mDictBufAdjust; }
~Dictionary(); ~Dictionary();
// public static utility methods // public static utility methods
@ -62,11 +64,17 @@ public:
private: private:
bool hasBigram(); bool hasBigram();
const unsigned char *DICT; const unsigned char *mDict;
// Used only for the mmap version of dictionary loading, but we use these as dummy variables
// also for the malloc version.
const int mDictSize;
const int mMmapFd;
const int mDictBufAdjust;
const bool IS_LATEST_DICT_VERSION; const bool IS_LATEST_DICT_VERSION;
void *mAsset;
BigramDictionary *mBigramDictionary;
UnigramDictionary *mUnigramDictionary; UnigramDictionary *mUnigramDictionary;
BigramDictionary *mBigramDictionary;
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View file

@ -42,14 +42,20 @@ UnigramDictionary::UnigramDictionary(const unsigned char *dict, int typedLetterM
UnigramDictionary::~UnigramDictionary() {} UnigramDictionary::~UnigramDictionary() {}
int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short *outWords, int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short *outWords,
int *frequencies, int *nextLetters, int nextLettersSize) int *frequencies, int *nextLetters, int nextLettersSize) {
{ PROF_OPEN;
PROF_START(0);
initSuggestions(codes, codesSize, outWords, frequencies); initSuggestions(codes, codesSize, outWords, frequencies);
if (DEBUG_DICT) assert(codesSize == mInputLength); if (DEBUG_DICT) assert(codesSize == mInputLength);
const int MAX_DEPTH = min(mInputLength * MAX_DEPTH_MULTIPLIER, MAX_WORD_LENGTH); const int MAX_DEPTH = min(mInputLength * MAX_DEPTH_MULTIPLIER, MAX_WORD_LENGTH);
getSuggestionCandidates(-1, -1, -1, nextLetters, nextLettersSize, MAX_DEPTH); PROF_END(0);
PROF_START(1);
getSuggestionCandidates(-1, -1, -1, nextLetters, nextLettersSize, MAX_DEPTH);
PROF_END(1);
PROF_START(2);
// Suggestion with missing character // Suggestion with missing character
if (SUGGEST_WORDS_WITH_MISSING_CHARACTER) { if (SUGGEST_WORDS_WITH_MISSING_CHARACTER) {
for (int i = 0; i < codesSize; ++i) { for (int i = 0; i < codesSize; ++i) {
@ -57,7 +63,9 @@ int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short
getSuggestionCandidates(i, -1, -1, NULL, 0, MAX_DEPTH); getSuggestionCandidates(i, -1, -1, NULL, 0, MAX_DEPTH);
} }
} }
PROF_END(2);
PROF_START(3);
// Suggestion with excessive character // Suggestion with excessive character
if (SUGGEST_WORDS_WITH_EXCESSIVE_CHARACTER if (SUGGEST_WORDS_WITH_EXCESSIVE_CHARACTER
&& mInputLength >= MIN_USER_TYPED_LENGTH_FOR_EXCESSIVE_CHARACTER_SUGGESTION) { && mInputLength >= MIN_USER_TYPED_LENGTH_FOR_EXCESSIVE_CHARACTER_SUGGESTION) {
@ -66,7 +74,9 @@ int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short
getSuggestionCandidates(-1, i, -1, NULL, 0, MAX_DEPTH); getSuggestionCandidates(-1, i, -1, NULL, 0, MAX_DEPTH);
} }
} }
PROF_END(3);
PROF_START(4);
// Suggestion with transposed characters // Suggestion with transposed characters
// Only suggest words that length is mInputLength // Only suggest words that length is mInputLength
if (SUGGEST_WORDS_WITH_TRANSPOSED_CHARACTERS) { if (SUGGEST_WORDS_WITH_TRANSPOSED_CHARACTERS) {
@ -75,7 +85,9 @@ int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short
getSuggestionCandidates(-1, -1, i, NULL, 0, mInputLength - 1); getSuggestionCandidates(-1, -1, i, NULL, 0, mInputLength - 1);
} }
} }
PROF_END(4);
PROF_START(5);
// Suggestions with missing space // Suggestions with missing space
if (SUGGEST_WORDS_WITH_MISSING_SPACE_CHARACTER if (SUGGEST_WORDS_WITH_MISSING_SPACE_CHARACTER
&& mInputLength >= MIN_USER_TYPED_LENGTH_FOR_MISSING_SPACE_SUGGESTION) { && mInputLength >= MIN_USER_TYPED_LENGTH_FOR_MISSING_SPACE_SUGGESTION) {
@ -84,7 +96,9 @@ int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short
getMissingSpaceWords(mInputLength, i); getMissingSpaceWords(mInputLength, i);
} }
} }
PROF_END(5);
PROF_START(6);
// Get the word count // Get the word count
int suggestedWordsCount = 0; int suggestedWordsCount = 0;
while (suggestedWordsCount < MAX_WORDS && mFrequencies[suggestedWordsCount] > 0) { while (suggestedWordsCount < MAX_WORDS && mFrequencies[suggestedWordsCount] > 0) {
@ -99,9 +113,9 @@ int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short
LOGI("%c = %d,", k, nextLetters[k]); LOGI("%c = %d,", k, nextLetters[k]);
} }
} }
LOGI("\n");
} }
PROF_END(6);
PROF_CLOSE;
return suggestedWordsCount; return suggestedWordsCount;
} }
@ -254,6 +268,14 @@ void UnigramDictionary::getSuggestionCandidates(const int skipPos,
} }
} }
inline static void multiplyRate(const int rate, int *freq) {
if (rate > 1000000) {
*freq = (*freq / 100) * rate;
} else {
*freq = *freq * rate / 100;
}
}
bool UnigramDictionary::getMissingSpaceWords(const int inputLength, const int missingSpacePos) { bool UnigramDictionary::getMissingSpaceWords(const int inputLength, const int missingSpacePos) {
if (missingSpacePos <= 0 || missingSpacePos >= inputLength if (missingSpacePos <= 0 || missingSpacePos >= inputLength
|| inputLength >= MAX_WORD_LENGTH) return false; || inputLength >= MAX_WORD_LENGTH) return false;
@ -279,7 +301,7 @@ bool UnigramDictionary::getMissingSpaceWords(const int inputLength, const int mi
int pairFreq = ((firstFreq + secondFreq) / 2); int pairFreq = ((firstFreq + secondFreq) / 2);
for (int i = 0; i < inputLength; ++i) pairFreq *= TYPED_LETTER_MULTIPLIER; for (int i = 0; i < inputLength; ++i) pairFreq *= TYPED_LETTER_MULTIPLIER;
pairFreq = pairFreq * WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE / 100; multiplyRate(WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE, &pairFreq);
addWord(word, newWordLength, pairFreq); addWord(word, newWordLength, pairFreq);
return true; return true;
} }
@ -330,14 +352,13 @@ inline int UnigramDictionary::calculateFinalFreq(const int inputIndex, const int
const bool sameLength) { const bool sameLength) {
// TODO: Demote by edit distance // TODO: Demote by edit distance
int finalFreq = freq * snr; int finalFreq = freq * snr;
if (skipPos >= 0) finalFreq = finalFreq * WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE / 100; if (skipPos >= 0) multiplyRate(WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE, &finalFreq);
if (transposedPos >= 0) finalFreq = finalFreq if (transposedPos >= 0) multiplyRate(
* WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE / 100; WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE, &finalFreq);
if (excessivePos >= 0) { if (excessivePos >= 0) {
finalFreq = finalFreq * WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE / 100; multiplyRate(WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE, &finalFreq);
if (!existsAdjacentProximityChars(inputIndex, mInputLength)) { if (!existsAdjacentProximityChars(inputIndex, mInputLength)) {
finalFreq = finalFreq multiplyRate(WORDS_WITH_EXCESSIVE_CHARACTER_OUT_OF_PROXIMITY_DEMOTION_RATE, &finalFreq);
* WORDS_WITH_EXCESSIVE_CHARACTER_OUT_OF_PROXIMITY_DEMOTION_RATE / 100;
} }
} }
if (sameLength && skipPos < 0) finalFreq *= FULL_WORD_MULTIPLIER; if (sameLength && skipPos < 0) finalFreq *= FULL_WORD_MULTIPLIER;

View file

@ -80,13 +80,13 @@ private:
bool existsAdjacentProximityChars(const int inputIndex, const int inputLength); bool existsAdjacentProximityChars(const int inputIndex, const int inputLength);
int* getInputCharsAt(const int index) {return mInputCodes + (index * MAX_PROXIMITY_CHARS);} int* getInputCharsAt(const int index) {return mInputCodes + (index * MAX_PROXIMITY_CHARS);}
const unsigned char *DICT; const unsigned char *DICT;
const int MAX_WORDS;
const int MAX_WORD_LENGTH; const int MAX_WORD_LENGTH;
const int MAX_WORDS;
const int MAX_PROXIMITY_CHARS; const int MAX_PROXIMITY_CHARS;
const bool IS_LATEST_DICT_VERSION; const bool IS_LATEST_DICT_VERSION;
const int ROOT_POS;
const int TYPED_LETTER_MULTIPLIER; const int TYPED_LETTER_MULTIPLIER;
const int FULL_WORD_MULTIPLIER; const int FULL_WORD_MULTIPLIER;
const int ROOT_POS;
int *mFrequencies; int *mFrequencies;
unsigned short *mOutputChars; unsigned short *mOutputChars;

View file

@ -38,49 +38,15 @@ public class SuggestHelper {
private final String TAG; private final String TAG;
/** Uses main dictionary only **/ /** Uses main dictionary only **/
public SuggestHelper(String tag, Context context, int[] resId) { public SuggestHelper(String tag, Context context, int resId) {
TAG = tag; TAG = tag;
InputStream[] is = null; mSuggest = new Suggest(context, resId);
try {
// merging separated dictionary into one if dictionary is separated
int total = 0;
is = new InputStream[resId.length];
for (int i = 0; i < resId.length; i++) {
is[i] = context.getResources().openRawResource(resId[i]);
total += is[i].available();
}
ByteBuffer byteBuffer =
ByteBuffer.allocateDirect(total).order(ByteOrder.nativeOrder());
int got = 0;
for (int i = 0; i < resId.length; i++) {
got += Channels.newChannel(is[i]).read(byteBuffer);
}
if (got != total) {
Log.w(TAG, "Read " + got + " bytes, expected " + total);
} else {
mSuggest = new Suggest(context, byteBuffer);
Log.i(TAG, "Created mSuggest " + total + " bytes");
}
} catch (IOException e) {
Log.w(TAG, "No available memory for binary dictionary");
} finally {
try {
if (is != null) {
for (int i = 0; i < is.length; i++) {
is[i].close();
}
}
} catch (IOException e) {
Log.w(TAG, "Failed to close input stream");
}
}
mSuggest.setAutoTextEnabled(false); mSuggest.setAutoTextEnabled(false);
mSuggest.setCorrectionMode(Suggest.CORRECTION_FULL_BIGRAM); mSuggest.setCorrectionMode(Suggest.CORRECTION_FULL_BIGRAM);
} }
/** Uses both main dictionary and user-bigram dictionary **/ /** Uses both main dictionary and user-bigram dictionary **/
public SuggestHelper(String tag, Context context, int[] resId, int userBigramMax, public SuggestHelper(String tag, Context context, int resId, int userBigramMax,
int userBigramDelete) { int userBigramDelete) {
this(tag, context, resId); this(tag, context, resId);
mUserBigram = new UserBigramDictionary(context, null, Locale.US.toString(), mUserBigram = new UserBigramDictionary(context, null, Locale.US.toString(),

View file

@ -36,9 +36,9 @@ public class SuggestPerformanceTests extends AndroidTestCase {
// For testing with real dictionary, TEMPORARILY COPY main dictionary into test directory. // For testing with real dictionary, TEMPORARILY COPY main dictionary into test directory.
// DO NOT SUBMIT real dictionary under test directory. // DO NOT SUBMIT real dictionary under test directory.
//int[] resId = new int[] { R.raw.main0, R.raw.main1, R.raw.main2 }; //int resId = R.raw.main;
int[] resId = new int[] { R.raw.test }; int resId = R.raw.test;
sh = new SuggestHelper(TAG, getTestContext(), resId); sh = new SuggestHelper(TAG, getTestContext(), resId);
loadString(); loadString();

View file

@ -26,7 +26,7 @@ public class SuggestTests extends AndroidTestCase {
@Override @Override
protected void setUp() { protected void setUp() {
int[] resId = new int[] { R.raw.test }; int resId = R.raw.test;
sh = new SuggestHelper(TAG, getTestContext(), resId); sh = new SuggestHelper(TAG, getTestContext(), resId);
} }

Some files were not shown because too many files have changed in this diff Show more